truefoundry 0.3.3__py3-none-any.whl → 0.4.0.dev1__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 (225) hide show
  1. truefoundry/cli/__main__.py +3 -17
  2. truefoundry/common/__init__.py +0 -0
  3. truefoundry/common/request_utils.py +56 -0
  4. truefoundry/deploy/cli/cli.py +1 -1
  5. truefoundry/deploy/cli/util.py +3 -1
  6. truefoundry/deploy/lib/auth/credential_provider.py +2 -12
  7. truefoundry/deploy/lib/clients/servicefoundry_client.py +0 -9
  8. truefoundry/deploy/lib/exceptions.py +1 -6
  9. truefoundry/deploy/lib/session.py +1 -16
  10. truefoundry/langchain/truefoundry_chat.py +1 -1
  11. truefoundry/langchain/truefoundry_embeddings.py +1 -1
  12. truefoundry/langchain/truefoundry_llm.py +1 -1
  13. truefoundry/langchain/utils.py +0 -41
  14. truefoundry/ml/__init__.py +46 -6
  15. truefoundry/ml/artifact/__init__.py +0 -0
  16. truefoundry/ml/artifact/truefoundry_artifact_repo.py +1120 -0
  17. truefoundry/ml/autogen/__init__.py +0 -0
  18. truefoundry/ml/autogen/client/__init__.py +373 -0
  19. truefoundry/ml/autogen/client/api/__init__.py +16 -0
  20. truefoundry/ml/autogen/client/api/auth_api.py +184 -0
  21. truefoundry/ml/autogen/client/api/deprecated_api.py +605 -0
  22. truefoundry/ml/autogen/client/api/experiments_api.py +2109 -0
  23. truefoundry/ml/autogen/client/api/health_api.py +299 -0
  24. truefoundry/ml/autogen/client/api/metrics_api.py +371 -0
  25. truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +7213 -0
  26. truefoundry/ml/autogen/client/api/python_deployment_config_api.py +201 -0
  27. truefoundry/ml/autogen/client/api/run_artifacts_api.py +231 -0
  28. truefoundry/ml/autogen/client/api/runs_api.py +2919 -0
  29. truefoundry/ml/autogen/client/api_client.py +822 -0
  30. truefoundry/ml/autogen/client/api_response.py +30 -0
  31. truefoundry/ml/autogen/client/configuration.py +489 -0
  32. truefoundry/ml/autogen/client/exceptions.py +161 -0
  33. truefoundry/ml/autogen/client/models/__init__.py +344 -0
  34. truefoundry/ml/autogen/client/models/add_custom_metrics_to_model_version_request_dto.py +69 -0
  35. truefoundry/ml/autogen/client/models/add_features_to_model_version_request_dto.py +83 -0
  36. truefoundry/ml/autogen/client/models/agent.py +125 -0
  37. truefoundry/ml/autogen/client/models/agent_app.py +118 -0
  38. truefoundry/ml/autogen/client/models/agent_open_api_tool.py +143 -0
  39. truefoundry/ml/autogen/client/models/agent_open_api_tool_with_fqn.py +144 -0
  40. truefoundry/ml/autogen/client/models/agent_with_fqn.py +127 -0
  41. truefoundry/ml/autogen/client/models/artifact_dto.py +115 -0
  42. truefoundry/ml/autogen/client/models/artifact_response_dto.py +75 -0
  43. truefoundry/ml/autogen/client/models/artifact_type.py +39 -0
  44. truefoundry/ml/autogen/client/models/artifact_version_dto.py +141 -0
  45. truefoundry/ml/autogen/client/models/artifact_version_response_dto.py +77 -0
  46. truefoundry/ml/autogen/client/models/artifact_version_status.py +35 -0
  47. truefoundry/ml/autogen/client/models/assistant_message.py +89 -0
  48. truefoundry/ml/autogen/client/models/authorize_user_for_model_request_dto.py +69 -0
  49. truefoundry/ml/autogen/client/models/authorize_user_for_model_version_request_dto.py +69 -0
  50. truefoundry/ml/autogen/client/models/backfill_default_storage_integration_id_request_dto.py +67 -0
  51. truefoundry/ml/autogen/client/models/blob_storage_reference.py +93 -0
  52. truefoundry/ml/autogen/client/models/body_get_search_runs_get.py +72 -0
  53. truefoundry/ml/autogen/client/models/chat_prompt.py +156 -0
  54. truefoundry/ml/autogen/client/models/chat_prompt_messages_inner.py +171 -0
  55. truefoundry/ml/autogen/client/models/columns_dto.py +73 -0
  56. truefoundry/ml/autogen/client/models/content.py +153 -0
  57. truefoundry/ml/autogen/client/models/content1.py +153 -0
  58. truefoundry/ml/autogen/client/models/content2.py +174 -0
  59. truefoundry/ml/autogen/client/models/content2_any_of_inner.py +150 -0
  60. truefoundry/ml/autogen/client/models/create_artifact_request_dto.py +74 -0
  61. truefoundry/ml/autogen/client/models/create_artifact_response_dto.py +66 -0
  62. truefoundry/ml/autogen/client/models/create_artifact_version_request_dto.py +74 -0
  63. truefoundry/ml/autogen/client/models/create_artifact_version_response_dto.py +66 -0
  64. truefoundry/ml/autogen/client/models/create_dataset_request_dto.py +76 -0
  65. truefoundry/ml/autogen/client/models/create_experiment_request_dto.py +94 -0
  66. truefoundry/ml/autogen/client/models/create_experiment_response_dto.py +67 -0
  67. truefoundry/ml/autogen/client/models/create_model_version_request_dto.py +95 -0
  68. truefoundry/ml/autogen/client/models/create_multi_part_upload_for_dataset_request_dto.py +73 -0
  69. truefoundry/ml/autogen/client/models/create_multi_part_upload_for_dataset_response_dto.py +79 -0
  70. truefoundry/ml/autogen/client/models/create_multi_part_upload_request_dto.py +73 -0
  71. truefoundry/ml/autogen/client/models/create_python_deployment_config_request_dto.py +72 -0
  72. truefoundry/ml/autogen/client/models/create_python_deployment_config_response_dto.py +68 -0
  73. truefoundry/ml/autogen/client/models/create_run_request_dto.py +97 -0
  74. truefoundry/ml/autogen/client/models/create_run_response_dto.py +76 -0
  75. truefoundry/ml/autogen/client/models/dataset_dto.py +112 -0
  76. truefoundry/ml/autogen/client/models/dataset_response_dto.py +75 -0
  77. truefoundry/ml/autogen/client/models/delete_artifact_versions_request_dto.py +65 -0
  78. truefoundry/ml/autogen/client/models/delete_dataset_request_dto.py +74 -0
  79. truefoundry/ml/autogen/client/models/delete_model_version_request_dto.py +65 -0
  80. truefoundry/ml/autogen/client/models/delete_run_request.py +65 -0
  81. truefoundry/ml/autogen/client/models/delete_tag_request_dto.py +68 -0
  82. truefoundry/ml/autogen/client/models/experiment_dto.py +127 -0
  83. truefoundry/ml/autogen/client/models/experiment_id_request_dto.py +67 -0
  84. truefoundry/ml/autogen/client/models/experiment_response_dto.py +75 -0
  85. truefoundry/ml/autogen/client/models/experiment_tag_dto.py +69 -0
  86. truefoundry/ml/autogen/client/models/feature_dto.py +68 -0
  87. truefoundry/ml/autogen/client/models/feature_value_type.py +35 -0
  88. truefoundry/ml/autogen/client/models/file_info_dto.py +76 -0
  89. truefoundry/ml/autogen/client/models/finalize_artifact_version_request_dto.py +101 -0
  90. truefoundry/ml/autogen/client/models/get_experiment_response_dto.py +88 -0
  91. truefoundry/ml/autogen/client/models/get_latest_run_log_response_dto.py +76 -0
  92. truefoundry/ml/autogen/client/models/get_metric_history_response.py +79 -0
  93. truefoundry/ml/autogen/client/models/get_signed_url_for_dataset_write_request_dto.py +68 -0
  94. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_read_request_dto.py +68 -0
  95. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_read_response_dto.py +81 -0
  96. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_write_request_dto.py +69 -0
  97. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_write_response_dto.py +83 -0
  98. truefoundry/ml/autogen/client/models/get_signed_urls_for_dataset_read_request_dto.py +68 -0
  99. truefoundry/ml/autogen/client/models/get_signed_urls_for_dataset_read_response_dto.py +81 -0
  100. truefoundry/ml/autogen/client/models/get_signed_urls_for_dataset_write_response_dto.py +81 -0
  101. truefoundry/ml/autogen/client/models/get_tenant_id_response_dto.py +74 -0
  102. truefoundry/ml/autogen/client/models/http_validation_error.py +82 -0
  103. truefoundry/ml/autogen/client/models/image_content_part.py +87 -0
  104. truefoundry/ml/autogen/client/models/image_url.py +75 -0
  105. truefoundry/ml/autogen/client/models/internal_metadata.py +180 -0
  106. truefoundry/ml/autogen/client/models/latest_run_log_dto.py +78 -0
  107. truefoundry/ml/autogen/client/models/list_artifact_versions_request_dto.py +107 -0
  108. truefoundry/ml/autogen/client/models/list_artifact_versions_response_dto.py +87 -0
  109. truefoundry/ml/autogen/client/models/list_artifacts_request_dto.py +96 -0
  110. truefoundry/ml/autogen/client/models/list_artifacts_response_dto.py +86 -0
  111. truefoundry/ml/autogen/client/models/list_colums_response_dto.py +75 -0
  112. truefoundry/ml/autogen/client/models/list_datasets_request_dto.py +78 -0
  113. truefoundry/ml/autogen/client/models/list_datasets_response_dto.py +86 -0
  114. truefoundry/ml/autogen/client/models/list_experiments_response_dto.py +86 -0
  115. truefoundry/ml/autogen/client/models/list_files_for_artifact_version_request_dto.py +76 -0
  116. truefoundry/ml/autogen/client/models/list_files_for_artifact_versions_response_dto.py +82 -0
  117. truefoundry/ml/autogen/client/models/list_files_for_dataset_request_dto.py +76 -0
  118. truefoundry/ml/autogen/client/models/list_files_for_dataset_response_dto.py +82 -0
  119. truefoundry/ml/autogen/client/models/list_latest_run_logs_response_dto.py +82 -0
  120. truefoundry/ml/autogen/client/models/list_metric_history_request_dto.py +69 -0
  121. truefoundry/ml/autogen/client/models/list_metric_history_response_dto.py +84 -0
  122. truefoundry/ml/autogen/client/models/list_model_version_response_dto.py +87 -0
  123. truefoundry/ml/autogen/client/models/list_model_versions_request_dto.py +93 -0
  124. truefoundry/ml/autogen/client/models/list_models_request_dto.py +89 -0
  125. truefoundry/ml/autogen/client/models/list_models_response_dto.py +84 -0
  126. truefoundry/ml/autogen/client/models/list_run_artifacts_response_dto.py +84 -0
  127. truefoundry/ml/autogen/client/models/list_run_logs_response_dto.py +82 -0
  128. truefoundry/ml/autogen/client/models/list_seed_experiments_response_dto.py +81 -0
  129. truefoundry/ml/autogen/client/models/log_batch_request_dto.py +106 -0
  130. truefoundry/ml/autogen/client/models/log_metric_request_dto.py +80 -0
  131. truefoundry/ml/autogen/client/models/log_param_request_dto.py +76 -0
  132. truefoundry/ml/autogen/client/models/method.py +37 -0
  133. truefoundry/ml/autogen/client/models/metric_collection_dto.py +82 -0
  134. truefoundry/ml/autogen/client/models/metric_dto.py +76 -0
  135. truefoundry/ml/autogen/client/models/mime_type.py +37 -0
  136. truefoundry/ml/autogen/client/models/model_configuration.py +103 -0
  137. truefoundry/ml/autogen/client/models/model_dto.py +122 -0
  138. truefoundry/ml/autogen/client/models/model_response_dto.py +75 -0
  139. truefoundry/ml/autogen/client/models/model_schema_dto.py +85 -0
  140. truefoundry/ml/autogen/client/models/model_version_dto.py +163 -0
  141. truefoundry/ml/autogen/client/models/model_version_response_dto.py +75 -0
  142. truefoundry/ml/autogen/client/models/multi_part_upload_dto.py +107 -0
  143. truefoundry/ml/autogen/client/models/multi_part_upload_response_dto.py +79 -0
  144. truefoundry/ml/autogen/client/models/multi_part_upload_storage_provider.py +34 -0
  145. truefoundry/ml/autogen/client/models/notify_artifact_version_failure_dto.py +65 -0
  146. truefoundry/ml/autogen/client/models/openapi_spec.py +152 -0
  147. truefoundry/ml/autogen/client/models/param_dto.py +66 -0
  148. truefoundry/ml/autogen/client/models/parameters.py +84 -0
  149. truefoundry/ml/autogen/client/models/prediction_type.py +34 -0
  150. truefoundry/ml/autogen/client/models/resolve_agent_app_response_dto.py +75 -0
  151. truefoundry/ml/autogen/client/models/restore_run_request_dto.py +65 -0
  152. truefoundry/ml/autogen/client/models/run_data_dto.py +104 -0
  153. truefoundry/ml/autogen/client/models/run_dto.py +84 -0
  154. truefoundry/ml/autogen/client/models/run_info_dto.py +105 -0
  155. truefoundry/ml/autogen/client/models/run_log_dto.py +90 -0
  156. truefoundry/ml/autogen/client/models/run_log_input_dto.py +80 -0
  157. truefoundry/ml/autogen/client/models/run_response_dto.py +75 -0
  158. truefoundry/ml/autogen/client/models/run_tag_dto.py +66 -0
  159. truefoundry/ml/autogen/client/models/search_runs_request_dto.py +94 -0
  160. truefoundry/ml/autogen/client/models/search_runs_response_dto.py +84 -0
  161. truefoundry/ml/autogen/client/models/set_experiment_tag_request_dto.py +73 -0
  162. truefoundry/ml/autogen/client/models/set_tag_request_dto.py +76 -0
  163. truefoundry/ml/autogen/client/models/signed_url_dto.py +69 -0
  164. truefoundry/ml/autogen/client/models/stop.py +152 -0
  165. truefoundry/ml/autogen/client/models/store_run_logs_request_dto.py +83 -0
  166. truefoundry/ml/autogen/client/models/system_message.py +89 -0
  167. truefoundry/ml/autogen/client/models/text.py +153 -0
  168. truefoundry/ml/autogen/client/models/text_content_part.py +84 -0
  169. truefoundry/ml/autogen/client/models/update_artifact_version_request_dto.py +74 -0
  170. truefoundry/ml/autogen/client/models/update_dataset_request_dto.py +74 -0
  171. truefoundry/ml/autogen/client/models/update_experiment_request_dto.py +74 -0
  172. truefoundry/ml/autogen/client/models/update_model_version_request_dto.py +93 -0
  173. truefoundry/ml/autogen/client/models/update_run_request_dto.py +78 -0
  174. truefoundry/ml/autogen/client/models/update_run_response_dto.py +76 -0
  175. truefoundry/ml/autogen/client/models/url.py +153 -0
  176. truefoundry/ml/autogen/client/models/user_message.py +89 -0
  177. truefoundry/ml/autogen/client/models/validation_error.py +87 -0
  178. truefoundry/ml/autogen/client/models/validation_error_loc_inner.py +154 -0
  179. truefoundry/ml/autogen/client/rest.py +426 -0
  180. truefoundry/ml/autogen/client_README.md +322 -0
  181. truefoundry/ml/cli/__init__.py +0 -0
  182. truefoundry/ml/cli/cli.py +18 -0
  183. truefoundry/ml/cli/commands/__init__.py +3 -0
  184. truefoundry/ml/cli/commands/download.py +87 -0
  185. truefoundry/ml/constants.py +84 -0
  186. truefoundry/ml/enums.py +70 -0
  187. truefoundry/ml/env_vars.py +13 -0
  188. truefoundry/ml/exceptions.py +8 -0
  189. truefoundry/ml/git_info.py +60 -0
  190. truefoundry/ml/internal_namespace.py +52 -0
  191. truefoundry/ml/log_types/__init__.py +4 -0
  192. truefoundry/ml/log_types/artifacts/artifact.py +427 -0
  193. truefoundry/ml/log_types/artifacts/constants.py +33 -0
  194. truefoundry/ml/log_types/artifacts/dataset.py +383 -0
  195. truefoundry/ml/log_types/artifacts/general_artifact.py +110 -0
  196. truefoundry/ml/log_types/artifacts/model.py +628 -0
  197. truefoundry/ml/log_types/artifacts/model_extras.py +48 -0
  198. truefoundry/ml/log_types/artifacts/utils.py +161 -0
  199. truefoundry/ml/log_types/image/__init__.py +3 -0
  200. truefoundry/ml/log_types/image/constants.py +8 -0
  201. truefoundry/ml/log_types/image/image.py +358 -0
  202. truefoundry/ml/log_types/image/image_normalizer.py +101 -0
  203. truefoundry/ml/log_types/image/types.py +68 -0
  204. truefoundry/ml/log_types/plot.py +281 -0
  205. truefoundry/ml/log_types/pydantic_base.py +10 -0
  206. truefoundry/ml/log_types/utils.py +12 -0
  207. truefoundry/ml/logger.py +17 -0
  208. truefoundry/ml/login.py +241 -0
  209. truefoundry/ml/mlfoundry_api.py +1620 -0
  210. truefoundry/ml/mlfoundry_run.py +1238 -0
  211. truefoundry/ml/run_utils.py +102 -0
  212. truefoundry/ml/services/__init__.py +0 -0
  213. truefoundry/ml/services/auth_service.py +109 -0
  214. truefoundry/ml/services/entities.py +108 -0
  215. truefoundry/ml/services/servicefoundry_service.py +35 -0
  216. truefoundry/ml/services/utils.py +122 -0
  217. truefoundry/ml/session.py +271 -0
  218. truefoundry/ml/validation_utils.py +346 -0
  219. truefoundry/pydantic_v1.py +5 -1
  220. {truefoundry-0.3.3.dist-info → truefoundry-0.4.0.dev1.dist-info}/METADATA +18 -11
  221. truefoundry-0.4.0.dev1.dist-info/RECORD +342 -0
  222. truefoundry-0.3.3.dist-info/RECORD +0 -136
  223. /truefoundry/{python_deploy_codegen.py → deploy/python_deploy_codegen.py} +0 -0
  224. {truefoundry-0.3.3.dist-info → truefoundry-0.4.0.dev1.dist-info}/WHEEL +0 -0
  225. {truefoundry-0.3.3.dist-info → truefoundry-0.4.0.dev1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,60 @@
1
+ from typing import Optional
2
+
3
+ from git import Repo
4
+ from git.exc import InvalidGitRepositoryError
5
+
6
+ from truefoundry.ml.logger import logger
7
+
8
+
9
+ class GitInfo:
10
+ def __init__(self, path: str):
11
+ try:
12
+ self.repo: Repo = self.build_repo(path)
13
+ except InvalidGitRepositoryError as ex:
14
+ # NOTE: gitpython library does not set proper exception message while raising the
15
+ # exception. So we are catching and raising the same exception with proper message
16
+ raise InvalidGitRepositoryError("git repository is not present") from ex
17
+
18
+ def build_repo(self, path: str):
19
+ # https://github.com/gitpython-developers/GitPython/blob/cd29f07b2efda24bdc690626ed557590289d11a6/git/cmd.py#L365
20
+ # looks like the import itself may fail in case the git executable
21
+ # is not found
22
+ # putting the import here so that the caller can handle the exception
23
+ import git
24
+
25
+ repo = git.Repo(path, search_parent_directories=True)
26
+
27
+ return repo
28
+
29
+ @property
30
+ def current_commit_sha(self) -> str:
31
+ return str(self.repo.head.object.hexsha)
32
+
33
+ @property
34
+ def current_branch_name(self) -> str:
35
+ try:
36
+ branch_name = self.repo.active_branch.name
37
+ return branch_name
38
+ except TypeError as ex:
39
+ # NOTE: TypeError will be raised here if
40
+ # head is in detached state.
41
+ # git checkout commit_sha
42
+ # in this case returning empty string
43
+ logger.warning(f"cannot get branch name because of {ex}")
44
+ return ""
45
+
46
+ @property
47
+ def remote_url(self) -> Optional[str]:
48
+ remotes = self.repo.remotes
49
+ if len(remotes) != 1:
50
+ logger.warning("either more than one or no remote detected")
51
+ return None
52
+ return remotes[0].url
53
+
54
+ @property
55
+ def diff_patch(self) -> str:
56
+ return str(self.repo.git.diff("--patch", "HEAD"))
57
+
58
+ @property
59
+ def is_dirty(self) -> bool:
60
+ return self.repo.is_dirty()
@@ -0,0 +1,52 @@
1
+ import os
2
+ import typing
3
+
4
+ from truefoundry.ml.exceptions import MlFoundryException
5
+
6
+
7
+ class _InternalNamespace:
8
+ NAMESPACE = "mlf"
9
+ DELIMETER = "."
10
+ NAMESPACE_VIOLATION_MESSAGE = """
11
+ {name} cannot start with {prefix}
12
+ """
13
+
14
+ def __call__(self, name: str, delimeter: str = DELIMETER):
15
+ if not name:
16
+ raise MlFoundryException("name should be a non empty string")
17
+ return _InternalNamespace.NAMESPACE + delimeter + name
18
+
19
+ def __truediv__(self, path: str):
20
+ return os.path.join(_InternalNamespace.NAMESPACE, path)
21
+
22
+ @staticmethod
23
+ def _validate_name_not_using_namespace(name: typing.Optional[str], delimeter: str):
24
+ if name and name.startswith(_InternalNamespace.NAMESPACE + delimeter):
25
+ raise MlFoundryException(
26
+ _InternalNamespace.NAMESPACE_VIOLATION_MESSAGE.format(
27
+ name=name, prefix=_InternalNamespace.NAMESPACE + delimeter
28
+ )
29
+ )
30
+
31
+ def validate_namespace_not_used(
32
+ self,
33
+ names: typing.Optional[typing.Union[str, typing.Iterable[str]]] = None,
34
+ delimeter: str = DELIMETER,
35
+ path: typing.Optional[str] = None,
36
+ ):
37
+ if isinstance(names, str):
38
+ names = [names]
39
+ if names is not None:
40
+ for name_ in names:
41
+ self._validate_name_not_using_namespace(name_, delimeter)
42
+ if path:
43
+ prefix = os.path.normpath(os.path.join(_InternalNamespace.NAMESPACE, ""))
44
+ if os.path.normpath(path).startswith(prefix):
45
+ raise MlFoundryException(
46
+ _InternalNamespace.NAMESPACE_VIOLATION_MESSAGE.format(
47
+ name=path, prefix=prefix
48
+ )
49
+ )
50
+
51
+
52
+ NAMESPACE = _InternalNamespace()
@@ -0,0 +1,4 @@
1
+ from truefoundry.ml.log_types.image import Image
2
+ from truefoundry.ml.log_types.plot import Plot
3
+
4
+ __all__ = ["Image", "Plot"]
@@ -0,0 +1,427 @@
1
+ import copy
2
+ import datetime
3
+ import json
4
+ import os
5
+ import tempfile
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING, Any, Dict, NamedTuple, Optional, Tuple, Union
8
+
9
+ from truefoundry.ml.artifact.truefoundry_artifact_repo import (
10
+ ArtifactIdentifier,
11
+ MlFoundryArtifactsRepository,
12
+ )
13
+ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
14
+ ArtifactDto,
15
+ ArtifactType,
16
+ ArtifactVersionDto,
17
+ CreateArtifactVersionRequestDto,
18
+ DeleteArtifactVersionsRequestDto,
19
+ FinalizeArtifactVersionRequestDto,
20
+ MlfoundryArtifactsApi,
21
+ NotifyArtifactVersionFailureDto,
22
+ UpdateArtifactVersionRequestDto,
23
+ )
24
+ from truefoundry.ml.autogen.client import (
25
+ InternalMetadata as InternalMetadataDto,
26
+ )
27
+ from truefoundry.ml.exceptions import MlFoundryException
28
+ from truefoundry.ml.log_types.artifacts.constants import INTERNAL_METADATA_PATH
29
+ from truefoundry.ml.log_types.artifacts.utils import (
30
+ _validate_artifact_metadata,
31
+ _validate_description,
32
+ calculate_local_directory_size,
33
+ )
34
+ from truefoundry.ml.logger import logger
35
+ from truefoundry.ml.session import _get_api_client
36
+ from truefoundry.pydantic_v1 import BaseModel, Extra
37
+
38
+ if TYPE_CHECKING:
39
+ from truefoundry.ml.mlfoundry_run import MlFoundryRun
40
+
41
+
42
+ class ArtifactPath(NamedTuple):
43
+ src: str
44
+ dest: Optional[str] = None
45
+
46
+
47
+ class ArtifactVersionInternalMetadata(BaseModel):
48
+ class Config:
49
+ extra = Extra.allow
50
+
51
+ files_dir: str # relative to root
52
+
53
+
54
+ class ArtifactVersionDownloadInfo(BaseModel):
55
+ download_dir: str
56
+ content_dir: str
57
+
58
+
59
+ class ArtifactVersion:
60
+ def __init__(
61
+ self,
62
+ artifact_version: ArtifactVersionDto,
63
+ artifact: ArtifactDto,
64
+ ) -> None:
65
+ self._api_client = _get_api_client()
66
+ self._mlfoundry_artifacts_api = MlfoundryArtifactsApi(
67
+ api_client=self._api_client
68
+ )
69
+ self._artifact_version: ArtifactVersionDto = artifact_version
70
+ self._artifact: ArtifactDto = artifact
71
+ self._deleted = False
72
+ self._description: str = ""
73
+ self._metadata: Dict[str, Any] = {}
74
+ self._set_mutable_attrs()
75
+
76
+ @classmethod
77
+ def from_fqn(cls, fqn: str) -> "ArtifactVersion":
78
+ """
79
+ Get the version of an Artifact to download contents or load them in memory
80
+
81
+ Args:
82
+ fqn (str): Fully qualified name of the artifact version.
83
+
84
+ Returns:
85
+ ArtifactVersion: An ArtifactVersion instance of the artifact
86
+
87
+ Examples:
88
+
89
+ ```python
90
+ from truefoundry.ml import get_client, ArtifactVersion
91
+
92
+ client = get_client()
93
+ artifact_version = ArtifactVersion.from_fqn(fqn="<artifact-fqn>")
94
+ ```
95
+ """
96
+ api_client = _get_api_client()
97
+ mlfoundry_artifacts_api = MlfoundryArtifactsApi(api_client=api_client)
98
+ _artifact_version = mlfoundry_artifacts_api.get_artifact_version_by_fqn_get(
99
+ fqn=fqn
100
+ )
101
+ artifact_version = _artifact_version.artifact_version
102
+ _artifact = mlfoundry_artifacts_api.get_artifact_by_id_get(
103
+ id=artifact_version.artifact_id
104
+ )
105
+ return cls(
106
+ artifact_version=_artifact_version.artifact_version,
107
+ artifact=_artifact.artifact,
108
+ )
109
+
110
+ def _ensure_not_deleted(self):
111
+ if self._deleted:
112
+ raise MlFoundryException(
113
+ "Artifact Version was deleted, cannot access a deleted version"
114
+ )
115
+
116
+ def _set_mutable_attrs(self, refetch=False):
117
+ if refetch:
118
+ _artifact_version = (
119
+ self._mlfoundry_artifacts_api.get_artifact_version_by_id_get(
120
+ id=self._artifact_version.id
121
+ )
122
+ )
123
+ self._artifact_version = _artifact_version.artifact_version
124
+ self._description = self._artifact_version.description or ""
125
+ self._metadata = copy.deepcopy(self._artifact_version.artifact_metadata)
126
+
127
+ def __repr__(self):
128
+ return f"{self.__class__.__name__}(fqn={self.fqn!r})"
129
+
130
+ def _get_artifacts_repo(self):
131
+ return MlFoundryArtifactsRepository(
132
+ artifact_identifier=ArtifactIdentifier(
133
+ artifact_version_id=self._artifact_version.id
134
+ ),
135
+ api_client=self._api_client,
136
+ )
137
+
138
+ @property
139
+ def name(self) -> str:
140
+ """Get the name of the artifact"""
141
+ return self._artifact.name
142
+
143
+ @property
144
+ def artifact_fqn(self) -> str:
145
+ """Get fqn of the artifact"""
146
+ return self._artifact.fqn
147
+
148
+ @property
149
+ def version(self) -> int:
150
+ """Get version information of the artifact"""
151
+ return self._artifact_version.version
152
+
153
+ @property
154
+ def fqn(self) -> str:
155
+ """Get fqn of the current artifact version"""
156
+ return self._artifact_version.fqn
157
+
158
+ @property
159
+ def step(self) -> int:
160
+ """Get the step in which artifact was created"""
161
+ return self._artifact_version.step
162
+
163
+ @property
164
+ def description(self) -> Optional[str]:
165
+ """Get description of the artifact"""
166
+ return self._description
167
+
168
+ @description.setter
169
+ def description(self, value: str):
170
+ """set the description of the artifact"""
171
+ _validate_description(value)
172
+ self._description = value
173
+
174
+ @property
175
+ def metadata(self) -> Dict[str, Any]:
176
+ """Get metadata for the current artifact"""
177
+ return self._metadata
178
+
179
+ @metadata.setter
180
+ def metadata(self, value: Dict[str, Any]):
181
+ """set the metadata for current artifact"""
182
+ _validate_artifact_metadata(value)
183
+ self._metadata = value
184
+
185
+ @property
186
+ def created_by(self) -> str:
187
+ """Get the information about who created the artifact"""
188
+ return self._artifact_version.created_by
189
+
190
+ @property
191
+ def created_at(self) -> datetime.datetime:
192
+ """Get the time at which artifact was created"""
193
+ return self._artifact_version.created_at
194
+
195
+ @property
196
+ def updated_at(self) -> datetime.datetime:
197
+ """Get the information about when the artifact was updated"""
198
+ return self._artifact_version.updated_at
199
+
200
+ def raw_download(
201
+ self,
202
+ path: Optional[Union[str, Path]],
203
+ overwrite: bool = False,
204
+ progress: Optional[bool] = None,
205
+ ) -> str:
206
+ """
207
+ Download an artifact file or directory to a local directory if applicable, and return a
208
+ local path for it.
209
+
210
+ Args:
211
+ path (str): Absolute path of the local filesystem destination directory to which to
212
+ download the specified artifacts. This directory must already exist.
213
+ If unspecified, the artifacts will either be downloaded to a new
214
+ uniquely-named directory on the local filesystem.
215
+ overwrite (bool): If True it will overwrite the file if it is already present in the download directory else
216
+ it will throw an error
217
+ progress (bool): value to show progress bar, defaults to None.
218
+
219
+ Returns:
220
+ path: Absolute path of the local filesystem location containing the desired artifacts.
221
+
222
+ Examples:
223
+
224
+ ```python
225
+ from truefoundry.ml import get_client
226
+
227
+ client = get_client()
228
+ artifact_version = client.get_artifact_version_by_fqn(fqn="<your-artifact-fqn>")
229
+ artifact_version.raw_download(path="<your-desired-download-path>")
230
+ ```
231
+ """
232
+ logger.info(
233
+ "Downloading artifact version contents, this might take a while ..."
234
+ )
235
+ artifacts_repo = self._get_artifacts_repo()
236
+ return artifacts_repo.download_artifacts(
237
+ artifact_path="", dst_path=path, overwrite=overwrite, progress=progress
238
+ )
239
+
240
+ def _download(
241
+ self,
242
+ path: Optional[Union[str, Path]],
243
+ overwrite: bool = False,
244
+ progress: Optional[bool] = None,
245
+ ) -> Tuple[ArtifactVersionInternalMetadata, str]:
246
+ self._ensure_not_deleted()
247
+ download_dir = self.raw_download(
248
+ path=path, overwrite=overwrite, progress=progress
249
+ )
250
+ internal_metadata_path = os.path.join(download_dir, INTERNAL_METADATA_PATH)
251
+ if not os.path.exists(internal_metadata_path):
252
+ raise MlFoundryException(
253
+ "Artifact version seems to be corrupted or in invalid format due to missing artifact metadata. "
254
+ "You can still use .raw_download(path='/your/path/here') to download and inspect files."
255
+ )
256
+ with open(internal_metadata_path) as f:
257
+ internal_metadata = ArtifactVersionInternalMetadata.parse_obj(json.load(f))
258
+ download_path = os.path.join(download_dir, internal_metadata.files_dir)
259
+ return internal_metadata, download_path
260
+
261
+ def download(
262
+ self,
263
+ path: Optional[Union[str, Path]] = None,
264
+ overwrite: bool = False,
265
+ progress: Optional[bool] = None,
266
+ ) -> str:
267
+ """
268
+ Download an artifact file or directory to a local directory if applicable, and return a
269
+ local path for it.
270
+
271
+ Args:
272
+ path (str): Absolute path of the local filesystem destination directory to which to
273
+ download the specified artifacts. This directory must already exist.
274
+ If unspecified, the artifacts will either be downloaded to a new
275
+ uniquely-named directory on the local filesystem or will be returned
276
+ directly in the case of the Local ArtifactRepository.
277
+ overwrite (bool): If True it will overwrite the file if it is already present in the download directory else
278
+ it will throw an error
279
+ progress (bool): value to show progress bar, defaults to None.
280
+
281
+ Returns:
282
+ path: Absolute path of the local filesystem location containing the desired artifacts.
283
+
284
+ Examples:
285
+
286
+ ```python
287
+ from truefoundry.ml import get_client
288
+
289
+ client = get_client()
290
+ artifact_version = client.get_artifact_version_by_fqn(fqn="<your-artifact-fqn>")
291
+ artifact_version.download(path="<your-desired-download-path>")
292
+ ```
293
+ """
294
+ _, download_path = self._download(
295
+ path=path, overwrite=overwrite, progress=progress
296
+ )
297
+ return download_path
298
+
299
+ def delete(self) -> bool:
300
+ """
301
+ Deletes the current instance of the ArtifactVersion hence deleting the current version.
302
+
303
+ Returns:
304
+ True if artifact was deleted successfully
305
+
306
+ Examples:
307
+
308
+ ```python
309
+ from truefoundry.ml import get_client
310
+
311
+ client = get_client()
312
+ artifact_version = client.get_artifact_version_by_fqn(fqn="<your-artifact-fqn>")
313
+ artifact_version.delete()
314
+ ```
315
+ """
316
+ self._ensure_not_deleted()
317
+ self._mlfoundry_artifacts_api.delete_artifact_version_post(
318
+ delete_artifact_versions_request_dto=DeleteArtifactVersionsRequestDto(
319
+ id=self._artifact_version.id
320
+ )
321
+ )
322
+ self._deleted = True
323
+ return True
324
+
325
+ def update(self):
326
+ """
327
+ Updates the current instance of the ArtifactVersion hence updating the current version.
328
+
329
+ Examples:
330
+
331
+ ```python
332
+ from truefoundry.ml import get_client
333
+
334
+ client = get_client()
335
+ artifact_version = client.get_artifact_version_by_fqn(fqn="<your-artifact-fqn>")
336
+ artifact_version.description = 'This is the new description'
337
+ artifact_version.update()
338
+ ```
339
+ """
340
+ self._ensure_not_deleted()
341
+
342
+ _artifact_version = self._mlfoundry_artifacts_api.update_artifact_version_post(
343
+ update_artifact_version_request_dto=UpdateArtifactVersionRequestDto(
344
+ id=self._artifact_version.id,
345
+ description=self.description,
346
+ artifact_metadata=self.metadata,
347
+ )
348
+ )
349
+ self._artifact_version = _artifact_version.artifact_version
350
+ self._set_mutable_attrs()
351
+
352
+
353
+ def _log_artifact_version_helper(
354
+ run: "MlFoundryRun",
355
+ name: str,
356
+ artifact_type: ArtifactType,
357
+ artifact_dir: tempfile.TemporaryDirectory,
358
+ mlfoundry_artifacts_api: Optional[MlfoundryArtifactsApi] = None,
359
+ ml_repo_id: Optional[str] = None,
360
+ description: Optional[str] = None,
361
+ internal_metadata: Optional[BaseModel] = None,
362
+ metadata: Optional[Dict[str, Any]] = None,
363
+ step: int = 0,
364
+ progress: Optional[bool] = None,
365
+ ) -> ArtifactVersion:
366
+ if (run and mlfoundry_artifacts_api) or (not run and not mlfoundry_artifacts_api):
367
+ raise MlFoundryException(
368
+ "Exactly one of run, mlfoundry_artifacts_api should be passed"
369
+ )
370
+ if mlfoundry_artifacts_api and not ml_repo_id:
371
+ raise MlFoundryException(
372
+ "If mlfoundry_artifacts_api is passed, ml_repo_id must also be passed"
373
+ )
374
+ if run:
375
+ mlfoundry_artifacts_api = run._mlfoundry_artifacts_api
376
+
377
+ _create_artifact_response = mlfoundry_artifacts_api.create_artifact_version_post(
378
+ create_artifact_version_request_dto=CreateArtifactVersionRequestDto(
379
+ experiment_id=int(run._experiment_id if run else ml_repo_id),
380
+ name=name,
381
+ artifact_type=artifact_type,
382
+ )
383
+ )
384
+ version_id = _create_artifact_response.id
385
+ artifacts_repo = MlFoundryArtifactsRepository(
386
+ artifact_identifier=ArtifactIdentifier(artifact_version_id=version_id),
387
+ api_client=mlfoundry_artifacts_api.api_client,
388
+ )
389
+ total_size = calculate_local_directory_size(artifact_dir)
390
+ try:
391
+ logger.info(
392
+ "Packaging and uploading files to remote with Artifact Size: %.6f MB",
393
+ total_size / 1000000.0,
394
+ )
395
+ artifacts_repo.log_artifacts(
396
+ local_dir=artifact_dir.name, artifact_path=None, progress=progress
397
+ )
398
+ except Exception as e:
399
+ mlfoundry_artifacts_api.notify_failure_post(
400
+ notify_artifact_version_failure_dto=NotifyArtifactVersionFailureDto(
401
+ id=version_id
402
+ )
403
+ )
404
+ raise MlFoundryException("Failed to log Artifact") from e
405
+ finally:
406
+ artifact_dir.cleanup()
407
+
408
+ # Note: Here we call from_dict instead of directly passing in init and relying on it
409
+ # to convert because the complicated union of types generates a custom type to handle casting
410
+ # Check the source of `InternalMetadataDto` to see the generated code
411
+ internal_metadata_dto = InternalMetadataDto.from_dict(
412
+ internal_metadata.dict() if internal_metadata is not None else {}
413
+ )
414
+ finalize_artifact_version_request_dto = FinalizeArtifactVersionRequestDto(
415
+ id=version_id,
416
+ run_uuid=run.run_id if run else None,
417
+ description=description,
418
+ internal_metadata=internal_metadata_dto,
419
+ artifact_metadata=metadata,
420
+ data_path=INTERNAL_METADATA_PATH,
421
+ step=step,
422
+ artifact_size=total_size,
423
+ )
424
+ _artifact_version = mlfoundry_artifacts_api.finalize_artifact_version_post(
425
+ finalize_artifact_version_request_dto=finalize_artifact_version_request_dto
426
+ )
427
+ return ArtifactVersion.from_fqn(fqn=_artifact_version.artifact_version.fqn)
@@ -0,0 +1,33 @@
1
+ """
2
+ .
3
+ ├── .truefoundry/
4
+ │ └── metadata.json
5
+ └── files/
6
+ └── model/
7
+ """
8
+
9
+ import posixpath
10
+
11
+ INTERNAL_METADATA_DIR = ".truefoundry"
12
+ INTERNAL_METADATA_FILE_NAME = "metadata.json"
13
+ INTERNAL_METADATA_PATH = posixpath.join(
14
+ INTERNAL_METADATA_DIR, INTERNAL_METADATA_FILE_NAME
15
+ )
16
+ FILES_DIR = "files"
17
+ MODEL_DIR_NAME = "model"
18
+ DESCRIPTION_MAX_LENGTH = 1024
19
+
20
+ # Link to docs here explaining schema consistency across model versions
21
+ MODEL_SCHEMA_UPDATE_FAILURE_HELP = """Model was logged successfully but failed to update the model schema because
22
+ it is inconsistent with the previous versions of the model. You can still fix the schema and update it using the
23
+ following:
24
+
25
+ ```
26
+ from truefoundry.ml import get_client
27
+ from truefoundry.ml import ModelVersion, ModelSchema, Feature, FeatureValueType, PredictionValueType
28
+ client = get_client()
29
+ model_version = ModelVersion(fqn="{fqn}")
30
+ model_version = ModelSchema(...) # or schema in dictionary format {{"features": [...], "prediction": ...}}
31
+ model_version.update()
32
+ ```
33
+ """