truefoundry 0.5.2__py3-none-any.whl → 0.5.3__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 (63) hide show
  1. truefoundry/__init__.py +10 -1
  2. truefoundry/autodeploy/agents/base.py +1 -1
  3. truefoundry/autodeploy/agents/developer.py +1 -1
  4. truefoundry/autodeploy/agents/project_identifier.py +1 -1
  5. truefoundry/autodeploy/agents/tester.py +1 -1
  6. truefoundry/autodeploy/cli.py +2 -2
  7. truefoundry/autodeploy/tools/base.py +2 -1
  8. truefoundry/autodeploy/tools/commit.py +1 -1
  9. truefoundry/autodeploy/tools/docker_build.py +1 -1
  10. truefoundry/autodeploy/tools/docker_run.py +1 -1
  11. truefoundry/autodeploy/tools/file_type_counts.py +1 -1
  12. truefoundry/autodeploy/tools/list_files.py +1 -1
  13. truefoundry/autodeploy/tools/read_file.py +1 -2
  14. truefoundry/autodeploy/tools/send_request.py +1 -1
  15. truefoundry/autodeploy/tools/write_file.py +1 -1
  16. truefoundry/cli/util.py +12 -3
  17. truefoundry/common/auth_service_client.py +7 -4
  18. truefoundry/common/constants.py +3 -0
  19. truefoundry/common/credential_provider.py +7 -8
  20. truefoundry/common/exceptions.py +11 -7
  21. truefoundry/common/request_utils.py +96 -14
  22. truefoundry/common/servicefoundry_client.py +31 -29
  23. truefoundry/common/session.py +93 -0
  24. truefoundry/common/storage_provider_utils.py +331 -0
  25. truefoundry/common/utils.py +9 -9
  26. truefoundry/common/warnings.py +21 -0
  27. truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +8 -21
  28. truefoundry/deploy/cli/commands/deploy_command.py +4 -4
  29. truefoundry/deploy/lib/clients/servicefoundry_client.py +13 -14
  30. truefoundry/deploy/lib/dao/application.py +2 -2
  31. truefoundry/deploy/lib/dao/workspace.py +1 -1
  32. truefoundry/deploy/lib/session.py +1 -1
  33. truefoundry/deploy/v2/lib/deploy.py +2 -2
  34. truefoundry/deploy/v2/lib/deploy_workflow.py +1 -1
  35. truefoundry/deploy/v2/lib/patched_models.py +70 -4
  36. truefoundry/deploy/v2/lib/source.py +2 -1
  37. truefoundry/ml/artifact/truefoundry_artifact_repo.py +33 -297
  38. truefoundry/ml/autogen/client/__init__.py +3 -0
  39. truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +149 -0
  40. truefoundry/ml/autogen/client/models/__init__.py +3 -0
  41. truefoundry/ml/autogen/client/models/artifact_version_manifest.py +25 -1
  42. truefoundry/ml/autogen/client/models/get_artifact_version_aliases_response_dto.py +67 -0
  43. truefoundry/ml/autogen/client/models/model_version_manifest.py +18 -0
  44. truefoundry/ml/autogen/client_README.md +2 -0
  45. truefoundry/ml/autogen/entities/artifacts.py +7 -1
  46. truefoundry/ml/clients/servicefoundry_client.py +36 -15
  47. truefoundry/ml/exceptions.py +2 -1
  48. truefoundry/ml/log_types/artifacts/artifact.py +37 -4
  49. truefoundry/ml/log_types/artifacts/model.py +51 -10
  50. truefoundry/ml/log_types/artifacts/utils.py +2 -2
  51. truefoundry/ml/mlfoundry_api.py +6 -38
  52. truefoundry/ml/mlfoundry_run.py +6 -15
  53. truefoundry/ml/model_framework.py +5 -3
  54. truefoundry/ml/session.py +69 -97
  55. truefoundry/workflow/remote_filesystem/tfy_signed_url_client.py +42 -9
  56. truefoundry/workflow/remote_filesystem/tfy_signed_url_fs.py +126 -7
  57. {truefoundry-0.5.2.dist-info → truefoundry-0.5.3.dist-info}/METADATA +2 -2
  58. {truefoundry-0.5.2.dist-info → truefoundry-0.5.3.dist-info}/RECORD +60 -59
  59. {truefoundry-0.5.2.dist-info → truefoundry-0.5.3.dist-info}/WHEEL +1 -1
  60. truefoundry/deploy/lib/auth/servicefoundry_session.py +0 -61
  61. truefoundry/ml/clients/entities.py +0 -8
  62. truefoundry/ml/clients/utils.py +0 -122
  63. {truefoundry-0.5.2.dist-info → truefoundry-0.5.3.dist-info}/entry_points.txt +0 -0
