From 3bf38ef47d85cea51d5dcb5c4e15aaa4c8d21572 Mon Sep 17 00:00:00 2001 From: Marius Killinger <155577904+marius-baseten@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:47:03 -0800 Subject: [PATCH] Clean up deprecated/unused feautres (#1236) --- docs/chains/doc_gen/API-reference.mdx | 20 +-- docs/chains/doc_gen/README.md | 6 +- docs/chains/doc_gen/generate_reference.py | 1 - docs/chains/doc_gen/generated-reference.mdx | 37 +---- docs/chains/doc_gen/reference.patch | 141 +++++++----------- .../audio-transcription/whisper_chainlet.py | 4 +- truss-chains/tests/chains_e2e_test.py | 11 +- truss-chains/tests/itest_chain/itest_chain.py | 26 +--- truss-chains/truss_chains/__init__.py | 2 - truss-chains/truss_chains/code_gen.py | 23 +-- truss-chains/truss_chains/definitions.py | 26 +--- truss-chains/truss_chains/framework.py | 11 +- truss-chains/truss_chains/model_skeleton.py | 16 +- truss-chains/truss_chains/public_api.py | 39 +---- truss-chains/truss_chains/remote.py | 20 +-- truss/cli/cli.py | 71 +-------- 16 files changed, 116 insertions(+), 338 deletions(-) diff --git a/docs/chains/doc_gen/API-reference.mdx b/docs/chains/doc_gen/API-reference.mdx index 0c42beb9d..6ff27670b 100644 --- a/docs/chains/doc_gen/API-reference.mdx +++ b/docs/chains/doc_gen/API-reference.mdx @@ -81,10 +81,8 @@ an access token for downloading model weights). | Name | Type | Description | |-----------------------|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `data_dir` | *Path\|None* | The directory where the chainlet can store and access data, e.g. for downloading model weights. | -| `user_config` | *UserConfigT* | User-defined configuration for the chainlet. | | `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#class-truss-chains-servicedescriptor)]* | A mapping from chainlet names to service descriptors. This is used create RPCs sessions to dependency chainlets. It contains only the chainlet services that are dependencies of the current chainlet. | | `secrets` | *Mapping[str,str]* | A mapping from secret names to secret values. It contains only the secrets that are listed in `remote_config.assets.secret_keys` of the current chainlet. | -| `user_env` | *Mapping[str,str]* | These values can be provided to the deploy command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | | `environment` | *[Environment](#class-truss-chains-definitions-environment)\|None* | The environment that the chainlet is deployed in. None if the chainlet is not associated with an environment. | #### get_baseten_api_key() @@ -216,14 +214,14 @@ modules and keep their requirement files right next their python source files. **Parameters:** -| Name | Type | Description | -|-------------------------|----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `base_image` | *[BasetenImage](#truss-chains-basetenimage)\|[CustomImage](#truss-chains-customimage)* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`). Specification by string is deprecated. | -| `pip_requirements_file` | *AbsPath\|None* | Path to a file containing pip requirements. The file content is naively concatenated with `pip_requirements`. | -| `pip_requirements` | *list[str]* | A list of pip requirements to install. The items are naively concatenated with the content of the `pip_requirements_file`. | -| `apt_requirements` | *list[str]* | A list of apt requirements to install. | -| `data_dir` | *AbsPath\|None* | Data from this directory is copied into the docker image and accessible to the remote chainlet at runtime. | -| `external_package_dirs` | *list[AbsPath]\|None* | A list of directories containing additional python packages outside the chain’s workspace dir, e.g. a shared library. This code is copied into the docker image and importable at runtime. | +| Name | Type | Description | +|-------------------------|----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `base_image` | *[BasetenImage](#truss-chains-basetenimage)\|[CustomImage](#truss-chains-customimage)* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`). | +| `pip_requirements_file` | *AbsPath\|None* | Path to a file containing pip requirements. The file content is naively concatenated with `pip_requirements`. | +| `pip_requirements` | *list[str]* | A list of pip requirements to install. The items are naively concatenated with the content of the `pip_requirements_file`. | +| `apt_requirements` | *list[str]* | A list of apt requirements to install. | +| `data_dir` | *AbsPath\|None* | Data from this directory is copied into the docker image and accessible to the remote chainlet at runtime. | +| `external_package_dirs` | *list[AbsPath]\|None* | A list of directories containing additional python packages outside the chain’s workspace dir, e.g. a shared library. This code is copied into the docker image and importable at runtime. | ### *class* `truss_chains.BasetenImage` @@ -331,7 +329,6 @@ Deploys a chain remotely (with all dependent chainlets). | `chain_name` | *str* | The name of the chain. | | `publish` | *bool* | Whether to publish the chain as a published deployment (it is a draft deployment otherwise) | | `promote` | *bool* | Whether to promote the chain to be the production deployment (this implies publishing as well). | -| `user_env` | *Mapping[str,str]\|None* | These values can be provided to the push command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | | `only_generate_trusses` | *bool* | Used for debugging purposes. If set to True, only the the underlying truss models for the chainlets are generated in `/tmp/.chains_generated`. | | `remote` | *str\|None* | name of a remote config in .trussrc. If not provided, it will be inquired. | | `environment` | *str\|None* | The name of an environment to promote deployment into. | @@ -465,7 +462,6 @@ corresponding fields of | `secrets` | *Mapping[str,str]\|None* | A dict of secrets keys and values to provide to the chainlets. | | `data_dir` | *Path\|str\|None* | Path to a directory with data files. | | `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#class-truss-chains-servicedescriptor)* | A dict of chainlet names to service descriptors. | -| `user_env` | *Mapping[str,str]\|None* | see [`push`](#truss-chains-push). | * **Return type:** *ContextManager*[None] diff --git a/docs/chains/doc_gen/README.md b/docs/chains/doc_gen/README.md index 3c1934787..6b44de55e 100644 --- a/docs/chains/doc_gen/README.md +++ b/docs/chains/doc_gen/README.md @@ -9,9 +9,9 @@ Extra deps required: The general process is: 1. Document as much as possible in the code, including usage examples, links etc. -2. Auto-generate `generated-API-reference.mdx` with `poetry run python - docs/chains/doc_gen/generate_reference.py`. This applies the patch file and - launches meld to resolve conflicts. +2. Auto-generate `generated-API-reference.mdx` with + `poetry run python docs/chains/doc_gen/generate_reference.py`. + This applies the patch file and launches meld to resolve conflicts. 4. Proofread `docs/chains/doc_gen/API-reference.mdx`. 5. If proofreading leads to edits or the upstream docstrings changed lot, update the patch file: `diff -u \ diff --git a/docs/chains/doc_gen/generate_reference.py b/docs/chains/doc_gen/generate_reference.py index 2f09fc5c0..e8b4323d2 100644 --- a/docs/chains/doc_gen/generate_reference.py +++ b/docs/chains/doc_gen/generate_reference.py @@ -69,7 +69,6 @@ "General framework and helper functions.", [ "truss_chains.push", - "truss_chains.deploy_remotely", "truss_chains.remote.ChainService", "truss_chains.make_abs_path_here", "truss_chains.run_local", diff --git a/docs/chains/doc_gen/generated-reference.mdx b/docs/chains/doc_gen/generated-reference.mdx index 911457158..d0a3bb48b 100644 --- a/docs/chains/doc_gen/generated-reference.mdx +++ b/docs/chains/doc_gen/generated-reference.mdx @@ -71,7 +71,7 @@ context instance is provided. ### *class* `truss_chains.DeploymentContext` -Bases: `pydantic.BaseModel`, `Generic`[`UserConfigT`] +Bases: `pydantic.BaseModel` Bundles config values and resources needed to instantiate Chainlets. @@ -85,10 +85,9 @@ an access token for downloading model weights). | Name | Type | Description | |------|------|-------------| | `data_dir` | *Path\|None* | The directory where the chainlet can store and access data, e.g. for downloading model weights. | -| `user_config` | *UserConfigT* | User-defined configuration for the chainlet. | +| `user_config` | ** | User-defined configuration for the chainlet. | | `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#truss_chains.ServiceDescriptor* | A mapping from chainlet names to service descriptors. This is used create RPCs sessions to dependency chainlets. It contains only the chainlet services that are dependencies of the current chainlet. | | `secrets` | *MappingNoIter[str,str]* | A mapping from secret names to secret values. It contains only the secrets that are listed in `remote_config.assets.secret_keys` of the current chainlet. | -| `user_env` | *Mapping[str,str]* | These values can be provided to the deploy command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | | `environment` | *[Environment](#truss_chains.definitions.Environment* | The environment that the chainlet is deployed in. None if the chainlet is not associated with an environment. | #### chainlet_to_service *: Mapping[str, [ServiceDescriptor](#truss_chains.ServiceDescriptor)]* @@ -111,10 +110,6 @@ an access token for downloading model weights). #### secrets *: MappingNoIter[str, str]* -#### user_config *: UserConfigT* - -#### user_env *: Mapping[str, str]* - ### *class* `truss_chains.definitions.Environment` Bases: `pydantic.BaseModel` @@ -256,7 +251,7 @@ modules and keep their requirement files right next their python source files. | Name | Type | Description | |------|------|-------------| -| `base_image` | *[BasetenImage](#truss_chains.BasetenImage* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a Baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`). Specification by string is deprecated. | +| `base_image` | *[BasetenImage](#truss_chains.BasetenImage* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a Baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`).. | | `pip_requirements_file` | *AbsPath\|None* | Path to a file containing pip requirements. The file content is naively concatenated with `pip_requirements`. | | `pip_requirements` | *list[str]* | A list of pip requirements to install. The items are naively concatenated with the content of the `pip_requirements_file`. | | `apt_requirements` | *list[str]* | A list of apt requirements to install. | @@ -265,7 +260,7 @@ modules and keep their requirement files right next their python source files. #### apt_requirements *: list[str]* -#### base_image *: [BasetenImage](#truss_chains.BasetenImage) | [CustomImage](#truss_chains.CustomImage) | str* +#### base_image *: [BasetenImage](#truss_chains.BasetenImage) | [CustomImage](#truss_chains.CustomImage)* #### data_dir *: AbsPath | None* @@ -355,7 +350,7 @@ For example, model weight caching can be used like this: ```default import truss_chains as chains -from truss import truss_config +from truss.base import truss_config mistral_cache = truss_config.ModelRepo( repo_id="mistralai/Mistral-7B-Instruct-v0.2", @@ -406,7 +401,6 @@ Deploys a chain remotely (with all dependent chainlets). | `chain_name` | *str* | The name of the chain. | | `publish` | *bool* | Whether to publish the chain as a published deployment (it is a draft deployment otherwise) | | `promote` | *bool* | Whether to promote the chain to be the production deployment (this implies publishing as well). | -| `user_env` | *Mapping[str,str]\|None* | These values can be provided to the push command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | | `only_generate_trusses` | *bool* | Used for debugging purposes. If set to True, only the the underlying truss models for the chainlets are generated in `/tmp/.chains_generated`. | | `remote` | *str\|None* | name of a remote config in .trussrc. If not provided, it will be inquired. | | `environment` | *str\|None* | The name of an environment to promote deployment into. | @@ -416,26 +410,6 @@ Deploys a chain remotely (with all dependent chainlets). * **Return type:** *BasetenChainService* -### `truss_chains.deploy_remotely` - -Deprecated, use `push` instead. - - -**Parameters:** - -| Name | Type | Description | -|------|------|-------------| -| `entrypoint` | *Type[ABCChainlet]* | | -| `chain_name` | *str* | | -| `publish` | *bool* | | -| `promote` | *bool* | | -| `user_env` | *Mapping[str,str]\|None* | | -| `only_generate_trusses` | *bool* | | -| `remote` | *str\|None* | | - -* **Return type:** - *BasetenChainService* - ### *class* `truss_chains.remote.ChainService` Bases: `ABC` @@ -562,7 +536,6 @@ corresponding fields of `DeploymentContext`. | `secrets` | *Mapping[str,str]\|None* | A dict of secrets keys and values to provide to the chainlets. | | `data_dir` | *Path\|str\|None* | Path to a directory with data files. | | `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#truss_chains.ServiceDescriptor* | A dict of chainlet names to service descriptors. | -| `user_env` | *Mapping[str,str]\|None* | see `deploy_remotely`. | * **Return type:** *ContextManager*[None] diff --git a/docs/chains/doc_gen/reference.patch b/docs/chains/doc_gen/reference.patch index b31761583..ecf741a4f 100644 --- a/docs/chains/doc_gen/reference.patch +++ b/docs/chains/doc_gen/reference.patch @@ -1,5 +1,5 @@ ---- docs/chains/doc_gen/generated-reference.mdx 2024-11-04 11:41:28.619593764 -0800 -+++ docs/chains/doc_gen/API-reference.mdx 2024-11-04 11:53:15.657920649 -0800 +--- docs/chains/doc_gen/generated-reference.mdx 2024-11-07 16:51:32.687418306 -0800 ++++ docs/chains/doc_gen/API-reference.mdx 2024-11-07 16:58:24.661786055 -0800 @@ -24,31 +24,28 @@ dependency of another chainlet. The return value of `depends` is intended to be used as a default argument in a chainlet’s `__init__`-method. @@ -40,7 +40,7 @@ ### `truss_chains.depends_context` -@@ -58,20 +55,19 @@ +@@ -58,16 +55,15 @@ [example chainlet](https://github.com/basetenlabs/truss/blob/main/truss-chains/truss_chains/example_chainlet.py) for more guidance on the `__init__`-signature of chainlets. @@ -59,22 +59,16 @@ ### *class* `truss_chains.DeploymentContext` --Bases: `pydantic.BaseModel`, `Generic`[`UserConfigT`] -+Bases: `pydantic.BaseModel` - - Bundles config values and resources needed to instantiate Chainlets. - -@@ -82,20 +78,14 @@ +@@ -82,19 +78,12 @@ **Parameters:** -| Name | Type | Description | -|------|------|-------------| -| `data_dir` | *Path\|None* | The directory where the chainlet can store and access data, e.g. for downloading model weights. | --| `user_config` | *UserConfigT* | User-defined configuration for the chainlet. | +-| `user_config` | ** | User-defined configuration for the chainlet. | -| `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#truss_chains.ServiceDescriptor* | A mapping from chainlet names to service descriptors. This is used create RPCs sessions to dependency chainlets. It contains only the chainlet services that are dependencies of the current chainlet. | -| `secrets` | *MappingNoIter[str,str]* | A mapping from secret names to secret values. It contains only the secrets that are listed in `remote_config.assets.secret_keys` of the current chainlet. | --| `user_env` | *Mapping[str,str]* | These values can be provided to the deploy command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | -| `environment` | *[Environment](#truss_chains.definitions.Environment* | The environment that the chainlet is deployed in. None if the chainlet is not associated with an environment. | - -#### chainlet_to_service *: Mapping[str, [ServiceDescriptor](#truss_chains.ServiceDescriptor)]* @@ -85,15 +79,13 @@ +| Name | Type | Description | +|-----------------------|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `data_dir` | *Path\|None* | The directory where the chainlet can store and access data, e.g. for downloading model weights. | -+| `user_config` | *UserConfigT* | User-defined configuration for the chainlet. | +| `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#class-truss-chains-servicedescriptor)]* | A mapping from chainlet names to service descriptors. This is used create RPCs sessions to dependency chainlets. It contains only the chainlet services that are dependencies of the current chainlet. | +| `secrets` | *Mapping[str,str]* | A mapping from secret names to secret values. It contains only the secrets that are listed in `remote_config.assets.secret_keys` of the current chainlet. | -+| `user_env` | *Mapping[str,str]* | These values can be provided to the deploy command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | +| `environment` | *[Environment](#class-truss-chains-definitions-environment)\|None* | The environment that the chainlet is deployed in. None if the chainlet is not associated with an environment. | #### get_baseten_api_key() -@@ -104,16 +94,14 @@ +@@ -103,12 +92,14 @@ #### get_service_descriptor(chainlet_name) @@ -101,22 +93,19 @@ - **chainlet_name** (*str*) -* **Return type:** - [*ServiceDescriptor*](#truss_chains.ServiceDescriptor) -- --#### secrets *: MappingNoIter[str, str]* +**Parameters:** --#### user_config *: UserConfigT* +-#### secrets *: MappingNoIter[str, str]* +| Name | Type | Description | +|-----------------|-------|---------------------------| +| `chainlet_name` | *str* | The name of the chainlet. | - --#### user_env *: Mapping[str, str]* ++ +* **Return type:** + [*ServiceDescriptor*](#class-truss-chains-servicedescriptor) ### *class* `truss_chains.definitions.Environment` -@@ -123,7 +111,6 @@ +@@ -118,7 +109,6 @@ * **Parameters:** **name** (*str*) – The name of the environment. @@ -124,7 +113,7 @@ ### *class* `truss_chains.ChainletOptions` -@@ -132,14 +119,10 @@ +@@ -127,14 +117,10 @@ **Parameters:** @@ -143,7 +132,7 @@ ### *class* `truss_chains.RPCOptions` -@@ -149,15 +132,10 @@ +@@ -144,15 +130,10 @@ **Parameters:** @@ -163,7 +152,7 @@ ### `truss_chains.mark_entrypoint` -@@ -169,18 +147,23 @@ +@@ -164,18 +145,23 @@ Example usage: @@ -191,7 +180,7 @@ # Remote Configuration -@@ -194,7 +177,7 @@ +@@ -189,7 +175,7 @@ This is specified as a class variable for each chainlet class, e.g.: @@ -200,7 +189,7 @@ import truss_chains as chains -@@ -210,34 +193,13 @@ +@@ -205,34 +191,13 @@ **Parameters:** @@ -242,7 +231,7 @@ ### *class* `truss_chains.DockerImage` -@@ -245,35 +207,23 @@ +@@ -240,35 +205,23 @@ Configures the docker image in which a remoted chainlet is deployed. @@ -260,7 +249,7 @@ -| Name | Type | Description | -|------|------|-------------| --| `base_image` | *[BasetenImage](#truss_chains.BasetenImage* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a Baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`). Specification by string is deprecated. | +-| `base_image` | *[BasetenImage](#truss_chains.BasetenImage* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a Baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`).. | -| `pip_requirements_file` | *AbsPath\|None* | Path to a file containing pip requirements. The file content is naively concatenated with `pip_requirements`. | -| `pip_requirements` | *list[str]* | A list of pip requirements to install. The items are naively concatenated with the content of the `pip_requirements_file`. | -| `apt_requirements` | *list[str]* | A list of apt requirements to install. | @@ -269,7 +258,7 @@ - -#### apt_requirements *: list[str]* - --#### base_image *: [BasetenImage](#truss_chains.BasetenImage) | [CustomImage](#truss_chains.CustomImage) | str* +-#### base_image *: [BasetenImage](#truss_chains.BasetenImage) | [CustomImage](#truss_chains.CustomImage)* - -#### data_dir *: AbsPath | None* - @@ -278,35 +267,35 @@ -#### pip_requirements *: list[str]* - -#### pip_requirements_file *: AbsPath | None* -+| Name | Type | Description | -+|-------------------------|----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -+| `base_image` | *[BasetenImage](#truss-chains-basetenimage)\|[CustomImage](#truss-chains-customimage)* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`). Specification by string is deprecated. | -+| `pip_requirements_file` | *AbsPath\|None* | Path to a file containing pip requirements. The file content is naively concatenated with `pip_requirements`. | -+| `pip_requirements` | *list[str]* | A list of pip requirements to install. The items are naively concatenated with the content of the `pip_requirements_file`. | -+| `apt_requirements` | *list[str]* | A list of apt requirements to install. | -+| `data_dir` | *AbsPath\|None* | Data from this directory is copied into the docker image and accessible to the remote chainlet at runtime. | -+| `external_package_dirs` | *list[AbsPath]\|None* | A list of directories containing additional python packages outside the chain’s workspace dir, e.g. a shared library. This code is copied into the docker image and importable at runtime. | ++| Name | Type | Description | ++|-------------------------|----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ++| `base_image` | *[BasetenImage](#truss-chains-basetenimage)\|[CustomImage](#truss-chains-customimage)* | The base image used by the chainlet. Other dependencies and assets are included as additional layers on top of that image. You can choose a baseten default image for a supported python version (e.g. `BasetenImage.PY311`), this will also include GPU drivers if needed, or provide a custom image (e.g. `CustomImage(image="python:3.11-slim")`). | ++| `pip_requirements_file` | *AbsPath\|None* | Path to a file containing pip requirements. The file content is naively concatenated with `pip_requirements`. | ++| `pip_requirements` | *list[str]* | A list of pip requirements to install. The items are naively concatenated with the content of the `pip_requirements_file`. | ++| `apt_requirements` | *list[str]* | A list of apt requirements to install. | ++| `data_dir` | *AbsPath\|None* | Data from this directory is copied into the docker image and accessible to the remote chainlet at runtime. | ++| `external_package_dirs` | *list[AbsPath]\|None* | A list of directories containing additional python packages outside the chain’s workspace dir, e.g. a shared library. This code is copied into the docker image and importable at runtime. | ### *class* `truss_chains.BasetenImage` -@@ -282,11 +232,12 @@ +@@ -277,11 +230,12 @@ Default images, curated by baseten, for different python versions. If a Chainlet uses GPUs, drivers will be included in the image. -#### PY310 *= 'py310'* +- +-#### PY311 *= 'py311'* +| Enum Member | Value | +|-------------|---------| +| `PY310` | *py310* | +| `PY311 ` | *py311* | +| `PY39` | *py39* | --#### PY311 *= 'py311'* -- -#### PY39 *= 'py39'* ### *class* `truss_chains.CustomImage` -@@ -296,42 +247,35 @@ +@@ -291,42 +245,35 @@ **Parameters:** @@ -365,7 +354,7 @@ It is important to understand the difference between predict_concurrency and the concurrency target (used for autoscaling, i.e. adding or removing replicas). Furthermore, the `predict_concurrency` of a single instance is implemented in -@@ -342,18 +286,13 @@ +@@ -337,52 +284,33 @@ - With a threadpool if it’s a synchronous function. This requires that the threads don’t have significant CPU load (due to the GIL). @@ -383,9 +372,16 @@ -```default +```python import truss_chains as chains - from truss import truss_config + from truss.base import truss_config + + mistral_cache = truss_config.ModelRepo( + repo_id="mistralai/Mistral-7B-Instruct-v0.2", + allow_patterns=["*.json", "*.safetensors", ".model"] +- ) ++) + chains.Assets(cached=[mistral_cache], ...) + ``` -@@ -367,27 +306,13 @@ See [truss caching guide](https://docs.baseten.co/deploy/guides/model-cache#enabling-caching-for-a-model) for more details on caching. @@ -418,7 +414,7 @@ # Core -@@ -400,75 +325,41 @@ +@@ -395,24 +323,26 @@ **Parameters:** @@ -428,7 +424,6 @@ -| `chain_name` | *str* | The name of the chain. | -| `publish` | *bool* | Whether to publish the chain as a published deployment (it is a draft deployment otherwise) | -| `promote` | *bool* | Whether to promote the chain to be the production deployment (this implies publishing as well). | --| `user_env` | *Mapping[str,str]\|None* | These values can be provided to the push command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | -| `only_generate_trusses` | *bool* | Used for debugging purposes. If set to True, only the the underlying truss models for the chainlets are generated in `/tmp/.chains_generated`. | -| `remote` | *str\|None* | name of a remote config in .trussrc. If not provided, it will be inquired. | -| `environment` | *str\|None* | The name of an environment to promote deployment into. | @@ -438,7 +433,6 @@ +| `chain_name` | *str* | The name of the chain. | +| `publish` | *bool* | Whether to publish the chain as a published deployment (it is a draft deployment otherwise) | +| `promote` | *bool* | Whether to promote the chain to be the production deployment (this implies publishing as well). | -+| `user_env` | *Mapping[str,str]\|None* | These values can be provided to the push command and customize the behavior of deployed chainlets. E.g. for differentiating between prod and dev version of the same chain. | +| `only_generate_trusses` | *bool* | Used for debugging purposes. If set to True, only the the underlying truss models for the chainlets are generated in `/tmp/.chains_generated`. | +| `remote` | *str\|None* | name of a remote config in .trussrc. If not provided, it will be inquired. | +| `environment` | *str\|None* | The name of an environment to promote deployment into. | @@ -449,34 +443,17 @@ - *BasetenChainService* + [*ChainService*](#class-truss-chains-remote-chainservice) - ### `truss_chains.deploy_remotely` - --Deprecated, use `push` instead. -- -- --**Parameters:** -- --| Name | Type | Description | --|------|------|-------------| --| `entrypoint` | *Type[ABCChainlet]* | | --| `chain_name` | *str* | | --| `publish` | *bool* | | --| `promote` | *bool* | | --| `user_env` | *Mapping[str,str]\|None* | | --| `only_generate_trusses` | *bool* | | --| `remote` | *str\|None* | | -- --* **Return type:** -- *BasetenChainService* +-### *class* `truss_chains.remote.ChainService` ++### `truss_chains.deploy_remotely` ++ +Deprecated, use [`push`](#truss-chains-push) instead. - ### *class* `truss_chains.remote.ChainService` - -Bases: `ABC` -- ++### *class* `truss_chains.remote.ChainService` + Handle for a deployed chain. - A `ChainService` is created and returned when using `push`. It +@@ -420,29 +350,13 @@ bundles the individual services for each chainlet in the chain, and provides utilities to query their status, invoke the entrypoint etc. @@ -509,7 +486,7 @@ * **Return type:** list[*DeployedChainlet*] -@@ -478,18 +369,23 @@ +@@ -452,18 +366,23 @@ Invokes the entrypoint with JSON data. @@ -537,7 +514,7 @@ Link to status page on Baseten. -@@ -511,12 +407,12 @@ +@@ -485,12 +404,12 @@ You can now in `root/sub_package/chainlet.py` point to the requirements file like this: @@ -552,7 +529,7 @@ This helper uses the directory of the immediately calling module as an absolute reference point for resolving the file location. Therefore, you MUST NOT wrap the instantiation of `make_abs_path_here` into a -@@ -524,7 +420,7 @@ +@@ -498,7 +417,7 @@ Ok: @@ -561,7 +538,7 @@ def foo(path: AbsPath): abs_path = path.abs_path -@@ -534,7 +430,7 @@ +@@ -508,7 +427,7 @@ Not Ok: @@ -570,7 +547,7 @@ def foo(path: str): dangerous_value = make_abs_path_here(path).abs_path -@@ -542,8 +438,15 @@ +@@ -516,8 +435,15 @@ foo("./somewhere") ``` @@ -588,7 +565,7 @@ * **Return type:** *AbsPath* -@@ -552,24 +455,24 @@ +@@ -526,23 +452,23 @@ Context manager local debug execution of a chain. The arguments only need to be provided if the chainlets explicitly access any the @@ -604,13 +581,11 @@ -| `secrets` | *Mapping[str,str]\|None* | A dict of secrets keys and values to provide to the chainlets. | -| `data_dir` | *Path\|str\|None* | Path to a directory with data files. | -| `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#truss_chains.ServiceDescriptor* | A dict of chainlet names to service descriptors. | --| `user_env` | *Mapping[str,str]\|None* | see `deploy_remotely`. | +| Name | Type | Description | +|-----------------------|--------------------------------------------------------------------------|----------------------------------------------------------------| +| `secrets` | *Mapping[str,str]\|None* | A dict of secrets keys and values to provide to the chainlets. | +| `data_dir` | *Path\|str\|None* | Path to a directory with data files. | +| `chainlet_to_service` | *Mapping[str,[ServiceDescriptor](#class-truss-chains-servicedescriptor)* | A dict of chainlet names to service descriptors. | -+| `user_env` | *Mapping[str,str]\|None* | see [`push`](#truss-chains-push). | * **Return type:** *ContextManager*[None] @@ -622,7 +597,7 @@ import os import truss_chains as chains -@@ -595,7 +498,8 @@ +@@ -568,7 +494,8 @@ print(result) ``` @@ -632,7 +607,7 @@ for more details. ### *class* `truss_chains.ServiceDescriptor` -@@ -607,22 +511,13 @@ +@@ -580,22 +507,13 @@ **Parameters:** @@ -661,7 +636,7 @@ Base class for stubs that invoke remote chainlets. -@@ -630,17 +525,18 @@ +@@ -603,17 +521,18 @@ in user-code for wrapping a deployed truss model into the chains framework, e.g. like that: @@ -682,7 +657,7 @@ resp = await self._remote.predict_async( json_payload={"audio": audio_b64}) return WhisperOutput(text=resp["text"], language=resp["language"]) -@@ -657,28 +553,24 @@ +@@ -630,28 +549,24 @@ ) ``` @@ -720,7 +695,7 @@ ### *class* `truss_chains.RemoteErrorDetail` -@@ -690,20 +582,13 @@ +@@ -663,20 +578,13 @@ **Parameters:** @@ -748,7 +723,7 @@ #### format() -@@ -712,7 +597,3 @@ +@@ -685,7 +593,3 @@ * **Return type:** str diff --git a/truss-chains/examples/audio-transcription/whisper_chainlet.py b/truss-chains/examples/audio-transcription/whisper_chainlet.py index 7fff4da52..65823190d 100644 --- a/truss-chains/examples/audio-transcription/whisper_chainlet.py +++ b/truss-chains/examples/audio-transcription/whisper_chainlet.py @@ -18,7 +18,9 @@ def base64_to_wav(base64_string, output_file_path): class WhisperModel(chains.ChainletBase): remote_config = chains.RemoteConfig( docker_image=chains.DockerImage( - base_image="baseten/truss-server-base:3.10-gpu-v0.9.0", + base_image=chains.CustomImage( + image="baseten/truss-server-base:3.10-gpu-v0.9.0" + ), apt_requirements=[ "ffmpeg", ], diff --git a/truss-chains/tests/chains_e2e_test.py b/truss-chains/tests/chains_e2e_test.py index 9e403a91b..f10d90cbe 100644 --- a/truss-chains/tests/chains_e2e_test.py +++ b/truss-chains/tests/chains_e2e_test.py @@ -16,10 +16,7 @@ def test_chain(): root = Path(__file__).parent.resolve() chain_root = root / "itest_chain" / "itest_chain.py" with framework.import_target(chain_root, "ItestChain") as entrypoint: - options = definitions.PushOptionsLocalDocker( - chain_name="integration-test", - user_env={"test_env_key": "test_env_value"}, - ) + options = definitions.PushOptionsLocalDocker(chain_name="integration-test") service = remote.push(entrypoint, options) url = service.run_remote_url.replace("host.docker.internal", "localhost") @@ -41,7 +38,6 @@ def test_chain(): "part_lens": [10], }, ["a", "b"], - "test_env_value", ] # Call with values for default arguments. response = requests.post( @@ -67,7 +63,6 @@ def test_chain(): "part_lens": [3], }, ["bola"], - "test_env_value", ] # Test with errors. @@ -87,7 +82,7 @@ async def test_chain_local(): root = Path(__file__).parent.resolve() chain_root = root / "itest_chain" / "itest_chain.py" with framework.import_target(chain_root, "ItestChain") as entrypoint: - with public_api.run_local(user_env={"test_env_key": "test_env_value"}): + with public_api.run_local(): with pytest.raises(ValueError): # First time `SplitTextFailOnce` raises an error and # currently local mode does not have retries. @@ -104,7 +99,6 @@ async def test_chain_local(): "part_lens": [10], }, ["a", "b"], - "test_env_value", ) # Convert the pydantic model to a dict for comparison @@ -114,7 +108,6 @@ async def test_chain_local(): result[2], result[3].dict(), result[4], - result[5], ) assert result_dict == expected diff --git a/truss-chains/tests/itest_chain/itest_chain.py b/truss-chains/tests/itest_chain/itest_chain.py index 2d565b4c6..5881ad4f3 100644 --- a/truss-chains/tests/itest_chain/itest_chain.py +++ b/truss-chains/tests/itest_chain/itest_chain.py @@ -1,6 +1,5 @@ import math -import pydantic from user_package import shared_chainlet from user_package.nested_package import io_types @@ -20,11 +19,6 @@ pip_requirements_file=chains.make_abs_path_here("requirements.txt"), ) -IMAGE_STR = chains.DockerImage( - base_image="python:3.11-slim", - pip_requirements_file=chains.make_abs_path_here("requirements.txt"), -) - class GenerateData(chains.ChainletBase): remote_config = chains.RemoteConfig( @@ -37,31 +31,24 @@ def run_remote(self, length: int) -> str: return (template * repetitions)[:length] -class DummyUserConfig(pydantic.BaseModel): - multiplier: int - - class TextReplicator(chains.ChainletBase): remote_config = chains.RemoteConfig(docker_image=IMAGE_CUSTOM) - default_user_config = DummyUserConfig(multiplier=2) def __init__(self, context=chains.depends_context()): - self.user_config = context.user_config + self.multiplier = 2 def run_remote(self, data: str) -> str: if len(data) > 30: raise ValueError(f"This input is too long: {len(data)}.") - return data * self.user_config.multiplier + return data * self.multiplier class SideEffectBase(chains.ChainletBase): - default_user_config = DummyUserConfig(multiplier=2) - def __init__(self, context=chains.depends_context()): - self.user_config = context.user_config + self.ctx = context def run_remote(self) -> None: - print(f"I'm have no input and no outputs, I just print: {self.user_config}") + print("I'm have no input and no outputs, I just print.") class SideEffectOnlySubclass(SideEffectBase): @@ -75,7 +62,7 @@ def run_remote(self) -> None: class TextToNum(chains.ChainletBase): - remote_config = chains.RemoteConfig(docker_image=IMAGE_STR) + remote_config = chains.RemoteConfig(docker_image=IMAGE_BASETEN) def __init__( self, @@ -119,7 +106,7 @@ async def run_remote( parts=[], part_lens=[10] ), simple_default_arg: list[str] = ["a", "b"], - ) -> tuple[int, str, int, shared_chainlet.SplitTextOutput, list[str], str]: + ) -> tuple[int, str, int, shared_chainlet.SplitTextOutput, list[str]]: data = self._data_generator.run_remote(length) text_parts, number = await self._data_splitter.run_remote( io_types.SplitTextInput( @@ -139,5 +126,4 @@ async def run_remote( number, pydantic_default_arg, simple_default_arg, - self._context.user_env["test_env_key"], ) diff --git a/truss-chains/truss_chains/__init__.py b/truss-chains/truss_chains/__init__.py index 69c1493c8..a9dd61551 100644 --- a/truss-chains/truss_chains/__init__.py +++ b/truss-chains/truss_chains/__init__.py @@ -36,7 +36,6 @@ ChainletBase, depends, depends_context, - deploy_remotely, # Alias for backwards compat. mark_entrypoint, push, run_local, @@ -60,7 +59,6 @@ "StubBase", "depends", "depends_context", - "deploy_remotely", "make_abs_path_here", "mark_entrypoint", "push", diff --git a/truss-chains/truss_chains/code_gen.py b/truss-chains/truss_chains/code_gen.py index 37e12c701..8107a2573 100644 --- a/truss-chains/truss_chains/code_gen.py +++ b/truss-chains/truss_chains/code_gen.py @@ -476,14 +476,7 @@ def _gen_truss_chainlet_model( _SpecifyChainletTypeAnnotation(user_chainlet_ref.src) ) model_class_src = libcst.Module(body=[class_definition]).code - - if utils.issubclass_safe(chainlet_descriptor.user_config_type.raw, type(None)): - userconfig_pin = "UserConfigT = type(None)" - else: - user_config_ref = _gen_type_import_and_ref(chainlet_descriptor.user_config_type) - imports.update(user_config_ref.imports) - userconfig_pin = f"UserConfigT = {user_config_ref.src}" - return _Source(src=f"{userconfig_pin}\n\n{model_class_src}", imports=imports) + return _Source(src=model_class_src, imports=imports) def _gen_truss_chainlet_file( @@ -559,18 +552,17 @@ def _inplace_fill_base_image( mutable_truss_config.base_image.python_executable_path = ( image.base_image.python_executable_path ) - elif isinstance(image.base_image, str): # This options is deprecated. - mutable_truss_config.base_image = truss_config.BaseImage(image=image.base_image) + raise NotImplementedError( + "Specifying docker base image as string is deprecated" + ) def _make_truss_config( chainlet_dir: pathlib.Path, chains_config: definitions.RemoteConfig, - user_config: definitions.UserConfigT, chainlet_to_service: Mapping[str, definitions.ServiceDescriptor], model_name: str, - user_env: Mapping[str, str], ) -> truss_config.TrussConfig: """Generate a truss config for a Chainlet.""" config = truss_config.TrussConfig() @@ -614,9 +606,7 @@ def _make_truss_config( config.external_data = truss_config.ExternalData(items=assets.external_data) # Metadata. chains_metadata: definitions.TrussMetadata = definitions.TrussMetadata( - user_config=user_config, - chainlet_to_service=chainlet_to_service, - user_env=user_env, + chainlet_to_service=chainlet_to_service ) config.model_metadata[definitions.TRUSS_CONFIG_CHAINS_KEY] = ( chains_metadata.model_dump() @@ -634,7 +624,6 @@ def gen_truss_chainlet( chainlet_descriptor: definitions.ChainletAPIDescriptor, model_name: str, chainlet_display_name_to_url: Mapping[str, str], - user_env: Mapping[str, str], ) -> pathlib.Path: # Filter needed services and customize options. dep_services = {} @@ -650,10 +639,8 @@ def gen_truss_chainlet( _make_truss_config( chainlet_dir, chainlet_descriptor.chainlet_cls.remote_config, - chainlet_descriptor.chainlet_cls.default_user_config, dep_services, model_name, - user_env, ) # TODO This assumes all imports are absolute w.r.t chain root (or site-packages). truss_path.copy_tree_path( diff --git a/truss-chains/truss_chains/definitions.py b/truss-chains/truss_chains/definitions.py index 6a2e1b5a6..04d08ed86 100644 --- a/truss-chains/truss_chains/definitions.py +++ b/truss-chains/truss_chains/definitions.py @@ -28,8 +28,6 @@ from truss.remote import baseten as baseten_remote from truss.remote import remote_cli, remote_factory -UserConfigT = TypeVar("UserConfigT", bound=Union[pydantic.BaseModel, None]) - BASETEN_API_SECRET_NAME = "baseten_chain_api_key" SECRET_DUMMY = "***" TRUSS_CONFIG_CHAINS_KEY = "chains_metadata" @@ -173,8 +171,7 @@ class DockerImage(SafeModelNonSerializable): assets are included as additional layers on top of that image. You can choose a Baseten default image for a supported python version (e.g. ``BasetenImage.PY311``), this will also include GPU drivers if needed, or - provide a custom image (e.g. ``CustomImage(image="python:3.11-slim")``). - Specification by string is deprecated. + provide a custom image (e.g. ``CustomImage(image="python:3.11-slim")``).. pip_requirements_file: Path to a file containing pip requirements. The file content is naively concatenated with ``pip_requirements``. pip_requirements: A list of pip requirements to install. The items are @@ -188,8 +185,7 @@ class DockerImage(SafeModelNonSerializable): """ # TODO: this is not stable yet and might change or refer back to truss. - # Image as str is deprecated. - base_image: Union[BasetenImage, CustomImage, str] = BasetenImage.PY311 + base_image: Union[BasetenImage, CustomImage] = BasetenImage.PY311 pip_requirements_file: Optional[AbsPath] = None pip_requirements: list[str] = [] apt_requirements: list[str] = [] @@ -301,7 +297,7 @@ class Assets: mistral_cache = truss_config.ModelRepo( repo_id="mistralai/Mistral-7B-Instruct-v0.2", allow_patterns=["*.json", "*.safetensors", ".model"] - ) + ) chains.Assets(cached=[mistral_cache], ...) See `truss caching guide `_ @@ -416,7 +412,7 @@ class Environment(SafeModel): # can add more fields here as we add them to dynamic_config configmap -class DeploymentContext(SafeModelNonSerializable, Generic[UserConfigT]): +class DeploymentContext(SafeModelNonSerializable): """Bundles config values and resources needed to instantiate Chainlets. The context can optionally added as a trailing argument in a Chainlet's @@ -433,18 +429,13 @@ class DeploymentContext(SafeModelNonSerializable, Generic[UserConfigT]): secrets: A mapping from secret names to secret values. It contains only the secrets that are listed in ``remote_config.assets.secret_keys`` of the current chainlet. - user_env: These values can be provided to - the deploy command and customize the behavior of deployed chainlets. E.g. - for differentiating between prod and dev version of the same chain. environment: The environment that the chainlet is deployed in. None if the chainlet is not associated with an environment. """ data_dir: Optional[pathlib.Path] = None - user_config: UserConfigT chainlet_to_service: Mapping[str, ServiceDescriptor] secrets: MappingNoIter[str, str] - user_env: Mapping[str, str] environment: Optional[Environment] = None def get_service_descriptor(self, chainlet_name: str) -> ServiceDescriptor: @@ -474,17 +465,14 @@ def get_baseten_api_key(self) -> str: return api_key -class TrussMetadata(SafeModel, Generic[UserConfigT]): +class TrussMetadata(SafeModel): """Plugin for the truss config (in config["model_metadata"]["chains_metadata"]).""" - user_config: UserConfigT chainlet_to_service: Mapping[str, ServiceDescriptor] - user_env: Mapping[str, str] class ABCChainlet(abc.ABC): remote_config: ClassVar[RemoteConfig] = RemoteConfig(docker_image=DockerImage()) - default_user_config: ClassVar[Optional[pydantic.BaseModel]] = None _init_is_patched: ClassVar[bool] = False @classmethod @@ -555,7 +543,6 @@ class ChainletAPIDescriptor(SafeModelNonSerializable): has_context: bool dependencies: Mapping[str, DependencyDescriptor] endpoint: EndpointAPIDescriptor - user_config_type: TypeDescriptor def __hash__(self) -> int: return hash(self.chainlet_cls) @@ -632,7 +619,6 @@ class GenericRemoteException(Exception): ... class PushOptions(SafeModelNonSerializable): chain_name: str - user_env: Mapping[str, str] only_generate_trusses: bool = False @@ -648,7 +634,6 @@ def create( publish: bool, promote: Optional[bool], only_generate_trusses: bool, - user_env: Mapping[str, str], remote: Optional[str] = None, environment: Optional[str] = None, ) -> "PushOptionsBaseten": @@ -669,7 +654,6 @@ def create( chain_name=chain_name, publish=publish, only_generate_trusses=only_generate_trusses, - user_env=user_env, environment=environment, ) diff --git a/truss-chains/truss_chains/framework.py b/truss-chains/truss_chains/framework.py index 58f19d98e..9e24366ae 100644 --- a/truss-chains/truss_chains/framework.py +++ b/truss-chains/truss_chains/framework.py @@ -522,12 +522,11 @@ def __init__( [dep_1: dep_1_type = truss_chains.depends(dep_1_class),] ... [dep_N: dep_N_type = truss_chains.provides(dep_N_class),] - [context: truss_chains.Context[UserConfig] = truss_chains.provide_context()] + [context: truss_chains.Context = truss_chains.depends_context()] ) -> None: ``` * The context argument is optionally trailing and must have a default constructed - with the `provide_context` directive. The type can be templated by a user - defined config e.g. `truss_chains.Context[UserConfig]`. + with the `provide_context` directive. * The names and number of Chainlet "dependency" arguments are arbitrary. * Default values for dependencies must be constructed with the `depends` directive to make the dependency injection work. The argument to `depends` must be a @@ -695,7 +694,6 @@ def validate_and_register_class(cls: Type[definitions.ABCChainlet]) -> None: has_context=init_validator.has_context, endpoint=_validate_and_describe_endpoint(cls, location), src_path=src_path, - user_config_type=definitions.TypeDescriptor(raw=type(cls.default_user_config)), ) logging.debug( f"Descriptor for {cls}:\n{pprint.pformat(chainlet_descriptor, indent=4)}\n" @@ -843,7 +841,6 @@ def _create_modified_init_for_local( secrets: Mapping[str, str], data_dir: Optional[pathlib.Path], chainlet_to_service: Mapping[str, definitions.ServiceDescriptor], - user_env: Mapping[str, str], ): """Replaces the default argument values with local Chainlet instantiations. @@ -974,11 +971,9 @@ def __init_local__(self: definitions.ABCChainlet, **kwargs) -> None: and definitions.CONTEXT_ARG_NAME not in kwargs_mod ): kwargs_mod[definitions.CONTEXT_ARG_NAME] = definitions.DeploymentContext( - user_config=chainlet_descriptor.chainlet_cls.default_user_config, secrets=secrets, data_dir=data_dir, chainlet_to_service=chainlet_to_service, - user_env=user_env, ) for arg_name, dep in chainlet_descriptor.dependencies.items(): chainlet_cls = dep.chainlet_cls @@ -1017,7 +1012,6 @@ def run_local( secrets: Mapping[str, str], data_dir: Optional[pathlib.Path], chainlet_to_service: Mapping[str, definitions.ServiceDescriptor], - user_env: Mapping[str, str], ) -> Any: """Context to run Chainlets with dependency injection from local instances.""" # TODO: support retries in local mode. @@ -1040,7 +1034,6 @@ def run_local( secrets, data_dir, chainlet_to_service, - user_env, ) chainlet_descriptor.chainlet_cls.__init__ = init_for_local # type: ignore[method-assign] chainlet_descriptor.chainlet_cls._init_is_patched = True diff --git a/truss-chains/truss_chains/model_skeleton.py b/truss-chains/truss_chains/model_skeleton.py index cd97ba161..2173b5fed 100644 --- a/truss-chains/truss_chains/model_skeleton.py +++ b/truss-chains/truss_chains/model_skeleton.py @@ -1,18 +1,14 @@ import pathlib from typing import Optional -import pydantic from truss.templates.shared import secrets_resolver from truss_chains import definitions from truss_chains.utils import override_chainlet_to_service_metadata -# Better: in >=3.10 use `TypeAlias`. -UserConfigT = pydantic.BaseModel - class TrussChainletModel: - _context: definitions.DeploymentContext[UserConfigT] + _context: definitions.DeploymentContext _chainlet: definitions.ABCChainlet def __init__( @@ -24,10 +20,8 @@ def __init__( dict ] = None, # TODO: Remove the default value once all truss versions are synced up. ) -> None: - truss_metadata: definitions.TrussMetadata[UserConfigT] = ( - definitions.TrussMetadata[ - UserConfigT - ].model_validate( + truss_metadata: definitions.TrussMetadata = ( + definitions.TrussMetadata.model_validate( config["model_metadata"][definitions.TRUSS_CONFIG_CHAINS_KEY] ) ) @@ -36,12 +30,10 @@ def __init__( ) override_chainlet_to_service_metadata(truss_metadata.chainlet_to_service) - self._context = definitions.DeploymentContext[UserConfigT]( - user_config=truss_metadata.user_config, + self._context = definitions.DeploymentContext( chainlet_to_service=truss_metadata.chainlet_to_service, secrets=secrets, data_dir=data_dir, - user_env=truss_metadata.user_env, environment=deployment_environment, ) diff --git a/truss-chains/truss_chains/public_api.py b/truss-chains/truss_chains/public_api.py index d8817decb..aab38f798 100644 --- a/truss-chains/truss_chains/public_api.py +++ b/truss-chains/truss_chains/public_api.py @@ -1,6 +1,5 @@ import functools import pathlib -import warnings from typing import ContextManager, Mapping, Optional, Type, Union from truss_chains import definitions, framework @@ -122,7 +121,6 @@ def push( chain_name: str, publish: bool = True, promote: bool = True, - user_env: Optional[Mapping[str, str]] = None, only_generate_trusses: bool = False, remote: Optional[str] = None, environment: Optional[str] = None, @@ -137,9 +135,6 @@ def push( draft deployment otherwise) promote: Whether to promote the chain to be the production deployment (this implies publishing as well). - user_env: These values can be provided to - the push command and customize the behavior of deployed chainlets. E.g. - for differentiating between prod and dev version of the same chain. only_generate_trusses: Used for debugging purposes. If set to True, only the the underlying truss models for the chainlets are generated in ``/tmp/.chains_generated``. @@ -155,7 +150,6 @@ def push( chain_name=chain_name, publish=publish, promote=promote, - user_env=user_env or {}, only_generate_trusses=only_generate_trusses, remote=remote, environment=environment, @@ -165,38 +159,10 @@ def push( return service -def deploy_remotely( - entrypoint: Type[definitions.ABCChainlet], - chain_name: str, - publish: bool = True, - promote: bool = True, - user_env: Optional[Mapping[str, str]] = None, - only_generate_trusses: bool = False, - remote: Optional[str] = None, -) -> chains_remote.BasetenChainService: - """Deprecated, use ``push`` instead.""" - warnings.warn( - "Chains `deploy_remotely()` is deprecated and will be removed in a " - "future version. Please use `push()` instead.", - DeprecationWarning, - stacklevel=2, - ) - return push( - entrypoint, - chain_name, - publish, - promote, - user_env, - only_generate_trusses, - remote, - ) - - def run_local( secrets: Optional[Mapping[str, str]] = None, data_dir: Optional[Union[pathlib.Path, str]] = None, chainlet_to_service: Optional[Mapping[str, definitions.ServiceDescriptor]] = None, - user_env: Optional[Mapping[str, str]] = None, ) -> ContextManager[None]: """Context manager local debug execution of a chain. @@ -207,7 +173,6 @@ def run_local( secrets: A dict of secrets keys and values to provide to the chainlets. data_dir: Path to a directory with data files. chainlet_to_service: A dict of chainlet names to service descriptors. - user_env: see ``deploy_remotely``. Example usage (as trailing main section in a chain file):: @@ -240,6 +205,4 @@ class HelloWorld(chains.ChainletBase): for more details. """ data_dir = pathlib.Path(data_dir) if data_dir else None - return framework.run_local( - secrets or {}, data_dir, chainlet_to_service or {}, user_env or {} - ) + return framework.run_local(secrets or {}, data_dir, chainlet_to_service or {}) diff --git a/truss-chains/truss_chains/remote.py b/truss-chains/truss_chains/remote.py index e7a7abcc8..564376f4e 100644 --- a/truss-chains/truss_chains/remote.py +++ b/truss-chains/truss_chains/remote.py @@ -392,7 +392,6 @@ def push( chainlet_descriptor, model_name, chainlet_display_name_to_url, - self._options.user_env, ) if self._options.only_generate_trusses: chainlet_display_name_to_url[chainlet_descriptor.display_name] = ( @@ -547,7 +546,7 @@ def _assert_chainlet_names_same(self, new_names: set[str]) -> None: raise definitions.ChainsDeploymentError("\n".join(msg_parts)) def _code_gen_and_patch_thread( - self, descr: definitions.ChainletAPIDescriptor, user_env: Mapping[str, str] + self, descr: definitions.ChainletAPIDescriptor ) -> tuple[b10_remote.PatchResult, list[str]]: with log_utils.LogInterceptor() as log_interceptor: # TODO: Maybe try-except code_gen errors explicitly. @@ -558,7 +557,6 @@ def _code_gen_and_patch_thread( descr, self._chainlet_data[descr.display_name].oracle_name, self._chainlet_display_name_to_url, - user_env, ) patch_result = self._remote_provider.patch_for_chainlet( chainlet_dir, self._ignore_patterns @@ -566,11 +564,7 @@ def _code_gen_and_patch_thread( logs = log_interceptor.get_logs() return patch_result, logs - def _patch( - self, - executor: concurrent.futures.Executor, - user_env: Optional[Mapping[str, str]], - ) -> None: + def _patch(self, executor: concurrent.futures.Executor) -> None: exception_raised = None stack_trace = "" with log_utils.LogInterceptor() as log_interceptor, self._console.status( @@ -593,7 +587,6 @@ def _patch( future = executor.submit( self._code_gen_and_patch_thread, chainlet_descr, - user_env or {}, ) future_to_display_name[future] = chainlet_descr.display_name # Threads need to finish while inside the `import_target`-context. @@ -678,15 +671,15 @@ def _check_patch_results( ) self._error_console.print(msg) - def watch(self, user_env: Optional[Mapping[str, str]]) -> None: + def watch(self) -> None: with concurrent.futures.ThreadPoolExecutor() as executor: # Perform one initial patch at startup. - self._patch(executor, user_env) + self._patch(executor) self._console.print("👀 Watching for new changes.", style="blue") for _ in watchfiles.watch( self._chain_root, watch_filter=self._watch_filter, raise_interrupt=False ): - self._patch(executor, user_env) + self._patch(executor) self._console.print("👀 Watching for new changes.", style="blue") @@ -696,7 +689,6 @@ def watch( entrypoint: Optional[str], name: Optional[str], remote: Optional[str], - user_env: Optional[Mapping[str, str]], console: "rich_console.Console", error_console: "rich_console.Console", show_stack_trace: bool, @@ -711,4 +703,4 @@ def watch( patcher = _Watcher( source, entrypoint, name, remote, console, error_console, show_stack_trace ) - patcher.watch(user_env) + patcher.watch() diff --git a/truss/cli/cli.py b/truss/cli/cli.py index 61dc9b955..2ab0fc567 100644 --- a/truss/cli/cli.py +++ b/truss/cli/cli.py @@ -7,7 +7,7 @@ import warnings from functools import wraps from pathlib import Path -from typing import Any, Callable, List, Optional, Tuple, Union +from typing import Callable, List, Optional, Tuple, Union import rich import rich.live @@ -409,35 +409,7 @@ def watch( # Chains Stuff ######################################################################### -class ChainsGroup(click.Group): - _ALIASES = {"deploy": "push"} # Alias `deploy` to push for backwards compat. - - def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Command]: - if cmd_name in self._ALIASES: - if cmd_name == "deploy": - warnings.warn( - "`truss chains deploy` is deprecated and will be removed in a " - "future version. Please use `truss chains push` instead.", - DeprecationWarning, - stacklevel=1, - ) - cmd_name = self._ALIASES[cmd_name] - - return super().get_command(ctx, cmd_name) - - def list_commands(self, ctx: click.Context) -> List[str]: - commands = super().list_commands(ctx) - return commands + list(self._ALIASES.keys()) - - def invoke(self, ctx: click.Context) -> Any: - # This import raises error messages if pydantic v2 or python older than 3.9 - # are installed. - import truss_chains # noqa: F401 - - return super().invoke(ctx) - - -@click.group(cls=ChainsGroup) +@click.group() def chains(): """Subcommands for truss chains""" @@ -586,10 +558,8 @@ def _create_chains_table(service) -> Tuple[rich.table.Table, List[str]]: "--user_env", required=False, type=str, - help=( - "Key-value-pairs (as JSON str) that can be used to control " - "deployment-specific chainlet behavior." - ), + help="[DEPRECATED], use ``environment`` instead.", + hidde=True, ) @log_level_option @error_handling @@ -633,17 +603,7 @@ def push_chain( wait = True if user_env: - try: - user_env_parsed = json.loads(user_env) - except json.JSONDecodeError as e: - raise ValueError( - f"Invalid JSON string for user_env: `{user_env}`.\n" - f"user_env must be a JSON dict with string values and string keys.\n" - 'Example: --user_env \'{"key1": "value1", "key2": "value2"}\'.\n' - f"Error: {e}" - ) - else: - user_env_parsed = {} + raise ValueError("`user_env` is deprecated, use `environment` instead.") if promote and environment: promote_warning = "`promote` flag and `environment` flag were both specified. Ignoring the value of `promote`" @@ -656,7 +616,6 @@ def push_chain( promote=promote, publish=publish, only_generate_trusses=dryrun, - user_env=user_env_parsed, remote=remote, environment=environment, ) @@ -713,7 +672,6 @@ def push_chain( entrypoint, name, remote, - user_env_parsed, console, error_console, show_stack_trace=not is_humanfriendly_log_level, @@ -747,10 +705,8 @@ def push_chain( "--user_env", required=False, type=str, - help=( - "Key-value-pairs (as JSON str) that can be used to control " - "deployment-specific chainlet behavior." - ), + help="[DEPRECATED], use `environment` instead.", + hidden=True, ) @log_level_option @error_handling @@ -777,24 +733,13 @@ def watch_chains( console.print("") # Print a newline. if user_env: - try: - user_env_parsed = json.loads(user_env) - except json.JSONDecodeError as e: - raise ValueError( - f"Invalid JSON string for user_env: `{user_env}`.\n" - f"user_env must be a JSON dict with string values and string keys.\n" - 'Example: --user_env \'{"key1": "value1", "key2": "value2"}\'.\n' - f"Error: {e}" - ) - else: - user_env_parsed = {} + raise ValueError("`user_env` is deprecated, use `environment` instead.") chains_remote.watch( source, entrypoint, name, remote, - user_env_parsed, console, error_console, show_stack_trace=not is_humanfriendly_log_level,