-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Use Union[bytes, Text] for paths in os.py #1054
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In order to unify these two versions I'm making all paths be _PathType = Union[bytes, Text] Fixes python#439
stdlib/2/os/__init__.pyi
Outdated
def symlink(source: _PathType, link_name: _PathType) -> None: ... | ||
def unlink(path: _PathType) -> None: ... | ||
def utime(path: _PathType, times: Optional[Tuple[int, int]]) -> None: ... | ||
def walk(top: _PathType, topdown: bool = ..., onerror: Any = ..., |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AnyStr is actually correct here: os.walk returns bytes if you give it bytes and Text if you give it Text. Besides, we should generally avoid Unions in return types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. Went a bit too far here.
stdlib/2/os/__init__.pyi
Outdated
def execle(file: _PathType, *args) -> None: ... | ||
def execlp(file: _PathType, *args) -> None: ... | ||
def execlpe(file: _PathType, *args) -> None: ... | ||
def execv(path: _PathType, args: Union[Tuple[_PathType], List[_PathType]]) -> None: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PathType is an unfortunate name for the args, since they don't have to be Paths.
I think the best solution might be to add a second type alias (or just use Union directly here), so we can easily change the _PathType alias later to include os.PathLike in Python 3.6+.
This also applies to the other exec* function and to the spawn* functions below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
stdlib/3/os/__init__.pyi
Outdated
def execvp(file: AnyStr, args: Union[Tuple[AnyStr], List[AnyStr]]) -> None: ... | ||
def execvpe(file: AnyStr, args: Union[Tuple[AnyStr], List[AnyStr]], | ||
def execv(path: _PathType, args: Union[Tuple[_PathType], List[_PathType]]) -> None: ... | ||
def execve(path: _PathType, args: Union[Tuple[_PathType], List[_PathType]], env: Mapping[_PathType, _PathType]) -> None: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments as on the Python 2 version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
Would it make sense to unify the Python 2 and 3 stubs first, or are the differences still big enough to make that not feasible? |
I did start with a a full merge but thought splitting it up might be useful. I think my plan is:
I think that will make it easier to review everything and not miss anything. I'm still pretty new to github so I don't know if splitting up a diff into multiple PRs is useful or not. |
Thanks, that makes sense. Splitting things up definitely makes it easier to review. |
Thanks! |
I think
to
in |
Hey @JelleZijlstra Welcome to the crew! Can you please always use Squash Merge to merge PRs? We don't want the contributor's local history preserved forever in our master branch; the history remains available for archeologists in the (closed) PR itself. For this PR what's done is done, but in the future I'd really appreciate it. (Also, we probably need to write this up somewhere.) |
Oops, sorry for that. I'll squash in the future. |
This caused some errors in mypy's test suite:
I think mypy is right here: the argument to List is invariant, so We can't make these functions take a |
Sounds like a plan. Maybe the union should even include |
Oops. Sorry about that. Will send out a PR right now! |
This was fixed in #1075. |
It seems that AnyStr has the main advantage of ensuring that multiple arguments (or argument(s) and return values) have the same type (i.e. `str` and `bytes` are both okay but shouldn't be mixed). However it makes it significantly more difficult to cast to a single type. With a Union, something like: ```python def foo(a: Union[bytes, Text]) -> Text: if isinstance(a, bytes): a = a.decode() return "Hello, " + a ``` works fine. With AnyStr, you have to define a new intermediate variable, something like: ```python def foo(a: AnyStr) -> str: if isinstance(a, bytes): b = a.decode() else: b = a return "Hello, " + b ``` If there's no advantage to using AnyStr (since there's no other AnyStr argument or return value), I think the Union would be simpler, have no significant disadvantage, and there is [precedent for similar changes](python#1054). > It's only the case that if there's exactly one parameter of type exactly AnyStr, and no other use of AnyStr in the signature, then Union[str, bytes] should be acceptable. - [gvanrossum](python#439 (comment)) Discussion: - python#1054 - python/mypy#1141 - python#439
In order to unify these two versions I'm making all paths be
_PathType = Union[bytes, Text]
Fixes #439