Files
Eduard van Valkenburg 50fdcbaf57 Python: chore(python): improve dependency range automation (#4343)
* chore(python): improve dependency range automation

- tighten dependency bounds and coding standards guidance\n- add dependency range validation workflow, reporting, and issue automation\n- update related tests and dependency pins for compatibility

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* updated text and pyarrow

* new lock

* fixed workflow

* updated deps

* fix tiktoken

* chore(python): refine dependency validation workflows

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs(python): add high-level dependency validation comments

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* WIP

* added additional comments and excludes

* added dev dependency handling and workflow and updates to package ranges

* added readme and simplified commands

* fix markers

* chore(python): address dependency review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Tighten dependency bounds, remove stale overrides, restore Python 3.10 support

- Apply dependency bound policy across all packages: stable >=1.0 deps use
  >=floor,<next_major; pre-1.0/prerelease deps use validated hard-bounded ranges
- Remove stale root tool.uv.override-dependencies (uvicorn, websockets, grpcio)
- Lower github_copilot requires-python to >=3.10 with github-copilot-sdk gated
  behind python_version >= 3.11 marker; import raises ImportError on 3.10
- Skip github_copilot pyright/mypy/test tasks on Python <3.11
- Use version-conditional pyrightconfig for samples on Python 3.10
- Add compatibility fix in core responses client for older openai typed dicts
- Normalize uv.lock prerelease mode and refresh dev dependencies
- Update CODING_STANDARD.md, DEV_SETUP.md, and package management skill docs

Closes #902

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* small tweaks

* add note in workflow

* fix workflows and several versions

* fix duplicate

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-13 12:32:37 +00:00

87 lines
2.9 KiB
Python

# Copyright (c) Microsoft. All rights reserved.
# ruff: noqa: INP001
"""Shared runtime helpers for dependency-bound validation commands."""
from __future__ import annotations
from functools import lru_cache
from pathlib import Path
import tomli
from packaging.requirements import InvalidRequirement, Requirement
_TOOL_REQUIREMENT_NAMES = {
"mypy",
"poethepoet",
"pyright",
"pytest",
"pytest-asyncio",
"pytest-cov",
"pytest-retry",
"pytest-timeout",
"pytest-xdist",
"ruff",
}
_ADDITIONAL_RUNTIME_REQUIREMENTS = (
"graphviz",
"opentelemetry-exporter-otlp-proto-grpc",
"opentelemetry-exporter-otlp-proto-http",
)
# Run pyright through the current interpreter so its import resolution matches the uv-created environment.
_PYRIGHT_COMMAND = (
"import subprocess, sys; "
"raise SystemExit(subprocess.call([sys.executable, '-m', 'pyright', '--pythonpath', sys.executable]))"
)
@lru_cache(maxsize=8)
def load_runtime_tool_requirements(workspace_root: str) -> list[str]:
"""Load shared tool requirements used by package test and typing tasks."""
workspace_path = Path(workspace_root)
pyproject_path = workspace_path / "pyproject.toml"
data = tomli.loads(pyproject_path.read_text())
dev_requirements = data.get("dependency-groups", {}).get("dev", []) or []
# `uv run --isolated` starts from a clean environment, so the validator has to re-attach the
# shared tooling that package-level poe tasks expect to find.
runtime_requirements: list[str] = []
for requirement in dev_requirements:
if not isinstance(requirement, str):
continue
try:
parsed = Requirement(requirement)
except InvalidRequirement:
continue
if parsed.name.lower() in _TOOL_REQUIREMENT_NAMES:
runtime_requirements.append(requirement)
return runtime_requirements
def extend_command_with_runtime_tools(command: list[str], workspace_root: Path) -> None:
"""Append shared tooling requirements to a uv run command."""
# Mirror the repo-wide test/lint toolchain inside the temporary environment before adding the task.
for requirement in load_runtime_tool_requirements(str(workspace_root.resolve())):
command.extend(["--with", requirement])
for requirement in _ADDITIONAL_RUNTIME_REQUIREMENTS:
command.extend(["--with", requirement])
def extend_command_with_task(command: list[str], task_name: str) -> None:
"""Append the command needed to execute one validation task."""
if task_name == "pyright":
command.extend(["python", "-c", _PYRIGHT_COMMAND])
return
command.extend(["python", "-m", "poethepoet", task_name])
def next_zero_major_minor_boundary(version_text: str) -> str:
"""Return the exclusive upper bound for the next 0.x minor after the given version."""
from packaging.version import Version
version = Version(version_text)
return f"0.{version.minor + 1}.0"