zenml-nightly 0.61.0.dev20240712__py3-none-any.whl → 0.62.0.dev20240727__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 +2 -2
- RELEASE_NOTES.md +40 -0
- zenml/VERSION +1 -1
- zenml/__init__.py +2 -0
- zenml/cli/stack.py +114 -248
- zenml/cli/stack_components.py +5 -3
- zenml/config/pipeline_spec.py +2 -2
- zenml/config/step_configurations.py +3 -3
- zenml/constants.py +3 -0
- zenml/enums.py +16 -0
- zenml/integrations/__init__.py +1 -0
- zenml/integrations/azure/__init__.py +2 -2
- zenml/integrations/constants.py +1 -0
- zenml/integrations/databricks/__init__.py +52 -0
- zenml/integrations/databricks/flavors/__init__.py +30 -0
- zenml/integrations/databricks/flavors/databricks_model_deployer_flavor.py +118 -0
- zenml/integrations/databricks/flavors/databricks_orchestrator_flavor.py +147 -0
- zenml/integrations/databricks/model_deployers/__init__.py +20 -0
- zenml/integrations/databricks/model_deployers/databricks_model_deployer.py +249 -0
- zenml/integrations/databricks/orchestrators/__init__.py +20 -0
- zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +497 -0
- zenml/integrations/databricks/orchestrators/databricks_orchestrator_entrypoint_config.py +97 -0
- zenml/integrations/databricks/services/__init__.py +19 -0
- zenml/integrations/databricks/services/databricks_deployment.py +407 -0
- zenml/integrations/databricks/utils/__init__.py +14 -0
- zenml/integrations/databricks/utils/databricks_utils.py +87 -0
- zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +44 -28
- zenml/integrations/great_expectations/data_validators/ge_data_validator.py +12 -8
- zenml/integrations/huggingface/materializers/huggingface_datasets_materializer.py +88 -3
- zenml/integrations/huggingface/steps/accelerate_runner.py +1 -7
- zenml/integrations/kubernetes/__init__.py +3 -2
- zenml/integrations/kubernetes/flavors/__init__.py +8 -0
- zenml/integrations/kubernetes/flavors/kubernetes_step_operator_flavor.py +166 -0
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +1 -13
- zenml/integrations/kubernetes/orchestrators/manifest_utils.py +22 -4
- zenml/integrations/kubernetes/pod_settings.py +4 -0
- zenml/integrations/kubernetes/step_operators/__init__.py +22 -0
- zenml/integrations/kubernetes/step_operators/kubernetes_step_operator.py +235 -0
- zenml/integrations/lightgbm/__init__.py +1 -0
- zenml/integrations/mlflow/__init__.py +1 -1
- zenml/integrations/mlflow/model_registries/mlflow_model_registry.py +6 -2
- zenml/integrations/mlflow/services/mlflow_deployment.py +1 -1
- zenml/integrations/skypilot_azure/__init__.py +1 -3
- zenml/integrations/skypilot_lambda/__init__.py +1 -1
- zenml/logging/step_logging.py +34 -35
- zenml/materializers/built_in_materializer.py +1 -1
- zenml/materializers/cloudpickle_materializer.py +1 -1
- zenml/model/model.py +1 -1
- zenml/models/v2/core/code_repository.py +2 -2
- zenml/models/v2/core/component.py +29 -0
- zenml/models/v2/core/server_settings.py +0 -20
- zenml/models/v2/misc/full_stack.py +32 -0
- zenml/models/v2/misc/stack_deployment.py +5 -0
- zenml/new/pipelines/run_utils.py +1 -1
- zenml/orchestrators/__init__.py +4 -0
- zenml/orchestrators/step_launcher.py +1 -0
- zenml/orchestrators/wheeled_orchestrator.py +147 -0
- zenml/service_connectors/service_connector_utils.py +408 -0
- zenml/stack_deployments/azure_stack_deployment.py +179 -0
- zenml/stack_deployments/gcp_stack_deployment.py +13 -4
- zenml/stack_deployments/stack_deployment.py +10 -0
- zenml/stack_deployments/utils.py +4 -0
- zenml/steps/base_step.py +7 -5
- zenml/utils/function_utils.py +1 -1
- zenml/utils/pipeline_docker_image_builder.py +8 -0
- zenml/utils/source_utils.py +4 -1
- zenml/zen_server/dashboard/assets/{404-DpJaNHKF.js → 404-B_YdvmwS.js} +1 -1
- zenml/zen_server/dashboard/assets/{@reactflow-DJfzkHO1.js → @reactflow-l_1hUr1S.js} +1 -1
- zenml/zen_server/dashboard/assets/{AwarenessChannel-BYDLT2xC.js → AwarenessChannel-CFg5iX4Z.js} +1 -1
- zenml/zen_server/dashboard/assets/{CodeSnippet-BkOuRmyq.js → CodeSnippet-Dvkx_82E.js} +1 -1
- zenml/zen_server/dashboard/assets/CollapsibleCard-opiuBHHc.js +1 -0
- zenml/zen_server/dashboard/assets/{Commands-ZvWR1BRs.js → Commands-DoN1xrEq.js} +1 -1
- zenml/zen_server/dashboard/assets/{CopyButton-DVwLkafa.js → CopyButton-Cr7xYEPb.js} +1 -1
- zenml/zen_server/dashboard/assets/{CsvVizualization-C2IiqX4I.js → CsvVizualization-Ck-nZ43m.js} +3 -3
- zenml/zen_server/dashboard/assets/{Error-CqX0VqW_.js → Error-kLtljEOM.js} +1 -1
- zenml/zen_server/dashboard/assets/{ExecutionStatus-BoLUXR9t.js → ExecutionStatus-DguLLgTK.js} +1 -1
- zenml/zen_server/dashboard/assets/{Helpbox-LFydyVwh.js → Helpbox-BXUMP21n.js} +1 -1
- zenml/zen_server/dashboard/assets/{Infobox-DnENC0sh.js → Infobox-DSt0O-dm.js} +1 -1
- zenml/zen_server/dashboard/assets/{InlineAvatar-CbJtYr0t.js → InlineAvatar-xsrsIGE-.js} +1 -1
- zenml/zen_server/dashboard/assets/Pagination-C6X-mifw.js +1 -0
- zenml/zen_server/dashboard/assets/{SetPassword-BYBdbQDo.js → SetPassword-BXGTWiwj.js} +1 -1
- zenml/zen_server/dashboard/assets/{SuccessStep-Nx743hll.js → SuccessStep-DZC60t0x.js} +1 -1
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DF9gSzE0.js → UpdatePasswordSchemas-DGvwFWO1.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-right-double-BiEMg7rd.js → chevron-right-double-CZBOf6JM.js} +1 -1
- zenml/zen_server/dashboard/assets/cloud-only-C_yFCAkP.js +1 -0
- zenml/zen_server/dashboard/assets/index-BczVOqUf.js +55 -0
- zenml/zen_server/dashboard/assets/index-EpMIKgrI.css +1 -0
- zenml/zen_server/dashboard/assets/{login-mutation-BUnVASxp.js → login-mutation-CrHrndTI.js} +1 -1
- zenml/zen_server/dashboard/assets/logs-D8k8BVFf.js +1 -0
- zenml/zen_server/dashboard/assets/{not-found-B4VnX8gK.js → not-found-DYa4pC-C.js} +1 -1
- zenml/zen_server/dashboard/assets/{package-CsUhPmou.js → package-B3fWP-Dh.js} +1 -1
- zenml/zen_server/dashboard/assets/page-1h_sD1jz.js +1 -0
- zenml/zen_server/dashboard/assets/{page-Sxn82W-5.js → page-1iL8aMqs.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DMOYZppS.js → page-2grKx_MY.js} +1 -1
- zenml/zen_server/dashboard/assets/page-5NCOHOsy.js +1 -0
- zenml/zen_server/dashboard/assets/{page-JyfeDUfu.js → page-8a4UMKXZ.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-Bx6o0ARS.js → page-B6h3iaHJ.js} +1 -1
- zenml/zen_server/dashboard/assets/page-BDns21Iz.js +1 -0
- zenml/zen_server/dashboard/assets/{page-3efNCDeb.js → page-BhgCDInH.js} +2 -2
- zenml/zen_server/dashboard/assets/{page-DKlIdAe5.js → page-Bi-wtWiO.js} +2 -2
- zenml/zen_server/dashboard/assets/{page-7zTHbhhI.js → page-BkeAAYwp.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CRTJ0UuR.js → page-BkuQDIf-.js} +1 -1
- zenml/zen_server/dashboard/assets/page-BnaevhnB.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BEs6jK71.js → page-Bq0YxkLV.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Bs2F4eoD.js +2 -0
- zenml/zen_server/dashboard/assets/{page-CUZIGO-3.js → page-C6-UGEbH.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-Xu8JEjSU.js → page-CCNRIt_f.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DvCvroOM.js → page-CHNxpz3n.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BpSqIf4B.js → page-DgorQFqi.js} +1 -1
- zenml/zen_server/dashboard/assets/page-K8ebxVIs.js +1 -0
- zenml/zen_server/dashboard/assets/{page-Cx67M0QT.js → page-MFQyIJd3.js} +1 -1
- zenml/zen_server/dashboard/assets/page-TgCF0P_U.js +1 -0
- zenml/zen_server/dashboard/assets/page-ZnCEe-eK.js +9 -0
- zenml/zen_server/dashboard/assets/{page-Dc_7KMQE.js → page-uA5prJGY.js} +1 -1
- zenml/zen_server/dashboard/assets/persist-D7HJNBWx.js +1 -0
- zenml/zen_server/dashboard/assets/plus-C8WOyCzt.js +1 -0
- zenml/zen_server/dashboard/assets/stack-detail-query-Cficsl6d.js +1 -0
- zenml/zen_server/dashboard/assets/update-server-settings-mutation-7d8xi1tS.js +1 -0
- zenml/zen_server/dashboard/assets/{url-DuQMeqYA.js → url-D7mAQGUM.js} +1 -1
- zenml/zen_server/dashboard/index.html +4 -4
- zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
- zenml/zen_server/dashboard_legacy/index.html +1 -1
- zenml/zen_server/dashboard_legacy/{precache-manifest.c8c57fb0d2132b1d3c2119e776b7dfb3.js → precache-manifest.12246c7548e71e2c4438e496360de80c.js} +4 -4
- zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
- zenml/zen_server/dashboard_legacy/static/js/main.3b27024b.chunk.js +2 -0
- zenml/zen_server/dashboard_legacy/static/js/{main.382439a7.chunk.js.map → main.3b27024b.chunk.js.map} +1 -1
- zenml/zen_server/deploy/helm/Chart.yaml +1 -1
- zenml/zen_server/deploy/helm/README.md +2 -2
- zenml/zen_server/rbac/utils.py +10 -2
- zenml/zen_server/routers/devices_endpoints.py +4 -1
- zenml/zen_server/routers/server_endpoints.py +29 -2
- zenml/zen_server/routers/service_connectors_endpoints.py +57 -0
- zenml/zen_server/routers/steps_endpoints.py +2 -1
- zenml/zen_stores/migrations/versions/0.62.0_release.py +23 -0
- zenml/zen_stores/migrations/versions/b4fca5241eea_migrate_onboarding_state.py +167 -0
- zenml/zen_stores/rest_zen_store.py +4 -0
- zenml/zen_stores/schemas/component_schemas.py +14 -0
- zenml/zen_stores/schemas/server_settings_schemas.py +23 -11
- zenml/zen_stores/sql_zen_store.py +151 -1
- {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240727.dist-info}/METADATA +5 -5
- {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240727.dist-info}/RECORD +144 -121
- zenml/zen_server/dashboard/assets/Pagination-DEbVUupy.js +0 -1
- zenml/zen_server/dashboard/assets/chevron-down-D_ZlKMqH.js +0 -1
- zenml/zen_server/dashboard/assets/cloud-only-DVbIeckv.js +0 -1
- zenml/zen_server/dashboard/assets/index-C_CrU4vI.js +0 -1
- zenml/zen_server/dashboard/assets/index-DK1ynKjA.js +0 -55
- zenml/zen_server/dashboard/assets/index-inApY3KQ.css +0 -1
- zenml/zen_server/dashboard/assets/page-C43QGHTt.js +0 -9
- zenml/zen_server/dashboard/assets/page-CR0OG7ss.js +0 -1
- zenml/zen_server/dashboard/assets/page-CaopxiU1.js +0 -1
- zenml/zen_server/dashboard/assets/page-D7Z399xy.js +0 -1
- zenml/zen_server/dashboard/assets/page-D93kd7Xj.js +0 -1
- zenml/zen_server/dashboard/assets/page-DMsSn3dv.js +0 -2
- zenml/zen_server/dashboard/assets/page-Hus2pr9T.js +0 -1
- zenml/zen_server/dashboard/assets/page-TKXERe16.js +0 -1
- zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +0 -1
- zenml/zen_server/dashboard/assets/update-server-settings-mutation-CR8e3Sir.js +0 -1
- zenml/zen_server/dashboard_legacy/static/js/main.382439a7.chunk.js +0 -2
- {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240727.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240727.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.61.0.dev20240712.dist-info → zenml_nightly-0.62.0.dev20240727.dist-info}/entry_points.txt +0 -0
@@ -371,7 +371,7 @@ class MLFlowModelRegistry(BaseModelRegistry):
|
|
371
371
|
self.get_model(name=name)
|
372
372
|
except KeyError:
|
373
373
|
logger.info(
|
374
|
-
f"No registered model with name {name} found. Creating a new"
|
374
|
+
f"No registered model with name {name} found. Creating a new "
|
375
375
|
"registered model."
|
376
376
|
)
|
377
377
|
self.register_model(
|
@@ -615,7 +615,11 @@ class MLFlowModelRegistry(BaseModelRegistry):
|
|
615
615
|
for mlflow_model_version in mlflow_model_versions:
|
616
616
|
# check if given MlFlow model version matches the given request
|
617
617
|
# before casting it
|
618
|
-
if
|
618
|
+
if (
|
619
|
+
stage
|
620
|
+
and not ModelVersionStage(mlflow_model_version.current_stage)
|
621
|
+
== stage
|
622
|
+
):
|
619
623
|
continue
|
620
624
|
if created_after and not (
|
621
625
|
mlflow_model_version.creation_timestamp
|
@@ -260,7 +260,7 @@ class MLFlowDeploymentService(LocalDaemonService, BaseDeploymentService):
|
|
260
260
|
)
|
261
261
|
|
262
262
|
if self.endpoint.prediction_url is not None:
|
263
|
-
if type(request)
|
263
|
+
if type(request) is pd.DataFrame:
|
264
264
|
response = requests.post( # nosec
|
265
265
|
self.endpoint.prediction_url,
|
266
266
|
json={"instances": request.to_dict("records")},
|
@@ -19,13 +19,11 @@ orchestrator for a remote orchestration of ZenML pipelines on VMs.
|
|
19
19
|
from typing import List, Type
|
20
20
|
|
21
21
|
from zenml.integrations.constants import (
|
22
|
-
|
23
22
|
SKYPILOT_AZURE,
|
24
23
|
)
|
25
24
|
from zenml.integrations.integration import Integration
|
26
25
|
from zenml.stack import Flavor
|
27
26
|
|
28
|
-
|
29
27
|
SKYPILOT_AZURE_ORCHESTRATOR_FLAVOR = "vm_azure"
|
30
28
|
|
31
29
|
|
@@ -33,7 +31,7 @@ class SkypilotAzureIntegration(Integration):
|
|
33
31
|
"""Definition of Skypilot (Azure) Integration for ZenML."""
|
34
32
|
|
35
33
|
NAME = SKYPILOT_AZURE
|
36
|
-
REQUIREMENTS = ["skypilot[azure]
|
34
|
+
REQUIREMENTS = ["skypilot-nightly[azure]==1.0.0.dev20240716"]
|
37
35
|
APT_PACKAGES = ["openssh-client", "rsync"]
|
38
36
|
|
39
37
|
@classmethod
|
@@ -31,7 +31,7 @@ class SkypilotLambdaIntegration(Integration):
|
|
31
31
|
"""Definition of Skypilot Lambda Integration for ZenML."""
|
32
32
|
|
33
33
|
NAME = SKYPILOT_LAMBDA
|
34
|
-
REQUIREMENTS = ["skypilot[lambda]
|
34
|
+
REQUIREMENTS = ["skypilot[lambda]~=0.6.0"]
|
35
35
|
|
36
36
|
@classmethod
|
37
37
|
def flavors(cls) -> List[Type[Flavor]]:
|
zenml/logging/step_logging.py
CHANGED
@@ -240,8 +240,6 @@ class StepLogsStorage:
|
|
240
240
|
|
241
241
|
# Immutable filesystems state
|
242
242
|
self.last_merge_time = time.time()
|
243
|
-
self.log_files_not_merged: List[str] = []
|
244
|
-
self.next_merged_file_name: str = self._get_timestamped_filename()
|
245
243
|
|
246
244
|
@property
|
247
245
|
def artifact_store(self) -> "BaseArtifactStore":
|
@@ -279,13 +277,16 @@ class StepLogsStorage:
|
|
279
277
|
or time.time() - self.last_save_time >= self.time_interval
|
280
278
|
)
|
281
279
|
|
282
|
-
def _get_timestamped_filename(self) -> str:
|
280
|
+
def _get_timestamped_filename(self, suffix: str = "") -> str:
|
283
281
|
"""Returns a timestamped filename.
|
284
282
|
|
283
|
+
Args:
|
284
|
+
suffix: optional suffix for the file name
|
285
|
+
|
285
286
|
Returns:
|
286
287
|
The timestamped filename.
|
287
288
|
"""
|
288
|
-
return f"{time.time()}{LOGS_EXTENSION}"
|
289
|
+
return f"{time.time()}{suffix}{LOGS_EXTENSION}"
|
289
290
|
|
290
291
|
def save_to_file(self, force: bool = False) -> None:
|
291
292
|
"""Method to save the buffer to the given URI.
|
@@ -302,12 +303,7 @@ class StepLogsStorage:
|
|
302
303
|
try:
|
303
304
|
if self.buffer:
|
304
305
|
if self.artifact_store.config.IS_IMMUTABLE_FILESYSTEM:
|
305
|
-
if not self.log_files_not_merged:
|
306
|
-
self.next_merged_file_name = (
|
307
|
-
self._get_timestamped_filename()
|
308
|
-
)
|
309
306
|
_logs_uri = self._get_timestamped_filename()
|
310
|
-
self.log_files_not_merged.append(_logs_uri)
|
311
307
|
with self.artifact_store.open(
|
312
308
|
os.path.join(
|
313
309
|
self.logs_uri,
|
@@ -346,42 +342,40 @@ class StepLogsStorage:
|
|
346
342
|
and time.time() - self.last_merge_time > self.merge_files_interval
|
347
343
|
):
|
348
344
|
try:
|
349
|
-
self.merge_log_files(
|
350
|
-
self.next_merged_file_name, self.log_files_not_merged
|
351
|
-
)
|
345
|
+
self.merge_log_files()
|
352
346
|
except (OSError, IOError) as e:
|
353
347
|
logger.error(f"Error while trying to roll up logs: {e}")
|
354
|
-
else:
|
355
|
-
self.log_files_not_merged = []
|
356
348
|
finally:
|
357
349
|
self.last_merge_time = time.time()
|
358
350
|
|
359
|
-
def merge_log_files(
|
360
|
-
self,
|
361
|
-
file_name: Optional[str] = None,
|
362
|
-
files: Optional[List[str]] = None,
|
363
|
-
) -> None:
|
351
|
+
def merge_log_files(self, merge_all_files: bool = False) -> None:
|
364
352
|
"""Merges all log files into one in the given URI.
|
365
353
|
|
366
354
|
Called on the logging context exit.
|
367
355
|
|
368
356
|
Args:
|
369
|
-
|
370
|
-
files: The list of log files to merge.
|
357
|
+
merge_all_files: whether to merge all files or only raw files
|
371
358
|
"""
|
372
359
|
if self.artifact_store.config.IS_IMMUTABLE_FILESYSTEM:
|
373
|
-
|
374
|
-
|
360
|
+
merged_file_suffix = "_merged"
|
361
|
+
files_ = self.artifact_store.listdir(self.logs_uri)
|
362
|
+
if not merge_all_files:
|
363
|
+
# already merged files will not be merged again
|
364
|
+
files_ = [f for f in files_ if merged_file_suffix not in f]
|
365
|
+
file_name_ = self._get_timestamped_filename(
|
366
|
+
suffix=merged_file_suffix
|
367
|
+
)
|
375
368
|
if len(files_) > 1:
|
376
369
|
files_.sort()
|
377
370
|
logger.debug("Log files count: %s", len(files_))
|
378
371
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
372
|
+
missing_files = set()
|
373
|
+
# dump all logs to a local file first
|
374
|
+
with self.artifact_store.open(
|
375
|
+
os.path.join(self.logs_uri, file_name_), "w"
|
376
|
+
) as merged_file:
|
377
|
+
for file in files_:
|
378
|
+
try:
|
385
379
|
merged_file.write(
|
386
380
|
str(
|
387
381
|
_load_file_from_artifact_store(
|
@@ -391,11 +385,12 @@ class StepLogsStorage:
|
|
391
385
|
)
|
392
386
|
)
|
393
387
|
)
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
388
|
+
except DoesNotExistException:
|
389
|
+
missing_files.add(file)
|
390
|
+
|
391
|
+
# clean up left over files
|
392
|
+
for file in files_:
|
393
|
+
if file not in missing_files:
|
399
394
|
self.artifact_store.remove(
|
400
395
|
os.path.join(self.logs_uri, str(file))
|
401
396
|
)
|
@@ -452,7 +447,6 @@ class StepLogsStorageContext:
|
|
452
447
|
Restores the `write` method of both stderr and stdout.
|
453
448
|
"""
|
454
449
|
self.storage.save_to_file(force=True)
|
455
|
-
self.storage.merge_log_files()
|
456
450
|
|
457
451
|
setattr(sys.stdout, "write", self.stdout_write)
|
458
452
|
setattr(sys.stdout, "flush", self.stdout_flush)
|
@@ -462,6 +456,11 @@ class StepLogsStorageContext:
|
|
462
456
|
|
463
457
|
redirected.set(False)
|
464
458
|
|
459
|
+
try:
|
460
|
+
self.storage.merge_log_files(merge_all_files=True)
|
461
|
+
except (OSError, IOError) as e:
|
462
|
+
logger.warning(f"Step logs roll-up failed: {e}")
|
463
|
+
|
465
464
|
def _wrap_write(self, method: Callable[..., Any]) -> Callable[..., Any]:
|
466
465
|
"""Wrapper function that utilizes the storage object to store logs.
|
467
466
|
|
@@ -80,7 +80,7 @@ class BuiltInMaterializer(BaseMaterializer):
|
|
80
80
|
The data read.
|
81
81
|
"""
|
82
82
|
contents = yaml_utils.read_json(self.data_path)
|
83
|
-
if type(contents)
|
83
|
+
if type(contents) is not data_type:
|
84
84
|
# TODO [ENG-142]: Raise error or try to coerce
|
85
85
|
logger.debug(
|
86
86
|
f"Contents {contents} was type {type(contents)} but expected "
|
@@ -94,7 +94,7 @@ class CloudpickleMaterializer(BaseMaterializer):
|
|
94
94
|
"""
|
95
95
|
# Log a warning if this materializer was not explicitly specified for
|
96
96
|
# the given data type.
|
97
|
-
if type(self)
|
97
|
+
if type(self) is CloudpickleMaterializer:
|
98
98
|
logger.warning(
|
99
99
|
f"No materializer is registered for type `{type(data)}`, so "
|
100
100
|
"the default Pickle materializer was used. Pickle is not "
|
zenml/model/model.py
CHANGED
@@ -518,7 +518,7 @@ class Model(BaseModel):
|
|
518
518
|
and not suppress_class_validation_warnings
|
519
519
|
):
|
520
520
|
logger.info(
|
521
|
-
f"
|
521
|
+
f"Version `{version}` matches one of the possible "
|
522
522
|
"`ModelStages` and will be fetched using stage."
|
523
523
|
)
|
524
524
|
if str(version).isnumeric() and not suppress_class_validation_warnings:
|
@@ -18,7 +18,7 @@ from uuid import UUID
|
|
18
18
|
|
19
19
|
from pydantic import Field
|
20
20
|
|
21
|
-
from zenml.config.source import Source
|
21
|
+
from zenml.config.source import Source, SourceWithValidator
|
22
22
|
from zenml.constants import STR_FIELD_MAX_LENGTH, TEXT_FIELD_MAX_LENGTH
|
23
23
|
from zenml.models.v2.base.base import BaseUpdate
|
24
24
|
from zenml.models.v2.base.scoped import (
|
@@ -71,7 +71,7 @@ class CodeRepositoryUpdate(BaseUpdate):
|
|
71
71
|
description="Configuration for the code repository.",
|
72
72
|
default=None,
|
73
73
|
)
|
74
|
-
source: Optional[
|
74
|
+
source: Optional[SourceWithValidator] = Field(
|
75
75
|
description="The code repository source.", default=None
|
76
76
|
)
|
77
77
|
logo_url: Optional[str] = Field(
|
@@ -191,6 +191,17 @@ class ComponentResponseBody(WorkspaceScopedResponseBody):
|
|
191
191
|
title="The flavor of the stack component.",
|
192
192
|
max_length=STR_FIELD_MAX_LENGTH,
|
193
193
|
)
|
194
|
+
integration: Optional[str] = Field(
|
195
|
+
default=None,
|
196
|
+
title="The name of the integration that the component's flavor "
|
197
|
+
"belongs to.",
|
198
|
+
max_length=STR_FIELD_MAX_LENGTH,
|
199
|
+
)
|
200
|
+
logo_url: Optional[str] = Field(
|
201
|
+
default=None,
|
202
|
+
title="Optionally, a url pointing to a png,"
|
203
|
+
"svg or jpg can be attached.",
|
204
|
+
)
|
194
205
|
|
195
206
|
|
196
207
|
class ComponentResponseMetadata(WorkspaceScopedResponseMetadata):
|
@@ -285,6 +296,24 @@ class ComponentResponse(
|
|
285
296
|
"""
|
286
297
|
return self.get_body().flavor
|
287
298
|
|
299
|
+
@property
|
300
|
+
def integration(self) -> Optional[str]:
|
301
|
+
"""The `integration` property.
|
302
|
+
|
303
|
+
Returns:
|
304
|
+
the value of the property.
|
305
|
+
"""
|
306
|
+
return self.get_body().integration
|
307
|
+
|
308
|
+
@property
|
309
|
+
def logo_url(self) -> Optional[str]:
|
310
|
+
"""The `logo_url` property.
|
311
|
+
|
312
|
+
Returns:
|
313
|
+
the value of the property.
|
314
|
+
"""
|
315
|
+
return self.get_body().logo_url
|
316
|
+
|
288
317
|
@property
|
289
318
|
def configuration(self) -> Dict[str, Any]:
|
290
319
|
"""The `configuration` property.
|
@@ -15,8 +15,6 @@
|
|
15
15
|
|
16
16
|
from datetime import datetime
|
17
17
|
from typing import (
|
18
|
-
Any,
|
19
|
-
Dict,
|
20
18
|
Optional,
|
21
19
|
)
|
22
20
|
from uuid import UUID
|
@@ -57,10 +55,6 @@ class ServerSettingsUpdate(BaseZenModel):
|
|
57
55
|
default=None,
|
58
56
|
title="Whether to display notifications about ZenML updates in the dashboard.",
|
59
57
|
)
|
60
|
-
onboarding_state: Optional[Dict[str, Any]] = Field(
|
61
|
-
default=None,
|
62
|
-
title="The server's onboarding state.",
|
63
|
-
)
|
64
58
|
|
65
59
|
|
66
60
|
# ------------------ Response Model ------------------
|
@@ -96,11 +90,6 @@ class ServerSettingsResponseBody(BaseResponseBody):
|
|
96
90
|
class ServerSettingsResponseMetadata(BaseResponseMetadata):
|
97
91
|
"""Response metadata for server settings."""
|
98
92
|
|
99
|
-
onboarding_state: Dict[str, Any] = Field(
|
100
|
-
default={},
|
101
|
-
title="The server's onboarding state.",
|
102
|
-
)
|
103
|
-
|
104
93
|
|
105
94
|
class ServerSettingsResponseResources(BaseResponseResources):
|
106
95
|
"""Response resources for server settings."""
|
@@ -199,15 +188,6 @@ class ServerSettingsResponse(
|
|
199
188
|
"""
|
200
189
|
return self.get_body().updated
|
201
190
|
|
202
|
-
@property
|
203
|
-
def onboarding_state(self) -> Dict[str, Any]:
|
204
|
-
"""The `onboarding_state` property.
|
205
|
-
|
206
|
-
Returns:
|
207
|
-
the value of the property.
|
208
|
-
"""
|
209
|
-
return self.get_metadata().onboarding_state
|
210
|
-
|
211
191
|
|
212
192
|
# ------------------ Filter Model ------------------
|
213
193
|
|
@@ -21,6 +21,7 @@ from pydantic import BaseModel, Field, model_validator
|
|
21
21
|
from zenml.constants import STR_FIELD_MAX_LENGTH
|
22
22
|
from zenml.enums import StackComponentType
|
23
23
|
from zenml.models.v2.base.base import BaseRequest
|
24
|
+
from zenml.models.v2.core.component import ComponentResponse
|
24
25
|
|
25
26
|
|
26
27
|
class ServiceConnectorInfo(BaseModel):
|
@@ -95,3 +96,34 @@ class FullStackRequest(BaseRequest):
|
|
95
96
|
"the position in the list of service connectors."
|
96
97
|
)
|
97
98
|
return self
|
99
|
+
|
100
|
+
|
101
|
+
class ResourcesInfo(BaseModel):
|
102
|
+
"""Information about the resources needed for CLI and UI."""
|
103
|
+
|
104
|
+
flavor: str
|
105
|
+
flavor_display_name: str
|
106
|
+
required_configuration: Dict[str, str] = {}
|
107
|
+
use_resource_value_as_fixed_config: bool = False
|
108
|
+
|
109
|
+
accessible_by_service_connector: List[str]
|
110
|
+
connected_through_service_connector: List[ComponentResponse]
|
111
|
+
|
112
|
+
@model_validator(mode="after")
|
113
|
+
def _validate_resource_info(self) -> "ResourcesInfo":
|
114
|
+
if (
|
115
|
+
self.use_resource_value_as_fixed_config
|
116
|
+
and len(self.required_configuration) > 1
|
117
|
+
):
|
118
|
+
raise ValueError(
|
119
|
+
"Cannot use resource value as fixed config if more than one required configuration key is provided."
|
120
|
+
)
|
121
|
+
return self
|
122
|
+
|
123
|
+
|
124
|
+
class ServiceConnectorResourcesInfo(BaseModel):
|
125
|
+
"""Information about the service connector resources needed for CLI and UI."""
|
126
|
+
|
127
|
+
connector_type: str
|
128
|
+
|
129
|
+
components_resources_info: Dict[StackComponentType, List[ResourcesInfo]]
|
@@ -55,6 +55,11 @@ class StackDeploymentInfo(BaseModel):
|
|
55
55
|
description="The locations where the stack can be deployed, as a "
|
56
56
|
"dictionary mapping location names to descriptions.",
|
57
57
|
)
|
58
|
+
skypilot_default_regions: Dict[str, str] = Field(
|
59
|
+
title="The locations where the Skypilot clusters can be deployed by default.",
|
60
|
+
description="The locations where the Skypilot clusters can be deployed by default, as a "
|
61
|
+
"dictionary mapping location names to descriptions.",
|
62
|
+
)
|
58
63
|
|
59
64
|
|
60
65
|
class StackDeploymentConfig(BaseModel):
|
zenml/new/pipelines/run_utils.py
CHANGED
@@ -250,7 +250,7 @@ def _validate_new_version_requests(
|
|
250
250
|
if not is_cloud_model:
|
251
251
|
logger.info(
|
252
252
|
"Models can be viewed in the dashboard using ZenML Pro. Sign up "
|
253
|
-
"for a free trial at https://www.zenml.io/
|
253
|
+
"for a free trial at https://www.zenml.io/pro/"
|
254
254
|
)
|
255
255
|
|
256
256
|
|
zenml/orchestrators/__init__.py
CHANGED
@@ -30,6 +30,9 @@ from zenml.orchestrators.base_orchestrator import (
|
|
30
30
|
from zenml.orchestrators.containerized_orchestrator import (
|
31
31
|
ContainerizedOrchestrator,
|
32
32
|
)
|
33
|
+
from zenml.orchestrators.wheeled_orchestrator import (
|
34
|
+
WheeledOrchestrator,
|
35
|
+
)
|
33
36
|
from zenml.orchestrators.local.local_orchestrator import (
|
34
37
|
LocalOrchestrator,
|
35
38
|
LocalOrchestratorFlavor,
|
@@ -44,6 +47,7 @@ __all__ = [
|
|
44
47
|
"BaseOrchestratorConfig",
|
45
48
|
"BaseOrchestratorFlavor",
|
46
49
|
"ContainerizedOrchestrator",
|
50
|
+
"WheeledOrchestrator",
|
47
51
|
"LocalOrchestrator",
|
48
52
|
"LocalOrchestratorFlavor",
|
49
53
|
"LocalDockerOrchestrator",
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2021. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at:
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
12
|
+
# or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
"""Wheeled orchestrator class."""
|
15
|
+
|
16
|
+
import os
|
17
|
+
import re
|
18
|
+
import subprocess
|
19
|
+
import tempfile
|
20
|
+
from abc import ABC
|
21
|
+
|
22
|
+
from zenml import __version__
|
23
|
+
from zenml.io import fileio
|
24
|
+
from zenml.logger import get_logger
|
25
|
+
from zenml.orchestrators import BaseOrchestrator
|
26
|
+
from zenml.utils.io_utils import copy_dir
|
27
|
+
from zenml.utils.source_utils import get_source_root
|
28
|
+
|
29
|
+
logger = get_logger(__name__)
|
30
|
+
|
31
|
+
DEFAULT_PACKAGE_NAME = "zenmlproject"
|
32
|
+
|
33
|
+
|
34
|
+
class WheeledOrchestrator(BaseOrchestrator, ABC):
|
35
|
+
"""Base class for wheeled orchestrators."""
|
36
|
+
|
37
|
+
package_name = DEFAULT_PACKAGE_NAME
|
38
|
+
package_version = __version__
|
39
|
+
|
40
|
+
def copy_repository_to_temp_dir_and_add_setup_py(self) -> str:
|
41
|
+
"""Copy the repository to a temporary directory and add a setup.py file.
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
Path to the temporary directory containing the copied repository.
|
45
|
+
"""
|
46
|
+
repo_path = get_source_root()
|
47
|
+
|
48
|
+
self.package_name = f"{DEFAULT_PACKAGE_NAME}_{self.sanitize_name(os.path.basename(repo_path))}"
|
49
|
+
|
50
|
+
# Create a temporary folder
|
51
|
+
temp_dir = tempfile.mkdtemp(prefix="zenml-temp-")
|
52
|
+
|
53
|
+
# Create a folder within the temporary directory
|
54
|
+
temp_repo_path = os.path.join(temp_dir, self.package_name)
|
55
|
+
fileio.mkdir(temp_repo_path)
|
56
|
+
|
57
|
+
# Copy the repository to the temporary directory
|
58
|
+
copy_dir(repo_path, temp_repo_path)
|
59
|
+
|
60
|
+
# Create init file in the copied directory
|
61
|
+
init_file_path = os.path.join(temp_repo_path, "__init__.py")
|
62
|
+
with fileio.open(init_file_path, "w") as f:
|
63
|
+
f.write("")
|
64
|
+
|
65
|
+
# Create a setup.py file
|
66
|
+
setup_py_content = f"""
|
67
|
+
from setuptools import setup, find_packages
|
68
|
+
|
69
|
+
setup(
|
70
|
+
name="{self.package_name}",
|
71
|
+
version="{self.package_version}",
|
72
|
+
packages=find_packages(),
|
73
|
+
)
|
74
|
+
"""
|
75
|
+
setup_py_path = os.path.join(temp_dir, "setup.py")
|
76
|
+
with fileio.open(setup_py_path, "w") as f:
|
77
|
+
f.write(setup_py_content)
|
78
|
+
|
79
|
+
return temp_dir
|
80
|
+
|
81
|
+
def create_wheel(self, temp_dir: str) -> str:
|
82
|
+
"""Create a wheel for the package in the given temporary directory.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
temp_dir (str): Path to the temporary directory containing the package.
|
86
|
+
|
87
|
+
Raises:
|
88
|
+
RuntimeError: If the wheel file could not be created.
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
str: Path to the created wheel file.
|
92
|
+
"""
|
93
|
+
# Change to the temporary directory
|
94
|
+
original_dir = os.getcwd()
|
95
|
+
os.chdir(temp_dir)
|
96
|
+
|
97
|
+
try:
|
98
|
+
# Run the `pip wheel` command to create the wheel
|
99
|
+
result = subprocess.run(
|
100
|
+
["pip", "wheel", "."], check=True, capture_output=True
|
101
|
+
)
|
102
|
+
logger.debug(f"Wheel creation stdout: {result.stdout.decode()}")
|
103
|
+
logger.debug(f"Wheel creation stderr: {result.stderr.decode()}")
|
104
|
+
|
105
|
+
# Find the created wheel file
|
106
|
+
wheel_file = next(
|
107
|
+
(
|
108
|
+
file
|
109
|
+
for file in os.listdir(temp_dir)
|
110
|
+
if file.endswith(".whl")
|
111
|
+
),
|
112
|
+
None,
|
113
|
+
)
|
114
|
+
|
115
|
+
if wheel_file is None:
|
116
|
+
raise RuntimeError("Failed to create wheel file.")
|
117
|
+
|
118
|
+
wheel_path = os.path.join(temp_dir, wheel_file)
|
119
|
+
|
120
|
+
# Verify the wheel file is a valid zip file
|
121
|
+
import zipfile
|
122
|
+
|
123
|
+
if not zipfile.is_zipfile(wheel_path):
|
124
|
+
raise RuntimeError(
|
125
|
+
f"The file {wheel_path} is not a valid zip file."
|
126
|
+
)
|
127
|
+
|
128
|
+
return wheel_path
|
129
|
+
finally:
|
130
|
+
# Change back to the original directory
|
131
|
+
os.chdir(original_dir)
|
132
|
+
|
133
|
+
def sanitize_name(self, name: str) -> str:
|
134
|
+
"""Sanitize the value to be used in a cluster name.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
name: Arbitrary input cluster name.
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
Sanitized cluster name.
|
141
|
+
"""
|
142
|
+
name = re.sub(
|
143
|
+
r"[^a-z0-9-]", "-", name.lower()
|
144
|
+
) # replaces any character that is not a lowercase letter, digit, or hyphen with a hyphen
|
145
|
+
name = re.sub(r"^[-]+", "", name) # trim leading hyphens
|
146
|
+
name = re.sub(r"[-]+$", "", name) # trim trailing hyphens
|
147
|
+
return name
|