diff --git a/libs/langchain/pyproject.toml b/libs/langchain/pyproject.toml index c25cb2685c2..be538730303 100644 --- a/libs/langchain/pyproject.toml +++ b/libs/langchain/pyproject.toml @@ -152,6 +152,8 @@ test = [ "langchain-core @ file:///${PROJECT_ROOT}/../core", "langchain-text-splitters @ file:///${PROJECT_ROOT}/../text-splitters", "langchain-openai @ file:///${PROJECT_ROOT}/../partners/openai", + "toml>=0.10.2", + "packaging>=24.2", ] codespell = [ "codespell<3.0.0,>=2.2.0", diff --git a/libs/langchain/tests/unit_tests/test_dependencies.py b/libs/langchain/tests/unit_tests/test_dependencies.py index 285daa62017..a029ea84788 100644 --- a/libs/langchain/tests/unit_tests/test_dependencies.py +++ b/libs/langchain/tests/unit_tests/test_dependencies.py @@ -5,6 +5,7 @@ from typing import Any, Dict, Mapping import pytest import toml +from packaging.requirements import Requirement HERE = Path(__file__).parent @@ -12,30 +13,21 @@ PYPROJECT_TOML = HERE / "../../pyproject.toml" @pytest.fixture() -def poetry_conf() -> Dict[str, Any]: +def uv_conf() -> Dict[str, Any]: """Load the pyproject.toml file.""" with open(PYPROJECT_TOML) as f: - return toml.load(f)["tool"]["poetry"] + return toml.load(f) -def test_required_dependencies(poetry_conf: Mapping[str, Any]) -> None: +def test_required_dependencies(uv_conf: Mapping[str, Any]) -> None: """A test that checks if a new non-optional dependency is being introduced. If this test is triggered, it means that a contributor is trying to introduce a new required dependency. This should be avoided in most situations. """ # Get the dependencies from the [tool.poetry.dependencies] section - dependencies = poetry_conf["dependencies"] - - is_required = { - package_name: isinstance(requirements, str) - or isinstance(requirements, list) - or not requirements.get("optional", False) - for package_name, requirements in dependencies.items() - } - required_dependencies = [ - package_name for package_name, required in is_required.items() if required - ] + dependencies = uv_conf["project"]["dependencies"] + required_dependencies = set(Requirement(dep).name for dep in dependencies) assert sorted(required_dependencies) == sorted( [ @@ -48,22 +40,13 @@ def test_required_dependencies(poetry_conf: Mapping[str, Any]) -> None: "langsmith", "numpy", "pydantic", - "python", "requests", "tenacity", ] ) - unrequired_dependencies = [ - package_name for package_name, required in is_required.items() if not required - ] - in_extras = [ - dep for group in poetry_conf.get("extras", {}).values() for dep in group - ] - assert set(unrequired_dependencies) == set(in_extras) - -def test_test_group_dependencies(poetry_conf: Mapping[str, Any]) -> None: +def test_test_group_dependencies(uv_conf: Mapping[str, Any]) -> None: """Check if someone is attempting to add additional test dependencies. Only dependencies associated with test running infrastructure should be added @@ -72,9 +55,10 @@ def test_test_group_dependencies(poetry_conf: Mapping[str, Any]) -> None: Examples of dependencies that should NOT be included: boto3, azure, postgres, etc. """ - test_group_deps = sorted(poetry_conf["group"]["test"]["dependencies"]) + dependencies = uv_conf["dependency-groups"]["test"] + test_group_deps = set(Requirement(dep).name for dep in dependencies) - assert test_group_deps == sorted( + assert sorted(test_group_deps) == sorted( [ "duckdb-engine", "freezegun", @@ -83,6 +67,7 @@ def test_test_group_dependencies(poetry_conf: Mapping[str, Any]) -> None: "langchain-text-splitters", "langchain-openai", "lark", + "packaging", "pandas", "pytest", "pytest-asyncio", @@ -94,6 +79,7 @@ def test_test_group_dependencies(poetry_conf: Mapping[str, Any]) -> None: "pytest-xdist", "responses", "syrupy", + "toml", "requests-mock", # TODO: temporary hack since cffi 1.17.1 doesn't work with py 3.9. "cffi", diff --git a/libs/langchain/uv.lock b/libs/langchain/uv.lock index 599ca9a8238..6a4952ef92a 100644 --- a/libs/langchain/uv.lock +++ b/libs/langchain/uv.lock @@ -1650,6 +1650,7 @@ test = [ { name = "langchain-tests" }, { name = "langchain-text-splitters" }, { name = "lark" }, + { name = "packaging" }, { name = "pandas" }, { name = "pytest" }, { name = "pytest-asyncio" }, @@ -1662,6 +1663,7 @@ test = [ { name = "requests-mock" }, { name = "responses" }, { name = "syrupy" }, + { name = "toml" }, ] test-integration = [ { name = "cassio" }, @@ -1725,6 +1727,7 @@ test = [ { name = "langchain-tests", directory = "../standard-tests" }, { name = "langchain-text-splitters", directory = "../text-splitters" }, { name = "lark", specifier = ">=1.1.5,<2.0.0" }, + { name = "packaging", specifier = ">=24.2" }, { name = "pandas", specifier = ">=2.0.0,<3.0.0" }, { name = "pytest", specifier = ">=8,<9" }, { name = "pytest-asyncio", specifier = ">=0.23.2,<1.0.0" }, @@ -1737,6 +1740,7 @@ test = [ { name = "requests-mock", specifier = ">=1.11.0,<2.0.0" }, { name = "responses", specifier = ">=0.22.0,<1.0.0" }, { name = "syrupy", specifier = ">=4.0.2,<5.0.0" }, + { name = "toml", specifier = ">=0.10.2" }, ] test-integration = [ { name = "cassio", specifier = ">=0.1.0,<1.0.0" }, @@ -3783,6 +3787,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, +] + [[package]] name = "tomli" version = "2.2.1"