diff --git a/.github/scripts/check_diff.py b/.github/scripts/check_diff.py index 73eaa52ecae..186d8a80d95 100644 --- a/.github/scripts/check_diff.py +++ b/.github/scripts/check_diff.py @@ -134,6 +134,8 @@ def _get_configs_for_single_dir(job: str, dir_: str) -> List[Dict[str, str]]: py_versions = ["3.10", "3.13"] elif dir_ == "libs/langchain_v1": py_versions = ["3.10", "3.13"] + elif dir_ in {"libs/cli"}: + py_versions = ["3.10", "3.13"] elif dir_ == ".": # unable to install with 3.13 because tokenizers doesn't support 3.13 yet diff --git a/.github/workflows/check_diffs.yml b/.github/workflows/check_diffs.yml index a27e6cdd9bc..ccf70e7e867 100644 --- a/.github/workflows/check_diffs.yml +++ b/.github/workflows/check_diffs.yml @@ -198,6 +198,28 @@ jobs: - name: '⚡ Run Benchmarks: ${{ matrix.job-configs.working-directory }}' uses: CodSpeedHQ/action@v4 + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + ANTHROPIC_FILES_API_IMAGE_ID: ${{ secrets.ANTHROPIC_FILES_API_IMAGE_ID }} + ANTHROPIC_FILES_API_PDF_ID: ${{ secrets.ANTHROPIC_FILES_API_PDF_ID }} + AZURE_OPENAI_API_VERSION: ${{ secrets.AZURE_OPENAI_API_VERSION }} + AZURE_OPENAI_API_BASE: ${{ secrets.AZURE_OPENAI_API_BASE }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }} + AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME }} + AZURE_OPENAI_LLM_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LLM_DEPLOYMENT_NAME }} + AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME }} + COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }} + DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }} + EXA_API_KEY: ${{ secrets.EXA_API_KEY }} + FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }} + GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }} + HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }} + MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }} + NOMIC_API_KEY: ${{ secrets.NOMIC_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + PPLX_API_KEY: ${{ secrets.PPLX_API_KEY }} + XAI_API_KEY: ${{ secrets.XAI_API_KEY }} with: token: ${{ secrets.CODSPEED_TOKEN }} run: | diff --git a/libs/cli/Makefile b/libs/cli/Makefile index 1dbec29a610..319ed2abfd8 100644 --- a/libs/cli/Makefile +++ b/libs/cli/Makefile @@ -38,15 +38,16 @@ _e2e_test: mkdir .integration_test cd .integration_test && \ python3 -m venv .venv && \ - pip install --upgrade poetry && \ + $(PYTHON) -m pip install --upgrade uv && \ $(PYTHON) -m pip install -e .. && \ $(PYTHON) -m langchain_cli.cli integration new --name parrot-link --name-class ParrotLink && \ $(PYTHON) -m langchain_cli.cli integration new --name parrot-link --name-class ParrotLinkB --src=integration_template/chat_models.py --dst=langchain-parrot-link/langchain_parrot_link/chat_models_b.py && \ $(PYTHON) -m langchain_cli.cli integration create-doc --name parrot-link --name-class ParrotLinkB --component-type ChatModel --destination-dir langchain-parrot-link/docs && \ cd langchain-parrot-link && \ - poetry install --with lint,typing,test && \ - poetry run pip install -e ../../../standard-tests && \ + unset UV_FROZEN && \ + unset VIRTUAL_ENV && \ + uv sync && \ + uv add --editable ../../../standard-tests && \ make format lint tests && \ - poetry install --with test_integration && \ - poetry run pip install -e ../../../core && \ + uv add --editable ../../../core && \ make integration_test diff --git a/libs/cli/langchain_cli/integration_template/Makefile b/libs/cli/langchain_cli/integration_template/Makefile index cb965ba5b3c..9ef2d93efeb 100644 --- a/libs/cli/langchain_cli/integration_template/Makefile +++ b/libs/cli/langchain_cli/integration_template/Makefile @@ -10,14 +10,14 @@ integration_test integration_tests: TEST_FILE = tests/integration_tests/ # unit tests are run with the --disable-socket flag to prevent network calls test tests: - poetry run pytest --disable-socket --allow-unix-socket $(TEST_FILE) + uv run pytest --disable-socket --allow-unix-socket $(TEST_FILE) test_watch: - poetry run ptw --snapshot-update --now . -- -vv $(TEST_FILE) + uv run ptw --snapshot-update --now . -- -vv $(TEST_FILE) # integration tests are run without the --disable-socket flag to allow network calls integration_test integration_tests: - poetry run pytest $(TEST_FILE) + uv run pytest $(TEST_FILE) ###################### # LINTING AND FORMATTING @@ -33,22 +33,22 @@ lint_tests: PYTHON_FILES=tests lint_tests: MYPY_CACHE=.mypy_cache_test lint lint_diff lint_package lint_tests: - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check $(PYTHON_FILES) - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff - [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) + [ "$(PYTHON_FILES)" = "" ] || uv run ruff check $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || uv run ruff format $(PYTHON_FILES) --diff + [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && uv run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) format format_diff: - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --fix $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || uv run ruff format $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || uv run ruff check --fix $(PYTHON_FILES) spell_check: - poetry run codespell --toml pyproject.toml + uv run codespell --toml pyproject.toml spell_fix: - poetry run codespell --toml pyproject.toml -w + uv run codespell --toml pyproject.toml -w check_imports: $(shell find __module_name__ -name '*.py') - poetry run python ./scripts/check_imports.py $^ + uv run python ./scripts/check_imports.py $^ ###################### # HELP diff --git a/libs/cli/langchain_cli/integration_template/pyproject.toml b/libs/cli/langchain_cli/integration_template/pyproject.toml index d94989dc00f..20c2b34772e 100644 --- a/libs/cli/langchain_cli/integration_template/pyproject.toml +++ b/libs/cli/langchain_cli/integration_template/pyproject.toml @@ -1,26 +1,38 @@ [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["pdm-backend"] +build-backend = "pdm.backend" -[tool.poetry] +[project] name = "__package_name__" version = "0.1.0" description = "An integration package connecting __ModuleName__ and LangChain" authors = [] readme = "README.md" -repository = "https://github.com/langchain-ai/langchain" license = "MIT" +requires-python = ">=3.10" +dependencies = [ + "langchain-core>=0.3.15", +] + +[project.urls] +"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/partners/__package_name_short__" +"Release Notes" = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22__package_name_short__%3D%3D0%22&expanded=true" +"Repository" = "https://github.com/langchain-ai/langchain" [tool.mypy] disallow_untyped_defs = "True" -[tool.poetry.urls] -"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/partners/__package_name_short__" -"Release Notes" = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22__package_name_short__%3D%3D0%22&expanded=true" - -[tool.poetry.dependencies] -python = ">=3.9,<4.0" -langchain-core = "^0.3.15" +[tool.uv] +dev-dependencies = [ + "pytest>=7.4.3", + "pytest-asyncio>=0.23.2", + "pytest-socket>=0.7.0", + "pytest-watcher>=0.3.4", + "langchain-tests>=0.3.5", + "codespell>=2.2.6", + "ruff>=0.5", + "mypy>=1.10", +] [tool.ruff.lint] select = ["E", "F", "I", "T201"] @@ -37,38 +49,3 @@ markers = [ "compile: mark placeholder test used to compile integration tests without running them", ] asyncio_mode = "auto" - -[tool.poetry.group.test] -optional = true - -[tool.poetry.group.codespell] -optional = true - -[tool.poetry.group.test_integration] -optional = true - -[tool.poetry.group.lint] -optional = true - -[tool.poetry.group.dev] -optional = true - -[tool.poetry.group.dev.dependencies] - -[tool.poetry.group.test.dependencies] -pytest = "^7.4.3" -pytest-asyncio = "^0.23.2" -pytest-socket = "^0.7.0" -pytest-watcher = "^0.3.4" -langchain-tests = "^0.3.5" - -[tool.poetry.group.codespell.dependencies] -codespell = "^2.2.6" - -[tool.poetry.group.test_integration.dependencies] - -[tool.poetry.group.lint.dependencies] -ruff = "^0.5" - -[tool.poetry.group.typing.dependencies] -mypy = "^1.10" diff --git a/libs/cli/langchain_cli/namespaces/app.py b/libs/cli/langchain_cli/namespaces/app.py index 20b629e9623..5572f72a719 100644 --- a/libs/cli/langchain_cli/namespaces/app.py +++ b/libs/cli/langchain_cli/namespaces/app.py @@ -52,7 +52,6 @@ def new( typer.Option( "--pip/--no-pip", help="Pip install the template(s) as editable dependencies", - is_flag=True, ), ] = None, noninteractive: Annotated[ @@ -60,7 +59,6 @@ def new( typer.Option( "--non-interactive/--interactive", help="Don't prompt for any input", - is_flag=True, ), ] = False, ) -> None: @@ -156,7 +154,6 @@ def add( typer.Option( "--pip/--no-pip", help="Pip install the template(s) as editable dependencies", - is_flag=True, prompt="Would you like to `pip install -e` the template(s)?", ), ], diff --git a/libs/cli/langchain_cli/namespaces/integration.py b/libs/cli/langchain_cli/namespaces/integration.py index 047d96f3a07..ca7b1c67641 100644 --- a/libs/cli/langchain_cli/namespaces/integration.py +++ b/libs/cli/langchain_cli/namespaces/integration.py @@ -1,7 +1,6 @@ """Develop integration packages for LangChain.""" -from __future__ import annotations - +import os import re import shutil import subprocess @@ -127,12 +126,28 @@ def new( # replacements in files replace_glob(destination_dir, "**/*", cast("dict[str, str]", replacements)) - # poetry install - subprocess.run( - ["poetry", "install", "--with", "lint,test,typing,test_integration"], # noqa: S607 - cwd=destination_dir, - check=True, - ) + # dependency install + try: + # Use --no-progress to avoid tty issues in CI/test environments + env = os.environ.copy() + env.pop("UV_FROZEN", None) + env.pop("VIRTUAL_ENV", None) + subprocess.run( + ["uv", "sync", "--dev", "--no-progress"], # noqa: S607 + cwd=destination_dir, + check=True, + env=env, + ) + except FileNotFoundError: + typer.echo( + "uv is not installed. Skipping dependency installation; run " + "`uv sync --dev` manually if needed.", + ) + except subprocess.CalledProcessError: + typer.echo( + "Failed to install dependencies. You may need to run " + "`uv sync --dev` manually in the package directory.", + ) else: # confirm src and dst are the same length if not src: diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index a7f6de2fc3a..7320f395f65 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -7,7 +7,7 @@ authors = [{ name = "Erick Friis", email = "erick@langchain.dev" }] license = { text = "MIT" } requires-python = ">=3.10" dependencies = [ - "typer<1.0.0,>=0.9.0", + "typer<1.0.0,>=0.17", "gitpython<4,>=3", "langserve[all]>=0.0.51", "uvicorn<1.0,>=0.23", @@ -80,6 +80,12 @@ pyupgrade.keep-runtime-typing = true "tests/**" = [ "D1", "DOC", "S", "SLF",] "scripts/**" = [ "INP", "S",] +[tool.pytest.ini_options] +addopts = "--strict-markers --strict-config --durations=5" +markers = [ + "compile: mark placeholder test used to compile integration tests without running them", +] + [tool.mypy] plugins = ["pydantic.mypy"] strict = true diff --git a/libs/cli/uv.lock b/libs/cli/uv.lock index 73df7f8f573..39913fbf5a0 100644 --- a/libs/cli/uv.lock +++ b/libs/cli/uv.lock @@ -468,7 +468,7 @@ requires-dist = [ { name = "gritql", specifier = ">=0.2.0,<1.0.0" }, { name = "langserve", extras = ["all"], specifier = ">=0.0.51" }, { name = "tomlkit", specifier = ">=0.12" }, - { name = "typer", specifier = ">=0.9.0,<1.0.0" }, + { name = "typer", specifier = ">=0.17,<1.0.0" }, { name = "uvicorn", specifier = ">=0.23,<1.0" }, ]