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.

Files changed (59) hide show
  1. truefoundry/common/constants.py +36 -2
  2. truefoundry/common/credential_provider.py +4 -2
  3. truefoundry/common/request_utils.py +1 -1
  4. truefoundry/common/servicefoundry_client.py +4 -2
  5. truefoundry/common/tfy_signed_url_client.py +260 -0
  6. truefoundry/common/tfy_signed_url_fs.py +244 -0
  7. truefoundry/common/utils.py +18 -5
  8. truefoundry/deploy/auto_gen/models.py +39 -4
  9. truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +1 -1
  10. truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +2 -4
  11. truefoundry/deploy/lib/clients/servicefoundry_client.py +2 -1
  12. truefoundry/deploy/lib/model/entity.py +0 -4
  13. truefoundry/deploy/python_deploy_codegen.py +79 -7
  14. truefoundry/ml/artifact/truefoundry_artifact_repo.py +448 -424
  15. truefoundry/ml/autogen/client/__init__.py +24 -3
  16. truefoundry/ml/autogen/client/api/experiments_api.py +0 -137
  17. truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +2 -0
  18. truefoundry/ml/autogen/client/models/__init__.py +24 -3
  19. truefoundry/ml/autogen/client/models/artifact_dto.py +9 -0
  20. truefoundry/ml/autogen/client/models/artifact_version_dto.py +26 -0
  21. truefoundry/ml/autogen/client/models/artifact_version_serialization_format.py +34 -0
  22. truefoundry/ml/autogen/client/models/create_artifact_version_response_dto.py +8 -2
  23. truefoundry/ml/autogen/client/models/create_run_request_dto.py +1 -10
  24. truefoundry/ml/autogen/client/models/dataset_dto.py +9 -0
  25. truefoundry/ml/autogen/client/models/experiment_dto.py +14 -3
  26. truefoundry/ml/autogen/client/models/external_model_source.py +79 -0
  27. truefoundry/ml/autogen/client/models/finalize_artifact_version_request_dto.py +11 -0
  28. truefoundry/ml/autogen/client/models/framework.py +154 -0
  29. truefoundry/ml/autogen/client/models/library_name.py +35 -0
  30. truefoundry/ml/autogen/client/models/model_dto.py +9 -0
  31. truefoundry/ml/autogen/client/models/model_version_dto.py +26 -0
  32. truefoundry/ml/autogen/client/models/model_version_manifest.py +119 -0
  33. truefoundry/ml/autogen/client/models/run_info_dto.py +10 -1
  34. truefoundry/ml/autogen/client/models/source.py +177 -0
  35. truefoundry/ml/autogen/client/models/subject.py +79 -0
  36. truefoundry/ml/autogen/client/models/subject_type.py +34 -0
  37. truefoundry/ml/autogen/client/models/tensorflow_framework.py +74 -0
  38. truefoundry/ml/autogen/client/models/transformers_framework.py +90 -0
  39. truefoundry/ml/autogen/client/models/truefoundry_model_source.py +79 -0
  40. truefoundry/ml/autogen/client/models/update_model_version_request_dto.py +11 -0
  41. truefoundry/ml/autogen/client/models/upload_model_source.py +74 -0
  42. truefoundry/ml/autogen/client_README.md +12 -2
  43. truefoundry/ml/autogen/entities/artifacts.py +236 -4
  44. truefoundry/ml/log_types/artifacts/artifact.py +10 -11
  45. truefoundry/ml/log_types/artifacts/dataset.py +13 -10
  46. truefoundry/ml/log_types/artifacts/general_artifact.py +3 -1
  47. truefoundry/ml/log_types/artifacts/model.py +18 -35
  48. truefoundry/ml/log_types/artifacts/utils.py +42 -25
  49. truefoundry/ml/log_types/image/image.py +2 -0
  50. truefoundry/ml/log_types/plot.py +2 -0
  51. truefoundry/ml/mlfoundry_api.py +7 -3
  52. truefoundry/ml/session.py +3 -1
  53. truefoundry/workflow/__init__.py +10 -0
  54. {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/METADATA +1 -1
  55. {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/RECORD +57 -45
  56. truefoundry/ml/autogen/client/models/list_seed_experiments_response_dto.py +0 -81
  57. truefoundry/ml/env_vars.py +0 -9
  58. {truefoundry-0.4.3.dist-info → truefoundry-0.4.4.dist-info}/WHEEL +0 -0
  59. {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-09T13:00:44+00:00
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=2\n+usage=The helm chart name\n+uiType=InputSelect\n+uiProps={"creatable":true, "searchable":true}',
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=3\n+usage=Helm chart version\n+uiType=InputSelect\n+uiProps={"creatable":true, "searchable":true}',
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] = None
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 TFY_CLI_PYTHONBUILD_PYTHON_IMAGE_REPO_ENV_KEY
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": os.getenv(
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 generate_code(
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
- application_type = application.__root__.type
110
-
111
- spec_repr = get_python_repr(application.__root__)
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 = generate_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