diff --git a/libs/langchain/langchain/cli/cli.py b/libs/langchain/langchain/cli/cli.py index 8f5cfeef02..8a89ace5db 100644 --- a/libs/langchain/langchain/cli/cli.py +++ b/libs/langchain/langchain/cli/cli.py @@ -1,5 +1,12 @@ """A CLI for creating a new project with LangChain.""" from pathlib import Path +from typing import Optional + +from typing_extensions import Annotated + +from langchain.cli.create_repo.base import create, is_poetry_installed +from langchain.cli.create_repo.pypi_name import is_name_taken, lint_name +from langchain.cli.create_repo.user_info import get_git_user_email, get_git_user_name try: import typer @@ -9,45 +16,94 @@ except ImportError: "You can install it with `pip install typer`." ) -from typing_extensions import Annotated - -from langchain.cli.create_repo.base import create, is_poetry_installed -from langchain.cli.create_repo.user_info import get_git_user_email, get_git_user_name app = typer.Typer(no_args_is_help=False, add_completion=False) -AUTHOR_NAME_OPTION = typer.Option( - default_factory=get_git_user_name, - prompt=True, - help="If not specified, will be inferred from git config if possible. ", -) -AUTHOR_EMAIL_OPTION = typer.Option( - default_factory=get_git_user_email, - prompt=True, - help="If not specified, will be inferred from git config if possible. ", -) -USE_POETRY_OPTION = typer.Option( - default_factory=is_poetry_installed, - prompt=True, - help=( - "Whether to use Poetry to manage the project. " - "If not specified, Poetry will be used if poetry is installed." - ), -) +def _select_project_name(suggested_project_name: str) -> str: + """Help the user select a valid project name.""" + while True: + project_name = typer.prompt("Project Name", default=suggested_project_name) + + project_name_diagnostics = lint_name(project_name) + if project_name_diagnostics: + typer.echo( + f"{typer.style('Warning:', fg=typer.colors.MAGENTA)}" + f" The project name" + f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}" + f" is not valid.", + err=True, + ) + + for diagnostic in project_name_diagnostics: + typer.echo(f" - {diagnostic}") + if typer.confirm( + "Select another name?", + default=True, + ): + continue + if is_name_taken(project_name): + typer.echo( + f"{typer.style('Error:', fg=typer.colors.RED)}" + f" The project name" + f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}" + f" is already taken on pypi", + err=True, + ) + + if typer.confirm( + "Select another name?", + default=True, + ): + continue + + # If we got here then the project name is valid and not taken + return project_name + + +# +# @app.command() def new( project_directory: Annotated[ Path, typer.Argument(help="The directory to create the project in.") ], - author_name: Annotated[str, AUTHOR_NAME_OPTION], - author_email: Annotated[str, AUTHOR_EMAIL_OPTION], - use_poetry: Annotated[bool, USE_POETRY_OPTION], + author_name: Optional[str] = None, + author_email: Optional[str] = None, + use_poetry: Annotated[ + Optional[bool], typer.Option(help="Specify whether to use Poetry or not.") + ] = None, ) -> None: """Create a new project with LangChain.""" - create(project_directory, author_name, author_email, use_poetry) + + project_directory_path = Path(project_directory) + project_name_suggestion = project_directory_path.name.replace("-", "_") + project_name = _select_project_name(project_name_suggestion) + + if not author_name: + author_name = typer.prompt("Author Name", default=get_git_user_name()) + + if not author_email: + author_email = typer.prompt("Author Email", default=get_git_user_email()) + + if use_poetry is None: + if is_poetry_installed(): + typer.echo("🎉 Found Poetry installed. Project can be set up using poetry.") + use_poetry = typer.confirm("Use Poetry? (no to use pip)", default=True) + else: + typer.echo("ℹī¸ Could not find Poetry installed.") + use_pip = typer.confirm("Use Pip? (no to use poetry)", default=True) + use_poetry = not use_pip + + if author_name is None: + raise typer.BadParameter("Author name is required") + + if author_email is None: + raise typer.BadParameter("Author email is required") + + create(project_directory, project_name, author_name, author_email, use_poetry) if __name__ == "__main__": diff --git a/libs/langchain/langchain/cli/create_repo/base.py b/libs/langchain/langchain/cli/create_repo/base.py index 2581fb65dd..4cfa902eef 100644 --- a/libs/langchain/langchain/cli/create_repo/base.py +++ b/libs/langchain/langchain/cli/create_repo/base.py @@ -9,7 +9,6 @@ from typing import List, Sequence import typer import langchain -from langchain.cli.create_repo.pypi_name import is_name_taken, lint_name class UnderscoreTemplate(string.Template): @@ -145,7 +144,7 @@ def _pip_install(project_directory_path: Path) -> None: def _init_git(project_directory_path: Path) -> None: """Initialize git repository.""" typer.echo( - f"\n{typer.style('3.', bold=True, fg=typer.colors.GREEN)} Initializing git..." + f"\n{typer.style('Initializing git...', bold=True, fg=typer.colors.GREEN)}" ) subprocess.run(["git", "init"], cwd=project_directory_path) @@ -157,58 +156,12 @@ def _init_git(project_directory_path: Path) -> None: ) -def _select_project_name(suggested_project_name: str) -> str: - """Help the user select a valid project name.""" - while True: - project_name = typer.prompt( - "Please choose a project name: ", default=suggested_project_name - ) - - project_name_diagnostics = lint_name(project_name) - if project_name_diagnostics: - typer.echo( - f"{typer.style('Error:', fg=typer.colors.RED)}" - f" The project name" - f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}" - f" is not valid:", - err=True, - ) - - for diagnostic in project_name_diagnostics: - typer.echo(f" - {diagnostic}") - - if typer.confirm( - "Would you like to choose another name? " - "Choose NO to proceed with existing name.", - default=True, - ): - continue - - if is_name_taken(project_name): - typer.echo( - f"{typer.style('Error:', fg=typer.colors.RED)}" - f" The project name" - f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}" - f" is already taken on pypi", - err=True, - ) - - if typer.confirm( - "Would you like to choose another name? " - "Choose NO to proceed with existing name.", - default=True, - ): - continue - - # If we got here then the project name is valid and not taken - return project_name - - # PUBLIC API def create( project_directory: pathlib.Path, + project_name: str, author_name: str, author_email: str, use_poetry: bool, @@ -217,27 +170,29 @@ def create( Args: project_directory (str): The directory to create the project in. + project_name: The name of the project. author_name (str): The name of the author. author_email (str): The email of the author. use_poetry (bool): Whether to use Poetry to manage the project. """ project_directory_path = Path(project_directory) - project_name_suggestion = project_directory_path.name.replace("-", "_") - project_name = _select_project_name(project_name_suggestion) project_name_identifier = project_name - resolved_path = project_directory_path.resolve() if not typer.confirm( - f"\n{typer.style('>', bold=True, fg=typer.colors.GREEN)} " - f"Creating new LangChain project " - f"{typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}" - f" in" - f" {typer.style(resolved_path, fg=typer.colors.BRIGHT_CYAN)}", + f"\n" + f"Creating a new LangChain project đŸĻœī¸đŸ”—\n" + f"Name: {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}\n" + f"Path: {typer.style(resolved_path, fg=typer.colors.BRIGHT_CYAN)}\n" + f"Project name: {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}\n" + f"Author name: {typer.style(author_name, fg=typer.colors.BRIGHT_CYAN)}\n" + f"Author email: {typer.style(author_email, fg=typer.colors.BRIGHT_CYAN)}\n" + f"Use Poetry: {typer.style(str(use_poetry), fg=typer.colors.BRIGHT_CYAN)}\n" + "Continue?", default=True, ): - typer.echo("OK! Canceling project creation.") + typer.echo("Cancelled project creation. See you later! 👋") raise typer.Exit(code=0) _create_project_dir( @@ -258,7 +213,7 @@ def create( _init_git(project_directory_path) typer.echo( - f"\n{typer.style('Done!', bold=True, fg=typer.colors.GREEN)}" + f"\n{typer.style('Done!🙌', bold=True, fg=typer.colors.GREEN)}" f" Your new LangChain project" f" {typer.style(project_name, fg=typer.colors.BRIGHT_CYAN)}" f" has been created in"