mafw.devtools.dependencies.freeze

Dependency freezing and unfreezing utilities for MAFw.

This module provides functions for adding and removing computed upper-bound constraints in pyproject.toml dependency declarations. It is used by the release workflow to pin dependencies during release and unpin them afterwards.

Functions

compute_upper_bound(lower_bound)

Compute an upper bound for a dependency based on PEP 440 compatible-release philosophy.

format_requirement(requirement)

Serialize a packaging requirement object back to a PEP 508 compatible string.

freeze_dependencies(*, dry_run)

Freeze dependencies by adding computed upper bounds in pyproject.toml.

freeze_pyproject_toml(toml_text, *[, ...])

Freeze dependencies in a pyproject.toml payload by adding upper bounds.

freeze_requirement(requirement_text, *[, ...])

Add a computed upper bound to a requirement string, if eligible.

has_frozen_upper_bound(requirement)

Determine whether a requirement already contains an upper bound constraint.

highest_lower_bound(requirement)

Extract the highest lower-bound version from >= and > specifiers.

iter_specifiers(requirement)

Return a concrete list of specifiers for the given requirement.

summarize_freeze_changes(before, after)

Build a short summary for dry-run output.

unfreeze_dependencies(...)

Unfreeze dependencies by removing computed upper bounds in pyproject.toml.

unfreeze_pyproject_toml(toml_text, *[, ...])

Unfreeze dependencies in a pyproject.toml payload by removing computed upper bounds.

unfreeze_requirement(requirement_text)

Remove a computed upper bound from a requirement string, if it matches the computed rule.

update_dependency_list(dependencies, *, ...)

Update a TOML list of dependency strings in-place.

update_requirements_and_readme(*, dry_run)

Update the requirements RST files and README.rst.

mafw.devtools.dependencies.freeze.compute_upper_bound(lower_bound: str) str[source]

Compute an upper bound for a dependency based on PEP 440 compatible-release philosophy.

The rule implemented here is purposely conservative and mirrors the intent of compatible release clauses while remaining explicit:

  • For major-versioned releases (X.* with X > 0), freeze to <(X + 1).

  • For 0.* releases, freeze to <0.(minor + 1) (rolling compatibility during pre-1.0).

Parameters:

lower_bound (str) – Version string used as the starting point for the freeze rule.

Returns:

Upper-bound version string without operator.

Return type:

str

Raises:

DevtoolsError – If the version cannot be parsed.

mafw.devtools.dependencies.freeze.format_requirement(requirement: Requirement) str[source]

Serialize a packaging requirement object back to a PEP 508 compatible string.

Parameters:

requirement (Requirement) – Parsed requirement instance.

Returns:

PEP 508 requirement string.

Return type:

str

mafw.devtools.dependencies.freeze.freeze_dependencies(*, dry_run: bool) str[source]

Freeze dependencies by adding computed upper bounds in pyproject.toml.

Parameters:

dry_run (bool) – Whether command execution is disabled.

Returns:

Original pyproject.toml content captured before freeze.

Return type:

str

mafw.devtools.dependencies.freeze.freeze_pyproject_toml(toml_text: str, *, resolved_versions: dict[str, Version] | None = None, doc: TOMLDocument | None = None) tuple[str, list[str]][source]

Freeze dependencies in a pyproject.toml payload by adding upper bounds.

The TOML structure is preserved via tomlkit; only dependency strings may be normalized.

When resolved_versions is provided, the function uses those compiled versions as the basis for upper-bound computation. Otherwise the declared lower bounds are used as a fallback.

Parameters:
  • toml_text (str) – Raw TOML file content.

  • resolved_versions (dict[str, Version] | None) – Optional mapping of dependency names to resolved versions.

  • doc (tomlkit.TOMLDocument | None) – Optional pre-parsed TOML document to reuse when available.

Returns:

Updated TOML plus warnings.

Return type:

tuple[str, list[str]]

Raises:

DevtoolsError – If TOML parsing fails.

mafw.devtools.dependencies.freeze.freeze_requirement(requirement_text: str, *, resolved_version: str | None = None) tuple[str, list[str]][source]

Add a computed upper bound to a requirement string, if eligible.

The function is intentionally conservative:

  • URL-based requirements are skipped (cannot be version constrained).

  • Requirements already containing <, <=, ~=, == or === are skipped.

  • Requirements without a lower bound emit a warning and are left unchanged.

  • When a resolved version is provided, the upper bound is computed from that version instead of the declared lower bound.

