From 43257a295c36aae8dd5d4afb1d5c8d03779b7a50 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 25 Oct 2023 18:30:02 -0700 Subject: [PATCH] CLI Git Improvements (#12311) - delete repo sources like pip - git dep fixes - error messaging --- libs/cli/langchain_cli/constants.py | 1 + libs/cli/langchain_cli/namespaces/serve.py | 34 +++-- libs/cli/langchain_cli/utils/git.py | 136 ++++++++---------- libs/cli/poetry.lock | 154 ++++++++++----------- libs/cli/tests/test_utils.py | 72 +++++++++- 5 files changed, 221 insertions(+), 176 deletions(-) diff --git a/libs/cli/langchain_cli/constants.py b/libs/cli/langchain_cli/constants.py index 58513d5aff..92d4c3ece5 100644 --- a/libs/cli/langchain_cli/constants.py +++ b/libs/cli/langchain_cli/constants.py @@ -1,2 +1,3 @@ DEFAULT_GIT_REPO = "https://github.com/langchain-ai/langchain.git" DEFAULT_GIT_SUBDIRECTORY = "templates" +DEFAULT_GIT_REF = "langserve-templates" diff --git a/libs/cli/langchain_cli/namespaces/serve.py b/libs/cli/langchain_cli/namespaces/serve.py index c341a21a38..63d4a004f3 100644 --- a/libs/cli/langchain_cli/namespaces/serve.py +++ b/libs/cli/langchain_cli/namespaces/serve.py @@ -3,16 +3,22 @@ Manage LangServe application projects. """ import typer -from typing import Optional, List +from typing import Optional, List, Tuple, Dict from typing_extensions import Annotated from pathlib import Path import shutil import subprocess -from langchain_cli.utils.git import copy_repo, update_repo +from langchain_cli.utils.git import ( + copy_repo, + update_repo, + parse_dependency_string, + DependencySource, +) from langchain_cli.utils.packages import get_package_root from langchain_cli.utils.events import create_events from langserve.packages import list_packages, get_langserve_export import tomli +from collections import defaultdict REPO_DIR = Path(typer.get_app_dir("langchain")) / "git_repos" @@ -29,9 +35,7 @@ def new( ] = None, with_poetry: Annotated[ bool, - typer.Option( - "--with-poetry/--no-poetry", help="Run poetry install" - ), + typer.Option("--with-poetry/--no-poetry", help="Run poetry install"), ] = False, ): """ @@ -79,9 +83,7 @@ def add( ] = [], with_poetry: Annotated[ bool, - typer.Option( - "--with-poetry/--no-poetry", help="Run poetry install" - ), + typer.Option("--with-poetry/--no-poetry", help="Run poetry install"), ] = False, ): """ @@ -97,6 +99,7 @@ def add( if dependencies is None: dependencies = [] + method = "" # cannot have both repo and dependencies if len(repo) != 0: if len(dependencies) != 0: @@ -128,8 +131,17 @@ def add( for i, dependency in enumerate(dependencies): # update repo typer.echo(f"Adding {dependency}...") - source_path = update_repo(dependency, REPO_DIR) + dep = parse_dependency_string(dependency) + source_repo_path = update_repo(dep["git"], dep["ref"], REPO_DIR) + source_path = ( + source_repo_path / dep["subdirectory"] + if dep["subdirectory"] + else source_repo_path + ) pyproject_path = source_path / "pyproject.toml" + if not pyproject_path.exists(): + typer.echo(f"Could not find {pyproject_path}") + continue langserve_export = get_langserve_export(pyproject_path) # detect name conflict @@ -161,9 +173,7 @@ def remove( api_paths: Annotated[List[str], typer.Argument(help="The API paths to remove")], with_poetry: Annotated[ bool, - typer.Option( - "--with_poetry/--no-poetry", help="Don't run poetry remove" - ), + typer.Option("--with_poetry/--no-poetry", help="Don't run poetry remove"), ] = False, ): """ diff --git a/libs/cli/langchain_cli/utils/git.py b/libs/cli/langchain_cli/utils/git.py index 5733eef359..4a9809e7a7 100644 --- a/libs/cli/langchain_cli/utils/git.py +++ b/libs/cli/langchain_cli/utils/git.py @@ -3,7 +3,11 @@ from pathlib import Path import shutil import re -from langchain_cli.constants import DEFAULT_GIT_REPO, DEFAULT_GIT_SUBDIRECTORY +from langchain_cli.constants import ( + DEFAULT_GIT_REPO, + DEFAULT_GIT_SUBDIRECTORY, + DEFAULT_GIT_REF, +) import hashlib from git import Repo @@ -14,65 +18,49 @@ class DependencySource(TypedDict): subdirectory: Optional[str] -def _get_main_branch(repo: Repo) -> Optional[str]: - """ - Get the name of the main branch of a git repo. - From https://stackoverflow.com/questions/69651536/how-to-get-master-main-branch-from-gitpython - """ - try: - # replace "origin" with your remote name if differs - show_result = repo.git.remote("show", "origin") - - # The show_result contains a wall of text in the language that - # is set by your locales. Now you can use regex to extract the - # default branch name, but if your language is different - # from english, you need to adjust this regex pattern. - - matches = re.search(r"\s*HEAD branch:\s*(.*)", show_result) - if matches: - default_branch = matches.group(1) - return default_branch - except Exception: - pass - # fallback to main/master - if "main" in repo.heads: - return "main" - if "master" in repo.heads: - return "master" - - raise ValueError("Could not find main branch") - - # use poetry dependency string format -def _parse_dependency_string(package_string: str) -> DependencySource: +def parse_dependency_string(package_string: str) -> DependencySource: if package_string.startswith("git+"): # remove git+ - remaining = package_string[4:] - # split main string from params - gitstring, *params = remaining.split("#") - # parse params - params_dict = {} - for param in params: - if not param: - # ignore empty entries - continue - if "=" in param: - key, value = param.split("=") - if key in params_dict: - raise ValueError( - f"Duplicate parameter {key} in dependency string {package_string}" - ) - params_dict[key] = value - else: - if "ref" in params_dict: - raise ValueError( - f"Duplicate parameter ref in dependency string {package_string}" - ) - params_dict["ref"] = param + gitstring = package_string[4:] + subdirectory = None + ref = None + # first check for #subdirectory= on the end + if "#subdirectory=" in gitstring: + gitstring, subdirectory = gitstring.split("#subdirectory=") + if "#" in subdirectory or "@" in subdirectory: + raise ValueError( + "#subdirectory must be the last part of the dependency string" + ) + + # find first slash after :// + # find @ or # after that slash + # remainder is ref + # if no @ or #, then ref is None + + # find first slash after :// + if "://" not in gitstring: + raise ValueError( + "git+ dependencies must start with git+https:// or git+ssh://" + ) + + _, find_slash = gitstring.split("://", 1) + + if "/" not in find_slash: + post_slash = find_slash + ref = None + else: + _, post_slash = find_slash.split("/", 1) + if "@" in post_slash or "#" in post_slash: + _, ref = re.split(r"[@#]", post_slash, 1) + + # gitstring is everything before that + gitstring = gitstring[: -len(ref) - 1] if ref is not None else gitstring + return DependencySource( git=gitstring, - ref=params_dict.get("ref"), - subdirectory=params_dict.get("subdirectory"), + ref=ref, + subdirectory=subdirectory, ) elif package_string.startswith("https://"): @@ -81,12 +69,13 @@ def _parse_dependency_string(package_string: str) -> DependencySource: # it's a default git repo dependency gitstring = DEFAULT_GIT_REPO subdirectory = str(Path(DEFAULT_GIT_SUBDIRECTORY) / package_string) - return DependencySource(git=gitstring, ref=None, subdirectory=subdirectory) + return DependencySource( + git=gitstring, ref=DEFAULT_GIT_REF, subdirectory=subdirectory + ) -def _get_repo_path(dependency: DependencySource, repo_dir: Path) -> Path: +def _get_repo_path(gitstring: str, repo_dir: Path) -> Path: # only based on git for now - gitstring = dependency["git"] hashed = hashlib.sha256(gitstring.encode("utf-8")).hexdigest()[:8] removed_protocol = gitstring.split("://")[-1] @@ -98,32 +87,27 @@ def _get_repo_path(dependency: DependencySource, repo_dir: Path) -> Path: return repo_dir / directory_name -def update_repo(gitpath: str, repo_dir: Path) -> Path: +def update_repo(gitstring: str, ref: Optional[str], repo_dir: Path) -> Path: # see if path already saved - dependency = _parse_dependency_string(gitpath) - repo_path = _get_repo_path(dependency, repo_dir) - if not repo_path.exists(): - repo = Repo.clone_from(dependency["git"], repo_path) - else: - repo = Repo(repo_path) - - # pull it - ref = dependency.get("ref") if dependency.get("ref") else _get_main_branch(repo) - repo.git.checkout(ref) + repo_path = _get_repo_path(gitstring, repo_dir) + if repo_path.exists(): + shutil.rmtree(repo_path) - repo.git.pull() - - return ( - repo_path - if dependency["subdirectory"] is None - else repo_path / dependency["subdirectory"] - ) + # now we have fresh dir + Repo.clone_from(gitstring, repo_path, branch=ref, depth=1) + return repo_path def copy_repo( source: Path, destination: Path, ) -> None: + """ + Copies a repo, ignoring git folders. + + Raises FileNotFound error if it can't find source + """ + def ignore_func(_, files): return [f for f in files if f == ".git"] diff --git a/libs/cli/poetry.lock b/libs/cli/poetry.lock index 3411cd597d..dded71fa81 100644 --- a/libs/cli/poetry.lock +++ b/libs/cli/poetry.lock @@ -469,74 +469,68 @@ test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre [[package]] name = "greenlet" -version = "3.0.0" +version = "3.0.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" files = [ - {file = "greenlet-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e09dea87cc91aea5500262993cbd484b41edf8af74f976719dd83fe724644cd6"}, - {file = "greenlet-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47932c434a3c8d3c86d865443fadc1fbf574e9b11d6650b656e602b1797908a"}, - {file = "greenlet-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdfaeecf8cc705d35d8e6de324bf58427d7eafb55f67050d8f28053a3d57118c"}, - {file = "greenlet-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a68d670c8f89ff65c82b936275369e532772eebc027c3be68c6b87ad05ca695"}, - {file = "greenlet-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ad562a104cd41e9d4644f46ea37167b93190c6d5e4048fcc4b80d34ecb278f"}, - {file = "greenlet-3.0.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02a807b2a58d5cdebb07050efe3d7deaf915468d112dfcf5e426d0564aa3aa4a"}, - {file = "greenlet-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b1660a15a446206c8545edc292ab5c48b91ff732f91b3d3b30d9a915d5ec4779"}, - {file = "greenlet-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:813720bd57e193391dfe26f4871186cf460848b83df7e23e6bef698a7624b4c9"}, - {file = "greenlet-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:aa15a2ec737cb609ed48902b45c5e4ff6044feb5dcdfcf6fa8482379190330d7"}, - {file = "greenlet-3.0.0-cp310-universal2-macosx_11_0_x86_64.whl", hash = "sha256:7709fd7bb02b31908dc8fd35bfd0a29fc24681d5cc9ac1d64ad07f8d2b7db62f"}, - {file = "greenlet-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:211ef8d174601b80e01436f4e6905aca341b15a566f35a10dd8d1e93f5dbb3b7"}, - {file = "greenlet-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6512592cc49b2c6d9b19fbaa0312124cd4c4c8a90d28473f86f92685cc5fef8e"}, - {file = "greenlet-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:871b0a8835f9e9d461b7fdaa1b57e3492dd45398e87324c047469ce2fc9f516c"}, - {file = "greenlet-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b505fcfc26f4148551826a96f7317e02c400665fa0883fe505d4fcaab1dabfdd"}, - {file = "greenlet-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123910c58234a8d40eaab595bc56a5ae49bdd90122dde5bdc012c20595a94c14"}, - {file = "greenlet-3.0.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96d9ea57292f636ec851a9bb961a5cc0f9976900e16e5d5647f19aa36ba6366b"}, - {file = "greenlet-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b72b802496cccbd9b31acea72b6f87e7771ccfd7f7927437d592e5c92ed703c"}, - {file = "greenlet-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:527cd90ba3d8d7ae7dceb06fda619895768a46a1b4e423bdb24c1969823b8362"}, - {file = "greenlet-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:37f60b3a42d8b5499be910d1267b24355c495064f271cfe74bf28b17b099133c"}, - {file = "greenlet-3.0.0-cp311-universal2-macosx_10_9_universal2.whl", hash = "sha256:c3692ecf3fe754c8c0f2c95ff19626584459eab110eaab66413b1e7425cd84e9"}, - {file = "greenlet-3.0.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:be557119bf467d37a8099d91fbf11b2de5eb1fd5fc5b91598407574848dc910f"}, - {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73b2f1922a39d5d59cc0e597987300df3396b148a9bd10b76a058a2f2772fc04"}, - {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1e22c22f7826096ad503e9bb681b05b8c1f5a8138469b255eb91f26a76634f2"}, - {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d363666acc21d2c204dd8705c0e0457d7b2ee7a76cb16ffc099d6799744ac99"}, - {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:334ef6ed8337bd0b58bb0ae4f7f2dcc84c9f116e474bb4ec250a8bb9bd797a66"}, - {file = "greenlet-3.0.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6672fdde0fd1a60b44fb1751a7779c6db487e42b0cc65e7caa6aa686874e79fb"}, - {file = "greenlet-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:952256c2bc5b4ee8df8dfc54fc4de330970bf5d79253c863fb5e6761f00dda35"}, - {file = "greenlet-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:269d06fa0f9624455ce08ae0179430eea61085e3cf6457f05982b37fd2cefe17"}, - {file = "greenlet-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9adbd8ecf097e34ada8efde9b6fec4dd2a903b1e98037adf72d12993a1c80b51"}, - {file = "greenlet-3.0.0-cp312-universal2-macosx_10_9_universal2.whl", hash = "sha256:553d6fb2324e7f4f0899e5ad2c427a4579ed4873f42124beba763f16032959af"}, - {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b5ce7f40f0e2f8b88c28e6691ca6806814157ff05e794cdd161be928550f4c"}, - {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf94aa539e97a8411b5ea52fc6ccd8371be9550c4041011a091eb8b3ca1d810"}, - {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80dcd3c938cbcac986c5c92779db8e8ce51a89a849c135172c88ecbdc8c056b7"}, - {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e52a712c38e5fb4fd68e00dc3caf00b60cb65634d50e32281a9d6431b33b4af1"}, - {file = "greenlet-3.0.0-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5539f6da3418c3dc002739cb2bb8d169056aa66e0c83f6bacae0cd3ac26b423"}, - {file = "greenlet-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:343675e0da2f3c69d3fb1e894ba0a1acf58f481f3b9372ce1eb465ef93cf6fed"}, - {file = "greenlet-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:abe1ef3d780de56defd0c77c5ba95e152f4e4c4e12d7e11dd8447d338b85a625"}, - {file = "greenlet-3.0.0-cp37-cp37m-win32.whl", hash = "sha256:e693e759e172fa1c2c90d35dea4acbdd1d609b6936115d3739148d5e4cd11947"}, - {file = "greenlet-3.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bdd696947cd695924aecb3870660b7545a19851f93b9d327ef8236bfc49be705"}, - {file = "greenlet-3.0.0-cp37-universal2-macosx_11_0_x86_64.whl", hash = "sha256:cc3e2679ea13b4de79bdc44b25a0c4fcd5e94e21b8f290791744ac42d34a0353"}, - {file = "greenlet-3.0.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:63acdc34c9cde42a6534518e32ce55c30f932b473c62c235a466469a710bfbf9"}, - {file = "greenlet-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a1a6244ff96343e9994e37e5b4839f09a0207d35ef6134dce5c20d260d0302c"}, - {file = "greenlet-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b822fab253ac0f330ee807e7485769e3ac85d5eef827ca224feaaefa462dc0d0"}, - {file = "greenlet-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8060b32d8586e912a7b7dac2d15b28dbbd63a174ab32f5bc6d107a1c4143f40b"}, - {file = "greenlet-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:621fcb346141ae08cb95424ebfc5b014361621b8132c48e538e34c3c93ac7365"}, - {file = "greenlet-3.0.0-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6bb36985f606a7c49916eff74ab99399cdfd09241c375d5a820bb855dfb4af9f"}, - {file = "greenlet-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10b5582744abd9858947d163843d323d0b67be9432db50f8bf83031032bc218d"}, - {file = "greenlet-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f351479a6914fd81a55c8e68963609f792d9b067fb8a60a042c585a621e0de4f"}, - {file = "greenlet-3.0.0-cp38-cp38-win32.whl", hash = "sha256:9de687479faec7db5b198cc365bc34addd256b0028956501f4d4d5e9ca2e240a"}, - {file = "greenlet-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:3fd2b18432e7298fcbec3d39e1a0aa91ae9ea1c93356ec089421fabc3651572b"}, - {file = "greenlet-3.0.0-cp38-universal2-macosx_11_0_x86_64.whl", hash = "sha256:3c0d36f5adc6e6100aedbc976d7428a9f7194ea79911aa4bf471f44ee13a9464"}, - {file = "greenlet-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4cd83fb8d8e17633ad534d9ac93719ef8937568d730ef07ac3a98cb520fd93e4"}, - {file = "greenlet-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a5b2d4cdaf1c71057ff823a19d850ed5c6c2d3686cb71f73ae4d6382aaa7a06"}, - {file = "greenlet-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e7dcdfad252f2ca83c685b0fa9fba00e4d8f243b73839229d56ee3d9d219314"}, - {file = "greenlet-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c94e4e924d09b5a3e37b853fe5924a95eac058cb6f6fb437ebb588b7eda79870"}, - {file = "greenlet-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6fb737e46b8bd63156b8f59ba6cdef46fe2b7db0c5804388a2d0519b8ddb99"}, - {file = "greenlet-3.0.0-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d55db1db455c59b46f794346efce896e754b8942817f46a1bada2d29446e305a"}, - {file = "greenlet-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:56867a3b3cf26dc8a0beecdb4459c59f4c47cdd5424618c08515f682e1d46692"}, - {file = "greenlet-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a812224a5fb17a538207e8cf8e86f517df2080c8ee0f8c1ed2bdaccd18f38f4"}, - {file = "greenlet-3.0.0-cp39-cp39-win32.whl", hash = "sha256:0d3f83ffb18dc57243e0151331e3c383b05e5b6c5029ac29f754745c800f8ed9"}, - {file = "greenlet-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:831d6f35037cf18ca5e80a737a27d822d87cd922521d18ed3dbc8a6967be50ce"}, - {file = "greenlet-3.0.0-cp39-universal2-macosx_11_0_x86_64.whl", hash = "sha256:a048293392d4e058298710a54dfaefcefdf49d287cd33fb1f7d63d55426e4355"}, - {file = "greenlet-3.0.0.tar.gz", hash = "sha256:19834e3f91f485442adc1ee440171ec5d9a4840a1f7bd5ed97833544719ce10b"}, + {file = "greenlet-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f89e21afe925fcfa655965ca8ea10f24773a1791400989ff32f467badfe4a064"}, + {file = "greenlet-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28e89e232c7593d33cac35425b58950789962011cc274aa43ef8865f2e11f46d"}, + {file = "greenlet-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8ba29306c5de7717b5761b9ea74f9c72b9e2b834e24aa984da99cbfc70157fd"}, + {file = "greenlet-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19bbdf1cce0346ef7341705d71e2ecf6f41a35c311137f29b8a2dc2341374565"}, + {file = "greenlet-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599daf06ea59bfedbec564b1692b0166a0045f32b6f0933b0dd4df59a854caf2"}, + {file = "greenlet-3.0.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b641161c302efbb860ae6b081f406839a8b7d5573f20a455539823802c655f63"}, + {file = "greenlet-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d57e20ba591727da0c230ab2c3f200ac9d6d333860d85348816e1dca4cc4792e"}, + {file = "greenlet-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5805e71e5b570d490938d55552f5a9e10f477c19400c38bf1d5190d760691846"}, + {file = "greenlet-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:52e93b28db27ae7d208748f45d2db8a7b6a380e0d703f099c949d0f0d80b70e9"}, + {file = "greenlet-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f7bfb769f7efa0eefcd039dd19d843a4fbfbac52f1878b1da2ed5793ec9b1a65"}, + {file = "greenlet-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e6c7db42638dc45cf2e13c73be16bf83179f7859b07cfc139518941320be96"}, + {file = "greenlet-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1757936efea16e3f03db20efd0cd50a1c86b06734f9f7338a90c4ba85ec2ad5a"}, + {file = "greenlet-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19075157a10055759066854a973b3d1325d964d498a805bb68a1f9af4aaef8ec"}, + {file = "greenlet-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9d21aaa84557d64209af04ff48e0ad5e28c5cca67ce43444e939579d085da72"}, + {file = "greenlet-3.0.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2847e5d7beedb8d614186962c3d774d40d3374d580d2cbdab7f184580a39d234"}, + {file = "greenlet-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:97e7ac860d64e2dcba5c5944cfc8fa9ea185cd84061c623536154d5a89237884"}, + {file = "greenlet-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b2c02d2ad98116e914d4f3155ffc905fd0c025d901ead3f6ed07385e19122c94"}, + {file = "greenlet-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:22f79120a24aeeae2b4471c711dcf4f8c736a2bb2fabad2a67ac9a55ea72523c"}, + {file = "greenlet-3.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:100f78a29707ca1525ea47388cec8a049405147719f47ebf3895e7509c6446aa"}, + {file = "greenlet-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60d5772e8195f4e9ebf74046a9121bbb90090f6550f81d8956a05387ba139353"}, + {file = "greenlet-3.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:daa7197b43c707462f06d2c693ffdbb5991cbb8b80b5b984007de431493a319c"}, + {file = "greenlet-3.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea6b8aa9e08eea388c5f7a276fabb1d4b6b9d6e4ceb12cc477c3d352001768a9"}, + {file = "greenlet-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d11ebbd679e927593978aa44c10fc2092bc454b7d13fdc958d3e9d508aba7d0"}, + {file = "greenlet-3.0.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbd4c177afb8a8d9ba348d925b0b67246147af806f0b104af4d24f144d461cd5"}, + {file = "greenlet-3.0.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20107edf7c2c3644c67c12205dc60b1bb11d26b2610b276f97d666110d1b511d"}, + {file = "greenlet-3.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8bef097455dea90ffe855286926ae02d8faa335ed8e4067326257cb571fc1445"}, + {file = "greenlet-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:b2d3337dcfaa99698aa2377c81c9ca72fcd89c07e7eb62ece3f23a3fe89b2ce4"}, + {file = "greenlet-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80ac992f25d10aaebe1ee15df45ca0d7571d0f70b645c08ec68733fb7a020206"}, + {file = "greenlet-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:337322096d92808f76ad26061a8f5fccb22b0809bea39212cd6c406f6a7060d2"}, + {file = "greenlet-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9934adbd0f6e476f0ecff3c94626529f344f57b38c9a541f87098710b18af0a"}, + {file = "greenlet-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc4d815b794fd8868c4d67602692c21bf5293a75e4b607bb92a11e821e2b859a"}, + {file = "greenlet-3.0.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41bdeeb552d814bcd7fb52172b304898a35818107cc8778b5101423c9017b3de"}, + {file = "greenlet-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e6061bf1e9565c29002e3c601cf68569c450be7fc3f7336671af7ddb4657166"}, + {file = "greenlet-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fa24255ae3c0ab67e613556375a4341af04a084bd58764731972bcbc8baeba36"}, + {file = "greenlet-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:b489c36d1327868d207002391f662a1d163bdc8daf10ab2e5f6e41b9b96de3b1"}, + {file = "greenlet-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f33f3258aae89da191c6ebaa3bc517c6c4cbc9b9f689e5d8452f7aedbb913fa8"}, + {file = "greenlet-3.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:d2905ce1df400360463c772b55d8e2518d0e488a87cdea13dd2c71dcb2a1fa16"}, + {file = "greenlet-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a02d259510b3630f330c86557331a3b0e0c79dac3d166e449a39363beaae174"}, + {file = "greenlet-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55d62807f1c5a1682075c62436702aaba941daa316e9161e4b6ccebbbf38bda3"}, + {file = "greenlet-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3fcc780ae8edbb1d050d920ab44790201f027d59fdbd21362340a85c79066a74"}, + {file = "greenlet-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4eddd98afc726f8aee1948858aed9e6feeb1758889dfd869072d4465973f6bfd"}, + {file = "greenlet-3.0.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eabe7090db68c981fca689299c2d116400b553f4b713266b130cfc9e2aa9c5a9"}, + {file = "greenlet-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f2f6d303f3dee132b322a14cd8765287b8f86cdc10d2cb6a6fae234ea488888e"}, + {file = "greenlet-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d923ff276f1c1f9680d32832f8d6c040fe9306cbfb5d161b0911e9634be9ef0a"}, + {file = "greenlet-3.0.1-cp38-cp38-win32.whl", hash = "sha256:0b6f9f8ca7093fd4433472fd99b5650f8a26dcd8ba410e14094c1e44cd3ceddd"}, + {file = "greenlet-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:990066bff27c4fcf3b69382b86f4c99b3652bab2a7e685d968cd4d0cfc6f67c6"}, + {file = "greenlet-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ce85c43ae54845272f6f9cd8320d034d7a946e9773c693b27d620edec825e376"}, + {file = "greenlet-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89ee2e967bd7ff85d84a2de09df10e021c9b38c7d91dead95b406ed6350c6997"}, + {file = "greenlet-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87c8ceb0cf8a5a51b8008b643844b7f4a8264a2c13fcbcd8a8316161725383fe"}, + {file = "greenlet-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6a8c9d4f8692917a3dc7eb25a6fb337bff86909febe2f793ec1928cd97bedfc"}, + {file = "greenlet-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fbc5b8f3dfe24784cee8ce0be3da2d8a79e46a276593db6868382d9c50d97b1"}, + {file = "greenlet-3.0.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85d2b77e7c9382f004b41d9c72c85537fac834fb141b0296942d52bf03fe4a3d"}, + {file = "greenlet-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:696d8e7d82398e810f2b3622b24e87906763b6ebfd90e361e88eb85b0e554dc8"}, + {file = "greenlet-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:329c5a2e5a0ee942f2992c5e3ff40be03e75f745f48847f118a3cfece7a28546"}, + {file = "greenlet-3.0.1-cp39-cp39-win32.whl", hash = "sha256:cf868e08690cb89360eebc73ba4be7fb461cfbc6168dd88e2fbbe6f31812cd57"}, + {file = "greenlet-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:ac4a39d1abae48184d420aa8e5e63efd1b75c8444dd95daa3e03f6c6310e9619"}, + {file = "greenlet-3.0.1.tar.gz", hash = "sha256:816bd9488a94cba78d93e1abb58000e8266fa9cc2aa9ccdd6eb0696acb24005b"}, ] [package.extras] @@ -647,13 +641,13 @@ files = [ [[package]] name = "langchain" -version = "0.0.322" +version = "0.0.323" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langchain-0.0.322-py3-none-any.whl", hash = "sha256:f065d19eff2702cd941fd1f6adca6baf2a1181387f04d3429a0ec7a197e96155"}, - {file = "langchain-0.0.322.tar.gz", hash = "sha256:8415327a964bff9d643202697aca1dcbcfd2d89fb0b49f799bdea37d01fa7f51"}, + {file = "langchain-0.0.323-py3-none-any.whl", hash = "sha256:8c305c8d162262439b0cb73a6621c6ae8b3abde56d45c561a6b88709567cc765"}, + {file = "langchain-0.0.323.tar.gz", hash = "sha256:320116337933fdda48911e84f46c2d71e74eba647c05922a117c71669ccee9e2"}, ] [package.dependencies] @@ -687,38 +681,34 @@ text-helpers = ["chardet (>=5.1.0,<6.0.0)"] [[package]] name = "langserve" -version = "0.0.15" +version = "0.0.16" description = "" optional = false -python-versions = "^3.8.1" -files = [] -develop = false +python-versions = ">=3.8.1,<4.0.0" +files = [ + {file = "langserve-0.0.16-py3-none-any.whl", hash = "sha256:54a9b94e22ed5948f683e24f01939d793c4a07460c58f23a52dab1909a6627e9"}, + {file = "langserve-0.0.16.tar.gz", hash = "sha256:b38c3524515f5d244dfdead8a0ddda76465966d218d95b002abaefd0470ff4cb"}, +] [package.dependencies] httpx = ">=0.23.0" langchain = ">=0.0.322" -pydantic = "^1" +pydantic = ">=1,<2" [package.extras] all = ["fastapi (>=0.90.1)", "httpx-sse (>=0.3.1)", "sse-starlette (>=1.3.0,<2.0.0)"] client = ["httpx-sse (>=0.3.1)"] server = ["fastapi (>=0.90.1)", "sse-starlette (>=1.3.0,<2.0.0)"] -[package.source] -type = "git" -url = "https://github.com/langchain-ai/langserve" -reference = "HEAD" -resolved_reference = "94e08e797206a7c12ac3a5998f20413c571297c2" - [[package]] name = "langsmith" -version = "0.0.51" +version = "0.0.52" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.51-py3-none-any.whl", hash = "sha256:6d65d038f8410344fba13a67437d1d7644a728983ca22ccf2c40dc32b8ba0368"}, - {file = "langsmith-0.0.51.tar.gz", hash = "sha256:b014e16d95c48797e6ed7a053c952bbd23d3034883df4bca13cc958334332a7f"}, + {file = "langsmith-0.0.52-py3-none-any.whl", hash = "sha256:d02a0ade5a53b36143084e57003ed38ccbdf5fc15a5a0eb14f8989ceaee0b807"}, + {file = "langsmith-0.0.52.tar.gz", hash = "sha256:1dc29082d257deea1859cb22c53d9481ca5c4a37f3af40c0f9d300fb8adc91db"}, ] [package.dependencies] @@ -1488,4 +1478,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "68f22526ee53566155cd618c2022cda7c7ce9335c4ba8e260311aaae4de6ddf9" +content-hash = "dd2b124e3e0b96500d6096b31fc7094840524eb85daf3d984d649e96274113fc" diff --git a/libs/cli/tests/test_utils.py b/libs/cli/tests/test_utils.py index bc8118c5d1..1c103806ac 100644 --- a/libs/cli/tests/test_utils.py +++ b/libs/cli/tests/test_utils.py @@ -1,9 +1,14 @@ -from langchain_cli.utils.git import _parse_dependency_string, DependencySource -from langchain_cli.constants import DEFAULT_GIT_REPO, DEFAULT_GIT_SUBDIRECTORY +import pytest +from langchain_cli.utils.git import parse_dependency_string, DependencySource +from langchain_cli.constants import ( + DEFAULT_GIT_REPO, + DEFAULT_GIT_SUBDIRECTORY, + DEFAULT_GIT_REF, +) def test_dependency_string() -> None: - assert _parse_dependency_string( + assert parse_dependency_string( "git+ssh://git@github.com/efriis/myrepo.git" ) == DependencySource( git="ssh://git@github.com/efriis/myrepo.git", @@ -11,7 +16,7 @@ def test_dependency_string() -> None: subdirectory=None, ) - assert _parse_dependency_string( + assert parse_dependency_string( "git+https://github.com/efriis/myrepo.git#subdirectory=src" ) == DependencySource( git="https://github.com/efriis/myrepo.git", @@ -19,14 +24,69 @@ def test_dependency_string() -> None: ref=None, ) - assert _parse_dependency_string( + assert parse_dependency_string( "git+ssh://git@github.com:efriis/myrepo.git#develop" ) == DependencySource( git="ssh://git@github.com:efriis/myrepo.git", ref="develop", subdirectory=None ) - assert _parse_dependency_string("simple-pirate") == DependencySource( + # also support a slash in ssh + assert parse_dependency_string( + "git+ssh://git@github.com/efriis/myrepo.git#develop" + ) == DependencySource( + git="ssh://git@github.com/efriis/myrepo.git", ref="develop", subdirectory=None + ) + + # looks like poetry supports both an @ and a # + assert parse_dependency_string( + "git+ssh://git@github.com:efriis/myrepo.git@develop" + ) == DependencySource( + git="ssh://git@github.com:efriis/myrepo.git", ref="develop", subdirectory=None + ) + + assert parse_dependency_string("simple-pirate") == DependencySource( git=DEFAULT_GIT_REPO, subdirectory=f"{DEFAULT_GIT_SUBDIRECTORY}/simple-pirate", + ref=DEFAULT_GIT_REF, + ) + + +def test_dependency_string_both() -> None: + assert parse_dependency_string( + "git+https://github.com/efriis/myrepo.git@branch#subdirectory=src" + ) == DependencySource( + git="https://github.com/efriis/myrepo.git", + subdirectory="src", + ref="branch", + ) + + +def test_dependency_string_invalids() -> None: + # expect error for wrong order + with pytest.raises(ValueError): + parse_dependency_string( + "git+https://github.com/efriis/myrepo.git#subdirectory=src@branch" + ) + # expect error for @subdirectory + + +def test_dependency_string_edge_case() -> None: + # weird unsolvable edge case of + # git+ssh://a@b + # this could be a ssh dep with user=a, and default ref + # or a ssh dep at a with ref=b. + # in this case, assume the first case (be greedy with the '@') + assert parse_dependency_string("git+ssh://a@b") == DependencySource( + git="ssh://a@b", + subdirectory=None, ref=None, ) + + # weird one that is actually valid + assert parse_dependency_string( + "git+https://github.com/efriis/myrepo.git@subdirectory=src" + ) == DependencySource( + git="https://github.com/efriis/myrepo.git", + subdirectory=None, + ref="subdirectory=src", + )