zenml-nightly 0.82.0.dev20250513__py3-none-any.whl → 0.82.0.dev20250514__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.
Files changed (27) hide show
  1. zenml/VERSION +1 -1
  2. zenml/config/build_configuration.py +9 -0
  3. zenml/config/docker_settings.py +97 -16
  4. zenml/constants.py +1 -0
  5. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +12 -1
  6. zenml/integrations/kubernetes/orchestrators/kube_utils.py +24 -1
  7. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +3 -0
  8. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +21 -5
  9. zenml/integrations/kubernetes/orchestrators/manifest_utils.py +13 -0
  10. zenml/orchestrators/step_launcher.py +4 -0
  11. zenml/orchestrators/step_run_utils.py +30 -1
  12. zenml/pipelines/build_utils.py +8 -0
  13. zenml/utils/pipeline_docker_image_builder.py +133 -7
  14. zenml/utils/tag_utils.py +3 -3
  15. zenml/zen_server/feature_gate/endpoint_utils.py +9 -12
  16. zenml/zen_server/feature_gate/feature_gate_interface.py +4 -6
  17. zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +8 -9
  18. zenml/zen_server/rbac/endpoint_utils.py +1 -1
  19. zenml/zen_server/rbac/rbac_sql_zen_store.py +2 -2
  20. zenml/zen_server/routers/run_templates_endpoints.py +10 -1
  21. zenml/zen_server/template_execution/utils.py +12 -1
  22. zenml/zen_stores/sql_zen_store.py +3 -6
  23. {zenml_nightly-0.82.0.dev20250513.dist-info → zenml_nightly-0.82.0.dev20250514.dist-info}/METADATA +1 -1
  24. {zenml_nightly-0.82.0.dev20250513.dist-info → zenml_nightly-0.82.0.dev20250514.dist-info}/RECORD +27 -27
  25. {zenml_nightly-0.82.0.dev20250513.dist-info → zenml_nightly-0.82.0.dev20250514.dist-info}/LICENSE +0 -0
  26. {zenml_nightly-0.82.0.dev20250513.dist-info → zenml_nightly-0.82.0.dev20250514.dist-info}/WHEEL +0 -0
  27. {zenml_nightly-0.82.0.dev20250513.dist-info → zenml_nightly-0.82.0.dev20250514.dist-info}/entry_points.txt +0 -0
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.82.0.dev20250513
1
+ 0.82.0.dev20250514
@@ -135,6 +135,9 @@ class BuildConfiguration(BaseModel):
135
135
  Returns:
136
136
  Whether files should be included in the image.
137
137
  """
138
+ if self.settings.local_project_install_command:
139
+ return True
140
+
138
141
  if self.should_download_files(code_repository=code_repository):
139
142
  return False
140
143
 
@@ -153,6 +156,9 @@ class BuildConfiguration(BaseModel):
153
156
  Returns:
154
157
  Whether files should be downloaded in the image.
155
158
  """
159
+ if self.settings.local_project_install_command:
160
+ return False
161
+
156
162
  if self.should_download_files_from_code_repository(
157
163
  code_repository=code_repository
158
164
  ):
@@ -176,6 +182,9 @@ class BuildConfiguration(BaseModel):
176
182
  Returns:
177
183
  Whether files should be downloaded from the code repository.
178
184
  """
185
+ if self.settings.local_project_install_command:
186
+ return False
187
+
179
188
  if (
180
189
  code_repository
181
190
  and self.settings.allow_download_from_code_repository
@@ -91,12 +91,21 @@ class DockerSettings(BaseSettings):
91
91
  --------------------------------
92
92
  Depending on the configuration of this object, requirements will be
93
93
  installed in the following order (each step optional):
94
- - The packages installed in your local python environment
94
+ - The packages installed in your local python environment (extracted using
95
+ `pip freeze`)
95
96
  - The packages required by the stack unless this is disabled by setting
96
- `install_stack_requirements=False`.
97
+ `install_stack_requirements=False`
97
98
  - The packages specified via the `required_integrations`
99
+ - The packages defined inside a pyproject.toml file given by the
100
+ `pyproject_path` attribute.
98
101
  - The packages specified via the `requirements` attribute
99
102
 
103
+ If neither `replicate_local_python_environment`, `pyproject_path` or
104
+ `requirements` are specified, ZenML will try to automatically find a
105
+ requirements.txt or pyproject.toml file in your current source root
106
+ and installs packages from the first one it finds. You can disable this
107
+ behavior by setting `disable_automatic_requirements_detection=True`.
108
+
100
109
  Attributes:
101
110
  parent_image: Full name of the Docker image that should be
102
111
  used as the parent for the image that will be built. Defaults to
@@ -137,10 +146,29 @@ class DockerSettings(BaseSettings):
137
146
  packages.
138
147
  python_package_installer_args: Arguments to pass to the python package
139
148
  installer.
140
- replicate_local_python_environment: If not `None`, ZenML will use the
141
- specified method to generate a requirements file that replicates
142
- the packages installed in the currently running python environment.
143
- This requirements file will then be installed in the Docker image.
149
+ disable_automatic_requirements_detection: If set to True, ZenML will
150
+ not automatically detect requirements.txt files or pyproject.toml
151
+ files in your source root.
152
+ replicate_local_python_environment: If set to True, ZenML will run
153
+ `pip freeze` to gather the requirements of the local Python
154
+ environment and then install them in the Docker image.
155
+ pyproject_path: Path to a pyproject.toml file. If given, the
156
+ dependencies will be exported to a requirements.txt
157
+ formatted file using the `pyproject_export_command` and then
158
+ installed inside the Docker image.
159
+ pyproject_export_command: Command to export the dependencies inside a
160
+ pyproject.toml file to a requirements.txt formatted file. If not
161
+ given and ZenML needs to export the requirements anyway, `uv export`
162
+ and `poetry export` will be tried to see if one of them works. This
163
+ command can contain a `{directory}` placeholder which will be
164
+ replaced with the directory in which the pyproject.toml file is
165
+ stored.
166
+ **Note**: This command will be run before any code files are copied
167
+ into the image. It is therefore not possible to install a local
168
+ project using this command. This command should exclude any local
169
+ projects, and you can specify a `local_project_install_command`
170
+ instead which will be run after the code files are copied into the
171
+ image.
144
172
  requirements: Path to a requirements file or a list of required pip
145
173
  packages. During the image build, these requirements will be
146
174
  installed using pip. If you need to use a different tool to
@@ -149,13 +177,16 @@ class DockerSettings(BaseSettings):
149
177
  required_integrations: List of ZenML integrations that should be
150
178
  installed. All requirements for the specified integrations will
151
179
  be installed inside the Docker image.
152
- required_hub_plugins: DEPRECATED/UNUSED.
153
180
  install_stack_requirements: If `True`, ZenML will automatically detect
154
181
  if components of your active stack are part of a ZenML integration
155
182
  and install the corresponding requirements and apt packages.
156
183
  If you set this to `False` or use custom components in your stack,
157
184
  you need to make sure these get installed by specifying them in
158
185
  the `requirements` and `apt_packages` attributes.
186
+ local_project_install_command: Command to install a local project in
187
+ the Docker image. This is run after the code files are copied into
188
+ the image, and it is therefore only possible when code is included
189
+ in the image, not downloaded at runtime.
159
190
  apt_packages: APT packages to install inside the Docker image.
160
191
  environment: Dictionary of environment variables to set inside the
161
192
  Docker image.
@@ -170,14 +201,6 @@ class DockerSettings(BaseSettings):
170
201
  from a code repository if possible.
171
202
  allow_download_from_artifact_store: If `True`, code can be downloaded
172
203
  from the artifact store.
173
- build_options: DEPRECATED, use parent_image_build_config.build_options
174
- instead.
175
- dockerignore: DEPRECATED, use build_config.dockerignore instead.
176
- copy_files: DEPRECATED/UNUSED.
177
- copy_global_config: DEPRECATED/UNUSED.
178
- source_files: DEPRECATED. Use allow_including_files_in_images,
179
- allow_download_from_code_repository and
180
- allow_download_from_artifact_store instead.
181
204
  """
182
205
 
183
206
  parent_image: Optional[str] = None
@@ -191,14 +214,18 @@ class DockerSettings(BaseSettings):
191
214
  PythonPackageInstaller.PIP
192
215
  )
193
216
  python_package_installer_args: Dict[str, Any] = {}
217
+ disable_automatic_requirements_detection: bool = True
194
218
  replicate_local_python_environment: Optional[
195
- Union[List[str], PythonEnvironmentExportMethod]
219
+ Union[List[str], PythonEnvironmentExportMethod, bool]
196
220
  ] = Field(default=None, union_mode="left_to_right")
221
+ pyproject_path: Optional[str] = None
222
+ pyproject_export_command: Optional[List[str]] = None
197
223
  requirements: Union[None, str, List[str]] = Field(
198
224
  default=None, union_mode="left_to_right"
199
225
  )
