chore(cli): select ALL rules with exclusions (#31936)

Co-authored-by: Mason Daugherty <mason@langchain.dev>
This commit is contained in:
Christophe Bornet
2025-08-12 00:43:11 +02:00
committed by GitHub
parent 09a616fe85
commit cf2b4bbe09
15 changed files with 78 additions and 89 deletions

View File

@@ -13,7 +13,7 @@ def create_demo_server(
*,
config_keys: Sequence[str] = (),
playground_type: Literal["default", "chat"] = "default",
):
) -> FastAPI:
"""Create a demo server for the current template."""
app = FastAPI()
package_root = get_package_root()
@@ -40,11 +40,11 @@ def create_demo_server(
return app
def create_demo_server_configurable():
def create_demo_server_configurable() -> FastAPI:
"""Create a configurable demo server."""
return create_demo_server(config_keys=["configurable"])
def create_demo_server_chat():
def create_demo_server_chat() -> FastAPI:
"""Create a chat demo server."""
return create_demo_server(playground_type="chat")

View File

@@ -8,6 +8,7 @@ from pathlib import Path
from typing import Annotated, Optional
import typer
import uvicorn
from langchain_cli.utils.events import create_events
from langchain_cli.utils.git import (
@@ -261,7 +262,7 @@ def add(
cmd = ["pip", "install", "-e", *installed_destination_strs]
cmd_str = " \\\n ".join(installed_destination_strs)
typer.echo(f"Running: pip install -e \\\n {cmd_str}")
subprocess.run(cmd, cwd=cwd) # noqa: S603
subprocess.run(cmd, cwd=cwd, check=True) # noqa: S603
chain_names = []
for e in installed_exports:
@@ -367,8 +368,6 @@ def serve(
app_str = app if app is not None else "app.server:app"
host_str = host if host is not None else "127.0.0.1"
import uvicorn
uvicorn.run(
app_str,
host=host_str,

View File

@@ -129,6 +129,7 @@ def new(
subprocess.run(
["poetry", "install", "--with", "lint,test,typing,test_integration"], # noqa: S607
cwd=destination_dir,
check=True,
)
else:
# confirm src and dst are the same length

View File

@@ -3,6 +3,7 @@
import importlib
import inspect
import pkgutil
from types import ModuleType
def generate_raw_migrations(
@@ -89,7 +90,7 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
items = []
# Function to handle importing from modules
def handle_module(module, module_name) -> None:
def handle_module(module: ModuleType, module_name: str) -> None:
if hasattr(module, "__all__"):
all_objects = module.__all__
for name in all_objects:

View File

@@ -5,10 +5,9 @@ import inspect
import os
import pathlib
from pathlib import Path
from types import ModuleType
from typing import Any, Optional
from typing_extensions import override
HERE = Path(__file__).parent
# Should bring us to [root]/src
PKGS_ROOT = HERE.parent.parent.parent.parent.parent
@@ -19,15 +18,14 @@ PARTNER_PKGS = PKGS_ROOT / "partners"
class ImportExtractor(ast.NodeVisitor):
"""Import extractor"""
"""Import extractor."""
def __init__(self, *, from_package: Optional[str] = None) -> None:
"""Extract all imports from the given code, optionally filtering by package."""
self.imports: list = []
self.package = from_package
@override
def visit_ImportFrom(self, node) -> None:
def visit_ImportFrom(self, node: ast.ImportFrom) -> None: # noqa: N802
if node.module and (
self.package is None or str(node.module).startswith(self.package)
):
@@ -46,7 +44,7 @@ def _get_class_names(code: str) -> list[str]:
# Define a node visitor class to collect class names
class ClassVisitor(ast.NodeVisitor):
def visit_ClassDef(self, node) -> None: # noqa: N802
def visit_ClassDef(self, node: ast.ClassDef) -> None: # noqa: N802
class_names.append(node.name)
self.generic_visit(node)
@@ -65,7 +63,7 @@ def is_subclass(class_obj: Any, classes_: list[type]) -> bool:
)
def find_subclasses_in_module(module, classes_: list[type]) -> list[str]:
def find_subclasses_in_module(module: ModuleType, classes_: list[type]) -> list[str]:
"""Find all classes in the module that inherit from one of the classes."""
subclasses = []
# Iterate over all attributes of the module that are classes
@@ -77,8 +75,7 @@ def find_subclasses_in_module(module, classes_: list[type]) -> list[str]:
def _get_all_classnames_from_file(file: Path, pkg: str) -> list[tuple[str, str]]:
"""Extract all class names from a file."""
with open(file, encoding="utf-8") as f:
code = f.read()
code = Path(file).read_text(encoding="utf-8")
module_name = _get_current_module(file, pkg)
class_names = _get_class_names(code)
@@ -91,8 +88,7 @@ def identify_all_imports_in_file(
from_package: Optional[str] = None,
) -> list[tuple[str, str]]:
"""Let's also identify all the imports in the given file."""
with open(file, encoding="utf-8") as f:
code = f.read()
code = Path(file).read_text(encoding="utf-8")
return find_imports_from_package(code, from_package=from_package)
@@ -162,8 +158,7 @@ def find_imports_from_package(
def _get_current_module(path: Path, pkg_root: str) -> str:
"""Convert a path to a module name."""
path_as_pathlib = pathlib.Path(os.path.abspath(path))
relative_path = path_as_pathlib.relative_to(pkg_root).with_suffix("")
relative_path = path.relative_to(pkg_root).with_suffix("")
posix_path = relative_path.as_posix()
norm_path = os.path.normpath(str(posix_path))
fully_qualified_module = norm_path.replace("/", ".")

View File

@@ -7,7 +7,9 @@ from pathlib import Path
from typing import Annotated, Optional
import typer
import uvicorn
from langchain_cli.utils.github import list_packages
from langchain_cli.utils.packages import get_langserve_export, get_package_root
package_cli = typer.Typer(no_args_is_help=True, add_completion=False)
@@ -79,7 +81,7 @@ def new(
# poetry install
if with_poetry:
subprocess.run(["poetry", "install"], cwd=destination_dir) # noqa: S607
subprocess.run(["poetry", "install"], cwd=destination_dir, check=True) # noqa: S607
@package_cli.command()
@@ -128,8 +130,6 @@ def serve(
)
)
import uvicorn
uvicorn.run(
script,
factory=True,
@@ -142,8 +142,6 @@ def serve(
@package_cli.command()
def list(contains: Annotated[Optional[str], typer.Argument()] = None) -> None: # noqa: A001
"""List all or search for available templates."""
from langchain_cli.utils.github import list_packages
packages = list_packages(contains=contains)
for package in packages:
typer.echo(package)

View File

@@ -16,6 +16,7 @@ class EventDict(TypedDict):
event: The name of the event.
properties: Optional dictionary of event properties.
"""
event: str
properties: Optional[dict[str, Any]]

View File

@@ -1,6 +1,7 @@
"""Git utilities."""
import hashlib
import logging
import re
import shutil
from collections.abc import Sequence
@@ -15,6 +16,8 @@ from langchain_cli.constants import (
DEFAULT_GIT_SUBDIRECTORY,
)
logger = logging.getLogger(__name__)
class DependencySource(TypedDict):
"""Dependency source information."""
@@ -181,16 +184,15 @@ def update_repo(gitstring: str, ref: Optional[str], repo_dir: Path) -> Path:
# try pulling
try:
repo = Repo(repo_path)
if repo.active_branch.name != ref:
raise ValueError
repo.remotes.origin.pull()
if repo.active_branch.name == ref:
repo.remotes.origin.pull()
return repo_path
except Exception:
# if it fails, delete and clone again
shutil.rmtree(repo_path)
Repo.clone_from(gitstring, repo_path, branch=ref, depth=1)
else:
Repo.clone_from(gitstring, repo_path, branch=ref, depth=1)
logger.exception("Failed to pull existing repo")
# if it fails, delete and clone again
shutil.rmtree(repo_path)
Repo.clone_from(gitstring, repo_path, branch=ref, depth=1)
return repo_path
@@ -203,7 +205,7 @@ def copy_repo(
Raises FileNotFound error if it can't find source
"""
def ignore_func(_, files):
def ignore_func(_: str, files: list[str]) -> list[str]:
return [f for f in files if f == ".git"]
shutil.copytree(source, destination, ignore=ignore_func)

View File

@@ -39,7 +39,7 @@ class LangServeExport(TypedDict):
def get_langserve_export(filepath: Path) -> LangServeExport:
"""Get LangServe export information from a pyproject.toml file."""
with open(filepath) as f:
with filepath.open() as f:
data: dict[str, Any] = load(f)
try:
module = data["tool"]["langserve"]["export_module"]

View File

@@ -20,7 +20,7 @@ def add_dependencies_to_pyproject_toml(
local_editable_dependencies: Iterable[tuple[str, Path]],
) -> None:
"""Add dependencies to pyproject.toml."""
with open(pyproject_toml, encoding="utf-8") as f:
with pyproject_toml.open(encoding="utf-8") as f:
# tomlkit types aren't amazing - treat as Dict instead
pyproject: dict[str, Any] = load(f)
pyproject["tool"]["poetry"]["dependencies"].update(
@@ -29,7 +29,7 @@ def add_dependencies_to_pyproject_toml(
for name, loc in local_editable_dependencies
},
)
with open(pyproject_toml, "w", encoding="utf-8") as f:
with pyproject_toml.open("w", encoding="utf-8") as f:
dump(pyproject, f)
@@ -38,12 +38,13 @@ def remove_dependencies_from_pyproject_toml(
local_editable_dependencies: Iterable[str],
) -> None:
"""Remove dependencies from pyproject.toml."""
with open(pyproject_toml, encoding="utf-8") as f:
with pyproject_toml.open(encoding="utf-8") as f:
pyproject: dict[str, Any] = load(f)
# tomlkit types aren't amazing - treat as Dict instead
dependencies = pyproject["tool"]["poetry"]["dependencies"]
for name in local_editable_dependencies:
with contextlib.suppress(KeyError):
del dependencies[name]
with open(pyproject_toml, "w", encoding="utf-8") as f:
with pyproject_toml.open("w", encoding="utf-8") as f:
dump(pyproject, f)