Repository navigation
fix: avoid deprecated os.path.commonprefix() in RelativePath - #365
Conversation
cclauss
commented
Oct 12, 2026
- os.path.commonprefix deprecated in Python 3.15 #364
- https://docs.python.org/3/library/os.path.html#os.path.commonpath
- https://docs.python.org/3/whatsnew/3.15.html#pending-removal-in-future-versions
3a543b0 to
f6d72fd
Compare
gengjiawen
left a comment
There was a problem hiding this comment.
Thanks for picking this up! Unfortunately os.path.commonpath() isn't a drop-in replacement here. When the only shared ancestor is the filesystem root, it returns the root with a trailing separator (/, C:\, \\srv\share\), so .split(os.path.sep) yields an extra empty component and prefix_len is off by one. The result is missing one .. and drops the first component of path:
path |
relative_to |
main |
this PR |
|---|---|---|---|
/a/b |
/c |
../a/b |
b ❌ |
/a |
/ |
../a |
'' ❌ |
C:\work\proj |
C:\Users\me\node-gyp |
..\..\..\work\proj |
..\..\proj ❌ |
\\srv\share\a |
\\srv\share\b |
..\a |
'' ❌ |
/a/b |
/a/c |
../b |
../b ✅ |
For example, a .gyp file under /tmp with --depth under /home (or C:\work vs C:\Users on Windows) would get wrong relative paths written into the generated build files. CI doesn't catch this because RelativePath has no unit tests and none of the fixtures cross a top-level directory.
path_split and relative_to_split are already lists of components, so the simplest fix is to count the shared leading components directly (see the inline suggestion). I compared it with the old commonprefix() for every pair of paths up to depth 3 under /, C:\ and \\srv\share\, and the results are identical, so behavior is unchanged.
Could you also add a regression test to pylib/gyp/common_test.py? This fails on the current PR and passes on main and with the suggestion:
class TestRelativePath(unittest.TestCase):
def test_common_parent(self):
assert gyp.common.RelativePath("/a/b", "/a/c") == os.path.join("..", "b")
def test_only_root_in_common(self):
"""Paths whose only common ancestor is the filesystem root."""
assert gyp.common.RelativePath("/a/b", "/c") == os.path.join("..", "a", "b")
def test_same_path(self):
assert gyp.common.RelativePath("/a/b", "/a/b") == ""Nit: please retitle the PR to a Conventional Commits title such as fix: avoid deprecated os.path.commonprefix() in RelativePath. The squash commit uses the commit title only while the PR has a single commit; after more pushes it uses the PR title, and release-please silently drops titles it can't parse. The current title also says commonpath, which won't be accurate after this change.
7936f51 to
012b7f3
Compare
gengjiawen
left a comment
There was a problem hiding this comment.
Thanks for the update! LGTM — verified locally (pytest + ruff), and the new tests run on all CI platforms.