truefoundry 0.5.0rc3__py3-none-any.whl → 0.5.0rc5__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 (27) hide show
  1. truefoundry/deploy/v2/lib/deploy_workflow.py +8 -2
  2. truefoundry/ml/__init__.py +6 -3
  3. truefoundry/ml/autogen/client/__init__.py +9 -4
  4. truefoundry/ml/autogen/client/models/__init__.py +9 -4
  5. truefoundry/ml/autogen/client/models/artifact_version_dto.py +3 -5
  6. truefoundry/ml/autogen/client/models/artifact_version_manifest.py +111 -0
  7. truefoundry/ml/autogen/client/models/{external_model_source.py → external_artifact_source.py} +8 -8
  8. truefoundry/ml/autogen/client/models/finalize_artifact_version_request_dto.py +3 -5
  9. truefoundry/ml/autogen/client/models/manifest.py +154 -0
  10. truefoundry/ml/autogen/client/models/model_version_manifest.py +17 -4
  11. truefoundry/ml/autogen/client/models/source.py +23 -23
  12. truefoundry/ml/autogen/client/models/source1.py +154 -0
  13. truefoundry/ml/autogen/client/models/transformers_framework.py +6 -1
  14. truefoundry/ml/autogen/client/models/{truefoundry_model_source.py → true_foundry_artifact_source.py} +9 -9
  15. truefoundry/ml/autogen/client/models/update_artifact_version_request_dto.py +11 -1
  16. truefoundry/ml/autogen/client_README.md +5 -2
  17. truefoundry/ml/autogen/entities/artifacts.py +26 -8
  18. truefoundry/ml/log_types/artifacts/artifact.py +131 -63
  19. truefoundry/ml/log_types/artifacts/general_artifact.py +7 -26
  20. truefoundry/ml/log_types/artifacts/model.py +99 -81
  21. truefoundry/ml/mlfoundry_api.py +6 -4
  22. truefoundry/ml/mlfoundry_run.py +10 -5
  23. truefoundry/ml/model_framework.py +2 -2
  24. {truefoundry-0.5.0rc3.dist-info → truefoundry-0.5.0rc5.dist-info}/METADATA +2 -2
  25. {truefoundry-0.5.0rc3.dist-info → truefoundry-0.5.0rc5.dist-info}/RECORD +27 -24
  26. {truefoundry-0.5.0rc3.dist-info → truefoundry-0.5.0rc5.dist-info}/WHEEL +0 -0
  27. {truefoundry-0.5.0rc3.dist-info → truefoundry-0.5.0rc5.dist-info}/entry_points.txt +0 -0
@@ -3,9 +3,12 @@ import datetime
3
3
  import json
4
4
  import os
5
5
  import tempfile
6
+ import typing
6
7
  import uuid
7
8
  from pathlib import Path
8
- from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Tuple, Union
9
+ from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Union
10
+
11
+ from pydantic import StrictStr
9
12
 
10
13
  from truefoundry.ml.artifact.truefoundry_artifact_repo import (
11
14
  ArtifactIdentifier,
@@ -15,11 +18,15 @@ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
15
18
  ArtifactDto,
16
19
  ArtifactType,
17
20
  ArtifactVersionDto,
21
+ ArtifactVersionManifest,
18
22
  CreateArtifactVersionRequestDto,
19
23
  DeleteArtifactVersionsRequestDto,
24
+ ExternalArtifactSource,
20
25
  FinalizeArtifactVersionRequestDto,
26
+ Manifest,
21
27
  MlfoundryArtifactsApi,
22
28
  NotifyArtifactVersionFailureDto,
29
+ TrueFoundryArtifactSource,
23
30
  UpdateArtifactVersionRequestDto,
24
31
  )
25
32
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
@@ -47,6 +54,10 @@ class ArtifactPath(NamedTuple):
47
54
  dest: Optional[str] = None
48
55
 
49
56
 
57
+ class BlobStorageDirectory(BaseModel):
58
+ uri: StrictStr
59
+
60
+
50
61
  class ArtifactVersionInternalMetadata(BaseModel):
51
62
  class Config:
52
63
  extra = Extra.allow
@@ -56,7 +67,6 @@ class ArtifactVersionInternalMetadata(BaseModel):
56
67
 