@@ -79,6 +79,9 @@ from truefoundry.ml.autogen.client.models.export_deployment_files_request_dto im
79
79
  from truefoundry.ml.autogen.client.models.finalize_artifact_version_request_dto import (
80
80
  FinalizeArtifactVersionRequestDto,
81
81
  )
82
+ from truefoundry.ml.autogen.client.models.get_artifact_version_aliases_response_dto import (
83
+ GetArtifactVersionAliasesResponseDto,
84
+ )
82
85
  from truefoundry.ml.autogen.client.models.get_signed_url_for_dataset_write_request_dto import (
83
86
  GetSignedURLForDatasetWriteRequestDto,
84
87
  )
@@ -5338,6 +5341,152 @@ class MlfoundryArtifactsApi:
5338
5341
  _request_auth=_params.get("_request_auth"),
5339
5342
  )
5340
5343
 
5344
+ @validate_arguments
5345
+ def get_version_aliases_for_artifact_get(
5346
+ self, artifact_id: StrictStr, **kwargs
5347
+ ) -> GetArtifactVersionAliasesResponseDto: # noqa: E501
5348
+ """Get Version Aliases For Artifact # noqa: E501
5349
+
5350
+ This method makes a synchronous HTTP request by default. To make an
5351
+ asynchronous HTTP request, please pass async_req=True
5352
+
5353
+ >>> thread = api.get_version_aliases_for_artifact_get(artifact_id, async_req=True)
5354
+ >>> result = thread.get()
5355
+
5356
+ :param artifact_id: (required)
5357
+ :type artifact_id: str
5358
+ :param async_req: Whether to execute the request asynchronously.
5359
+ :type async_req: bool, optional
5360
+ :param _request_timeout: timeout setting for this request.
5361
+ If one number provided, it will be total request
5362
+ timeout. It can also be a pair (tuple) of
5363
+ (connection, read) timeouts.
5364
+ :return: Returns the result object.
5365
+ If the method is called asynchronously,
5366
+ returns the request thread.
5367
+ :rtype: GetArtifactVersionAliasesResponseDto
5368
+ """
5369
+ kwargs["_return_http_data_only"] = True
5370
+ if "_preload_content" in kwargs:
5371
+ message = "Error! Please call the get_version_aliases_for_artifact_get_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501
5372
+ raise ValueError(message)
5373
+ return self.get_version_aliases_for_artifact_get_with_http_info(
5374
+ artifact_id, **kwargs
5375
+ ) # noqa: E501
5376
+
5377
+ @validate_arguments
5378
+ def get_version_aliases_for_artifact_get_with_http_info(
5379
+ self, artifact_id: StrictStr, **kwargs
5380
+ ) -> ApiResponse: # noqa: E501
5381
+ """Get Version Aliases For Artifact # noqa: E501
5382
+
5383
+ This method makes a synchronous HTTP request by default. To make an
5384
+ asynchronous HTTP request, please pass async_req=True
5385
+
5386
+ >>> thread = api.get_version_aliases_for_artifact_get_with_http_info(artifact_id, async_req=True)
5387
+ >>> result = thread.get()
5388
+
5389
+ :param artifact_id: (required)
5390
+ :type artifact_id: str
5391
+ :param async_req: Whether to execute the request asynchronously.
5392
+ :type async_req: bool, optional
5393
+ :param _preload_content: if False, the ApiResponse.data will
5394
+ be set to none and raw_data will store the
5395
+ HTTP response body without reading/decoding.
5396
+ Default is True.
5397
+ :type _preload_content: bool, optional
5398
+ :param _return_http_data_only: response data instead of ApiResponse
5399
+ object with status code, headers, etc
5400
+ :type _return_http_data_only: bool, optional
5401
+ :param _request_timeout: timeout setting for this request. If one
5402
+ number provided, it will be total request
5403
+ timeout. It can also be a pair (tuple) of
5404
+ (connection, read) timeouts.
5405
+ :param _request_auth: set to override the auth_settings for an a single
5406
+ request; this effectively ignores the authentication
5407
+ in the spec for a single request.
5408
+ :type _request_auth: dict, optional
5409
+ :type _content_type: string, optional: force content-type for the request
5410
+ :return: Returns the result object.
5411
+ If the method is called asynchronously,
5412
+ returns the request thread.
5413
+ :rtype: tuple(GetArtifactVersionAliasesResponseDto, status_code(int), headers(HTTPHeaderDict))
5414
+ """
5415
+
5416
+ _params = locals()
5417
+
5418
+ _all_params = ["artifact_id"]
5419
+ _all_params.extend(
5420
+ [
5421
+ "async_req",
5422
+ "_return_http_data_only",
5423
+ "_preload_content",
5424
+ "_request_timeout",
5425
+ "_request_auth",
5426
+ "_content_type",
5427
+ "_headers",
5428
+ ]
5429
+ )
5430
+
5431
+ # validate the arguments
5432
+ for _key, _val in _params["kwargs"].items():
5433
+ if _key not in _all_params:
5434
+ raise ApiTypeError(
5435
+ "Got an unexpected keyword argument '%s'"
5436
+ " to method get_version_aliases_for_artifact_get" % _key
5437
+ )
5438
+ _params[_key] = _val
5439
+ del _params["kwargs"]
5440
+
5441
+ _collection_formats = {}
5442
+
5443
+ # process the path parameters
5444
+ _path_params = {}
5445
+
5446
+ # process the query parameters
5447
+ _query_params = []
5448
+ if _params.get("artifact_id") is not None: # noqa: E501
5449
+ _query_params.append(("artifact_id", _params["artifact_id"]))
5450
+
5451
+ # process the header parameters
5452
+ _header_params = dict(_params.get("_headers", {}))
5453
+ # process the form parameters
5454
+ _form_params = []
5455
+ _files = {}
5456
+ # process the body parameter
5457
+ _body_params = None
5458
+ # set the HTTP header `Accept`
5459
+ _header_params["Accept"] = self.api_client.select_header_accept(
5460
+ ["application/json"]
5461
+ ) # noqa: E501
5462
+
5463
+ # authentication setting
5464
+ _auth_settings = ["HTTPBearer", "APIKeyCookie"] # noqa: E501
5465
+
5466
+ _response_types_map = {
5467
+ "200": "GetArtifactVersionAliasesResponseDto",
5468
+ "422": "HTTPValidationError",
5469
+ }
5470
+
5471
+ return self.api_client.call_api(
5472
+ "/api/2.0/mlflow/mlfoundry-artifacts/artifacts/get-version-aliases",
5473
+ "GET",
5474
+ _path_params,
5475
+ _query_params,
5476
+ _header_params,
5477
+ body=_body_params,
5478
+ post_params=_form_params,
5479
+ files=_files,
5480
+ response_types_map=_response_types_map,
5481
+ auth_settings=_auth_settings,
5482
+ async_req=_params.get("async_req"),
5483
+ _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501
5484
+ _preload_content=_params.get("_preload_content", True),
5485
+ _request_timeout=_params.get("_request_timeout"),
5486
+ collection_formats=_collection_formats,
5487
+ _request_auth=_params.get("_request_auth"),
5488
+ )
5489
+
5341
5490
  @validate_arguments