200
226
  required_integrations: List[str] = []
201
227
  install_stack_requirements: bool = True
228
+ local_project_install_command: Optional[str] = None
202
229
  apt_packages: List[str] = []
203
230
  environment: Dict[str, Any] = {}
204
231
  user: Optional[str] = None
@@ -221,6 +248,8 @@ class DockerSettings(BaseSettings):
221
248
  "copy_global_config",
222
249
  "source_files",
223
250
  "required_hub_plugins",
251
+ "build_options",
252
+ "dockerignore",
224
253
  )
225
254
 
226
255
  @model_validator(mode="before")
@@ -305,6 +334,58 @@ class DockerSettings(BaseSettings):
305
334
 
306
335
  return self
307
336
 
337
+ @model_validator(mode="after")
338
+ def _validate_code_files_included_if_installing_local_project(
339
+ self,
340
+ ) -> "DockerSettings":
341
+ """Ensures that files are included when installing a local package.
342
+
343
+ Raises:
344
+ ValueError: If files are not included in the Docker image
345
+ when trying to install a local package.
346
+
347
+ Returns:
348
+ The validated settings values.
349
+ """
350
+ if (
351
+ self.local_project_install_command
352
+ and not self.allow_including_files_in_images
353
+ ):
354
+ raise ValueError(
355
+ "Files must be included in the Docker image when trying to "
356
+ "install a local python package. You can do so by setting "
357
+ "the `allow_including_files_in_images` attribute of your "
358
+ "DockerSettings to `True`."
359
+ )
360
+
361
+ return self
362
+
363
+ @model_validator(mode="after")
364
+ def _deprecate_replicate_local_environment_commands(
365
+ self,
366
+ ) -> "DockerSettings":
367
+ """Deprecates some values for `replicate_local_python_environment`.
368
+
369
+ Returns:
370
+ The validated settings values.
371
+ """
372
+ if isinstance(
373
+ self.replicate_local_python_environment,
374
+ (str, list, PythonEnvironmentExportMethod),
375
+ ):
376
+ logger.warning(
377
+ "Specifying a command (`%s`) for "
378
+ "`DockerSettings.replicate_local_python_environment` is "
379
+ "deprecated. If you want to replicate your exact local "
380
+ "environment using `pip freeze`, set "
381
+ "`DockerSettings.replicate_local_python_environment=True`. "
382
+ "If you want to export requirements from a pyproject.toml "
383
+ "file, use `DockerSettings.pyproject_path` and "
384
+ "`DockerSettings.pyproject_export_command` instead."
385
+ )
386
+
387
+ return self
388
+
308
389
  model_config = ConfigDict(
309
390
  # public attributes are immutable
310
391
  frozen=True,
zenml/constants.py CHANGED
@@ -341,6 +341,7 @@ DEFAULT_ZENML_SERVER_REPORT_USER_ACTIVITY_TO_DB_SECONDS = 30
341
341
  DEFAULT_ZENML_SERVER_MAX_REQUEST_BODY_SIZE_IN_BYTES = 256 * 1024 * 1024
342
342
 
343
343
  DEFAULT_REPORTABLE_RESOURCES = ["project", "pipeline", "pipeline_run", "model"]
344
+ RUN_TEMPLATE_TRIGGERS_FEATURE_NAME = "template_run"
344
345
 
345
346
  # API Endpoint paths:
346
347
  ACTIVATE = "/activate"
@@ -15,7 +15,7 @@
15
15
 
16
16
  from typing import TYPE_CHECKING, Optional, Type
17
17
 
18
- from pydantic import PositiveInt
18
+ from pydantic import NonNegativeInt, PositiveInt
19
19
 
20
20
  from zenml.config.base_settings import BaseSettings
21
21
  from zenml.constants import KUBERNETES_CLUSTER_RESOURCE_TYPE
@@ -59,6 +59,14 @@ class KubernetesOrchestratorSettings(BaseSettings):
59
59
  pod_failure_backoff: The backoff factor for pod failure retries and
60
60
  pod startup retries.
61
61
  max_parallelism: Maximum number of steps to run in parallel.
62
+ successful_jobs_history_limit: The number of successful jobs
63
+ to retain. This only applies to jobs created when scheduling a
64
+ pipeline.
65
+ failed_jobs_history_limit: The number of failed jobs to retain.
66
+ This only applies to jobs created when scheduling a pipeline.
67
+ ttl_seconds_after_finished: The amount of seconds to keep finished jobs
68
+ before deleting them. This only applies to jobs created when
69
+ scheduling a pipeline.
62
70
  """
63
71
 
64
72
  synchronous: bool = True
@@ -74,6 +82,9 @@ class KubernetesOrchestratorSettings(BaseSettings):
74
82
  pod_failure_retry_delay: int = 10
75
83
  pod_failure_backoff: float = 1.0
76
84
  max_parallelism: Optional[PositiveInt] = None
85
+ successful_jobs_history_limit: Optional[NonNegativeInt] = None
86
+ failed_jobs_history_limit: Optional[NonNegativeInt] = None
87
+ ttl_seconds_after_finished: Optional[NonNegativeInt] = None
77
88
 
78
89
 
79
90
  class KubernetesOrchestratorConfig(
@@ -34,7 +34,7 @@ Adjusted from https://github.com/tensorflow/tfx/blob/master/tfx/utils/kube_utils
34
34
  import enum
35
35
  import re
36
36
  import time
37
- from typing import Any, Callable, Dict, Optional, TypeVar, cast
37
+ from typing import Any, Callable, Dict, List, Optional, TypeVar, cast
38
38
 
39
39
  from kubernetes import client as k8s_client
40
40
  from kubernetes import config as k8s_config
@@ -554,3 +554,26 @@ def create_and_wait_for_pod_to_start(
554
554
  total_wait += delay
555
555
  time.sleep(delay)
556
556
  delay *= startup_failure_backoff
557
+
558
+
559
+ def get_pod_owner_references(
560
+ core_api: k8s_client.CoreV1Api, pod_name: str, namespace: str
561
+ ) -> List[k8s_client.V1OwnerReference]:
562
+ """Get owner references for a pod.
563
+
564
+ Args:
565
+ core_api: Kubernetes CoreV1Api client.
566
+ pod_name: Name of the pod.
567
+ namespace: Kubernetes namespace.
568
+
569
+ Returns:
570
+ List of owner references.
571
+ """
572
+ pod = get_pod(core_api=core_api, pod_name=pod_name, namespace=namespace)
573
+
574
+ if not pod or not pod.metadata or not pod.metadata.owner_references:
575
+ return []
576
+
577
+ return cast(
578
+ List[k8s_client.V1OwnerReference], pod.metadata.owner_references
579
+ )
@@ -523,6 +523,9 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
523
523
  pod_settings=orchestrator_pod_settings,
524
524
  env=environment,
525
525
  mount_local_stores=self.config.is_local,
526
+ successful_jobs_history_limit=settings.successful_jobs_history_limit,
527
+ failed_jobs_history_limit=settings.failed_jobs_history_limit,
528
+ ttl_seconds_after_finished=settings.ttl_seconds_after_finished,
526
529
  )
527
530
 
528
531
  self._k8s_batch_api.create_namespaced_cron_job(
@@ -71,7 +71,7 @@ def main() -> None:
71
71
  # Parse / extract args.
72
72
  args = parse_args()
73
73
 
74
- orchestrator_run_id = socket.gethostname()
74
+ orchestrator_pod_name = socket.gethostname()
75
75
 
76
76
  client = Client()
77
77
 
@@ -95,7 +95,22 @@ def main() -> None:
95
95
  core_api = k8s_client.CoreV1Api(kube_client)
96
96
 
97
97
  env = get_config_environment_vars()
98
- env[ENV_ZENML_KUBERNETES_RUN_ID] = orchestrator_run_id
98
+ env[ENV_ZENML_KUBERNETES_RUN_ID] = orchestrator_pod_name
99
+
100
+ try:
101
+ owner_references = kube_utils.get_pod_owner_references(
102
+ core_api=core_api,
103
+ pod_name=orchestrator_pod_name,
104
+ namespace=args.kubernetes_namespace,
105
+ )
106
+ except Exception as e:
107
+ logger.warning(f"Failed to get pod owner references: {str(e)}")
108
+ owner_references = []
109
+ else:
110
+ # Make sure None of the owner references are marked as controllers of
111
+ # the created pod, which messes with the garbage collection logic.
112
+ for owner_reference in owner_references:
113
+ owner_reference.controller = False
99
114
 
100
115
  def run_step_on_kubernetes(step_name: str) -> None:
101
116
  """Run a pipeline step in a separate Kubernetes pod.
@@ -112,7 +127,7 @@ def main() -> None:
112
127
  settings.model_dump() if settings else {}
113
128
  )
114
129
 