57
68
  class ArtifactVersionDownloadInfo(BaseModel):
58
69
  download_dir: str
59
- content_dir: str
60
70
 
61
71
 
62
72
  class ArtifactVersion:
@@ -116,16 +126,24 @@ class ArtifactVersion:
116
126
  "Artifact Version was deleted, cannot access a deleted version"
117
127
  )
118
128
 
119
- def _set_mutable_attrs(self, refetch=False):
120
- if refetch:
121
- _artifact_version = (
122
- self._mlfoundry_artifacts_api.get_artifact_version_by_id_get(
123
- id=self._artifact_version.id
124
- )
129
+ def _set_mutable_attrs(self):
130
+ if self._artifact_version.manifest:
131
+ manifest = self._artifact_version.manifest.actual_instance
132
+ self._description = manifest.description or ""
133
+ self._metadata = copy.deepcopy(manifest.metadata)
134
+ else:
135
+ self._description = self._artifact_version.description or ""
136
+ self._metadata = copy.deepcopy(self._artifact_version.artifact_metadata)
137
+
138
+ def _refetch_artifact_version(self, reset_mutable_attrs: bool = True):
139
+ _artifact_version = (
140
+ self._mlfoundry_artifacts_api.get_artifact_version_by_id_get(
141
+ id=self._artifact_version.id
125
142
  )
126
- self._artifact_version = _artifact_version.artifact_version
127
- self._description = self._artifact_version.description or ""
128
- self._metadata = copy.deepcopy(self._artifact_version.artifact_metadata)
143
+ )
144
+ self._artifact_version = _artifact_version.artifact_version
145
+ if reset_mutable_attrs:
146
+ self._set_mutable_attrs()
129
147
 
130
148
  def __repr__(self):
131
149
  return f"{self.__class__.__name__}(fqn={self.fqn!r})"
@@ -159,12 +177,14 @@ class ArtifactVersion:
159
177
  return self._artifact_version.fqn
160
178
 
161
179
  @property
162
- def step(self) -> int:
180
+ def step(self) -> Optional[int]:
163
181
  """Get the step in which artifact was created"""
182
+ if self._artifact_version.manifest:
183
+ return self._artifact_version.manifest.actual_instance.step
164
184
  return self._artifact_version.step
165
185
 
166
186
  @property
167
- def description(self) -> Optional[str]:
187
+ def description(self) -> str:
168
188
  """Get description of the artifact"""
169
189
  return self._description
170
190
 
@@ -183,15 +203,15 @@ class ArtifactVersion:
183
203
  def metadata(self, value: Dict[str, Any]):
184
204
  """set the metadata for current artifact"""
185
205
  _validate_artifact_metadata(value)
186
- self._metadata = value
206
+ self._metadata = copy.deepcopy(value)
187
207
 
188
208
  @property
189
- def created_at(self) -> datetime.datetime:
209
+ def created_at(self) -> Optional[datetime.datetime]:
190
210
  """Get the time at which artifact was created"""
191
211
  return self._artifact_version.created_at
192
212
 
193
213
  @property
194
- def updated_at(self) -> datetime.datetime:
214
+ def updated_at(self) -> Optional[datetime.datetime]:
195
215
  """Get the information about when the artifact was updated"""
196
216
  return self._artifact_version.updated_at
197
217
 
@@ -240,11 +260,17 @@ class ArtifactVersion:
240
260
  path: Optional[Union[str, Path]],
241
261
  overwrite: bool = False,
242
262
  progress: Optional[bool] = None,
243
- ) -> Tuple[ArtifactVersionInternalMetadata, str]:
263
+ ) -> ArtifactVersionDownloadInfo:
244
264
  self._ensure_not_deleted()
245
265
  download_dir = self.raw_download(
246
266
  path=path, overwrite=overwrite, progress=progress
247
267
  )
268
+ if self._artifact_version.manifest:
269
+ download_info = ArtifactVersionDownloadInfo(
270
+ download_dir=download_dir,
271
+ )
272
+ return download_info
273
+
248
274
  internal_metadata_path = os.path.join(download_dir, INTERNAL_METADATA_PATH)
