ruff: more rules across the board & fixes (#31898)

* standardizes ruff dep version across all `pyproject.toml` files
* cli: ruff rules and corrections
* langchain: rules and corrections
This commit is contained in:
Mason Daugherty
2025-07-07 17:48:01 -04:00
committed by GitHub
parent 706a66eccd
commit e7eac27241
408 changed files with 2783 additions and 1671 deletions

View File

@@ -79,7 +79,9 @@ def new(
package_prompt = "What package would you like to add? (leave blank to skip)"
while True:
package_str = typer.prompt(
package_prompt, default="", show_default=False
package_prompt,
default="",
show_default=False,
)
if not package_str:
break
@@ -121,26 +123,29 @@ def new(
typer.echo("Then add templates with commands like:\n")
typer.echo(" langchain app add extraction-openai-functions")
typer.echo(
" langchain app add git+ssh://git@github.com/efriis/simple-pirate.git\n\n"
" langchain app add git+ssh://git@github.com/efriis/simple-pirate.git\n\n",
)
@app_cli.command()
def add(
dependencies: Annotated[
Optional[list[str]], typer.Argument(help="The dependency to add")
Optional[list[str]],
typer.Argument(help="The dependency to add"),
] = None,
*,
api_path: Annotated[list[str], typer.Option(help="API paths to add")] = [],
project_dir: Annotated[
Optional[Path], typer.Option(help="The project directory")
Optional[Path],
typer.Option(help="The project directory"),
] = None,
repo: Annotated[
list[str],
typer.Option(help="Install templates from a specific github repo instead"),
] = [],
branch: Annotated[
list[str], typer.Option(help="Install templates from a specific branch")
list[str],
typer.Option(help="Install templates from a specific branch"),
] = [],
pip: Annotated[
bool,
@@ -152,13 +157,12 @@ def add(
),
],
) -> None:
"""Adds the specified template to the current LangServe app.
"""Add the specified template to the current LangServe app.
e.g.:
langchain app add extraction-openai-functions
langchain app add git+ssh://git@github.com/efriis/simple-pirate.git
"""
if not branch and not repo:
warnings.warn(
"Adding templates from the default branch and repo is deprecated."
@@ -173,7 +177,7 @@ def add(
package_dir = project_root / "packages"
create_events(
[{"event": "serve add", "properties": {"parsed_dep": d}} for d in parsed_deps]
[{"event": "serve add", "properties": {"parsed_dep": d}} for d in parsed_deps],
)
# group by repo/ref
@@ -248,7 +252,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)
subprocess.run(cmd, cwd=cwd) # noqa: S603
chain_names = []
for e in installed_exports:
@@ -296,10 +300,11 @@ def remove(
api_paths: Annotated[list[str], typer.Argument(help="The API paths to remove")],
*,
project_dir: Annotated[
Optional[Path], typer.Option(help="The project directory")
Optional[Path],
typer.Option(help="The project directory"),
] = None,
) -> None:
"""Removes the specified package from the current LangServe app."""
"""Remove the specified package from the current LangServe app."""
project_root = get_package_root(project_dir)
project_pyproject = project_root / "pyproject.toml"
@@ -320,7 +325,7 @@ def remove(
shutil.rmtree(package_dir)
remove_deps.append(api_path)
except Exception:
except Exception: # noqa: S110
pass
try:
@@ -334,16 +339,19 @@ def remove(
def serve(
*,
port: Annotated[
Optional[int], typer.Option(help="The port to run the server on")
Optional[int],
typer.Option(help="The port to run the server on"),
] = None,
host: Annotated[
Optional[str], typer.Option(help="The host to run the server on")
Optional[str],
typer.Option(help="The host to run the server on"),
] = None,
app: Annotated[
Optional[str], typer.Option(help="The app to run, e.g. `app.server:app`")
Optional[str],
typer.Option(help="The app to run, e.g. `app.server:app`"),
] = None,
) -> None:
"""Starts the LangServe app."""
"""Start the LangServe app."""
# add current dir as first entry of path
sys.path.append(str(Path.cwd()))
@@ -353,5 +361,8 @@ def serve(
import uvicorn
uvicorn.run(
app_str, host=host_str, port=port if port is not None else 8000, reload=True
app_str,
host=host_str,
port=port if port is not None else 8000,
reload=True,
)

View File

@@ -66,7 +66,7 @@ def new(
Optional[str],
typer.Option(
help="The name of the integration in PascalCase. e.g. `MyIntegration`."
" This is used to name classes like `MyIntegrationVectorStore`"
" This is used to name classes like `MyIntegrationVectorStore`",
),
] = None,
src: Annotated[
@@ -85,7 +85,7 @@ def new(
),
] = None,
) -> None:
"""Creates a new integration package."""
"""Create a new integration package."""
try:
replacements = _process_name(name)
except ValueError as e:
@@ -96,13 +96,14 @@ def new(
if not re.match(r"^[A-Z][a-zA-Z0-9]*$", name_class):
typer.echo(
"Name should only contain letters (a-z, A-Z), numbers, and underscores"
", and start with a capital letter."
", and start with a capital letter.",
)
raise typer.Exit(code=1)
replacements["__ModuleName__"] = name_class
else:
replacements["__ModuleName__"] = typer.prompt(
"Name of integration in PascalCase", default=replacements["__ModuleName__"]
"Name of integration in PascalCase",
default=replacements["__ModuleName__"],
)
project_template_dir = Path(__file__).parents[1] / "integration_template"
@@ -124,7 +125,7 @@ def new(
# poetry install
subprocess.run(
["poetry", "install", "--with", "lint,test,typing,test_integration"],
["poetry", "install", "--with", "lint,test,typing,test_integration"], # noqa: S607
cwd=destination_dir,
)
else:
@@ -152,7 +153,7 @@ def new(
if len(dst_paths) != len(set(dst_paths)):
typer.echo(
"Duplicate destination paths provided or computed - please "
"specify them explicitly with --dst."
"specify them explicitly with --dst.",
)
raise typer.Exit(code=1)
@@ -224,10 +225,10 @@ def create_doc(
),
] = "docs/docs/integrations/chat/",
) -> None:
"""Creates a new integration doc."""
"""Create a new integration doc."""
if component_type not in TEMPLATE_MAP:
typer.echo(
f"Unrecognized {component_type=}. Expected one of {_component_types_str}."
f"Unrecognized {component_type=}. Expected one of {_component_types_str}.",
)
raise typer.Exit(code=1)

View File

@@ -6,14 +6,17 @@ import pkgutil
def generate_raw_migrations(
from_package: str, to_package: str, filter_by_all: bool = False
from_package: str,
to_package: str,
filter_by_all: bool = False, # noqa: FBT001, FBT002
) -> list[tuple[str, str]]:
"""Scan the `langchain` package and generate migrations for all modules."""
package = importlib.import_module(from_package)
items = []
for _importer, modname, _ispkg in pkgutil.walk_packages(
package.__path__, package.__name__ + "."
package.__path__,
package.__name__ + ".",
):
try:
module = importlib.import_module(modname)
@@ -34,33 +37,35 @@ def generate_raw_migrations(
obj = getattr(module, name, None)
except ImportError:
continue
if obj and (inspect.isclass(obj) or inspect.isfunction(obj)):
if obj.__module__.startswith(to_package):
items.append(
(f"{modname}.{name}", f"{obj.__module__}.{obj.__name__}")
)
if (
obj
and (inspect.isclass(obj) or inspect.isfunction(obj))
and obj.__module__.startswith(to_package)
):
items.append(
(f"{modname}.{name}", f"{obj.__module__}.{obj.__name__}"),
)
if not filter_by_all:
# Iterate over all members of the module
for name, obj in inspect.getmembers(module):
# Check if it's a class or function
if inspect.isclass(obj) or inspect.isfunction(obj):
# Check if the module name of the obj starts with
# 'langchain_community'
if obj.__module__.startswith(to_package):
items.append(
(f"{modname}.{name}", f"{obj.__module__}.{obj.__name__}")
)
# Check if the module name of the obj starts with
# 'langchain_community'
if inspect.isclass(obj) or (
inspect.isfunction(obj) and obj.__module__.startswith(to_package)
):
items.append(
(f"{modname}.{name}", f"{obj.__module__}.{obj.__name__}"),
)
return items
def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
"""This code will look at all the top level modules in langchain_community.
"""Look at all the top level modules in langchain_community.
It'll attempt to import everything from each __init__ file
for example,
Attempt to import everything from each ``__init__`` file. For example,
langchain_community/
chat_models/
@@ -74,10 +79,10 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
Each tuple will contain the fully qualified path of the class / function to where
its logic is defined
(e.g., langchain_community.chat_models.xyz_implementation.ver2.XYZ)
(e.g., ``langchain_community.chat_models.xyz_implementation.ver2.XYZ``)
and the second tuple will contain the path
to importing it from the top level namespaces
(e.g., langchain_community.chat_models.XYZ)
(e.g., ``langchain_community.chat_models.XYZ``)
"""
package = importlib.import_module(pkg)
@@ -98,7 +103,7 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
top_level_import = f"{module_name}.{name}"
# Append the tuple with original and top-level paths
items.append(
(f"{original_module}.{original_name}", top_level_import)
(f"{original_module}.{original_name}", top_level_import),
)
# Handle the package itself (root level)
@@ -106,7 +111,8 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
# Only iterate through top-level modules/packages
for _finder, modname, ispkg in pkgutil.iter_modules(
package.__path__, package.__name__ + "."
package.__path__,
package.__name__ + ".",
):
if ispkg:
try:
@@ -119,11 +125,15 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
def generate_simplified_migrations(
from_package: str, to_package: str, filter_by_all: bool = True
from_package: str,
to_package: str,
filter_by_all: bool = True, # noqa: FBT001, FBT002
) -> list[tuple[str, str]]:
"""Get all the raw migrations, then simplify them if possible."""
raw_migrations = generate_raw_migrations(
from_package, to_package, filter_by_all=filter_by_all
from_package,
to_package,
filter_by_all=filter_by_all,
)
top_level_simplifications = generate_top_level_imports(to_package)
top_level_dict = dict(top_level_simplifications)

View File

@@ -17,7 +17,7 @@ def dump_migrations_as_grit(name: str, migration_pairs: list[tuple[str, str]]) -
]
"""
for from_module, to_module in migration_pairs
]
],
)
pattern_name = f"langchain_migrate_{name}"
return f"""

View File

@@ -28,6 +28,7 @@ def get_migrations_for_partner_package(pkg_name: str) -> list[tuple[str, str]]:
Returns:
List of 2-tuples containing old and new import paths.
"""
package = importlib.import_module(pkg_name)
classes_ = find_subclasses_in_module(

View File

@@ -20,7 +20,7 @@ class ImportExtractor(ast.NodeVisitor):
self.imports: list = []
self.package = from_package
def visit_ImportFrom(self, node) -> None:
def visit_ImportFrom(self, node) -> None: # noqa: N802
if node.module and (
self.package is None or str(node.module).startswith(self.package)
):
@@ -39,7 +39,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:
def visit_ClassDef(self, node) -> None: # noqa: N802
class_names.append(node.name)
self.generic_visit(node)
@@ -79,7 +79,9 @@ def _get_all_classnames_from_file(file: Path, pkg: str) -> list[tuple[str, str]]
def identify_all_imports_in_file(
file: str, *, from_package: Optional[str] = None
file: str,
*,
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:
@@ -96,10 +98,13 @@ def identify_pkg_source(pkg_root: str) -> pathlib.Path:
Returns:
Returns the path to the source code for the package.
"""
dirs = [d for d in Path(pkg_root).iterdir() if d.is_dir()]
matching_dirs = [d for d in dirs if d.name.startswith("langchain_")]
assert len(matching_dirs) == 1, "There should be only one langchain package."
if len(matching_dirs) != 1:
msg = "There should be only one langchain package."
raise ValueError(msg)
return matching_dirs[0]
@@ -134,7 +139,9 @@ def list_init_imports_by_package(pkg_root: str) -> list[tuple[str, str]]:
def find_imports_from_package(
code: str, *, from_package: Optional[str] = None
code: str,
*,
from_package: Optional[str] = None,
) -> list[tuple[str, str]]:
# Parse the code into an AST
tree = ast.parse(code)

View File

@@ -4,7 +4,7 @@ from pathlib import Path
import rich
import typer
from gritql import run # type: ignore
from gritql import run # type: ignore[import]
from typer import Option
@@ -17,13 +17,13 @@ def get_gritdir_path() -> Path:
def migrate(
ctx: typer.Context,
# Using diff instead of dry-run for backwards compatibility with the old CLI
diff: bool = Option(
False,
diff: bool = Option( # noqa: FBT001
False, # noqa: FBT003
"--diff",
help="Show the changes that would be made without applying them.",
),
interactive: bool = Option(
False,
interactive: bool = Option( # noqa: FBT001
False, # noqa: FBT003
"--interactive",
help="Prompt for confirmation before making each change",
),
@@ -54,7 +54,7 @@ def migrate(
'⚠️ This script is a "best-effort", and is likely to make some '
"mistakes.\n\n"
"🛡️ Backup your code prior to running the migration script -- it will "
"modify your files!\n\n"
"modify your files!\n\n",
)
rich.print("-" * 10)
rich.print()

View File

@@ -16,12 +16,12 @@ package_cli = typer.Typer(no_args_is_help=True, add_completion=False)
@package_cli.command()
def new(
name: Annotated[str, typer.Argument(help="The name of the folder to create")],
with_poetry: Annotated[
with_poetry: Annotated[ # noqa: FBT002
bool,
typer.Option("--with-poetry/--no-poetry", help="Don't run poetry install"),
] = False,
) -> None:
"""Creates a new template package."""
"""Create a new template package."""
computed_name = name if name != "." else Path.cwd().name
destination_dir = Path.cwd() / name if name != "." else Path.cwd()
@@ -53,8 +53,9 @@ def new(
pyproject_contents = pyproject.read_text()
pyproject.write_text(
pyproject_contents.replace("__package_name__", package_name).replace(
"__module_name__", module_name
)
"__module_name__",
module_name,
),
)
# move module folder
@@ -71,23 +72,26 @@ def new(
readme_contents = readme.read_text()
readme.write_text(
readme_contents.replace("__package_name__", package_name).replace(
"__app_route_code__", app_route_code
)
"__app_route_code__",
app_route_code,
),
)
# poetry install
if with_poetry:
subprocess.run(["poetry", "install"], cwd=destination_dir)
subprocess.run(["poetry", "install"], cwd=destination_dir) # noqa: S607
@package_cli.command()
def serve(
*,
port: Annotated[
Optional[int], typer.Option(help="The port to run the server on")
Optional[int],
typer.Option(help="The port to run the server on"),
] = None,
host: Annotated[
Optional[str], typer.Option(help="The host to run the server on")
Optional[str],
typer.Option(help="The host to run the server on"),
] = None,
configurable: Annotated[
Optional[bool],
@@ -104,7 +108,7 @@ def serve(
),
] = False,
) -> None:
"""Starts a demo app for this template."""
"""Start a demo app for this template."""
# load pyproject.toml
project_dir = get_package_root()
pyproject = project_dir / "pyproject.toml"
@@ -136,7 +140,7 @@ def serve(
@package_cli.command()
def list(contains: Annotated[Optional[str], typer.Argument()] = None) -> None:
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