mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-28 17:38:36 +00:00
cli: create specific files from template (#28556)
This commit is contained in:
parent
a197e0ba3d
commit
7ecf38f4fa
@ -38,6 +38,8 @@ _e2e_test:
|
|||||||
$(PYTHON) -m pip install --upgrade poetry && \
|
$(PYTHON) -m pip install --upgrade poetry && \
|
||||||
$(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 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 && \
|
poetry install --with lint,typing,test && \
|
||||||
poetry run pip install -e ../../../standard-tests && \
|
poetry run pip install -e ../../../standard-tests && \
|
||||||
|
@ -69,6 +69,21 @@ def new(
|
|||||||
" This is used to name classes like `MyIntegrationVectorStore`"
|
" This is used to name classes like `MyIntegrationVectorStore`"
|
||||||
),
|
),
|
||||||
] = None,
|
] = None,
|
||||||
|
src: Annotated[
|
||||||
|
Optional[list[str]],
|
||||||
|
typer.Option(
|
||||||
|
help="The name of the single template file to copy."
|
||||||
|
" e.g. `--src integration_template/chat_models.py "
|
||||||
|
"--dst my_integration/chat_models.py`. Can be used multiple times.",
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
dst: Annotated[
|
||||||
|
Optional[list[str]],
|
||||||
|
typer.Option(
|
||||||
|
help="The relative path to the integration package to place the new file in"
|
||||||
|
". e.g. `my-integration/my_integration.py`",
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Creates a new integration package.
|
Creates a new integration package.
|
||||||
@ -93,13 +108,14 @@ def new(
|
|||||||
"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"
|
||||||
destination_dir = Path.cwd() / replacements["__package_name__"]
|
destination_dir = Path.cwd() / replacements["__package_name__"]
|
||||||
|
if not src and not dst:
|
||||||
if destination_dir.exists():
|
if destination_dir.exists():
|
||||||
typer.echo(f"Folder {destination_dir} exists.")
|
typer.echo(f"Folder {destination_dir} exists.")
|
||||||
raise typer.Exit(code=1)
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
# copy over template from ../integration_template
|
# copy over template from ../integration_template
|
||||||
project_template_dir = Path(__file__).parents[1] / "integration_template"
|
|
||||||
shutil.copytree(project_template_dir, destination_dir, dirs_exist_ok=False)
|
shutil.copytree(project_template_dir, destination_dir, dirs_exist_ok=False)
|
||||||
|
|
||||||
# folder movement
|
# folder movement
|
||||||
@ -114,6 +130,44 @@ def new(
|
|||||||
["poetry", "install", "--with", "lint,test,typing,test_integration"],
|
["poetry", "install", "--with", "lint,test,typing,test_integration"],
|
||||||
cwd=destination_dir,
|
cwd=destination_dir,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
# confirm src and dst are the same length
|
||||||
|
if not src:
|
||||||
|
typer.echo("Cannot provide --dst without --src.")
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
src_paths = [project_template_dir / p for p in src]
|
||||||
|
if dst and len(src) != len(dst):
|
||||||
|
typer.echo("Number of --src and --dst arguments must match.")
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
if not dst:
|
||||||
|
# assume we're in a package dir, copy to equivalent path
|
||||||
|
dst_paths = [destination_dir / p for p in src]
|
||||||
|
else:
|
||||||
|
dst_paths = [Path.cwd() / p for p in dst]
|
||||||
|
dst_paths = [
|
||||||
|
p / f"{replacements['__package_name_short_snake__']}.ipynb"
|
||||||
|
if not p.suffix
|
||||||
|
else p
|
||||||
|
for p in dst_paths
|
||||||
|
]
|
||||||
|
|
||||||
|
# confirm no duplicate dst_paths
|
||||||
|
if len(dst_paths) != len(set(dst_paths)):
|
||||||
|
typer.echo(
|
||||||
|
"Duplicate destination paths provided or computed - please "
|
||||||
|
"specify them explicitly with --dst."
|
||||||
|
)
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
|
# confirm no files exist at dst_paths
|
||||||
|
for dst_path in dst_paths:
|
||||||
|
if dst_path.exists():
|
||||||
|
typer.echo(f"File {dst_path} exists.")
|
||||||
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
TEMPLATE_MAP: dict[str, str] = {
|
TEMPLATE_MAP: dict[str, str] = {
|
||||||
@ -176,43 +230,15 @@ def create_doc(
|
|||||||
"""
|
"""
|
||||||
Creates a new integration doc.
|
Creates a new integration doc.
|
||||||
"""
|
"""
|
||||||
try:
|
if component_type not in TEMPLATE_MAP:
|
||||||
replacements = _process_name(name, community=component_type == "Tool")
|
|
||||||
except ValueError as e:
|
|
||||||
typer.echo(e)
|
|
||||||
raise typer.Exit(code=1)
|
|
||||||
|
|
||||||
if name_class:
|
|
||||||
if not re.match(r"^[A-Z][a-zA-Z0-9]*$", name_class):
|
|
||||||
typer.echo(
|
typer.echo(
|
||||||
"Name should only contain letters (a-z, A-Z), numbers, and underscores"
|
|
||||||
", and start with a capital letter."
|
|
||||||
)
|
|
||||||
raise typer.Exit(code=1)
|
|
||||||
replacements["__ModuleName__"] = name_class
|
|
||||||
else:
|
|
||||||
replacements["__ModuleName__"] = typer.prompt(
|
|
||||||
(
|
|
||||||
"The PascalCase name of the integration (e.g. `OpenAI`, `VertexAI`). "
|
|
||||||
"Do not include a 'Chat', 'VectorStore', etc. prefix/suffix."
|
|
||||||
),
|
|
||||||
default=replacements["__ModuleName__"],
|
|
||||||
)
|
|
||||||
destination_path = (
|
|
||||||
Path.cwd()
|
|
||||||
/ destination_dir
|
|
||||||
/ (replacements["__package_name_short_snake__"] + ".ipynb")
|
|
||||||
)
|
|
||||||
|
|
||||||
# copy over template from ../integration_template
|
|
||||||
template_dir = Path(__file__).parents[1] / "integration_template" / "docs"
|
|
||||||
if component_type in TEMPLATE_MAP:
|
|
||||||
docs_template = template_dir / TEMPLATE_MAP[component_type]
|
|
||||||
else:
|
|
||||||
raise ValueError(
|
|
||||||
f"Unrecognized {component_type=}. Expected one of {_component_types_str}."
|
f"Unrecognized {component_type=}. Expected one of {_component_types_str}."
|
||||||
)
|
)
|
||||||
shutil.copy(docs_template, destination_path)
|
raise typer.Exit(code=1)
|
||||||
|
|
||||||
# replacements in file
|
new(
|
||||||
replace_file(destination_path, cast(Dict[str, str], replacements))
|
name=name,
|
||||||
|
name_class=name_class,
|
||||||
|
src=[f"docs/{TEMPLATE_MAP[component_type]}"],
|
||||||
|
dst=[destination_dir],
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user