249
275
  if not os.path.exists(internal_metadata_path):
250
276
  raise MlFoundryException(
@@ -254,7 +280,7 @@ class ArtifactVersion:
254
280
  with open(internal_metadata_path) as f:
255
281
  internal_metadata = ArtifactVersionInternalMetadata.parse_obj(json.load(f))
256
282
  download_path = os.path.join(download_dir, internal_metadata.files_dir)
257
- return internal_metadata, download_path
283
+ return ArtifactVersionDownloadInfo(download_dir=download_path)
258
284
 
259
285
  def download(
260
286
  self,
@@ -289,10 +315,10 @@ class ArtifactVersion:
289
315
  artifact_version.download(path="<your-desired-download-path>")
290
316
  ```
291
317
  """
292
- _, download_path = self._download(
318
+ download_path = self._download(
293
319
  path=path, overwrite=overwrite, progress=progress
294
320
  )
295
- return download_path
321
+ return download_path.download_dir
296
322
 
297
323
  def delete(self) -> bool:
298
324
  """
@@ -336,16 +362,31 @@ class ArtifactVersion:
336
362
  ```
337
363
  """
338
364
  self._ensure_not_deleted()
339
-
340
- _artifact_version = self._mlfoundry_artifacts_api.update_artifact_version_post(
341
- update_artifact_version_request_dto=UpdateArtifactVersionRequestDto(
342
- id=self._artifact_version.id,
343
- description=self.description,
344
- artifact_metadata=self.metadata,
365
+ if self._artifact_version.manifest:
366
+ manifest = self._artifact_version.manifest.actual_instance
367
+ assert isinstance(manifest, ArtifactVersionManifest)
368
+ manifest.description = self.description
369
+ manifest.metadata = self.metadata
370
+ else:
371
+ manifest = None
372
+ try:
373
+ _artifact_version = (
374
+ self._mlfoundry_artifacts_api.update_artifact_version_post(
375
+ update_artifact_version_request_dto=UpdateArtifactVersionRequestDto(
376
+ id=self._artifact_version.id,
377
+ description=self.description,
378
+ artifact_metadata=self.metadata,
379
+ manifest=manifest,
380
+ )
381
+ )
345
382
  )
346
- )
347
- self._artifact_version = _artifact_version.artifact_version
348
- self._set_mutable_attrs()
383
+ except Exception:
384
+ # rollback edits to internal object
385
+ self._refetch_artifact_version(reset_mutable_attrs=False)
386
+ raise
387
+ else:
388
+ self._artifact_version = _artifact_version.artifact_version
389
+ self._set_mutable_attrs()
349
390
 
350
391
 
351
392
  class ChatPromptVersion(ArtifactVersion):
@@ -404,12 +445,15 @@ class ChatPromptVersion(ArtifactVersion):
404
445
  def variables(self) -> Dict[str, Any]:
405
446
  return self._chat_prompt.variables or {}
406
447
 
448
+ def update(self):
449
+ raise NotImplementedError("ChatPromptVersion does not support update operation")
450
+
407
451
 
408
452
  def _log_artifact_version_helper(
409
- run: "MlFoundryRun",
453
+ run: Optional["MlFoundryRun"],
410
454
  name: str,
411
455
  artifact_type: ArtifactType,
412
- artifact_dir: tempfile.TemporaryDirectory,
456
+ artifact_dir: Union[tempfile.TemporaryDirectory, BlobStorageDirectory],
413
457
  dest_to_src_map: Dict[str, str],
414
458
  mlfoundry_artifacts_api: Optional[MlfoundryArtifactsApi] = None,
415
459
  ml_repo_id: Optional[str] = None,
@@ -439,48 +483,72 @@ def _log_artifact_version_helper(
439
483
  )
440
484
  )
441
485
  version_id = _create_artifact_response.id
442
- artifacts_repo = MlFoundryArtifactsRepository(
443
- artifact_identifier=ArtifactIdentifier(
444
- artifact_version_id=uuid.UUID(version_id),
445
- ),
446
- api_client=mlfoundry_artifacts_api.api_client,
447
- )
448
-
449
- total_size = calculate_total_size(list(dest_to_src_map.values()))
450
- try:
451
- logger.info(
452
- "Packaging and uploading files to remote with size: %.6f MB",
453
- total_size / 1000000.0,
486
+ artifact_storage_root = _create_artifact_response.artifact_storage_root
487
+ if isinstance(artifact_dir, tempfile.TemporaryDirectory):
488
+ # Source is of type TrueFoundryArtifactSource
489
+ source = TrueFoundryArtifactSource(
490
+ type="truefoundry", uri=artifact_storage_root
454
491
  )
455
- src_dest_pairs = _get_src_dest_pairs(
456
- root_dir=artifact_dir.name, dest_to_src_map=dest_to_src_map
492
+ artifacts_repo = MlFoundryArtifactsRepository(
493
+ artifact_identifier=ArtifactIdentifier(
494
+ artifact_version_id=uuid.UUID(version_id),
495
+ ),
496
+ api_client=mlfoundry_artifacts_api.api_client,
457
497
  )
458
- artifacts_repo.log_artifacts(src_dest_pairs=src_dest_pairs, progress=progress)
459
- except Exception as e:
460
- mlfoundry_artifacts_api.notify_failure_post(
461
- notify_artifact_version_failure_dto=NotifyArtifactVersionFailureDto(
462
- id=version_id
498
+
499
+ total_size = calculate_total_size(list(dest_to_src_map.values()))
500
+ try:
501
+ logger.info(
502
+ "Packaging and uploading files to remote with size: %.6f MB",
503
+ total_size / 1000000.0,
504
+ )
505
+ src_dest_pairs = _get_src_dest_pairs(
506
+ root_dir=artifact_dir.name, dest_to_src_map=dest_to_src_map
507
+ )
508
+ artifacts_repo.log_artifacts(
509
+ src_dest_pairs=src_dest_pairs, progress=progress
463
510
  )
511
+ except Exception as e:
512
+ mlfoundry_artifacts_api.notify_failure_post(
513
+ notify_artifact_version_failure_dto=NotifyArtifactVersionFailureDto(
514
+ id=version_id
515
+ )
516
+ )
517
+ raise MlFoundryException("Failed to log Artifact") from e
518
+ finally:
519
+ artifact_dir.cleanup()
520
+
521
+ # Note: Here we call from_dict instead of directly passing in init and relying on it
522
+ # to convert because the complicated union of types generates a custom type to handle casting
523
+ # Check the source of `InternalMetadataDto` to see the generated code
524
+ internal_metadata_dto = InternalMetadataDto.from_dict(
525
+ internal_metadata.dict() if internal_metadata is not None else {}
526
+ )
527
+ elif isinstance(artifact_dir, BlobStorageDirectory):
528
+ source = ExternalArtifactSource(type="external", uri=artifact_dir.uri)
529
+ else:
530
+ raise MlFoundryException("Invalid artifact_dir provided")
531
+
532
+ artifact_manifest = None
533
+ if artifact_type == ArtifactType.ARTIFACT:
534
+ _source_cls = typing.get_type_hints(ArtifactVersionManifest)["source"]
535
+ artifact_manifest = ArtifactVersionManifest(
536
+ description=description,
537
+ metadata=metadata or {},
538
+ source=_source_cls.from_dict(source.dict()),
539
+ step=step,
464
540
  )
465
- raise MlFoundryException("Failed to log Artifact") from e
466
- finally:
467
- artifact_dir.cleanup()
468
-
469
- # Note: Here we call from_dict instead of directly passing in init and relying on it
470
- # to convert because the complicated union of types generates a custom type to handle casting
471
- # Check the source of `InternalMetadataDto` to see the generated code
472
- internal_metadata_dto = InternalMetadataDto.from_dict(
473
- internal_metadata.dict() if internal_metadata is not None else {}
474
- )
475
541
  finalize_artifact_version_request_dto = FinalizeArtifactVersionRequestDto(
476
542
  id=version_id,
477
543
  run_uuid=run.run_id if run else None,
478
- description=description,
479
- internal_metadata=internal_metadata_dto,
544
+ internal_metadata=internal_metadata_dto if internal_metadata else None,
480
545
  artifact_metadata=metadata,
481
- data_path=INTERNAL_METADATA_PATH,
546
+ data_path=INTERNAL_METADATA_PATH if internal_metadata else None,
482
547
  step=step,
483
548
  artifact_size=total_size,
549
+ manifest=Manifest.from_dict(artifact_manifest.to_dict())
550
+ if artifact_manifest
551
+ else None,
484
552
  )
485
553
  _artifact_version = mlfoundry_artifacts_api.finalize_artifact_version_post(
486
554
  finalize_artifact_version_request_dto=finalize_artifact_version_request_dto
@@ -1,8 +1,6 @@
1
1
  import collections
2
- import json
3
- import os.path
4
2
  import tempfile
5
- from typing import Any, Dict, List, Optional, Tuple, Union
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
6
4
 
7
5
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
8
6
  ArtifactType,
@@ -12,13 +10,8 @@ from truefoundry.ml.exceptions import MlFoundryException
12
10
  from truefoundry.ml.log_types.artifacts.artifact import (
13
11
  ArtifactPath,
14
12
  ArtifactVersion,
15
- ArtifactVersionInternalMetadata,
16
13
  _log_artifact_version_helper,
17
14
  )
18
- from truefoundry.ml.log_types.artifacts.constants import (
19
- FILES_DIR,
20
- INTERNAL_METADATA_PATH,
21
- )
22
15
  from truefoundry.ml.log_types.artifacts.utils import (
23
16
  _copy_additional_files,
24
17
  _validate_artifact_metadata,
@@ -26,9 +19,12 @@ from truefoundry.ml.log_types.artifacts.utils import (
26
19
  )
27
20
  from truefoundry.ml.logger import logger
28
21
 
22
+ if TYPE_CHECKING:
23
+ from truefoundry.ml.mlfoundry_run import MlFoundryRun
24
+
29
25
 
30
26
  def _log_artifact_version(
31
- run,
27
+ run: Optional["MlFoundryRun"],
32
28
  name: str,
33
29
  artifact_paths: List[Union[ArtifactPath, Tuple[str, Optional[str]], Tuple[str]]],
34
30
  mlfoundry_artifacts_api: Optional[MlfoundryArtifactsApi] = None,
@@ -68,18 +64,10 @@ def _log_artifact_version(
68
64
  logger.info("Logging the artifact, this might take a while ...")
69
65
  temp_dir = tempfile.TemporaryDirectory(prefix="truefoundry-")
70
66
 
71
- internal_metadata = ArtifactVersionInternalMetadata(
72
- files_dir=FILES_DIR,
73
- )
74
-
75
67
  try:
76
- local_files_dir = os.path.join(temp_dir.name, internal_metadata.files_dir)
77
- os.makedirs(local_files_dir, exist_ok=True)
78
-
79
- logger.info("Copying the files to log")
80
68
  temp_dest_to_src_map = _copy_additional_files(
81
69
  root_dir=temp_dir.name,
82
- files_dir=internal_metadata.files_dir,
70
+ files_dir="",
83
71
  model_dir=None,
84
72
  additional_files=artifact_paths,
85
73
  )
@@ -89,13 +77,6 @@ def _log_artifact_version(
89
77
  temp_dir.cleanup()
90
78
  raise MlFoundryException("Failed to log artifact") from e
91
79
 
92
- # save internal metadata
93
- local_internal_metadata_path = os.path.join(temp_dir.name, INTERNAL_METADATA_PATH)
94
- os.makedirs(os.path.dirname(local_internal_metadata_path), exist_ok=True)
95
- with open(local_internal_metadata_path, "w") as f:
96
- json.dump(internal_metadata.dict(), f)
97
- temp_dest_to_src_map[local_internal_metadata_path] = local_internal_metadata_path
98
-
99
80
  return _log_artifact_version_helper(
100
81
  run=run,
101
82
  ml_repo_id=ml_repo_id,
@@ -105,7 +86,7 @@ def _log_artifact_version(
105
86
  dest_to_src_map=temp_dest_to_src_map,
106
87
  mlfoundry_artifacts_api=mlfoundry_artifacts_api,
107
88
  description=description,
108
- internal_metadata=internal_metadata,
89
+ internal_metadata=None,
109
90
  metadata=metadata,
110
91
  step=step,
111
92
  progress=progress,