Parameters:

requirement_text (str) – Raw PEP 508 requirement string.

Returns:

Updated requirement text plus warnings.

Return type:

tuple[str, list[str]]

Raises:

DevtoolsError – If parsing fails.

mafw.devtools.dependencies.freeze.has_frozen_upper_bound(requirement: Requirement) bool[source]

Determine whether a requirement already contains an upper bound constraint.

Parameters:

requirement (Requirement) – Parsed requirement instance.

Returns:

True if the requirement is already frozen.

Return type:

bool

mafw.devtools.dependencies.freeze.highest_lower_bound(requirement: Requirement) str | None[source]

Extract the highest lower-bound version from >= and > specifiers.

Parameters:

requirement (Requirement) – Parsed requirement instance.

Returns:

Highest lower bound version string, or None if missing.

Return type:

str | None

Raises:

DevtoolsError – If version parsing fails.

mafw.devtools.dependencies.freeze.iter_specifiers(requirement: Requirement) list[Specifier][source]

Return a concrete list of specifiers for the given requirement.

Parameters:

requirement (Requirement) – Parsed requirement instance.

Returns:

List of specifier objects.

Return type:

list[Specifier]

mafw.devtools.dependencies.freeze.summarize_freeze_changes(before: str, after: str) str[source]

Build a short summary for dry-run output.

Parameters:
  • before (str) – Original TOML content.

  • after (str) – Updated TOML content.

Returns:

Human-readable summary line.

Return type:

str

mafw.devtools.dependencies.freeze.unfreeze_dependencies(original_pyproject_toml: str, *, dry_run: bool) None[source]

Unfreeze dependencies by removing computed upper bounds in pyproject.toml.

Parameters:

dry_run (bool) – Whether command execution is disabled.

mafw.devtools.dependencies.freeze.unfreeze_pyproject_toml(toml_text: str, *, baseline_toml_text: str | None = None, doc: TOMLDocument | None = None, baseline_doc: TOMLDocument | None = None) tuple[str, list[str]][source]

Unfreeze dependencies in a pyproject.toml payload by removing computed upper bounds.

Only upper bounds matching the computed rule are removed; existing manual constraints remain.

Parameters:
  • toml_text (str) – Raw TOML file content.

  • baseline_toml_text (str | None) – Optional original TOML text captured before freezing. When provided, unfreezing is computed against the baseline to avoid altering dependencies that were already frozen before release.

  • doc (tomlkit.TOMLDocument | None) – Optional pre-parsed TOML document to reuse when available.

  • baseline_doc (tomlkit.TOMLDocument | None) – Optional pre-parsed baseline TOML document to reuse when available.

Returns:

Updated TOML plus warnings.

Return type:

tuple[str, list[str]]

Raises:

DevtoolsError – If TOML parsing fails.

mafw.devtools.dependencies.freeze.unfreeze_requirement(requirement_text: str) tuple[str, list[str]][source]

Remove a computed upper bound from a requirement string, if it matches the computed rule.

Only the auto-generated upper bound <upper is removed; existing manual upper bounds are preserved.

Parameters:

requirement_text (str) – Raw PEP 508 requirement string.

Returns:

Updated requirement text plus warnings.

Return type:

tuple[str, list[str]]

Raises:

DevtoolsError – If parsing fails.

mafw.devtools.dependencies.freeze.update_dependency_list(dependencies: Any, *, transformer: Callable[[str], tuple[str, list[str]]], warnings: list[str], context: str) None[source]

Update a TOML list of dependency strings in-place.

Parameters:
  • dependencies (Any) – TOML array that contains dependency strings.

  • transformer (Any) – Callable applied to each dependency string.

  • warnings (list[str]) – List of warnings to append to.

  • context (str) – Human-readable location for warnings.

mafw.devtools.dependencies.freeze.update_requirements_and_readme(*, dry_run: bool) None[source]

Update the requirements RST files and README.rst.

Parameters:

dry_run (bool) – Whether command execution is disabled.

mafw.devtools.dependencies.freeze._FROZEN_OPERATORS: Final[set[str]] = {'<', '<=', '==', '===', '~='}

Operators that already constrain the maximum compatible version and should not be auto-frozen.