Skip to content

change create_symlink with type hints and error handling - #257

Open
marvin1099 wants to merge 1 commit into
shymega/validate-dosdevices-symlinksfrom
marvin1099-change-symlink-fn
Open

change create_symlink with type hints and error handling#257
marvin1099 wants to merge 1 commit into
shymega/validate-dosdevices-symlinksfrom
marvin1099-change-symlink-fn

Conversation

@marvin1099

Copy link
Copy Markdown
Collaborator

Refactor create_symlink function to add type hints and enhance error handling for existing symlinks and files.

This is how i would change create_symlink.

@marvin1099
marvin1099 requested a review from shymega April 30, 2026 11:21

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the create_symlink function in src/mainutils.py to use pathlib for more robust path handling and adds logic to manage existing destination files or directories. The review feedback identifies a missing pathlib import that would lead to a NameError and highlights that resolving the source path to an absolute path may break relative symlinks, suggesting the use of the original source path to ensure portability.

Comment thread src/mainutils.py
Comment thread src/mainutils.py Outdated
Comment thread src/mainutils.py Outdated
@marvin1099
marvin1099 force-pushed the marvin1099-change-symlink-fn branch 2 times, most recently from f1ba182 to abd19fc Compare April 30, 2026 11:35
@marvin1099

Copy link
Copy Markdown
Collaborator Author

gemini-code-assist was good this time.
Fixed missing import pathlib
and using a resolved path only for checks not for making the link to maintain relative paths.
Force pushed to keep commits clean.

@marvin1099
marvin1099 force-pushed the marvin1099-change-symlink-fn branch 2 times, most recently from 4fddefd to 69a4b58 Compare April 30, 2026 11:43
@shymega

shymega commented May 1, 2026 via email

Copy link
Copy Markdown
Member

@marvin1099
marvin1099 force-pushed the marvin1099-change-symlink-fn branch from 69a4b58 to 1a48847 Compare May 1, 2026 07:55
@marvin1099

Copy link
Copy Markdown
Collaborator Author

Yes, it was effective on this one. The only thing I'm a little bit against is the nested conditionals and excessive on that front. Do we need so many? Could we use AND/OR logic?

Flattend code as to your request.

@shymega
shymega force-pushed the shymega/validate-dosdevices-symlinks branch from 65f0d31 to 67b691c Compare May 2, 2026 22:42
@shymega

shymega commented May 4, 2026 via email

Copy link
Copy Markdown
Member

@marvin1099
marvin1099 force-pushed the marvin1099-change-symlink-fn branch 2 times, most recently from f92143b to 36f1884 Compare May 4, 2026 09:29
@marvin1099

Copy link
Copy Markdown
Collaborator Author

Now its rebased

@shymega

shymega commented May 8, 2026

Copy link
Copy Markdown
Member

/gemini review

@shymega

shymega commented May 8, 2026

Copy link
Copy Markdown
Member

Just prodding Gemini for another review, and then I'll test.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors src/mainutils.py by moving pathlib imports to the top level and rewriting the create_symlink function with type hints and enhanced replacement logic. However, the refactored function introduces critical bugs: it incorrectly resolves relative paths relative to the current working directory instead of the destination's parent, contains a logic error that prevents creating new symlinks when replace is False, and risks crashing by calling unlink on non-existent paths.

Comment thread src/mainutils.py
@shymega

shymega commented May 8, 2026

Copy link
Copy Markdown
Member

@marvin1099 I'm not sure what you think of the bot's recent review, but I'd like to make sure the launcher doesn't crash.

OOI, what version of Python are you on? I'm on 3.13.x, but if people use varying levels of Python (before we transition to a compiled binary), it could have unexpected behaviour between systems.

@marvin1099
marvin1099 force-pushed the marvin1099-change-symlink-fn branch from 36f1884 to 9e3dedc Compare May 8, 2026 23:16
@marvin1099

Copy link
Copy Markdown
Collaborator Author

Fixed. I know what a long comment.

@shymega
shymega force-pushed the shymega/validate-dosdevices-symlinks branch 2 times, most recently from a0b5690 to 65f0d31 Compare May 14, 2026 23:35
@shymega
shymega force-pushed the marvin1099-change-symlink-fn branch from 9e3dedc to f825cb6 Compare May 15, 2026 19:49
@shymega

shymega commented May 15, 2026

