Skip to content

Commit 36e2fe7

Browse files
author
Grant Harris
committed
fix upgrade logic in setup.py
1 parent ff3bc83 commit 36e2fe7

1 file changed

Lines changed: 56 additions & 2 deletions

File tree

versioning/helper/setup_utils.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
at build time, ensuring all packages in the monorepo use the exact same version.
99
"""
1010

11+
import re
1112
from os import environ
13+
from pathlib import Path
1214

1315

1416
def get_package_version() -> str:
@@ -101,6 +103,43 @@ def get_next_major_version(base_version: str) -> str:
101103
return base_version
102104

103105

106+
def _parse_root_constraints(root_pyproject_path: Path) -> dict[str, str]:
107+
"""
108+
Parse constraint-dependencies from the root pyproject.toml.
109+
110+
Returns a dict mapping normalized package names to their full constraint strings.
111+
Example: {"semantic-kernel": "semantic-kernel >= 1.39.3"}
112+
"""
113+
try:
114+
import tomllib
115+
except ImportError:
116+
try:
117+
import tomli as tomllib # type: ignore[no-redef]
118+
except ImportError:
119+
return {}
120+
121+
try:
122+
with open(root_pyproject_path, "rb") as f:
123+
root_data = tomllib.load(f)
124+
except (FileNotFoundError, PermissionError):
125+
return {}
126+
127+
constraints_list = root_data.get("tool", {}).get("uv", {}).get("constraint-dependencies", [])
128+
constraints: dict[str, str] = {}
129+
for entry in constraints_list:
130+
if not isinstance(entry, str):
131+
continue
132+
pkg_name = re.split(r"\s*[<>=!~]", entry, maxsplit=1)[0].strip()
133+
normalized = pkg_name.lower().replace("_", "-")
134+
constraints[normalized] = entry
135+
return constraints
136+
137+
138+
def _has_version_constraint(dep: str) -> bool:
139+
"""Check if a dependency string already includes a version constraint."""
140+
return bool(re.search(r"[<>=!~]", dep))
141+
142+
104143
def get_dynamic_dependencies(
105144
pyproject_path: str = "pyproject.toml",
106145
use_exact_match: bool = False,
@@ -126,7 +165,9 @@ def get_dynamic_dependencies(
126165
Example: == 0.1.0.dev5
127166
- Forces exact version match
128167
129-
External packages keep their original version constraints.
168+
External packages without version constraints get the centralized constraint
169+
from the root pyproject.toml constraint-dependencies, ensuring published packages
170+
enforce minimum versions for security and compatibility.
130171
131172
Args:
132173
pyproject_path: Path to the pyproject.toml file (default: "pyproject.toml")
@@ -204,6 +245,12 @@ def get_dynamic_dependencies(
204245
file=sys.stderr,
205246
)
206247

248+
# Load centralized constraints from root pyproject.toml so that published
249+
# packages enforce the same minimum versions used during development.
250+
pkg_pyproject = Path(pyproject_path).resolve()
251+
root_pyproject = pkg_pyproject.parent.parent.parent / "pyproject.toml"
252+
root_constraints = _parse_root_constraints(root_pyproject)
253+
207254
# Update internal package versions dynamically
208255
updated_dependencies = []
209256
for dep in dependencies:
@@ -229,8 +276,15 @@ def get_dynamic_dependencies(
229276
else:
230277
# Minimum version (default): >= base_version
231278
updated_dependencies.append(f"{pkg_name} >= {base_version}")
279+
elif not _has_version_constraint(dep):
280+
# External dep with no version constraint — apply root constraint if available
281+
normalized = dep.strip().lower().replace("_", "-")
282+
if normalized in root_constraints:
283+
updated_dependencies.append(root_constraints[normalized])
284+
else:
285+
updated_dependencies.append(dep)
232286
else:
233-
# Keep external dependencies as-is
287+
# External dependency already has a version constraint — keep as-is
234288
updated_dependencies.append(dep)
235289

236290
return updated_dependencies

0 commit comments

Comments
 (0)