Skip to content

Conversation

sirosen
Copy link
Member

@sirosen sirosen commented Aug 4, 2025

When statically parsing a pyproject.toml, we can encounter self-referential package usage. For example, an extra which names another extra on the same package.

The source for these requirements is the current package, but as a concrete requirement, not an abstract one. To make it concrete, we use a URI dependency link pointed at the package directory as a file-URI.

When the input path to pyproject.toml is relative, it needs to be made absolute for use as a URI. Failing to do so results in errors.

Because the pip-compile output of an such an extra depends concretely on the specific version of the package found in-tree, and not abstractly on the package name (without the URI), tests confirm that we see the rendered package directory as a file URI in pip-compile output.

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.1 milestone Aug 4, 2025
assert out.exit_code == 0
assert out.stdout == dedent(
f"""\
foo[ext1] @ {src_file.parent.absolute().as_uri()}
Copy link
Member

Choose a reason for hiding this comment

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

Is this really what we want? I don't think people would expect absolute paths from someone else's computer to end up in their lock files..

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 agree, and it's why I was pretty hesitant at first. But also, that's the behavior from 7.4.1 -- it's just not tested.

In theory, someone could be using this in some controlled context like an image build and wanting the concrete dependency path that this provides. So although I'm uncertain that it's right for the long term, I don't want to treat it as blocking the fix.

Copy link
Member

Choose a reason for hiding this comment

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

Wait, did it always use absolute paths in 7.4.1? Not relative? I thought it'd conform to the shape of input that the 7.5.0 changelog promises.. Can we use file://./rel/path/?

Copy link
Member Author

Choose a reason for hiding this comment

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

The path in this case is part of the InstallRequirement itself -- the "link" attribute is populated with this file URI.
The normalization in 7.5.0 only applies to the comes_from data ("via").

We could reach down into this as well and convert to file://./rel/path/ as you say, but I'm not sure if we should. It would be a separate bit of data transformation -- we could share code but it's a different attribute of the parsed requirements data that we'd be manipulating.

Copy link
Member

Choose a reason for hiding this comment

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

I suppose, we could postpone that for now. There might be a use case coverage missing for stripping the @ http://..source in some contexts.

@webknjaz
Copy link
Member

webknjaz commented Aug 4, 2025

Oh, looks like Windows is unhappy about the delimiters again.

@sirosen sirosen force-pushed the fix-relpath-static-pyproject-parse branch from 4507cdf to fc92905 Compare August 4, 2025 23:53
sirosen and others added 2 commits August 4, 2025 18:55
When statically parsing a pyproject.toml , we can encounter
self-referential package usage. For example, an extra which names
another extra on the same package.

The source for these requirements is the current package, but as a
concrete requirement, not an abstract one. To make it concrete, we use
a URI dependency link pointed at the package directory as a file-URI.

When the input path to `pyproject.toml` is relative, it needs to be
made absolute for use as a URI. Failing to do so results in errors.

Because the `pip-compile` output of an such an extra depends
concretely on the specific version of the package found in-tree, and
not abstractly on the package name (without the URI), tests confirm
that we see the rendered package directory as a file URI in
`pip-compile` output.
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
@sirosen sirosen force-pushed the fix-relpath-static-pyproject-parse branch from fc92905 to b05d736 Compare August 4, 2025 23:55
@sirosen
Copy link
Member Author

sirosen commented Aug 5, 2025

The thing I broke in the tests is treatment of comes_from data in this scenario. We're stringifying the path to the package dir here:

comes_from = f"{package_name} ({src_file})"

It's easy to "fix" by just adding an as_posix() call there, but I can imagine this becoming inconsistent with the behavior when that information is rendered via some other path. I'm going to run some experiments later this week to try to figure out what the variations are on this.

@webknjaz webknjaz moved this to 🧐 @webknjaz's review queue 📋 in 📅 Procrastinating in public Aug 7, 2025
@maurerle

This comment was marked as resolved.

@sirosen

This comment was marked as resolved.

@maurerle

This comment was marked as off-topic.

kim-mskw pushed a commit to assume-framework/assume that referenced this pull request Aug 13, 2025
# Pull Request

There is an issue with self-referential packages in a pyproject.toml
with the latest pip-tools release.
The self-referential [all] package, which is not written to the
requirements.txt as it is not selected still throws a pip-compile error.

More information for this can be found in the ticket:
jazzband/pip-tools#2215

The pin should be removed when
jazzband/pip-tools#2221 gets merged.
@sirosen

This comment was marked as off-topic.

@sirosen
Copy link
Member Author

sirosen commented Aug 13, 2025

I've just gotten back to this, taken a look at the open threads and marked the ones which were applied as suggestions as resolved.

I looked at what happens in the case of dynamic metadata, and we have a similar bit of path formatting in there.

I'd like to resolve this by adding calls to as_posix() to both locations in piptools/build.py.
One is the place mentioned above, where a static build is happening and we're writing the comes_from data.
The other is this line in this function which does the same work on requirements from dynamic metadata.

@webknjaz, are you okay with that increase in scope? I'll need to add some new tests to cover it and another changelog note.
As an overall project direction, I think it's best to try to make all of our outputs posix paths, to make the outputs consistent.

@webknjaz
Copy link
Member

@sirosen agreed. Increasing the scope sounds justified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants