zenml-nightly 0.70.0.dev20241203__py3-none-any.whl → 0.70.0.dev20241204__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 (25) hide show
  1. zenml/VERSION +1 -1
  2. zenml/image_builders/base_image_builder.py +5 -2
  3. zenml/image_builders/build_context.py +7 -16
  4. zenml/integrations/aws/__init__.py +3 -0
  5. zenml/integrations/aws/flavors/__init__.py +6 -0
  6. zenml/integrations/aws/flavors/aws_image_builder_flavor.py +146 -0
  7. zenml/integrations/aws/image_builders/__init__.py +20 -0
  8. zenml/integrations/aws/image_builders/aws_image_builder.py +307 -0
  9. zenml/integrations/kaniko/image_builders/kaniko_image_builder.py +2 -1
  10. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +11 -0
  11. zenml/integrations/lightning/flavors/lightning_orchestrator_flavor.py +11 -0
  12. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +12 -0
  13. zenml/materializers/built_in_materializer.py +1 -1
  14. zenml/orchestrators/base_orchestrator.py +12 -0
  15. zenml/orchestrators/output_utils.py +5 -1
  16. zenml/service_connectors/service_connector_utils.py +3 -9
  17. zenml/stack_deployments/aws_stack_deployment.py +22 -0
  18. zenml/utils/archivable.py +65 -36
  19. zenml/utils/code_utils.py +8 -4
  20. zenml/utils/docker_utils.py +9 -0
  21. {zenml_nightly-0.70.0.dev20241203.dist-info → zenml_nightly-0.70.0.dev20241204.dist-info}/METADATA +1 -1
  22. {zenml_nightly-0.70.0.dev20241203.dist-info → zenml_nightly-0.70.0.dev20241204.dist-info}/RECORD +25 -22
  23. {zenml_nightly-0.70.0.dev20241203.dist-info → zenml_nightly-0.70.0.dev20241204.dist-info}/LICENSE +0 -0
  24. {zenml_nightly-0.70.0.dev20241203.dist-info → zenml_nightly-0.70.0.dev20241204.dist-info}/WHEEL +0 -0
  25. {zenml_nightly-0.70.0.dev20241203.dist-info → zenml_nightly-0.70.0.dev20241204.dist-info}/entry_points.txt +0 -0
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.70.0.dev20241203
1
+ 0.70.0.dev20241204
@@ -25,6 +25,7 @@ from zenml.io import fileio
25
25
  from zenml.logger import get_logger
26
26
  from zenml.stack import Flavor, StackComponent
27
27
  from zenml.stack.stack_component import StackComponentConfig
28
+ from zenml.utils.archivable import ArchiveType
28
29
 
29
30
  if TYPE_CHECKING:
30
31
  from zenml.container_registries import BaseContainerRegistry
@@ -100,6 +101,7 @@ class BaseImageBuilder(StackComponent, ABC):
100
101
  def _upload_build_context(
101
102
  build_context: "BuildContext",
102
103
  parent_path_directory_name: str,
104
+ archive_type: ArchiveType = ArchiveType.TAR_GZ,
103
105
  ) -> str:
104
106
  """Uploads a Docker image build context to a remote location.
105
107
 
@@ -109,6 +111,7 @@ class BaseImageBuilder(StackComponent, ABC):
109
111
  the build context to. It will be appended to the artifact
110
112
  store path to create the parent path where the build context
111
113
  will be uploaded to.
114
+ archive_type: The type of archive to create.
112
115
 
113
116
  Returns:
114
117
  The path to the uploaded build context.
@@ -119,7 +122,7 @@ class BaseImageBuilder(StackComponent, ABC):
119
122
 
120
123
  hash_ = hashlib.sha1() # nosec
121
124
  with tempfile.NamedTemporaryFile(mode="w+b", delete=False) as f:
122
- build_context.write_archive(f, use_gzip=True)
125
+ build_context.write_archive(f, archive_type)
123
126
 
124
127
  while True:
125
128
  data = f.read(64 * 1024)
@@ -127,7 +130,7 @@ class BaseImageBuilder(StackComponent, ABC):
127
130
  break
128
131
  hash_.update(data)
129
132
 
130
- filename = f"{hash_.hexdigest()}.tar.gz"
133
+ filename = f"{hash_.hexdigest()}.{archive_type.value}"
131
134
  filepath = f"{parent_path}/{filename}"
132
135
  if not fileio.exists(filepath):
133
136
  logger.info("Uploading build context to `%s`.", filepath)
@@ -20,7 +20,7 @@ from zenml.constants import REPOSITORY_DIRECTORY_NAME
20
20
  from zenml.io import fileio
21
21
  from zenml.logger import get_logger
22
22
  from zenml.utils import io_utils, string_utils
23
- from zenml.utils.archivable import Archivable
23
+ from zenml.utils.archivable import Archivable, ArchiveType
24
24
 
25
25
  logger = get_logger(__name__)
26
26
 
@@ -69,28 +69,19 @@ class BuildContext(Archivable):
69
69
  return None
70
70
 
71
71
  def write_archive(
72
- self, output_file: IO[bytes], use_gzip: bool = True
72
+ self,
73
+ output_file: IO[bytes],
74
+ archive_type: ArchiveType = ArchiveType.TAR_GZ,
73
75
  ) -> None:
74
76
  """Writes an archive of the build context to the given file.
75
77
 
76
78
  Args:
77
79
  output_file: The file to write the archive to.
78
- use_gzip: Whether to use `gzip` to compress the file.
80
+ archive_type: The type of archive to create.
79
81
  """
80
- from docker.utils import build as docker_build_utils
81
-
82
- files = self.get_files()
83
- extra_files = self.get_extra_files()
84
-
85
- context_archive = docker_build_utils.create_archive(
86
- fileobj=output_file,
87
- root=self._root,
88
- files=sorted(files.keys()),
89
- gzip=use_gzip,
90
- extra_files=list(extra_files.items()),
91
- )
82
+ super().write_archive(output_file, archive_type)
92
83
 
93
- build_context_size = os.path.getsize(context_archive.name)
84
+ build_context_size = os.path.getsize(output_file.name)
94
85
  if (
95
86
  self._root
96
87
  and build_context_size > 50 * 1024 * 1024
@@ -33,6 +33,7 @@ AWS_SAGEMAKER_ORCHESTRATOR_FLAVOR = "sagemaker"
33
33
  AWS_CONNECTOR_TYPE = "aws"
34
34
  AWS_RESOURCE_TYPE = "aws-generic"
35
35
  S3_RESOURCE_TYPE = "s3-bucket"
36
+ AWS_IMAGE_BUILDER_FLAVOR = "aws"
36
37
 
37
38
  class AWSIntegration(Integration):
38
39
  """Definition of AWS integration for ZenML."""
@@ -59,12 +60,14 @@ class AWSIntegration(Integration):
59
60
  """
60
61
  from zenml.integrations.aws.flavors import (
61
62
  AWSContainerRegistryFlavor,
63
+ AWSImageBuilderFlavor,
62
64
  SagemakerOrchestratorFlavor,
63
65
  SagemakerStepOperatorFlavor,
64
66
  )
65
67
 
66
68
  return [
67
69
  AWSContainerRegistryFlavor,
70
+ AWSImageBuilderFlavor,
68
71
  SagemakerStepOperatorFlavor,
69
72
  SagemakerOrchestratorFlavor,
70
73
  ]
@@ -17,6 +17,10 @@ from zenml.integrations.aws.flavors.aws_container_registry_flavor import (
17
17
  AWSContainerRegistryConfig,
18
18
  AWSContainerRegistryFlavor,
19
19
  )
20
+ from zenml.integrations.aws.flavors.aws_image_builder_flavor import (
21
+ AWSImageBuilderConfig,
22
+ AWSImageBuilderFlavor,
23
+ )
20
24
  from zenml.integrations.aws.flavors.sagemaker_orchestrator_flavor import (
21
25
  SagemakerOrchestratorConfig,
22
26
  SagemakerOrchestratorFlavor,
@@ -29,6 +33,8 @@ from zenml.integrations.aws.flavors.sagemaker_step_operator_flavor import (
29
33
  __all__ = [
30
34
  "AWSContainerRegistryFlavor",
31
35
  "AWSContainerRegistryConfig",
36
+ "AWSImageBuilderConfig",
37
+ "AWSImageBuilderFlavor",
32
38
  "SagemakerStepOperatorFlavor",
33
39
  "SagemakerStepOperatorConfig",
34
40
  "SagemakerOrchestratorFlavor",
@@ -0,0 +1,146 @@
1
+ # Copyright (c) ZenML GmbH 2024. 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
+ """AWS Code Build image builder flavor."""
15
+
16
+ from typing import TYPE_CHECKING, Dict, Optional, Type
17
+
18
+ from zenml.image_builders import BaseImageBuilderConfig, BaseImageBuilderFlavor
19
+ from zenml.integrations.aws import (
20
+ AWS_CONNECTOR_TYPE,
21
+ AWS_IMAGE_BUILDER_FLAVOR,
22
+ AWS_RESOURCE_TYPE,
23
+ )
24
+ from zenml.models import ServiceConnectorRequirements
25
+
26
+ if TYPE_CHECKING:
27
+ from zenml.integrations.aws.image_builders import AWSImageBuilder
28
+
29
+
30
+ DEFAULT_CLOUDBUILD_IMAGE = "bentolor/docker-dind-awscli"
31
+ DEFAULT_CLOUDBUILD_COMPUTE_TYPE = "BUILD_GENERAL1_SMALL"
32
+
33
+
34
+ class AWSImageBuilderConfig(BaseImageBuilderConfig):
35
+ """AWS Code Build image builder configuration.
36
+
37
+ Attributes:
38
+ code_build_project: The name of an existing AWS CodeBuild project to use
39
+ to build the image. The CodeBuild project must exist in the AWS
40
+ account and region inferred from the AWS service connector
41
+ credentials or implicitly from the local AWS config.
42
+ build_image: The Docker image to use for the AWS CodeBuild environment.
43
+ The image must have Docker installed and be able to run Docker
44
+ commands. The default image is bentolor/docker-dind-awscli.
45
+ This can be customized to use a mirror, if needed, in case the
46
+ Dockerhub image is not accessible or rate-limited.
47
+ custom_env_vars: Custom environment variables to pass to the AWS
48
+ CodeBuild build.
49
+ compute_type: The compute type to use for the AWS CodeBuild build.
50
+ The default is BUILD_GENERAL1_SMALL.
51
+ implicit_container_registry_auth: Whether to use implicit authentication
52
+ to authenticate the AWS Code Build build to the container registry
53
+ when pushing container images. If set to False, the container
54
+ registry credentials must be explicitly configured for the container
55
+ registry stack component or the container registry stack component
56
+ must be linked to a service connector.
57
+ NOTE: When implicit_container_registry_auth is set to False, the
58
+ container registry credentials will be passed to the AWS Code Build
59
+ build as environment variables. This is not recommended for
60
+ production use unless your service connector is configured to
61
+ generate short-lived credentials.
62
+ """
63
+
64
+ code_build_project: str
65
+ build_image: str = DEFAULT_CLOUDBUILD_IMAGE
66
+ custom_env_vars: Optional[Dict[str, str]] = None
67
+ compute_type: str = DEFAULT_CLOUDBUILD_COMPUTE_TYPE
68
+ implicit_container_registry_auth: bool = True
69
+
70
+
71
+ class AWSImageBuilderFlavor(BaseImageBuilderFlavor):
72
+ """AWS Code Build image builder flavor."""
73
+
74
+ @property
75
+ def name(self) -> str:
76
+ """The flavor name.
77
+
78
+ Returns:
79
+ The name of the flavor.
80
+ """
81
+ return AWS_IMAGE_BUILDER_FLAVOR
82
+
83
+ @property
84
+ def service_connector_requirements(
85
+ self,
86
+ ) -> Optional[ServiceConnectorRequirements]:
87
+ """Service connector resource requirements for service connectors.
88
+
89
+ Specifies resource requirements that are used to filter the available
90
+ service connector types that are compatible with this flavor.
91
+
92
+ Returns:
93
+ Requirements for compatible service connectors, if a service
94
+ connector is required for this flavor.
95
+ """
96
+ return ServiceConnectorRequirements(
97
+ connector_type=AWS_CONNECTOR_TYPE,
98
+ resource_type=AWS_RESOURCE_TYPE,
99
+ )
100
+
101
+ @property
102
+ def docs_url(self) -> Optional[str]:
103
+ """A url to point at docs explaining this flavor.
104
+
105
+ Returns:
106
+ A flavor docs url.
107
+ """
108
+ return self.generate_default_docs_url()
109
+
110
+ @property
111
+ def sdk_docs_url(self) -> Optional[str]:
112
+ """A url to point at SDK docs explaining this flavor.
113
+
114
+ Returns:
115
+ A flavor SDK docs url.
116
+ """
117
+ return self.generate_default_sdk_docs_url()
118
+
119
+ @property
120
+ def logo_url(self) -> str:
121
+ """A url to represent the flavor in the dashboard.
122
+
123
+ Returns:
124
+ The flavor logo.
125
+ """
126
+ return "https://public-flavor-logos.s3.eu-central-1.amazonaws.com/image_builder/aws.png"
127
+
128
+ @property
129
+ def config_class(self) -> Type[BaseImageBuilderConfig]:
130
+ """The config class.
131
+
132
+ Returns:
133
+ The config class.
134
+ """
135
+ return AWSImageBuilderConfig
136
+
137
+ @property
138
+ def implementation_class(self) -> Type["AWSImageBuilder"]:
139
+ """Implementation class.
140
+
141
+ Returns:
142
+ The implementation class.
143
+ """
144
+ from zenml.integrations.aws.image_builders import AWSImageBuilder
145
+
146
+ return AWSImageBuilder
@@ -0,0 +1,20 @@
1
+ # Copyright (c) ZenML GmbH 2024. 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
+ """Initialization for the AWS image builder."""
15
+
16
+ from zenml.integrations.aws.image_builders.aws_image_builder import (
17
+ AWSImageBuilder,
18
+ )
19
+
20
+ __all__ = ["AWSImageBuilder"]
@@ -0,0 +1,307 @@
1
+ # Copyright (c) ZenML GmbH 2024. 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
+ """AWS Code Build image builder implementation."""
15
+
16
+ import time
17
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, cast
18
+ from urllib.parse import urlparse
19
+ from uuid import uuid4
20
+
21
+ import boto3
22
+
23
+ from zenml.enums import StackComponentType
24
+ from zenml.image_builders import BaseImageBuilder
25
+ from zenml.integrations.aws import (
26
+ AWS_CONTAINER_REGISTRY_FLAVOR,
27
+ )
28
+ from zenml.integrations.aws.flavors import AWSImageBuilderConfig
29
+ from zenml.logger import get_logger
30
+ from zenml.stack import StackValidator
31
+ from zenml.utils.archivable import ArchiveType
32
+
33
+ if TYPE_CHECKING:
34
+ from zenml.container_registries import BaseContainerRegistry
35
+ from zenml.image_builders import BuildContext
36
+ from zenml.stack import Stack
37
+
38
+ logger = get_logger(__name__)
39
+
40
+
41
+ class AWSImageBuilder(BaseImageBuilder):
42
+ """AWS Code Build image builder implementation."""
43
+
44
+ _code_build_client: Optional[Any] = None
45
+
46
+ @property
47
+ def config(self) -> AWSImageBuilderConfig:
48
+ """The stack component configuration.
49
+
50
+ Returns:
51
+ The configuration.
52
+ """
53
+ return cast(AWSImageBuilderConfig, self._config)
54
+
55
+ @property
56
+ def is_building_locally(self) -> bool:
57
+ """Whether the image builder builds the images on the client machine.
58
+
59
+ Returns:
60
+ True if the image builder builds locally, False otherwise.
61
+ """
62
+ return False
63
+
64
+ @property
65
+ def validator(self) -> Optional["StackValidator"]:
66
+ """Validates the stack for the AWS Code Build Image Builder.
67
+
68
+ The AWS Code Build Image Builder requires a container registry to
69
+ push the image to and an S3 Artifact Store to upload the build context,
70
+ so AWS Code Build can access it.
71
+
72
+ Returns:
73
+ Stack validator.
74
+ """
75
+
76
+ def _validate_remote_components(stack: "Stack") -> Tuple[bool, str]:
77
+ if stack.artifact_store.flavor != "s3":
78
+ return False, (
79
+ "The AWS Image Builder requires an S3 Artifact Store to "
80
+ "upload the build context, so AWS Code Build can access it."
81
+ "Please update your stack to include an S3 Artifact Store "
82
+ "and try again."
83
+ )
84
+
85
+ return True, ""
86
+
87
+ return StackValidator(
88
+ required_components={StackComponentType.CONTAINER_REGISTRY},
89
+ custom_validation_function=_validate_remote_components,
90
+ )
91
+
92
+ @property
93
+ def code_build_client(self) -> Any:
94
+ """The authenticated AWS Code Build client to use for interacting with AWS services.
95
+
96
+ Returns:
97
+ The authenticated AWS Code Build client.
98
+
99
+ Raises:
100
+ RuntimeError: If the AWS Code Build client cannot be created.
101
+ """
102
+ if (
103
+ self._code_build_client is not None
104
+ and self.connector_has_expired()
105
+ ):
106
+ self._code_build_client = None
107
+ if self._code_build_client is not None:
108
+ return self._code_build_client
109
+
110
+ # Option 1: Service connector
111
+ if connector := self.get_connector():
112
+ boto_session = connector.connect()
113
+ if not isinstance(boto_session, boto3.Session):
114
+ raise RuntimeError(
115
+ f"Expected to receive a `boto3.Session` object from the "
116
+ f"linked connector, but got type `{type(boto_session)}`."
117
+ )
118
+ # Option 2: Implicit configuration
119
+ else:
120
+ boto_session = boto3.Session()
121
+
122
+ self._code_build_client = boto_session.client("codebuild")
123
+ return self._code_build_client
124
+
125
+ def build(
126
+ self,
127
+ image_name: str,
128
+ build_context: "BuildContext",
129
+ docker_build_options: Dict[str, Any],
130
+ container_registry: Optional["BaseContainerRegistry"] = None,
131
+ ) -> str:
132
+ """Builds and pushes a Docker image.
133
+
134
+ Args:
135
+ image_name: Name of the image to build and push.
136
+ build_context: The build context to use for the image.
137
+ docker_build_options: Docker build options.
138
+ container_registry: Optional container registry to push to.
139
+
140
+ Returns:
141
+ The Docker image name with digest.
142
+
143
+ Raises:
144
+ RuntimeError: If no container registry is passed.
145
+ RuntimeError: If the Cloud Build build fails.
146
+ """
147
+ if not container_registry:
148
+ raise RuntimeError(
149
+ "The AWS Image Builder requires a container registry to push "
150
+ "the image to. Please provide one and try again."
151
+ )
152
+
153
+ logger.info("Using AWS Code Build to build image `%s`", image_name)
154
+ cloud_build_context = self._upload_build_context(
155
+ build_context=build_context,
156
+ parent_path_directory_name=f"code-build-contexts/{str(self.id)}",
157
+ archive_type=ArchiveType.ZIP,
158
+ )
159
+
160
+ url_parts = urlparse(cloud_build_context)
161
+ bucket = url_parts.netloc
162
+ object_path = url_parts.path.lstrip("/")
163
+ logger.info(
164
+ "Build context located in bucket `%s` and object path `%s`",
165
+ bucket,
166
+ object_path,
167
+ )
168
+
169
+ # Pass authentication credentials as environment variables, if
170
+ # the container registry has credentials and if implicit authentication
171
+ # is disabled
172
+ environment_variables_override: Dict[str, str] = {}
173
+ pre_build_commands = []
174
+ if not self.config.implicit_container_registry_auth:
175
+ credentials = container_registry.credentials
176
+ if credentials:
177
+ environment_variables_override = {
178
+ "CONTAINER_REGISTRY_USERNAME": credentials[0],
179
+ "CONTAINER_REGISTRY_PASSWORD": credentials[1],
180
+ }
181
+ pre_build_commands = [
182
+ "echo Logging in to container registry",
183
+ 'echo "$CONTAINER_REGISTRY_PASSWORD" | docker login --username "$CONTAINER_REGISTRY_USERNAME" --password-stdin '
184
+ f"{container_registry.config.uri}",
185
+ ]
186
+ elif container_registry.flavor == AWS_CONTAINER_REGISTRY_FLAVOR:
187
+ pre_build_commands = [
188
+ "echo Logging in to EKS",
189
+ f"aws ecr get-login-password --region {self.code_build_client._client_config.region_name} | docker login --username AWS --password-stdin {container_registry.config.uri}",
190
+ ]
191
+
192
+ # Convert the docker_build_options dictionary to a list of strings
193
+ docker_build_args = ""
194
+ for key, value in docker_build_options.items():
195
+ option = f"--{key}"
196
+ if isinstance(value, list):
197
+ for val in value:
198
+ docker_build_args += f"{option} {val} "
199
+ elif value is not None and not isinstance(value, bool):
200
+ docker_build_args += f"{option} {value} "
201
+ elif value is not False:
202
+ docker_build_args += f"{option} "
203
+
204
+ pre_build_commands_str = "\n".join(
205
+ [f" - {command}" for command in pre_build_commands]
206
+ )
207
+
208
+ # Generate and use a unique tag for the Docker image. This is easier
209
+ # than trying to parse the image digest from the Code Build logs.
210
+ build_id = str(uuid4())
211
+ # Replace the tag in the image name with the unique build ID
212
+ repo_name = image_name.split(":")[0]
213
+ alt_image_name = f"{repo_name}:{build_id}"
214
+
215
+ buildspec = f"""
216
+ version: 0.2
217
+ phases:
218
+ pre_build:
219
+ commands:
220
+ {pre_build_commands_str}
221
+ build:
222
+ commands:
223
+ - echo Build started on `date`
224
+ - echo Building the Docker image...
225
+ - docker build -t {image_name} . {docker_build_args}
226
+ - echo Build completed on `date`
227
+ post_build:
228
+ commands:
229
+ - echo Pushing the Docker image...
230
+ - docker push {image_name}
231
+ - docker tag {image_name} {alt_image_name}
232
+ - docker push {alt_image_name}
233
+ - echo Pushed the Docker image
234
+ artifacts:
235
+ files:
236
+ - '**/*'
237
+ """
238
+
239
+ if self.config.custom_env_vars:
240
+ environment_variables_override.update(self.config.custom_env_vars)
241
+
242
+ environment_variables_override_list = [
243
+ {
244
+ "name": key,
245
+ "value": value,
246
+ "type": "PLAINTEXT",
247
+ }
248
+ for key, value in environment_variables_override.items()
249
+ ]
250
+
251
+ # Override the build project with the parameters needed to run a
252
+ # docker-in-docker build, as covered here: https://docs.aws.amazon.com/codebuild/latest/userguide/sample-docker-section.html
253
+ response = self.code_build_client.start_build(
254
+ projectName=self.config.code_build_project,
255
+ environmentTypeOverride="LINUX_CONTAINER",
256
+ imageOverride=self.config.build_image,
257
+ computeTypeOverride=self.config.compute_type,
258
+ privilegedModeOverride=False,
259
+ sourceTypeOverride="S3",
260
+ sourceLocationOverride=f"{bucket}/{object_path}",
261
+ buildspecOverride=buildspec,
262
+ environmentVariablesOverride=environment_variables_override_list,
263
+ # no artifacts
264
+ artifactsOverride={"type": "NO_ARTIFACTS"},
265
+ )
266
+
267
+ build_arn = response["build"]["arn"]
268
+
269
+ # Parse the AWS region, account, codebuild project and build name from the ARN
270
+ aws_region, aws_account, build = build_arn.split(":", maxsplit=5)[3:6]
271
+ codebuild_project = build.split("/")[1].split(":")[0]
272
+
273
+ logs_url = f"https://{aws_region}.console.aws.amazon.com/codesuite/codebuild/{aws_account}/projects/{codebuild_project}/{build}/log"
274
+ logger.info(
275
+ f"Running Code Build to build the Docker image. Cloud Build logs: `{logs_url}`",
276
+ )
277
+
278
+ # Wait for the build to complete
279
+ code_build_id = response["build"]["id"]
280
+ while True:
281
+ build_status = self.code_build_client.batch_get_builds(
282
+ ids=[code_build_id]
283
+ )
284
+ build = build_status["builds"][0]
285
+ status = build["buildStatus"]
286
+ if status in [
287
+ "SUCCEEDED",
288
+ "FAILED",
289
+ "FAULT",
290
+ "TIMED_OUT",
291
+ "STOPPED",
292
+ ]:
293
+ break
294
+ time.sleep(10)
295
+
296
+ if status != "SUCCEEDED":
297
+ raise RuntimeError(
298
+ f"The Code Build run to build the Docker image has failed. More "
299
+ f"information can be found in the Cloud Build logs: {logs_url}."
300
+ )
301
+
302
+ logger.info(
303
+ f"The Docker image has been built successfully. More information can "
304
+ f"be found in the Cloud Build logs: `{logs_url}`."
305
+ )
306
+
307
+ return alt_image_name
@@ -25,6 +25,7 @@ from zenml.image_builders import BaseImageBuilder
25
25
  from zenml.integrations.kaniko.flavors import KanikoImageBuilderConfig
26
26
  from zenml.logger import get_logger
27
27
  from zenml.stack import StackValidator
28
+ from zenml.utils.archivable import ArchiveType
28
29
 
29
30
  if TYPE_CHECKING:
30
31
  from zenml.container_registries import BaseContainerRegistry
@@ -295,7 +296,7 @@ class KanikoImageBuilder(BaseImageBuilder):
295
296
  logger.debug("Writing build context to process stdin.")
296
297
  assert process.stdin
297
298
  with process.stdin as _, tempfile.TemporaryFile(mode="w+b") as f:
298
- build_context.write_archive(f, use_gzip=True)
299
+ build_context.write_archive(f, archive_type=ArchiveType.TAR_GZ)
299
300
  while True:
300
301
  data = f.read(1024)
301
302
  if not data:
@@ -134,6 +134,17 @@ class KubernetesOrchestratorConfig(
134
134
  """
135
135
  return True
136
136
 
137
+ @property
138
+ def supports_client_side_caching(self) -> bool:
139
+ """Whether the orchestrator supports client side caching.
140
+
141
+ Returns:
142
+ Whether the orchestrator supports client side caching.
143
+ """
144
+ # The Kubernetes orchestrator starts step pods from a pipeline pod.
145
+ # This is currently not supported when using client-side caching.
146
+ return False
147
+
137
148
 
138
149
  class KubernetesOrchestratorFlavor(BaseOrchestratorFlavor):
139
150
  """Kubernetes orchestrator flavor."""
@@ -94,6 +94,17 @@ class LightningOrchestratorConfig(
94
94
  """
95
95
  return False
96
96
 
97
+ @property
98
+ def supports_client_side_caching(self) -> bool:
99
+ """Whether the orchestrator supports client side caching.
100
+
101
+ Returns:
102
+ Whether the orchestrator supports client side caching.
103
+ """
104
+ # The Lightning orchestrator starts step studios from a pipeline studio.
105
+ # This is currently not supported when using client-side caching.
106
+ return False
107
+
97
108
 
98
109
  class LightningOrchestratorFlavor(BaseOrchestratorFlavor):
99
110
  """Lightning orchestrator flavor."""
@@ -144,3 +144,15 @@ class SkypilotBaseOrchestratorConfig(
144
144
  True if this config is for a local component, False otherwise.
145
145
  """
146
146
  return False
147
+
148
+ @property
149
+ def supports_client_side_caching(self) -> bool:
150
+ """Whether the orchestrator supports client side caching.
151
+
152
+ Returns:
153
+ Whether the orchestrator supports client side caching.
154
+ """
155
+ # The Skypilot orchestrator runs the entire pipeline in a single VM, or
156
+ # starts additional VMs from the root VM. Both of those cases are
157
+ # currently not supported when using client-side caching.
158
+ return False
@@ -429,7 +429,7 @@ class BuiltInContainerMaterializer(BaseMaterializer):
429
429
  # doesn't work for non-serializable types as they
430
430
  # are saved as list of lists in different files
431
431
  if _is_serializable(data):
432
- return {self.data_path: VisualizationType.JSON}
432
+ return {self.data_path.replace("\\", "/"): VisualizationType.JSON}
433
433
  return {}
434
434
 
435
435
  def extract_metadata(self, data: Any) -> Dict[str, "MetadataType"]:
@@ -84,6 +84,15 @@ class BaseOrchestratorConfig(StackComponentConfig):
84
84
  """
85
85
  return False
86
86
 
87
+ @property
88
+ def supports_client_side_caching(self) -> bool:
89
+ """Whether the orchestrator supports client side caching.
90
+
91
+ Returns:
92
+ Whether the orchestrator supports client side caching.
93
+ """
94
+ return True
95
+
87
96
 
88
97
  class BaseOrchestrator(StackComponent, ABC):
89
98
  """Base class for all orchestrators.
@@ -205,6 +214,7 @@ class BaseOrchestrator(StackComponent, ABC):
205
214
 
206
215
  if (
207
216
  placeholder_run
217
+ and self.config.supports_client_side_caching
208
218
  and not deployment.schedule
209
219
  and not prevent_client_side_caching
210
220
  ):
@@ -232,6 +242,8 @@ class BaseOrchestrator(StackComponent, ABC):
232
242
  self._cleanup_run()
233
243
  logger.info("All steps of the pipeline run were cached.")
234
244
  return
245
+ else:
246
+ logger.debug("Skipping client-side caching.")
235
247
 
236
248
  try:
237
249
  if metadata_iterator := self.prepare_or_run_pipeline(
@@ -19,6 +19,7 @@ from uuid import uuid4
19
19
 
20
20
  from zenml.client import Client
21
21
  from zenml.logger import get_logger
22
+ from zenml.utils import string_utils
22
23
 
23
24
  if TYPE_CHECKING:
24
25
  from zenml.artifact_stores import BaseArtifactStore
@@ -75,10 +76,13 @@ def prepare_output_artifact_uris(
75
76
  artifact_store = stack.artifact_store
76
77
  output_artifact_uris: Dict[str, str] = {}
77
78
  for output_name in step.config.outputs.keys():
79
+ substituted_output_name = string_utils.format_name_template(
80
+ output_name, substitutions=step_run.config.substitutions
81
+ )
78
82
  artifact_uri = generate_artifact_uri(
79
83
  artifact_store=stack.artifact_store,
80
84
  step_run=step_run,
81
- output_name=output_name,
85
+ output_name=substituted_output_name,
82
86
  )
83
87
  if artifact_store.exists(artifact_uri):
84
88
  raise RuntimeError("Artifact already exists")
@@ -60,15 +60,9 @@ def _raise_specific_cloud_exception_if_needed(
60
60
  orchestrators: List[ResourcesInfo],
61
61
  container_registries: List[ResourcesInfo],
62
62
  ) -> None:
63
- AWS_DOCS = (
64
- "https://docs.zenml.io/how-to/infrastructure-deployment/auth-management/aws-service-connector"
65
- )
66
- GCP_DOCS = (
67
- "https://docs.zenml.io/how-to/infrastructure-deployment/auth-management/gcp-service-connector"
68
- )
69
- AZURE_DOCS = (
70
- "https://docs.zenml.io/how-to/infrastructure-deployment/auth-management/azure-service-connector"
71
- )
63
+ AWS_DOCS = "https://docs.zenml.io/how-to/infrastructure-deployment/auth-management/aws-service-connector"
64
+ GCP_DOCS = "https://docs.zenml.io/how-to/infrastructure-deployment/auth-management/gcp-service-connector"
65
+ AZURE_DOCS = "https://docs.zenml.io/how-to/infrastructure-deployment/auth-management/azure-service-connector"
72
66
 
73
67
  if not artifact_stores:
74
68
  error_msg = (
@@ -73,6 +73,7 @@ of any potential costs:
73
73
  - An ECR repository registered as a [ZenML container registry](https://docs.zenml.io/stack-components/container-registries/aws).
74
74
  - Sagemaker registered as a [ZenML orchestrator](https://docs.zenml.io/stack-components/orchestrators/sagemaker)
75
75
  as well as a [ZenML step operator](https://docs.zenml.io/stack-components/step-operators/sagemaker).
76
+ - A CodeBuild project registered as a [ZenML image builder](https://docs.zenml.io/stack-components/image-builder/aws).
76
77
  - An IAM user and IAM role with the minimum necessary permissions to access the
77
78
  above resources.
78
79
  - An AWS access key used to give access to ZenML to connect to the above
@@ -158,6 +159,26 @@ console.
158
159
  "ecr:PutImage",
159
160
  "ecr:GetAuthorizationToken",
160
161
  ],
162
+ "CloudBuild (Client)": [
163
+ "codebuild:CreateProject",
164
+ "codebuild:BatchGetBuilds",
165
+ ],
166
+ "CloudBuild (Service)": [
167
+ "s3:GetObject",
168
+ "s3:GetObjectVersion",
169
+ "logs:CreateLogGroup",
170
+ "logs:CreateLogStream",
171
+ "logs:PutLogEvents",
172
+ "ecr:BatchGetImage",
173
+ "ecr:DescribeImages",
174
+ "ecr:BatchCheckLayerAvailability",
175
+ "ecr:GetDownloadUrlForLayer",
176
+ "ecr:InitiateLayerUpload",
177
+ "ecr:UploadLayerPart",
178
+ "ecr:CompleteLayerUpload",
179
+ "ecr:PutImage",
180
+ "ecr:GetAuthorizationToken",
181
+ ],
161
182
  "SageMaker (Client)": [
162
183
  "sagemaker:CreatePipeline",
163
184
  "sagemaker:StartPipelineExecution",
@@ -243,6 +264,7 @@ console.
243
264
  param_ResourceName=f"zenml-{random_str(6).lower()}",
244
265
  param_ZenMLServerURL=self.zenml_server_url,
245
266
  param_ZenMLServerAPIToken=self.zenml_server_api_token,
267
+ param_CodeBuild="true",
246
268
  )
247
269
  # Encode the parameters as URL query parameters
248
270
  query_params = "&".join([f"{k}={v}" for k, v in params.items()])
zenml/utils/archivable.py CHANGED
@@ -15,11 +15,21 @@
15
15
 
16
16
  import io
17
17
  import tarfile
18
+ import zipfile
18
19
  from abc import ABC, abstractmethod
19
20
  from pathlib import Path
20
- from typing import IO, Any, Dict
21
+ from typing import IO, Any, Dict, Optional
21
22
 
22
23
  from zenml.io import fileio
24
+ from zenml.utils.enum_utils import StrEnum
25
+
26
+
27
+ class ArchiveType(StrEnum):
28
+ """Archive types supported by the ZenML build context."""
29
+
30
+ TAR = "tar"
31
+ TAR_GZ = "tar.gz"
32
+ ZIP = "zip"
23
33
 
24
34
 
25
35
  class Archivable(ABC):
@@ -81,52 +91,71 @@ class Archivable(ABC):
81
91
  self._extra_files[file_destination.as_posix()] = f.read()
82
92
 
83
93
  def write_archive(
84
- self, output_file: IO[bytes], use_gzip: bool = True
94
+ self,
95
+ output_file: IO[bytes],
96
+ archive_type: ArchiveType = ArchiveType.TAR_GZ,
85
97
  ) -> None:
86
98
  """Writes an archive of the build context to the given file.
87
99
 
88
100
  Args:
89
101
  output_file: The file to write the archive to.
90
- use_gzip: Whether to use `gzip` to compress the file.
102
+ archive_type: The type of archive to create.
91
103
  """
92
104
  files = self.get_files()
93
105
  extra_files = self.get_extra_files()
106
+ close_fileobj: Optional[Any] = None
107
+ fileobj: Any = output_file
94
108
 
95
- if use_gzip:
96
- from gzip import GzipFile
97
-
98
- # We don't use the builtin gzip functionality of the `tarfile`
99
- # library as that one includes the tar filename and creation
100
- # timestamp in the archive which causes the hash of the resulting
101
- # file to be different each time. We use this hash to avoid
102
- # duplicate uploads, which is why we pass empty values for filename
103
- # and mtime here.
104
- fileobj: Any = GzipFile(
105
- filename="", mode="wb", fileobj=output_file, mtime=0.0
106
- )
109
+ if archive_type == ArchiveType.ZIP:
110
+ fileobj = zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED)
107
111
  else:
108
- fileobj = output_file
109
-
110
- with tarfile.open(mode="w", fileobj=fileobj) as tf:
111
- for archive_path, file_path in files.items():
112
- if archive_path in extra_files:
113
- continue
114
-
115
- if info := tf.gettarinfo(file_path, arcname=archive_path):
116
- if info.isfile():
117
- with open(file_path, "rb") as f:
118
- tf.addfile(info, f)
112
+ if archive_type == ArchiveType.TAR_GZ:
113
+ from gzip import GzipFile
114
+
115
+ # We don't use the builtin gzip functionality of the `tarfile`
116
+ # library as that one includes the tar filename and creation
117
+ # timestamp in the archive which causes the hash of the resulting
118
+ # file to be different each time. We use this hash to avoid
119
+ # duplicate uploads, which is why we pass empty values for filename
120
+ # and mtime here.
121
+ close_fileobj = fileobj = GzipFile(
122
+ filename="", mode="wb", fileobj=output_file, mtime=0.0
123
+ )
124
+ fileobj = tarfile.open(mode="w", fileobj=fileobj)
125
+
126
+ try:
127
+ with fileobj as af:
128
+ for archive_path, file_path in files.items():
129
+ if archive_path in extra_files:
130
+ continue
131
+ if archive_type == ArchiveType.ZIP:
132
+ assert isinstance(af, zipfile.ZipFile)
133
+ af.write(file_path, arcname=archive_path)
119
134
  else:
120
- tf.addfile(info, None)
121
-
122
- for archive_path, contents in extra_files.items():
123
- info = tarfile.TarInfo(archive_path)
124
- contents_encoded = contents.encode("utf-8")
125
- info.size = len(contents_encoded)
126
- tf.addfile(info, io.BytesIO(contents_encoded))
127
-
128
- if use_gzip:
129
- fileobj.close()
135
+ assert isinstance(af, tarfile.TarFile)
136
+ if info := af.gettarinfo(
137
+ file_path, arcname=archive_path
138
+ ):
139
+ if info.isfile():
140
+ with open(file_path, "rb") as f:
141
+ af.addfile(info, f)
142
+ else:
143
+ af.addfile(info, None)
144
+
145
+ for archive_path, contents in extra_files.items():
146
+ contents_encoded = contents.encode("utf-8")
147
+
148
+ if archive_type == ArchiveType.ZIP:
149
+ assert isinstance(af, zipfile.ZipFile)
150
+ af.writestr(archive_path, contents_encoded)
151
+ else:
152
+ assert isinstance(af, tarfile.TarFile)
153
+ info = tarfile.TarInfo(archive_path)
154
+ info.size = len(contents_encoded)
155
+ af.addfile(info, io.BytesIO(contents_encoded))
156
+ finally:
157
+ if close_fileobj:
158
+ close_fileobj.close()
130
159
 
131
160
  output_file.seek(0)
132
161
 
zenml/utils/code_utils.py CHANGED
@@ -25,7 +25,7 @@ from zenml.client import Client
25
25
  from zenml.io import fileio
26
26
  from zenml.logger import get_logger
27
27
  from zenml.utils import source_utils, string_utils
28
- from zenml.utils.archivable import Archivable
28
+ from zenml.utils.archivable import Archivable, ArchiveType
29
29
 
30
30
  if TYPE_CHECKING:
31
31
  from git.repo.base import Repo
@@ -152,15 +152,19 @@ class CodeArchive(Archivable):
152
152
  return all_files
153
153
 
154
154
  def write_archive(
155
- self, output_file: IO[bytes], use_gzip: bool = True
155
+ self,
156
+ output_file: IO[bytes],
157
+ archive_type: ArchiveType = ArchiveType.TAR_GZ,
156
158
  ) -> None:
157
159
  """Writes an archive of the build context to the given file.
158
160
 
159
161
  Args:
160
162
  output_file: The file to write the archive to.
161
- use_gzip: Whether to use `gzip` to compress the file.
163
+ archive_type: The type of archive to create.
162
164
  """
163
- super().write_archive(output_file=output_file, use_gzip=use_gzip)
165
+ super().write_archive(
166
+ output_file=output_file, archive_type=archive_type
167
+ )
164
168
  archive_size = os.path.getsize(output_file.name)
165
169
  if archive_size > 20 * 1024 * 1024:
166
170
  logger.warning(
@@ -266,6 +266,14 @@ def push_image(
266
266
  logger.info("Finished pushing Docker image.")
267
267
 
268
268
  image_name_without_tag, _ = image_name.rsplit(":", maxsplit=1)
269
+
270
+ image = docker_client.images.get(image_name)
271
+ repo_digests: List[str] = image.attrs["RepoDigests"]
272
+
273
+ for digest in repo_digests:
274
+ if digest.startswith(f"{image_name_without_tag}@"):
275
+ return digest
276
+
269
277
  for info in reversed(aux_info):
270
278
  try:
271
279
  repo_digest = info["Digest"]
@@ -304,6 +312,7 @@ def get_image_digest(image_name: str) -> Optional[str]:
304
312
 
305
313
  image = docker_client.images.get(image_name)
306
314
  repo_digests = image.attrs["RepoDigests"]
315
+
307
316
  if len(repo_digests) == 1:
308
317
  return cast(str, repo_digests[0])
309
318
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zenml-nightly
3
- Version: 0.70.0.dev20241203
3
+ Version: 0.70.0.dev20241204
4
4
  Summary: ZenML: Write production-ready ML code.
5
5
  Home-page: https://zenml.io
6
6
  License: Apache-2.0
@@ -6,7 +6,7 @@ RELEASE_NOTES.md,sha256=DleauURHESDrTrcVzCVLqPiSM9NIAk5vldvEFMc7qlk,389375
6
6
  ROADMAP.md,sha256=hiLSmr16BH8Dfx7SaQM4JcXCGCVl6mFZPFAwJeDTrJU,407
7
7
  SECURITY.md,sha256=9DepA8y03yvCZLHEfcXLTDH4lUyKHquAdukBsccNN7c,682
8
8
  zenml/README.md,sha256=827dekbOWAs1BpW7VF1a4d7EbwPbjwccX-2zdXBENZo,1777
9
- zenml/VERSION,sha256=X1k6h9fTwNJHLhvwMrbIeu0zyNdWZlpq_FOYVzRDLMg,19
9
+ zenml/VERSION,sha256=-A-FM4tTGBeZdWuioST8Yb1XGa9Iixr9mH9R98y-uNI,19
10
10
  zenml/__init__.py,sha256=SkMObQA41ajqdZqGErN00S1Vf3KAxpLvbZ-OBy5uYoo,2130
11
11
  zenml/actions/__init__.py,sha256=mrt6wPo73iKRxK754_NqsGyJ3buW7RnVeIGXr1xEw8Y,681
12
12
  zenml/actions/base_action.py,sha256=UcaHev6BTuLDwuswnyaPjdA8AgUqB5xPZ-lRtuvf2FU,25553
@@ -126,8 +126,8 @@ zenml/hooks/__init__.py,sha256=lEifDzp1dkcatoBpCmmRNOEAh0vgrqtQQP_GH_4z1pk,1037
126
126
  zenml/hooks/alerter_hooks.py,sha256=XJPhrnVimOayD2VjYBG_5D6R6sZ08rytwDHvvMD3lNI,3042
127
127
  zenml/hooks/hook_validators.py,sha256=35VuolTruFoj6GUQf8n3PpQVMu54dp6apIGPui4FZu4,2516
128
128
  zenml/image_builders/__init__.py,sha256=WVBxXTCiyhVhvGezovS5O-ypwC8V0YRihCOacd7i5iQ,1210
129
- zenml/image_builders/base_image_builder.py,sha256=-Y5N3zFZsMJvVuzm1M3tU-r38fT9KCdLPFH4knCKM4o,5318
130
- zenml/image_builders/build_context.py,sha256=TTY5T8aG4epeKOOpLItr8PDjmDijfcGaY3zFzmGV1II,6157
129
+ zenml/image_builders/base_image_builder.py,sha256=yFmtn8Y6PdNxie3F51tbpMf8zBhNRnNGr-ejTCEcq4Q,5491
130
+ zenml/image_builders/build_context.py,sha256=k38xERo4IXU9KKM-Zi5A2HzIp1pUZeWnhCPuRPSjkEQ,5864
131
131
  zenml/image_builders/local_image_builder.py,sha256=R_zMpERtUCWLLDZg9kXuAQSWLtin1ve_rxpbUBiym7s,6448
132
132
  zenml/integrations/README.md,sha256=hFIZwjsAItHjvDWVBqGSF-ZAeMsFR2GKX1Axl2g1Bz0,6190
133
133
  zenml/integrations/__init__.py,sha256=GiLRzSCu1O9Jg5NSCRKVDWLIXtKuc90ozntqYjUHo08,4905
@@ -142,13 +142,16 @@ zenml/integrations/argilla/annotators/__init__.py,sha256=QjRMxIQ-skulcLN94GuHuuk
142
142
  zenml/integrations/argilla/annotators/argilla_annotator.py,sha256=aIA5rcwfOYLnUVp2c_aaTAUnVW8GV9gP8myze_jY_qY,15586
143
143
  zenml/integrations/argilla/flavors/__init__.py,sha256=MTogEeiZ1k7nLzGKok3azK_VhKUAJl0GL6OQvsvMlZo,917
144
144
  zenml/integrations/argilla/flavors/argilla_annotator_flavor.py,sha256=NAy6QKLWYXHPTCoWc9RIovsngcRGMwseu3rdNjiCpo4,4473
145
- zenml/integrations/aws/__init__.py,sha256=PGGTfYmnOqh7vFPiu_SFYQ2xE38zhf6TAm0Bp3hz2fo,2386
145
+ zenml/integrations/aws/__init__.py,sha256=x-Ym8FlmeX7bAjL7zBxUp40U11IVZGyfcClRIeEydlI,2489
146
146
  zenml/integrations/aws/container_registries/__init__.py,sha256=fOwo84MiaX_7XhNQEXeyVh8AyOlcIl6nSu_ig68GkSs,827
147
147
  zenml/integrations/aws/container_registries/aws_container_registry.py,sha256=SCxKj_w79Ka0LdxYOdDmaXitketTQRDHrQ4XQ0_f4hs,6091
148
- zenml/integrations/aws/flavors/__init__.py,sha256=-7dzzHCVuGixi_fjm0TVUcaNT5LEJz_Roq6jHoozIcE,1296
148
+ zenml/integrations/aws/flavors/__init__.py,sha256=XYL9fpwKzeFfHCjakU0iJ3SyHVRJk63QT7luOy9Giek,1480
149
149
  zenml/integrations/aws/flavors/aws_container_registry_flavor.py,sha256=GIDLOySz1zF08YSkmKIj89TxBqSLWueXLAHyxYwm-NI,4169
150
+ zenml/integrations/aws/flavors/aws_image_builder_flavor.py,sha256=XobJOw5ymbY22i7YHWGYOKDQoJQAqTeMIfvkADt-DDc,5343
150
151
  zenml/integrations/aws/flavors/sagemaker_orchestrator_flavor.py,sha256=UyHXFP9rn9DQ-Erd9Rtqun9GTcp3Rftbn2a9Xysh_TU,12826
151
152
  zenml/integrations/aws/flavors/sagemaker_step_operator_flavor.py,sha256=OnNokixzGvOTBoZJQ5TDG3k4FFsP1pJmxbiij2VLW4s,5978
153
+ zenml/integrations/aws/image_builders/__init__.py,sha256=91hgH1OphG2i-vk-G8N4yKBFIzK89Wu7BK4-T5yOA7E,786
154
+ zenml/integrations/aws/image_builders/aws_image_builder.py,sha256=UcPYYYjJjfsicY3hV4OZeJt552AVmwPZPlv-AsG1g1I,11489
152
155
  zenml/integrations/aws/orchestrators/__init__.py,sha256=Wh0Fhtt_uo6YrkvXY9kL0M478FL7XpapjoFreUZbgUg,794
153
156
  zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py,sha256=OlnXr_KTWE8fOyO6bNmsCbRdRaCPqWGrUEX4gyVbD80,26801
154
157
  zenml/integrations/aws/orchestrators/sagemaker_orchestrator_entrypoint_config.py,sha256=WXCWdVojIZxx5_3-g1T95S2vsJ-RLNGcp-V409wgme0,1555
@@ -325,7 +328,7 @@ zenml/integrations/kaniko/__init__.py,sha256=r40dq-xp9ji2xtfymwffryglCmsOZe2g1_9
325
328
  zenml/integrations/kaniko/flavors/__init__.py,sha256=PpI7yUpjgLwwAi1ma5uTGihG4zUWxURiRTpHoHEXBIw,865
326
329
  zenml/integrations/kaniko/flavors/kaniko_image_builder_flavor.py,sha256=iRICgO_f9RF1XOp7bO8qjmHm83v2NYqoJWorHZKhVzE,5080
327
330
  zenml/integrations/kaniko/image_builders/__init__.py,sha256=X-ydYoG_6t4OWXDuCgfbugtVvPeOc97Kwf8RQ0KcPiU,787
328
- zenml/integrations/kaniko/image_builders/kaniko_image_builder.py,sha256=30RnR2VvVQ5kkR0KQqS1fpiJf2zrJa7BCWOoOiX53rs,13656
331
+ zenml/integrations/kaniko/image_builders/kaniko_image_builder.py,sha256=N4rLjIHYdw8v1CZvJP9G8RYpaMbERhzDyLP0UcEO3JA,13721
329
332
  zenml/integrations/kubeflow/__init__.py,sha256=ab3v3sJBwo09vbyI2UQ5SnKfL0C9j8hrxR5ji-Xfswo,1791
330
333
  zenml/integrations/kubeflow/flavors/__init__.py,sha256=l560A0oIpYeTpVVrdrVVYj-2-Y5CeyCSQMfwErZROxY,878
331
334
  zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py,sha256=b7W4oASHLYN9o2n__-W3zajb_MXhPaY0UutecsW0Xw4,10381
@@ -334,7 +337,7 @@ zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py,sha256=H4rpm3
334
337
  zenml/integrations/kubeflow/orchestrators/local_deployment_utils.py,sha256=qszoOdvBpgIp40XkncphXAr9dRKnyZzGiz2mJ56bYmw,15448
335
338
  zenml/integrations/kubernetes/__init__.py,sha256=UzU5CaogX6ud5ChCK8JSZ06eoW18eIudbgntgPijYSc,1853
336
339
  zenml/integrations/kubernetes/flavors/__init__.py,sha256=a5gU45qCj3FkLwl_uVjlIkL_2F5DHk-w1gdcZrvVjBI,1266
337
- zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py,sha256=HkCyDWqv1lDd8W6GeXE6PeHQiUrHPfSkfw3sB0B2xuA,7911
340
+ zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py,sha256=al3EwEhwbG2uCHpkfC_4J-nOPCNW-LdJ568X0hPAvxE,8312
338
341
  zenml/integrations/kubernetes/flavors/kubernetes_step_operator_flavor.py,sha256=ILN-H4cl7z3i4ltb4UBs55wbtIo871b4ib28pYkQoyQ,5605
339
342
  zenml/integrations/kubernetes/orchestrators/__init__.py,sha256=TJID3OTieZBox36WpQpzD0jdVRA_aZVcs_bNtfXS8ik,811
340
343
  zenml/integrations/kubernetes/orchestrators/kube_utils.py,sha256=0Cj1RoiuXL4oACnfyzEpOiCTnHt_YoF5ml3bhobyOEg,12195
@@ -369,7 +372,7 @@ zenml/integrations/lightgbm/materializers/lightgbm_booster_materializer.py,sha25
369
372
  zenml/integrations/lightgbm/materializers/lightgbm_dataset_materializer.py,sha256=q1L1cke0j9hYNbruPxaWDDgp0thNPNHZA0gH4gyfugI,2856
370
373
  zenml/integrations/lightning/__init__.py,sha256=Wyj8P7ihX8DpOO4bmggM_Pq3HDwU02fjdB51s5sHJSA,1521
371
374
  zenml/integrations/lightning/flavors/__init__.py,sha256=Ma949QQTTYw1Zw1fo6zSUXomXfXQRTPHY9N2wZGweMA,883
372
- zenml/integrations/lightning/flavors/lightning_orchestrator_flavor.py,sha256=prKhMbvbtEXWYbprM9udc4HJltwCNTKqCRqUZwWgJ2I,4853
375
+ zenml/integrations/lightning/flavors/lightning_orchestrator_flavor.py,sha256=U6ewra4C8cSrnRQTlEJrY2ouR4XJ3ShnAg1fDoC9fFQ,5259
373
376
  zenml/integrations/lightning/orchestrators/__init__.py,sha256=rUaCQPcbpAPy57jx8ZqEOjTJv8zigT_nCPrMdfQJ8OU,1030
374
377
  zenml/integrations/lightning/orchestrators/lightning_orchestrator.py,sha256=6XGg-cKKRNCot6DI9ub4oZWF4_K41OHs1lT90FL8VsM,24712
375
378
  zenml/integrations/lightning/orchestrators/lightning_orchestrator_entrypoint.py,sha256=VHVXZ6jZ0URLhwaIPMyDmrnrBpYvzDnqQdIoSVM9m6E,11506
@@ -478,7 +481,7 @@ zenml/integrations/sklearn/materializers/__init__.py,sha256=vHIx7njuVcP_kGbyECgJ
478
481
  zenml/integrations/sklearn/materializers/sklearn_materializer.py,sha256=IaE8DS9L2gjfRVv8RT8p7ls7cJJ5qzt6hRgdpL6pp20,1562
479
482
  zenml/integrations/skypilot/__init__.py,sha256=PzNuJJykzfu34pTC4kSD18ARyGysuhzEW8oLTm4oHuo,612
480
483
  zenml/integrations/skypilot/flavors/__init__.py,sha256=PzNuJJykzfu34pTC4kSD18ARyGysuhzEW8oLTm4oHuo,612
481
- zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py,sha256=_lMmSo1aBSpnfYPGKD1CbpEdrGfVVIavA_yl2ZvGiYU,6204
484
+ zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py,sha256=UPHfsB75CDZ8ecxxlL8aTo3IGIVuCAU_USBHzhULMuc,6675
482
485
  zenml/integrations/skypilot/orchestrators/__init__.py,sha256=elo6QiImzys1m_bgu96U1HCVRepHQI1m7Jgqn6aEJ4Q,844
483
486
  zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py,sha256=Oxd_8MEDd5JFovPgHE5xWreLTBQhTJZPA1nLYpvgIa0,14290
484
487
  zenml/integrations/skypilot/orchestrators/skypilot_orchestrator_entrypoint.py,sha256=5sq04vu2ArsyW56wvH8CRLG8kmeaSkPYPzirGGe7mds,9737
@@ -595,7 +598,7 @@ zenml/login/pro/utils.py,sha256=PnQ90eiqijY-VKqd974HzCtAosrHhzOxL1NpqZbpE5M,5355
595
598
  zenml/login/web_login.py,sha256=NkFKnPj8qDZAb2FfDW8ZvkWrGiurf7YiYEEs5m844aM,9037
596
599
  zenml/materializers/__init__.py,sha256=maME5CxKcgOkIFwG_iARt1-tuW8u8ZhTzfw50uyv_BA,1667
597
600
  zenml/materializers/base_materializer.py,sha256=M4hwkw7PB0LskCE92r-S35011l7DlFemit-EuUCW3Nc,14002
598
- zenml/materializers/built_in_materializer.py,sha256=XGFZJ0ZzB4QrTe4bnayEcr7dkj5sihmdxVgv6Sgc0XA,15649
601
+ zenml/materializers/built_in_materializer.py,sha256=AFrCW_LErey2ws6vfLTbBP5gx3IFi05YPEmT4BA-CzY,15668
599
602
  zenml/materializers/cloudpickle_materializer.py,sha256=x8a6jEMTky6N2YVHiwrnGWSfVJUpiy-4kQsD2Aqj_E0,4837
600
603
  zenml/materializers/materializer_registry.py,sha256=ic-aWhJ2Ex9F_rml2dDVAxhRfW3nd71QMxzfTPP6BIM,4002
601
604
  zenml/materializers/numpy_materializer.py,sha256=OLcHF9Z0tAqQ_U8TraA0vGmZjHoT7eT_XevncIutt0M,1715
@@ -674,7 +677,7 @@ zenml/models/v2/misc/service_connector_type.py,sha256=jGJLvIsBB87ZIEeZCLLueUf28H
674
677
  zenml/models/v2/misc/stack_deployment.py,sha256=PgQevLjvHTpsecY_rzrXesr7jiGms7rH_QbFtI2ZIaA,3768
675
678
  zenml/models/v2/misc/user_auth.py,sha256=1-yafNA9qK4wL8ToROjaklTVI7Mj9va0t80_4wm7w3U,6988
676
679
  zenml/orchestrators/__init__.py,sha256=p4Y9Ni7Lp33fZ6UrjgI7qu-rrg8LrlyafCM-K1WC81w,1961
677
- zenml/orchestrators/base_orchestrator.py,sha256=rKC76EVovOIRyRM5x3Y6gNOhnrCLan_vM_d9CU71i68,12267
680
+ zenml/orchestrators/base_orchestrator.py,sha256=vQsMUhhZUX34EyJbYpXB4F0iPmrOHaVLtsKM0vuN1yE,12646
678
681
  zenml/orchestrators/cache_utils.py,sha256=J5sMmgy-qRJVtTWt5hDjSAR6vPPulOhMJu0m-Y1onO8,4327
679
682
  zenml/orchestrators/containerized_orchestrator.py,sha256=rdebgBW0Bk--JcHcT0NpLkAbyhY0VS5xO1uwWEgkLpA,3230
680
683
  zenml/orchestrators/dag_runner.py,sha256=0F0zOy90ZHad_YUiwG_47JiH7KEVFQ5tLen0kGPvppk,6940
@@ -683,7 +686,7 @@ zenml/orchestrators/local/__init__.py,sha256=qlU91hgqGKeycw-Qntrn-iMuoMTaNrq-Rgf
683
686
  zenml/orchestrators/local/local_orchestrator.py,sha256=VCVemtPtW1bXvEM80wgaqdmoXiPrVOTNITXJ2MauTaw,5505
684
687
  zenml/orchestrators/local_docker/__init__.py,sha256=k8J68ydy6HmmvE9tWo32g761H8P_Dw4AxWNf4UMpsbs,669
685
688
  zenml/orchestrators/local_docker/local_docker_orchestrator.py,sha256=kzxvmKwEi7ihXfeoopIUwipSorvpB4Lw2pdCAOcZaZ0,9190
686
- zenml/orchestrators/output_utils.py,sha256=Gz7SX2cbQ3w4eyfU0XuhKEKGtalQGBoc6moDRNVHN8M,3311
689
+ zenml/orchestrators/output_utils.py,sha256=01vqke1ZfmfuLpgxNerF-QL2wA0VPv1zUdvlMw0OwUY,3508
687
690
  zenml/orchestrators/publish_utils.py,sha256=oLvcjCx_WT3_RITB86WNEaUe_qMsPMTD_warAvjS2dA,4752
688
691
  zenml/orchestrators/step_launcher.py,sha256=iSrp6X-fIfuqCBS4zCgHLKlV2P08lFPf7wwBjT69LRA,17922
689
692
  zenml/orchestrators/step_run_utils.py,sha256=N1_Sd8q9i5u-uWqhTH-gssxf-XkF3vbSDMwu1byyCSk,20424
@@ -712,7 +715,7 @@ zenml/service_connectors/__init__.py,sha256=gIBAVUPBZtdO6JtEBCixy9YG4wZRA1mnaxaG
712
715
  zenml/service_connectors/docker_service_connector.py,sha256=_6WPqYCcSUf8JPakipbkJRvaN2ghhY7zCr38WCHG0SI,13218
713
716
  zenml/service_connectors/service_connector.py,sha256=HW8dTE826ZSD1vWQlqQRm8XYq08v7tDZQ8ORnJ5rTcE,55351
714
717
  zenml/service_connectors/service_connector_registry.py,sha256=mCabyKAr7Y6bcAbIFXbir9YrHczDe1ZJ8Bks5bOQouk,9658
715
- zenml/service_connectors/service_connector_utils.py,sha256=JlpfqpjftTjQvUSlamg4eSoaWBhDGips0DnJnNb8lwo,18104
718
+ zenml/service_connectors/service_connector_utils.py,sha256=x_8rxl2yQc8VvvaWYXyxUxVijo7CCdlnod0z-jd-vUk,18056
716
719
  zenml/services/__init__.py,sha256=8aSLtYlX9EVLB1Se1I4dbhZdTqrjNrAfsn1d_RCc_nk,2800
717
720
  zenml/services/container/__init__.py,sha256=dFHcmlXgNXjUaCR18oGQJ19-I_6f3UeAUURHjqldjTs,668
718
721
  zenml/services/container/container_service.py,sha256=DJIK7DD53Q_mgZByM0oeIyAgkrwN12T5E3QCWjubkLs,18383
@@ -736,7 +739,7 @@ zenml/stack/stack_component.py,sha256=4V111uBLpmsPaNffaQS-fLuz163WFEjsmIFzb_lq7i
736
739
  zenml/stack/stack_validator.py,sha256=hWbvvGIeWLj6NwSsF4GCc6RAxAWvxHXTcBZL9nJvcak,3111
737
740
  zenml/stack/utils.py,sha256=qHMFi8SVMSDFeZTFO4KkvaLUbF-l3B0_JZ5SSMxYrwI,6406
738
741
  zenml/stack_deployments/__init__.py,sha256=-7593cQ_ZgRn774Ol-8AKXXQquIU4DSiaThVEr6TfWM,644
739
- zenml/stack_deployments/aws_stack_deployment.py,sha256=_bB0N3meKc0kH3gtysO0sIGp-80AUC44SYRvbqZMNg0,11450
742
+ zenml/stack_deployments/aws_stack_deployment.py,sha256=FnkiSwSMiM9O8KVTQmGfIKjsp5RkOiO-AbOsr7cd3zE,12358
740
743
  zenml/stack_deployments/azure_stack_deployment.py,sha256=E0PhlmC_2Urf_7k1U7EoOHU21CbhY_3jZG0wXO1NcWI,13032
741
744
  zenml/stack_deployments/gcp_stack_deployment.py,sha256=RD9Z0cZicZexUyK2YE0855LHu_VGOrLUnzy-QnrBRnA,12596
742
745
  zenml/stack_deployments/stack_deployment.py,sha256=hrupbDuIfI6YhzHcmxNLsfnS7Qu_Pgv_5didiyv0msk,7572
@@ -754,16 +757,16 @@ zenml/steps/step_invocation.py,sha256=ETfOaV-P4_iXGk9y1-xK54Kfg2QRYaGoj_jTyEYZfb
754
757
  zenml/steps/utils.py,sha256=hEIOhxHp69WO-9YX6sBpZrVLK6fytqvdzhW5p1aB09M,18580
755
758
  zenml/types.py,sha256=LhGWJ4t3nybBk1l9Ox3tqqHbTYSuCqhkRsL5FqO6yf4,1206
756
759
  zenml/utils/__init__.py,sha256=jaMTbjm8tLYkaRoxlZ0Em4ye_ZHOHKgP2goPTTiYGUQ,797
757
- zenml/utils/archivable.py,sha256=vabL1-2G7_-p-0jyKslxbvlad8fyN1ot-DvOJ19jsOA,5275
760
+ zenml/utils/archivable.py,sha256=QuLe1IhyABTrE6Y0hAT3tKjaUCpcze5ffZ_RKoKtJwY,6549
758
761
  zenml/utils/callback_registry.py,sha256=QBWdaraLAxBxi8DKbv9X1SUpTKDhhj-XE0JomB2Ax2Y,2411
759
762
  zenml/utils/code_repository_utils.py,sha256=CobRYMYfP2yNoA0hcu_WRz5oAff_jY95oyLCHz4fDOo,4734
760
- zenml/utils/code_utils.py,sha256=rLRYUAgc9hvrxDc6QooZaVngmzJ_hgjUfQGF8g1n6Wc,11260
763
+ zenml/utils/code_utils.py,sha256=y7_vmqYv_e11xekFjK7Dm4LkFu6SGl73tr2fVxBAK3s,11336
761
764
  zenml/utils/cuda_utils.py,sha256=RR21m__Zs-OnI5n-veFUzWniZjwLSbalHE5QV3jK1Hw,1624
762
765
  zenml/utils/daemon.py,sha256=GZ7Dx6GLHK04SR50wBxpKYmFhxPBfdLWxJiAWzJC6cM,11863
763
766
  zenml/utils/dashboard_utils.py,sha256=JyT-rOsqipazmImXBB-UzCg0GJ3UNzVCFdMcQisInfQ,5379
764
767
  zenml/utils/deprecation_utils.py,sha256=2cyeUeYas2OCcOcUJul2EGKd5zR_0KOjm6fKCshtFm0,6253
765
768
  zenml/utils/dict_utils.py,sha256=i7KAaKrkaWA_cG5IvVfMnr0CwWlBJ7KAsGvP2wxjZI8,2667
766
- zenml/utils/docker_utils.py,sha256=bJSlal3NeyQDvqXPE13X8ZJl7jcXE3LStiVX4IVAo3U,13661
769
+ zenml/utils/docker_utils.py,sha256=QvkKnvIYSKAhW7mErXwSaQ432-q1LAsLjo2YWSXD8Bk,13889
767
770
  zenml/utils/downloaded_repository_context.py,sha256=S660PSSQ3dsNBA0qAj8ap_Thyw1n6x4VDcRWbCMDP2M,1502
768
771
  zenml/utils/enum_utils.py,sha256=0fA0B9v9Wjutuqlu_owUoOit1utIw2UH5J6YHXSqhLU,1368
769
772
  zenml/utils/env_utils.py,sha256=2--2DDUt3gPOvCNVyobBtAciikQ0OEXs5WWp7NvYuKo,5276
@@ -1276,8 +1279,8 @@ zenml/zen_stores/secrets_stores/sql_secrets_store.py,sha256=Bq1djrUP9saoD7vECjS7
1276
1279
  zenml/zen_stores/sql_zen_store.py,sha256=gq7hwCqXuvABUGHoo6J_fOdf4PGuN88BFWE84KK_-UM,408283
1277
1280
  zenml/zen_stores/template_utils.py,sha256=EKYBgmDLTS_PSMWaIO5yvHPLiQvMqHcsAe6NUCrv-i4,9068
1278
1281
  zenml/zen_stores/zen_store_interface.py,sha256=vf2gKBWfUUPtcGZC35oQB6pPNVzWVyQC8nWxVLjfrxM,92692
1279
- zenml_nightly-0.70.0.dev20241203.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1280
- zenml_nightly-0.70.0.dev20241203.dist-info/METADATA,sha256=qZZHNrbpj8dGXfo9ZYuePjmJKt5XXOo3rsZpQKioRSA,21208
1281
- zenml_nightly-0.70.0.dev20241203.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
1282
- zenml_nightly-0.70.0.dev20241203.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1283
- zenml_nightly-0.70.0.dev20241203.dist-info/RECORD,,
1282
+ zenml_nightly-0.70.0.dev20241204.dist-info/LICENSE,sha256=wbnfEnXnafPbqwANHkV6LUsPKOtdpsd-SNw37rogLtc,11359
1283
+ zenml_nightly-0.70.0.dev20241204.dist-info/METADATA,sha256=SsbWnr1H59o25vg7YOc1twHRrEODkGD23akgH9vanYU,21208
1284
+ zenml_nightly-0.70.0.dev20241204.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
1285
+ zenml_nightly-0.70.0.dev20241204.dist-info/entry_points.txt,sha256=QK3ETQE0YswAM2mWypNMOv8TLtr7EjnqAFq1br_jEFE,43
1286
+ zenml_nightly-0.70.0.dev20241204.dist-info/RECORD,,