115
- if settings.pod_name_prefix and not orchestrator_run_id.startswith(
130
+ if settings.pod_name_prefix and not orchestrator_pod_name.startswith(
116
131
  settings.pod_name_prefix
117
132
  ):
118
133
  max_length = (
@@ -125,7 +140,7 @@ def main() -> None:
125
140
  )
126
141
  pod_name = f"{pod_name_prefix}-{step_name}"
127
142
  else:
128
- pod_name = f"{orchestrator_run_id}-{step_name}"
143
+ pod_name = f"{orchestrator_pod_name}-{step_name}"
129
144
 
130
145
  pod_name = kube_utils.sanitize_pod_name(
131
146
  pod_name, namespace=args.kubernetes_namespace
@@ -179,6 +194,7 @@ def main() -> None:
179
194
  service_account_name=settings.step_pod_service_account_name
180
195
  or settings.service_account_name,
181
196
  mount_local_stores=mount_local_stores,
197
+ owner_references=owner_references,
182
198
  )
183
199
 
184
200
  kube_utils.create_and_wait_for_pod_to_start(
@@ -231,7 +247,7 @@ def main() -> None:
231
247
  else:
232
248
  # For a run triggered by a schedule, we can only use the
233
249
  # orchestrator run ID to find the pipeline run.
234
- list_args = dict(orchestrator_run_id=orchestrator_run_id)
250
+ list_args = dict(orchestrator_run_id=orchestrator_pod_name)
235
251
 
236
252
  pipeline_runs = client.list_pipeline_runs(
237
253
  hydrate=True,
@@ -107,6 +107,7 @@ def build_pod_manifest(
107
107
  service_account_name: Optional[str] = None,
108
108
  env: Optional[Dict[str, str]] = None,
109
109
  mount_local_stores: bool = False,
110
+ owner_references: Optional[List[k8s_client.V1OwnerReference]] = None,
110
111
  ) -> k8s_client.V1Pod:
111
112
  """Build a Kubernetes pod manifest for a ZenML run or step.
112
113
 
@@ -125,6 +126,7 @@ def build_pod_manifest(
125
126
  env: Environment variables to set.
126
127
  mount_local_stores: Whether to mount the local stores path inside the
127
128
  pod.
129
+ owner_references: List of owner references for the pod.
128
130
 
129
131
  Returns:
130
132
  Pod manifest.
@@ -180,6 +182,7 @@ def build_pod_manifest(
180
182
  pod_metadata = k8s_client.V1ObjectMeta(
181
183
  name=pod_name,
182
184
  labels=labels,
185
+ owner_references=owner_references,
183
186
  )
184
187
 
185
188
  if pod_settings and pod_settings.annotations:
@@ -279,6 +282,9 @@ def build_cron_job_manifest(
279
282
  service_account_name: Optional[str] = None,
280
283
  env: Optional[Dict[str, str]] = None,
281
284
  mount_local_stores: bool = False,
285
+ successful_jobs_history_limit: Optional[int] = None,
286
+ failed_jobs_history_limit: Optional[int] = None,
287
+ ttl_seconds_after_finished: Optional[int] = None,
282
288
  ) -> k8s_client.V1CronJob:
283
289
  """Create a manifest for launching a pod as scheduled CRON job.
284
290
 
@@ -298,6 +304,10 @@ def build_cron_job_manifest(
298
304
  env: Environment variables to set.
299
305
  mount_local_stores: Whether to mount the local stores path inside the
300
306
  pod.
307
+ successful_jobs_history_limit: The number of successful jobs to retain.
308
+ failed_jobs_history_limit: The number of failed jobs to retain.
309
+ ttl_seconds_after_finished: The amount of seconds to keep finished jobs
310
+ before deleting them.
301
311
 
302
312
  Returns:
303
313
  CRON job manifest.
@@ -318,6 +328,8 @@ def build_cron_job_manifest(
318
328
 
319
329
  job_spec = k8s_client.V1CronJobSpec(
320
330
  schedule=cron_expression,
331
+ successful_jobs_history_limit=successful_jobs_history_limit,
332
+ failed_jobs_history_limit=failed_jobs_history_limit,
321
333
  job_template=k8s_client.V1JobTemplateSpec(
322
334
  metadata=pod_manifest.metadata,
323
335
  spec=k8s_client.V1JobSpec(
@@ -325,6 +337,7 @@ def build_cron_job_manifest(
325
337
  metadata=pod_manifest.metadata,
326
338
  spec=pod_manifest.spec,
327
339
  ),
340
+ ttl_seconds_after_finished=ttl_seconds_after_finished,
328
341
  ),
329
342
  ),
330
343
  )
@@ -292,6 +292,10 @@ class StepLauncher:
292
292
  artifacts=step_run.outputs,
293
293
  model_version=model_version,
294
294
  )
295
+ step_run_utils.cascade_tags_for_output_artifacts(
296
+ artifacts=step_run.outputs,
297
+ tags=pipeline_run.config.tags,
298
+ )
295
299
 
296
300
  except: # noqa: E722
297
301
  logger.error(f"Pipeline run `{pipeline_run.name}` failed.")
@@ -13,8 +13,9 @@
13
13
  # permissions and limitations under the License.
14
14
  """Utilities for creating step runs."""
15
15
 
16
- from typing import Dict, List, Optional, Set, Tuple
16
+ from typing import Dict, List, Optional, Set, Tuple, Union
17
17
 
18
+ from zenml import Tag, add_tags
18
19
  from zenml.client import Client
19
20
  from zenml.config.step_configurations import Step
20
21
  from zenml.constants import CODE_HASH_PARAMETER_NAME, TEXT_FIELD_MAX_LENGTH
@@ -333,6 +334,11 @@ def create_cached_step_runs(
333
334
  model_version=model_version,
334
335
  )
335
336
 
337
+ cascade_tags_for_output_artifacts(
338
+ artifacts=step_run.outputs,
339
+ tags=pipeline_run.config.tags,
340
+ )
341
+
336
342
  logger.info("Using cached version of step `%s`.", invocation_id)
337
343
  cached_invocations.add(invocation_id)
338
344
 
@@ -382,3 +388,26 @@ def link_output_artifacts_to_model_version(
382
388
  artifact_version=output_artifact,
383
389
  model_version=model_version,
384
390
  )
391
+
392
+
393
+ def cascade_tags_for_output_artifacts(
394
+ artifacts: Dict[str, List[ArtifactVersionResponse]],
395
+ tags: Optional[List[Union[str, Tag]]] = None,
396
+ ) -> None:
397
+ """Tag the outputs of a step run.
398
+
399
+ Args:
400
+ artifacts: The step output artifacts.
401
+ tags: The tags to add to the artifacts.
402
+ """
403
+ if tags is None:
404
+ return
405
+
406
+ cascade_tags = [t for t in tags if isinstance(t, Tag) and t.cascade]
407
+
408
+ for output_artifacts in artifacts.values():
409
+ for output_artifact in output_artifacts:
410
+ add_tags(
411
+ tags=[t.name for t in cascade_tags],
412
+ artifact_version_id=output_artifact.id,
413
+ )
@@ -80,6 +80,11 @@ def requires_included_code(
80
80
  for step in deployment.step_configurations.values():
81
81
  docker_settings = step.config.docker_settings
82
82
 
83
+ if docker_settings.local_project_install_command:
84
+ # When installing a local package, we need to include the code
85
+ # files in the container image.
86
+ return True
87
+
83
88
  if docker_settings.allow_download_from_artifact_store:
84
89
  return False
85
90
 
@@ -136,6 +141,9 @@ def code_download_possible(
136
141
  Whether code download is possible for the deployment.
137
142
  """
138
143
  for step in deployment.step_configurations.values():
144
+ if step.config.docker_settings.local_project_install_command:
145
+ return False
146
+
139
147
  if step.config.docker_settings.allow_download_from_artifact_store:
140
148
  continue
141
149
 
@@ -68,6 +68,11 @@ PIP_DEFAULT_ARGS = {
68
68
  }
69
69
  UV_DEFAULT_ARGS = {"no-cache-dir": None}
70
70
 
71
+ DEFAULT_PYPROJECT_EXPORT_COMMANDS = [
72
+ "uv export --format=requirements-txt --directory={directory} --no-hashes --no-emit-project",
73
+ "poetry export --format=requirements.txt --directory={directory} --without-hashes",
74
+ ]
75
+
71
76
 
72
77
  class PipelineDockerImageBuilder:
73
78
  """Builds Docker images to run a ZenML pipeline."""
@@ -156,10 +161,11 @@ class PipelineDockerImageBuilder:
156
161
  requires_zenml_build = any(
157
162
  [
158
163
  docker_settings.requirements,
164
+ docker_settings.pyproject_path,
159
165
  docker_settings.required_integrations,
160
- docker_settings.required_hub_plugins,
161
166
  docker_settings.replicate_local_python_environment,
162
167
  docker_settings.install_stack_requirements,
168
+ docker_settings.local_project_install_command,
163
169
  docker_settings.apt_packages,
164
170
  docker_settings.environment,
165
171
  include_files,
@@ -434,8 +440,56 @@ class PipelineDockerImageBuilder:
434
440
  - Packages installed in the local Python environment
435
441
  - Requirements defined by stack integrations
436
442
  - Requirements defined by user integrations
443
+ - Requirements exported from a pyproject.toml
437
444
  - User-defined requirements
438
445
  """
446
+ implicit_requirements = False
447
+ pyproject_path = docker_settings.pyproject_path
448
+ requirements = docker_settings.requirements
449
+
450
+ if not any(
451
+ [
452
+ docker_settings.replicate_local_python_environment,
453
+ requirements,
454
+ pyproject_path,
455
+ ]
456
+ ):
457
+ root = source_utils.get_source_root()
458
+ requirements_path = os.path.join(root, "requirements.txt")
459
+ pyproject_file_path = os.path.join(root, "pyproject.toml")
460
+
461
+ if os.path.exists(requirements_path):
462
+ implicit_requirements = True
463
+ requirements = requirements_path
464
+ elif os.path.exists(pyproject_file_path):
465
+ implicit_requirements = True
466
+ pyproject_path = pyproject_file_path
467
+
468
+ if (
469
+ implicit_requirements
470
+ and docker_settings.disable_automatic_requirements_detection
471
+ ):
472
+ # TODO: This is only temporary to log a warning notifying users
473
+ # that we will soon switch the default behavior to
474
+ # `disable_automatic_requirements_detection=False`. Remove and
475
+ # adjust the logic once we've made this change.
476
+ if log:
477
+ logger.warning(
478
+ "Detected `requirements.txt` or `pyproject.toml` files in "
479
+ "the source root. In future versions of ZenML, these will "
480
+ "be automatically picked up and installed in Docker images "
481
+ "by default. To disable this behavior and keep the "
482
+ "current behavior, set "
483
+ "`DockerSettings.disable_automatic_requirements_detection` "
484
+ "to `True`. If you want to enable this behavior right away, "
485
+ "you can do so by setting "
486
+ "`DockerSettings.disable_automatic_requirements_detection` "
487
+ "to `False`."
488
+ )
489
+ implicit_requirements = False
490
+ requirements = None
491
+ pyproject_path = None
492
+
439
493
  requirements_files: List[Tuple[str, str, List[str]]] = []
440
494
 
441
495
  # Generate requirements file for the local environment if configured
@@ -447,6 +501,10 @@ class PipelineDockerImageBuilder:
447
501
  command = (
448
502
  docker_settings.replicate_local_python_environment.command
449
503
  )
504
+ elif isinstance(
505
+ docker_settings.replicate_local_python_environment, bool
506
+ ):
507
+ command = PythonEnvironmentExportMethod.PIP_FREEZE.command
450
508
  else:
451
509
  command = " ".join(
452
510
  docker_settings.replicate_local_python_environment
@@ -520,9 +578,69 @@ class PipelineDockerImageBuilder:
520
578
  ", ".join(f"`{r}`" for r in integration_requirements_list),
521
579
  )
522
580
 
581
+ if pyproject_path:
582
+ path = os.path.abspath(pyproject_path)
583
+
584
+ if not os.path.exists(path):
585
+ raise FileNotFoundError(
586
+ f"Pyproject file {path} does not exist."
587
+ )
588
+
589
+ def _run_command(command: str) -> str:
590
+ command = command.format(directory=os.path.dirname(path))
591
+
592
+ result = subprocess.run(
593
+ command,
594
+ capture_output=True,
595
+ check=True,
596
+ shell=True, # nosec
597
+ )
598
+ return result.stdout.decode()
599
+
600
+ if docker_settings.pyproject_export_command:
601
+ command = " ".join(docker_settings.pyproject_export_command)
602
+
603
+ try:
604
+ pyproject_requirements = _run_command(command)
605
+ except subprocess.CalledProcessError as e:
606
+ raise RuntimeError(
607
+ "Failed to export pyproject dependencies with "
608
+ f"command `{command}`: {e.stderr.decode()}"
609
+ )
610
+ else:
611
+ command_errors = {}
612
+
613
+ for command in DEFAULT_PYPROJECT_EXPORT_COMMANDS:
614
+ try:
615
+ pyproject_requirements = _run_command(command)
616
+ except subprocess.CalledProcessError as e:
617
+ command_errors[command] = e.stderr.decode()
618
+ else:
619
+ break
620
+ else:
621
+ raise RuntimeError(
622
+ "Failed to export pyproject dependencies with the "
623
+ f"following commands: {command_errors}. Please specify "
624
+ "a working command to export your pyproject.toml "
625
+ "dependencies to a requirements.txt formatted file "
626
+ "using `DockerSettings.pyproject_export_command`."
627
+ )
628
+
629
+ requirements_files.append(
630
+ (".zenml_pyproject_requirements", pyproject_requirements, [])
631
+ )
632
+ if log:
633
+ logger.info(
634
+ "- %s python packages from file `%s`",
635
+ "Implicitly including"
636
+ if implicit_requirements
637
+ else "Including",
638
+ path,
639
+ )
640
+
523
641
  # Generate/Read requirements file for user-defined requirements
524
- if isinstance(docker_settings.requirements, str):
525
- path = os.path.abspath(docker_settings.requirements)
642
+ if isinstance(requirements, str):
643
+ path = os.path.abspath(requirements)
526
644
  try:
527
645
  user_requirements = io_utils.read_file_contents_as_string(path)
528
646
  except FileNotFoundError as e:
@@ -531,15 +649,18 @@ class PipelineDockerImageBuilder:
531
649
  ) from e
532
650
  if log:
533
651
  logger.info(
534
- "- Including user-defined requirements from file `%s`",
652
+ "- %s user-defined requirements from file `%s`",
653
+ "Implicitly including"
654
+ if implicit_requirements
655
+ else "Including",
535
656
  path,
536
657
  )
537
- elif isinstance(docker_settings.requirements, List):
538
- user_requirements = "\n".join(docker_settings.requirements)
658
+ elif isinstance(requirements, List):
659
+ user_requirements = "\n".join(requirements)
539
660
  if log:
540
661
  logger.info(
541
662
  "- Including user-defined requirements: %s",
542
- ", ".join(f"`{r}`" for r in docker_settings.requirements),
663
+ ", ".join(f"`{r}`" for r in requirements),
543
664
  )
544
665
  else:
545
666
  user_requirements = None
@@ -638,6 +759,11 @@ class PipelineDockerImageBuilder:
638
759
  lines.append("COPY . .")
639
760
  lines.append("RUN chmod -R a+rw .")
640
761
 
762
+ if docker_settings.local_project_install_command:
763
+ lines.append(
764
+ f"RUN {docker_settings.local_project_install_command}"
765
+ )
766
+
641
767
  if docker_settings.user:
642
768
  # Change file ownership to specified user
643
769
  lines.append(f"RUN chown -R {docker_settings.user} .")
zenml/utils/tag_utils.py CHANGED
@@ -348,10 +348,10 @@ def add_tags(
348
348
  if isinstance(tag, Tag):
349
349
  tag_model = client.get_tag(tag.name)
350
350
 
351
- if tag.exclusive != tag_model.exclusive:
351
+ if bool(tag.exclusive) != tag_model.exclusive:
352
352
  raise ValueError(
353
- f"The tag `{tag.name}` is an "
354
- f"{'exclusive' if tag_model.exclusive else 'non-exclusive'} "
353
+ f"The tag `{tag.name}` is "
354
+ f"{'an exclusive' if tag_model.exclusive else 'a non-exclusive'} "
355
355
  "tag. Please update it before attaching it to a resource."
356
356
  )
357
357
  if tag.cascade is not None:
@@ -15,47 +15,44 @@
15
15
 
16
16
  from uuid import UUID
17
17
 
18
- from zenml.zen_server.rbac.models import ResourceType
19
18
  from zenml.zen_server.utils import feature_gate, server_config
20
19
 
21
20
 
22
- def check_entitlement(resource_type: ResourceType) -> None:
21
+ def check_entitlement(feature: str) -> None:
23
22
  """Queries the feature gate to see if the operation falls within the Pro workspaces entitlements.
24
23
 
25
24
  Raises an exception if the user is not entitled to create an instance of the
26
25
  resource. Otherwise, simply returns.
27
26
 
28
27
  Args:
29
- resource_type: The type of resource to check for.
28
+ feature: The feature to check for.
30
29
  """
31
30
  if not server_config().feature_gate_enabled:
32
31
  return
33
- return feature_gate().check_entitlement(resource=resource_type)
32
+ return feature_gate().check_entitlement(feature=feature)
34
33
 
35
34
 
36
- def report_usage(resource_type: ResourceType, resource_id: UUID) -> None:
35
+ def report_usage(feature: str, resource_id: UUID) -> None:
37
36
  """Reports the creation/usage of a feature/resource.
38
37
 
39
38
  Args:
40
- resource_type: The type of resource to report a usage for
39
+ feature: The feature to report a usage for.
41
40
  resource_id: ID of the resource that was created.
42
41
  """
43
42
  if not server_config().feature_gate_enabled:
44
43
  return
45
- feature_gate().report_event(
46
- resource=resource_type, resource_id=resource_id
47
- )
44
+ feature_gate().report_event(feature=feature, resource_id=resource_id)
48
45
 
49
46
 
50
- def report_decrement(resource_type: ResourceType, resource_id: UUID) -> None:
47
+ def report_decrement(feature: str, resource_id: UUID) -> None:
51
48
  """Reports the deletion/deactivation of a feature/resource.
52
49
 
53
50
  Args:
54
- resource_type: The type of resource to report a decrement in count for.
51
+ feature: The feature to report a decrement in count for.
55
52
  resource_id: ID of the resource that was deleted.
56
53
  """
57
54
  if not server_config().feature_gate_enabled:
58
55
  return
59
56
  feature_gate().report_event(
60
- resource=resource_type, resource_id=resource_id, is_decrement=True
57
+ feature=feature, resource_id=resource_id, is_decrement=True
61
58
  )
@@ -16,18 +16,16 @@
16
16
  from abc import ABC, abstractmethod
17
17
  from uuid import UUID
18
18
 
19
- from zenml.zen_server.rbac.models import ResourceType
20
-
21
19
 
22
20
  class FeatureGateInterface(ABC):
23
21
  """Feature gate interface definition."""
24
22
 
25
23
  @abstractmethod
26
- def check_entitlement(self, resource: ResourceType) -> None:
24
+ def check_entitlement(self, feature: str) -> None:
27
25
  """Checks if a user is entitled to create a resource.
28
26
 
29
27
  Args:
30
- resource: The resource the user wants to create
28
+ feature: The feature the user wants to use.
31
29
 
32
30
  Raises:
33
31
  UpgradeRequiredError in case a subscription limit is reached
@@ -36,14 +34,14 @@ class FeatureGateInterface(ABC):
36
34
  @abstractmethod
37
35
  def report_event(
38
36
  self,
39
- resource: ResourceType,
37
+ feature: str,
40
38
  resource_id: UUID,
41
39
  is_decrement: bool = False,
42
40
  ) -> None:
43
41
  """Reports the usage of a feature to the aggregator backend.
44
42
 
45
43
  Args:
46
- resource: The resource the user created
44
+ feature: The feature the user used.
47
45
  resource_id: ID of the resource that was created/deleted.
48
46
  is_decrement: In case this event reports an actual decrement of usage
49
47
  """
@@ -25,7 +25,6 @@ from zenml.zen_server.cloud_utils import cloud_connection
25
25
  from zenml.zen_server.feature_gate.feature_gate_interface import (
26
26
  FeatureGateInterface,
27
27
  )
28
- from zenml.zen_server.rbac.models import ResourceType
29
28
 
30
29
  logger = get_logger(__name__)
31
30
 
@@ -47,7 +46,7 @@ class RawUsageEvent(BaseModel):
47
46
  organization_id: str = Field(
48
47
  description="The organization that this usage can be attributed to.",
49
48
  )
50
- feature: ResourceType = Field(
49
+ feature: str = Field(
51
50
  description="The feature whose usage is being reported.",
52
51
  )
53
52
  total: int = Field(
@@ -66,22 +65,22 @@ class ZenMLCloudFeatureGateInterface(FeatureGateInterface):
66
65
  """Initialize the object."""
67
66
  self._connection = cloud_connection()
68
67
 
69
- def check_entitlement(self, resource: ResourceType) -> None:
68
+ def check_entitlement(self, feature: str) -> None:
70
69
  """Checks if a user is entitled to create a resource.
71
70
 
72
71
  Args:
73
- resource: The resource the user wants to create
72
+ feature: The feature the user wants to use.
74
73
 
75
74
  Raises:
76
75
  SubscriptionUpgradeRequiredError: in case a subscription limit is reached
77
76
  """
78
77
  try:
79
78
  response = self._connection.get(
80
- endpoint=ENTITLEMENT_ENDPOINT + "/" + resource, params=None
79
+ endpoint=ENTITLEMENT_ENDPOINT + "/" + feature, params=None
81
80
  )
82
81
  except SubscriptionUpgradeRequiredError:
83
82
  raise SubscriptionUpgradeRequiredError(
84
- f"Your subscription reached its `{resource}` limit. Please "
83
+ f"Your subscription reached its `{feature}` limit. Please "
85
84
  f"upgrade your subscription or reach out to us."
86
85
  )
87
86
 
@@ -94,20 +93,20 @@ class ZenMLCloudFeatureGateInterface(FeatureGateInterface):
94
93
 
95
94
  def report_event(
96
95
  self,
97
- resource: ResourceType,
96
+ feature: str,
98
97
  resource_id: UUID,
99
98
  is_decrement: bool = False,
100
99
  ) -> None:
101
100
  """Reports the usage of a feature to the aggregator backend.
102
101
 
103
102
  Args:
104
- resource: The resource the user created
103
+ feature: The feature the user used.
105
104
  resource_id: ID of the resource that was created/deleted.
106
105
  is_decrement: In case this event reports an actual decrement of usage
107
106
  """
108
107
  data = RawUsageEvent(
109
108
  organization_id=ORGANIZATION_ID,
110
- feature=resource,
109
+ feature=feature,
111
110
  total=1 if not is_decrement else -1,
112
111
  metadata={
113
112
  "workspace_id": str(server_config.get_external_server_id()),
@@ -182,7 +182,7 @@ def verify_permissions_and_get_or_create_entity(
182
182
  def _pre_creation_hook() -> None:
183
183
  verify_permission_for_model(model=request_model, action=Action.CREATE)
184
184
  if resource_type and needs_usage_increment:
185
- check_entitlement(resource_type=resource_type)
185
+ check_entitlement(feature=resource_type)
186
186
 
187
187
  model, created = get_or_create_method(request_model, _pre_creation_hook)
188
188
 
@@ -67,7 +67,7 @@ class RBACSqlZenStore(SqlZenStore):
67
67
  action=Action.CREATE,
68
68
  project_id=model_request.project,
69
69
  )
70
- check_entitlement(resource_type=ResourceType.MODEL)
70
+ check_entitlement(feature=ResourceType.MODEL)
71
71
  except Exception as e:
72
72
  allow_model_creation = False
73
73
  error = e
@@ -92,7 +92,7 @@ class RBACSqlZenStore(SqlZenStore):
92
92
 
93
93
  if created:
94
94
  report_usage(
95
- resource_type=ResourceType.MODEL, resource_id=model_response.id
95
+ feature=ResourceType.MODEL, resource_id=model_response.id
96
96
  )
97
97
  else:
98
98
  verify_permission_for_model(model_response, action=Action.READ)
@@ -25,7 +25,12 @@ from fastapi import (
25
25
  from zenml.analytics.enums import AnalyticsEvent
26
26
  from zenml.analytics.utils import track_handler
27
27
  from zenml.config.pipeline_run_configuration import PipelineRunConfiguration
28
- from zenml.constants import API, RUN_TEMPLATES, VERSION_1
28
+ from zenml.constants import (
29
+ API,
30
+ RUN_TEMPLATE_TRIGGERS_FEATURE_NAME,
31
+ RUN_TEMPLATES,
32
+ VERSION_1,
33
+ )
29
34
  from zenml.models import (
30
35
  Page,
31
36
  PipelineRunResponse,
@@ -36,6 +41,9 @@ from zenml.models import (
36
41
  )
37
42
  from zenml.zen_server.auth import AuthContext, authorize
38
43
  from zenml.zen_server.exceptions import error_response
44
+ from zenml.zen_server.feature_gate.endpoint_utils import (
45
+ check_entitlement,
46
+ )
39
47
  from zenml.zen_server.rbac.endpoint_utils import (
40
48
  verify_permissions_and_create_entity,
41
49
  verify_permissions_and_delete_entity,
@@ -269,6 +277,7 @@ if server_config().workload_manager_enabled:
269
277
  action=Action.CREATE,
270
278
  project_id=template.project.id,
271
279
  )
280
+ check_entitlement(feature=RUN_TEMPLATE_TRIGGERS_FEATURE_NAME)
272
281
 
273
282
  return run_template(
274
283
  template=template,
@@ -24,6 +24,7 @@ from zenml.constants import (
24
24
  ENV_ZENML_RUNNER_IMAGE_DISABLE_UV,
25
25
  ENV_ZENML_RUNNER_PARENT_IMAGE,
26
26
  ENV_ZENML_RUNNER_POD_TIMEOUT,
27
+ RUN_TEMPLATE_TRIGGERS_FEATURE_NAME,
27
28
  handle_bool_env_var,
28
29
  handle_int_env_var,
29
30
  )
@@ -49,7 +50,11 @@ from zenml.pipelines.run_utils import (
49
50
  )
50
51
  from zenml.stack.flavor import Flavor
51
52
  from zenml.utils import pydantic_utils, requirements_utils, settings_utils
53
+ from zenml.utils.time_utils import utc_now
52
54
  from zenml.zen_server.auth import AuthContext, generate_access_token
55
+ from zenml.zen_server.feature_gate.endpoint_utils import (
56
+ report_usage,
57
+ )
53
58
  from zenml.zen_server.template_execution.runner_entrypoint_configuration import (
54
59
  RunnerEntrypointConfiguration,
55
60
  )
@@ -190,6 +195,11 @@ def run_template(
190
195
  placeholder_run = create_placeholder_run(deployment=new_deployment)
191
196
  assert placeholder_run
192
197
 
198
+ report_usage(
199
+ feature=RUN_TEMPLATE_TRIGGERS_FEATURE_NAME,
200
+ resource_id=placeholder_run.id,
201
+ )
202
+
193
203
  # We create an API token scoped to the pipeline run that never expires
194
204
  api_token = generate_access_token(
195
205
  user_id=auth_context.user.id,
@@ -300,7 +310,8 @@ def run_template(
300
310
  zen_store().update_run(
301
311
  run_id=placeholder_run.id,
302
312
  run_update=PipelineRunUpdate(
303
- status=ExecutionStatus.FAILED
313
+ status=ExecutionStatus.FAILED,
314
+ end_time=utc_now(),
304
315
  ),
305
316
  )
306
317
  raise
@@ -11354,13 +11354,10 @@ class SqlZenStore(BaseZenStore):
11354
11354
  except EntityExistsError:
11355
11355
  if isinstance(tag, tag_utils.Tag):
11356
11356
  tag_schema = self._get_tag_schema(tag.name, session)
11357
- if (
11358
- tag.exclusive is not None
11359
- and tag.exclusive != tag_schema.exclusive
11360
- ):
11357
+ if bool(tag.exclusive) != tag_schema.exclusive:
11361
11358
  raise ValueError(
11362
- f"Tag `{tag_schema.name}` has been defined as a "
11363
- f"{'exclusive' if tag_schema.exclusive else 'non-exclusive'} "
11359
+ f"Tag `{tag_schema.name}` has been defined as "
11360
+ f"{'an exclusive' if tag_schema.exclusive else 'a non-exclusive'} "
11364
11361
  "tag. Please update it before attaching it to resources."
11365
11362
  )
11366
11363
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: zenml-nightly
3
- Version: 0.82.0.dev20250513
3
+ Version: 0.82.0.dev20250514
4
4
  Summary: ZenML: Write production-ready ML code.
5
5
  License: Apache-2.0
6
6
  Keywords: machine learning,production,pipeline,mlops,devops
@@ -1,5 +1,5 @@
1
1
  zenml/README.md,sha256=827dekbOWAs1BpW7VF1a4d7EbwPbjwccX-2zdXBENZo,1777
2
- zenml/VERSION,sha256=GgvcZ4qW8lpLu66ULVW2IWU5xLriT6P_N-LWtNfqCL8,19
2
+ zenml/VERSION,sha256=tqY-3ZZVi7BBuFj-AGEU8O9NpFcVRZl7FWjOi6F9yb8,19
3
3
  zenml/__init__.py,sha256=CKEyepFK-7akXYiMrNVh92Nb01Cjs23w4_YyI6sgdc8,2242
4
4
  zenml/actions/__init__.py,sha256=mrt6wPo73iKRxK754_NqsGyJ3buW7RnVeIGXr1xEw8Y,681
5
5
  zenml/actions/base_action.py,sha256=UcaHev6BTuLDwuswnyaPjdA8AgUqB5xPZ-lRtuvf2FU,25553
@@ -64,10 +64,10 @@ zenml/code_repositories/git/local_git_repository_context.py,sha256=hfX7zVDQ27Le0
64
64
  zenml/code_repositories/local_repository_context.py,sha256=1VyiYkJBDVg0iGusgRQDToGRPJuu9lx7jTBDpplukDg,2816
65
65
  zenml/config/__init__.py,sha256=DZEic7euSbwI9Yb3FMRQhTgfhqz-C6OdAiYmOb0-opI,1519
66
66
  zenml/config/base_settings.py,sha256=itoLqc1cOwEYhgSGdZmSKSaBevQkvYH7NQh7PUamazc,1700
67
- zenml/config/build_configuration.py,sha256=tEAIXwAGS8Flxo4mK5BGHsBk7LPWW16MOa6oRDymZ7k,6172
67
+ zenml/config/build_configuration.py,sha256=me2jXT91Ndbrq6OFFTz2zbKimUWp6APQiE_goYONLgM,6417
68
68
  zenml/config/compiler.py,sha256=bK3LCDkrFc9SapJYH-vuQZ_o8scHNs-FdC5DblIUU4U,23024
69
69
  zenml/config/constants.py,sha256=QvSgMwXWxtspcJ45CrFDP1ZY3w6gS3bIhXLOtIDAbZA,713
70
- zenml/config/docker_settings.py,sha256=w62SDW2Qo5jFxcikHr8p-Lk6ymC2ieh3MnEfkte9Lf0,13322
70
+ zenml/config/docker_settings.py,sha256=B3pYlnyQDiwSEHO6y965Jx6BMrVqKARjp7v23uBziLc,17068
71
71
  zenml/config/global_config.py,sha256=ZD3WodfcWMBJZOl1FNn3ztzwilGDDv9EKdHClLqSO8s,29562
72
72
  zenml/config/pipeline_configurations.py,sha256=7trCbElpqGGgawii2FrdLW8fKaAWCR8jACkNqdG_vcQ,3983
73
73
  zenml/config/pipeline_run_configuration.py,sha256=Y9C5mVUH-w4gc1w1PCQFpjEmfBBpSMvb8riA_sL78hY,2311
@@ -85,7 +85,7 @@ zenml/config/step_run_info.py,sha256=KiVRSTtKmZ1GbvseDTap2imr7XwMHD3jSFVpyLNEK1I
85
85
  zenml/config/store_config.py,sha256=Cla5p5dTB6nNlo8_OZDs9hod5hspi64vxwtZj882XgU,3559
86
86
  zenml/config/strict_base_model.py,sha256=t_ULrtJF2eW7TgyYBRobl1fscwwIZXATYky8ER97ev4,860
87
87
  zenml/console.py,sha256=hj_KerPQKwnyKACj0ehSqUQX0mGVCJBKE1QvCt6ik3A,1160
88
- zenml/constants.py,sha256=Lkm9EWkhAEwxdOuVHxSmLB6XEpa6-sw1TfKvpaVNEhk,16545
88
+ zenml/constants.py,sha256=nLjJUhBqFHWHlGKbZZw-_tn7x99y6q4vmk5LOe7GhJI,16597
89
89
  zenml/container_registries/__init__.py,sha256=ZSPbBIOnzhg88kQSpYgKe_POLuru14m629665-kAVAA,2200
90
90
  zenml/container_registries/azure_container_registry.py,sha256=t1sfDa94Vzbyqtb1iPFNutJ2EXV5_p9CUNITasoiQ70,2667
91
91
  zenml/container_registries/base_container_registry.py,sha256=-9RIkD6oXNPaU59R3PB_PtyCqsFoLPLSn5xYZmEmzbc,8915
@@ -334,14 +334,14 @@ zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py,sha256=ihM8s0
334
334
  zenml/integrations/kubeflow/orchestrators/local_deployment_utils.py,sha256=qszoOdvBpgIp40XkncphXAr9dRKnyZzGiz2mJ56bYmw,15448
335
335
  zenml/integrations/kubernetes/__init__.py,sha256=k1bfrdI1u5RBnAh7yT4w-m-4SWgZ7b4L5uu7dPRc0SI,1809
336
336
  zenml/integrations/kubernetes/flavors/__init__.py,sha256=a5gU45qCj3FkLwl_uVjlIkL_2F5DHk-w1gdcZrvVjBI,1266
337
- zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py,sha256=bO_2RZ6TIO0Qp2zduha324m2zrg6cGw-ymK51Nm2E9o,9505
337
+ zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py,sha256=JH_Kxfh1eoiSlz-OpixJ6itEsDiGPvbkA5_PffMTa54,10215
338
338
  zenml/integrations/kubernetes/flavors/kubernetes_step_operator_flavor.py,sha256=xFO7cSusji-mgbRrt4mU29gdyC9iEjEHKtomdFLp9mM,6265
339
339
  zenml/integrations/kubernetes/orchestrators/__init__.py,sha256=TJID3OTieZBox36WpQpzD0jdVRA_aZVcs_bNtfXS8ik,811
340
- zenml/integrations/kubernetes/orchestrators/kube_utils.py,sha256=oU0EYP-x35oG7PAy7NZKeFA8_89Eckgq6hibwc9v5l0,18108
341
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py,sha256=tzGhxFyf2of7soyEiEYAixuU9uDjT49-StAqhRJLMVo,25730
342
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py,sha256=krsIXrHUk2EZAVpqMCn8KgICNhD_YtVlySarQD5C4bI,12039
340
+ zenml/integrations/kubernetes/orchestrators/kube_utils.py,sha256=8BVOpg40dGeRSkbzG_66xOksry5xpMVVmcXVDqb1bSs,18747
341
+ zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py,sha256=qubV13fSGE_vo8wSzIfcp66McclLw-zDtmB4yCCaS08,25974
342
+ zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py,sha256=Nd1YZsP6FZ4LTpoeFIM3YlFUugHX7F9axb7U9ZgGNdQ,12692
343
343
  zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint_configuration.py,sha256=KjHfQK9VQEQkkkM2i9w51AzqolgIU01M5dgb2YGamvY,2754
344
- zenml/integrations/kubernetes/orchestrators/manifest_utils.py,sha256=Mte6q_NX0bU_JTivtN7ByQtfQX32iI2z2sElIpQhj7g,13271
344
+ zenml/integrations/kubernetes/orchestrators/manifest_utils.py,sha256=QmK0HrAMalalcQMyG0rqBysoB3srQ4ywnKARdf-LtFc,14083
345
345
  zenml/integrations/kubernetes/pod_settings.py,sha256=QPV8Fq8SHZ7pwKavplcADJep-Y9olIbC3RlG10HI0pw,6683
346
346
  zenml/integrations/kubernetes/serialization_utils.py,sha256=cPSe4szdBLzDnUZT9nQc2CCA8h84aj5oTA8vsUE36ig,7000
347
347
  zenml/integrations/kubernetes/service_connectors/__init__.py,sha256=Uf6zlHIapYrRDl3xOPWQ2jA7jt85SXx1U7DmSxzxTvQ,818
@@ -690,14 +690,14 @@ zenml/orchestrators/local_docker/__init__.py,sha256=k8J68ydy6HmmvE9tWo32g761H8P_
690
690
  zenml/orchestrators/local_docker/local_docker_orchestrator.py,sha256=4b4oiCQ_PnfzgsHZuGrWeVEvjsrq_0yvVqtBUqz3Ai4,9353
691
691
  zenml/orchestrators/output_utils.py,sha256=01vqke1ZfmfuLpgxNerF-QL2wA0VPv1zUdvlMw0OwUY,3508
692
692
  zenml/orchestrators/publish_utils.py,sha256=_77t2sVq3Tm-yAYg2NPxcCD7Y8lwe0lm55NNrtMUzQQ,4741
693
- zenml/orchestrators/step_launcher.py,sha256=YOeQtvmI__c8ugrqk2KSyITYVOxoLIAZxUIxkLyv-UY,17857
694
- zenml/orchestrators/step_run_utils.py,sha256=7GOWAW3izFopGPkvvjYyJKiYgYuHuHJ8V6eZfwjAx8E,13401
693
+ zenml/orchestrators/step_launcher.py,sha256=UM0TeFx_VtOy3Rq7uHRjljtABAezwiXYkUgGe6GGToA,18056
694
+ zenml/orchestrators/step_run_utils.py,sha256=bG3ybu1hPt0IGe-7W4-4Qktb8EO7D7L1ChVMZAqEPmE,14256
695
695
  zenml/orchestrators/step_runner.py,sha256=EUgKG_g0fOQ6gnB1hPSSa6UXwUKVkguC-Yj-Q0yEQXg,26632
696
696
  zenml/orchestrators/topsort.py,sha256=D8evz3X47zwpXd90NMLsJD-_uCeXtV6ClzNfDUrq7cM,5784
697
697
  zenml/orchestrators/utils.py,sha256=agh8m5v1OYU-16Rcp6YDwDbHt9S1F46zsRe3AWC_tBc,12967
698
698
  zenml/orchestrators/wheeled_orchestrator.py,sha256=eOnMcnd3sCzfhA2l6qRAzF0rOXzaojbjvvYvTkqixQo,4791
699
699
  zenml/pipelines/__init__.py,sha256=hpIX7hN8jsQRHT5R-xSXZL88qrHwkmrvGLQeu1rWt4o,873
700
- zenml/pipelines/build_utils.py,sha256=FYflpfK8i9jLgy8Ybr2dhQZarUDA1_0shvEARPkBMYA,27591
700
+ zenml/pipelines/build_utils.py,sha256=DltGesybT8qYum4i23mvWZlVRgp7UxWdbHd1Y9ySv5c,27889
701
701
  zenml/pipelines/pipeline_context.py,sha256=4BixReLcPo33VtNBDrMwnJqjKTinHjmO5AOfmoeIOQM,3659
702
702
  zenml/pipelines/pipeline_decorator.py,sha256=LB21QYrbFeBdUGwKBUNbdpXAxO4OOtYl5Vs_mzJNXqU,4600
703
703
  zenml/pipelines/pipeline_definition.py,sha256=954y2DmoY9luHhutC2nVRXzZ_KLnTWFnS5LSzrq_OZo,59637
@@ -784,7 +784,7 @@ zenml/utils/networking_utils.py,sha256=zTDbOMkMPRWiWLZ2ccchd37rvvZWIIh0Kr9dZE-VJ
784
784
  zenml/utils/notebook_utils.py,sha256=VBMU9Qnx_NdpB1TQtnej56L0hRr11fwniOva3ltUT90,4113
785
785
  zenml/utils/package_utils.py,sha256=wy0Mh8hHhOX2z1JfGN5lifG9yEsBQGLwNfur0M3J2tQ,2730
786
786
  zenml/utils/pagination_utils.py,sha256=TufckOqOKeDPwE3ySefL05zOzGUUA2Fqx_QFVhE2so0,1445
787
- zenml/utils/pipeline_docker_image_builder.py,sha256=QOZV_AYFbUtcfJZGNO7pH2_EoXyRqs9GZF_hTeoqW5E,25036
787
+ zenml/utils/pipeline_docker_image_builder.py,sha256=Gp_eKg_LEdyBUSuZDC_PReyPHlqonKNwjxPJJLoAFY0,30256
788
788
  zenml/utils/proxy_utils.py,sha256=fgRlLa9pfXJDoxtB31_YP7DClOMQLek_nMmM0et6i3w,7241
789
789
  zenml/utils/pydantic_utils.py,sha256=oQcxY4VXuVY3n632atlvdmi12EYcSQ1xZuQJY3Je-sA,16592
790
790
  zenml/utils/requirements_utils.py,sha256=JqVChflTQwBMByRtKfsS3dV91QeWbdGYefcEBkTKXGk,2605
@@ -795,7 +795,7 @@ zenml/utils/singleton.py,sha256=uFRrUlUdS5VyY9lLJyl_n5kqppsqJLKkBhSj4g5VPkY,2757
795
795
  zenml/utils/source_code_utils.py,sha256=8iyNA2MGIORYVEkSdxNTXfS1ZdFKXTAG1dZRkeQtPL0,3751
796
796
  zenml/utils/source_utils.py,sha256=joKLghhDq9dh0fd8B0WRGX-nN-uwnGQdgmsyY_n-8gY,27033
797
797
  zenml/utils/string_utils.py,sha256=xJ8Abm52yFQyOpNrgpoLjDbPCgb6rpJsi8N4-7bb5GU,7254
798
- zenml/utils/tag_utils.py,sha256=C9VeVFB-WuhHhGG_iVsNghJrGjX8EKVuRJZs8hMhwpA,19172
798
+ zenml/utils/tag_utils.py,sha256=2LJ-3XkXuWnffUsyfCwahzL_N2k4lIYIgBs1HVShhA0,19180
799
799
  zenml/utils/time_utils.py,sha256=-9Y9zwJ-6Gv7hoZQCoftPyC2LCLo2bYj6OgdyBaE44o,4076
800
800
  zenml/utils/typed_model.py,sha256=00EAo1I1VnOBHG4-ce8dPkyHRPpgi67SRIU-KdewRWs,4757
801
801
  zenml/utils/typing_utils.py,sha256=jP7JKrlLsuMIStXhwKFNWykE6SMOR72tJIJ_qEbQSNc,6555
@@ -1014,16 +1014,16 @@ zenml/zen_server/deploy/exceptions.py,sha256=tX0GNnLB_GMkeN7zGNlJRwtlrpZ5Slvyj_u
1014
1014
  zenml/zen_server/download_utils.py,sha256=g366TqytIWR4L4u9dd0jg-ouSWpDwdAh_-F2zryFzfo,4224
1015
1015
  zenml/zen_server/exceptions.py,sha256=hP8zJBofQljxPByFIa4tKpVjKdCAMJlKvk_5Opgusqg,9718
1016
1016
  zenml/zen_server/feature_gate/__init__.py,sha256=yabe4fBY6NSusn-QlKQDLOvXVLERNpcAQgigsyWQIbQ,612
1017
- zenml/zen_server/feature_gate/endpoint_utils.py,sha256=o6sBVlqqlc9KokMaEsRTYeMra7f2a6kCt3FrB-oHhCw,2227
1018
- zenml/zen_server/feature_gate/feature_gate_interface.py,sha256=XCgsqUN5yYCipodHCIDmCHRhyYMyt483Pp5mdpqzwHA,1647
1019
- zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py,sha256=aZHYgtJk-IDgucsawSWZsNrqBk2KQPmcn9VsPcacggg,4409
1017
+ zenml/zen_server/feature_gate/endpoint_utils.py,sha256=1LbOhY0D0KoJHnkWtSaN8DqUq_CWc8txLGa9029lvyw,2049
1018
+ zenml/zen_server/feature_gate/feature_gate_interface.py,sha256=4UdXaK-rVxpI9PKpp2GGWLV1-8TIhycAOaWooLwjcAo,1564
1019
+ zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py,sha256=kek99YFYEhC927XBrqTGskri3tHDte05ifp00PH-Ef4,4315
1020
1020
  zenml/zen_server/jwt.py,sha256=N45kKuGLZWKR7j1CyPVpu6Xvmk1BUwZKiaIxJUl9rs4,6857
1021
1021
  zenml/zen_server/rate_limit.py,sha256=rOg5H_6rOGQ_qiSCtMKPREmL1LL3bZyn4czKILtImJg,6057
1022
1022
  zenml/zen_server/rbac/__init__.py,sha256=nACbn_G7nZt_AWM3zeFL0FCmELvQnvaOFMwvTG3-6ZE,637
1023
- zenml/zen_server/rbac/endpoint_utils.py,sha256=l6V6DwsPGmT6dLJmY4MHMRfRXdc0lZVibD-Aea5UAHc,11604
1023
+ zenml/zen_server/rbac/endpoint_utils.py,sha256=cpukjGh4CA9flzuFKPI_dhQQl8nL8WVKXhcCTHrEOOE,11598
1024
1024
  zenml/zen_server/rbac/models.py,sha256=Xhz0XqmVqg3ji9uTwjlhQ4IuQ2ivrT4gVdHi5ZkjFC4,4933
1025
1025
  zenml/zen_server/rbac/rbac_interface.py,sha256=VPMNnUIPcqJWDngITX6cfaPlM6zJwzCApXAnT_oaxSQ,3431
1026
- zenml/zen_server/rbac/rbac_sql_zen_store.py,sha256=djGycBkciChk48q8oL7mHM0c-cHJM-S7inv5f3gcDgg,5942
1026
+ zenml/zen_server/rbac/rbac_sql_zen_store.py,sha256=ZBjAbCUlhMsp8GZiIkULl2ztJ8K2Wf-0QdSxzQXwovM,5930
1027
1027
  zenml/zen_server/rbac/utils.py,sha256=09r1dSZ04hcag21rg6Ug2fMCdYfNjSBnx_W8C336GzE,24254
1028
1028
  zenml/zen_server/rbac/zenml_cloud_rbac.py,sha256=L1Tio4IcNNxNWnVpAqBWYgdVfrqR20ddvdhWAo1i3f4,6055
1029
1029
  zenml/zen_server/routers/__init__.py,sha256=ViyAhWL-ogHxE9wBvB_iMcur5H1NRVrzXkpogVY7FBA,641
@@ -1044,7 +1044,7 @@ zenml/zen_server/routers/pipelines_endpoints.py,sha256=R6OM-0Tc6ZNPzQmLs5MWTJIE4
1044
1044
  zenml/zen_server/routers/plugin_endpoints.py,sha256=vgIdA0kdYsf8PeF_pqDaqEYnIi2mlYALAv4uB9Nn7S0,3239
1045
1045
  zenml/zen_server/routers/projects_endpoints.py,sha256=iIgCg_0_iR5OddgULvsP4xxMOOmEGmtCuSKYZVRE9f4,8464
1046
1046
  zenml/zen_server/routers/run_metadata_endpoints.py,sha256=UTWQvweZTGuZnLrqhbIRYQ-z_TfOPY3Kn9p4YwU0tqw,3662
1047
- zenml/zen_server/routers/run_templates_endpoints.py,sha256=rEREmFmG38O_w6ktVJU5iu-dguGZpSC8RN9qH4WkEsA,8254
1047
+ zenml/zen_server/routers/run_templates_endpoints.py,sha256=AdBvwbXefo9nKU2erkNZNFjZ3b8LitPuWR22rgWF3JM,8469
1048
1048
  zenml/zen_server/routers/runs_endpoints.py,sha256=YoTqWm-Mx97q8ZMYXgIY8gr2ICJpRlk6DxxHKN1utFU,12631
1049
1049
  zenml/zen_server/routers/schedule_endpoints.py,sha256=UXt6TIEX0PYhLoBgU-n5kIvWckX1BY_P5uUA_lK9J9A,5782
1050
1050
  zenml/zen_server/routers/secrets_endpoints.py,sha256=diYTC-jl6Hxd_BHVaNsPf2ZcWUwC99naWHsM1xRjR-g,9198
@@ -1064,7 +1064,7 @@ zenml/zen_server/routers/webhook_endpoints.py,sha256=KOJsuykv_TMjL3oEItpC4OWWP75
1064
1064
  zenml/zen_server/secure_headers.py,sha256=glh6QujnjyeoH1_FK-tAS-105G-qKS_34AqSzqJ6TRc,4182
1065
1065
  zenml/zen_server/template_execution/__init__.py,sha256=79knXLKfegsvVSVSWecpqrepq6iAavTUA4hKuiDk-WE,613
1066
1066
  zenml/zen_server/template_execution/runner_entrypoint_configuration.py,sha256=Y8aYJhqqs8Kv8I1q-dM1WemS5VBIfyoaaYH_YkzC7iY,1541
1067
- zenml/zen_server/template_execution/utils.py,sha256=6a62U0hLDe79xLbZM-WbzY-miOeTejQ7vpIkmch0ggU,19086
1067
+ zenml/zen_server/template_execution/utils.py,sha256=CiN7d8jCUTV5oKuoNF9Z_eDkitZrhL6V_Tz4CjU7em8,19410
1068
1068
  zenml/zen_server/template_execution/workload_manager_interface.py,sha256=CL9c7z8ajuZE01DaHmdCDCZmsroDcTarvN-nE8jv6qQ,2590
1069
1069
  zenml/zen_server/utils.py,sha256=yOwPI0DxzDIxF7Ppnty_DuGMWYJ_ubHUNWfbTQ1_q9Q,18461
1070
1070
  zenml/zen_server/zen_server_api.py,sha256=1_YHOUmBulXuHWCxDLYtDCMxGze159UmU3f05643PSg,18182
@@ -1315,11 +1315,11 @@ zenml/zen_stores/secrets_stores/hashicorp_secrets_store.py,sha256=5err1a-TrV3SR5
1315
1315
  zenml/zen_stores/secrets_stores/secrets_store_interface.py,sha256=Q2Jbnt2Pp7NGlR-u1YBfRZV2g8su2Fd0ArBMdksAE-Q,2819
1316
1316
  zenml/zen_stores/secrets_stores/service_connector_secrets_store.py,sha256=S87ne23D08PAwtfRVlVnBn8R0ilTpEh6r8blauNV5WQ,6941
1317
1317
  zenml/zen_stores/secrets_stores/sql_secrets_store.py,sha256=LPFW757WCJLP1S8vrvjsrl2Tf1yo281xUTjSBsos4qk,8788
1318
- zenml/zen_stores/sql_zen_store.py,sha256=biOoDb2_zYmpsN-J-FSlKICYdwM9KDIe-_KN_yDf_mA,441414
1318
+ zenml/zen_stores/sql_zen_store.py,sha256=CK0owrZvLV9u8N0Fa-JrPld-aXxBDncX5MlUexjTIFk,441321
1319
1319
  zenml/zen_stores/template_utils.py,sha256=GbJ7LgGVYHSCKPEA8RNTxPoVTWqpC77F_lGzjJ4O1Fw,9220
1320
1320
  zenml/zen_stores/zen_store_interface.py,sha256=fF_uL_FplnvGvM5o3jOQ8i1zHXhuhKLL2n4nvIKSR7E,92090
1321
- zenml_nightly-0.82.0.dev20250513.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1322
- zenml_nightly-0.82.0.dev20250513.dist-info/METADATA,sha256=hMwBzq4y98Z1jeZUvJMdUimsg1jZUzvmzqDMXpMrSIs,24317
1323
- zenml_nightly-0.82.0.dev20250513.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
1324
- zenml_nightly-0.82.0.dev20250513.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1325
- zenml_nightly-0.82.0.dev20250513.dist-info/RECORD,,
1321
+ zenml_nightly-0.82.0.dev20250514.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1322
+ zenml_nightly-0.82.0.dev20250514.dist-info/METADATA,sha256=t7QND4rpTdtRqG1-abGR9CHeSqTFxKWMoTCLNht1VrQ,24317
1323
+ zenml_nightly-0.82.0.dev20250514.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
1324
+ zenml_nightly-0.82.0.dev20250514.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1325
+ zenml_nightly-0.82.0.dev20250514.dist-info/RECORD,,