From 6b1b607d9b3d0d343cfc7871c559016659362dd8 Mon Sep 17 00:00:00 2001 From: eavanvalkenburg Date: Mon, 22 Jun 2026 15:43:37 +0200 Subject: [PATCH] Python: stabilize dependency maintenance final checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../python-dependency-maintenance.yml | 4 +- .../_dependency_bounds_upper_impl.py | 48 ++++++++----------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/.github/workflows/python-dependency-maintenance.yml b/.github/workflows/python-dependency-maintenance.yml index bca0f6aeba9..6aab41b13fc 100644 --- a/.github/workflows/python-dependency-maintenance.yml +++ b/.github/workflows/python-dependency-maintenance.yml @@ -49,7 +49,7 @@ jobs: working-directory: ./python - name: Refresh lockfile after dev pin updates - run: uv lock --upgrade + run: uv lock working-directory: ./python - name: Save dev dependency changes @@ -285,7 +285,7 @@ jobs: - name: Refresh lockfile after dependency range updates if: steps.validate_bounds_test.outcome == 'success' && steps.validate_ranges.outcome == 'success' - run: uv lock --upgrade + run: uv lock working-directory: ./python - name: Install final dependency set diff --git a/python/scripts/dependencies/_dependency_bounds_upper_impl.py b/python/scripts/dependencies/_dependency_bounds_upper_impl.py index 66d68fd51d0..7ae1cc058ea 100644 --- a/python/scripts/dependencies/_dependency_bounds_upper_impl.py +++ b/python/scripts/dependencies/_dependency_bounds_upper_impl.py @@ -17,7 +17,6 @@ import threading from dataclasses import dataclass from datetime import datetime, timezone -from functools import lru_cache from pathlib import Path from urllib import error as urllib_error from urllib import request as urllib_request @@ -39,6 +38,7 @@ CHECK_TASK_PRIORITY = ("check", "typing", "pyright", "mypy", "lint") AZURE_MONITOR_OPENTELEMETRY = "azure-monitor-opentelemetry" OPENTELEMETRY_SDK = "opentelemetry-sdk" +VALIDATION_TOOL_DEV_PINS = frozenset({"mypy", "pyrefly", "pyright", "ruff", "ty", "zuban"}) REQ_PATTERN = r"^\s*([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(.*?)\s*$" SECTION_HEADER_PATTERN = re.compile(r"^\s*\[([^\]]+)\]\s*$") INLINE_ARRAY_ASSIGNMENT_PATTERN = re.compile( @@ -252,25 +252,6 @@ def _exact_pin_version(requirement: Requirement) -> Version | None: return None -@lru_cache(maxsize=8) -def _load_workspace_package_versions(workspace_root: str) -> dict[str, Version]: - workspace_path = Path(workspace_root) - versions: dict[str, Version] = {} - for package_pyproject in sorted((workspace_path / "packages").glob("*/pyproject.toml")): - with package_pyproject.open("rb") as f: - package_data = tomli.load(f) - project_section = package_data.get("project", {}) or {} - package_name = str(project_section.get("name", "")).strip().lower() - package_version = project_section.get("version") - if not package_name or not package_version: - continue - try: - versions[package_name] = Version(str(package_version)) - except InvalidVersion: - continue - return versions - - def _collect_dev_pin_replacements( pyproject_file: Path, *, @@ -287,8 +268,6 @@ def _collect_dev_pin_replacements( optional_dependencies.keys(), dependency_groups.keys(), ) - workspace_versions = _load_workspace_package_versions(str(pyproject_file.parent.parent.parent.resolve())) - dev_requirements: list[str] = [] dev_requirements.extend( requirement for requirement in (optional_dependencies.get("dev", []) or []) if isinstance(requirement, str) @@ -322,16 +301,27 @@ def _collect_dev_pin_replacements( continue dependency_name = parsed_requirement.name.lower() if dependency_name.startswith("agent-framework"): - latest_version = workspace_versions.get(dependency_name) - else: - # Dev-tool refreshes should follow the selected version source (PyPI by default) - # instead of being pinned by the current lockfile. VersionCatalog already falls - # back to lock data when PyPI cannot be reached or --version-source=lock is used. - latest_version = _select_latest_dev_version(catalog.get(dependency_name)) + logger.info( + "Skipping %s in %s because internal package pins are maintained by package versioning.", + dependency_name, + pyproject_file, + ) + continue + # Dev-tool refreshes should follow the selected version source (PyPI by default) + # instead of being pinned by the current lockfile. VersionCatalog already falls + # back to lock data when PyPI cannot be reached or --version-source=lock is used. + latest_version = _select_latest_dev_version(catalog.get(dependency_name)) if latest_version is None: continue current_exact_version = _exact_pin_version(parsed_requirement) - if current_exact_version is None and not dependency_name.startswith("agent-framework"): + if current_exact_version is not None and dependency_name in VALIDATION_TOOL_DEV_PINS: + logger.info( + "Skipping %s in %s because validation tool upgrades should be handled separately.", + dependency_name, + pyproject_file, + ) + continue + if current_exact_version is None: locked_version = _select_latest_dev_version(catalog.get_lock(dependency_name)) if locked_version is not None: latest_version = locked_version