5342
5491
  def list_artifact_versions_post(
5343
5492
  self,
@@ -155,6 +155,9 @@ from truefoundry.ml.autogen.client.models.finalize_artifact_version_request_dto
155
155
  FinalizeArtifactVersionRequestDto,
156
156
  )
157
157
  from truefoundry.ml.autogen.client.models.framework import Framework
158
+ from truefoundry.ml.autogen.client.models.get_artifact_version_aliases_response_dto import (
159
+ GetArtifactVersionAliasesResponseDto,
160
+ )
158
161
  from truefoundry.ml.autogen.client.models.get_experiment_response_dto import (
159
162
  GetExperimentResponseDto,
160
163
  )
@@ -42,12 +42,35 @@ class ArtifactVersionManifest(BaseModel):
42
42
  default=...,
43
43
  description="+label=Metadata +docs=Metadata for the artifact or model version +usage=Metadata for the artifact or model version +uiType=JsonInput",
44
44
  )
45
+ version_alias: Optional[constr(strict=True, max_length=128)] = Field(
46
+ default=None,
47
+ description="+label=Version Alias +usage=The version alias for artifact or model version which should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc) +docs=The version alias for artifact or model version which should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc) +message=The version alias should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc)",
48
+ )
45
49
  type: Optional[StrictStr] = "artifact-version"
46
50
  source: Source = Field(...)
47
51
  step: Optional[conint(strict=True, ge=0)] = Field(
48
52
  default=0, description="+label=Step"
49
53
  )
