GeezerVison is showing github.com — `os.path.isabs` change in behavior in Python 3.13 on MS-Windows · Issue #125283 · python/cpython
os.path.isabs change in behavior in Python 3.13 on MS-Windows #125283
DescriptionBug report
Bug description:
I'm not sure if this is a fix or a regression issue?
os.path.isabs use to return True when a windows path started with /.
In python 3.13
Python 3.13.0 (tags/v3.13.0:60403a5, Oct 7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os.path
>>> os.path.isabs("/c:")
False
In python 3.12
Python 3.12.7 (tags/v3.12.7:0b05ead, Oct 1 2024, 03:06:41) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os.path
>>> os.path.isabs("/c:")
True
CPython versions tested on:
3.13
Operating systems tested on:
Windows Activitynineteendo commented on Oct 11, 2024 Works as intended: #113829, maybe a new function could be considered to check if a path is rooted? ikappaki commented on Oct 11, 2024
Works as intended: #113829, maybe a new function could be considered to check if a path is rooted?
This behavior changes how os.path.isabs interacts with urllib.parse.urlparse when dealing with absolute paths in Windows URIs. In Python 3.12, paths parsed from local file URIs (drive and network paths) were recognized as absolute, but in Python 3.13, they no longer are
import os.path
import pathlib
import urllib.parse
>>> urllib.parse.urlparse(pathlib.Path('c:\\xyz').as_uri())
ParseResult(scheme='file', netloc='', path='/c:/xyz', params='', query='', fragment='')
>>> urllib.parse.urlparse(pathlib.Path('\\\\machine\\xyz').as_uri())
ParseResult(scheme='file', netloc='machine', path='/xyz/', params='', query='', fragment='')
In Python 3.12, os.path.isabs would correctly identify these paths as absolute, including network paths:
>>> os.path.isabs(urllib.parse.urlparse(pathlib.Path('c:\\xyz').as_uri()).path)
True
>>> os.path.isabs(urllib.parse.urlparse(pathlib.Path('\\\\machine\\xyz').as_uri()).path)
True
but not any more in 3.13
>>> os.path.isabs(urllib.parse.urlparse(pathlib.Path('c:\\xyz').as_uri()).path)
False
>>> os.path.isabs(urllib.parse.urlparse(pathlib.Path('\\\\machine\\xyz').as_uri()).path)
False
It seems as if os.path.isabs was never intended to be used with ParseResult paths. I suppose a more appropriate solution would be to directly check if the path starts with '/', which would indicate that it's absolute. nineteendo commented on Oct 11, 2024 You can use pathlib.Path.from_uri() starting from 3.13:
>>> import pathlib
>>> pathlib.Path.from_uri(pathlib.Path('c:/xyz').as_uri())
WindowsPath('c:/xyz')
>>> pathlib.Path.from_uri(pathlib.Path('//server/drive/xyz').as_uri())
WindowsPath('//server/drive/xyz')
This doesn't roundtrip:
>>> import pathlib
>>> import urllib.parse
>>> pathlib.Path(urllib.parse.urlparse(pathlib.Path('c:/xyz').as_uri()).path)
WindowsPath('/c:/xyz')
>>> pathlib.Path(urllib.parse.urlparse(pathlib.Path('//server/drive/xyz').as_uri()).path)
WindowsPath('/drive/xyz')
Also, aren't uri's always absolute? marc-hb commented on Oct 11, 2024
Also, aren't uri's always absolute?
Relative URLs work perfectly fine.
EDIT: I meant in general in life, not related to Python. nineteendo commented on Oct 11, 2024 Well, at least pathlib doesn't allow creating them. barneygale commented on Oct 11, 2024
It seems as if os.path.isabs was never intended to be used with ParseResult paths. I suppose a more appropriate solution would be to directly check if the path starts with '/', which would indicate that it's absolute.
Checking whether it starts with a / makes most sense to me. Another option is posixpath.isabs(). nineteendo commented on Oct 11, 2024 Use p.scheme and p.netloc and p.path.startswith("/") to check if an uri is absolute, an absolute path doesn't change when joined with another path:
>>> import urllib.parse
>>> urllib.parse.urljoin("file://netloc/foo/", "bar")
'file://netloc/foo/bar'
>>> urllib.parse.urljoin("file://netloc/foo/", "/bar")
'file://netloc/bar'
>>> urllib.parse.urljoin("file://netloc/foo/", "//netloc2/bar")
'file://netloc2/bar'
>>> urllib.parse.urljoin("file://netloc/foo/", "file://netloc2/bar")
'file://netloc2/bar'
That's also why we changed the behaviour of os.path.isabs():
>>> import os.path
>>> os.path.join(r"c:\foo", "bar")
'c:\\foo\\bar'
>>> os.path.join(r"c:\foo", r"\bar")
'c:\\bar'
>>> os.path.join(r"c:\foo", r"d:\bar")
'd:\\bar'
Reacted by Barney Gale and ikappaki nineteendo commented on Oct 11, 2024 I think this can be closed. barneygale commented on Oct 11, 2024 kayychou commented on Dec 3, 2024
Works as intended: #113829, maybe a new function could be considered to check if a path is rooted?
hi @nineteendo, @barneygale,
the doc updated in #113829 still indicates the following behavior:
Return ``True`` if *path* is an absolute pathname. On Unix, that means it
begins with a slash, on Windows that it begins with two (back)slashes, or a
drive letter, colon, and (back)slash together.
whereas the intended behavior, as illustrated in Lib/test/test_ntpath.py, appears to be now :
>>> os.path.isabs("/foo/bar") # path beginning with a slash on windows
False
>>> os.path.isabs("\\foo\\bar") # path beginning with two backslashes on windows
False
maybe I'm missing something under the hood
Thanks for your help! barneygale commented on Dec 3, 2024 Reacted by Nice Zombies and kayychou
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|