From 5170d87134178634839263c54ff61759e9e5236a Mon Sep 17 00:00:00 2001 From: Bola Malek Date: Mon, 24 Jul 2023 21:29:02 -0700 Subject: [PATCH] Add interactive CLI for truss push (#467) * Add interactive CLI for truss push * Update inquirer UX * Self-review --- .tool-versions | 2 +- poetry.lock | 250 ++++------------------ pyproject.toml | 1 + truss/cli.py | 12 +- truss/remote/remote_cli.py | 50 +++++ truss/remote/remote_factory.py | 65 ++++-- truss/remote/truss_remote.py | 9 + truss/tests/remote/test_remote_factory.py | 23 +- 8 files changed, 174 insertions(+), 238 deletions(-) create mode 100644 truss/remote/remote_cli.py diff --git a/.tool-versions b/.tool-versions index 4a678234c..bff6ea103 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ python 3.9.11 -poetry 1.4.2 +poetry 1.5.1 diff --git a/poetry.lock b/poetry.lock index 099d907d8..529f4cecf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "absl-py" version = "1.4.0" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -16,7 +15,6 @@ files = [ name = "alembic" version = "1.11.1" description = "A database migration tool for SQLAlchemy." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -38,7 +36,6 @@ tz = ["python-dateutil"] name = "anyio" version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -60,7 +57,6 @@ trio = ["trio (<0.22)"] name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" -category = "dev" optional = false python-versions = "*" files = [ @@ -72,7 +68,6 @@ files = [ name = "astunparse" version = "1.6.3" description = "An AST unparser for Python" -category = "dev" optional = false python-versions = "*" files = [ @@ -88,7 +83,6 @@ wheel = ">=0.23.0,<1.0" name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -107,7 +101,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" -category = "dev" optional = false python-versions = "*" files = [ @@ -119,7 +112,6 @@ files = [ name = "beautifulsoup4" version = "4.12.2" description = "Screen-scraping library" -category = "dev" optional = false python-versions = ">=3.6.0" files = [ @@ -138,7 +130,6 @@ lxml = ["lxml"] name = "black" version = "22.12.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -174,7 +165,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "blake3" version = "0.3.3" description = "Python bindings for the Rust blake3 crate" -category = "main" optional = false python-versions = "*" files = [ @@ -209,7 +199,6 @@ files = [ name = "bleach" version = "6.0.0" description = "An easy safelist-based HTML-sanitizing tool." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -228,7 +217,6 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] name = "blinker" version = "1.6.2" description = "Fast, simple object-to-object and broadcast signaling" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -240,7 +228,6 @@ files = [ name = "boto3" version = "1.28.2" description = "The AWS SDK for Python" -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -260,7 +247,6 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] name = "botocore" version = "1.31.2" description = "Low-level, data-driven core of boto 3." -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -280,7 +266,6 @@ crt = ["awscrt (==0.16.9)"] name = "cachetools" version = "5.3.1" description = "Extensible memoizing collections and decorators" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -292,7 +277,6 @@ files = [ name = "certifi" version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -304,7 +288,6 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." -category = "dev" optional = false python-versions = "*" files = [ @@ -381,7 +364,6 @@ pycparser = "*" name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -393,7 +375,6 @@ files = [ name = "charset-normalizer" version = "3.2.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -478,7 +459,6 @@ files = [ name = "click" version = "8.1.4" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -493,7 +473,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "cloudpickle" version = "2.2.1" description = "Extended pickling support for Python objects" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -505,7 +484,6 @@ files = [ name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -517,7 +495,6 @@ files = [ name = "comm" version = "0.1.3" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -537,7 +514,6 @@ typing = ["mypy (>=0.990)"] name = "coverage" version = "6.5.0" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -603,7 +579,6 @@ toml = ["tomli"] name = "databricks-cli" version = "0.17.7" description = "A command line interface for Databricks" -category = "dev" optional = false python-versions = "*" files = [ @@ -624,7 +599,6 @@ urllib3 = ">=1.26.7,<2.0.0" name = "debugpy" version = "1.6.7" description = "An implementation of the Debug Adapter Protocol for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -652,7 +626,6 @@ files = [ name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -664,7 +637,6 @@ files = [ name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -676,7 +648,6 @@ files = [ name = "distlib" version = "0.3.6" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ @@ -688,7 +659,6 @@ files = [ name = "docker" version = "6.1.3" description = "A Python library for the Docker Engine API." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -710,7 +680,6 @@ ssh = ["paramiko (>=2.4.3)"] name = "dockerfile" version = "3.2.0" description = "Parse a dockerfile into a high-level representation using the official go parser." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -724,7 +693,6 @@ files = [ name = "entrypoints" version = "0.4" description = "Discover and load entry points from installed packages." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -736,7 +704,6 @@ files = [ name = "exceptiongroup" version = "1.1.2" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -751,7 +718,6 @@ test = ["pytest (>=6)"] name = "fastapi" version = "0.95.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -773,7 +739,6 @@ test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6 name = "fastjsonschema" version = "2.17.1" description = "Fastest Python implementation of JSON schema" -category = "dev" optional = false python-versions = "*" files = [ @@ -788,7 +753,6 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc name = "filelock" version = "3.12.2" description = "A platform independent file lock." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -804,7 +768,6 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p name = "flake8" version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -821,7 +784,6 @@ pyflakes = ">=2.4.0,<2.5.0" name = "flask" version = "2.3.2" description = "A simple framework for building complex web applications." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -845,7 +807,6 @@ dotenv = ["python-dotenv"] name = "flatbuffers" version = "23.5.26" description = "The FlatBuffers serialization format for Python" -category = "dev" optional = false python-versions = "*" files = [ @@ -857,7 +818,6 @@ files = [ name = "fsspec" version = "2023.6.0" description = "File-system specification" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -893,7 +853,6 @@ tqdm = ["tqdm"] name = "gast" version = "0.4.0" description = "Python AST that abstracts the underlying Python version" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -905,7 +864,6 @@ files = [ name = "gitdb" version = "4.0.10" description = "Git Object Database" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -920,7 +878,6 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.32" description = "GitPython is a Python library used to interact with Git repositories" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -935,7 +892,6 @@ gitdb = ">=4.0.1,<5" name = "google-auth" version = "2.21.0" description = "Google Authentication Library" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -961,7 +917,6 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] name = "google-auth-oauthlib" version = "1.0.0" description = "Google Authentication Library" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -980,7 +935,6 @@ tool = ["click (>=6.0.0)"] name = "google-pasta" version = "0.2.0" description = "pasta is an AST-based Python refactoring library" -category = "dev" optional = false python-versions = "*" files = [ @@ -996,7 +950,6 @@ six = "*" name = "greenlet" version = "2.0.2" description = "Lightweight in-process concurrent programming" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ @@ -1070,7 +1023,6 @@ test = ["objgraph", "psutil"] name = "grpcio" version = "1.56.0" description = "HTTP/2-based RPC framework" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1128,7 +1080,6 @@ protobuf = ["grpcio-tools (>=1.56.0)"] name = "gunicorn" version = "20.1.0" description = "WSGI HTTP Server for UNIX" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1149,7 +1100,6 @@ tornado = ["tornado (>=0.2)"] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1161,7 +1111,6 @@ files = [ name = "h5py" version = "3.9.0" description = "Read and write HDF5 files from Python" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1195,7 +1144,6 @@ numpy = ">=1.17.3" name = "httpcore" version = "0.17.3" description = "A minimal low-level HTTP client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1207,17 +1155,16 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "httpx" version = "0.24.1" description = "The next generation HTTP client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1227,24 +1174,23 @@ files = [ [package.dependencies] certifi = "*" -click = {version = ">=8.0.0,<9.0.0", optional = true, markers = "extra == \"cli\""} +click = {version = "==8.*", optional = true, markers = "extra == \"cli\""} httpcore = ">=0.15.0,<0.18.0" idna = "*" -pygments = {version = ">=2.0.0,<3.0.0", optional = true, markers = "extra == \"cli\""} +pygments = {version = "==2.*", optional = true, markers = "extra == \"cli\""} rich = {version = ">=10,<14", optional = true, markers = "extra == \"cli\""} sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" version = "0.16.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1277,7 +1223,6 @@ typing = ["pydantic", "types-PyYAML", "types-requests", "types-simplejson", "typ name = "identify" version = "2.5.24" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1292,7 +1237,6 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1304,7 +1248,6 @@ files = [ name = "importlib-metadata" version = "5.2.0" description = "Read metadata from Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1324,7 +1267,6 @@ testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packag name = "importlib-resources" version = "6.0.0" description = "Read resources from Python packages" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1343,7 +1285,6 @@ testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1351,11 +1292,28 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "inquirerpy" +version = "0.3.4" +description = "Python port of Inquirer.js (A collection of common interactive command-line user interfaces)" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "InquirerPy-0.3.4-py3-none-any.whl", hash = "sha256:c65fdfbac1fa00e3ee4fb10679f4d3ed7a012abf4833910e63c295827fe2a7d4"}, + {file = "InquirerPy-0.3.4.tar.gz", hash = "sha256:89d2ada0111f337483cb41ae31073108b2ec1e618a49d7110b0d7ade89fc197e"}, +] + +[package.dependencies] +pfzy = ">=0.3.1,<0.4.0" +prompt-toolkit = ">=3.0.1,<4.0.0" + +[package.extras] +docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17-beta.43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] + [[package]] name = "ipdb" version = "0.13.13" description = "IPython-enabled pdb" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1372,7 +1330,6 @@ tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < name = "ipykernel" version = "6.24.0" description = "IPython Kernel for Jupyter" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1386,7 +1343,7 @@ comm = ">=0.1.1" debugpy = ">=1.6.5" ipython = ">=7.23.1" jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" matplotlib-inline = ">=0.1" nest-asyncio = "*" packaging = "*" @@ -1406,7 +1363,6 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio" name = "ipython" version = "7.34.0" description = "IPython: Productive Interactive Computing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1443,7 +1399,6 @@ test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments" name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -1461,7 +1416,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "itsdangerous" version = "2.1.2" description = "Safely pass data to untrusted environments and back." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1473,7 +1427,6 @@ files = [ name = "jax" version = "0.4.13" description = "Differentiate, compile, and transform Numpy code." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1504,7 +1457,6 @@ tpu = ["jaxlib (==0.4.13)", "libtpu-nightly (==0.1.dev20230622)"] name = "jedi" version = "0.18.2" description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1524,7 +1476,6 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1542,7 +1493,6 @@ i18n = ["Babel (>=2.7)"] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1554,7 +1504,6 @@ files = [ name = "joblib" version = "1.3.1" description = "Lightweight pipelining with Python functions" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1566,7 +1515,6 @@ files = [ name = "jsonschema" version = "4.18.0" description = "An implementation of JSON Schema validation for Python" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1590,7 +1538,6 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- name = "jsonschema-specifications" version = "2023.6.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1606,7 +1553,6 @@ referencing = ">=0.28.0" name = "jupyter-client" version = "8.3.0" description = "Jupyter protocol implementation and client libraries" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1616,7 +1562,7 @@ files = [ [package.dependencies] importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" python-dateutil = ">=2.8.2" pyzmq = ">=23.0" tornado = ">=6.2" @@ -1630,7 +1576,6 @@ test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pyt name = "jupyter-core" version = "5.3.1" description = "Jupyter core package. A base package on which Jupyter projects rely." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1651,7 +1596,6 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] name = "jupyterlab-pygments" version = "0.2.2" description = "Pygments theme using JupyterLab CSS variables" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1663,7 +1607,6 @@ files = [ name = "keras" version = "2.12.0" description = "Deep learning for humans." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1674,7 +1617,6 @@ files = [ name = "libclang" version = "16.0.0" description = "Clang Python Bindings, mirrored from the official LLVM repo: https://github.com/llvm/llvm-project/tree/main/clang/bindings/python, to make the installation process easier." -category = "dev" optional = false python-versions = "*" files = [ @@ -1692,7 +1634,6 @@ files = [ name = "lightgbm" version = "3.3.5" description = "LightGBM Python Package" -category = "dev" optional = false python-versions = "*" files = [ @@ -1716,7 +1657,6 @@ dask = ["dask[array] (>=2.0.0)", "dask[dataframe] (>=2.0.0)", "dask[distributed] name = "mako" version = "1.2.4" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1736,7 +1676,6 @@ testing = ["pytest"] name = "markdown" version = "3.4.3" description = "Python implementation of John Gruber's Markdown." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1754,7 +1693,6 @@ testing = ["coverage", "pyyaml"] name = "markdown-it-py" version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1779,7 +1717,6 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1839,7 +1776,6 @@ files = [ name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -1854,7 +1790,6 @@ traitlets = "*" name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" files = [ @@ -1866,7 +1801,6 @@ files = [ name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1878,7 +1812,6 @@ files = [ name = "mistune" version = "3.0.1" description = "A sane and fast Markdown parser with useful plugins and renderers" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1890,7 +1823,6 @@ files = [ name = "ml-dtypes" version = "0.2.0" description = "" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1927,7 +1859,6 @@ dev = ["absl-py", "pyink", "pylint (>=2.6.0)", "pytest", "pytest-xdist"] name = "mlflow" version = "1.30.1" description = "MLflow: A Platform for ML Development and Productionization" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1970,7 +1901,6 @@ sqlserver = ["mlflow-dbstore"] name = "msgpack" version = "1.0.5" description = "MessagePack serializer" -category = "main" optional = false python-versions = "*" files = [ @@ -2043,7 +1973,6 @@ files = [ name = "msgpack-numpy" version = "0.4.8" description = "Numpy data serialization using msgpack" -category = "main" optional = false python-versions = "*" files = [ @@ -2059,7 +1988,6 @@ numpy = ">=1.9.0" name = "mypy" version = "1.4.1" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2106,7 +2034,6 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2118,7 +2045,6 @@ files = [ name = "nbclient" version = "0.8.0" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -2128,7 +2054,7 @@ files = [ [package.dependencies] jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.0 || >=5.1.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" nbformat = ">=5.1" traitlets = ">=5.4" @@ -2141,7 +2067,6 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= name = "nbconvert" version = "7.6.0" description = "Converting Jupyter Notebooks" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2180,7 +2105,6 @@ webpdf = ["pyppeteer (>=1,<1.1)"] name = "nbformat" version = "5.9.1" description = "The Jupyter Notebook format" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2202,7 +2126,6 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] name = "nest-asyncio" version = "1.5.6" description = "Patch asyncio to allow nested event loops" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2214,7 +2137,6 @@ files = [ name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -2229,7 +2151,6 @@ setuptools = "*" name = "numpy" version = "1.23.5" description = "NumPy is the fundamental package for array computing with Python." -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -2267,7 +2188,6 @@ files = [ name = "nvidia-cublas-cu11" version = "11.10.3.66" description = "CUBLAS native runtime libraries" -category = "dev" optional = false python-versions = ">=3" files = [ @@ -2283,7 +2203,6 @@ wheel = "*" name = "nvidia-cuda-nvrtc-cu11" version = "11.7.99" description = "NVRTC native runtime libraries" -category = "dev" optional = false python-versions = ">=3" files = [ @@ -2300,7 +2219,6 @@ wheel = "*" name = "nvidia-cuda-runtime-cu11" version = "11.7.99" description = "CUDA Runtime native Libraries" -category = "dev" optional = false python-versions = ">=3" files = [ @@ -2316,7 +2234,6 @@ wheel = "*" name = "nvidia-cudnn-cu11" version = "8.5.0.96" description = "cuDNN runtime libraries" -category = "dev" optional = false python-versions = ">=3" files = [ @@ -2332,7 +2249,6 @@ wheel = "*" name = "oauthlib" version = "3.2.2" description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2349,7 +2265,6 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] name = "opt-einsum" version = "3.3.0" description = "Optimizing numpys einsum function" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -2368,7 +2283,6 @@ tests = ["pytest", "pytest-cov", "pytest-pep8"] name = "packaging" version = "20.9" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2383,7 +2297,6 @@ pyparsing = ">=2.0.2" name = "pandas" version = "1.5.2" description = "Powerful data structures for data analysis, time series, and statistics" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -2432,7 +2345,6 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] name = "pandocfilters" version = "1.5.0" description = "Utilities for writing pandoc filters in python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2444,7 +2356,6 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2460,7 +2371,6 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2472,7 +2382,6 @@ files = [ name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "dev" optional = false python-versions = "*" files = [ @@ -2483,11 +2392,24 @@ files = [ [package.dependencies] ptyprocess = ">=0.5" +[[package]] +name = "pfzy" +version = "0.3.4" +description = "Python port of the fzy fuzzy string matching algorithm" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "pfzy-0.3.4-py3-none-any.whl", hash = "sha256:5f50d5b2b3207fa72e7ec0ef08372ef652685470974a107d0d4999fc5a903a96"}, + {file = "pfzy-0.3.4.tar.gz", hash = "sha256:717ea765dd10b63618e7298b2d98efd819e0b30cd5905c9707223dceeb94b3f1"}, +] + +[package.extras] +docs = ["Sphinx (>=4.1.2,<5.0.0)", "furo (>=2021.8.17-beta.43,<2022.0.0)", "myst-parser (>=0.15.1,<0.16.0)", "sphinx-autobuild (>=2021.3.14,<2022.0.0)", "sphinx-copybutton (>=0.4.0,<0.5.0)"] + [[package]] name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" optional = false python-versions = "*" files = [ @@ -2499,7 +2421,6 @@ files = [ name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2511,7 +2432,6 @@ files = [ name = "platformdirs" version = "3.8.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2527,7 +2447,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest- name = "pluggy" version = "1.2.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2543,7 +2462,6 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2562,7 +2480,6 @@ virtualenv = ">=20.10.0" name = "prometheus-client" version = "0.17.1" description = "Python client for the Prometheus monitoring system." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2577,7 +2494,6 @@ twisted = ["twisted"] name = "prometheus-flask-exporter" version = "0.22.4" description = "Prometheus metrics exporter for Flask" -category = "dev" optional = false python-versions = "*" files = [ @@ -2593,7 +2509,6 @@ prometheus-client = "*" name = "prompt-toolkit" version = "3.0.39" description = "Library for building powerful interactive command lines in Python" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -2608,7 +2523,6 @@ wcwidth = "*" name = "protobuf" version = "4.23.4" description = "" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2631,7 +2545,6 @@ files = [ name = "psutil" version = "5.9.5" description = "Cross-platform lib for process and system monitoring in Python." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2658,7 +2571,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -2670,7 +2582,6 @@ files = [ name = "pyasn1" version = "0.5.0" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2682,7 +2593,6 @@ files = [ name = "pyasn1-modules" version = "0.3.0" description = "A collection of ASN.1-based protocols modules" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -2697,7 +2607,6 @@ pyasn1 = ">=0.4.6,<0.6.0" name = "pycodestyle" version = "2.8.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -2709,7 +2618,6 @@ files = [ name = "pycparser" version = "2.21" description = "C parser in Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2721,7 +2629,6 @@ files = [ name = "pydantic" version = "1.10.11" description = "Data validation and settings management using python type hints" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2774,7 +2681,6 @@ email = ["email-validator (>=1.0.3)"] name = "pyflakes" version = "2.4.0" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -2786,7 +2692,6 @@ files = [ name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2801,7 +2706,6 @@ plugins = ["importlib-metadata"] name = "pyjwt" version = "2.7.0" description = "JSON Web Token implementation in Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2819,7 +2723,6 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] name = "pyparsing" version = "3.1.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" optional = false python-versions = ">=3.6.8" files = [ @@ -2834,7 +2737,6 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pytest" version = "7.2.0" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -2858,7 +2760,6 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. name = "pytest-cov" version = "3.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -2877,7 +2778,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-split" version = "0.8.1" description = "Pytest plugin which splits the test suite to equally sized sub suites based on test execution time." -category = "dev" optional = false python-versions = ">=3.7.1,<4.0" files = [ @@ -2892,7 +2792,6 @@ pytest = ">=5,<8" name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -2907,7 +2806,6 @@ six = ">=1.5" name = "python-json-logger" version = "2.0.7" description = "A python library adding a json log formatter" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -2919,7 +2817,6 @@ files = [ name = "python-on-whales" version = "0.46.0" description = "A Docker client for Python, designed to be fun and intuitive!" -category = "main" optional = false python-versions = ">=3.7, <4" files = [ @@ -2938,7 +2835,6 @@ typing-extensions = "*" name = "pytz" version = "2022.7.1" description = "World timezone definitions, modern and historical" -category = "dev" optional = false python-versions = "*" files = [ @@ -2950,7 +2846,6 @@ files = [ name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "dev" optional = false python-versions = "*" files = [ @@ -2974,7 +2869,6 @@ files = [ name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3024,7 +2918,6 @@ files = [ name = "pyzmq" version = "25.1.0" description = "Python bindings for 0MQ" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3114,7 +3007,6 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} name = "querystring-parser" version = "1.2.4" description = "QueryString parser for Python/Django that correctly handles nested dictionaries" -category = "dev" optional = false python-versions = "*" files = [ @@ -3129,7 +3021,6 @@ six = "*" name = "referencing" version = "0.29.1" description = "JSON Referencing + Python" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3145,7 +3036,6 @@ rpds-py = ">=0.7.0" name = "regex" version = "2023.6.3" description = "Alternative regular expression module, to replace re." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3243,7 +3133,6 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3265,7 +3154,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "requests-oauthlib" version = "1.3.1" description = "OAuthlib authentication support for Requests." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -3284,7 +3172,6 @@ rsa = ["oauthlib[signedtoken] (>=3.0.0)"] name = "rich" version = "13.4.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -3304,7 +3191,6 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] name = "rpds-py" version = "0.8.10" description = "Python bindings to Rust's persistent data structures (rpds)" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3411,7 +3297,6 @@ files = [ name = "rsa" version = "4.9" description = "Pure-Python RSA implementation" -category = "dev" optional = false python-versions = ">=3.6,<4" files = [ @@ -3426,7 +3311,6 @@ pyasn1 = ">=0.1.3" name = "s3transfer" version = "0.6.1" description = "An Amazon S3 Transfer Manager" -category = "main" optional = false python-versions = ">= 3.7" files = [ @@ -3444,7 +3328,6 @@ crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] name = "safetensors" version = "0.3.1" description = "Fast and Safe Tensor serialization" -category = "dev" optional = false python-versions = "*" files = [ @@ -3505,7 +3388,6 @@ torch = ["torch (>=1.10)"] name = "scikit-learn" version = "1.0.2" description = "A set of python modules for machine learning and data mining" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3559,7 +3441,6 @@ tests = ["black (>=21.6b0)", "flake8 (>=3.8.2)", "matplotlib (>=2.2.3)", "mypy ( name = "scipy" version = "1.10.1" description = "Fundamental algorithms for scientific computing in Python" -category = "dev" optional = false python-versions = "<3.12,>=3.8" files = [ @@ -3598,7 +3479,6 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo name = "setuptools" version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3615,7 +3495,6 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "single-source" version = "0.3.0" description = "Access to the project version in Python code for PEP 621-style projects" -category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -3627,7 +3506,6 @@ files = [ name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -3639,7 +3517,6 @@ files = [ name = "smmap" version = "5.0.0" description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -3651,7 +3528,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3663,7 +3539,6 @@ files = [ name = "soupsieve" version = "2.4.1" description = "A modern CSS selector implementation for Beautiful Soup." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3675,7 +3550,6 @@ files = [ name = "sqlalchemy" version = "1.4.49" description = "Database Abstraction Library" -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ @@ -3720,7 +3594,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} [package.extras] aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] @@ -3747,7 +3621,6 @@ sqlcipher = ["sqlcipher3-binary"] name = "sqlparse" version = "0.4.4" description = "A non-validating SQL parser." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -3764,7 +3637,6 @@ test = ["pytest", "pytest-cov"] name = "starlette" version = "0.27.0" description = "The little ASGI library that shines." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -3783,7 +3655,6 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam name = "tabulate" version = "0.9.0" description = "Pretty-print tabular data" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3798,7 +3669,6 @@ widechars = ["wcwidth"] name = "tenacity" version = "8.2.2" description = "Retry code until it succeeds" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -3813,7 +3683,6 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] name = "tensorboard" version = "2.12.3" description = "TensorBoard lets you watch Tensors Flow" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3838,7 +3707,6 @@ wheel = ">=0.26" name = "tensorboard-data-server" version = "0.7.1" description = "Fast data loading for TensorBoard" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3851,7 +3719,6 @@ files = [ name = "tensorflow" version = "2.12.0" description = "TensorFlow is an open source machine learning framework for everyone." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -3901,7 +3768,6 @@ wrapt = ">=1.11.0,<1.15" name = "tensorflow-estimator" version = "2.12.0" description = "TensorFlow Estimator." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -3912,7 +3778,6 @@ files = [ name = "tensorflow-hub" version = "0.12.0" description = "TensorFlow Hub is a library to foster the publication, discovery, and consumption of reusable parts of machine learning models." -category = "dev" optional = false python-versions = "*" files = [ @@ -3931,7 +3796,6 @@ make-nearest-neighbour-index = ["annoy", "apache-beam"] name = "tensorflow-io-gcs-filesystem" version = "0.32.0" description = "TensorFlow IO" -category = "dev" optional = false python-versions = ">=3.7, <3.12" files = [ @@ -3962,7 +3826,6 @@ tensorflow-rocm = ["tensorflow-rocm (>=2.12.0,<2.13.0)"] name = "tensorflow-macos" version = "2.12.0" description = "TensorFlow is an open source machine learning framework for everyone." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -4004,7 +3867,6 @@ wrapt = ">=1.11.0,<1.15" name = "termcolor" version = "2.3.0" description = "ANSI color formatting for output in terminal" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4019,7 +3881,6 @@ tests = ["pytest", "pytest-cov"] name = "threadpoolctl" version = "3.1.0" description = "threadpoolctl" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -4031,7 +3892,6 @@ files = [ name = "tinycss2" version = "1.2.1" description = "A tiny CSS parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4050,7 +3910,6 @@ test = ["flake8", "isort", "pytest"] name = "tokenizers" version = "0.13.3" description = "Fast and Customizable Tokenizers" -category = "dev" optional = false python-versions = "*" files = [ @@ -4105,7 +3964,6 @@ testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4117,7 +3975,6 @@ files = [ name = "torch" version = "1.13.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -4158,7 +4015,6 @@ opt-einsum = ["opt-einsum (>=3.3)"] name = "tornado" version = "6.3.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." -category = "dev" optional = false python-versions = ">= 3.8" files = [ @@ -4179,7 +4035,6 @@ files = [ name = "tqdm" version = "4.65.0" description = "Fast, Extensible Progress Meter" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4200,7 +4055,6 @@ telegram = ["requests"] name = "traitlets" version = "5.9.0" description = "Traitlets Python configuration system" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4216,7 +4070,6 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] name = "transformers" version = "4.30.2" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -4286,7 +4139,6 @@ vision = ["Pillow"] name = "typer" version = "0.9.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -4308,7 +4160,6 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. name = "typing-extensions" version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4320,7 +4171,6 @@ files = [ name = "urllib3" version = "1.26.16" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ @@ -4337,7 +4187,6 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] name = "uvicorn" version = "0.21.1" description = "The lightning-fast ASGI server." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4356,7 +4205,6 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", name = "virtualenv" version = "20.23.1" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4377,7 +4225,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess name = "waitress" version = "2.1.2" description = "Waitress WSGI server" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -4393,7 +4240,6 @@ testing = ["coverage (>=5.0)", "pytest", "pytest-cover"] name = "watchfiles" version = "0.19.0" description = "Simple, modern and high performance file watching and code reload in python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -4428,7 +4274,6 @@ anyio = ">=3.0.0" name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -4440,7 +4285,6 @@ files = [ name = "webencodings" version = "0.5.1" description = "Character encoding aliases for legacy web content" -category = "dev" optional = false python-versions = "*" files = [ @@ -4452,7 +4296,6 @@ files = [ name = "websocket-client" version = "1.6.1" description = "WebSocket client for Python with low level API options" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4469,7 +4312,6 @@ test = ["websockets"] name = "werkzeug" version = "2.3.6" description = "The comprehensive WSGI web application library." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -4487,7 +4329,6 @@ watchdog = ["watchdog (>=2.3)"] name = "wheel" version = "0.40.0" description = "A built-package format for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -4502,7 +4343,6 @@ test = ["pytest (>=6.0.0)"] name = "wrapt" version = "1.14.1" description = "Module for decorators, wrappers and monkey patching." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -4576,7 +4416,6 @@ files = [ name = "xgboost" version = "1.7.6" description = "XGBoost Python Package" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -4604,7 +4443,6 @@ scikit-learn = ["scikit-learn"] name = "zipp" version = "3.16.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -4619,4 +4457,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "ad117168ccf349648a7835583c94a57c88434b44431beb13769938211bd00c42" +content-hash = "24e514baf8d8a5647081058390bcd365a7ed7977c691803df95d12068f0eb934" diff --git a/pyproject.toml b/pyproject.toml index f921c6901..5ac2d1b58 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ boto3 = "^1.26.157" rich = "^13.4.2" watchfiles = "^0.19.0" huggingface_hub = "^0.16.4" +inquirerpy = "^0.3.4" [tool.poetry.group.builder.dependencies] python = ">=3.8,<3.12" diff --git a/truss/cli.py b/truss/cli.py index 1ce224c66..45366f276 100644 --- a/truss/cli.py +++ b/truss/cli.py @@ -8,6 +8,7 @@ import click import truss import yaml +from truss.remote.remote_cli import inquire_model_name, inquire_remote_name from truss.remote.remote_factory import RemoteFactory logging.basicConfig(level=logging.INFO) @@ -298,7 +299,7 @@ def train(target_directory: str, build_dir, tag, var: List[str], vars_yaml_file, @click.option( "--remote", type=str, - required=True, + required=False, help="Name of the remote in .trussrc to push to", ) @click.option("--model-name", type=str, required=False, help="Name of the model") @@ -323,16 +324,17 @@ def push( TARGET_DIRECTORY: A Truss directory. If none, use current directory. """ + if not remote: + remote = inquire_remote_name(RemoteFactory.get_available_config_names()) + remote_provider = RemoteFactory.create(remote=remote) tr = _get_truss_from_directory(target_directory=target_directory) # Push model_name = model_name or tr.spec.config.model_name - if model_name is None: - raise ValueError( - "Model name must be provided either as a flag or in the Truss config" - ) + if not model_name: + model_name = inquire_model_name() # Write model name to config if it's not already there if model_name != tr.spec.config.model_name: diff --git a/truss/remote/remote_cli.py b/truss/remote/remote_cli.py new file mode 100644 index 000000000..69319523a --- /dev/null +++ b/truss/remote/remote_cli.py @@ -0,0 +1,50 @@ +from typing import List + +import rich +from InquirerPy import inquirer +from truss.remote.remote_factory import RemoteFactory +from truss.remote.truss_remote import RemoteConfig + + +def inquire_remote_config() -> RemoteConfig: + # TODO(bola): extract questions from remote + rich.print("💻 Let's add a Baseten remote!") + remote_url = inquirer.text( + message="🌐 Baseten remote url:", + default="https://app.baseten.co", + qmark="", + ).execute() + api_key = inquirer.secret( + message="🤫 Quiety paste your API_KEY:", + qmark="", + ).execute() + return RemoteConfig( + name="baseten", + configs={ + "remote_provider": "baseten", + "api_key": api_key, + "remote_url": remote_url, + }, + ) + + +def inquire_remote_name(available_remotes: List[str]) -> str: + if len(available_remotes) > 1: + remote = inquirer.select( + "🎮 Which remote do you want to push to?", + qmark="", + choices=[available_remotes], + ).execute() + return remote + elif len(available_remotes) == 1: + return available_remotes[0] + remote_config = inquire_remote_config() + RemoteFactory.update_remote_config(remote_config) + return remote_config.name + + +def inquire_model_name() -> str: + return inquirer.text( + "📦 Name this model:", + qmark="", + ).execute() diff --git a/truss/remote/remote_factory.py b/truss/remote/remote_factory.py index ad7fe0767..2010d18dd 100644 --- a/truss/remote/remote_factory.py +++ b/truss/remote/remote_factory.py @@ -1,10 +1,25 @@ -import configparser import inspect +from configparser import DEFAULTSECT, SafeConfigParser +from functools import partial +from operator import is_not from pathlib import Path -from typing import Dict, Type +from typing import Dict, List, Type from truss.remote.baseten import BasetenRemote -from truss.remote.truss_remote import TrussRemote +from truss.remote.truss_remote import RemoteConfig, TrussRemote + +USER_TRUSSRC_PATH = Path("~/.trussrc").expanduser() + + +def load_config() -> SafeConfigParser: + config = SafeConfigParser() + config.read(USER_TRUSSRC_PATH) + return config + + +def update_config(config: SafeConfigParser): + with open(USER_TRUSSRC_PATH, "w") as configfile: + config.write(configfile) class RemoteFactory: @@ -15,22 +30,36 @@ class RemoteFactory: REGISTRY: Dict[str, Type[TrussRemote]] = {"baseten": BasetenRemote} @staticmethod - def load_remote_config(remote_name: str) -> Dict: + def get_available_config_names() -> List[str]: + if not USER_TRUSSRC_PATH.exists(): + return [] + + config = load_config() + return list(filter(partial(is_not, DEFAULTSECT), config.keys())) + + @staticmethod + def load_remote_config(remote_name: str) -> RemoteConfig: """ Load and validate a remote config from the .trussrc file """ - config_path = Path("~/.trussrc").expanduser() - - if not config_path.exists(): - raise FileNotFoundError(f"No .trussrc file found at {config_path}") + if not USER_TRUSSRC_PATH.exists(): + raise FileNotFoundError("No ~/.trussrc file found.") - config = configparser.ConfigParser() - config.read(config_path) + config = load_config() if remote_name not in config: - raise ValueError(f"Service provider {remote_name} not found in .trussrc") + raise ValueError(f"Service provider {remote_name} not found in ~/.trussrc") - return dict(config[remote_name]) + return RemoteConfig(name=remote_name, configs=dict(config[remote_name])) + + @staticmethod + def update_remote_config(remote_config: RemoteConfig): + """ + Load and validate a remote config from the .trussrc file + """ + config = load_config() + config[remote_config.name] = remote_config.configs + update_config(config) @staticmethod def validate_remote_config(remote_config: Dict, remote_name: str): @@ -76,17 +105,17 @@ def required_params(remote: Type[TrussRemote]) -> set: @classmethod def create(cls, remote: str) -> TrussRemote: remote_config = cls.load_remote_config(remote) - cls.validate_remote_config(remote_config, remote) + configs = remote_config.configs + cls.validate_remote_config(configs, remote) - remote_class = cls.REGISTRY[remote_config.pop("remote_provider")] + remote_class = cls.REGISTRY[configs.pop("remote_provider")] remote_params = { - param: remote_config.get(param) - for param in cls.required_params(remote_class) + param: configs.get(param) for param in cls.required_params(remote_class) } # Add any additional params provided by the user in their .trussrc - additional_params = set(remote_config.keys()) - set(remote_params.keys()) + additional_params = set(configs.keys()) - set(remote_params.keys()) for param in additional_params: - remote_params[param] = remote_config.get(param) + remote_params[param] = configs.get(param) return remote_class(**remote_params) # type: ignore diff --git a/truss/remote/truss_remote.py b/truss/remote/truss_remote.py index 5a7f8e479..7ec258b44 100644 --- a/truss/remote/truss_remote.py +++ b/truss/remote/truss_remote.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +from dataclasses import dataclass, field from typing import Dict, Optional import requests @@ -186,3 +187,11 @@ def authenticate(self, **kwargs): **kwargs: Additional keyword arguments for the authentication operation. """ pass + + +@dataclass +class RemoteConfig: + """Class to hold configs for various remotes""" + + name: str + configs: Dict = field(default_factory=dict) diff --git a/truss/tests/remote/test_remote_factory.py b/truss/tests/remote/test_remote_factory.py index f552e0240..bd575b148 100644 --- a/truss/tests/remote/test_remote_factory.py +++ b/truss/tests/remote/test_remote_factory.py @@ -2,7 +2,7 @@ import pytest from truss.remote.remote_factory import RemoteFactory -from truss.remote.truss_remote import TrussRemote +from truss.remote.truss_remote import RemoteConfig, TrussRemote SAMPLE_CONFIG = {"api_key": "test_key", "remote_url": "http://test.com"} @@ -38,11 +38,17 @@ def push(self): def mock_service_config(): - return {"remote_provider": "test_remote", **SAMPLE_CONFIG} + return RemoteConfig( + name="mock-service", + configs={"remote_provider": "test_remote", **SAMPLE_CONFIG}, + ) def mock_incorrect_service_config(): - return {"remote_provider": "nonexistent_remote", **SAMPLE_CONFIG} + return RemoteConfig( + name="mock-incorrect-service", + configs={"remote_provider": "nonexistent_remote", **SAMPLE_CONFIG}, + ) @mock.patch.dict(RemoteFactory.REGISTRY, {"test_remote": TestRemote}, clear=True) @@ -73,7 +79,8 @@ def test_create_no_service(mock_load_remote_config): @mock.patch("pathlib.Path.exists", return_value=True) def test_load_remote_config(mock_exists, mock_open): service = RemoteFactory.load_remote_config("test") - assert service == {"remote_provider": "test_remote", **SAMPLE_CONFIG} + assert service.name == "test" + assert service.configs == {"remote_provider": "test_remote", **SAMPLE_CONFIG} @mock.patch.dict(RemoteFactory.REGISTRY, {"test_remote": TestRemote}, clear=True) @@ -104,9 +111,9 @@ def test_required_params(): ) @mock.patch("pathlib.Path.exists", return_value=True) def test_validate_remote_config_no_remote(mock_exists, mock_open): + service = RemoteFactory.load_remote_config("test") with pytest.raises(ValueError): - service = RemoteFactory.load_remote_config("test") - RemoteFactory.validate_remote_config(service, "test") + RemoteFactory.validate_remote_config(service.configs, "test") @mock.patch.dict(RemoteFactory.REGISTRY, {"test_remote": TestRemote}, clear=True) @@ -115,6 +122,6 @@ def test_validate_remote_config_no_remote(mock_exists, mock_open): ) @mock.patch("pathlib.Path.exists", return_value=True) def test_load_remote_config_no_params(mock_exists, mock_open): + service = RemoteFactory.load_remote_config("test") with pytest.raises(ValueError): - service = RemoteFactory.load_remote_config("test") - RemoteFactory.validate_remote_config(service, "test") + RemoteFactory.validate_remote_config(service.configs, "test")