Skip to content

Commit d7be806

Browse files
committed
Fix get_min_versions.py to respect Python version markers
The script now evaluates python_version markers in dependencies and only extracts minimum versions for packages applicable to the current Python version. This ensures: - Python 3.9 CI jobs use LangChain 0.3.x minimums - Python 3.10+ CI jobs use LangChain 1.x minimums This prevents incompatible package combinations like langchain-core 0.3.78 with langchain-openai 1.1.0 (which requires langchain-core >= 1.1.0).
1 parent 3499780 commit d7be806

File tree

1 file changed

+31
-28
lines changed

1 file changed

+31
-28
lines changed

.github/scripts/get_min_versions.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,43 @@ def get_min_version_from_toml(toml_path: str):
4747
# Parse dependencies list into a dictionary
4848
# Format: "package-name>=x.x.x,<y.y.y" or "package-name>=x.x.x; python_version < '3.10'"
4949
dependencies = {}
50+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
51+
5052
for dep in dependencies_list:
51-
# Remove environment markers (everything after semicolon)
52-
dep_without_marker = dep.split(";")[0].strip()
53+
# Check if there's a Python version marker
54+
if ";" in dep:
55+
dep_without_marker, marker = dep.split(";", 1)
56+
dep_without_marker = dep_without_marker.strip()
57+
marker = marker.strip()
58+
59+
# Check if this dependency applies to current Python version
60+
# Handle python_version < '3.10' and python_version >= '3.10' markers
61+
applies_to_current = True
62+
if "python_version" in marker:
63+
if "<" in marker and not ">=" in marker:
64+
# python_version < 'X.Y'
65+
match = re.search(r"python_version\s*<\s*['\"](\d+\.\d+)['\"]", marker)
66+
if match:
67+
max_version = match.group(1)
68+
applies_to_current = parse_version(python_version) < parse_version(max_version)
69+
elif ">=" in marker:
70+
# python_version >= 'X.Y'
71+
match = re.search(r"python_version\s*>=\s*['\"](\d+\.\d+)['\"]", marker)
72+
if match:
73+
min_version_marker = match.group(1)
74+
applies_to_current = parse_version(python_version) >= parse_version(min_version_marker)
75+
76+
if not applies_to_current:
77+
continue
78+
else:
79+
dep_without_marker = dep.strip()
5380

5481
# Extract package name and version spec
5582
match = re.match(r"^([a-zA-Z0-9_-]+)(.*)$", dep_without_marker)
5683
if match:
5784
pkg_name = match.group(1)
5885
version_spec = match.group(2)
59-
60-
# If this package already exists, collect both version specs
61-
if pkg_name in dependencies:
62-
# Store as a list to handle multiple version constraints
63-
if isinstance(dependencies[pkg_name], list):
64-
dependencies[pkg_name].append(version_spec)
65-
else:
66-
dependencies[pkg_name] = [dependencies[pkg_name], version_spec]
67-
else:
68-
dependencies[pkg_name] = version_spec
86+
dependencies[pkg_name] = version_spec
6987

7088
# Initialize a dictionary to store the minimum versions
7189
min_versions = {}
@@ -74,23 +92,8 @@ def get_min_version_from_toml(toml_path: str):
7492
for lib in MIN_VERSION_LIBS:
7593
# Check if the lib is present in the dependencies
7694
if lib in dependencies:
77-
# Get the version string(s)
7895
version_spec = dependencies[lib]
79-
80-
# Handle list format (multiple version constraints for different Python versions)
81-
if isinstance(version_spec, list):
82-
# Extract all version strings from the list and find the minimum
83-
versions = []
84-
for spec in version_spec:
85-
if spec:
86-
versions.append(get_min_version(spec))
87-
88-
# If we found versions, use the minimum one
89-
if versions:
90-
min_version = min(versions, key=parse_version)
91-
min_versions[lib] = min_version
92-
elif isinstance(version_spec, str) and version_spec:
93-
# Handle simple string format
96+
if version_spec:
9497
min_version = get_min_version(version_spec)
9598
min_versions[lib] = min_version
9699

0 commit comments

Comments
 (0)