Skip to content

fix(pylock): evaluate environments markers in the lock_file context - #1447

Open
feiiiiii5 wants to merge 1 commit into
pypa:mainfrom
feiiiiii5:fix/pylock-environments-context
Open

feiiiiii5 wants to merge 1 commit into
pypa:mainfrom
feiiiiii5:fix/pylock-environments-context

Conversation

@feiiiiii5

Copy link
Copy Markdown
Contributor

Pylock.select() raises on a legal lock file whose environments marker mentions extras or dependency_groups:

lock = Pylock(..., extras=[NormalizedName("docs")], environments=[Marker('"docs" in extras')], ...)
lock.select(extras=["docs"], tags=[])  # UndefinedEnvironmentName: 'extras'

select() builds env in the step the code quotes from the spec ("Gather the extras and dependency groups to install and set extras and dependency_groups for marker evaluation"), and the environments check is the step immediately after it. But that check evaluated the markers against environment or {} — the caller's raw dict — with context="requirement". Marker.evaluate only supplies defaults for those two set-valued variables in the lock_file context (src/packaging/markers.py:534-537), so the values step 1 just computed are missing and the lookup raises instead of evaluating.

The package loop right below already does it the other way: package.marker.evaluate(env, context="lock_file") (src/packaging/pylock.py:759). Using the same env and the same context for the top-level check makes the two marker surfaces agree, and leaves markers that do not reference those variables evaluating exactly as before.

Test: pytest tests/test_pylock_select.py -k "environments_" fails on 332d716 with UndefinedEnvironmentName: 'extras' and 'dependency_groups', and passes on this branch. Whole suite: on 332d716 2 failed, 62491 passed, 1 skipped, here 62493 passed, 1 skipped. Under coverage (coverage run --source=src/packaging -m pytest tests then coverage report --fail-under=100) the run passes and pylock.py stays at 100%. ruff check, ruff format --check (v0.16.8) and mypy (2.3.1) are clean on both files. I did not run the remaining nox sessions or the docs build.

@sbidoul

sbidoul commented Oct 10, 2026

Copy link
Copy Markdown
Member

I don't think this is a valid use case. Extras and dependency groups are not part of the environment.

@feiiiiii5

Copy link
Copy Markdown
Contributor Author

Thanks for looking at this. I read the ordering of the algorithm as the hint: the step that builds env says extras and dependency_groups are set "for marker evaluation", and the environments check is the step right after it, so I assumed the markers there see what the package-level markers see. Your reading — that environments describes the target environment and extras are not part of it — is at least as good a match for the wording "environment marker expressions", and neither the field docs nor the spec says which variables are in scope.

So the intent decides the shape, and both are small:

  1. Extras and groups are out of scope here. Then a lock file that mentions them in environments is not valid input, and what is missing is a clear diagnostic instead of UndefinedEnvironmentName from Marker.evaluate. I would retarget this PR to raise that error at the environments check and leave the marker context alone.
  2. They are in scope. Then the change is the one line at src/packaging/pylock.py:747 — evaluate with the env that select() has already built (it carries extras and dependency_groups), which is what this branch does.

Tell me which one you want and I will do it in one commit. If it is 1 but you would rather leave today's exception as it is, say so and I will close this instead of keeping it open.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants