infra: get min versions (#27896)

This commit is contained in:
Erick Friis 2024-11-04 15:46:13 -08:00 committed by GitHub
parent 6973f7214f
commit ba5cba04ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 76 additions and 25 deletions

View File

@ -7,12 +7,17 @@ else:
# for python 3.10 and below, which doesnt have stdlib tomllib # for python 3.10 and below, which doesnt have stdlib tomllib
import tomli as tomllib import tomli as tomllib
from packaging.version import parse as parse_version
from packaging.specifiers import SpecifierSet from packaging.specifiers import SpecifierSet
from packaging.version import Version from packaging.version import Version
import requests
from packaging.version import parse
from typing import List
import re import re
MIN_VERSION_LIBS = [ MIN_VERSION_LIBS = [
"langchain-core", "langchain-core",
"langchain-community", "langchain-community",
@ -31,29 +36,61 @@ SKIP_IF_PULL_REQUEST = [
] ]
def get_min_version(version: str) -> str: def get_pypi_versions(package_name: str) -> List[str]:
# base regex for x.x.x with cases for rc/post/etc """
# valid strings: https://peps.python.org/pep-0440/#public-version-identifiers Fetch all available versions for a package from PyPI.
vstring = r"\d+(?:\.\d+){0,2}(?:(?:a|b|rc|\.post|\.dev)\d+)?"
# case ^x.x.x
_match = re.match(f"^\\^({vstring})$", version)
if _match:
return _match.group(1)
# case >=x.x.x,<y.y.y Args:
_match = re.match(f"^>=({vstring}),<({vstring})$", version) package_name (str): Name of the package
if _match:
_min = _match.group(1)
_max = _match.group(2)
assert parse_version(_min) < parse_version(_max)
return _min
# case x.x.x Returns:
_match = re.match(f"^({vstring})$", version) List[str]: List of all available versions
if _match:
return _match.group(1)
raise ValueError(f"Unrecognized version format: {version}") Raises:
requests.exceptions.RequestException: If PyPI API request fails
KeyError: If package not found or response format unexpected
"""
pypi_url = f"https://pypi.org/pypi/{package_name}/json"
response = requests.get(pypi_url)
response.raise_for_status()
return list(response.json()["releases"].keys())
def get_minimum_version(package_name: str, spec_string: str) -> Optional[str]:
"""
Find the minimum published version that satisfies the given constraints.
Args:
package_name (str): Name of the package
spec_string (str): Version specification string (e.g., ">=0.2.43,<0.4.0,!=0.3.0")
Returns:
Optional[str]: Minimum compatible version or None if no compatible version found
"""
# rewrite occurrences of ^0.0.z to 0.0.z (can be anywhere in constraint string)
spec_string = re.sub(r"\^0\.0\.(\d+)", r"0.0.\1", spec_string)
# rewrite occurrences of ^0.y.z to >=0.y.z,<0.y+1 (can be anywhere in constraint string)
for y in range(1, 10):
spec_string = re.sub(rf"\^0\.{y}\.(\d+)", rf">=0.{y}.\1,<0.{y+1}", spec_string)
# rewrite occurrences of ^x.y.z to >=x.y.z,<x+1.0.0 (can be anywhere in constraint string)
for x in range(1, 10):
spec_string = re.sub(
rf"\^{x}\.(\d+)\.(\d+)", rf">={x}.\1.\2,<{x+1}", spec_string
)
spec_set = SpecifierSet(spec_string)
all_versions = get_pypi_versions(package_name)
valid_versions = []
for version_str in all_versions:
try:
version = parse(version_str)
if spec_set.contains(version):
valid_versions.append(version)
except ValueError:
continue
return str(min(valid_versions)) if valid_versions else None
def get_min_version_from_toml( def get_min_version_from_toml(
@ -96,7 +133,7 @@ def get_min_version_from_toml(
][0]["version"] ][0]["version"]
# Use parse_version to get the minimum supported version from version_string # Use parse_version to get the minimum supported version from version_string
min_version = get_min_version(version_string) min_version = get_minimum_version(lib, version_string)
# Store the minimum version in the min_versions dictionary # Store the minimum version in the min_versions dictionary
min_versions[lib] = min_version min_versions[lib] = min_version
@ -112,6 +149,20 @@ def check_python_version(version_string, constraint_string):
:param constraint_string: A string representing the package's Python version constraints (e.g. ">=3.6, <4.0"). :param constraint_string: A string representing the package's Python version constraints (e.g. ">=3.6, <4.0").
:return: True if the version matches the constraints, False otherwise. :return: True if the version matches the constraints, False otherwise.
""" """
# rewrite occurrences of ^0.0.z to 0.0.z (can be anywhere in constraint string)
constraint_string = re.sub(r"\^0\.0\.(\d+)", r"0.0.\1", constraint_string)
# rewrite occurrences of ^0.y.z to >=0.y.z,<0.y+1.0 (can be anywhere in constraint string)
for y in range(1, 10):
constraint_string = re.sub(
rf"\^0\.{y}\.(\d+)", rf">=0.{y}.\1,<0.{y+1}.0", constraint_string
)
# rewrite occurrences of ^x.y.z to >=x.y.z,<x+1.0.0 (can be anywhere in constraint string)
for x in range(1, 10):
constraint_string = re.sub(
rf"\^{x}\.0\.(\d+)", rf">={x}.0.\1,<{x+1}.0.0", constraint_string
)
try: try:
version = Version(version_string) version = Version(version_string)
constraints = SpecifierSet(constraint_string) constraints = SpecifierSet(constraint_string)

View File

@ -247,7 +247,7 @@ jobs:
working-directory: ${{ inputs.working-directory }} working-directory: ${{ inputs.working-directory }}
id: min-version id: min-version
run: | run: |
poetry run pip install packaging poetry run pip install packaging requests
python_version="$(poetry run python --version | awk '{print $2}')" python_version="$(poetry run python --version | awk '{print $2}')"
min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml release $python_version)" min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml release $python_version)"
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT" echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"

View File

@ -47,7 +47,7 @@ jobs:
id: min-version id: min-version
shell: bash shell: bash
run: | run: |
poetry run pip install packaging tomli poetry run pip install packaging tomli requests
python_version="$(poetry run python --version | awk '{print $2}')" python_version="$(poetry run python --version | awk '{print $2}')"
min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml pull_request $python_version)" min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml pull_request $python_version)"
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT" echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"

View File

@ -31,7 +31,7 @@ jobs:
uses: Ana06/get-changed-files@v2.2.0 uses: Ana06/get-changed-files@v2.2.0
- id: set-matrix - id: set-matrix
run: | run: |
python -m pip install packaging python -m pip install packaging requests
python .github/scripts/check_diff.py ${{ steps.files.outputs.all }} >> $GITHUB_OUTPUT python .github/scripts/check_diff.py ${{ steps.files.outputs.all }} >> $GITHUB_OUTPUT
outputs: outputs:
lint: ${{ steps.set-matrix.outputs.lint }} lint: ${{ steps.set-matrix.outputs.lint }}