Document conditional dependencies and installable extras - #100
Merged
Conversation
Release notes for 0.13.23. A manual section on each: how a distribution may be declared more than once under mutually exclusive markers and what validation then requires of it, and how install_dependencies_extras selects groups for installation without changing what is published. The plugin reference gains the property with its accepted values, and its extra and markers rows are rewritten - the extra row documented extras as something only a downstream consumer could ever install, which is no longer the whole story. The project-info page gains the new extra key and says how it differs from the extras already there. The tutorial gains a short section on both shapes, and the coding agents guide the two declarations an agent is now likely to need to write.
arcivanov
added a commit
to pybuilder/pybuilder
that referenced
this pull request
Sep 13, 2026
…lease] (#950) Declaring the same distribution twice under different environment markers silently lost one of them. Markers took no part in a dependency's identity, so the two collided in the set that holds them and a Windows-only dependency would disappear because a Linux-only one had been declared first. Declaring it correctly did not help either, since validation counted by name alone and a per-interpreter pin was therefore a build failure. Separately, extras groups could be declared but never installed, so the code an extra guards could not be tested. ## Conditional duplicates Markers now participate in identity, compared in canonical form so that expressions differing only in quoting or whitespace remain one declaration rather than becoming two. Validation groups same-named declarations and reports a duplicate only where two of them apply at once, or where two carry identical conditions and so can never be told apart. Both declarations are published, each with its own marker; only the one that applies is installed, and only it reaches the constraints file. That last part matters because pip drops constraint lines whose markers do not hold but intersects everything else, so two live entries on one name became a `ResolutionImpossible` naming neither of them. PyBuilder decides it first, and says which declarations disagree. Markers are evaluated against the marker environment of the **target** interpreter rather than of the one running the build. `PythonEnv.marker_env` carries it, probed from that interpreter with the vendored `packaging`, whose `default_environment()` is itself the enumeration of PEP 508 variables and so leaves no list to maintain. The vendor directory travels to the probe as an argument rather than on `PYTHONPATH`, because the probe captures `os.environ` verbatim and PyBuilder reuses that capture for every later command run in that environment. ## Installable extras The new `install_dependencies_extras` property selects groups for installation (a name, a list of names, or `"*"`) and feeds the `build` and `test` venvs along with the install tasks. Naming a group the project does not declare fails validation and lists the ones it does. `project.dependencies` composes the base dependencies with the selected groups; the new `project.base_dependencies` returns the base ones alone and is what generates `install_requires` and `dependency_links`, so selecting an extra in order to test it never makes it a mandatory requirement of the published distribution. Asking for an extra was also a no-op on incremental builds. Nothing in installed metadata records which extras were requested (a `dist-info` is byte-identical whether or not one was, and `direct_url.json` has no field for it), so with the distribution already installed at a satisfying version the extra was skipped and its requirements never arrived. What an extra requires is now resolved from the installed distribution's own metadata and checked, which is why `get_packages_info` carries a per-extra requirement map and evaluates it against the target environment. Where the installed version no longer offers the extra at all, that is reported and the dependency handed to pip. ## Fixed in passing A marker containing quotes generated a **syntactically invalid `setup.py`**, because the rendered requirement was interpolated into single quotes of its own and markers are conventionally written with single quotes. This has affected every project spelling a marker the ordinary way (`sys_platform == 'win32'`) since markers shipped in 0.13.19. Values are now rendered as proper Python literals, which also covers backslashes. Also, `install_requires` dropped a dependency's own extras, and extras group names went unnormalized, so `extra="Security"` and `extra="security"` were emitted as two groups. ## Verification Full `pyb analyze publish` green: 848 unit tests, 60 integration tests, flake8 clean, coverage 85% → 86%. Two new integration tests cover the generated `setup.py` and constraints file for conditional declarations, and extras actually landing in the venvs. Documentation changes are in pybuilder/pybuilder.github.io#100.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documents the conditional-dependency and installable-extras work in pybuilder/pybuilder (branch
dependency-markers-and-extras).articles/_release-notes/v0.13.x.md): new 0.13.23 section covering the new features, the changedproject.dependenciessemantics, and the bugs fixed.extraandmarkersrows fordepends_on, plus the newinstall_dependencies_extrasproperty.extrakey now emitted bypyb -i.