truefoundry 0.3.4rc1__py3-none-any.whl → 0.4.0__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 (253) hide show
  1. truefoundry/__init__.py +2 -0
  2. truefoundry/autodeploy/agents/developer.py +1 -1
  3. truefoundry/autodeploy/agents/project_identifier.py +2 -2
  4. truefoundry/autodeploy/agents/tester.py +1 -1
  5. truefoundry/autodeploy/cli.py +1 -1
  6. truefoundry/autodeploy/tools/list_files.py +1 -1
  7. truefoundry/cli/__main__.py +3 -17
  8. truefoundry/common/__init__.py +0 -0
  9. truefoundry/{deploy/lib/auth → common}/auth_service_client.py +50 -40
  10. truefoundry/common/constants.py +12 -0
  11. truefoundry/{deploy/lib/auth → common}/credential_file_manager.py +7 -7
  12. truefoundry/{deploy/lib/auth → common}/credential_provider.py +10 -23
  13. truefoundry/common/entities.py +124 -0
  14. truefoundry/common/exceptions.py +12 -0
  15. truefoundry/common/request_utils.py +84 -0
  16. truefoundry/common/servicefoundry_client.py +91 -0
  17. truefoundry/common/utils.py +56 -0
  18. truefoundry/deploy/auto_gen/models.py +4 -6
  19. truefoundry/deploy/cli/cli.py +3 -1
  20. truefoundry/deploy/cli/commands/apply_command.py +1 -1
  21. truefoundry/deploy/cli/commands/build_command.py +1 -1
  22. truefoundry/deploy/cli/commands/deploy_command.py +1 -1
  23. truefoundry/deploy/cli/commands/login_command.py +2 -2
  24. truefoundry/deploy/cli/commands/patch_application_command.py +1 -1
  25. truefoundry/deploy/cli/commands/patch_command.py +1 -1
  26. truefoundry/deploy/cli/commands/terminate_comand.py +1 -1
  27. truefoundry/deploy/cli/util.py +1 -1
  28. truefoundry/deploy/function_service/remote/remote.py +1 -1
  29. truefoundry/deploy/lib/auth/servicefoundry_session.py +2 -2
  30. truefoundry/deploy/lib/clients/servicefoundry_client.py +120 -159
  31. truefoundry/deploy/lib/const.py +1 -35
  32. truefoundry/deploy/lib/exceptions.py +0 -16
  33. truefoundry/deploy/lib/model/entity.py +1 -112
  34. truefoundry/deploy/lib/session.py +14 -42
  35. truefoundry/deploy/lib/util.py +0 -37
  36. truefoundry/{python_deploy_codegen.py → deploy/python_deploy_codegen.py} +2 -2
  37. truefoundry/deploy/v2/lib/deploy.py +3 -3
  38. truefoundry/deploy/v2/lib/deployable_patched_models.py +1 -1
  39. truefoundry/langchain/truefoundry_chat.py +1 -1
  40. truefoundry/langchain/truefoundry_embeddings.py +1 -1
  41. truefoundry/langchain/truefoundry_llm.py +1 -1
  42. truefoundry/langchain/utils.py +0 -41
  43. truefoundry/ml/__init__.py +37 -6
  44. truefoundry/ml/artifact/__init__.py +0 -0
  45. truefoundry/ml/artifact/truefoundry_artifact_repo.py +1161 -0
  46. truefoundry/ml/autogen/__init__.py +0 -0
  47. truefoundry/ml/autogen/client/__init__.py +370 -0
  48. truefoundry/ml/autogen/client/api/__init__.py +16 -0
  49. truefoundry/ml/autogen/client/api/auth_api.py +184 -0
  50. truefoundry/ml/autogen/client/api/deprecated_api.py +605 -0
  51. truefoundry/ml/autogen/client/api/experiments_api.py +1944 -0
  52. truefoundry/ml/autogen/client/api/health_api.py +299 -0
  53. truefoundry/ml/autogen/client/api/metrics_api.py +371 -0
  54. truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +7213 -0
  55. truefoundry/ml/autogen/client/api/python_deployment_config_api.py +201 -0
  56. truefoundry/ml/autogen/client/api/run_artifacts_api.py +231 -0
  57. truefoundry/ml/autogen/client/api/runs_api.py +2919 -0
  58. truefoundry/ml/autogen/client/api_client.py +822 -0
  59. truefoundry/ml/autogen/client/api_response.py +30 -0
  60. truefoundry/ml/autogen/client/configuration.py +489 -0
  61. truefoundry/ml/autogen/client/exceptions.py +161 -0
  62. truefoundry/ml/autogen/client/models/__init__.py +341 -0
  63. truefoundry/ml/autogen/client/models/add_custom_metrics_to_model_version_request_dto.py +69 -0
  64. truefoundry/ml/autogen/client/models/add_features_to_model_version_request_dto.py +83 -0
  65. truefoundry/ml/autogen/client/models/agent.py +125 -0
  66. truefoundry/ml/autogen/client/models/agent_app.py +118 -0
  67. truefoundry/ml/autogen/client/models/agent_open_api_tool.py +143 -0
  68. truefoundry/ml/autogen/client/models/agent_open_api_tool_with_fqn.py +144 -0
  69. truefoundry/ml/autogen/client/models/agent_with_fqn.py +127 -0
  70. truefoundry/ml/autogen/client/models/artifact_dto.py +115 -0
  71. truefoundry/ml/autogen/client/models/artifact_response_dto.py +75 -0
  72. truefoundry/ml/autogen/client/models/artifact_type.py +39 -0
  73. truefoundry/ml/autogen/client/models/artifact_version_dto.py +141 -0
  74. truefoundry/ml/autogen/client/models/artifact_version_response_dto.py +77 -0
  75. truefoundry/ml/autogen/client/models/artifact_version_status.py +35 -0
  76. truefoundry/ml/autogen/client/models/assistant_message.py +89 -0
  77. truefoundry/ml/autogen/client/models/authorize_user_for_model_request_dto.py +69 -0
  78. truefoundry/ml/autogen/client/models/authorize_user_for_model_version_request_dto.py +69 -0
  79. truefoundry/ml/autogen/client/models/blob_storage_reference.py +93 -0
  80. truefoundry/ml/autogen/client/models/body_get_search_runs_get.py +72 -0
  81. truefoundry/ml/autogen/client/models/chat_prompt.py +156 -0
  82. truefoundry/ml/autogen/client/models/chat_prompt_messages_inner.py +171 -0
  83. truefoundry/ml/autogen/client/models/columns_dto.py +73 -0
  84. truefoundry/ml/autogen/client/models/content.py +153 -0
  85. truefoundry/ml/autogen/client/models/content1.py +153 -0
  86. truefoundry/ml/autogen/client/models/content2.py +174 -0
  87. truefoundry/ml/autogen/client/models/content2_any_of_inner.py +150 -0
  88. truefoundry/ml/autogen/client/models/create_artifact_request_dto.py +74 -0
  89. truefoundry/ml/autogen/client/models/create_artifact_response_dto.py +65 -0
  90. truefoundry/ml/autogen/client/models/create_artifact_version_request_dto.py +74 -0
  91. truefoundry/ml/autogen/client/models/create_artifact_version_response_dto.py +65 -0
  92. truefoundry/ml/autogen/client/models/create_dataset_request_dto.py +76 -0
  93. truefoundry/ml/autogen/client/models/create_experiment_request_dto.py +94 -0
  94. truefoundry/ml/autogen/client/models/create_experiment_response_dto.py +67 -0
  95. truefoundry/ml/autogen/client/models/create_model_version_request_dto.py +95 -0
  96. truefoundry/ml/autogen/client/models/create_multi_part_upload_for_dataset_request_dto.py +73 -0
  97. truefoundry/ml/autogen/client/models/create_multi_part_upload_for_dataset_response_dto.py +79 -0
  98. truefoundry/ml/autogen/client/models/create_multi_part_upload_request_dto.py +73 -0
  99. truefoundry/ml/autogen/client/models/create_python_deployment_config_request_dto.py +72 -0
  100. truefoundry/ml/autogen/client/models/create_python_deployment_config_response_dto.py +67 -0
  101. truefoundry/ml/autogen/client/models/create_run_request_dto.py +97 -0
  102. truefoundry/ml/autogen/client/models/create_run_response_dto.py +75 -0
  103. truefoundry/ml/autogen/client/models/dataset_dto.py +112 -0
  104. truefoundry/ml/autogen/client/models/dataset_response_dto.py +75 -0
  105. truefoundry/ml/autogen/client/models/delete_artifact_versions_request_dto.py +65 -0
  106. truefoundry/ml/autogen/client/models/delete_dataset_request_dto.py +74 -0
  107. truefoundry/ml/autogen/client/models/delete_model_version_request_dto.py +65 -0
  108. truefoundry/ml/autogen/client/models/delete_run_request.py +65 -0
  109. truefoundry/ml/autogen/client/models/delete_tag_request_dto.py +68 -0
  110. truefoundry/ml/autogen/client/models/experiment_dto.py +127 -0
  111. truefoundry/ml/autogen/client/models/experiment_id_request_dto.py +67 -0
  112. truefoundry/ml/autogen/client/models/experiment_response_dto.py +75 -0
  113. truefoundry/ml/autogen/client/models/experiment_tag_dto.py +69 -0
  114. truefoundry/ml/autogen/client/models/feature_dto.py +68 -0
  115. truefoundry/ml/autogen/client/models/feature_value_type.py +35 -0
  116. truefoundry/ml/autogen/client/models/file_info_dto.py +76 -0
  117. truefoundry/ml/autogen/client/models/finalize_artifact_version_request_dto.py +101 -0
  118. truefoundry/ml/autogen/client/models/get_experiment_response_dto.py +88 -0
  119. truefoundry/ml/autogen/client/models/get_latest_run_log_response_dto.py +75 -0
  120. truefoundry/ml/autogen/client/models/get_metric_history_response.py +79 -0
  121. truefoundry/ml/autogen/client/models/get_signed_url_for_dataset_write_request_dto.py +68 -0
  122. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_read_request_dto.py +68 -0
  123. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_read_response_dto.py +81 -0
  124. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_write_request_dto.py +69 -0
  125. truefoundry/ml/autogen/client/models/get_signed_urls_for_artifact_version_write_response_dto.py +83 -0
  126. truefoundry/ml/autogen/client/models/get_signed_urls_for_dataset_read_request_dto.py +68 -0
  127. truefoundry/ml/autogen/client/models/get_signed_urls_for_dataset_read_response_dto.py +81 -0
  128. truefoundry/ml/autogen/client/models/get_signed_urls_for_dataset_write_response_dto.py +81 -0
  129. truefoundry/ml/autogen/client/models/get_tenant_id_response_dto.py +73 -0
  130. truefoundry/ml/autogen/client/models/http_validation_error.py +82 -0
  131. truefoundry/ml/autogen/client/models/image_content_part.py +87 -0
  132. truefoundry/ml/autogen/client/models/image_url.py +75 -0
  133. truefoundry/ml/autogen/client/models/internal_metadata.py +180 -0
  134. truefoundry/ml/autogen/client/models/latest_run_log_dto.py +78 -0
  135. truefoundry/ml/autogen/client/models/list_artifact_versions_request_dto.py +107 -0
  136. truefoundry/ml/autogen/client/models/list_artifact_versions_response_dto.py +87 -0
  137. truefoundry/ml/autogen/client/models/list_artifacts_request_dto.py +96 -0
  138. truefoundry/ml/autogen/client/models/list_artifacts_response_dto.py +86 -0
  139. truefoundry/ml/autogen/client/models/list_colums_response_dto.py +75 -0
  140. truefoundry/ml/autogen/client/models/list_datasets_request_dto.py +78 -0
  141. truefoundry/ml/autogen/client/models/list_datasets_response_dto.py +86 -0
  142. truefoundry/ml/autogen/client/models/list_experiments_response_dto.py +86 -0
  143. truefoundry/ml/autogen/client/models/list_files_for_artifact_version_request_dto.py +76 -0
  144. truefoundry/ml/autogen/client/models/list_files_for_artifact_versions_response_dto.py +82 -0
  145. truefoundry/ml/autogen/client/models/list_files_for_dataset_request_dto.py +76 -0
  146. truefoundry/ml/autogen/client/models/list_files_for_dataset_response_dto.py +82 -0
  147. truefoundry/ml/autogen/client/models/list_latest_run_logs_response_dto.py +82 -0
  148. truefoundry/ml/autogen/client/models/list_metric_history_request_dto.py +69 -0
  149. truefoundry/ml/autogen/client/models/list_metric_history_response_dto.py +84 -0
  150. truefoundry/ml/autogen/client/models/list_model_version_response_dto.py +87 -0
  151. truefoundry/ml/autogen/client/models/list_model_versions_request_dto.py +93 -0
  152. truefoundry/ml/autogen/client/models/list_models_request_dto.py +89 -0
  153. truefoundry/ml/autogen/client/models/list_models_response_dto.py +84 -0
  154. truefoundry/ml/autogen/client/models/list_run_artifacts_response_dto.py +84 -0
  155. truefoundry/ml/autogen/client/models/list_run_logs_response_dto.py +82 -0
  156. truefoundry/ml/autogen/client/models/list_seed_experiments_response_dto.py +81 -0
  157. truefoundry/ml/autogen/client/models/log_batch_request_dto.py +106 -0
  158. truefoundry/ml/autogen/client/models/log_metric_request_dto.py +80 -0
  159. truefoundry/ml/autogen/client/models/log_param_request_dto.py +76 -0
  160. truefoundry/ml/autogen/client/models/method.py +37 -0
  161. truefoundry/ml/autogen/client/models/metric_collection_dto.py +82 -0
  162. truefoundry/ml/autogen/client/models/metric_dto.py +76 -0
  163. truefoundry/ml/autogen/client/models/mime_type.py +37 -0
  164. truefoundry/ml/autogen/client/models/model_configuration.py +103 -0
  165. truefoundry/ml/autogen/client/models/model_dto.py +122 -0
  166. truefoundry/ml/autogen/client/models/model_response_dto.py +75 -0
  167. truefoundry/ml/autogen/client/models/model_schema_dto.py +85 -0
  168. truefoundry/ml/autogen/client/models/model_version_dto.py +170 -0
  169. truefoundry/ml/autogen/client/models/model_version_response_dto.py +75 -0
  170. truefoundry/ml/autogen/client/models/multi_part_upload_dto.py +107 -0
  171. truefoundry/ml/autogen/client/models/multi_part_upload_response_dto.py +79 -0
  172. truefoundry/ml/autogen/client/models/multi_part_upload_storage_provider.py +34 -0
  173. truefoundry/ml/autogen/client/models/notify_artifact_version_failure_dto.py +65 -0
  174. truefoundry/ml/autogen/client/models/openapi_spec.py +152 -0
  175. truefoundry/ml/autogen/client/models/param_dto.py +66 -0
  176. truefoundry/ml/autogen/client/models/parameters.py +84 -0
  177. truefoundry/ml/autogen/client/models/prediction_type.py +34 -0
  178. truefoundry/ml/autogen/client/models/resolve_agent_app_response_dto.py +75 -0
  179. truefoundry/ml/autogen/client/models/restore_run_request_dto.py +65 -0
  180. truefoundry/ml/autogen/client/models/run_data_dto.py +104 -0
  181. truefoundry/ml/autogen/client/models/run_dto.py +84 -0
  182. truefoundry/ml/autogen/client/models/run_info_dto.py +105 -0
  183. truefoundry/ml/autogen/client/models/run_log_dto.py +90 -0
  184. truefoundry/ml/autogen/client/models/run_log_input_dto.py +80 -0
  185. truefoundry/ml/autogen/client/models/run_response_dto.py +75 -0
  186. truefoundry/ml/autogen/client/models/run_tag_dto.py +66 -0
  187. truefoundry/ml/autogen/client/models/search_runs_request_dto.py +94 -0
  188. truefoundry/ml/autogen/client/models/search_runs_response_dto.py +84 -0
  189. truefoundry/ml/autogen/client/models/set_experiment_tag_request_dto.py +73 -0
  190. truefoundry/ml/autogen/client/models/set_tag_request_dto.py +76 -0
  191. truefoundry/ml/autogen/client/models/signed_url_dto.py +69 -0
  192. truefoundry/ml/autogen/client/models/stop.py +152 -0
  193. truefoundry/ml/autogen/client/models/store_run_logs_request_dto.py +83 -0
  194. truefoundry/ml/autogen/client/models/system_message.py +89 -0
  195. truefoundry/ml/autogen/client/models/text.py +153 -0
  196. truefoundry/ml/autogen/client/models/text_content_part.py +84 -0
  197. truefoundry/ml/autogen/client/models/update_artifact_version_request_dto.py +74 -0
  198. truefoundry/ml/autogen/client/models/update_dataset_request_dto.py +74 -0
  199. truefoundry/ml/autogen/client/models/update_experiment_request_dto.py +74 -0
  200. truefoundry/ml/autogen/client/models/update_model_version_request_dto.py +93 -0
  201. truefoundry/ml/autogen/client/models/update_run_request_dto.py +78 -0
  202. truefoundry/ml/autogen/client/models/update_run_response_dto.py +75 -0
  203. truefoundry/ml/autogen/client/models/url.py +153 -0
  204. truefoundry/ml/autogen/client/models/user_message.py +89 -0
  205. truefoundry/ml/autogen/client/models/validation_error.py +87 -0
  206. truefoundry/ml/autogen/client/models/validation_error_loc_inner.py +154 -0
  207. truefoundry/ml/autogen/client/rest.py +426 -0
  208. truefoundry/ml/autogen/client_README.md +320 -0
  209. truefoundry/ml/cli/__init__.py +0 -0
  210. truefoundry/ml/cli/cli.py +18 -0
  211. truefoundry/ml/cli/commands/__init__.py +3 -0
  212. truefoundry/ml/cli/commands/download.py +87 -0
  213. truefoundry/ml/clients/__init__.py +0 -0
  214. truefoundry/ml/clients/entities.py +8 -0
  215. truefoundry/ml/clients/servicefoundry_client.py +45 -0
  216. truefoundry/ml/clients/utils.py +122 -0
  217. truefoundry/ml/constants.py +84 -0
  218. truefoundry/ml/entities.py +62 -0
  219. truefoundry/ml/enums.py +70 -0
  220. truefoundry/ml/env_vars.py +9 -0
  221. truefoundry/ml/exceptions.py +8 -0
  222. truefoundry/ml/git_info.py +60 -0
  223. truefoundry/ml/internal_namespace.py +52 -0
  224. truefoundry/ml/log_types/__init__.py +4 -0
  225. truefoundry/ml/log_types/artifacts/artifact.py +431 -0
  226. truefoundry/ml/log_types/artifacts/constants.py +33 -0
  227. truefoundry/ml/log_types/artifacts/dataset.py +384 -0
  228. truefoundry/ml/log_types/artifacts/general_artifact.py +110 -0
  229. truefoundry/ml/log_types/artifacts/model.py +611 -0
  230. truefoundry/ml/log_types/artifacts/model_extras.py +48 -0
  231. truefoundry/ml/log_types/artifacts/utils.py +161 -0
  232. truefoundry/ml/log_types/image/__init__.py +3 -0
  233. truefoundry/ml/log_types/image/constants.py +8 -0
  234. truefoundry/ml/log_types/image/image.py +357 -0
  235. truefoundry/ml/log_types/image/image_normalizer.py +102 -0
  236. truefoundry/ml/log_types/image/types.py +68 -0
  237. truefoundry/ml/log_types/plot.py +281 -0
  238. truefoundry/ml/log_types/pydantic_base.py +10 -0
  239. truefoundry/ml/log_types/utils.py +12 -0
  240. truefoundry/ml/logger.py +17 -0
  241. truefoundry/ml/mlfoundry_api.py +1575 -0
  242. truefoundry/ml/mlfoundry_run.py +1203 -0
  243. truefoundry/ml/run_utils.py +93 -0
  244. truefoundry/ml/session.py +168 -0
  245. truefoundry/ml/validation_utils.py +346 -0
  246. truefoundry/pydantic_v1.py +8 -1
  247. truefoundry/workflow/__init__.py +16 -1
  248. {truefoundry-0.3.4rc1.dist-info → truefoundry-0.4.0.dist-info}/METADATA +21 -14
  249. truefoundry-0.4.0.dist-info/RECORD +344 -0
  250. truefoundry/deploy/lib/clients/utils.py +0 -41
  251. truefoundry-0.3.4rc1.dist-info/RECORD +0 -136
  252. {truefoundry-0.3.4rc1.dist-info → truefoundry-0.4.0.dist-info}/WHEEL +0 -0
  253. {truefoundry-0.3.4rc1.dist-info → truefoundry-0.4.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,611 @@
1
+ import copy
2
+ import datetime
3
+ import json
4
+ import logging
5
+ import os.path
6
+ import tempfile
7
+ import uuid
8
+ from pathlib import Path
9
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple, Union
10
+
11
+ from truefoundry.ml.artifact.truefoundry_artifact_repo import (
12
+ ArtifactIdentifier,
13
+ MlFoundryArtifactsRepository,
14
+ )
15
+ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
16
+ AddCustomMetricsToModelVersionRequestDto,
17
+ ArtifactType,
18
+ CreateArtifactVersionRequestDto,
19
+ CreateModelVersionRequestDto,
20
+ DeleteArtifactVersionsRequestDto,
21
+ FinalizeArtifactVersionRequestDto,
22
+ MetricDto,
23
+ MlfoundryArtifactsApi,
24
+ ModelDto,
25
+ ModelVersionDto,
26
+ NotifyArtifactVersionFailureDto,
27
+ UpdateModelVersionRequestDto,
28
+ )
29
+ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
30
+ InternalMetadata as InternalMetadataDto,
31
+ )
32
+ from truefoundry.ml.enums import ModelFramework
33
+ from truefoundry.ml.exceptions import MlFoundryException
34
+ from truefoundry.ml.log_types.artifacts.constants import (
35
+ FILES_DIR,
36
+ INTERNAL_METADATA_PATH,
37
+ MODEL_DIR_NAME,
38
+ MODEL_SCHEMA_UPDATE_FAILURE_HELP,
39
+ )
40
+ from truefoundry.ml.log_types.artifacts.model_extras import CustomMetric, ModelSchema
41
+ from truefoundry.ml.log_types.artifacts.utils import (
42
+ _copy_additional_files,
43
+ _validate_artifact_metadata,
44
+ _validate_description,
45
+ )
46
+ from truefoundry.ml.session import _get_api_client
47
+ from truefoundry.pydantic_v1 import BaseModel, Extra
48
+ from truefoundry.version import __version__
49
+
50
+ if TYPE_CHECKING:
51
+ from truefoundry.ml.mlfoundry_run import MlFoundryRun
52
+
53
+ logger = logging.getLogger("truefoundry.ml")
54
+
55
+
56
+ # TODO: Support async download and upload
57
+
58
+
59
+ class ModelVersionInternalMetadata(BaseModel):
60
+ class Config:
61
+ extra = Extra.allow
62
+
63
+ files_dir: str # relative to root
64
+ model_dir: str # relative to `files_dir`
65
+ model_is_null: bool = False
66
+ framework: ModelFramework = ModelFramework.UNKNOWN
67
+ transformers_pipeline_task: Optional[str] = None
68
+ model_filename: Optional[str] = None
69
+ mlfoundry_version: Optional[str] = None
70
+ truefoundry_version: Optional[str] = None
71
+
72
+ def dict(self, *args, **kwargs):
73
+ dct = super().dict(*args, **kwargs)
74
+ dct["framework"] = dct["framework"].value
75
+ return dct
76
+
77
+
78
+ class ModelVersionDownloadInfo(BaseModel):
79
+ download_dir: str
80
+ model_dir: str
81
+ model_framework: ModelFramework = ModelFramework.UNKNOWN
82
+ model_filename: Optional[str] = None
83
+
84
+
85
+ class ModelVersion:
86
+ def __init__(
87
+ self,
88
+ model_version: ModelVersionDto,
89
+ model: ModelDto,
90
+ ) -> None:
91
+ self._api_client = _get_api_client()
92
+ self._mlfoundry_artifacts_api = MlfoundryArtifactsApi(
93
+ api_client=self._api_client
94
+ )
95
+ self._model_version = model_version
96
+ self._model = model
97
+ self._deleted = False
98
+ self._description: str = ""
99
+ self._metadata: Dict[str, Any] = {}
100
+ self._metrics: List[MetricDto] = []
101
+ self._set_metrics_attr()
102
+ self._set_mutable_attrs()
103
+
104
+ @classmethod
105
+ def from_fqn(cls, fqn: str) -> "ModelVersion":
106
+ """
107
+ Get the version of a model to download contents or load them in memory
108
+
109
+ Args:
110
+ fqn (str): Fully qualified name of the model version.
111
+
112
+ Returns:
113
+ ModelVersion: An ModelVersion instance of the Model
114
+
115
+ Examples:
116
+
117
+ ```python
118
+ from truefoundry.ml import get_client, ModelVersion
119
+
120
+ client = get_client()
121
+ model_version = ModelVersion.from_fqn(fqn="<your-model-fqn>")
122
+ ```
123
+ """
124
+ api_client = _get_api_client()
125
+ mlfoundry_artifacts_api = MlfoundryArtifactsApi(api_client=api_client)
126
+ _model_version = mlfoundry_artifacts_api.get_model_version_by_fqn_get(fqn=fqn)
127
+ model_version = _model_version.model_version
128
+ _model = mlfoundry_artifacts_api.get_model_get(id=model_version.model_id)
129
+ model = _model.model
130
+ instance = cls(model_version=model_version, model=model)
131
+ return instance
132
+
133
+ def _ensure_not_deleted(self):
134
+ if self._deleted:
135
+ raise MlFoundryException(
136
+ "Model Version was deleted, cannot perform updates on a deleted version"
137
+ )
138
+
139
+ def _set_metrics_attr(self):
140
+ self._metrics = sorted(
141
+ self._model_version.metrics or [], key=lambda m: m.timestamp
142
+ )
143
+
144
+ def _set_mutable_attrs(self):
145
+ self._description = self._model_version.description or ""
146
+ self._metadata = copy.deepcopy(self._model_version.artifact_metadata)
147
+
148
+ def _refetch_model_version(self):
149
+ _model_version = self._mlfoundry_artifacts_api.get_model_version_get(
150
+ id=self._model_version.id
151
+ )
152
+ self._model_version = _model_version.model_version
153
+ self._set_metrics_attr()
154
+ self._set_mutable_attrs()
155
+
156
+ def __repr__(self):
157
+ return f"{self.__class__.__name__}(fqn={self.fqn!r})"
158
+
159
+ def _get_artifacts_repo(self):
160
+ return MlFoundryArtifactsRepository(
161
+ artifact_identifier=ArtifactIdentifier(
162
+ artifact_version_id=uuid.UUID(self._model_version.id)
163
+ ),
164
+ api_client=self._api_client,
165
+ )
166
+
167
+ @property
168
+ def name(self) -> str:
169
+ """Get the name of the model"""
170
+ return self._model.name
171
+
172
+ @property
173
+ def model_fqn(self) -> str:
174
+ """Get fqn of the model"""
175
+ return self._model.fqn
176
+
177
+ @property
178
+ def version(self) -> int:
179
+ """Get version information of the model"""
180
+ return self._model_version.version
181
+
182
+ @property
183
+ def fqn(self) -> str:
184
+ """Get fqn of the current model version"""
185
+ return self._model_version.fqn
186
+
187
+ @property
188
+ def step(self) -> int:
189
+ """Get the step in which model was created"""
190
+ return self._model_version.step
191
+
192
+ @property
193
+ def description(self) -> Optional[str]:
194
+ """Get description of the model"""
195
+ return self._description
196
+
197
+ @description.setter
198
+ def description(self, value: str):
199
+ """set the description of the model"""
200
+ _validate_description(value)
201
+ self._description = value
202
+
203
+ @property
204
+ def metadata(self) -> Dict[str, Any]:
205
+ """Get metadata for the current model"""
206
+ return self._metadata
207
+
208
+ @metadata.setter
209
+ def metadata(self, value: Dict[str, Any]):
210
+ """set the metadata for current model"""
211
+ _validate_artifact_metadata(value)
212
+ self._metadata = value
213
+
214
+ @property
215
+ def metrics(self) -> Dict[str, Union[float, int]]:
216
+ """get the metrics for the current version of the model"""
217
+ metrics_as_kv: Dict[str, Union[float, int]] = {}
218
+ for metric in self._metrics:
219
+ metrics_as_kv[metric.key] = metric.value
220
+ return metrics_as_kv
221
+
222
+ @property
223
+ def created_by(self) -> str:
224
+ """Get the information about who created the model version"""
225
+ return self._model_version.created_by
226
+
227
+ @property
228
+ def created_at(self) -> datetime.datetime:
229
+ """Get the time at which model version was created"""
230
+ return self._model_version.created_at
231
+
232
+ @property
233
+ def updated_at(self) -> datetime.datetime:
234
+ """Get the information about when the model version was updated"""
235
+ return self._model_version.updated_at
236
+
237
+ def raw_download(
238
+ self,
239
+ path: Optional[Union[str, Path]],
240
+ overwrite: bool = False,
241
+ progress: Optional[bool] = None,
242
+ ) -> str:
243
+ """
244
+ Download a model file or directory to a local directory if applicable, and return a
245
+ local path for it.
246
+
247
+ Args:
248
+ path (str): Absolute path of the local filesystem destination directory to which to
249
+ download the specified models. This directory must already exist.
250
+ If unspecified, the models will either be downloaded to a new
251
+ uniquely-named directory on the local filesystem.
252
+ overwrite (bool): If True it will overwrite the file if it is already present in the download directory else
253
+ it will throw an error
254
+ progress (bool): value to show progress bar, defaults to None.
255
+
256
+ Returns:
257
+ path: Absolute path of the local filesystem location containing the desired models.
258
+
259
+ Examples:
260
+
261
+ ```python
262
+ from truefoundry.ml import get_client
263
+
264
+ client = get_client()
265
+ model_version = client.get_model_version_by_fqn(fqn="<your-model-fqn>")
266
+ model_version.raw_download(path="<your-desired-download-path>")
267
+ ```
268
+ """
269
+ logger.info("Downloading model version contents, this might take a while ...")
270
+ artifacts_repo = self._get_artifacts_repo()
271
+ return artifacts_repo.download_artifacts(
272
+ artifact_path="", dst_path=path, overwrite=overwrite, progress=progress
273
+ )
274
+
275
+ def _download(
276
+ self,
277
+ path: Optional[Union[str, Path]],
278
+ overwrite: bool = False,
279
+ progress: Optional[bool] = None,
280
+ ) -> Tuple[ModelVersionInternalMetadata, ModelVersionDownloadInfo]:
281
+ self._ensure_not_deleted()
282
+ download_dir = self.raw_download(
283
+ path=path, overwrite=overwrite, progress=progress
284
+ )
285
+ internal_metadata_path = os.path.join(download_dir, INTERNAL_METADATA_PATH)
286
+ if not os.path.exists(internal_metadata_path):
287
+ raise MlFoundryException(
288
+ "Model version seems to be corrupted or in invalid format due to missing model metadata. "
289
+ "You can still use .raw_download(path='/your/path/here') to download and inspect files."
290
+ )
291
+ with open(internal_metadata_path) as f:
292
+ internal_metadata = ModelVersionInternalMetadata.parse_obj(json.load(f))
293
+ download_info = ModelVersionDownloadInfo(
294
+ download_dir=os.path.join(download_dir, internal_metadata.files_dir),
295
+ model_dir=os.path.join(
296
+ download_dir, internal_metadata.files_dir, internal_metadata.model_dir
297
+ ),
298
+ model_framework=internal_metadata.framework,
299
+ model_filename=internal_metadata.model_filename,
300
+ )
301
+ return internal_metadata, download_info
302
+
303
+ def download(
304
+ self,
305
+ path: Optional[Union[str, Path]],
306
+ overwrite: bool = False,
307
+ progress: Optional[bool] = None,
308
+ ) -> ModelVersionDownloadInfo:
309
+ """
310
+ Download a model file or directory to a local directory if applicable, and return download info
311
+ containing `model_dir` - local path where model was downloaded
312
+
313
+ Args:
314
+ path (str): Absolute path of the local filesystem destination directory to which to
315
+ download the specified models. This directory must already exist.
316
+ If unspecified, the models will either be downloaded to a new
317
+ uniquely-named directory on the local filesystem.
318
+ overwrite (bool): If True it will overwrite the file if it is already present in the download directory else
319
+ it will throw an error
320
+ progress (bool): value to show progress bar, defaults to None.
321
+
322
+ Returns:
323
+ ModelVersionDownloadInfo: Download Info instance containing
324
+ `model_dir` (path to downloaded model folder) and other metadata
325
+
326
+ Examples:
327
+
328
+ ```python
329
+ from truefoundry.ml import get_client
330
+
331
+ client = get_client()
332
+ model_version = client.get_model_version_by_fqn(fqn="<your-model-fqn>")
333
+ download_info = model_version.download(path="<your-desired-download-path>")
334
+ print(download_info.model_dir)
335
+ ```
336
+ """
337
+ _, download_info = self._download(
338
+ path=path, overwrite=overwrite, progress=progress
339
+ )
340
+ return download_info
341
+
342
+ def delete(self) -> bool:
343
+ """
344
+ Deletes the current instance of the ModelVersion hence deleting the current version.
345
+
346
+ Returns:
347
+ True if model was deleted successfully
348
+
349
+ Examples:
350
+
351
+ ```python
352
+ from truefoundry.ml import get_client
353
+
354
+ client = get_client()
355
+ model_version = client.get_model_version_by_fqn(fqn="<your-model-fqn>")
356
+ model_version.delete()
357
+ ```
358
+ """
359
+ self._ensure_not_deleted()
360
+ self._mlfoundry_artifacts_api.delete_artifact_version_post(
361
+ delete_artifact_versions_request_dto=DeleteArtifactVersionsRequestDto(
362
+ id=self._model_version.id
363
+ )
364
+ )
365
+ self._deleted = True
366
+ return True
367
+
368
+ def update(self):
369
+ """
370
+ Updates the current instance of the ModelVersion hence updating the current version.
371
+
372
+ Examples:
373
+
374
+ ```python
375
+ from truefoundry.ml import get_client
376
+
377
+ client = get_client()
378
+ model_version = client.get_model_version_by_fqn(fqn="<your-model-fqn>")
379
+ model_version.description = 'This is the new description'
380
+ model_version.update()
381
+ ```
382
+ """
383
+ self._ensure_not_deleted()
384
+ _model_version = self._mlfoundry_artifacts_api.update_model_version_post(
385
+ update_model_version_request_dto=UpdateModelVersionRequestDto(
386
+ id=self._model_version.id,
387
+ description=self.description,
388
+ artifact_metadata=self.metadata,
389
+ )
390
+ )
391
+ self._model_version = _model_version.model_version
392
+ self._set_metrics_attr()
393
+ self._set_mutable_attrs()
394
+
395
+
396
+ def calculate_model_size(artifact_dir: tempfile.TemporaryDirectory):
397
+ """
398
+ Tells about the size of the model
399
+
400
+ Args:
401
+ artifact_dir (str): directory in which model is present.
402
+
403
+ Returns:
404
+ total size of the model
405
+ """
406
+ total_size = 0
407
+ for path, _dirs, files in os.walk(artifact_dir.name):
408
+ for f in files:
409
+ file_path = os.path.join(path, f)
410
+ total_size += os.stat(file_path).st_size
411
+ return total_size
412
+
413
+
414
+ def _log_model_version( # noqa: C901
415
+ run: Optional["MlFoundryRun"],
416
+ name: str,
417
+ model_file_or_folder: str,
418
+ framework: Optional[Union[ModelFramework, str]],
419
+ mlfoundry_artifacts_api: Optional[MlfoundryArtifactsApi] = None,
420
+ ml_repo_id: Optional[str] = None,
421
+ additional_files: Sequence[Tuple[Union[str, Path], Optional[str]]] = (),
422
+ description: Optional[str] = None,
423
+ metadata: Optional[Dict[str, Any]] = None,
424
+ model_schema: Optional[Union[Dict[str, Any], ModelSchema]] = None,
425
+ custom_metrics: Optional[List[Union[CustomMetric, Dict[str, Any]]]] = None,
426
+ step: Optional[int] = 0,
427
+ progress: Optional[bool] = None,
428
+ ) -> ModelVersion:
429
+ if (run and mlfoundry_artifacts_api) or (not run and not mlfoundry_artifacts_api):
430
+ raise MlFoundryException(
431
+ "Exactly one of run, mlfoundry_artifacts_api should be passed"
432
+ )
433
+ if mlfoundry_artifacts_api and not ml_repo_id:
434
+ raise MlFoundryException(
435
+ "If mlfoundry_artifacts_api is passed, ml_repo_id must also be passed"
436
+ )
437
+ if run:
438
+ mlfoundry_artifacts_api = run._mlfoundry_artifacts_api
439
+
440
+ assert mlfoundry_artifacts_api is not None
441
+
442
+ custom_metrics = custom_metrics or []
443
+ metadata = metadata or {}
444
+ additional_files = additional_files or {}
445
+ step = step or 0
446
+
447
+ # validations
448
+ if framework is None:
449
+ framework = ModelFramework.UNKNOWN
450
+ elif not isinstance(framework, ModelFramework):
451
+ framework = ModelFramework(framework)
452
+
453
+ _validate_description(description)
454
+ _validate_artifact_metadata(metadata)
455
+
456
+ if model_schema is not None and not isinstance(model_schema, ModelSchema):
457
+ model_schema = ModelSchema.parse_obj(model_schema)
458
+
459
+ if custom_metrics and not model_schema:
460
+ raise MlFoundryException(
461
+ "Custom Metrics defined without adding the Model Schema"
462
+ )
463
+ custom_metrics = [
464
+ CustomMetric.parse_obj(cm) if not isinstance(cm, CustomMetric) else cm
465
+ for cm in custom_metrics
466
+ ]
467
+
468
+ logger.info("Logging model and additional files, this might take a while ...")
469
+ temp_dir = tempfile.TemporaryDirectory(prefix="truefoundry-")
470
+
471
+ internal_metadata = ModelVersionInternalMetadata(
472
+ framework=framework,
473
+ files_dir=FILES_DIR,
474
+ model_dir=MODEL_DIR_NAME,
475
+ model_filename=(
476
+ os.path.basename(model_file_or_folder)
477
+ if model_file_or_folder and os.path.isfile(model_file_or_folder)
478
+ else None
479
+ ),
480
+ mlfoundry_version=__version__,
481
+ truefoundry_version=__version__,
482
+ )
483
+
484
+ try:
485
+ local_files_dir = os.path.join(temp_dir.name, internal_metadata.files_dir)
486
+ os.makedirs(local_files_dir, exist_ok=True)
487
+ # in case model was None, we still create an empty dir
488
+ local_model_dir = os.path.join(local_files_dir, internal_metadata.model_dir)
489
+ os.makedirs(local_model_dir, exist_ok=True)
490
+
491
+ logger.info("Adding model file/folder to model version content")
492
+ model_file_or_folder = [
493
+ (model_file_or_folder, MODEL_DIR_NAME.rstrip(os.sep) + os.sep)
494
+ ]
495
+ _copy_additional_files(
496
+ root_dir=temp_dir.name,
497
+ files_dir=internal_metadata.files_dir,
498
+ model_dir=internal_metadata.model_dir,
499
+ additional_files=model_file_or_folder,
500
+ ignore_model_dir_dest_conflict=True,
501
+ )
502
+
503
+ # verify additional files and paths, copy additional files
504
+ if additional_files:
505
+ logger.info("Adding `additional_files` to model version contents")
506
+ _copy_additional_files(
507
+ root_dir=temp_dir.name,
508
+ files_dir=internal_metadata.files_dir,
509
+ model_dir=internal_metadata.model_dir,
510
+ additional_files=additional_files,
511
+ ignore_model_dir_dest_conflict=False,
512
+ )
513
+
514
+ except Exception as e:
515
+ temp_dir.cleanup()
516
+ raise MlFoundryException("Failed to log model") from e
517
+
518
+ # save internal metadata
519
+ local_internal_metadata_path = os.path.join(temp_dir.name, INTERNAL_METADATA_PATH)
520
+ os.makedirs(os.path.dirname(local_internal_metadata_path), exist_ok=True)
521
+ with open(local_internal_metadata_path, "w") as f:
522
+ json.dump(internal_metadata.dict(), f)
523
+
524
+ # create entry
525
+ _create_artifact_version_response = (
526
+ mlfoundry_artifacts_api.create_artifact_version_post(
527
+ create_artifact_version_request_dto=CreateArtifactVersionRequestDto(
528
+ experiment_id=int(run._experiment_id if run else ml_repo_id),
529
+ artifact_type=ArtifactType.MODEL,
530
+ name=name,
531
+ )
532
+ )
533
+ )
534
+ version_id = _create_artifact_version_response.id
535
+ artifacts_repo = MlFoundryArtifactsRepository(
536
+ artifact_identifier=ArtifactIdentifier(
537
+ artifact_version_id=uuid.UUID(version_id)
538
+ ),
539
+ api_client=mlfoundry_artifacts_api.api_client,
540
+ )
541
+ model_size = calculate_model_size(temp_dir)
542
+ try:
543
+ logger.info(
544
+ "Packaging and uploading files to remote with Total Size: %.6f MB",
545
+ model_size / 1000000.0,
546
+ )
547
+ artifacts_repo.log_artifacts(
548
+ local_dir=temp_dir.name, artifact_path=None, progress=progress
549
+ )
550
+ except Exception as e:
551
+ mlfoundry_artifacts_api.notify_failure_post(
552
+ notify_artifact_version_failure_dto=NotifyArtifactVersionFailureDto(
553
+ id=version_id
554
+ )
555
+ )
556
+ raise MlFoundryException("Failed to log model") from e
557
+ finally:
558
+ temp_dir.cleanup()
559
+
560
+ # Note: Here we call from_dict instead of directly passing in init and relying on it
561
+ # to convert because the complicated union of types generates a custom type to handle casting
562
+ # Check the source of `InternalMetadataDto` to see the generated code
563
+ internal_metadata_dto = InternalMetadataDto.from_dict(
564
+ internal_metadata.dict() if internal_metadata is not None else {}
565
+ )
566
+ mlfoundry_artifacts_api.finalize_artifact_version_post(
567
+ finalize_artifact_version_request_dto=FinalizeArtifactVersionRequestDto(
568
+ id=version_id,
569
+ run_uuid=run.run_id if run else None,
570
+ artifact_size=model_size,
571
+ internal_metadata=internal_metadata_dto,
572
+ step=step if run else None,
573
+ )
574
+ )
575
+ _model_version = mlfoundry_artifacts_api.create_model_version_post(
576
+ create_model_version_request_dto=CreateModelVersionRequestDto(
577
+ artifact_version_id=version_id,
578
+ description=description,
579
+ artifact_metadata=metadata,
580
+ internal_metadata=internal_metadata_dto,
581
+ data_path=INTERNAL_METADATA_PATH,
582
+ step=step if run else None,
583
+ )
584
+ )
585
+ model_version = _model_version.model_version
586
+
587
+ # update model schema at end
588
+ update_args: Dict[str, Any] = {
589
+ "id": version_id,
590
+ "model_framework": framework.value,
591
+ }
592
+ if model_schema:
593
+ update_args["model_schema"] = model_schema
594
+
595
+ try:
596
+ _model_version = mlfoundry_artifacts_api.update_model_version_post(
597
+ update_model_version_request_dto=UpdateModelVersionRequestDto(**update_args)
598
+ )
599
+ model_version = _model_version.model_version
600
+ if model_schema:
601
+ _model_version = mlfoundry_artifacts_api.add_custom_metrics_to_model_version_post(
602
+ add_custom_metrics_to_model_version_request_dto=AddCustomMetricsToModelVersionRequestDto(
603
+ id=version_id, custom_metrics=custom_metrics
604
+ )
605
+ )
606
+ model_version = _model_version.model_version
607
+ except Exception:
608
+ # TODO (chiragjn): what is the best exception to catch here?
609
+ logger.error(MODEL_SCHEMA_UPDATE_FAILURE_HELP.format(fqn=model_version.fqn))
610
+
611
+ return ModelVersion.from_fqn(fqn=model_version.fqn)
@@ -0,0 +1,48 @@
1
+ import enum
2
+ from typing import List, Type, TypeVar
3
+
4
+ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
5
+ ModelSchemaDto,
6
+ )
7
+ from truefoundry.ml.exceptions import MlFoundryException
8
+ from truefoundry.pydantic_v1 import BaseModel
9
+
10
+ T = TypeVar("T")
11
+
12
+
13
+ class BaseEnum(enum.Enum):
14
+ @classmethod
15
+ def values(cls: Type[T]) -> List[T]:
16
+ return [member.value for member in cls]
17
+
18
+ @classmethod
19
+ def _missing_(cls: Type[T], value: object):
20
+ raise MlFoundryException(
21
+ f"Unknown value for type {cls.__name__}: {value}", status_code=400
22
+ )
23
+
24
+
25
+ @enum.unique
26
+ class CustomMetricValueType(str, BaseEnum):
27
+ FLOAT = "float"
28
+
29
+
30
+ @enum.unique
31
+ class CustomMetricType(str, BaseEnum):
32
+ METRIC = "metric"
33
+ PROJECTION = "projection"
34
+
35
+
36
+ class CustomMetric(BaseModel):
37
+ class Config:
38
+ validate_assignment = True
39
+ use_enum_values = True
40
+ extra = "allow"
41
+
42
+ name: str
43
+ value_type: CustomMetricValueType
44
+ type: CustomMetricType
45
+
46
+
47
+ class ModelSchema(ModelSchemaDto):
48
+ pass