Open-Source Wikis

/

uv

/

Crates

/

uv-pep508

astral-sh/uv

uv-pep508

crates/uv-pep508/ implements PEP 508 plus uv's non-PEP 508 extensions. It parses requirement strings (`requests[security] >=2; python_version

= "3.8"`) and the markers attached to them, and provides arithmetic and rendering for both.

It was imported in October 2023 from the standalone pep508-rs crate (#32) and absorbed into the workspace during the rename to uv in early 2024.

Purpose

Provide a battle-tested PEP 508 parser/printer for:

  • Requirements with optional version specifiers, extras, URLs, and markers.
  • MarkerEnvironments (the runtime values of python_version, sys_platform, etc.).
  • MarkerTrees (a normalized DNF / CNF representation of marker expressions).
  • VerbatimUrls (URLs that round-trip with their original syntax preserved for diagnostics).
  • The non-pep508-extensions feature: variable-arity in/notin and a few extensions uv uses internally.

Directory layout

crates/uv-pep508/src/
├── lib.rs              # 62k chars: Requirement, ExtraName/PackageName parsing, public API
├── verbatim_url.rs     # 31k chars: VerbatimUrl + ParsedUrl (preserve original syntax)
├── unnamed.rs          # UnnamedRequirement (URL-only without a package name)
├── marker/             # MarkerTree, MarkerEnvironment, MarkerExpression
├── origin.rs           # RequirementOrigin (pyproject.toml? requirements.txt? CLI?)
└── cursor.rs           # Tiny string cursor used by the hand-rolled parser

Key abstractions

Type File Role
Requirement lib.rs A complete requirement: name, extras, version specifier, URL, marker.
MarkerEnvironment marker/ The runtime environment values (PEP 508 §6) used to evaluate a MarkerTree.
MarkerTree marker/ Normalized boolean tree of marker expressions; supports intersection, conjunction, simplification.
MarkerExpression marker/ A leaf marker like python_version >= "3.8".
MarkerOperator marker/ The operator: ==, !=, <=, >=, <, >, ~=, in, not in.
MarkerValueString marker/ The right-hand side of a marker (a literal or a variable).
VerbatimUrl verbatim_url.rs A URL that also remembers its original textual form.
UnnamedRequirement unnamed.rs A requirement specified by URL only.
RequirementOrigin origin.rs Where a requirement came from (a path, a CLI flag, …). Used in error messages.

How it works

Parsing

The parser is hand-written using a small Cursor over the input bytes (cursor.rs). It is strict by default but accepts a few uv-specific extensions when the non-pep508-extensions feature is enabled (which is the default in the workspace):

  • Multi-value in / not in operators.
  • Specific recovery rules for malformed but obviously-intended inputs.

Errors carry byte offsets so they can be displayed with miette underlines.

Markers

MarkerTree is the most subtle part. Operations like tree.evaluate(env) are simple, but the resolver also needs:

  • Conjunction (tree.and(other)) and disjunction (tree.or(other)).
  • Negation (!tree).
  • Implication / containment (does tree A imply tree B?).
  • Simplification ((python_version >= "3.8") & (python_version >= "3.9")python_version >= "3.9").
  • Universal evaluation ("does this tree hold for every environment in this set?"), used during forking.

The implementation uses BDD-style canonicalization plus PEP 508-aware specializations for python_version, python_full_version, sys_platform, os_name, platform_machine, and the various other markers.

VerbatimUrl

Because uv has to reproduce user input in error messages and lockfiles, plain url::Url is not enough — it normalizes paths and percent-encodings. VerbatimUrl stores the original string alongside the parsed Url so that round-tripping is exact.

ParsedUrl (in crates/uv-pypi-types/) builds on VerbatimUrl to classify URLs into git/path/archive forms.

Integration points

  • uv-pep440 for Version and VersionSpecifiers.
  • uv-resolver for marker arithmetic during forking and conflict marker construction.
  • uv-pypi-types consumes Requirement/UnnamedRequirement and re-exports them.
  • uv-requirements-txt parses pip-style requirements files into Requirements.
  • uv-workspace parses pyproject.toml requirements.

Entry points for modification

  • Add a new marker variablemarker/. Each new variable needs:
    1. A token in the parser.
    2. A field on MarkerEnvironment.
    3. Comparison logic in evaluation and simplification.
  • Extend the requirement grammarlib.rs. Be careful: most requirement strings come from the wild and any change risks breaking real-world packages.
  • Improve marker simplificationmarker/. The resolver benefits directly: smaller marker trees mean smaller lockfiles and faster forks.

Key source files

File Purpose
crates/uv-pep508/src/lib.rs The Requirement type and parser.
crates/uv-pep508/src/verbatim_url.rs VerbatimUrl for byte-faithful URL display.
crates/uv-pep508/src/marker/ The marker subsystem.
crates/uv-pep508/src/cursor.rs The byte-oriented cursor used by the parser.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

uv-pep508 – uv wiki | Factory