zenml-nightly 0.83.1.dev20250624__py3-none-any.whl → 0.83.1.dev20250626__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 (54) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/base.py +3 -2
  3. zenml/cli/login.py +21 -3
  4. zenml/cli/service_connectors.py +5 -12
  5. zenml/cli/stack.py +1 -5
  6. zenml/cli/utils.py +8 -52
  7. zenml/client.py +32 -40
  8. zenml/config/__init__.py +13 -2
  9. zenml/constants.py +0 -1
  10. zenml/exceptions.py +16 -0
  11. zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +15 -6
  12. zenml/integrations/aws/container_registries/aws_container_registry.py +3 -1
  13. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +54 -58
  14. zenml/integrations/azure/orchestrators/azureml_orchestrator.py +28 -19
  15. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +19 -63
  16. zenml/integrations/databricks/orchestrators/databricks_orchestrator_entrypoint_config.py +8 -3
  17. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +36 -61
  18. zenml/integrations/hyperai/orchestrators/hyperai_orchestrator.py +19 -22
  19. zenml/integrations/integration.py +23 -58
  20. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +28 -31
  21. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +33 -20
  22. zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +25 -100
  23. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +19 -8
  24. zenml/integrations/skypilot/utils.py +17 -13
  25. zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +28 -12
  26. zenml/models/__init__.py +2 -0
  27. zenml/models/v2/core/service_connector.py +178 -108
  28. zenml/models/v2/core/step_run.py +1 -0
  29. zenml/orchestrators/__init__.py +2 -0
  30. zenml/orchestrators/base_orchestrator.py +137 -66
  31. zenml/orchestrators/input_utils.py +5 -13
  32. zenml/orchestrators/local/local_orchestrator.py +19 -9
  33. zenml/orchestrators/local_docker/local_docker_orchestrator.py +15 -5
  34. zenml/orchestrators/publish_utils.py +24 -0
  35. zenml/orchestrators/step_run_utils.py +1 -2
  36. zenml/pipelines/run_utils.py +12 -7
  37. zenml/service_connectors/service_connector.py +11 -61
  38. zenml/service_connectors/service_connector_utils.py +4 -2
  39. zenml/step_operators/step_operator_entrypoint_configuration.py +1 -1
  40. zenml/utils/package_utils.py +111 -1
  41. zenml/zen_server/routers/service_connectors_endpoints.py +7 -22
  42. zenml/zen_stores/migrations/versions/5bb25e95849c_add_internal_secrets.py +62 -0
  43. zenml/zen_stores/rest_zen_store.py +204 -132
  44. zenml/zen_stores/schemas/secret_schemas.py +5 -0
  45. zenml/zen_stores/schemas/service_connector_schemas.py +16 -14
  46. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +4 -1
  47. zenml/zen_stores/sql_zen_store.py +241 -119
  48. zenml/zen_stores/zen_store_interface.py +9 -1
  49. {zenml_nightly-0.83.1.dev20250624.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/METADATA +1 -1
  50. {zenml_nightly-0.83.1.dev20250624.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/RECORD +53 -53
  51. zenml/utils/integration_utils.py +0 -34
  52. {zenml_nightly-0.83.1.dev20250624.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/LICENSE +0 -0
  53. {zenml_nightly-0.83.1.dev20250624.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/WHEEL +0 -0
  54. {zenml_nightly-0.83.1.dev20250624.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/entry_points.txt +0 -0
@@ -13,10 +13,26 @@
13
13
  # permissions and limitations under the License.
14
14
  """Utility functions for the package."""
15
15
 
16
- from typing import List
16
+ import sys
17
+ from typing import Dict, List, Optional, Union, cast
17
18
 
18
19
  import requests
19
20
  from packaging import version
21
+ from packaging.markers import default_environment
22
+ from packaging.requirements import Requirement
23
+
24
+ if sys.version_info < (3, 10):
25
+ from importlib_metadata import (
26
+ PackageNotFoundError,
27
+ distribution,
28
+ distributions,
29
+ )
30
+ else:
31
+ from importlib.metadata import (
32
+ PackageNotFoundError,
33
+ distribution,
34
+ distributions,
35
+ )
20
36
 
21
37
 
22
38
  def is_latest_zenml_version() -> bool:
@@ -87,3 +103,97 @@ def clean_requirements(requirements: List[str]) -> List[str]:
87
103
  ):
88
104
  cleaned[package] = req
89
105
  return sorted(cleaned.values())
106
+
107
+
108
+ def requirement_installed(requirement: Union[str, Requirement]) -> bool:
109
+ """Check if a requirement is installed.
110
+
111
+ Args:
112
+ requirement: A requirement string.
113
+
114
+ Returns:
115
+ True if the requirement is installed, False otherwise.
116
+ """
117
+ if isinstance(requirement, str):
118
+ requirement = Requirement(requirement)
119
+
120
+ try:
121
+ dist = distribution(requirement.name)
122
+ except PackageNotFoundError:
123
+ return False
124
+
125
+ return requirement.specifier.contains(dist.version)
126
+
127
+
128
+ def get_dependencies(
129
+ requirement: Requirement, recursive: bool = False
130
+ ) -> List[Requirement]:
131
+ """Get the dependencies of a requirement.
132
+
133
+ Args:
134
+ requirement: A requirement string.
135
+ recursive: Whether to include recursive dependencies.
136
+
137
+ Returns:
138
+ A list of requirements.
139
+ """
140
+ dist = distribution(requirement.name)
141
+ marker_environment = cast(Dict[str, str], default_environment())
142
+
143
+ dependencies = []
144
+
145
+ for req in dist.requires or []:
146
+ parsed_req = Requirement(req)
147
+
148
+ if parsed_req.marker:
149
+ should_include = False
150
+
151
+ marker_environment["extra"] = ""
152
+ if parsed_req.marker.evaluate(environment=marker_environment):
153
+ should_include = True
154
+
155
+ if not should_include:
156
+ # Not required without extras, so check if it's required with
157
+ # any of the requested extras
158
+ for extra in requirement.extras:
159
+ marker_environment["extra"] = extra
160
+ if parsed_req.marker.evaluate(
161
+ environment=marker_environment
162
+ ):
163
+ should_include = True
164
+ break
165
+
166
+ if should_include:
167
+ dependencies.append(parsed_req)
168
+ else:
169
+ # No marker means always include
170
+ dependencies.append(parsed_req)
171
+
172
+ if recursive:
173
+ for dependency in dependencies:
174
+ dependencies.extend(get_dependencies(dependency, recursive=True))
175
+
176
+ return dependencies
177
+
178
+
179
+ def get_package_information(
180
+ package_names: Optional[List[str]] = None,
181
+ ) -> Dict[str, str]:
182
+ """Get package information.
183
+
184
+ Args:
185
+ package_names: Filter for specific package names. If no package names
186
+ are provided, all installed packages are returned.
187
+
188
+ Returns:
189
+ A dictionary of the name:version for the package names passed in or
190
+ all packages and their respective versions.
191
+ """
192
+ if package_names:
193
+ return {
194
+ dist.name: dist.version
195
+ for dist in distributions()
196
+ if dist.name in package_names
197
+ }
198
+
199
+ return {dist.name: dist.version for dist in distributions()}
@@ -152,6 +152,7 @@ def list_service_connectors(
152
152
  resource_type=ResourceType.SERVICE_CONNECTOR,
153
153
  list_method=zen_store().list_service_connectors,
154
154
  hydrate=hydrate,
155
+ expand_secrets=expand_secrets,
155
156
  )
156
157
 
157
158
  if expand_secrets:
@@ -163,9 +164,6 @@ def list_service_connectors(
163
164
  )
164
165
 
165
166
  for connector in connectors.items:
166
- if not connector.secret_id:
167
- continue
168
-
169
167
  if allowed_ids is None or is_owned_by_authenticated_user(
170
168
  connector
171
169
  ):
@@ -174,14 +172,8 @@ def list_service_connectors(
174
172
  pass
175
173
  elif connector.id not in allowed_ids:
176
174
  # The user is not allowed to read secret values for this
177
- # connector. We don't raise an exception here but don't include
178
- # the secret values
179
- continue
180
-
181
- secret = zen_store().get_secret(secret_id=connector.secret_id)
182
-
183
- # Update the connector configuration with the secret.
184
- connector.configuration.update(secret.secret_values)
175
+ # connector. We remove the secrets from the connector.
176
+ connector.remove_secrets()
185
177
 
186
178
  return connectors
187
179
 
@@ -253,21 +245,14 @@ def get_service_connector(
253
245
  The requested service connector.
254
246
  """
255
247
  connector = zen_store().get_service_connector(
256
- connector_id, hydrate=hydrate
248
+ connector_id, hydrate=hydrate, expand_secrets=expand_secrets
257
249
  )
258
250
  verify_permission_for_model(connector, action=Action.READ)
259
251
 
260
- if (
261
- expand_secrets
262
- and connector.secret_id
263
- and has_permissions_for_model(
264
- connector, action=Action.READ_SECRET_VALUE
265
- )
252
+ if expand_secrets and not has_permissions_for_model(
253
+ connector, action=Action.READ_SECRET_VALUE
266
254
  ):
267
- secret = zen_store().get_secret(secret_id=connector.secret_id)
268
-
269
- # Update the connector configuration with the secret.
270
- connector.configuration.update(secret.secret_values)
255
+ connector.remove_secrets()
271
256
 
272
257
  return dehydrate_response_model(connector)
273
258
 
@@ -0,0 +1,62 @@
1
+ """add internal secrets [5bb25e95849c].
2
+
3
+ Revision ID: 5bb25e95849c
4
+ Revises: 0.83.1
5
+ Create Date: 2025-06-23 20:49:44.184630
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "5bb25e95849c"
14
+ down_revision = "0.83.1"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ """Upgrade database schema and/or data, creating a new revision."""
21
+ # Step 1: Add internal column as nullable
22
+ with op.batch_alter_table("secret", schema=None) as batch_op:
23
+ batch_op.add_column(sa.Column("internal", sa.Boolean(), nullable=True))
24
+
25
+ # Step 2: Update existing records based on service connector references
26
+ # If a secret is referenced by a service_connector.secret_id, make it internal=True
27
+ # Otherwise, set it to internal=False
28
+ connection = op.get_bind()
29
+
30
+ # Update secrets that are referenced by service connectors to be internal
31
+ connection.execute(
32
+ sa.text("""
33
+ UPDATE secret
34
+ SET internal = TRUE
35
+ WHERE id IN (
36
+ SELECT DISTINCT secret_id
37
+ FROM service_connector
38
+ WHERE secret_id IS NOT NULL
39
+ );
40
+ """)
41
+ )
42
+
43
+ # Update all other secrets to be not internal
44
+ connection.execute(
45
+ sa.text("""
46
+ UPDATE secret
47
+ SET internal = FALSE
48
+ WHERE internal IS NULL;
49
+ """)
50
+ )
51
+
52
+ # Step 3: Make internal column non-nullable
53
+ with op.batch_alter_table("secret", schema=None) as batch_op:
54
+ batch_op.alter_column(
55
+ "internal", existing_type=sa.Boolean(), nullable=False
56
+ )
57
+
58
+
59
+ def downgrade() -> None:
60
+ """Downgrade database schema and/or data back to the previous revision."""
61
+ with op.batch_alter_table("secret", schema=None) as batch_op:
62
+ batch_op.drop_column("internal")