zenml-nightly 0.68.0.dev20241027__py3-none-any.whl → 0.68.1.dev20241101__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.
- README.md +17 -11
- RELEASE_NOTES.md +9 -0
- zenml/VERSION +1 -1
- zenml/__init__.py +1 -1
- zenml/analytics/context.py +16 -1
- zenml/analytics/utils.py +18 -7
- zenml/artifacts/utils.py +40 -216
- zenml/cli/__init__.py +63 -90
- zenml/cli/base.py +3 -3
- zenml/cli/login.py +951 -0
- zenml/cli/server.py +462 -353
- zenml/cli/service_accounts.py +4 -4
- zenml/cli/stack.py +77 -2
- zenml/cli/stack_components.py +5 -16
- zenml/cli/user_management.py +0 -12
- zenml/cli/utils.py +24 -77
- zenml/client.py +46 -14
- zenml/config/compiler.py +1 -0
- zenml/config/global_config.py +9 -0
- zenml/config/pipeline_configurations.py +2 -1
- zenml/config/pipeline_run_configuration.py +2 -1
- zenml/constants.py +3 -9
- zenml/enums.py +1 -1
- zenml/exceptions.py +11 -0
- zenml/integrations/github/code_repositories/github_code_repository.py +1 -1
- zenml/login/__init__.py +16 -0
- zenml/login/credentials.py +346 -0
- zenml/login/credentials_store.py +603 -0
- zenml/login/pro/__init__.py +16 -0
- zenml/login/pro/client.py +496 -0
- zenml/login/pro/constants.py +34 -0
- zenml/login/pro/models.py +25 -0
- zenml/login/pro/organization/__init__.py +14 -0
- zenml/login/pro/organization/client.py +79 -0
- zenml/login/pro/organization/models.py +32 -0
- zenml/login/pro/tenant/__init__.py +14 -0
- zenml/login/pro/tenant/client.py +92 -0
- zenml/login/pro/tenant/models.py +174 -0
- zenml/login/pro/utils.py +121 -0
- zenml/{cli → login}/web_login.py +64 -28
- zenml/materializers/base_materializer.py +43 -9
- zenml/materializers/built_in_materializer.py +1 -1
- zenml/metadata/metadata_types.py +49 -0
- zenml/model/model.py +0 -38
- zenml/models/__init__.py +3 -0
- zenml/models/v2/base/base.py +12 -8
- zenml/models/v2/base/filter.py +9 -0
- zenml/models/v2/core/artifact_version.py +49 -10
- zenml/models/v2/core/component.py +54 -19
- zenml/models/v2/core/flavor.py +13 -13
- zenml/models/v2/core/model.py +3 -1
- zenml/models/v2/core/model_version.py +3 -5
- zenml/models/v2/core/model_version_artifact.py +3 -1
- zenml/models/v2/core/model_version_pipeline_run.py +3 -1
- zenml/models/v2/core/pipeline.py +3 -1
- zenml/models/v2/core/pipeline_run.py +23 -1
- zenml/models/v2/core/run_template.py +3 -1
- zenml/models/v2/core/stack.py +7 -3
- zenml/models/v2/core/step_run.py +43 -2
- zenml/models/v2/misc/auth_models.py +11 -2
- zenml/models/v2/misc/server_models.py +2 -0
- zenml/orchestrators/base_orchestrator.py +8 -4
- zenml/orchestrators/step_launcher.py +1 -0
- zenml/orchestrators/step_run_utils.py +10 -2
- zenml/orchestrators/step_runner.py +67 -55
- zenml/orchestrators/utils.py +45 -22
- zenml/pipelines/pipeline_decorator.py +5 -0
- zenml/pipelines/pipeline_definition.py +206 -160
- zenml/pipelines/run_utils.py +11 -10
- zenml/services/local/local_daemon_entrypoint.py +4 -4
- zenml/services/service.py +2 -2
- zenml/stack/stack.py +2 -6
- zenml/stack/stack_component.py +2 -7
- zenml/stack/utils.py +26 -14
- zenml/steps/base_step.py +8 -2
- zenml/steps/step_context.py +0 -3
- zenml/steps/step_invocation.py +14 -5
- zenml/steps/utils.py +1 -0
- zenml/utils/materializer_utils.py +1 -1
- zenml/utils/requirements_utils.py +71 -0
- zenml/utils/singleton.py +15 -3
- zenml/utils/source_utils.py +39 -2
- zenml/utils/visualization_utils.py +1 -1
- zenml/zen_server/auth.py +44 -39
- zenml/zen_server/deploy/__init__.py +7 -7
- zenml/zen_server/deploy/base_provider.py +46 -73
- zenml/zen_server/deploy/{local → daemon}/__init__.py +3 -3
- zenml/zen_server/deploy/{local/local_provider.py → daemon/daemon_provider.py} +44 -63
- zenml/zen_server/deploy/{local/local_zen_server.py → daemon/daemon_zen_server.py} +50 -22
- zenml/zen_server/deploy/deployer.py +90 -171
- zenml/zen_server/deploy/deployment.py +20 -12
- zenml/zen_server/deploy/docker/docker_provider.py +9 -28
- zenml/zen_server/deploy/docker/docker_zen_server.py +19 -3
- zenml/zen_server/deploy/helm/Chart.yaml +1 -1
- zenml/zen_server/deploy/helm/README.md +2 -2
- zenml/zen_server/exceptions.py +11 -0
- zenml/zen_server/jwt.py +9 -9
- zenml/zen_server/routers/auth_endpoints.py +30 -8
- zenml/zen_server/routers/stack_components_endpoints.py +1 -1
- zenml/zen_server/routers/workspaces_endpoints.py +1 -1
- zenml/zen_server/template_execution/runner_entrypoint_configuration.py +7 -4
- zenml/zen_server/template_execution/utils.py +6 -61
- zenml/zen_server/utils.py +64 -36
- zenml/zen_stores/base_zen_store.py +4 -49
- zenml/zen_stores/migrations/versions/0.68.1_release.py +23 -0
- zenml/zen_stores/migrations/versions/c22561cbb3a9_add_artifact_unique_constraints.py +86 -0
- zenml/zen_stores/rest_zen_store.py +325 -147
- zenml/zen_stores/schemas/api_key_schemas.py +9 -4
- zenml/zen_stores/schemas/artifact_schemas.py +21 -2
- zenml/zen_stores/schemas/artifact_visualization_schemas.py +1 -1
- zenml/zen_stores/schemas/component_schemas.py +49 -6
- zenml/zen_stores/schemas/device_schemas.py +9 -4
- zenml/zen_stores/schemas/flavor_schemas.py +1 -1
- zenml/zen_stores/schemas/model_schemas.py +1 -1
- zenml/zen_stores/schemas/service_schemas.py +1 -1
- zenml/zen_stores/schemas/step_run_schemas.py +1 -1
- zenml/zen_stores/schemas/trigger_schemas.py +1 -1
- zenml/zen_stores/sql_zen_store.py +393 -140
- zenml/zen_stores/template_utils.py +3 -1
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/METADATA +18 -12
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/RECORD +124 -107
- zenml/api.py +0 -60
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/entry_points.txt +0 -0
README.md
CHANGED
@@ -228,22 +228,28 @@ And finally, here are some other examples and use cases for inspiration:
|
|
228
228
|
5. [LLMops](https://github.com/zenml-io/zenml-projects/tree/main/llm-complete-guide): Complete guide to do LLM with ZenML
|
229
229
|
|
230
230
|
|
231
|
+
## 📚 Learn from Books
|
232
|
+
|
233
|
+
<div align="center">
|
234
|
+
<a href="https://www.amazon.com/LLM-Engineers-Handbook-engineering-production/dp/1836200072">
|
235
|
+
<img src="docs/book/.gitbook/assets/llm_engineering_handbook_cover.jpg" alt="LLM Engineer's Handbook Cover" width="200"/></img>
|
236
|
+
</a>
|
237
|
+
<a href="https://www.amazon.com/-/en/Andrew-McMahon/dp/1837631964">
|
238
|
+
<img src="docs/book/.gitbook/assets/ml_engineering_with_python.jpg" alt="Machine Learning Engineering with Python Cover" width="200"/></img>
|
239
|
+
</a>
|
240
|
+
</br></br>
|
241
|
+
</div>
|
242
|
+
|
243
|
+
ZenML is featured in these comprehensive guides to modern MLOps and LLM engineering. Learn how to build production-ready machine learning systems with real-world examples and best practices.
|
244
|
+
|
231
245
|
## 🔋 Deploy ZenML
|
232
246
|
|
233
247
|
For full functionality ZenML should be deployed on the cloud to
|
234
248
|
enable collaborative features as the central MLOps interface for teams.
|
235
249
|
|
236
|
-
|
250
|
+
Read more about various deployment options [here](https://docs.zenml.io/getting-started/deploying-zenml).
|
237
251
|
|
238
|
-
|
239
|
-
offers a SaaS version which comes with a control plane to create and manage multiple ZenML servers.
|
240
|
-
These servers are managed and maintained by ZenML’s dedicated team, alleviating
|
241
|
-
the burden of server management from your end. They also come with additional features like RBAC, a Model Control Plane
|
242
|
-
and [much more](https://zenml-io.gitbook.io/zenml-documentation/getting-started/zenml-pro.
|
243
|
-
- **Self-hosted deployment**: Alternatively, you have the flexibility to [deploy
|
244
|
-
ZenML on your own self-hosted environment](https://docs.zenml.io/getting-started/deploying-zenml#deploying-a-zenml-server).
|
245
|
-
This can be achieved through various methods, including using our CLI, Docker,
|
246
|
-
Helm, or HuggingFace Spaces.
|
252
|
+
Or, sign up for [ZenML Pro to get a fully managed server on a free trial](https://cloud.zenml.io/?utm_source=readme&utm_medium=referral_link&utm_campaign=cloud_promotion&utm_content=signup_link).
|
247
253
|
|
248
254
|
## Use ZenML with VS Code
|
249
255
|
|
@@ -327,7 +333,7 @@ the Apache License Version 2.0.
|
|
327
333
|
<a href="https://github.com/zenml-io/zenml-projects">Projects Showcase</a>
|
328
334
|
<br />
|
329
335
|
<br />
|
330
|
-
🎉 Version 0.68.
|
336
|
+
🎉 Version 0.68.1 is out. Check out the release notes
|
331
337
|
<a href="https://github.com/zenml-io/zenml/releases">here</a>.
|
332
338
|
<br />
|
333
339
|
🖥️ Download our VS Code Extension <a href="https://marketplace.visualstudio.com/items?itemName=ZenML.zenml-vscode">here</a>.
|
RELEASE_NOTES.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
<!-- markdown-link-check-disable -->
|
2
2
|
|
3
|
+
# 0.68.1
|
4
|
+
|
5
|
+
Fixes an issue with some partially cached pipelines running on remote orchestrators.
|
6
|
+
|
7
|
+
## What's Changed
|
8
|
+
* Remove unavailable upstream steps during cache precomputation by @schustmi in https://github.com/zenml-io/zenml/pull/3146
|
9
|
+
|
10
|
+
**Full Changelog**: https://github.com/zenml-io/zenml/compare/0.68.0...0.68.1
|
11
|
+
|
3
12
|
# 0.68.0
|
4
13
|
|
5
14
|
## Highlights
|
zenml/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.68.
|
1
|
+
0.68.1.dev20241101
|
zenml/__init__.py
CHANGED
@@ -31,7 +31,7 @@ init_logging()
|
|
31
31
|
from zenml.models import * # noqa: F401
|
32
32
|
|
33
33
|
# Define public Python API
|
34
|
-
from zenml.
|
34
|
+
from zenml.zen_server.utils import show_dashboard as show
|
35
35
|
from zenml.artifacts.utils import (
|
36
36
|
log_artifact_metadata,
|
37
37
|
save_artifact,
|
zenml/analytics/context.py
CHANGED
@@ -25,6 +25,7 @@ from uuid import UUID
|
|
25
25
|
|
26
26
|
from zenml import __version__
|
27
27
|
from zenml.analytics.client import default_client
|
28
|
+
from zenml.analytics.utils import is_analytics_disabled_internally
|
28
29
|
from zenml.constants import (
|
29
30
|
ENV_ZENML_SERVER,
|
30
31
|
handle_bool_env_var,
|
@@ -73,14 +74,28 @@ class AnalyticsContext:
|
|
73
74
|
Returns:
|
74
75
|
The analytics context.
|
75
76
|
"""
|
77
|
+
if is_analytics_disabled_internally():
|
78
|
+
self.analytics_opt_in = False
|
79
|
+
return self
|
80
|
+
|
76
81
|
# Fetch the analytics opt-in setting
|
77
82
|
from zenml.config.global_config import GlobalConfiguration
|
78
83
|
|
79
84
|
try:
|
80
85
|
gc = GlobalConfiguration()
|
86
|
+
|
87
|
+
if not gc.is_initialized:
|
88
|
+
# If the global configuration is not initialized, using the
|
89
|
+
# zen store can lead to multiple initialization issues, because
|
90
|
+
# the analytics are triggered during the initialization of the
|
91
|
+
# zen store.
|
92
|
+
return self
|
93
|
+
|
81
94
|
store_info = gc.zen_store.get_store_info()
|
82
95
|
|
83
|
-
|
96
|
+
# For local ZenML servers, we always use the client's analytics
|
97
|
+
# opt-in configuration.
|
98
|
+
if self.in_server and not store_info.is_local():
|
84
99
|
self.analytics_opt_in = store_info.analytics_enabled
|
85
100
|
else:
|
86
101
|
self.analytics_opt_in = gc.analytics_opt_in
|
zenml/analytics/utils.py
CHANGED
@@ -14,7 +14,6 @@
|
|
14
14
|
"""Utility functions and classes for ZenML analytics."""
|
15
15
|
|
16
16
|
import json
|
17
|
-
import os
|
18
17
|
from functools import wraps
|
19
18
|
from typing import Any, Callable, Dict, Optional, TypeVar, cast
|
20
19
|
from uuid import UUID
|
@@ -22,13 +21,15 @@ from uuid import UUID
|
|
22
21
|
from zenml.analytics import identify, track
|
23
22
|
from zenml.analytics.enums import AnalyticsEvent
|
24
23
|
from zenml.analytics.models import AnalyticsTrackedModelMixin
|
25
|
-
from zenml.constants import ENV_ZENML_ANALYTICS_OPT_IN
|
26
24
|
from zenml.logger import get_logger
|
27
25
|
|
28
26
|
logger = get_logger(__name__)
|
29
27
|
F = TypeVar("F", bound=Callable[..., Any])
|
30
28
|
|
31
29
|
|
30
|
+
_INTERNAL_DISABLE_ANALYTICS = False
|
31
|
+
|
32
|
+
|
32
33
|
class AnalyticsEncoder(json.JSONEncoder):
|
33
34
|
"""Helper encoder class for JSON serialization."""
|
34
35
|
|
@@ -101,11 +102,13 @@ class analytics_disabler:
|
|
101
102
|
|
102
103
|
def __init__(self) -> None:
|
103
104
|
"""Initialization of the context manager."""
|
104
|
-
self.original_value =
|
105
|
+
self.original_value: Optional[bool] = None
|
105
106
|
|
106
107
|
def __enter__(self) -> None:
|
107
108
|
"""Disable the analytics."""
|
108
|
-
|
109
|
+
global _INTERNAL_DISABLE_ANALYTICS
|
110
|
+
self.original_value = _INTERNAL_DISABLE_ANALYTICS
|
111
|
+
_INTERNAL_DISABLE_ANALYTICS = True
|
109
112
|
|
110
113
|
def __exit__(
|
111
114
|
self,
|
@@ -120,10 +123,18 @@ class analytics_disabler:
|
|
120
123
|
exc_value: The instance of the exception
|
121
124
|
traceback: The traceback of the exception
|
122
125
|
"""
|
126
|
+
global _INTERNAL_DISABLE_ANALYTICS
|
123
127
|
if self.original_value is not None:
|
124
|
-
|
125
|
-
|
126
|
-
|
128
|
+
_INTERNAL_DISABLE_ANALYTICS = self.original_value
|
129
|
+
|
130
|
+
|
131
|
+
def is_analytics_disabled_internally() -> bool:
|
132
|
+
"""Whether analytics are disabled by an internal helper function.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
Whether analytics are disabled by an internal helper function.
|
136
|
+
"""
|
137
|
+
return _INTERNAL_DISABLE_ANALYTICS
|
127
138
|
|
128
139
|
|
129
140
|
def track_decorator(event: AnalyticsEvent) -> Callable[[F], F]:
|
zenml/artifacts/utils.py
CHANGED
@@ -16,13 +16,11 @@
|
|
16
16
|
import base64
|
17
17
|
import os
|
18
18
|
import tempfile
|
19
|
-
import time
|
20
19
|
import zipfile
|
21
20
|
from pathlib import Path
|
22
21
|
from typing import (
|
23
22
|
TYPE_CHECKING,
|
24
23
|
Any,
|
25
|
-
Callable,
|
26
24
|
Dict,
|
27
25
|
List,
|
28
26
|
Optional,
|
@@ -38,7 +36,6 @@ from zenml.artifacts.load_directory_materializer import (
|
|
38
36
|
)
|
39
37
|
from zenml.client import Client
|
40
38
|
from zenml.constants import (
|
41
|
-
MAX_RETRIES_FOR_VERSIONED_ENTITY_CREATION,
|
42
39
|
MODEL_METADATA_YAML_FILE_NAME,
|
43
40
|
)
|
44
41
|
from zenml.enums import (
|
@@ -50,13 +47,12 @@ from zenml.enums import (
|
|
50
47
|
)
|
51
48
|
from zenml.exceptions import (
|
52
49
|
DoesNotExistException,
|
53
|
-
EntityExistsError,
|
54
50
|
StepContextError,
|
55
51
|
)
|
56
52
|
from zenml.io import fileio
|
57
53
|
from zenml.logger import get_logger
|
54
|
+
from zenml.metadata.metadata_types import validate_metadata
|
58
55
|
from zenml.models import (
|
59
|
-
ArtifactRequest,
|
60
56
|
ArtifactVersionRequest,
|
61
57
|
ArtifactVersionResponse,
|
62
58
|
ArtifactVisualizationRequest,
|
@@ -65,7 +61,6 @@ from zenml.models import (
|
|
65
61
|
StepRunResponse,
|
66
62
|
StepRunUpdate,
|
67
63
|
)
|
68
|
-
from zenml.models.v2.core.artifact import ArtifactResponse
|
69
64
|
from zenml.stack import StackComponent
|
70
65
|
from zenml.steps.step_context import get_step_context
|
71
66
|
from zenml.utils import source_utils
|
@@ -135,12 +130,6 @@ def save_artifact(
|
|
135
130
|
|
136
131
|
client = Client()
|
137
132
|
|
138
|
-
artifact = _get_or_create_artifact(
|
139
|
-
name=name,
|
140
|
-
has_custom_name=has_custom_name,
|
141
|
-
tags=tags,
|
142
|
-
)
|
143
|
-
|
144
133
|
# Get the current artifact store
|
145
134
|
artifact_store = client.active_stack.artifact_store
|
146
135
|
|
@@ -176,7 +165,7 @@ def save_artifact(
|
|
176
165
|
|
177
166
|
# Save the artifact to the artifact store
|
178
167
|
data_type = type(data)
|
179
|
-
materializer_object.
|
168
|
+
materializer_object.validate_save_type_compatibility(data_type)
|
180
169
|
materializer_object.save(data)
|
181
170
|
|
182
171
|
# Save visualizations of the artifact
|
@@ -207,52 +196,35 @@ def save_artifact(
|
|
207
196
|
f"Failed to extract metadata for output artifact '{name}': {e}"
|
208
197
|
)
|
209
198
|
|
210
|
-
|
211
|
-
|
212
|
-
version: Union[int, str],
|
213
|
-
) -> Optional[ArtifactVersionResponse]:
|
214
|
-
artifact_version = ArtifactVersionRequest(
|
215
|
-
artifact_id=artifact.id,
|
216
|
-
version=version,
|
217
|
-
tags=tags,
|
218
|
-
type=materializer_object.ASSOCIATED_ARTIFACT_TYPE,
|
219
|
-
uri=materializer_object.uri,
|
220
|
-
materializer=source_utils.resolve(materializer_object.__class__),
|
221
|
-
data_type=source_utils.resolve(data_type),
|
222
|
-
user=Client().active_user.id,
|
223
|
-
workspace=Client().active_workspace.id,
|
224
|
-
artifact_store_id=artifact_store.id,
|
225
|
-
visualizations=visualizations,
|
226
|
-
has_custom_name=has_custom_name,
|
227
|
-
)
|
228
|
-
try:
|
229
|
-
return client.zen_store.create_artifact_version(
|
230
|
-
artifact_version=artifact_version
|
231
|
-
)
|
232
|
-
except EntityExistsError:
|
233
|
-
return None
|
234
|
-
|
235
|
-
response = _create_artifact_version_with_retries(
|
236
|
-
name=name,
|
199
|
+
artifact_version_request = ArtifactVersionRequest(
|
200
|
+
artifact_name=name,
|
237
201
|
version=version,
|
238
|
-
|
202
|
+
tags=tags,
|
203
|
+
type=materializer_object.ASSOCIATED_ARTIFACT_TYPE,
|
204
|
+
uri=materializer_object.uri,
|
205
|
+
materializer=source_utils.resolve(materializer_object.__class__),
|
206
|
+
data_type=source_utils.resolve(data_type),
|
207
|
+
user=Client().active_user.id,
|
208
|
+
workspace=Client().active_workspace.id,
|
209
|
+
artifact_store_id=artifact_store.id,
|
210
|
+
visualizations=visualizations,
|
211
|
+
has_custom_name=has_custom_name,
|
212
|
+
metadata=validate_metadata(artifact_metadata)
|
213
|
+
if artifact_metadata
|
214
|
+
else None,
|
215
|
+
)
|
216
|
+
artifact_version = client.zen_store.create_artifact_version(
|
217
|
+
artifact_version=artifact_version_request
|
239
218
|
)
|
240
|
-
|
241
|
-
if artifact_metadata:
|
242
|
-
client.create_run_metadata(
|
243
|
-
metadata=artifact_metadata,
|
244
|
-
resource_id=response.id,
|
245
|
-
resource_type=MetadataResourceTypes.ARTIFACT_VERSION,
|
246
|
-
)
|
247
219
|
|
248
220
|
if manual_save:
|
249
221
|
_link_artifact_version_to_the_step_and_model(
|
250
|
-
artifact_version=
|
222
|
+
artifact_version=artifact_version,
|
251
223
|
is_model_artifact=is_model_artifact,
|
252
224
|
is_deployment_artifact=is_deployment_artifact,
|
253
225
|
)
|
254
226
|
|
255
|
-
return
|
227
|
+
return artifact_version
|
256
228
|
|
257
229
|
|
258
230
|
def register_artifact(
|
@@ -304,56 +276,33 @@ def register_artifact(
|
|
304
276
|
name=name,
|
305
277
|
)
|
306
278
|
|
307
|
-
|
308
|
-
|
309
|
-
|
279
|
+
artifact_version_request = ArtifactVersionRequest(
|
280
|
+
artifact_name=name,
|
281
|
+
version=version,
|
310
282
|
tags=tags,
|
283
|
+
type=ArtifactType.DATA,
|
284
|
+
uri=folder_or_file_uri,
|
285
|
+
materializer=source_utils.resolve(PreexistingDataMaterializer),
|
286
|
+
data_type=source_utils.resolve(Path),
|
287
|
+
user=Client().active_user.id,
|
288
|
+
workspace=Client().active_workspace.id,
|
289
|
+
artifact_store_id=artifact_store.id,
|
290
|
+
has_custom_name=has_custom_name,
|
291
|
+
metadata=validate_metadata(artifact_metadata)
|
292
|
+
if artifact_metadata
|
293
|
+
else None,
|
311
294
|
)
|
312
|
-
|
313
|
-
|
314
|
-
def _create_version(
|
315
|
-
version: Union[int, str],
|
316
|
-
) -> Optional[ArtifactVersionResponse]:
|
317
|
-
artifact_version = ArtifactVersionRequest(
|
318
|
-
artifact_id=artifact.id,
|
319
|
-
version=version,
|
320
|
-
tags=tags,
|
321
|
-
type=ArtifactType.DATA,
|
322
|
-
uri=folder_or_file_uri,
|
323
|
-
materializer=source_utils.resolve(PreexistingDataMaterializer),
|
324
|
-
data_type=source_utils.resolve(Path),
|
325
|
-
user=Client().active_user.id,
|
326
|
-
workspace=Client().active_workspace.id,
|
327
|
-
artifact_store_id=artifact_store.id,
|
328
|
-
has_custom_name=has_custom_name,
|
329
|
-
)
|
330
|
-
try:
|
331
|
-
return client.zen_store.create_artifact_version(
|
332
|
-
artifact_version=artifact_version
|
333
|
-
)
|
334
|
-
except EntityExistsError:
|
335
|
-
return None
|
336
|
-
|
337
|
-
response = _create_artifact_version_with_retries(
|
338
|
-
name=name,
|
339
|
-
version=version,
|
340
|
-
create_version_fn=_create_version,
|
295
|
+
artifact_version = client.zen_store.create_artifact_version(
|
296
|
+
artifact_version=artifact_version_request
|
341
297
|
)
|
342
298
|
|
343
|
-
if artifact_metadata:
|
344
|
-
client.create_run_metadata(
|
345
|
-
metadata=artifact_metadata,
|
346
|
-
resource_id=response.id,
|
347
|
-
resource_type=MetadataResourceTypes.ARTIFACT_VERSION,
|
348
|
-
)
|
349
|
-
|
350
299
|
_link_artifact_version_to_the_step_and_model(
|
351
|
-
artifact_version=
|
300
|
+
artifact_version=artifact_version,
|
352
301
|
is_model_artifact=is_model_artifact,
|
353
302
|
is_deployment_artifact=is_deployment_artifact,
|
354
303
|
)
|
355
304
|
|
356
|
-
return
|
305
|
+
return artifact_version
|
357
306
|
|
358
307
|
|
359
308
|
def load_artifact(
|
@@ -662,107 +611,6 @@ def _check_if_artifact_with_given_uri_already_registered(
|
|
662
611
|
)
|
663
612
|
|
664
613
|
|
665
|
-
def _get_or_create_artifact(
|
666
|
-
name: str, has_custom_name: bool, tags: Optional[List[str]] = None
|
667
|
-
) -> ArtifactResponse:
|
668
|
-
"""Get or create an artifact with the given name.
|
669
|
-
|
670
|
-
Args:
|
671
|
-
name: The name of the artifact.
|
672
|
-
has_custom_name: If the artifact name is custom and should be listed in
|
673
|
-
the dashboard "Artifacts" tab.
|
674
|
-
tags: Tags to associate with the artifact.
|
675
|
-
|
676
|
-
Returns:
|
677
|
-
The artifact.
|
678
|
-
"""
|
679
|
-
client = Client()
|
680
|
-
# Get or create the artifact
|
681
|
-
try:
|
682
|
-
artifact = client.list_artifacts(name=name)[0]
|
683
|
-
if artifact.has_custom_name != has_custom_name:
|
684
|
-
client.update_artifact(
|
685
|
-
name_id_or_prefix=artifact.id, has_custom_name=has_custom_name
|
686
|
-
)
|
687
|
-
except IndexError:
|
688
|
-
try:
|
689
|
-
artifact = client.zen_store.create_artifact(
|
690
|
-
ArtifactRequest(
|
691
|
-
name=name,
|
692
|
-
has_custom_name=has_custom_name,
|
693
|
-
tags=tags,
|
694
|
-
)
|
695
|
-
)
|
696
|
-
except EntityExistsError:
|
697
|
-
artifact = client.list_artifacts(name=name)[0]
|
698
|
-
return artifact
|
699
|
-
|
700
|
-
|
701
|
-
def _create_artifact_version_with_retries(
|
702
|
-
name: str,
|
703
|
-
version: Optional[Union[int, str]],
|
704
|
-
create_version_fn: Callable[
|
705
|
-
[
|
706
|
-
Union[int, str],
|
707
|
-
],
|
708
|
-
Optional[ArtifactVersionResponse],
|
709
|
-
],
|
710
|
-
) -> ArtifactVersionResponse:
|
711
|
-
"""Create an artifact version with some retries.
|
712
|
-
|
713
|
-
This function will retry the creation of an artifact version up to
|
714
|
-
MAX_RETRIES_FOR_VERSIONED_ENTITY_CREATION times if it fails.
|
715
|
-
It can fail in high-concurrency environments.
|
716
|
-
|
717
|
-
Args:
|
718
|
-
name: The name of the artifact.
|
719
|
-
version: The version of the artifact. If not provided, a new
|
720
|
-
auto-incremented version will be used.
|
721
|
-
create_version_fn: The function to create the artifact version.
|
722
|
-
|
723
|
-
Returns:
|
724
|
-
The created artifact version.
|
725
|
-
|
726
|
-
Raises:
|
727
|
-
EntityExistsError: If the artifact version could not be created
|
728
|
-
after MAX_RETRIES_FOR_VERSIONED_ENTITY_CREATION attempts due
|
729
|
-
to collisions.
|
730
|
-
|
731
|
-
"""
|
732
|
-
response = None
|
733
|
-
if not version:
|
734
|
-
retries_made = 0
|
735
|
-
for i in range(MAX_RETRIES_FOR_VERSIONED_ENTITY_CREATION):
|
736
|
-
# Get new artifact version
|
737
|
-
version = _get_new_artifact_version(name)
|
738
|
-
if response := create_version_fn(version):
|
739
|
-
break
|
740
|
-
# smoothed exponential back-off, it will go as 0.2, 0.3,
|
741
|
-
# 0.45, 0.68, 1.01, 1.52, 2.28, 3.42, 5.13, 7.69, ...
|
742
|
-
sleep = 0.2 * 1.5**i
|
743
|
-
logger.debug(
|
744
|
-
f"Failed to create artifact version `{version}` for "
|
745
|
-
f"artifact `{name}`. Retrying in {sleep}..."
|
746
|
-
)
|
747
|
-
time.sleep(sleep)
|
748
|
-
retries_made += 1
|
749
|
-
if not response:
|
750
|
-
raise EntityExistsError(
|
751
|
-
f"Failed to create new artifact version for artifact "
|
752
|
-
f"`{name}`. Retried {retries_made} times. "
|
753
|
-
"This could be driven by exceptionally high concurrency of "
|
754
|
-
"pipeline runs. Please, reach out to us on ZenML Slack for support."
|
755
|
-
)
|
756
|
-
else:
|
757
|
-
response = create_version_fn(version)
|
758
|
-
if not response:
|
759
|
-
raise EntityExistsError(
|
760
|
-
f"Failed to create artifact version `{version}` for artifact "
|
761
|
-
f"`{name}`. Given version already exists."
|
762
|
-
)
|
763
|
-
return response
|
764
|
-
|
765
|
-
|
766
614
|
def _link_artifact_version_to_the_step_and_model(
|
767
615
|
artifact_version: ArtifactVersionResponse,
|
768
616
|
is_model_artifact: bool,
|
@@ -962,30 +810,6 @@ def _get_artifact_store_from_response_or_from_active_stack(
|
|
962
810
|
return Client().active_stack.artifact_store
|
963
811
|
|
964
812
|
|
965
|
-
def _get_new_artifact_version(artifact_name: str) -> int:
|
966
|
-
"""Get the next auto-incremented version for an artifact name.
|
967
|
-
|
968
|
-
Args:
|
969
|
-
artifact_name: The name of the artifact.
|
970
|
-
|
971
|
-
Returns:
|
972
|
-
The next auto-incremented version.
|
973
|
-
"""
|
974
|
-
artifact_versions = Client().list_artifact_versions(
|
975
|
-
name=artifact_name,
|
976
|
-
sort_by="desc:version_number",
|
977
|
-
size=1,
|
978
|
-
)
|
979
|
-
|
980
|
-
# If a numbered version exists, increment it
|
981
|
-
try:
|
982
|
-
return int(artifact_versions[0].version) + 1
|
983
|
-
|
984
|
-
# If no numbered versions exist yet, start at 1
|
985
|
-
except (IndexError, ValueError):
|
986
|
-
return 1
|
987
|
-
|
988
|
-
|
989
813
|
def _load_file_from_artifact_store(
|
990
814
|
uri: str,
|
991
815
|
artifact_store: "BaseArtifactStore",
|