50
- __properties = ["description", "metadata", "type", "source", "step"]
54
+ __properties = [
55
+ "description",
56
+ "metadata",
57
+ "version_alias",
58
+ "type",
59
+ "source",
60
+ "step",
61
+ ]
62
+
63
+ @validator("version_alias")
64
+ def version_alias_validate_regular_expression(cls, value):
65
+ """Validates the regular expression"""
66
+ if value is None:
67
+ return value
68
+
69
+ if not re.match(r"^v[a-zA-Z0-9.-]*([a-zA-Z0-9]+)$", value):
70
+ raise ValueError(
71
+ r"must validate the regular expression /^v[a-zA-Z0-9.-]*([a-zA-Z0-9]+)$/"
72
+ )
73
+ return value
51
74
 
52
75
  @validator("type")
53
76
  def type_validate_enum(cls, value):
@@ -99,6 +122,7 @@ class ArtifactVersionManifest(BaseModel):
99
122
  {
100
123
  "description": obj.get("description"),
101
124
  "metadata": obj.get("metadata"),
125
+ "version_alias": obj.get("version_alias"),
102
126
  "type": obj.get("type")
103
127
  if obj.get("type") is not None
104
128
  else "artifact-version",
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ FastAPI
5
+
6
+ No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
7
+
8
+ The version of the OpenAPI document: 0.1.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ import re # noqa: F401
19
+
20
+ from truefoundry.pydantic_v1 import BaseModel, Field, StrictStr, conlist
21
+
22
+
23
+ class GetArtifactVersionAliasesResponseDto(BaseModel):
24
+ """
25
+ GetArtifactVersionAliasesResponseDto
26
+ """
27
+
28
+ version_aliases: conlist(StrictStr) = Field(...)
29
+ __properties = ["version_aliases"]
30
+
31
+ class Config:
32
+ """Pydantic configuration"""
33
+
34
+ allow_population_by_field_name = True
35
+ validate_assignment = True
36
+
37
+ def to_str(self) -> str:
38
+ """Returns the string representation of the model using alias"""
39
+ return pprint.pformat(self.dict(by_alias=True))
40
+
41
+ def to_json(self) -> str:
42
+ """Returns the JSON representation of the model using alias"""
43
+ return json.dumps(self.to_dict())
44
+
45
+ @classmethod
46
+ def from_json(cls, json_str: str) -> GetArtifactVersionAliasesResponseDto:
47
+ """Create an instance of GetArtifactVersionAliasesResponseDto from a JSON string"""
48
+ return cls.from_dict(json.loads(json_str))
49
+
50
+ def to_dict(self):
51
+ """Returns the dictionary representation of the model using alias"""
52
+ _dict = self.dict(by_alias=True, exclude={}, exclude_none=True)
53
+ return _dict
54
+
55
+ @classmethod
56
+ def from_dict(cls, obj: dict) -> GetArtifactVersionAliasesResponseDto:
57
+ """Create an instance of GetArtifactVersionAliasesResponseDto from a dict"""
58
+ if obj is None:
59
+ return None
60
+
61
+ if not isinstance(obj, dict):
62
+ return GetArtifactVersionAliasesResponseDto.parse_obj(obj)
63
+
64
+ _obj = GetArtifactVersionAliasesResponseDto.parse_obj(
65
+ {"version_aliases": obj.get("version_aliases")}
66
+ )
67
+ return _obj
@@ -46,6 +46,10 @@ class ModelVersionManifest(BaseModel):
46
46
  default=...,
47
47
  description="+label=Metadata +docs=Metadata for the artifact or model version +usage=Metadata for the artifact or model version +uiType=JsonInput",
48
48
  )
49
+ version_alias: Optional[constr(strict=True, max_length=128)] = Field(
50
+ default=None,
51
+ description="+label=Version Alias +usage=The version alias for artifact or model version which should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc) +docs=The version alias for artifact or model version which should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc) +message=The version alias should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc)",
52
+ )
49
53
  type: Optional[StrictStr] = "model-version"
50
54
  source: Source1 = Field(...)
51
55
  framework: Optional[Framework] = None
@@ -56,6 +60,7 @@ class ModelVersionManifest(BaseModel):
56
60
  __properties = [
57
61
  "description",
58
62
  "metadata",
63
+ "version_alias",
59
64
  "type",
60
65
  "source",
61
66
  "framework",
@@ -63,6 +68,18 @@ class ModelVersionManifest(BaseModel):
63
68
  "step",
64
69
  ]
