mirror of
https://github.com/hwchase17/langchain.git
synced 2025-09-20 01:54:14 +00:00
refactor(cli): drop Python 3.9 (#32964)
This commit is contained in:
2
.github/scripts/check_diff.py
vendored
2
.github/scripts/check_diff.py
vendored
@@ -134,6 +134,8 @@ def _get_configs_for_single_dir(job: str, dir_: str) -> List[Dict[str, str]]:
|
|||||||
py_versions = ["3.9", "3.13"]
|
py_versions = ["3.9", "3.13"]
|
||||||
elif dir_ == "libs/langchain_v1":
|
elif dir_ == "libs/langchain_v1":
|
||||||
py_versions = ["3.10", "3.13"]
|
py_versions = ["3.10", "3.13"]
|
||||||
|
elif dir_ in {"libs/cli"}:
|
||||||
|
py_versions = ["3.10", "3.13"]
|
||||||
|
|
||||||
elif dir_ == ".":
|
elif dir_ == ".":
|
||||||
# unable to install with 3.13 because tokenizers doesn't support 3.13 yet
|
# unable to install with 3.13 because tokenizers doesn't support 3.13 yet
|
||||||
|
@@ -38,15 +38,16 @@ _e2e_test:
|
|||||||
mkdir .integration_test
|
mkdir .integration_test
|
||||||
cd .integration_test && \
|
cd .integration_test && \
|
||||||
python3 -m venv .venv && \
|
python3 -m venv .venv && \
|
||||||
pip install --upgrade poetry && \
|
$(PYTHON) -m pip install --upgrade uv && \
|
||||||
$(PYTHON) -m pip install -e .. && \
|
$(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 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 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 && \
|
$(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 && \
|
cd langchain-parrot-link && \
|
||||||
poetry install --with lint,typing,test && \
|
unset UV_FROZEN && \
|
||||||
poetry run pip install -e ../../../standard-tests && \
|
unset VIRTUAL_ENV && \
|
||||||
|
uv sync && \
|
||||||
|
uv add --editable ../../../standard-tests && \
|
||||||
make format lint tests && \
|
make format lint tests && \
|
||||||
poetry install --with test_integration && \
|
uv add --editable ../../../core && \
|
||||||
poetry run pip install -e ../../../core && \
|
|
||||||
make integration_test
|
make integration_test
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
"""LangChain CLI."""
|
"""LangChain CLI."""
|
||||||
|
|
||||||
from typing import Annotated, Optional
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
@@ -61,11 +63,11 @@ def _main(
|
|||||||
def serve(
|
def serve(
|
||||||
*,
|
*,
|
||||||
port: Annotated[
|
port: Annotated[
|
||||||
Optional[int],
|
int | None,
|
||||||
typer.Option(help="The port to run the server on"),
|
typer.Option(help="The port to run the server on"),
|
||||||
] = None,
|
] = None,
|
||||||
host: Annotated[
|
host: Annotated[
|
||||||
Optional[str],
|
str | None,
|
||||||
typer.Option(help="The host to run the server on"),
|
typer.Option(help="The host to run the server on"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@@ -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
|
# unit tests are run with the --disable-socket flag to prevent network calls
|
||||||
test tests:
|
test tests:
|
||||||
poetry run pytest --disable-socket --allow-unix-socket $(TEST_FILE)
|
uv run pytest --disable-socket --allow-unix-socket $(TEST_FILE)
|
||||||
|
|
||||||
test_watch:
|
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 tests are run without the --disable-socket flag to allow network calls
|
||||||
integration_test integration_tests:
|
integration_test integration_tests:
|
||||||
poetry run pytest $(TEST_FILE)
|
uv run pytest $(TEST_FILE)
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# LINTING AND FORMATTING
|
# LINTING AND FORMATTING
|
||||||
@@ -33,22 +33,22 @@ lint_tests: PYTHON_FILES=tests
|
|||||||
lint_tests: MYPY_CACHE=.mypy_cache_test
|
lint_tests: MYPY_CACHE=.mypy_cache_test
|
||||||
|
|
||||||
lint lint_diff lint_package lint_tests:
|
lint lint_diff lint_package lint_tests:
|
||||||
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff check $(PYTHON_FILES)
|
[ "$(PYTHON_FILES)" = "" ] || uv run ruff check $(PYTHON_FILES)
|
||||||
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff
|
[ "$(PYTHON_FILES)" = "" ] || uv run ruff format $(PYTHON_FILES) --diff
|
||||||
[ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE)
|
[ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) && uv run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE)
|
||||||
|
|
||||||
format format_diff:
|
format format_diff:
|
||||||
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES)
|
[ "$(PYTHON_FILES)" = "" ] || uv run ruff format $(PYTHON_FILES)
|
||||||
[ "$(PYTHON_FILES)" = "" ] || poetry run ruff check --fix $(PYTHON_FILES)
|
[ "$(PYTHON_FILES)" = "" ] || uv run ruff check --fix $(PYTHON_FILES)
|
||||||
|
|
||||||
spell_check:
|
spell_check:
|
||||||
poetry run codespell --toml pyproject.toml
|
uv run codespell --toml pyproject.toml
|
||||||
|
|
||||||
spell_fix:
|
spell_fix:
|
||||||
poetry run codespell --toml pyproject.toml -w
|
uv run codespell --toml pyproject.toml -w
|
||||||
|
|
||||||
check_imports: $(shell find __module_name__ -name '*.py')
|
check_imports: $(shell find __module_name__ -name '*.py')
|
||||||
poetry run python ./scripts/check_imports.py $^
|
uv run python ./scripts/check_imports.py $^
|
||||||
|
|
||||||
######################
|
######################
|
||||||
# HELP
|
# HELP
|
||||||
|
@@ -89,7 +89,7 @@ class Chat__ModuleName__(BaseChatModel):
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
for chunk in llm.stream(messages):
|
for chunk in llm.stream(messages):
|
||||||
print(chunk.text(), end="")
|
print(chunk.text, end="")
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@@ -1,26 +1,38 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["pdm-backend"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "pdm.backend"
|
||||||
|
|
||||||
[tool.poetry]
|
[project]
|
||||||
name = "__package_name__"
|
name = "__package_name__"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "An integration package connecting __ModuleName__ and LangChain"
|
description = "An integration package connecting __ModuleName__ and LangChain"
|
||||||
authors = []
|
authors = []
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/langchain-ai/langchain"
|
|
||||||
license = "MIT"
|
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]
|
[tool.mypy]
|
||||||
disallow_untyped_defs = "True"
|
disallow_untyped_defs = "True"
|
||||||
|
|
||||||
[tool.poetry.urls]
|
[tool.uv]
|
||||||
"Source Code" = "https://github.com/langchain-ai/langchain/tree/master/libs/partners/__package_name_short__"
|
dev-dependencies = [
|
||||||
"Release Notes" = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22__package_name_short__%3D%3D0%22&expanded=true"
|
"pytest>=7.4.3",
|
||||||
|
"pytest-asyncio>=0.23.2",
|
||||||
[tool.poetry.dependencies]
|
"pytest-socket>=0.7.0",
|
||||||
python = ">=3.9,<4.0"
|
"pytest-watcher>=0.3.4",
|
||||||
langchain-core = "^0.3.15"
|
"langchain-tests>=0.3.5",
|
||||||
|
"codespell>=2.2.6",
|
||||||
|
"ruff>=0.5",
|
||||||
|
"mypy>=1.10",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = ["E", "F", "I", "T201"]
|
select = ["E", "F", "I", "T201"]
|
||||||
@@ -37,38 +49,3 @@ markers = [
|
|||||||
"compile: mark placeholder test used to compile integration tests without running them",
|
"compile: mark placeholder test used to compile integration tests without running them",
|
||||||
]
|
]
|
||||||
asyncio_mode = "auto"
|
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"
|
|
||||||
|
@@ -50,7 +50,6 @@ def new(
|
|||||||
typer.Option(
|
typer.Option(
|
||||||
"--pip/--no-pip",
|
"--pip/--no-pip",
|
||||||
help="Pip install the template(s) as editable dependencies",
|
help="Pip install the template(s) as editable dependencies",
|
||||||
is_flag=True,
|
|
||||||
),
|
),
|
||||||
] = None,
|
] = None,
|
||||||
noninteractive: Annotated[
|
noninteractive: Annotated[
|
||||||
@@ -58,7 +57,6 @@ def new(
|
|||||||
typer.Option(
|
typer.Option(
|
||||||
"--non-interactive/--interactive",
|
"--non-interactive/--interactive",
|
||||||
help="Don't prompt for any input",
|
help="Don't prompt for any input",
|
||||||
is_flag=True,
|
|
||||||
),
|
),
|
||||||
] = False,
|
] = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -154,7 +152,6 @@ def add(
|
|||||||
typer.Option(
|
typer.Option(
|
||||||
"--pip/--no-pip",
|
"--pip/--no-pip",
|
||||||
help="Pip install the template(s) as editable dependencies",
|
help="Pip install the template(s) as editable dependencies",
|
||||||
is_flag=True,
|
|
||||||
prompt="Would you like to `pip install -e` the template(s)?",
|
prompt="Would you like to `pip install -e` the template(s)?",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -241,7 +238,7 @@ def add(
|
|||||||
try:
|
try:
|
||||||
add_dependencies_to_pyproject_toml(
|
add_dependencies_to_pyproject_toml(
|
||||||
project_root / "pyproject.toml",
|
project_root / "pyproject.toml",
|
||||||
zip(installed_destination_names, installed_destination_paths),
|
zip(installed_destination_names, installed_destination_paths, strict=False),
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
# Can fail if user modified/removed pyproject.toml
|
# Can fail if user modified/removed pyproject.toml
|
||||||
@@ -279,11 +276,11 @@ def add(
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
f"from {e['module']} import {e['attr']} as {name}"
|
f"from {e['module']} import {e['attr']} as {name}"
|
||||||
for e, name in zip(installed_exports, chain_names)
|
for e, name in zip(installed_exports, chain_names, strict=False)
|
||||||
]
|
]
|
||||||
routes = [
|
routes = [
|
||||||
f'add_routes(app, {name}, path="{path}")'
|
f'add_routes(app, {name}, path="{path}")'
|
||||||
for name, path in zip(chain_names, api_paths)
|
for name, path in zip(chain_names, api_paths, strict=False)
|
||||||
]
|
]
|
||||||
|
|
||||||
t = (
|
t = (
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
"""Develop integration packages for LangChain."""
|
"""Develop integration packages for LangChain."""
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -125,12 +126,28 @@ def new(
|
|||||||
# replacements in files
|
# replacements in files
|
||||||
replace_glob(destination_dir, "**/*", cast("dict[str, str]", replacements))
|
replace_glob(destination_dir, "**/*", cast("dict[str, str]", replacements))
|
||||||
|
|
||||||
# poetry install
|
# dependency install
|
||||||
subprocess.run(
|
try:
|
||||||
["poetry", "install", "--with", "lint,test,typing,test_integration"], # noqa: S607
|
# Use --no-progress to avoid tty issues in CI/test environments
|
||||||
cwd=destination_dir,
|
env = os.environ.copy()
|
||||||
check=True,
|
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:
|
else:
|
||||||
# confirm src and dst are the same length
|
# confirm src and dst are the same length
|
||||||
if not src:
|
if not src:
|
||||||
@@ -166,7 +183,7 @@ def new(
|
|||||||
typer.echo(f"File {dst_path} exists.")
|
typer.echo(f"File {dst_path} exists.")
|
||||||
raise typer.Exit(code=1)
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
for src_path, dst_path in zip(src_paths, dst_paths):
|
for src_path, dst_path in zip(src_paths, dst_paths, strict=False):
|
||||||
shutil.copy(src_path, dst_path)
|
shutil.copy(src_path, dst_path)
|
||||||
replace_file(dst_path, cast("dict[str, str]", replacements))
|
replace_file(dst_path, cast("dict[str, str]", replacements))
|
||||||
|
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
"""Events utilities."""
|
"""Events utilities."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import http.client
|
import http.client
|
||||||
import json
|
import json
|
||||||
from typing import Any, Optional, TypedDict
|
from typing import Any, TypedDict
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
@@ -18,10 +20,10 @@ class EventDict(TypedDict):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
event: str
|
event: str
|
||||||
properties: Optional[dict[str, Any]]
|
properties: dict[str, Any] | None
|
||||||
|
|
||||||
|
|
||||||
def create_events(events: list[EventDict]) -> Optional[dict[str, Any]]:
|
def create_events(events: list[EventDict]) -> dict[str, Any] | None:
|
||||||
"""Create events.
|
"""Create events.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
"""Git utilities."""
|
"""Git utilities."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional, TypedDict
|
from typing import Any, TypedDict
|
||||||
|
|
||||||
from git import Repo
|
from git import Repo
|
||||||
|
|
||||||
@@ -23,18 +25,18 @@ class DependencySource(TypedDict):
|
|||||||
"""Dependency source information."""
|
"""Dependency source information."""
|
||||||
|
|
||||||
git: str
|
git: str
|
||||||
ref: Optional[str]
|
ref: str | None
|
||||||
subdirectory: Optional[str]
|
subdirectory: str | None
|
||||||
api_path: Optional[str]
|
api_path: str | None
|
||||||
event_metadata: dict[str, Any]
|
event_metadata: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
# use poetry dependency string format
|
# use poetry dependency string format
|
||||||
def parse_dependency_string(
|
def parse_dependency_string(
|
||||||
dep: Optional[str],
|
dep: str | None,
|
||||||
repo: Optional[str],
|
repo: str | None,
|
||||||
branch: Optional[str],
|
branch: str | None,
|
||||||
api_path: Optional[str],
|
api_path: str | None,
|
||||||
) -> DependencySource:
|
) -> DependencySource:
|
||||||
"""Parse a dependency string into a DependencySource.
|
"""Parse a dependency string into a DependencySource.
|
||||||
|
|
||||||
@@ -125,7 +127,7 @@ def parse_dependency_string(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _list_arg_to_length(arg: Optional[list[str]], num: int) -> Sequence[Optional[str]]:
|
def _list_arg_to_length(arg: list[str] | None, num: int) -> Sequence[str | None]:
|
||||||
if not arg:
|
if not arg:
|
||||||
return [None] * num
|
return [None] * num
|
||||||
if len(arg) == 1:
|
if len(arg) == 1:
|
||||||
@@ -137,7 +139,7 @@ def _list_arg_to_length(arg: Optional[list[str]], num: int) -> Sequence[Optional
|
|||||||
|
|
||||||
|
|
||||||
def parse_dependencies(
|
def parse_dependencies(
|
||||||
dependencies: Optional[list[str]],
|
dependencies: list[str] | None,
|
||||||
repo: list[str],
|
repo: list[str],
|
||||||
branch: list[str],
|
branch: list[str],
|
||||||
api_path: list[str],
|
api_path: list[str],
|
||||||
@@ -180,17 +182,18 @@ def parse_dependencies(
|
|||||||
inner_branches = _list_arg_to_length(branch, num_deps)
|
inner_branches = _list_arg_to_length(branch, num_deps)
|
||||||
|
|
||||||
return list(
|
return list(
|
||||||
map(
|
map( # type: ignore[call-overload]
|
||||||
parse_dependency_string,
|
parse_dependency_string,
|
||||||
inner_deps,
|
inner_deps,
|
||||||
inner_repos,
|
inner_repos,
|
||||||
inner_branches,
|
inner_branches,
|
||||||
inner_api_paths,
|
inner_api_paths,
|
||||||
|
strict=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_repo_path(gitstring: str, ref: Optional[str], repo_dir: Path) -> Path:
|
def _get_repo_path(gitstring: str, ref: str | None, repo_dir: Path) -> Path:
|
||||||
# only based on git for now
|
# only based on git for now
|
||||||
ref_str = ref if ref is not None else ""
|
ref_str = ref if ref is not None else ""
|
||||||
hashed = hashlib.sha256((f"{gitstring}:{ref_str}").encode()).hexdigest()[:8]
|
hashed = hashlib.sha256((f"{gitstring}:{ref_str}").encode()).hexdigest()[:8]
|
||||||
@@ -204,7 +207,7 @@ def _get_repo_path(gitstring: str, ref: Optional[str], repo_dir: Path) -> Path:
|
|||||||
return repo_dir / directory_name
|
return repo_dir / directory_name
|
||||||
|
|
||||||
|
|
||||||
def update_repo(gitstring: str, ref: Optional[str], repo_dir: Path) -> Path:
|
def update_repo(gitstring: str, ref: str | None, repo_dir: Path) -> Path:
|
||||||
"""Update a git repository to the specified ref.
|
"""Update a git repository to the specified ref.
|
||||||
|
|
||||||
Tries to pull if the repo already exists, otherwise clones it.
|
Tries to pull if the repo already exists, otherwise clones it.
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
"""GitHub utilities."""
|
"""GitHub utilities."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import http.client
|
import http.client
|
||||||
import json
|
import json
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
def list_packages(*, contains: Optional[str] = None) -> list[str]:
|
def list_packages(*, contains: str | None = None) -> list[str]:
|
||||||
"""List all packages in the langchain repository templates directory.
|
"""List all packages in the langchain repository templates directory.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
"""Packages utilities."""
|
"""Packages utilities."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional, TypedDict
|
from typing import Any, TypedDict, cast
|
||||||
|
|
||||||
from tomlkit import load
|
from tomlkit import load
|
||||||
|
|
||||||
|
|
||||||
def get_package_root(cwd: Optional[Path] = None) -> Path:
|
def get_package_root(cwd: Path | None = None) -> Path:
|
||||||
"""Get package root directory.
|
"""Get package root directory.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -62,11 +64,12 @@ def get_langserve_export(filepath: Path) -> LangServeExport:
|
|||||||
KeyError: If the `pyproject.toml` file is missing required fields.
|
KeyError: If the `pyproject.toml` file is missing required fields.
|
||||||
"""
|
"""
|
||||||
with filepath.open() as f:
|
with filepath.open() as f:
|
||||||
data: dict[str, Any] = load(f)
|
# tomlkit types aren't amazing - treat as Dict instead
|
||||||
|
data = cast("dict[str, Any]", load(f))
|
||||||
try:
|
try:
|
||||||
module = data["tool"]["langserve"]["export_module"]
|
module = str(data["tool"]["langserve"]["export_module"])
|
||||||
attr = data["tool"]["langserve"]["export_attr"]
|
attr = str(data["tool"]["langserve"]["export_attr"])
|
||||||
package_name = data["tool"]["poetry"]["name"]
|
package_name = str(data["tool"]["poetry"]["name"])
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
msg = "Invalid LangServe PyProject.toml"
|
msg = "Invalid LangServe PyProject.toml"
|
||||||
raise KeyError(msg) from e
|
raise KeyError(msg) from e
|
||||||
|
@@ -5,9 +5,9 @@ build-backend = "pdm.backend"
|
|||||||
[project]
|
[project]
|
||||||
authors = [{ name = "Erick Friis", email = "erick@langchain.dev" }]
|
authors = [{ name = "Erick Friis", email = "erick@langchain.dev" }]
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typer<1.0.0,>=0.9.0",
|
"typer<1.0.0,>=0.17",
|
||||||
"gitpython<4,>=3",
|
"gitpython<4,>=3",
|
||||||
"langserve[all]>=0.0.51",
|
"langserve[all]>=0.0.51",
|
||||||
"uvicorn<1.0,>=0.23",
|
"uvicorn<1.0,>=0.23",
|
||||||
@@ -80,6 +80,12 @@ pyupgrade.keep-runtime-typing = true
|
|||||||
"tests/**" = [ "D1", "DOC", "S", "SLF",]
|
"tests/**" = [ "D1", "DOC", "S", "SLF",]
|
||||||
"scripts/**" = [ "INP", "S",]
|
"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]
|
[tool.mypy]
|
||||||
plugins = ["pydantic.mypy"]
|
plugins = ["pydantic.mypy"]
|
||||||
strict = true
|
strict = true
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
"""Script to generate migrations for the migration script."""
|
"""Script to generate migrations for the migration script."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import pkgutil
|
import pkgutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ def cli() -> None:
|
|||||||
def generic(
|
def generic(
|
||||||
pkg1: str,
|
pkg1: str,
|
||||||
pkg2: str,
|
pkg2: str,
|
||||||
output: Optional[str],
|
output: str | None,
|
||||||
filter_by_all: bool, # noqa: FBT001
|
filter_by_all: bool, # noqa: FBT001
|
||||||
format_: str,
|
format_: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -76,7 +77,7 @@ def generic(
|
|||||||
Path(output).write_text(dumped, encoding="utf-8")
|
Path(output).write_text(dumped, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
def handle_partner(pkg: str, output: Optional[str] = None) -> None:
|
def handle_partner(pkg: str, output: str | None = None) -> None:
|
||||||
"""Handle partner package migrations."""
|
"""Handle partner package migrations."""
|
||||||
migrations = get_migrations_for_partner_package(pkg)
|
migrations = get_migrations_for_partner_package(pkg)
|
||||||
# Run with python 3.9+
|
# Run with python 3.9+
|
||||||
|
@@ -52,7 +52,7 @@ class Folder:
|
|||||||
if len(self.files) != len(__value.files):
|
if len(self.files) != len(__value.files):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for self_file, other_file in zip(self.files, __value.files):
|
for self_file, other_file in zip(self.files, __value.files, strict=False):
|
||||||
if self_file != other_file:
|
if self_file != other_file:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ pytest.importorskip("gritql")
|
|||||||
|
|
||||||
|
|
||||||
def find_issue(current: Folder, expected: Folder) -> str:
|
def find_issue(current: Folder, expected: Folder) -> str:
|
||||||
for current_file, expected_file in zip(current.files, expected.files):
|
for current_file, expected_file in zip(current.files, expected.files, strict=False):
|
||||||
if current_file != expected_file:
|
if current_file != expected_file:
|
||||||
if current_file.name != expected_file.name:
|
if current_file.name != expected_file.name:
|
||||||
return (
|
return (
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
from typing import Any, Optional
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -13,10 +15,10 @@ from langchain_cli.utils.git import DependencySource, parse_dependency_string
|
|||||||
def _assert_dependency_equals(
|
def _assert_dependency_equals(
|
||||||
dep: DependencySource,
|
dep: DependencySource,
|
||||||
*,
|
*,
|
||||||
git: Optional[str] = None,
|
git: str | None = None,
|
||||||
ref: Optional[str] = None,
|
ref: str | None = None,
|
||||||
subdirectory: Optional[str] = None,
|
subdirectory: str | None = None,
|
||||||
event_metadata: Optional[dict[str, Any]] = None,
|
event_metadata: dict[str, Any] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if dep["git"] != git:
|
if dep["git"] != git:
|
||||||
msg = f"Expected git to be {git} but got {dep['git']}"
|
msg = f"Expected git to be {git} but got {dep['git']}"
|
||||||
|
1120
libs/cli/uv.lock
generated
1120
libs/cli/uv.lock
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user