88at build time, ensuring all packages in the monorepo use the exact same version.
99"""
1010
11+ import re
1112from os import environ
13+ from pathlib import Path
1214
1315
1416def 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+
104143def 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