models.dependencies

Dependency-entry parsing and constraint satisfiability for [dependencies].

Pure module (stdlib only): deliberately free of otto.config imports so models.settings can use it at validation time — like the duplicated version regex, models/ must never trigger the config package’s import-time surface.

Constraint semantics: clauses compare zero-padded (major, minor, patch) integer triples; a Version’s extra tag never participates, and the grammar rejects extra tags inside clauses to keep that promise enforceable.

otto.models.dependencies.normalize_name(name: str) str

PEP-503-style normalization: lowercase, collapse [-_.]+ runs to -.

class otto.models.dependencies.DependencyClause(op: '==' | '!=' | '>=' | '<=' | '>' | '<', version: tuple[int, int, int])

Bases: object

One constraint clause: an operator against a zero-padded version triple.

op : Literal['==', '!=', '>=', '<=', '>', '<']
version : tuple[int, int, int]
matches(key: tuple[int, int, int]) bool

Check whether key (a Version’s major/minor/patch triple) satisfies this clause.

class otto.models.dependencies.ParsedDependency(raw: str, name: str, normalized: str, constraint: str, clauses: list[DependencyClause], required: bool)

Bases: object

One parsed [dependencies] entry.

raw : str

The entry as written (stripped).

name : str

Declared project name, pre-normalization.

normalized : str

PEP-503-normalized name used for matching.

constraint : str

Clause text after the name ("" = any version).

clauses : list[DependencyClause]

Parsed comma-ANDed clauses (empty = any version).

required : bool

True for a required entry, False for optional.

otto.models.dependencies.parse_dependency_entry(entry: str, *, required: bool) ParsedDependency

Parse "name" or "name <op> N[.N[.N]], ..."; raise ValueError if malformed.

otto.models.dependencies.clauses_satisfiable(clauses: Sequence[DependencyClause]) bool

Check if at least one version triple satisfies every clause.

Exactly decidable over integer triples: fold clauses into a lower bound, an upper bound, == pins and != exclusions. Empty iff the bounds cross, pins conflict (with each other, the bounds, or an exclusion), or the bounds confine the range to a finite point set (identical major.minor) fully covered by exclusions — an upper-unbounded or major/minor-spanning range is infinite, which no finite exclusion set can empty.