Skip to content

Commit fc4fb14

Browse files
docs(python): add high-level dependency validation comments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ec650d0 commit fc4fb14

File tree

3 files changed

+18
-0
lines changed

3 files changed

+18
-0
lines changed

.github/workflows/python-dependency-range-validation.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ jobs:
3333

3434
- name: Run dependency range validation
3535
id: validate_ranges
36+
# Keep workflow running so we can still publish diagnostics from this run.
3637
continue-on-error: true
3738
run: uv run poe validate-dependency-ranges
3839
working-directory: ./python
3940

4041
- name: Upload dependency range report
42+
# Always publish the report so failures are inspectable even when validation fails.
4143
if: always()
4244
uses: actions/upload-artifact@v4
4345
with:
@@ -46,6 +48,7 @@ jobs:
4648
if-no-files-found: warn
4749

4850
- name: Create issues for failed dependency candidates
51+
# Always process the report so failed candidates create actionable tracking issues.
4952
if: always()
5053
uses: actions/github-script@v8
5154
with:
@@ -160,6 +163,7 @@ jobs:
160163
}
161164
162165
- name: Refresh lockfile
166+
# Only refresh lockfile after a clean validation to avoid committing known-bad ranges.
163167
if: steps.validate_ranges.outcome == 'success'
164168
run: uv lock --upgrade
165169
working-directory: ./python
@@ -186,6 +190,7 @@ jobs:
186190
echo "has_changes=true" >> "$GITHUB_OUTPUT"
187191
188192
- name: Create or update pull request with GitHub CLI
193+
# Only open/update PRs for validated updates to keep automation branches trustworthy.
189194
if: steps.validate_ranges.outcome == 'success' && steps.commit_updates.outputs.has_changes == 'true'
190195
run: |
191196
BRANCH="automation/python-dependency-range-updates"

python/scripts/validate_dependency_lower_bounds.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ def _optimize_dependency(
578578
attempted_versions: list[str] = []
579579
attempts: list[DependencyAttempt] = []
580580

581+
# Establish a validated baseline before searching for lower acceptable bounds.
581582
baseline_version = dependency.lower_version
582583
attempted_versions.append(str(baseline_version))
583584
print(f"[cyan]{package_label} :: {dependency.name} :: baseline current_lower [{baseline_version}] [/cyan]")
@@ -637,6 +638,7 @@ def _optimize_dependency(
637638
skipped_reason="No lower candidate bounds found within allowed boundary.",
638639
)
639640

641+
# Probe older bounds with a binary-search-style loop: keep successful tighter lowers, revert failures.
640642
low = 0
641643
high = len(candidates) - 1
642644
while low <= high:
@@ -710,6 +712,7 @@ def _process_package(
710712
skipped=["No check/test task combination found."],
711713
)
712714

715+
# Build the per-package optimization target set from eligible bounded dependency specifications.
713716
targets, skipped = _collect_targets(pyproject_file, dependency_filters=dependency_filters)
714717
if not targets:
715718
return PackageOutcome(
@@ -758,6 +761,7 @@ def _process_package(
758761
if candidate.exists():
759762
temp_internal_editables.append(candidate)
760763

764+
# Execute lower-bound trials per dependency and accumulate final replacement strings for persistence.
761765
dependency_results: list[DependencyOutcome] = []
762766
replacements: dict[str, str] = {}
763767
package_label = f"{plan.project_path} ({plan.package_name})"
@@ -893,6 +897,7 @@ def main() -> None:
893897
dependency_filters = {name.lower() for name in args.dependencies} if args.dependencies else None
894898
output_json_path = (workspace_root / args.output_json).resolve()
895899

900+
# Phase 1: prepare shared workspace metadata and collect package execution plans.
896901
package_map = _build_workspace_package_map(workspace_root)
897902
internal_graph = _build_internal_graph(workspace_root, package_map)
898903
lock_versions = _load_lock_versions(workspace_root)
@@ -927,6 +932,7 @@ def main() -> None:
927932
print("[yellow]No packages matched the selection.[/yellow]")
928933
return
929934

935+
# Phase 2: initialize incremental report state before running package validations in parallel.
930936
report: dict = {
931937
"started_at": _utc_now(),
932938
"workspace_root": str(workspace_root),
@@ -978,6 +984,7 @@ def main() -> None:
978984
if outcome.changed and not args.dry_run:
979985
_apply_package_replacements(plan.pyproject_path, outcome.replacements)
980986

987+
# Phase 3: aggregate outcomes, persist incremental JSON snapshots, and emit per-package progress.
981988
report["packages"].append(_to_json(outcome))
982989
report["summary"]["packages_changed"] = sum(1 for value in package_outcomes if value.changed)
983990
report["summary"]["dependencies_changed"] = sum(

python/scripts/validate_dependency_ranges.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ def _optimize_dependency(
576576
include_dev_group: bool,
577577
include_dev_extra: bool,
578578
) -> DependencyOutcome:
579+
# Build descending candidate trial bounds from the current constraint window.
579580
candidates = _build_trial_bounds(
580581
available_versions,
581582
lower=dependency.lower_version,
@@ -674,6 +675,7 @@ def _optimize_dependency(
674675
skipped_reason="No higher candidate bounds found.",
675676
)
676677

678+
# Probe candidates from highest to lowest; keep the first passing upper-bound rewrite.
677679
for candidate in candidates:
678680
attempted_versions.append(str(candidate))
679681
trial_requirements = [entry.with_upper(candidate) for entry in dependency.entries]
@@ -793,6 +795,7 @@ def _process_package(
793795
replacements: dict[str, str] = {}
794796
package_label = f"{plan.project_path} ({plan.package_name})"
795797

798+
# Run per-dependency trial generation + validation in the isolated temp workspace.
796799
for target in targets:
797800
versions = catalog.get(target.name)
798801
outcome = _optimize_dependency(
@@ -918,6 +921,7 @@ def main() -> None:
918921
parser.add_argument("--dry-run", action="store_true", help="Do not execute uv commands or update pyprojects.")
919922
args = parser.parse_args()
920923

924+
# Preparation/target collection: resolve workspace metadata and package execution plans.
921925
workspace_pyproject = Path(__file__).parent.parent / "pyproject.toml"
922926
workspace_root = workspace_pyproject.parent
923927
package_filters = set(args.packages) if args.packages else None
@@ -958,6 +962,7 @@ def main() -> None:
958962
print("[yellow]No packages matched the selection.[/yellow]")
959963
return
960964

965+
# Aggregation + persistence/reporting: initialize the incremental JSON report.
961966
report: dict = {
962967
"started_at": _utc_now(),
963968
"workspace_root": str(workspace_root),
@@ -1009,6 +1014,7 @@ def main() -> None:
10091014
if outcome.changed and not args.dry_run:
10101015
_apply_package_replacements(plan.pyproject_path, outcome.replacements)
10111016

1017+
# Persist each completed package outcome so long runs keep a live report.
10121018
report["packages"].append(_to_json(outcome))
10131019
report["summary"]["packages_changed"] = sum(1 for value in package_outcomes if value.changed)
10141020
report["summary"]["dependencies_changed"] = sum(

0 commit comments

Comments
 (0)