repomatic.deps.sources module¶
Swap git-tracked dependencies back to their released versions.
The sync-dep-sources updater manages one precise idiom: a dependency
temporarily consumed from a git branch while its next release is awaited.
The idiom is machine-recognizable because it pairs two declarations in
pyproject.toml:
a
[tool.uv.sources]entry tracking a branch (not arevortagpin), anda dev-version floor on the same package (like
mango>=2.1.0.dev0), whose base version names the awaited release.
Once the awaited release ships on the index, the swap rewrites the project
back to released artifacts: the source override is dropped, the .dev floor
is tightened to its base release, and a cooldown-bypass freeze adopts the
release through the exclude-newer window (the same deliberate-bypass
mechanism audit --fix uses for security fixes). The freeze then ages out
and is pruned by the ordinary sync-uv-lock lifecycle.
Note
The dev floor is authoritative, deliberately: the project declares that
anything from the awaited release onward satisfies it. If the project
quietly grew a dependency on branch commits newer than the release, the swap
PR’s CI run exposes the stale declaration, and the correction (bumping the
floor to the next .dev version, which retracts the swap on the next run)
is exactly the fix the project needed anyway. Overrides outside the idiom
(path or workspace sources, rev/tag pins, floor-less branch tracks) are
never touched.
The release gate that refuses to ship while such an override stands lives in
repomatic.deps.shippable.
- repomatic.deps.sources.DEV_BOUND_PATTERN = re.compile('(?P<op>>=?)\\s*(?P<version>[0-9][A-Za-z0-9.!+]*)')¶
Lower-bound clauses in a PEP 508 requirement string.
Captures the operator and the version literal so
strip_dev_bounds()can rewrite>=2.1.0.dev0into>=2.1.0in place, leaving extras, markers, and every other clause byte-for-byte untouched.
- class repomatic.deps.sources.ReleaseSwap(name, source_key, branch, floor, release, released)[source]¶
Bases:
objectA git-tracked dependency whose awaited release has shipped.
Built by
find_ready_swaps(); consumed byapply_release_swaps()(thepyproject.tomlrewrite) andformat_swap_section()(the PR report).- source_key: str¶
The entry key as written in
[tool.uv.sources](may differ fromnamein case or separators).
- property freeze_cutoff: str¶
The
exclude-newer-packagecutoff adoptingrelease.Delegates the margin policy to
repomatic.deps.cooldown.freeze_cutoff_after(): every distribution file of the adopted release sits inside the window even when its uploads straddle midnight, while the global cooldown still shields anything newer.
- repomatic.deps.sources.tracked_git_overrides(doc)[source]¶
Read the
[tool.uv.sources]entries tracking a git branch.Only single-source entries carrying both a
gitURL and abranchare returned: arevortagpin is a deliberate point-in-time choice, a path or workspace source is a local development arrangement, and a multi-source list (per-platform markers) is too bespoke to rewrite. None of those encode “waiting for the next release”.
- repomatic.deps.sources.find_ready_swaps(doc)[source]¶
Probe the index for git-tracked packages whose awaited release shipped.
For each branch-tracking override inside the managed idiom, the awaited release is considered shipped once PyPI carries a stable (non-prerelease, non-yanked) version satisfying the dev floor. The newest such release is adopted. Index misses (an unpublished package, a network failure) read as “not ready”: a swap needs positive confirmation, so the failure mode is always a skipped run, never a wrong rewrite.
- Parameters:
- Return type:
- Returns:
Ready swaps sorted by package name; empty when there is nothing to do.
- repomatic.deps.sources.strip_dev_bounds(requirement, release)[source]¶
Tighten a requirement string’s
.devlower bounds to their release.Rewrites only the version literal of
>=/>clauses whose version is a dev release older than or equal to release, replacing it with its base version (>=2.1.0.dev0becomes>=2.1.0). Everything else in the string (extras, markers, other clauses, spacing) is preserved byte-for-byte.
- repomatic.deps.sources.apply_release_swaps(doc, swaps)[source]¶
Rewrite a parsed
pyproject.tomlfor the given swaps, in place.Two of the three swap edits happen here: the
[tool.uv.sources]override is removed (and the emptied table with it), and every.devfloor on the swapped packages is tightened to its base release. The third edit, the cooldown-bypass freeze atReleaseSwap.freeze_cutoff, goes throughrepomatic.deps.cooldown.UvSettings.upsert()so the insertion position and inline-table formatting stay canonical.- Parameters:
doc (
Any) – The editable document, asrepomatic.deps.cooldown.UvSettings.docholds it.swaps (
list[ReleaseSwap]) – Ready swaps fromfind_ready_swaps().
- Return type:
- repomatic.deps.sources.SWAP_SECTION_NOTE = 'Dependencies tracked from a git branch while awaiting a release, swapped back to the package index: the `[tool.uv.sources]` override is dropped, the `.dev` version floor is tightened to its release form, and a cooldown bypass freezes the adoption until it ages past the [`exclude-newer`](https://docs.astral.sh/uv/reference/settings/#exclude-newer) cutoff.'¶
Intro paragraph for the
sync-dep-sourcesswap section.
- repomatic.deps.sources.format_swap_section(swaps, *, name_urls=None, reference_date=None)[source]¶
Format the release swaps as a markdown section.
The
sync-dep-sourcesreport section explaining thepyproject.tomlhunks: one row per swapped package, with the branch it tracked, the release it adopted, and when that release shipped.- Parameters:
swaps (
list[ReleaseSwap]) – Ready swaps fromfind_ready_swaps().name_urls (
Mapping[str,str] |None) – Optional mapping of names to a URL the name links to. Names absent from the mapping render plain.reference_date (
date|None) – When set, the “Released” date gains a relative hint measured from this date.
- Return type:
- Returns:
A markdown string with a
## 🔀 Source swapsheading and table, or an empty string when swaps is empty.