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
bpo-38807: Add os.PathLike to exception message raised by _check_arg_types #17160
Conversation
Hello, and thanks for your contribution! I'm a bot set up to make sure that the project can legally accept this contribution by verifying everyone involved has signed the PSF contributor agreement (CLA). CLA MissingOur records indicate the following people have not signed the CLA: For legal reasons we need all the people listed to sign the CLA before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue. If you have recently signed the CLA, please wait at least one business day You can check yourself to see if the CLA has been received. Thanks again for the contribution, we look forward to reviewing it! |
Thanks for your time @tomasfarias, and welcome to CPython! I assume that you've seen the bot's message about the CLA? |
Lib/genericpath.py
Outdated
@@ -149,7 +149,7 @@ def _check_arg_types(funcname, *args): | |||
elif isinstance(s, bytes): | |||
hasbytes = True | |||
else: | |||
raise TypeError('%s() argument must be str or bytes, not %r' % | |||
raise TypeError('%s() argument must be str, bytes or os.PathLike object, not %r' % |
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.
raise TypeError('%s() argument must be str, bytes or os.PathLike object, not %r' % | |
raise TypeError('%s() argument must be str, bytes, or os.PathLike object, not %r' % |
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.
Also, I think we can use an f-string here instead of the older % formatting. We often will avoid refactoring old code exclusively for the purpose of using f-strings, but it's preferred for any new code to use f-strings when possible. They're significantly easier to read.
This PR should also have a NEWS entry. Something like: Update :exc:`TypeError` messages for :meth:`os.path.join` to include :class:`os.PathLike` objects as acceptable input types. |
I'd say this falls under the category of |
Lib/genericpath.py
Outdated
raise TypeError('%s() argument must be str or bytes, not %r' % | ||
(funcname, s.__class__.__name__)) from None | ||
raise TypeError(f'{funcname}() argument must be str, bytes, or ' | ||
f'os.PathLike object, not {s.__class__.__name__}') from 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.
In order to use %r formatting in an f-string, the expression within the braces has to end with an !r
:
f'os.PathLike object, not {s.__class__.__name__}') from None | |
f'os.PathLike object, not {s.__class__.__name__!r}') from 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.
Good call, thank you!
The current uses of That makes the error message of I suggest adding a check for |
Would something like this be adequate? def _check_arg_types(funcname, *args):
hasstr = hasbytes = haspathlike = False
for s in args:
if isinstance(s, str):
hasstr = True
elif isinstance(s, bytes):
hasbytes = True
elif isinstance(s, os.PathLike):
haspathlike = True
else:
... I believe the conditional check below would also be needed, to ensure that os.PathLike instances aren't mixed with bytes: if haspathlike and hasbytes:
raise TypeError("Can't mix os.PathLike and bytes in path components") from None Currently, if you try to mix os.PathLike path and with a bytes literal, you get a potentially misleading error message: >>> a = pathlib.PurePath('dir')
>>> b = b'test.py'
>>> os.path.join(a, b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.7/posixpath.py", line 94, in join
genericpath._check_arg_types('join', a, *p)
File "/usr/lib/python3.7/genericpath.py", line 151, in _check_arg_types
raise TypeError("Can't mix strings and bytes in path components") from None
TypeError: Can't mix strings and bytes in path components I believe this occurs because in A check shouldn't be needed for >>> a = pathlib.PurePath('dir')
>>> b = "test.py"
>>> os.path.join(a, b)
'dir/test.py' Edit: the current error message is even more misleading the over way around: >>> a = 'dir'
>>> b = pathlib.PurePath('test.py')
>>> os.path.join(a, b)
'dir/test.py'
>>> a = b'dir'
>>> os.path.join(a, b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.7/posixpath.py", line 94, in join
genericpath._check_arg_types('join', a, *p)
File "/usr/lib/python3.7/genericpath.py", line 149, in _check_arg_types
(funcname, s.__class__.__name__)) from None
TypeError: join() argument must be str or bytes, not 'PurePosixPath' |
@aeros, you're right, adding that check like that to
IMO, no. I suggest changing |
I agree, that would likely be a better solution. Especially in the long term if any other valid types are added in the future that convert to strings with |
I've been afk the last couple of days so I'm just now reading the discussion. Thank you all for your comments. Is there a point to raising the first I agree with the comment, just wondering if also deleting the Edit: the exception message from |
Actually I think the A possible solution is to have Also thought about using a |
@rhettinger: Please replace |
Thanks @tomasfarias for the PR, and @rhettinger for merging it |
GH-17249 is a backport of this pull request to the 3.8 branch. |
Congrats on your first CPython contribution @tomasfarias! Looking forward to seeing more from you in the future. |
@rhettinger, did you follow the conversation here? The PR as merged doesn't appear to properly handle edge cases in |
os.PathLike
objects can be passed toos.path.join
, however this is not reflected in theTypeError
raised by_check_arg_types
when passing an invalid type:TypeError: join() argument must be str or bytes, not 'NoneType'
https://bugs.python.org/issue38807