truefoundry 0.4.3__py3-none-any.whl → 0.4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of truefoundry might be problematic. Click here for more details.
- truefoundry/common/constants.py +36 -2
- truefoundry/common/credential_provider.py +4 -2
- truefoundry/common/request_utils.py +1 -1
- truefoundry/common/servicefoundry_client.py +4 -2
- truefoundry/common/tfy_signed_url_client.py +260 -0
- truefoundry/common/tfy_signed_url_fs.py +244 -0
- truefoundry/common/utils.py +18 -5
- truefoundry/deploy/auto_gen/models.py +39 -4
- truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +1 -1
- truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +2 -4
- truefoundry/deploy/lib/clients/servicefoundry_client.py +2 -1
- truefoundry/deploy/lib/model/entity.py +0 -4
- truefoundry/deploy/python_deploy_codegen.py +79 -7
- truefoundry/ml/artifact/truefoundry_artifact_repo.py +448 -424
- truefoundry/ml/autogen/client/__init__.py +24 -3
- truefoundry/ml/autogen/client/api/experiments_api.py +0 -137
- truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +2 -0
- truefoundry/ml/autogen/client/models/__init__.py +24 -3
- truefoundry/ml/autogen/client/models/artifact_dto.py +9 -0
- truefoundry/ml/autogen/client/models/artifact_version_dto.py +26 -0
- truefoundry/ml/autogen/client/models/artifact_version_serialization_format.py +34 -0
- truefoundry/ml/autogen/client/models/create_artifact_version_response_dto.py +8 -2
- truefoundry/ml/autogen/client/models/create_run_request_dto.py +1 -10
- truefoundry/ml/autogen/client/models/dataset_dto.py +9 -0
- truefoundry/ml/autogen/client/models/experiment_dto.py +14 -3
- truefoundry/ml/autogen/client/models/external_model_source.py +79 -0
- truefoundry/ml/autogen/client/models/finalize_artifact_version_request_dto.py +11 -0
- truefoundry/ml/autogen/client/models/framework.py +154 -0
- truefoundry/ml/autogen/client/models/library_name.py +35 -0
- truefoundry/ml/autogen/client/models/model_dto.py +9 -0
- truefoundry/ml/autogen/client/models/model_version_dto.py +26 -0
- truefoundry/ml/autogen/client/models/model_version_manifest.py +119 -0
- truefoundry/ml/autogen/client/models/run_info_dto.py +10 -1
- truefoundry/ml/autogen/client/models/source.py +177 -0
- truefoundry/ml/autogen/client/models/subject.py +79 -0
- truefoundry/ml/autogen/client/models/subject_type.py +34 -0
- truefoundry/ml/autogen/client/models/tensorflow_framework.py +74 -0
- truefoundry/ml/autogen/client/models/transformers_framework.py +90 -0
- truefoundry/ml/autogen/client/models/truefoundry_model_source.py +79 -0
- truefoundry/ml/autogen/client/models/update_model_version_request_dto.py +11 -0
- truefoundry/ml/autogen/client/models/upload_model_source.py +74 -0
- truefoundry/ml/autogen/client_README.md +12 -2
- truefoundry/ml/autogen/entities/artifacts.py +236 -4
- truefoundry/ml/log_types/artifacts/artifact.py +10 -11
- truefoundry/ml/log_types/artifacts/dataset.py +13 -10
- truefoundry/ml/log_types/artifacts/general_artifact.py +3 -1
- truefoundry/ml/log_types/artifacts/model.py +18 -35
- truefoundry/ml/log_types/artifacts/utils.py +42 -25
- truefoundry/ml/log_types/image/image.py +2 -0
- truefoundry/ml/log_types/plot.py +2 -0
- truefoundry/ml/mlfoundry_api.py +7 -3
- truefoundry/ml/session.py +3 -1
- truefoundry/workflow/__init__.py +10 -0
- {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/METADATA +1 -1
- {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/RECORD +57 -45
- truefoundry/ml/autogen/client/models/list_seed_experiments_response_dto.py +0 -81
- truefoundry/ml/env_vars.py +0 -9
- {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/WHEEL +0 -0
- {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: application.json
|
|
3
|
-
# timestamp: 2024-10-
|
|
3
|
+
# timestamp: 2024-10-16T17:06:03+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -362,13 +362,17 @@ class HelmRepo(BaseModel):
|
|
|
362
362
|
...,
|
|
363
363
|
description="+label=Helm repository URL\n+sort=1\n+message=Needs to be a valid URL.",
|
|
364
364
|
)
|
|
365
|
+
integration_fqn: Optional[str] = Field(
|
|
366
|
+
None,
|
|
367
|
+
description='+docs=FQN of the helm repo integration. You can use the FQN of your desired helm integration (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations) page\n+label=Helm repo integration\n+sort=2\n+usage=FQN of the helm repo integration. If you can\'t find your integration here,\nadd it through the [Integrations](/integrations) page\n+uiType=IntegrationSelect\n+uiProps={"integrationType":"helm-repo"}',
|
|
368
|
+
)
|
|
365
369
|
chart: str = Field(
|
|
366
370
|
...,
|
|
367
|
-
description='+label=Chart name\n+sort=
|
|
371
|
+
description='+label=Chart name\n+sort=3\n+usage=The helm chart name\n+uiType=InputSelect\n+uiProps={"creatable":true, "searchable":true}',
|
|
368
372
|
)
|
|
369
373
|
version: str = Field(
|
|
370
374
|
...,
|
|
371
|
-
description='+label=Version\n+sort=
|
|
375
|
+
description='+label=Version\n+sort=4\n+usage=Helm chart version\n+uiType=InputSelect\n+uiProps={"creatable":true, "searchable":true}',
|
|
372
376
|
)
|
|
373
377
|
|
|
374
378
|
|
|
@@ -472,6 +476,31 @@ class JobAlert(BaseModel):
|
|
|
472
476
|
)
|
|
473
477
|
|
|
474
478
|
|
|
479
|
+
class Claim(BaseModel):
|
|
480
|
+
key: str
|
|
481
|
+
values: List[str]
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
class JwtAuthCreds(BaseModel):
|
|
485
|
+
"""
|
|
486
|
+
+label=JWT Authentication
|
|
487
|
+
+usage=Configure JWT-based authentication using JWKS
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
type: Literal["jwt_auth"] = Field(..., description="+value=jwt_auth")
|
|
491
|
+
issuer: str = Field(
|
|
492
|
+
..., description="+label=Issuer\n+usage=The issuer of the JWT tokens"
|
|
493
|
+
)
|
|
494
|
+
jwksUri: str = Field(
|
|
495
|
+
...,
|
|
496
|
+
description="+label=JWKS URI\n+usage=The URI of the JSON Web Key Set (JWKS) containing the public keys",
|
|
497
|
+
)
|
|
498
|
+
claims: Optional[List[Claim]] = Field(
|
|
499
|
+
None,
|
|
500
|
+
description="+label=Claims\n+usage=List of key-value pairs of claims to verify in the JWT token",
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
|
|
475
504
|
class KafkaMetricConfig(BaseModel):
|
|
476
505
|
type: Literal["kafka"] = Field(..., description="+value=kafka")
|
|
477
506
|
lag_threshold: conint(ge=1) = Field(
|
|
@@ -655,6 +684,10 @@ class OCIRepo(BaseModel):
|
|
|
655
684
|
oci_chart_url: constr(
|
|
656
685
|
regex=r"^(((oci):\/\/)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*))$"
|
|
657
686
|
) = Field(..., description="+label=OCI chart URL\n+message=Need to be a valid URL.")
|
|
687
|
+
integration_fqn: Optional[str] = Field(
|
|
688
|
+
None,
|
|
689
|
+
description='+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations) page\n+label=Container Registry\n+usage=FQN of the container registry. If you can\'t find your registry here,\nadd it through the [Integrations](/integrations) page\n+uiType=IntegrationSelect\n+uiProps={"integrationType":"docker-registry"}',
|
|
690
|
+
)
|
|
658
691
|
version: str = Field(..., description="+label=Version\n+usage=Helm chart version")
|
|
659
692
|
|
|
660
693
|
|
|
@@ -736,7 +769,9 @@ class Port(BaseModel):
|
|
|
736
769
|
None,
|
|
737
770
|
description="+label=Rewrite Path to\n+usage=Rewrite the path prefix to a different path.\nIf `path` is `/v1/api` and `rewrite_path_to` is `/api`. The URI in the HTTP request `http://0.0.0.0:8080/v1/api/houses` will be rewritten to `http://0.0.0.0:8080/api/houses` before the request is forwarded your service.\nDefaults to `/`.\nThis is only applicable if `path` is given.\n+message=Should begin and end with a forward slash (/). Each part can can contain alphabets, digits and hypen, must begin and end with an alphanumeric characters. Parts should be separated by forward slashes (/)",
|
|
738
771
|
)
|
|
739
|
-
auth: Optional[BasicAuthCreds] =
|
|
772
|
+
auth: Optional[Union[BasicAuthCreds, JwtAuthCreds]] = Field(
|
|
773
|
+
None, description="+usage=Username and Password for service auth"
|
|
774
|
+
)
|
|
740
775
|
|
|
741
776
|
|
|
742
777
|
class PythonBuild(BaseModel):
|
|
@@ -50,7 +50,7 @@ def generate_build_script_docker_commands(
|
|
|
50
50
|
all_environment_variables = " ".join(environment_variables)
|
|
51
51
|
run_build_script_command = f"""\
|
|
52
52
|
COPY {build_script_path} /tmp/user-build-script.sh
|
|
53
|
-
RUN {buildkit_secret_mounts} mkdir -p /var/log/ && {all_environment_variables} bash -ex /tmp/user-build-script.sh 2>&1 | tee /var/log/user-build-script-output.log
|
|
53
|
+
RUN {buildkit_secret_mounts} mkdir -p /var/log/ && {all_environment_variables} bash -ex /tmp/user-build-script.sh 2>&1 | tee /var/log/user-build-script-output.log && test ${{PIPESTATUS[0]}} -eq 0
|
|
54
54
|
"""
|
|
55
55
|
return run_build_script_command
|
|
56
56
|
|
|
@@ -3,7 +3,7 @@ from typing import Dict, List, Optional
|
|
|
3
3
|
|
|
4
4
|
from mako.template import Template
|
|
5
5
|
|
|
6
|
-
from truefoundry.common.constants import
|
|
6
|
+
from truefoundry.common.constants import ENV_VARS
|
|
7
7
|
from truefoundry.deploy.auto_gen.models import PythonBuild
|
|
8
8
|
from truefoundry.deploy.builder.constants import (
|
|
9
9
|
PIP_CONF_BUILDKIT_SECRET_MOUNT,
|
|
@@ -156,9 +156,7 @@ def generate_dockerfile_content(
|
|
|
156
156
|
apt_packages=build_configuration.apt_packages
|
|
157
157
|
)
|
|
158
158
|
template_args = {
|
|
159
|
-
"python_image_repo":
|
|
160
|
-
TFY_CLI_PYTHONBUILD_PYTHON_IMAGE_REPO_ENV_KEY, DEFAULT_PYTHON_IMAGE_REPO
|
|
161
|
-
),
|
|
159
|
+
"python_image_repo": ENV_VARS.TFY_PYTHONBUILD_PYTHON_IMAGE_REPO,
|
|
162
160
|
"python_version": build_configuration.python_version,
|
|
163
161
|
"apt_install_command": apt_install_command,
|
|
164
162
|
"requirements_path": requirements_path,
|
|
@@ -48,6 +48,7 @@ from truefoundry.pydantic_v1 import parse_obj_as
|
|
|
48
48
|
|
|
49
49
|
DEPLOYMENT_LOGS_SUBSCRIBE_MESSAGE = "DEPLOYMENT_LOGS"
|
|
50
50
|
BUILD_LOGS_SUBSCRIBE_MESSAGE = "BUILD_LOGS"
|
|
51
|
+
MAX_RETRIES_WORKFLOW_TRIGGER = 3
|
|
51
52
|
|
|
52
53
|
if TYPE_CHECKING:
|
|
53
54
|
from truefoundry.deploy.auto_gen.models import Application
|
|
@@ -597,7 +598,7 @@ class ServiceFoundryServiceClient(BaseServiceFoundryServiceClient):
|
|
|
597
598
|
def trigger_workflow(self, application_id: str, inputs: Dict[str, Any]):
|
|
598
599
|
url = f"{self._api_server_url}/{VERSION_PREFIX}/workflow/{application_id}/executions"
|
|
599
600
|
body = {"inputs": inputs}
|
|
600
|
-
response = session_with_retries().post(
|
|
601
|
+
response = session_with_retries(retries=MAX_RETRIES_WORKFLOW_TRIGGER).post(
|
|
601
602
|
url, json=body, headers=self._get_header()
|
|
602
603
|
)
|
|
603
604
|
response = request_handling(response)
|
|
@@ -32,7 +32,6 @@ class Base(BaseModel):
|
|
|
32
32
|
class Entity(Base):
|
|
33
33
|
createdAt: datetime.datetime = Field(repr=False)
|
|
34
34
|
updatedAt: datetime.datetime = Field(repr=False)
|
|
35
|
-
createdBy: str = Field(repr=False)
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
class Workspace(Entity):
|
|
@@ -56,7 +55,6 @@ class Workspace(Entity):
|
|
|
56
55
|
"cluster_fqn": self.clusterId,
|
|
57
56
|
"created_at": self.createdAt,
|
|
58
57
|
"updated_at": self.updatedAt,
|
|
59
|
-
"created_by": self.createdBy,
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
|
|
@@ -161,7 +159,6 @@ class Deployment(Entity):
|
|
|
161
159
|
"cluster_fqn": cluster_fqn,
|
|
162
160
|
"created_at": self.createdAt,
|
|
163
161
|
"updated_at": self.updatedAt,
|
|
164
|
-
"created_by": self.createdBy,
|
|
165
162
|
}
|
|
166
163
|
|
|
167
164
|
class Config:
|
|
@@ -208,7 +205,6 @@ class Application(Entity):
|
|
|
208
205
|
"cluster_fqn": self.workspace.clusterId,
|
|
209
206
|
"created_at": self.createdAt,
|
|
210
207
|
"updated_at": self.updatedAt,
|
|
211
|
-
"created_by": self.createdBy,
|
|
212
208
|
}
|
|
213
209
|
|
|
214
210
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import io
|
|
3
|
+
import json
|
|
3
4
|
import re
|
|
4
|
-
from typing import List
|
|
5
|
+
from typing import Dict, List, Optional
|
|
5
6
|
|
|
6
7
|
from rich.console import Console
|
|
7
8
|
from rich.pretty import pprint
|
|
8
9
|
|
|
9
|
-
from truefoundry.deploy import Application
|
|
10
|
+
from truefoundry.deploy import Application, LocalSource
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
def
|
|
13
|
+
def generate_deployment_code(
|
|
13
14
|
symbols_to_import: List[str],
|
|
14
15
|
application_type: str,
|
|
15
16
|
spec_repr: str,
|
|
@@ -106,9 +107,16 @@ def convert_deployment_config_to_python(workspace_fqn: str, application_spec: di
|
|
|
106
107
|
Convert a deployment config to a python file that can be used to deploy to a workspace
|
|
107
108
|
"""
|
|
108
109
|
application = Application.parse_obj(application_spec)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
application_obj = application.__root__
|
|
111
|
+
application_type = application_obj.type
|
|
112
|
+
if (
|
|
113
|
+
hasattr(application_obj, "image")
|
|
114
|
+
and application_obj.image.type == "build"
|
|
115
|
+
and application_obj.image.build_source.type == "remote"
|
|
116
|
+
):
|
|
117
|
+
application_obj.image.build_source = LocalSource(local_build=False)
|
|
118
|
+
|
|
119
|
+
spec_repr = get_python_repr(application_obj)
|
|
112
120
|
spec_repr = replace_enums_with_values(spec_repr)
|
|
113
121
|
spec_repr = remove_none_type_fields(spec_repr)
|
|
114
122
|
spec_repr = remove_type_field(spec_repr)
|
|
@@ -120,7 +128,7 @@ def convert_deployment_config_to_python(workspace_fqn: str, application_spec: di
|
|
|
120
128
|
if "GitSource" in symbols_to_import:
|
|
121
129
|
symbols_to_import.append("LocalSource")
|
|
122
130
|
|
|
123
|
-
generated_code =
|
|
131
|
+
generated_code = generate_deployment_code(
|
|
124
132
|
symbols_to_import=symbols_to_import,
|
|
125
133
|
application_type=application_type,
|
|
126
134
|
spec_repr=spec_repr,
|
|
@@ -131,3 +139,67 @@ def convert_deployment_config_to_python(workspace_fqn: str, application_spec: di
|
|
|
131
139
|
generated_code = add_local_source_comment(generated_code)
|
|
132
140
|
|
|
133
141
|
return generated_code
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def generate_python_snippet_for_trigger_job(
|
|
145
|
+
application_fqn: str, command: Optional[str], params: Optional[Dict[str, str]]
|
|
146
|
+
):
|
|
147
|
+
job_run_python_template = """\
|
|
148
|
+
from truefoundry.deploy import trigger_job
|
|
149
|
+
|
|
150
|
+
response = trigger_job(
|
|
151
|
+
application_fqn="{{application_fqn}}",
|
|
152
|
+
# You can pass command or params, but not both
|
|
153
|
+
# command={{command}}
|
|
154
|
+
# params={{params}}
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
print(response.jobRunName)
|
|
158
|
+
"""
|
|
159
|
+
output_python_str = job_run_python_template.replace(
|
|
160
|
+
"{{application_fqn}}", application_fqn
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if command is not None:
|
|
164
|
+
output_python_str = output_python_str.replace("# command", "command")
|
|
165
|
+
output_python_str = output_python_str.replace("{{command}}", repr(command))
|
|
166
|
+
else:
|
|
167
|
+
output_python_str = output_python_str.replace(
|
|
168
|
+
"{{command}}", "<Enter Command Here>"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if params is not None:
|
|
172
|
+
output_python_str = output_python_str.replace("# params", "params")
|
|
173
|
+
output_python_str = output_python_str.replace("{{params}}", repr(params))
|
|
174
|
+
else:
|
|
175
|
+
output_python_str = output_python_str.replace(
|
|
176
|
+
"{{params}}", "<Enter Params(key-value pairs) here as python dict>"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return output_python_str
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def generate_curl_snippet_for_trigger_job(
|
|
183
|
+
control_plane_url: str,
|
|
184
|
+
application_id: str,
|
|
185
|
+
command: Optional[str],
|
|
186
|
+
params: Optional[Dict[str, str]],
|
|
187
|
+
):
|
|
188
|
+
job_run_curl_request_template = """curl -X 'POST' \\
|
|
189
|
+
'{{control_plane_url}}/api/svc/v1/jobs/trigger' \\
|
|
190
|
+
-H 'accept: */*' \\
|
|
191
|
+
-H 'Authorization: Bearer <Paste your API key here. You can generate it from the Settings Page>' \\
|
|
192
|
+
-H 'Content-Type: application/json' \\
|
|
193
|
+
-d '{
|
|
194
|
+
"applicationId": "{{application_id}}",
|
|
195
|
+
"input": {{input}}
|
|
196
|
+
}'
|
|
197
|
+
"""
|
|
198
|
+
output_curl_str = job_run_curl_request_template.replace(
|
|
199
|
+
"{{control_plane_url}}", control_plane_url.rstrip("/")
|
|
200
|
+
)
|
|
201
|
+
output_curl_str = output_curl_str.replace("{{application_id}}", application_id)
|
|
202
|
+
output_curl_str = output_curl_str.replace(
|
|
203
|
+
"{{input}}", json.dumps({"command": command, "params": params}, indent=2)
|
|
204
|
+
)
|
|
205
|
+
return output_curl_str
|