Skip to content

Conversation

@sirosen
Copy link
Member

@sirosen sirosen commented Nov 4, 2025

resolves #2231

When -r is used to pass a path, we are normalizing with pathlib.Path.relative_to. This fails when the input is not a subpath of the current working directory.

In Python 3.12+ pathlib supports this usage (walk_up=True), but on older Pythons we need to fallback to using os.path.relpath.

In order to support this usage and give a clear indication of how we should upgrade when older versions are dropped, a small compat wrapper is here defined, _relative_to_walk_up which uses relative_to(..., walk_up=True) when it is available, and only uses os.path.relpath when necessary. After we drop Python 3.11 in a few years, the helper can be removed.

A new regression test reproduces #2231 and is fixed with this patch.
As part of writing that test, I wanted to leverage the TestFilesCollection helper, so this was extended in a small way to support usage without an explicit name.

Contributor checklist
  • Included tests for the changes.
  • A change note is created in changelog.d/ (see changelog.d/README.md for instructions) or the PR text says "no changelog needed".
Maintainer checklist
  • If no changelog is needed, apply the skip-changelog label.
  • Assign the PR to an existing or new milestone for the target version (following Semantic Versioning).

@sirosen sirosen added this to the 7.5.2 milestone Nov 4, 2025
@sirosen sirosen added the bug Something is not working label Nov 4, 2025
@@ -0,0 +1,2 @@
Fix `pip-compile` handling of relative path includes which are not subpaths of
Copy link
Member

Choose a reason for hiding this comment

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

non-imperative mood plz

Copy link
Member Author

Choose a reason for hiding this comment

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

I need to break this habit of writing changelogs like commit messages. I even updated docs at work to remind people to use past tense for changelogs, and then I go around forgetting it myself! 😆

Thanks for the save.

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we can get an LLM help out with this. I've been looking into configuring some LLM behaviors (CLAUDE.md / AGENTS.md) recently and this should be a func exercise.. Although, we could probably also try Vale.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm interested in Vale, I think it looks very cool.

Less interested in using an LLM for this, personally. I'm waiting for the hype to die down, and plan to be a late adopter of the tech (after some not-great experiences trying it so far) assuming I can square it with my ethics.

Copy link
Member

Choose a reason for hiding this comment

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

I think it's important to have these files in the repo because people are going to use agentic help regardless of what we tell them. And if there's some guidelines, the chance of them producing rubbish would be decreased. With that, they wouldn't waste as much compute retrying or generating nonsense. So in my book helping such tools be efficient is definitely positive if we're talking about the environmental impact.

We just got such configuration in ansible/ansible#85841 just now and I'm interested in exploring making such configs for projects better.

Copy link
Member

Choose a reason for hiding this comment

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

@sirosen re:vale — I have this old issue where I collect various prose checkers @ aio-libs/multidict#276. If we succeed in integating any of them, I'd like to scale that to other projects.

Comment on lines 217 to 229
def _relative_to_walk_up(path: pathlib.Path, start: pathlib.Path) -> pathlib.Path:
"""
Compute a relative path allowing for the input to not be a subpath of the start.
This is a compatibility helper for ``pathlib.Path.relative_to(..., walk_up=True)``
on all Python versions. (``walk_up: bool`` is Python 3.12+)
"""
# prefer `pathlib.Path.relative_to` where available
if sys.version_info >= (3, 12):
return path.relative_to(start, walk_up=True)

str_result = os.path.relpath(path, start=start)
return pathlib.Path(str_result)
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps this should go into a separate pathlib_compat.py?

Copy link
Member Author

Choose a reason for hiding this comment

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

My only concern would be that it might only ever have this one function.
What about a path_compat.py so that it's not only scoped to pathlib?

I wouldn't move other things over right away, but any helpers for handling drive letters and such could go there.

Copy link
Member Author

Choose a reason for hiding this comment

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

I snooped around and immediately found a second helper to put in here!

I still prefer path_compat.py, so I'll go with that for the moment, but I'm happy to rename as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

