tests.test_dep_sources module¶
Tests for the git-to-release dependency source swaps and the release gate.
- tests.test_dep_sources.PYPROJECT = '[project]\nname = "basket"\nversion = "1.0.0"\ndependencies = [\n "cherry>=1.2",\n "mango[fresh]>=2.1.0.dev0; python_version >= \'3.10\'",\n]\n\n[project.optional-dependencies]\njuice = [\n "mango[pressed]",\n]\n\n[dependency-groups]\ndocs = [\n "papaya>=3.0",\n]\ntest = [\n "mango>=2.1.0.dev0",\n { include-group = "docs" },\n]\n\n[tool.uv]\nexclude-newer = "1 week"\nexclude-newer-package = { mango = "2026-01-05T00:00:00Z" }\n\n[tool.uv.sources]\nmango = { git = "https://github.com/acme/mango", branch = "main" }\npapaya = { git = "https://github.com/acme/papaya", rev = "1234abcd" }\n'¶
A project tracking
mango’s main branch while awaiting its2.1.0release.papayais pinned to an exact commit andcherryis a plain registry dependency: both sit outside the managed idiom.
- tests.test_dep_sources.test_tracked_git_overrides_selects_branch_tracks(tmp_path)[source]¶
Only single-source git entries with a branch are considered tracked.
- tests.test_dep_sources.test_dev_floor_takes_highest_dev_bound(tmp_path)[source]¶
The floor is the highest
.devlower bound across every table.
- tests.test_dep_sources.test_strip_dev_bounds(requirement, release, expected)[source]¶
Only matching
.devlower bounds are tightened, byte-for-byte.
- tests.test_dep_sources.test_find_ready_swaps_adopts_newest_stable(tmp_path, monkeypatch)[source]¶
A stable release satisfying the floor makes the swap ready.
- tests.test_dep_sources.test_find_ready_swaps_needs_positive_confirmation(tmp_path, monkeypatch, releases)[source]¶
Anything short of a live stable release keeps the git track in place.
- tests.test_dep_sources.test_find_ready_swaps_skips_floorless_overrides(tmp_path, monkeypatch)[source]¶
A branch track without a dev floor is outside the managed idiom.
- tests.test_dep_sources.test_apply_release_swaps_rewrites_pyproject(tmp_path)[source]¶
The override is dropped and every dev floor tightened, nothing else.
- tests.test_dep_sources.test_apply_release_swaps_drops_emptied_sources_table(tmp_path)[source]¶
Removing the last override removes the
[tool.uv.sources]table too.
- tests.test_dep_sources.test_format_swap_section()[source]¶
One row per swap, with branch, adopted release, and ship date.
- tests.test_dep_sources.test_floors_inside_cooldown(tmp_path, requirement, floor, locked, age_days, flagged)[source]¶
Only a floor demanding a release inside the window is reported.
- Return type:
- tests.test_dep_sources.test_dependency_floors_clear_the_cooldown()[source]¶
No dependency floor requires a release still inside the cooldown.
Such a floor makes the published package uninstallable for anyone resolving it from an index: a downstream repo running a frozen workflow’s
uvx 'repomatic==X.Y.Z', or an end user runninguvx repomatic. Neither can seeuv.lockor[tool.uv] exclude-newer-package, and uv has no environment variable for a per-package exemption, so they have nowhere to record a bypass.This repository’s own CI cannot catch it, because it installs from
uv.lockand resolves straight through the local exemption. That is what makes this a release gate rather than a CI symptom. Wait for a release to clear the window before raising a floor onto it.- Return type:
- tests.test_dep_sources.SHIPPABLE_PYPROJECT = '[build-system]\nrequires = [ "uv-build>=0.8" ]\n\n[project]\nname = "basket"\nversion = "1.0.0"\ndependencies = [ "cherry>=1.2" ]\n\n[project.optional-dependencies]\njuice = [ "papaya>=3" ]\n\n[dependency-groups]\ntest = [ "mango>=2" ]\n'¶
A project whose every dependency resolves from PyPI.
Each rule below appends its own offending declaration to this base, so a finding can only come from what the test added.
- tests.test_dep_sources.test_clean_project_reports_nothing(tmp_path)[source]¶
A project resolving everything from PyPI has no findings.
- Return type:
- tests.test_dep_sources.test_unshippable_sources_block(tmp_path, extra, package, kind)[source]¶
Every way of resolving a dependency off-index blocks a release.
- Return type:
- tests.test_dep_sources.test_direct_references_block_in_every_table(tmp_path, table)[source]¶
A PEP 508 direct reference blocks wherever it is declared.
The
v5.0.0release shipped one in an extra, which PyPI refused at upload after the tag and the GitHub release had already been created.- Return type:
- tests.test_dep_sources.test_per_platform_source_list_reports_once_per_kind(tmp_path)[source]¶
A marker-split override is one finding, not one per platform.
- Return type:
- tests.test_dep_sources.test_pypi_element_does_not_mask_a_private_one(tmp_path)[source]¶
Deduplication must not let a clean list element hide a dirty one.
Both elements classify as an index source, and the PyPI one is skipped without reporting. Recording it as seen anyway would swallow the private index that follows it.
- Return type:
- tests.test_dep_sources.test_pypi_index_source_is_shippable(tmp_path)[source]¶
An explicit index entry pointing at PyPI is not a finding.
- Return type:
- tests.test_dep_sources.test_allowlist_downgrades_without_hiding(tmp_path)[source]¶
An allowed package still reports, carrying its reason, but stops blocking.
- Return type:
- tests.test_dep_sources.test_resolution_overrides_warn_without_blocking(tmp_path)[source]¶
override-dependenciesdiverges the tested tree without breaking installs.- Return type:
- tests.test_dep_sources.test_lock_catches_what_pyproject_never_names(tmp_path)[source]¶
A transitively-pulled git source shows up even with a clean pyproject.
This is why the gate reads the lock as well as the declarations: a source override can name a package no requirement array mentions, and only the resolved tree records it. The project’s own
editable = "."entry is not a dependency and is skipped.- Return type:
- tests.test_dep_sources.test_a_package_is_reported_once(tmp_path)[source]¶
A source flagged by both halves keeps the actionable pyproject finding.
- Return type:
- tests.test_dep_sources.test_consequence_distinguishes_broken_from_divergent(tmp_path, floor, expected)[source]¶
The report separates a failing install from a silently different one.
- Return type:
- tests.test_dep_sources.test_release_readiness_flips_the_pr_opening(tmp_path)[source]¶
The release PR announces readiness only while the project has it.
- Return type:
- tests.test_dep_sources.test_countdown_links_a_job_that_still_exists(branch)[source]¶
Each countdown link points at a job that still opens pull requests.
The link is a search over the job’s pull request branch, and that branch is the template name. Renaming or dropping a template would leave the banner pointing at a query nothing ever matches, which reads as “nothing is coming” rather than as a broken link.
- Return type:
- tests.test_dep_sources.test_countdown_links_the_job_that_lifts_each_blocker(tmp_path)[source]¶
A dated blocker points at
sync-uv-lock, an awaited one at the swap.Both jobs report the same clearing date from the same two numbers the banner reads: the locked release’s upload time, and the
exclude-newerspan. The link is what takes the reader from the verdict to that report.- Return type:
- tests.test_dep_sources.test_release_pr_reserves_caution_for_the_unguarded_step(tmp_path)[source]¶
The release PR’s two alerts rank by what else would catch the mistake.
Squash and mergeis a warning because the release lane catches it anyway:detect-squash-mergein_release-build.yamlfires on the collapsed history and files the recovery. Merging a blocked release has no such backstop on the merge itself, and by the timelint-depsfails in the release lane the freeze commit is onmainand the version has to be burned. So the caution is spent on the step nothing else guards, and the template must not spend it anywhere else.- Return type:
- tests.test_dep_sources.test_project_ships_only_released_dependencies()[source]¶
This repository can be released as it stands.
The generalization of
test_dependency_floors_clear_the_cooldownabove: that one covers a floor the cooldown makes unreachable, this one covers every other way a dependency fails to reach the people installing the published artifact. Both are release gates rather than CI symptoms, since this repository’s own workflows install fromuv.lockand resolve straight past the problem.The same check runs in the release lane (
_release-build.yaml’slint-depsjob) and in the release PR body, so this is the local copy of a gate that also holds downstream. Its value here is latency: apytestrun says so in milliseconds, where CI takes minutes and the release PR banner needs a push.- Return type: