From 97b3d6dae10e11e3a674778ea6beeac27649870c Mon Sep 17 00:00:00 2001 From: Mason Daugherty Date: Fri, 16 Jan 2026 14:24:46 -0500 Subject: [PATCH] chore(core, langchain): add version consistency check pre-commit hooks (#34782) --- .pre-commit-config.yaml | 12 ++++ libs/core/Makefile | 6 +- libs/core/scripts/check_version.py | 65 ++++++++++++++++++++++ libs/langchain_v1/Makefile | 6 +- libs/langchain_v1/scripts/check_version.py | 65 ++++++++++++++++++++++ 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 libs/core/scripts/check_version.py create mode 100644 libs/langchain_v1/scripts/check_version.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 920e2f4665..8fba635cfa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -117,3 +117,15 @@ repos: entry: make -C libs/partners/qdrant format lint files: ^libs/partners/qdrant/ pass_filenames: false + - id: core-version + name: check core version consistency + language: system + entry: make -C libs/core check_version + files: ^libs/core/(pyproject\.toml|langchain_core/version\.py)$ + pass_filenames: false + - id: langchain-v1-version + name: check langchain version consistency + language: system + entry: make -C libs/langchain_v1 check_version + files: ^libs/langchain_v1/(pyproject\.toml|langchain/__init__\.py)$ + pass_filenames: false diff --git a/libs/core/Makefile b/libs/core/Makefile index 05ac2d83ab..70425ce6d1 100644 --- a/libs/core/Makefile +++ b/libs/core/Makefile @@ -1,4 +1,4 @@ -.PHONY: all format lint test tests test_watch integration_tests help extended_tests +.PHONY: all format lint test tests test_watch integration_tests help extended_tests check_version # Default target executed when no arguments are given to make. all: help @@ -31,6 +31,9 @@ test_profile: check_imports: $(shell find langchain_core -name '*.py') uv run --group test python ./scripts/check_imports.py $^ +check_version: + uv run python ./scripts/check_version.py + extended_tests: uv run --group test pytest --only-extended --disable-socket --allow-unix-socket $(TEST_FILE) @@ -69,6 +72,7 @@ help: @echo '----' @echo 'format - run code formatters' @echo 'lint - run linters' + @echo 'check_version - validate version consistency' @echo 'test - run unit tests' @echo 'tests - run unit tests' @echo 'test TEST_FILE= - run all tests in file' diff --git a/libs/core/scripts/check_version.py b/libs/core/scripts/check_version.py new file mode 100644 index 0000000000..b0f47a0296 --- /dev/null +++ b/libs/core/scripts/check_version.py @@ -0,0 +1,65 @@ +"""Check version consistency between pyproject.toml and version.py. + +This script validates that the version defined in pyproject.toml matches +the VERSION variable in langchain_core/version.py. Intended for use as +a pre-commit hook to prevent version mismatches. +""" + +import re +import sys +from pathlib import Path + + +def get_pyproject_version(pyproject_path: Path) -> str | None: + """Extract version from pyproject.toml.""" + content = pyproject_path.read_text() + 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() + match = re.search(r'^VERSION\s*=\s*"([^"]+)"', content, re.MULTILINE) + return match.group(1) if match else None + + +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" + + if not pyproject_path.exists(): + print(f"Error: {pyproject_path} not found") # noqa: T201 + return 1 + + if not version_path.exists(): + print(f"Error: {version_path} not found") # noqa: T201 + 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") # noqa: T201 + return 1 + + if version_py_version is None: + print("Error: Could not find VERSION in langchain_core/version.py") # noqa: T201 + return 1 + + if pyproject_version != version_py_version: + print("Error: Version mismatch detected!") # noqa: T201 + print(f" pyproject.toml: {pyproject_version}") # noqa: T201 + print(f" langchain_core/version.py: {version_py_version}") # noqa: T201 + return 1 + + print(f"Version check passed: {pyproject_version}") # noqa: T201 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/libs/langchain_v1/Makefile b/libs/langchain_v1/Makefile index 38416fccd3..5e22daeefe 100644 --- a/libs/langchain_v1/Makefile +++ b/libs/langchain_v1/Makefile @@ -1,4 +1,4 @@ -.PHONY: all start_services stop_services coverage coverage_agents test test_fast extended_tests test_watch test_watch_extended integration_tests check_imports lint format lint_diff format_diff lint_package lint_tests help +.PHONY: all start_services stop_services coverage coverage_agents test test_fast extended_tests test_watch test_watch_extended integration_tests check_imports check_version lint format lint_diff format_diff lint_package lint_tests help # Default target executed when no arguments are given to make. all: help @@ -69,6 +69,9 @@ integration_tests: check_imports: $(shell find langchain -name '*.py') uv run python ./scripts/check_imports.py $^ +check_version: + uv run python ./scripts/check_version.py + ###################### # LINTING AND FORMATTING ###################### @@ -100,6 +103,7 @@ help: @echo '-- LINTING --' @echo 'format - run code formatters' @echo 'lint - run linters' + @echo 'check_version - validate version consistency' @echo '-- TESTS --' @echo 'coverage - run unit tests and generate coverage report' @echo 'coverage_agents - run middleware and agent tests with coverage report' diff --git a/libs/langchain_v1/scripts/check_version.py b/libs/langchain_v1/scripts/check_version.py new file mode 100644 index 0000000000..7c48652c1e --- /dev/null +++ b/libs/langchain_v1/scripts/check_version.py @@ -0,0 +1,65 @@ +"""Check version consistency between pyproject.toml and __init__.py. + +This script validates that the version defined in pyproject.toml matches +the __version__ variable in langchain/__init__.py. Intended for use as +a pre-commit hook to prevent version mismatches. +""" + +import re +import sys +from pathlib import Path + + +def get_pyproject_version(pyproject_path: Path) -> str | None: + """Extract version from pyproject.toml.""" + content = pyproject_path.read_text() + match = re.search(r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE) + return match.group(1) if match else None + + +def get_init_version(init_path: Path) -> str | None: + """Extract __version__ from __init__.py.""" + content = init_path.read_text() + match = re.search(r'^__version__\s*=\s*"([^"]+)"', content, re.MULTILINE) + return match.group(1) if match else None + + +def main() -> int: + """Validate version consistency.""" + script_dir = Path(__file__).parent + package_dir = script_dir.parent + + pyproject_path = package_dir / "pyproject.toml" + init_path = package_dir / "langchain" / "__init__.py" + + if not pyproject_path.exists(): + print(f"Error: {pyproject_path} not found") # noqa: T201 + return 1 + + if not init_path.exists(): + print(f"Error: {init_path} not found") # noqa: T201 + return 1 + + pyproject_version = get_pyproject_version(pyproject_path) + init_version = get_init_version(init_path) + + if pyproject_version is None: + print("Error: Could not find version in pyproject.toml") # noqa: T201 + return 1 + + if init_version is None: + print("Error: Could not find __version__ in langchain/__init__.py") # noqa: T201 + return 1 + + if pyproject_version != init_version: + print("Error: Version mismatch detected!") # noqa: T201 + print(f" pyproject.toml: {pyproject_version}") # noqa: T201 + print(f" langchain/__init__.py: {init_version}") # noqa: T201 + return 1 + + print(f"Version check passed: {pyproject_version}") # noqa: T201 + return 0 + + +if __name__ == "__main__": + sys.exit(main())