I unfortunately ended up with a little bit of extra change needed ( 3df3efa ) because my desire to put two related helpers together created an import cycle. I can revert if this feels like too much extraneous change.

Copy link
Member

Choose a reason for hiding this comment

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

@sirosen circular imports is not a new problem. They've been annoying people trying to organize helpers for quite some time: #2108.

I think we should postpone moving other things into the new helper module as to keep the PR atomic and prevent scope creep growing infinitely.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think you're right, especially coming back to this after a couple of days.
I'm going to partially revert, cutting it back to just this one helper in a path_compat.py module, as part of my rebase right now.

@sirosen sirosen force-pushed the improve-relpath-handling branch from 4ef3b4c to 21e5b23 Compare November 5, 2025 03:58
sirosen added a commit to sirosen/pip-tools that referenced this pull request Nov 5, 2025
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
@sirosen sirosen force-pushed the improve-relpath-handling branch from 3e781db to 95a824d Compare November 5, 2025 04:41
sirosen added a commit to sirosen/pip-tools that referenced this pull request Nov 5, 2025
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
@sirosen sirosen force-pushed the improve-relpath-handling branch from 3df3efa to bc8d8c8 Compare November 5, 2025 14:50


def is_path_relative_to(path1: pathlib.Path, path2: pathlib.Path) -> bool:
"""Return True if ``path1`` is relative to ``path2``."""
Copy link
Member

Choose a reason for hiding this comment

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

The literal can also be linked.

Suggested change
"""Return True if ``path1`` is relative to ``path2``."""
"""Return :data:`True` if ``path1`` is relative to ``path2``."""

But as I said elsewhere, let's not include this helper.

Copy link
Member Author

Choose a reason for hiding this comment

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

Since I reverted any move of this helper, I'm not changing the docstring, but 👍 to marking literals like this when possible.

Comment on lines 30 to 31
# TODO: remove this function in favor of Path.is_relative_to()
# when we drop support for Python 3.8
Copy link
Member

Choose a reason for hiding this comment

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

Both 3.8 and 3.9 are both EOL already: https://endoflife.date/python. And testing against pip is becoming difficult in older runtimes.

I think we could plan dropping Python 3.8 once #2257 is implemented and released. With that, there would be no need to even think about hosting this function in compat modules.

@@ -0,0 +1,36 @@
"""
Compatibility helpers for working with paths and ``pathlib`` across platforms
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Compatibility helpers for working with paths and ``pathlib`` across platforms
Compatibility helpers for working with paths and :mod:`pathlib` across platforms

sirosen and others added 3 commits November 6, 2025 13:43
When `-r` is used to pass a path, we are normalizing with
`pathlib.Path.relative_to`. This fails when the input is not a subpath
of the current working directory.

In Python 3.12+ pathlib supports this usage (`walk_up=True`), but on
older Pythons we need to fallback to using `os.path.relpath`.

In order to support this usage and give a clear indication of how we
should upgrade when older versions are dropped, a small compat wrapper
is here defined, `_relative_to_walk_up` which uses
`relative_to(..., walk_up=True)` when it is available, and only uses
`os.path.relpath` when necessary. After we drop Python 3.11 in a few
years, the helper can be removed.

A new regression test reproduces jazzband#2231 and is fixed with this patch.
As part of writing that test, I wanted to leverage the
`TestFilesCollection` helper, so this was extended in a small way to
support usage without an explicit name.
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
`piptools._compat.path_compat` is a new module for holding any helpers
dedicated to path inspection and manipulations.
@sirosen sirosen force-pushed the improve-relpath-handling branch from bc8d8c8 to 7c7fff5 Compare November 6, 2025 19:48
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
@sirosen sirosen force-pushed the improve-relpath-handling branch from 7c7fff5 to d7da20b Compare November 6, 2025 20:05
@webknjaz webknjaz added this pull request to the merge queue Nov 7, 2025
Merged via the queue into jazzband:main with commit 30ed588 Nov 7, 2025
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided bug Something is not working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pip-compile breaks when using paths outside of the current directory

2 participants