65
70
 
71
+ @validator("version_alias")
72
+ def version_alias_validate_regular_expression(cls, value):
73
+ """Validates the regular expression"""
74
+ if value is None:
75
+ return value
76
+
77
+ if not re.match(r"^v[a-zA-Z0-9.-]*([a-zA-Z0-9]+)$", value):
78
+ raise ValueError(
79
+ r"must validate the regular expression /^v[a-zA-Z0-9.-]*([a-zA-Z0-9]+)$/"
80
+ )
81
+ return value
82
+
66
83
  @validator("type")
67
84
  def type_validate_enum(cls, value):
68
85
  """Validates the enum"""
@@ -119,6 +136,7 @@ class ModelVersionManifest(BaseModel):
119
136
  {
120
137
  "description": obj.get("description"),
121
138
  "metadata": obj.get("metadata"),
139
+ "version_alias": obj.get("version_alias"),
122
140
  "type": obj.get("type")
123
141
  if obj.get("type") is not None
124
142
  else "model-version",
@@ -121,6 +121,7 @@ Class | Method | HTTP request | Description
121
121
  *MlfoundryArtifactsApi* | [**get_signed_urls_for_dataset_write_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#get_signed_urls_for_dataset_write_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/datasets/get-signed-urls-for-write | Get Signed Urls For Dataset Write
122
122
  *MlfoundryArtifactsApi* | [**get_signed_urls_for_read_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#get_signed_urls_for_read_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifact-versions/get-signed-urls-for-read | Get Signed Urls For Read
123
123
  *MlfoundryArtifactsApi* | [**get_signed_urls_for_write_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#get_signed_urls_for_write_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifact-versions/get-signed-urls-for-write | Get Signed Urls For Write
124
+ *MlfoundryArtifactsApi* | [**get_version_aliases_for_artifact_get**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#get_version_aliases_for_artifact_get) | **GET** /api/2.0/mlflow/mlfoundry-artifacts/artifacts/get-version-aliases | Get Version Aliases For Artifact
124
125
  *MlfoundryArtifactsApi* | [**list_artifact_versions_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#list_artifact_versions_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifact-versions/list | List Artifact Versions
125
126
  *MlfoundryArtifactsApi* | [**list_artifacts_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#list_artifacts_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifacts/list | List Artifacts
126
127
  *MlfoundryArtifactsApi* | [**list_datasets_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#list_datasets_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/datasets/list | List Datasets
@@ -219,6 +220,7 @@ Class | Method | HTTP request | Description
219
220
  - [FileInfoDto](truefoundry/ml/autogen/client/docs/FileInfoDto.md)
220
221
  - [FinalizeArtifactVersionRequestDto](truefoundry/ml/autogen/client/docs/FinalizeArtifactVersionRequestDto.md)
221
222
  - [Framework](truefoundry/ml/autogen/client/docs/Framework.md)
223
+ - [GetArtifactVersionAliasesResponseDto](truefoundry/ml/autogen/client/docs/GetArtifactVersionAliasesResponseDto.md)
222
224
  - [GetExperimentResponseDto](truefoundry/ml/autogen/client/docs/GetExperimentResponseDto.md)
223
225
  - [GetLatestRunLogResponseDto](truefoundry/ml/autogen/client/docs/GetLatestRunLogResponseDto.md)
224
226
  - [GetMetricHistoryResponse](truefoundry/ml/autogen/client/docs/GetMetricHistoryResponse.md)
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: artifacts.json
3
- # timestamp: 2024-12-09T09:04:12+00:00
3
+ # timestamp: 2025-01-03T09:11:54+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -58,6 +58,12 @@ class BaseArtifactVersion(BaseModel):
58
58
  ...,
59
59
  description="+label=Metadata\n+docs=Metadata for the artifact or model version\n+usage=Metadata for the artifact or model version\n+uiType=JsonInput",
60
60
  )
61
+ version_alias: Optional[
62
+ constr(regex=r"^v[a-zA-Z0-9.-]*([a-zA-Z0-9]+)$", max_length=128)
63
+ ] = Field(
64
+ None,
65
+ description="+label=Version Alias\n+usage=The version alias for artifact or model version which should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc)\n+docs=The version alias for artifact or model version which should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc)\n+message=The version alias should start with 'v' followed by alphanumeric and it can include '.' and '-' in between (e.g. v1.0.0, v-prod, v-dev, etc)",
66
+ )
61
67
 
62
68
 
63
69
  class MimeType(str, Enum):
@@ -1,36 +1,57 @@
1
- from typing import Optional
1
+ import functools
2
2
 
3
3
  from truefoundry.common.constants import (
4
4
  SERVICEFOUNDRY_CLIENT_MAX_RETRIES,
5
5
  VERSION_PREFIX,
6
6
  )
7
+ from truefoundry.common.exceptions import HttpRequestException
8
+ from truefoundry.common.request_utils import (
9
+ http_request,
10
+ request_handling,
11
+ requests_retry_session,
12
+ )
7
13
  from truefoundry.common.servicefoundry_client import (
8
14
  ServiceFoundryServiceClient as BaseServiceFoundryServiceClient,
9
15
  )
10
- from truefoundry.ml.clients.entities import (
11
- HostCreds,
12
- )
13
- from truefoundry.ml.clients.utils import http_request_safe
14
16
  from truefoundry.ml.exceptions import MlFoundryException
15
17
 
16
18
 
17
19
  class ServiceFoundryServiceClient(BaseServiceFoundryServiceClient):
18
- # TODO (chiragjn): Rename tracking_uri to tfy_host
19
- def __init__(self, tracking_uri: str, token: Optional[str] = None):
20
- super().__init__(base_url=tracking_uri)
21
- self.host_creds = HostCreds(host=self._api_server_url, token=token)
20
+ def __init__(self, tfy_host: str, token: str):
21
+ super().__init__(tfy_host=tfy_host)
22
+ self._token = token
23
+
24
+ @functools.cached_property
25
+ def _min_cli_version_required(self) -> str:
26
+ # TODO (chiragjn): read the mlfoundry min cli version from the config?
27
+ return self.python_sdk_config.truefoundry_cli_min_version
22
28
 
23
29
  def get_integration_from_id(self, integration_id: str):
24
30
  integration_id = integration_id or ""
25
- response = http_request_safe(
26
- host_creds=self.host_creds,
27
- endpoint=f"{VERSION_PREFIX}/provider-accounts/provider-integrations",
28
- params={"id": integration_id, "type": "blob-storage"},
31
+ session = requests_retry_session(retries=SERVICEFOUNDRY_CLIENT_MAX_RETRIES)
32
+ response = http_request(
29
33
  method="get",
34
+ url=f"{self._api_server_url}/{VERSION_PREFIX}/provider-accounts/provider-integrations",
35
+ token=self._token,
30
36
  timeout=3,
31
- max_retries=SERVICEFOUNDRY_CLIENT_MAX_RETRIES,
37
+ params={"id": integration_id, "type": "blob-storage"},
38
+ session=session,
32
39
  )
33
- data = response.json()
40
+
41
+ try:
42
+ data = request_handling(response)
43
+ assert isinstance(data, dict)
44
+ except HttpRequestException as he:
45
+ raise MlFoundryException(
46
+ f"Failed to get storage integration from id: {integration_id}. Error: {he.message}",
47
+ status_code=he.status_code,
48
+ ) from None
49
+ except Exception as e:
50
+ raise MlFoundryException(
51
+ f"Failed to get storage integration from id: {integration_id}. Error: {str(e)}"
52
+ ) from None
53
+
54
+ # TODO (chiragjn): Parse this using Pydantic
34
55
  if (
35
56
  data.get("providerIntegrations")
36
57
  and len(data["providerIntegrations"]) > 0
@@ -1,8 +1,9 @@
1
1
  from typing import Optional
2
2
 
3
3
 
4
+ # TODO (chiragjn): We need to establish uniform exception handling across codebase
4
5
  class MlFoundryException(Exception):
5
- def __init__(self, message, status_code: Optional[int] = None):
6
+ def __init__(self, message: str, status_code: Optional[int] = None):
6
7
  self.message = str(message)
7
8
  self.status_code = status_code
8
9
  super().__init__(message)
@@ -5,11 +5,11 @@ import os
5
5
  import tempfile
6
6
  import typing
7
7
  import uuid
8
+ import warnings
8
9
  from pathlib import Path
9
10
  from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Union
10
11
 
11
- from pydantic import StrictStr
12
-
12
+ from truefoundry.common.warnings import TrueFoundryDeprecationWarning
13
13
  from truefoundry.ml.artifact.truefoundry_artifact_repo import (
14
14
  ArtifactIdentifier,
15
15
  MlFoundryArtifactsRepository,
@@ -43,7 +43,7 @@ from truefoundry.ml.log_types.artifacts.utils import (
43
43
  )
44
44
  from truefoundry.ml.logger import logger
45
45
  from truefoundry.ml.session import _get_api_client
46
- from truefoundry.pydantic_v1 import BaseModel, Extra
46
+ from truefoundry.pydantic_v1 import BaseModel, Extra, StrictStr
47
47
 
48
48
  if TYPE_CHECKING:
49
49
  from truefoundry.ml.mlfoundry_run import MlFoundryRun
@@ -84,6 +84,7 @@ class ArtifactVersion:
84
84
  self._deleted = False
85
85
  self._description: str = ""
86
86
  self._metadata: Dict[str, Any] = {}
87
+ self._version_alias: Optional[str] = None
87
88
  self._set_mutable_attrs()
88
89
 
89
90
  @classmethod
@@ -131,9 +132,13 @@ class ArtifactVersion:
131
132
  manifest = self._artifact_version.manifest.actual_instance
132
133
  self._description = manifest.description or ""
133
134
  self._metadata = copy.deepcopy(manifest.metadata)
135
+ self._version_alias = manifest.version_alias or None
134
136
  else:
135
137
  self._description = self._artifact_version.description or ""
136
- self._metadata = copy.deepcopy(self._artifact_version.artifact_metadata)
138
+ self._metadata = copy.deepcopy(
139
+ self._artifact_version.artifact_metadata or {}
140
+ )
141
+ self._version_alias = None
137
142
 
138
143
  def _refetch_artifact_version(self, reset_mutable_attrs: bool = True):
139
144
  _artifact_version = (
@@ -205,6 +210,33 @@ class ArtifactVersion:
205
210
  _validate_artifact_metadata(value)
206
211
  self._metadata = copy.deepcopy(value)
207
212
 
213
+ @property
214
+ def version_alias(self) -> Optional[str]:
215
+ """
216
+ Get version alias for the current artifact version
217
+ """
218
+ if not self._artifact_version.manifest:
219
+ warnings.warn(
220
+ message="This artifact version was created using an older serialization format. version alias does not exist",
221
+ category=TrueFoundryDeprecationWarning,
222
+ stacklevel=2,
223
+ )
224
+ return self._version_alias
225
+
226
+ @version_alias.setter
227
+ def version_alias(self, value: Optional[str]):
228
+ """
229
+ Set the version alias for current artifact version
230
+ """
231
+ if not self._artifact_version.manifest:
232
+ warnings.warn(
233
+ message="This artifact version was created using an older serialization format. version alias will not be updated",
234
+ category=TrueFoundryDeprecationWarning,
235
+ stacklevel=2,
236
+ )
237
+ return
238
+ self._version_alias = value
239
+
208
240
  @property
209
241
  def created_at(self) -> Optional[datetime.datetime]:
210
242
  """Get the time at which artifact was created"""
@@ -367,6 +399,7 @@ class ArtifactVersion:
367
399
  assert isinstance(manifest, ArtifactVersionManifest)
368
400
  manifest.description = self.description
369
401
  manifest.metadata = self.metadata
402
+ manifest.version_alias = self.version_alias
370
403
  else:
371
404
  manifest = None
372
405
  try:
@@ -10,6 +10,7 @@ import warnings
10
10
  from pathlib import Path
11
11
  from typing import TYPE_CHECKING, Any, Dict, Optional, Union
12
12
 
13
+ from truefoundry.common.warnings import TrueFoundryDeprecationWarning
13
14
  from truefoundry.ml.artifact.truefoundry_artifact_repo import (
14
15
  ArtifactIdentifier,
15
16
  MlFoundryArtifactsRepository,
@@ -52,7 +53,7 @@ from truefoundry.ml.model_framework import (
52
53
  auto_update_model_framework_details,
53
54
  )
54
55
  from truefoundry.ml.session import _get_api_client
55
- from truefoundry.pydantic_v1 import BaseModel, Extra
56
+ from truefoundry.pydantic_v1 import BaseModel, Extra, parse_obj_as
56
57
 
57
58
  if TYPE_CHECKING:
58
59
  import numpy as np
@@ -108,6 +109,7 @@ class ModelVersion:
108
109
  self._metadata: Dict[str, Any] = {}
109
110
  self._environment: Optional[ModelVersionEnvironment] = None
110
111
  self._framework: Optional[ModelFrameworkType] = None
112
+ self._version_alias: Optional[str] = None
111
113
  self._set_mutable_attrs()
112
114
 
113
115
  @classmethod
@@ -147,21 +149,26 @@ class ModelVersion:
147
149
 
148
150
  def _set_mutable_attrs(self):
149
151
  if self._model_version.manifest:
150
- self._description = self._model_version.manifest.description or ""
151
- self._metadata = copy.deepcopy(self._model_version.manifest.metadata)
152
- self._environment = copy.deepcopy(self._model_version.manifest.environment)
152
+ manifest = self._model_version.manifest
153
+ self._description = manifest.description or ""
154
+ self._metadata = copy.deepcopy(manifest.metadata)
155
+ self._environment = copy.deepcopy(manifest.environment)
153
156
  self._framework = (
154
- copy.deepcopy(self._model_version.manifest.framework.actual_instance)
155
- if self._model_version.manifest.framework
157
+ parse_obj_as(
158
+ ModelFrameworkType, manifest.framework.actual_instance.to_dict()
159
+ )
160
+ if manifest.framework
156
161
  else None
157
162
  )
163
+ self._version_alias = self._model_version.manifest.version_alias or None
158
164
  else:
159
165
  self._description = self._model_version.description or ""
160
- self._metadata = copy.deepcopy(self._model_version.artifact_metadata)
166
+ self._metadata = copy.deepcopy(self._model_version.artifact_metadata or {})
161
167
  self._environment = None
162
168
  self._framework = _ModelFramework.to_model_framework_type(
163
169
  self._model_version.model_framework
164
170
  )
171
+ self._version_alias = None
165
172
 
166
173
  def _refetch_model_version(self, reset_mutable_attrs: bool = True):
167
174
  _model_version = self._mlfoundry_artifacts_api.get_model_version_get(
@@ -231,18 +238,51 @@ class ModelVersion:
231
238
  _validate_artifact_metadata(value)
232
239
  self._metadata = copy.deepcopy(value)
233
240
 
241
+ @property
242
+ def version_alias(self) -> Optional[str]:
243
+ """
244
+ Get version alias for the current model version
245
+ """
246
+ if not self._model_version.manifest:
247
+ warnings.warn(
248
+ message="This model version was created using an older serialization format. version alias does not exist",
249
+ category=TrueFoundryDeprecationWarning,
250
+ stacklevel=2,
251
+ )
252
+ return self._version_alias
253
+
254
+ @version_alias.setter
255
+ def version_alias(self, value: Optional[str]):
256
+ """
257
+ Set the version alias for current artifact version
258
+ """
259
+ if not self._model_version.manifest:
260
+ warnings.warn(
261
+ message="This model version was created using an older serialization format. version alias will not be updated",
262
+ category=TrueFoundryDeprecationWarning,
263
+ stacklevel=2,
264
+ )
265
+ return
266
+ self._version_alias = value
267
+
234
268
  @property
235
269
  def environment(self) -> Optional[ModelVersionEnvironment]:
236
270
  """Get the environment details for the model"""
271
+ if not self._model_version.manifest:
272
+ warnings.warn(
273
+ message="This model version was created using an older serialization format. environment does not exist, returning None",
274
+ category=TrueFoundryDeprecationWarning,
275
+ stacklevel=2,
276
+ )
237
277
  return self._environment
238
278
 
239
279
  @environment.setter
240
- def environment(self, value: Optional[Dict[str, Any]]):
280
+ def environment(self, value: Optional[ModelVersionEnvironment]):
241
281
  """set the environment details for the model"""
242
282
  if not self._model_version.manifest:
243
283
  warnings.warn(
244
284
  message="This model version was created using an older serialization format. Environment will not be updated",
245
- category=DeprecationWarning,
285
+ category=TrueFoundryDeprecationWarning,
246
286
  stacklevel=2,
247
287
  )
248
288
  return
@@ -261,7 +301,7 @@ class ModelVersion:
261
301
  if not self._model_version.manifest:
262
302
  warnings.warn(
263
303
  message="This model version was created using an older serialization format. Framework will not be updated",
264
- category=DeprecationWarning,
304
+ category=TrueFoundryDeprecationWarning,
265
305
  stacklevel=2,
266
306
  )
267
307
  return
@@ -449,6 +489,7 @@ class ModelVersion:
449
489
  self._model_version.manifest.framework = (
450
490
  Framework.from_dict(self.framework.dict()) if self.framework else None
451
491
  )
492
+ self._model_version.manifest.version_alias = self.version_alias
452
493
  try:
453
494
  _model_version = self._mlfoundry_artifacts_api.update_model_version_post(
454
495
  update_model_version_request_dto=UpdateModelVersionRequestDto(