mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-01 14:47:02 +00:00
104 lines
3.9 KiB
Python
104 lines
3.9 KiB
Python
"""Check version consistency between package metadata and generated artifacts.
|
|
|
|
This script validates that the version defined in pyproject.toml matches the `VERSION`
|
|
variable in `langchain_core/version.py`. It also checks checked-in snapshots that embed
|
|
`langchain-core` version metadata. Intended for use as a pre-commit hook to prevent
|
|
version mismatches.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Matches the `langchain-core` version embedded in serialized model metadata,
|
|
# e.g. `{'versions': {'langchain-core': '1.4.6'}}`. Intentionally broad: every such
|
|
# occurrence in a snapshot is expected to track the released version.
|
|
SNAPSHOT_VERSION_PATTERN = re.compile(r"langchain-core': '([^']+)'")
|
|
|
|
|
|
def get_pyproject_version(pyproject_path: Path) -> str | None:
|
|
"""Extract version from `pyproject.toml`."""
|
|
content = pyproject_path.read_text(encoding="utf-8")
|
|
match = re.search(r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE)
|
|
return match.group(1) if match else None
|
|
|
|
|
|
def get_version_py_version(version_path: Path) -> str | None:
|
|
"""Extract `VERSION` from `version.py`."""
|
|
content = version_path.read_text(encoding="utf-8")
|
|
match = re.search(r'^VERSION\s*=\s*"([^"]+)"', content, re.MULTILINE)
|
|
return match.group(1) if match else None
|
|
|
|
|
|
def get_snapshot_version_mismatches(
|
|
snapshots_dir: Path, expected_version: str
|
|
) -> list[tuple[Path, int, str]]:
|
|
"""Find snapshot `langchain-core` version metadata that is out of date."""
|
|
mismatches = []
|
|
for snapshot_path in sorted(snapshots_dir.rglob("*.ambr")):
|
|
# `errors="replace"` keeps a stray non-UTF-8 file from crashing the hook;
|
|
# the version strings we match are ASCII, so decoding is unaffected.
|
|
content = snapshot_path.read_text(encoding="utf-8", errors="replace")
|
|
for match in SNAPSHOT_VERSION_PATTERN.finditer(content):
|
|
version = match.group(1)
|
|
if version == expected_version:
|
|
continue
|
|
line_number = content.count("\n", 0, match.start()) + 1
|
|
mismatches.append((snapshot_path, line_number, version))
|
|
return mismatches
|
|
|
|
|
|
def main() -> int:
|
|
"""Validate version consistency."""
|
|
script_dir = Path(__file__).parent
|
|
package_dir = script_dir.parent
|
|
|
|
pyproject_path = package_dir / "pyproject.toml"
|
|
version_path = package_dir / "langchain_core" / "version.py"
|
|
# Scoped to this package's snapshots: only core's own `tests/` tree embeds
|
|
# `langchain-core` version metadata today.
|
|
snapshots_dir = package_dir / "tests"
|
|
|
|
if not pyproject_path.exists():
|
|
print(f"Error: {pyproject_path} not found")
|
|
return 1
|
|
|
|
if not version_path.exists():
|
|
print(f"Error: {version_path} not found")
|
|
return 1
|
|
|
|
pyproject_version = get_pyproject_version(pyproject_path)
|
|
version_py_version = get_version_py_version(version_path)
|
|
|
|
if pyproject_version is None:
|
|
print("Error: Could not find version in pyproject.toml")
|
|
return 1
|
|
|
|
if version_py_version is None:
|
|
print("Error: Could not find VERSION in langchain_core/version.py")
|
|
return 1
|
|
|
|
if pyproject_version != version_py_version:
|
|
print("Error: Version mismatch detected!")
|
|
print(f" pyproject.toml: {pyproject_version}")
|
|
print(f" langchain_core/version.py: {version_py_version}")
|
|
return 1
|
|
|
|
snapshot_mismatches = get_snapshot_version_mismatches(
|
|
snapshots_dir, pyproject_version
|
|
)
|
|
if snapshot_mismatches:
|
|
print("Error: Snapshot version mismatch detected!")
|
|
print(f" expected langchain-core version: {pyproject_version}")
|
|
for snapshot_path, line_number, snapshot_version in snapshot_mismatches:
|
|
relative_path = snapshot_path.relative_to(package_dir)
|
|
print(f" {relative_path}:{line_number}: {snapshot_version}")
|
|
return 1
|
|
|
|
print(f"Version check passed: {pyproject_version}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|