Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-dependency-maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- name: Set dependency release cutoff
run: |
cutoff="$(date -u -d '7 days ago' '+%Y-%m-%dT%H:%M:%SZ')"
echo "UV_EXCLUDE_NEWER=${cutoff}" >> "$GITHUB_ENV"
echo "DEPENDENCY_RELEASE_CUTOFF=${cutoff}" >> "$GITHUB_ENV"
echo "Using dependency release cutoff: ${cutoff}"

- name: Repin dev dependency declarations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ class SandboxRuntime(Protocol):
def execute(self, *, config: _RunConfig, code: str) -> list[Content]: ...


class _NamedDirectory(Protocol):
name: str


_T = TypeVar("_T")


Expand Down Expand Up @@ -725,7 +729,7 @@ def _collect_output_relative_paths(*, sandbox: Any, root: Path) -> set[str]:
def _parse_output_files(
*,
sandbox: Any,
output_dir: TemporaryDirectory[str] | None,
output_dir: _NamedDirectory | None,
expect_output_files: bool,
) -> list[Content]:
if output_dir is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def _fetch(self, package_name: str) -> list[Version]:


def _load_exclude_newer_from_env() -> datetime | None:
raw_value = os.environ.get("UV_EXCLUDE_NEWER")
raw_value = os.environ.get("DEPENDENCY_RELEASE_CUTOFF") or os.environ.get("UV_EXCLUDE_NEWER")
if not raw_value:
return None
normalized = raw_value.removesuffix("Z")
Expand Down
50 changes: 49 additions & 1 deletion python/scripts/dependencies/_dependency_bounds_upper_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
logger = logging.getLogger(__name__)

CHECK_TASK_PRIORITY = ("check", "typing", "pyright", "mypy", "lint")
AZURE_MONITOR_OPENTELEMETRY = "azure-monitor-opentelemetry"
OPENTELEMETRY_SDK = "opentelemetry-sdk"
REQ_PATTERN = r"^\s*([A-Za-z0-9_.-]+(?:\[[^\]]+\])?)\s*(.*?)\s*$"
SECTION_HEADER_PATTERN = re.compile(r"^\s*\[([^\]]+)\]\s*$")
INLINE_ARRAY_ASSIGNMENT_PATTERN = re.compile(
Expand Down Expand Up @@ -238,6 +240,18 @@ def _select_latest_dev_version(versions: list[Version]) -> Version | None:
return versions[-1]


def _exact_pin_version(requirement: Requirement) -> Version | None:
"""Return the exact pinned version from a requirement, if it has one."""
for specifier in requirement.specifier:
if specifier.operator not in {"==", "==="} or "*" in specifier.version:
continue
try:
return Version(specifier.version)
except InvalidVersion:
return None
return None


@lru_cache(maxsize=8)
def _load_workspace_package_versions(workspace_root: str) -> dict[str, Version]:
workspace_path = Path(workspace_root)
Expand Down Expand Up @@ -283,6 +297,13 @@ def _collect_dev_pin_replacements(
requirement for requirement in (dependency_groups.get("dev", []) or []) if isinstance(requirement, str)
)
logger.debug(f"Found {len(dev_requirements)} dev requirements in {pyproject_file}")
parsed_dev_requirements: dict[str, Requirement] = {}
for requirement in dev_requirements:
try:
parsed_requirement = Requirement(requirement)
except InvalidRequirement:
continue
parsed_dev_requirements[parsed_requirement.name.lower()] = parsed_requirement

seen_requirements: set[str] = set()
replacements: dict[str, str] = {}
Expand All @@ -309,6 +330,33 @@ def _collect_dev_pin_replacements(
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"):
locked_version = _select_latest_dev_version(catalog.get_lock(dependency_name))
if locked_version is not None:
latest_version = locked_version
if current_exact_version is not None and latest_version < current_exact_version:
logger.info(
"Skipping %s in %s because selected version %s is older than current pin %s.",
dependency_name,
pyproject_file,
latest_version,
current_exact_version,
)
continue
if (
dependency_name == OPENTELEMETRY_SDK
and AZURE_MONITOR_OPENTELEMETRY in parsed_dev_requirements
and current_exact_version is not None
and latest_version != current_exact_version
):
logger.info(
"Skipping %s in %s because %s currently pins the SDK version.",
dependency_name,
pyproject_file,
AZURE_MONITOR_OPENTELEMETRY,
)
continue

extras = f"[{','.join(sorted(parsed_requirement.extras))}]" if parsed_requirement.extras else ""
marker = f"; {parsed_requirement.marker}" if parsed_requirement.marker else ""
Expand Down Expand Up @@ -486,7 +534,7 @@ def _fetch(self, package_name: str) -> list[Version]:


def _load_exclude_newer_from_env() -> datetime | None:
raw_value = os.environ.get("UV_EXCLUDE_NEWER")
raw_value = os.environ.get("DEPENDENCY_RELEASE_CUTOFF") or os.environ.get("UV_EXCLUDE_NEWER")
if not raw_value:
return None
normalized = raw_value.removesuffix("Z")
Expand Down
Loading