Copy link
Copy Markdown
Member

@marvin1099 I've rebased this PR, would like to get it into my PR soon 👍

@shymega

shymega commented May 15, 2026

Copy link
Copy Markdown
Member

/gemini review

Refactor create_symlink function to add type hints and enhance error handling for existing symlinks and files.
@shymega
shymega force-pushed the marvin1099-change-symlink-fn branch from f825cb6 to a507fe2 Compare May 15, 2026 20:05
@shymega
shymega force-pushed the shymega/validate-dosdevices-symlinks branch from 65f0d31 to 6c9d41d Compare May 15, 2026 20:05

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request removes the requests dependency by implementing a custom http_get utility and a SimpleResponse class based on urllib.request. It also refactors create_symlink to use pathlib for more robust path management. Feedback highlights issues in SimpleResponse where the text property consumes the entire stream and iter_content is not reusable. Additionally, the default destructive behavior of create_symlink when encountering directories was flagged as a safety concern.

I am having trouble creating individual review comments. Click here to see my feedback.

src/coreutils.py (91-95)

high

The text property has a side effect of consuming the entire response stream when _stream is True. This exhausts the underlying socket, which means any subsequent attempts to use iter_content() will return no data. Additionally, it loads the entire content into memory, defeating the purpose of streaming for large files. It is recommended to avoid consuming the stream in a property getter or to cache the content in a way that doesn't break the streaming interface.

src/coreutils.py (108-111)

medium

The iter_content method uses an instance variable self._content_pos to track iteration progress for non-streamed content. This makes the response object's content iterable only once. Subsequent calls to iter_content() will yield nothing because self._content_pos remains at the end of the content. It is better to use a local variable for the iteration to allow multiple passes over the cached data.

        else:
            for i in range(0, len(self.content), chunk_size):
                yield self.content[i:i + chunk_size]

src/mainutils.py (721-724)

medium

The create_symlink function defaults to replace=True, which triggers shutil.rmtree(dst_path) if the destination is a directory. This is a highly destructive operation for a utility function that users might expect to only manage symlinks or files. A safer approach would be to default replace to None or False, or to require an explicit confirmation/flag before recursively deleting a directory tree to prevent accidental data loss.

@shymega

shymega commented May 15, 2026

Copy link
Copy Markdown
Member

That was a old push, I've fixed it now. I'll re-run the review with Gemini.

@shymega

shymega commented May 15, 2026

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors src/mainutils.py by promoting the pathlib import to the top level and rewriting the create_symlink function to include type hints and more robust path resolution. Review feedback suggests simplifying the path resolution logic and type hints. Additionally, a high-severity safety concern was raised regarding the default replace=True parameter, which could lead to unintended recursive directory deletion via shutil.rmtree.

Comment thread src/mainutils.py
os.remove(dst)
os.symlink(src, dst)

def create_symlink(src: Union[str, pathlib.Path], dst: Union[str, pathlib.Path], replace: Union[bool, None] = True) -> None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The type hint Union[bool, None] can be simplified to Optional[bool] since Optional is already imported. More importantly, defaulting replace to True is dangerous because it allows shutil.rmtree to recursively delete entire directory trees by default if they exist at the destination. This is a significant departure from the previous implementation's safety. It is highly recommended to change the default to None (replace only files and symlinks) or False for safety.

Suggested change
def create_symlink(src: Union[str, pathlib.Path], dst: Union[str, pathlib.Path], replace: Union[bool, None] = True) -> None:
def create_symlink(src: Union[str, pathlib.Path], dst: Union[str, pathlib.Path], replace: Optional[bool] = None) -> None:

Comment thread src/mainutils.py

# Resolve source relative to destination parent
# because relative symlink targets are interpreted there
check_src = (dst_path.parent / src_path).resolve() if not src_path.is_absolute() else src_path.resolve()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The conditional check if not src_path.is_absolute() is redundant when using pathlib. Joining a path with an absolute path (e.g., parent / absolute_src) automatically returns the absolute path. This can be simplified to a single expression.

Suggested change
check_src = (dst_path.parent / src_path).resolve() if not src_path.is_absolute() else src_path.resolve()
check_src = (dst_path.parent / src_path).resolve()

@marvin1099 marvin1099 added the pickup for v2 pickup or re-examine task or change in v2 label Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pickup for v2 pickup or re-examine task or change in v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants