mirror of
https://github.com/hwchase17/langchain.git
synced 2025-09-11 16:01:33 +00:00
committed by
GitHub
parent
451c90fefa
commit
a46a2b8bda
@@ -1,6 +1,4 @@
|
||||
"""
|
||||
Manage LangChain apps
|
||||
"""
|
||||
"""Manage LangChain apps."""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -62,15 +60,14 @@ def new(
|
||||
is_flag=True,
|
||||
),
|
||||
] = False,
|
||||
):
|
||||
"""
|
||||
Create a new LangServe application.
|
||||
"""
|
||||
) -> None:
|
||||
"""Create a new LangServe application."""
|
||||
has_packages = package is not None and len(package) > 0
|
||||
|
||||
if noninteractive:
|
||||
if name is None:
|
||||
raise typer.BadParameter("name is required when --non-interactive is set")
|
||||
msg = "name is required when --non-interactive is set"
|
||||
raise typer.BadParameter(msg)
|
||||
name_str = name
|
||||
pip_bool = bool(pip) # None should be false
|
||||
else:
|
||||
@@ -154,9 +151,8 @@ def add(
|
||||
prompt="Would you like to `pip install -e` the template(s)?",
|
||||
),
|
||||
],
|
||||
):
|
||||
"""
|
||||
Adds the specified template to the current LangServe app.
|
||||
) -> None:
|
||||
"""Adds the specified template to the current LangServe app.
|
||||
|
||||
e.g.:
|
||||
langchain app add extraction-openai-functions
|
||||
@@ -166,7 +162,8 @@ def add(
|
||||
if not branch and not repo:
|
||||
warnings.warn(
|
||||
"Adding templates from the default branch and repo is deprecated."
|
||||
" At a minimum, you will have to add `--branch v0.2` for this to work"
|
||||
" At a minimum, you will have to add `--branch v0.2` for this to work",
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
parsed_deps = parse_dependencies(dependencies, repo, branch, api_path)
|
||||
@@ -176,7 +173,7 @@ def add(
|
||||
package_dir = project_root / "packages"
|
||||
|
||||
create_events(
|
||||
[{"event": "serve add", "properties": dict(parsed_dep=d)} for d in parsed_deps]
|
||||
[{"event": "serve add", "properties": {"parsed_dep": d}} for d in parsed_deps]
|
||||
)
|
||||
|
||||
# group by repo/ref
|
||||
@@ -216,7 +213,7 @@ def add(
|
||||
destination_path = package_dir / inner_api_path
|
||||
if destination_path.exists():
|
||||
typer.echo(
|
||||
f"Folder {str(inner_api_path)} already exists. Skipping...",
|
||||
f"Folder {inner_api_path} already exists. Skipping...",
|
||||
)
|
||||
continue
|
||||
copy_repo(source_path, destination_path)
|
||||
@@ -248,7 +245,7 @@ def add(
|
||||
typer.echo("Failed to print install command, continuing...")
|
||||
else:
|
||||
if pip:
|
||||
cmd = ["pip", "install", "-e"] + installed_destination_strs
|
||||
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)
|
||||
@@ -282,13 +279,15 @@ def add(
|
||||
if len(chain_names) == 1
|
||||
else f"these {len(chain_names)} templates"
|
||||
)
|
||||
lines = (
|
||||
["", f"To use {t}, add the following to your app:\n\n```", ""]
|
||||
+ imports
|
||||
+ [""]
|
||||
+ routes
|
||||
+ ["```"]
|
||||
)
|
||||
lines = [
|
||||
"",
|
||||
f"To use {t}, add the following to your app:\n\n```",
|
||||
"",
|
||||
*imports,
|
||||
"",
|
||||
*routes,
|
||||
"```",
|
||||
]
|
||||
typer.echo("\n".join(lines))
|
||||
|
||||
|
||||
@@ -299,11 +298,8 @@ def remove(
|
||||
project_dir: Annotated[
|
||||
Optional[Path], typer.Option(help="The project directory")
|
||||
] = None,
|
||||
):
|
||||
"""
|
||||
Removes the specified package from the current LangServe app.
|
||||
"""
|
||||
|
||||
) -> None:
|
||||
"""Removes the specified package from the current LangServe app."""
|
||||
project_root = get_package_root(project_dir)
|
||||
|
||||
project_pyproject = project_root / "pyproject.toml"
|
||||
@@ -347,10 +343,7 @@ def serve(
|
||||
Optional[str], typer.Option(help="The app to run, e.g. `app.server:app`")
|
||||
] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Starts the LangServe app.
|
||||
"""
|
||||
|
||||
"""Starts the LangServe app."""
|
||||
# add current dir as first entry of path
|
||||
sys.path.append(str(Path.cwd()))
|
||||
|
||||
|
@@ -1,6 +1,4 @@
|
||||
"""
|
||||
Develop integration packages for LangChain.
|
||||
"""
|
||||
"""Develop integration packages for LangChain."""
|
||||
|
||||
import re
|
||||
import shutil
|
||||
@@ -28,18 +26,20 @@ class Replacements(TypedDict):
|
||||
def _process_name(name: str, *, community: bool = False) -> Replacements:
|
||||
preprocessed = name.replace("_", "-").lower()
|
||||
|
||||
if preprocessed.startswith("langchain-"):
|
||||
preprocessed = preprocessed[len("langchain-") :]
|
||||
preprocessed = preprocessed.removeprefix("langchain-")
|
||||
|
||||
if not re.match(r"^[a-z][a-z0-9-]*$", preprocessed):
|
||||
raise ValueError(
|
||||
msg = (
|
||||
"Name should only contain lowercase letters (a-z), numbers, and hyphens"
|
||||
", and start with a letter."
|
||||
)
|
||||
raise ValueError(msg)
|
||||
if preprocessed.endswith("-"):
|
||||
raise ValueError("Name should not end with `-`.")
|
||||
msg = "Name should not end with `-`."
|
||||
raise ValueError(msg)
|
||||
if preprocessed.find("--") != -1:
|
||||
raise ValueError("Name should not contain consecutive hyphens.")
|
||||
msg = "Name should not contain consecutive hyphens."
|
||||
raise ValueError(msg)
|
||||
replacements: Replacements = {
|
||||
"__package_name__": f"langchain-{preprocessed}",
|
||||
"__module_name__": "langchain_" + preprocessed.replace("-", "_"),
|
||||
@@ -84,11 +84,8 @@ def new(
|
||||
". e.g. `my-integration/my_integration.py`",
|
||||
),
|
||||
] = None,
|
||||
):
|
||||
"""
|
||||
Creates a new integration package.
|
||||
"""
|
||||
|
||||
) -> None:
|
||||
"""Creates a new integration package."""
|
||||
try:
|
||||
replacements = _process_name(name)
|
||||
except ValueError as e:
|
||||
@@ -123,7 +120,7 @@ def new(
|
||||
shutil.move(destination_dir / "integration_template", package_dir)
|
||||
|
||||
# replacements in files
|
||||
replace_glob(destination_dir, "**/*", cast(dict[str, str], replacements))
|
||||
replace_glob(destination_dir, "**/*", cast("dict[str, str]", replacements))
|
||||
|
||||
# poetry install
|
||||
subprocess.run(
|
||||
@@ -167,7 +164,7 @@ def new(
|
||||
|
||||
for src_path, dst_path in zip(src_paths, dst_paths):
|
||||
shutil.copy(src_path, dst_path)
|
||||
replace_file(dst_path, cast(dict[str, str], replacements))
|
||||
replace_file(dst_path, cast("dict[str, str]", replacements))
|
||||
|
||||
|
||||
TEMPLATE_MAP: dict[str, str] = {
|
||||
@@ -183,7 +180,7 @@ TEMPLATE_MAP: dict[str, str] = {
|
||||
"Retriever": "retrievers.ipynb",
|
||||
}
|
||||
|
||||
_component_types_str = ", ".join(f"`{k}`" for k in TEMPLATE_MAP.keys())
|
||||
_component_types_str = ", ".join(f"`{k}`" for k in TEMPLATE_MAP)
|
||||
|
||||
|
||||
@integration_cli.command()
|
||||
@@ -226,10 +223,8 @@ def create_doc(
|
||||
prompt="The relative path to the docs directory to place the new file in.",
|
||||
),
|
||||
] = "docs/docs/integrations/chat/",
|
||||
):
|
||||
"""
|
||||
Creates a new integration doc.
|
||||
"""
|
||||
) -> None:
|
||||
"""Creates a new integration doc."""
|
||||
if component_type not in TEMPLATE_MAP:
|
||||
typer.echo(
|
||||
f"Unrecognized {component_type=}. Expected one of {_component_types_str}."
|
||||
|
@@ -12,7 +12,7 @@ def generate_raw_migrations(
|
||||
package = importlib.import_module(from_package)
|
||||
|
||||
items = []
|
||||
for importer, modname, ispkg in pkgutil.walk_packages(
|
||||
for _importer, modname, _ispkg in pkgutil.walk_packages(
|
||||
package.__path__, package.__name__ + "."
|
||||
):
|
||||
try:
|
||||
@@ -84,9 +84,9 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
|
||||
items = []
|
||||
|
||||
# Function to handle importing from modules
|
||||
def handle_module(module, module_name):
|
||||
def handle_module(module, module_name) -> None:
|
||||
if hasattr(module, "__all__"):
|
||||
all_objects = getattr(module, "__all__")
|
||||
all_objects = module.__all__
|
||||
for name in all_objects:
|
||||
# Attempt to fetch each object declared in __all__
|
||||
obj = getattr(module, name, None)
|
||||
@@ -105,7 +105,7 @@ def generate_top_level_imports(pkg: str) -> list[tuple[str, str]]:
|
||||
handle_module(package, pkg)
|
||||
|
||||
# Only iterate through top-level modules/packages
|
||||
for finder, modname, ispkg in pkgutil.iter_modules(
|
||||
for _finder, modname, ispkg in pkgutil.iter_modules(
|
||||
package.__path__, package.__name__ + "."
|
||||
):
|
||||
if ispkg:
|
||||
@@ -126,7 +126,7 @@ def generate_simplified_migrations(
|
||||
from_package, to_package, filter_by_all=filter_by_all
|
||||
)
|
||||
top_level_simplifications = generate_top_level_imports(to_package)
|
||||
top_level_dict = {full: top_level for full, top_level in top_level_simplifications}
|
||||
top_level_dict = dict(top_level_simplifications)
|
||||
simple_migrations = []
|
||||
for migration in raw_migrations:
|
||||
original, new = migration
|
||||
|
@@ -1,12 +1,11 @@
|
||||
def split_package(package: str) -> tuple[str, str]:
|
||||
"""Split a package name into the containing package and the final name"""
|
||||
"""Split a package name into the containing package and the final name."""
|
||||
parts = package.split(".")
|
||||
return ".".join(parts[:-1]), parts[-1]
|
||||
|
||||
|
||||
def dump_migrations_as_grit(name: str, migration_pairs: list[tuple[str, str]]):
|
||||
def dump_migrations_as_grit(name: str, migration_pairs: list[tuple[str, str]]) -> str:
|
||||
"""Dump the migration pairs as a Grit file."""
|
||||
output = "language python"
|
||||
remapped = ",\n".join(
|
||||
[
|
||||
f"""
|
||||
@@ -21,7 +20,7 @@ def dump_migrations_as_grit(name: str, migration_pairs: list[tuple[str, str]]):
|
||||
]
|
||||
)
|
||||
pattern_name = f"langchain_migrate_{name}"
|
||||
output = f"""
|
||||
return f"""
|
||||
language python
|
||||
|
||||
// This migration is generated automatically - do not manually edit this file
|
||||
@@ -34,4 +33,3 @@ pattern {pattern_name}() {{
|
||||
// Add this for invoking directly
|
||||
{pattern_name}()
|
||||
"""
|
||||
return output
|
||||
|
@@ -46,9 +46,8 @@ def get_migrations_for_partner_package(pkg_name: str) -> list[tuple[str, str]]:
|
||||
|
||||
old_paths = community_classes + imports_for_pkg
|
||||
|
||||
migrations = [
|
||||
return [
|
||||
(f"{module}.{item}", f"{pkg_name}.{item}")
|
||||
for module, item in old_paths
|
||||
if item in classes_
|
||||
]
|
||||
return migrations
|
||||
|
@@ -20,7 +20,7 @@ class ImportExtractor(ast.NodeVisitor):
|
||||
self.imports: list = []
|
||||
self.package = from_package
|
||||
|
||||
def visit_ImportFrom(self, node):
|
||||
def visit_ImportFrom(self, node) -> None:
|
||||
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):
|
||||
def visit_ClassDef(self, node) -> None:
|
||||
class_names.append(node.name)
|
||||
self.generic_visit(node)
|
||||
|
||||
@@ -62,7 +62,7 @@ def find_subclasses_in_module(module, 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
|
||||
for name, obj in inspect.getmembers(module, inspect.isclass):
|
||||
for _name, obj in inspect.getmembers(module, inspect.isclass):
|
||||
if is_subclass(obj, classes_):
|
||||
subclasses.append(obj.__name__)
|
||||
return subclasses
|
||||
@@ -125,7 +125,7 @@ def list_init_imports_by_package(pkg_root: str) -> list[tuple[str, str]]:
|
||||
files = list(Path(pkg_source).rglob("*.py"))
|
||||
|
||||
for file in files:
|
||||
if not file.name == "__init__.py":
|
||||
if file.name != "__init__.py":
|
||||
continue
|
||||
import_in_file = identify_all_imports_in_file(str(file))
|
||||
module_name = _get_current_module(file, pkg_root)
|
||||
|
@@ -1,6 +1,4 @@
|
||||
"""
|
||||
Develop installable templates.
|
||||
"""
|
||||
"""Develop installable templates."""
|
||||
|
||||
import re
|
||||
import shutil
|
||||
@@ -22,10 +20,8 @@ def new(
|
||||
bool,
|
||||
typer.Option("--with-poetry/--no-poetry", help="Don't run poetry install"),
|
||||
] = False,
|
||||
):
|
||||
"""
|
||||
Creates a new template package.
|
||||
"""
|
||||
) -> None:
|
||||
"""Creates a new template package."""
|
||||
computed_name = name if name != "." else Path.cwd().name
|
||||
destination_dir = Path.cwd() / name if name != "." else Path.cwd()
|
||||
|
||||
@@ -108,9 +104,7 @@ def serve(
|
||||
),
|
||||
] = False,
|
||||
) -> None:
|
||||
"""
|
||||
Starts a demo app for this template.
|
||||
"""
|
||||
"""Starts a demo app for this template."""
|
||||
# load pyproject.toml
|
||||
project_dir = get_package_root()
|
||||
pyproject = project_dir / "pyproject.toml"
|
||||
@@ -143,9 +137,7 @@ def serve(
|
||||
|
||||
@package_cli.command()
|
||||
def list(contains: Annotated[Optional[str], typer.Argument()] = None) -> None:
|
||||
"""
|
||||
List all or search for available templates.
|
||||
"""
|
||||
"""List all or search for available templates."""
|
||||
from langchain_cli.utils.github import list_packages
|
||||
|
||||
packages = list_packages(contains=contains)
|
||||
|
Reference in New Issue
Block a user