zenml-nightly 0.68.0.dev20241027__py3-none-any.whl → 0.68.1.dev20241101__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. README.md +17 -11
  2. RELEASE_NOTES.md +9 -0
  3. zenml/VERSION +1 -1
  4. zenml/__init__.py +1 -1
  5. zenml/analytics/context.py +16 -1
  6. zenml/analytics/utils.py +18 -7
  7. zenml/artifacts/utils.py +40 -216
  8. zenml/cli/__init__.py +63 -90
  9. zenml/cli/base.py +3 -3
  10. zenml/cli/login.py +951 -0
  11. zenml/cli/server.py +462 -353
  12. zenml/cli/service_accounts.py +4 -4
  13. zenml/cli/stack.py +77 -2
  14. zenml/cli/stack_components.py +5 -16
  15. zenml/cli/user_management.py +0 -12
  16. zenml/cli/utils.py +24 -77
  17. zenml/client.py +46 -14
  18. zenml/config/compiler.py +1 -0
  19. zenml/config/global_config.py +9 -0
  20. zenml/config/pipeline_configurations.py +2 -1
  21. zenml/config/pipeline_run_configuration.py +2 -1
  22. zenml/constants.py +3 -9
  23. zenml/enums.py +1 -1
  24. zenml/exceptions.py +11 -0
  25. zenml/integrations/github/code_repositories/github_code_repository.py +1 -1
  26. zenml/login/__init__.py +16 -0
  27. zenml/login/credentials.py +346 -0
  28. zenml/login/credentials_store.py +603 -0
  29. zenml/login/pro/__init__.py +16 -0
  30. zenml/login/pro/client.py +496 -0
  31. zenml/login/pro/constants.py +34 -0
  32. zenml/login/pro/models.py +25 -0
  33. zenml/login/pro/organization/__init__.py +14 -0
  34. zenml/login/pro/organization/client.py +79 -0
  35. zenml/login/pro/organization/models.py +32 -0
  36. zenml/login/pro/tenant/__init__.py +14 -0
  37. zenml/login/pro/tenant/client.py +92 -0
  38. zenml/login/pro/tenant/models.py +174 -0
  39. zenml/login/pro/utils.py +121 -0
  40. zenml/{cli → login}/web_login.py +64 -28
  41. zenml/materializers/base_materializer.py +43 -9
  42. zenml/materializers/built_in_materializer.py +1 -1
  43. zenml/metadata/metadata_types.py +49 -0
  44. zenml/model/model.py +0 -38
  45. zenml/models/__init__.py +3 -0
  46. zenml/models/v2/base/base.py +12 -8
  47. zenml/models/v2/base/filter.py +9 -0
  48. zenml/models/v2/core/artifact_version.py +49 -10
  49. zenml/models/v2/core/component.py +54 -19
  50. zenml/models/v2/core/flavor.py +13 -13
  51. zenml/models/v2/core/model.py +3 -1
  52. zenml/models/v2/core/model_version.py +3 -5
  53. zenml/models/v2/core/model_version_artifact.py +3 -1
  54. zenml/models/v2/core/model_version_pipeline_run.py +3 -1
  55. zenml/models/v2/core/pipeline.py +3 -1
  56. zenml/models/v2/core/pipeline_run.py +23 -1
  57. zenml/models/v2/core/run_template.py +3 -1
  58. zenml/models/v2/core/stack.py +7 -3
  59. zenml/models/v2/core/step_run.py +43 -2
  60. zenml/models/v2/misc/auth_models.py +11 -2
  61. zenml/models/v2/misc/server_models.py +2 -0
  62. zenml/orchestrators/base_orchestrator.py +8 -4
  63. zenml/orchestrators/step_launcher.py +1 -0
  64. zenml/orchestrators/step_run_utils.py +10 -2
  65. zenml/orchestrators/step_runner.py +67 -55
  66. zenml/orchestrators/utils.py +45 -22
  67. zenml/pipelines/pipeline_decorator.py +5 -0
  68. zenml/pipelines/pipeline_definition.py +206 -160
  69. zenml/pipelines/run_utils.py +11 -10
  70. zenml/services/local/local_daemon_entrypoint.py +4 -4
  71. zenml/services/service.py +2 -2
  72. zenml/stack/stack.py +2 -6
  73. zenml/stack/stack_component.py +2 -7
  74. zenml/stack/utils.py +26 -14
  75. zenml/steps/base_step.py +8 -2
  76. zenml/steps/step_context.py +0 -3
  77. zenml/steps/step_invocation.py +14 -5
  78. zenml/steps/utils.py +1 -0
  79. zenml/utils/materializer_utils.py +1 -1
  80. zenml/utils/requirements_utils.py +71 -0
  81. zenml/utils/singleton.py +15 -3
  82. zenml/utils/source_utils.py +39 -2
  83. zenml/utils/visualization_utils.py +1 -1
  84. zenml/zen_server/auth.py +44 -39
  85. zenml/zen_server/deploy/__init__.py +7 -7
  86. zenml/zen_server/deploy/base_provider.py +46 -73
  87. zenml/zen_server/deploy/{local → daemon}/__init__.py +3 -3
  88. zenml/zen_server/deploy/{local/local_provider.py → daemon/daemon_provider.py} +44 -63
  89. zenml/zen_server/deploy/{local/local_zen_server.py → daemon/daemon_zen_server.py} +50 -22
  90. zenml/zen_server/deploy/deployer.py +90 -171
  91. zenml/zen_server/deploy/deployment.py +20 -12
  92. zenml/zen_server/deploy/docker/docker_provider.py +9 -28
  93. zenml/zen_server/deploy/docker/docker_zen_server.py +19 -3
  94. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  95. zenml/zen_server/deploy/helm/README.md +2 -2
  96. zenml/zen_server/exceptions.py +11 -0
  97. zenml/zen_server/jwt.py +9 -9
  98. zenml/zen_server/routers/auth_endpoints.py +30 -8
  99. zenml/zen_server/routers/stack_components_endpoints.py +1 -1
  100. zenml/zen_server/routers/workspaces_endpoints.py +1 -1
  101. zenml/zen_server/template_execution/runner_entrypoint_configuration.py +7 -4
  102. zenml/zen_server/template_execution/utils.py +6 -61
  103. zenml/zen_server/utils.py +64 -36
  104. zenml/zen_stores/base_zen_store.py +4 -49
  105. zenml/zen_stores/migrations/versions/0.68.1_release.py +23 -0
  106. zenml/zen_stores/migrations/versions/c22561cbb3a9_add_artifact_unique_constraints.py +86 -0
  107. zenml/zen_stores/rest_zen_store.py +325 -147
  108. zenml/zen_stores/schemas/api_key_schemas.py +9 -4
  109. zenml/zen_stores/schemas/artifact_schemas.py +21 -2
  110. zenml/zen_stores/schemas/artifact_visualization_schemas.py +1 -1
  111. zenml/zen_stores/schemas/component_schemas.py +49 -6
  112. zenml/zen_stores/schemas/device_schemas.py +9 -4
  113. zenml/zen_stores/schemas/flavor_schemas.py +1 -1
  114. zenml/zen_stores/schemas/model_schemas.py +1 -1
  115. zenml/zen_stores/schemas/service_schemas.py +1 -1
  116. zenml/zen_stores/schemas/step_run_schemas.py +1 -1
  117. zenml/zen_stores/schemas/trigger_schemas.py +1 -1
  118. zenml/zen_stores/sql_zen_store.py +393 -140
  119. zenml/zen_stores/template_utils.py +3 -1
  120. {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/METADATA +18 -12
  121. {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/RECORD +124 -107
  122. zenml/api.py +0 -60
  123. {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/LICENSE +0 -0
  124. {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/WHEEL +0 -0
  125. {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/entry_points.txt +0 -0
zenml/zen_server/utils.py CHANGED
@@ -39,13 +39,14 @@ from zenml.constants import (
39
39
  INFO,
40
40
  VERSION_1,
41
41
  )
42
+ from zenml.enums import StoreType
42
43
  from zenml.exceptions import IllegalOperationError, OAuthError
43
44
  from zenml.logger import get_logger
44
45
  from zenml.plugins.plugin_flavor_registry import PluginFlavorRegistry
45
- from zenml.zen_server.deploy.deployment import ServerDeployment
46
- from zenml.zen_server.deploy.local.local_zen_server import (
47
- LocalServerDeploymentConfig,
46
+ from zenml.zen_server.deploy.deployment import (
47
+ LocalServerDeployment,
48
48
  )
49
+ from zenml.zen_server.deploy.exceptions import ServerDeploymentNotFoundError
49
50
  from zenml.zen_server.exceptions import http_exception_from_error
50
51
  from zenml.zen_server.feature_gate.feature_gate_interface import (
51
52
  FeatureGateInterface,
@@ -236,7 +237,7 @@ def server_config() -> ServerConfiguration:
236
237
  return _server_config
237
238
 
238
239
 
239
- def get_local_server() -> Optional["ServerDeployment"]:
240
+ def get_local_server() -> Optional["LocalServerDeployment"]:
240
241
  """Get the active local server.
241
242
 
242
243
  Call this function to retrieve the local server deployed on this machine.
@@ -245,48 +246,75 @@ def get_local_server() -> Optional["ServerDeployment"]:
245
246
  The local server deployment or None, if no local server deployment was
246
247
  found.
247
248
  """
248
- from zenml.zen_server.deploy.deployer import ServerDeployer
249
+ from zenml.zen_server.deploy.deployer import LocalServerDeployer
249
250
 
250
- deployer = ServerDeployer()
251
- servers = deployer.list_servers()
252
- if not servers:
251
+ deployer = LocalServerDeployer()
252
+ try:
253
+ return deployer.get_server()
254
+ except ServerDeploymentNotFoundError:
253
255
  return None
254
256
 
255
- return servers[0]
256
257
 
258
+ def connected_to_local_server() -> bool:
259
+ """Check if the client is connected to a local server.
257
260
 
258
- def get_active_server_details() -> Tuple[str, Optional[int]]:
259
- """Get the URL of the current ZenML Server.
261
+ Returns:
262
+ True if the client is connected to a local server, False otherwise.
263
+ """
264
+ from zenml.zen_server.deploy.deployer import LocalServerDeployer
260
265
 
261
- When multiple servers are present, the following precedence is used to
262
- determine which server to use:
263
- - If the client is connected to a server, that server has precedence.
264
- - If no server is connected, the local server is used, if present.
266
+ deployer = LocalServerDeployer()
267
+ return deployer.is_connected_to_server()
265
268
 
266
- Returns:
267
- The URL and port of the currently active server.
269
+
270
+ def show_dashboard(
271
+ local: bool = False,
272
+ ngrok_token: Optional[str] = None,
273
+ ) -> None:
274
+ """Show the ZenML dashboard.
275
+
276
+ Args:
277
+ local: Whether to show the dashboard for the local server or the
278
+ one for the active server.
279
+ ngrok_token: An ngrok auth token to use for exposing the ZenML
280
+ dashboard on a public domain. Primarily used for accessing the
281
+ dashboard in Colab.
268
282
 
269
283
  Raises:
270
- RuntimeError: If no server is active.
284
+ RuntimeError: If no server is connected.
271
285
  """
272
- # Check for connected servers first
273
- gc = GlobalConfiguration()
274
- if not gc.uses_default_store():
275
- logger.debug("Getting URL of connected server.")
276
- parsed_url = urlparse(gc.store_configuration.url)
277
- return f"{parsed_url.scheme}://{parsed_url.hostname}", parsed_url.port
278
- # Else, check for local servers
279
- server = get_local_server()
280
- if server and server.status and server.status.url:
281
- if isinstance(server.config, LocalServerDeploymentConfig):
282
- return server.status.url, server.config.port
283
- return server.status.url, None
284
-
285
- raise RuntimeError(
286
- "ZenML is not connected to any server right now. Please use "
287
- "`zenml connect` to connect to a server or spin up a new local server "
288
- "via `zenml up`."
289
- )
286
+ from zenml.utils.dashboard_utils import show_dashboard
287
+ from zenml.utils.networking_utils import get_or_create_ngrok_tunnel
288
+
289
+ url: Optional[str] = None
290
+ if not local:
291
+ gc = GlobalConfiguration()
292
+ if gc.store_configuration.type == StoreType.REST:
293
+ url = gc.store_configuration.url
294
+
295
+ if not url:
296
+ # Else, check for local servers
297
+ server = get_local_server()
298
+ if server and server.status and server.status.url:
299
+ url = server.status.url
300
+
301
+ if not url:
302
+ raise RuntimeError(
303
+ "ZenML is not connected to any server right now. Please use "
304
+ "`zenml login` to connect to a server or spin up a new local server "
305
+ "via `zenml login --local`."
306
+ )
307
+
308
+ if ngrok_token:
309
+ parsed_url = urlparse(url)
310
+
311
+ ngrok_url = get_or_create_ngrok_tunnel(
312
+ ngrok_token=ngrok_token, port=parsed_url.port or 80
313
+ )
314
+ logger.debug(f"Tunneling dashboard from {url} to {ngrok_url}.")
315
+ url = ngrok_url
316
+
317
+ show_dashboard(url)
290
318
 
291
319
 
292
320
  F = TypeVar("F", bound=Callable[..., Any])
@@ -24,11 +24,9 @@ from typing import (
24
24
  Type,
25
25
  Union,
26
26
  )
27
- from urllib.parse import urlparse
28
27
  from uuid import UUID
29
28
 
30
29
  from pydantic import BaseModel, ConfigDict, model_validator
31
- from requests import ConnectionError
32
30
 
33
31
  import zenml
34
32
  from zenml.config.global_config import GlobalConfiguration
@@ -39,13 +37,11 @@ from zenml.constants import (
39
37
  DEFAULT_WORKSPACE_NAME,
40
38
  ENV_ZENML_DEFAULT_WORKSPACE_NAME,
41
39
  IS_DEBUG_ENV,
42
- ZENML_PRO_CONNECTION_ISSUES_SUSPENDED_PAUSED_TENANT_HINT,
43
40
  )
44
41
  from zenml.enums import (
45
42
  SecretsStoreType,
46
43
  StoreType,
47
44
  )
48
- from zenml.exceptions import AuthorizationException
49
45
  from zenml.logger import get_logger
50
46
  from zenml.models import (
51
47
  ServerDatabaseType,
@@ -57,9 +53,6 @@ from zenml.models import (
57
53
  WorkspaceResponse,
58
54
  )
59
55
  from zenml.utils.pydantic_utils import before_validator_handler
60
- from zenml.zen_stores.secrets_stores.sql_secrets_store import (
61
- SqlSecretsStoreConfiguration,
62
- )
63
56
  from zenml.zen_stores.zen_store_interface import ZenStoreInterface
64
57
 
65
58
  logger = get_logger(__name__)
@@ -136,51 +129,10 @@ class BaseZenStore(
136
129
  stack and user in the store will be skipped.
137
130
  **kwargs: Additional keyword arguments to pass to the Pydantic
138
131
  constructor.
139
-
140
- Raises:
141
- RuntimeError: If the store cannot be initialized.
142
- AuthorizationException: If the store cannot be initialized due to
143
- authentication errors.
144
132
  """
145
133
  super().__init__(**kwargs)
146
134
 
147
- try:
148
- self._initialize()
149
-
150
- # Handle cases where the ZenML server is not available
151
- except ConnectionError as e:
152
- error_message = (
153
- "Cannot connect to the ZenML database because the ZenML server "
154
- f"at {self.url} is not running."
155
- )
156
- if urlparse(self.url).hostname in ["localhost", "127.0.0.1"]:
157
- recommendation = (
158
- "Please run `zenml down` and `zenml up` to restart the "
159
- "server."
160
- )
161
- else:
162
- recommendation = (
163
- "Please run `zenml disconnect` and `zenml connect --url "
164
- f"{self.url}` to reconnect to the server."
165
- )
166
- raise RuntimeError(f"{error_message}\n{recommendation}") from e
167
-
168
- except AuthorizationException as e:
169
- raise AuthorizationException(
170
- f"Authorization failed for store at '{self.url}'. Please check "
171
- f"your credentials: {str(e)}"
172
- )
173
-
174
- except Exception as e:
175
- zenml_pro_extra = ""
176
- if ".zenml.io" in self.url:
177
- zenml_pro_extra = (
178
- ZENML_PRO_CONNECTION_ISSUES_SUSPENDED_PAUSED_TENANT_HINT
179
- )
180
- raise RuntimeError(
181
- f"Error initializing {self.type.value} store with URL "
182
- f"'{self.url}': {str(e)}" + zenml_pro_extra
183
- ) from e
135
+ self._initialize()
184
136
 
185
137
  if not skip_default_registrations:
186
138
  logger.debug("Initializing database")
@@ -293,6 +245,9 @@ class BaseZenStore(
293
245
  Returns:
294
246
  The default store configuration.
295
247
  """
248
+ from zenml.zen_stores.secrets_stores.sql_secrets_store import (
249
+ SqlSecretsStoreConfiguration,
250
+ )
296
251
  from zenml.zen_stores.sql_zen_store import SqlZenStoreConfiguration
297
252
 
298
253
  config = SqlZenStoreConfiguration(
@@ -0,0 +1,23 @@
1
+ """Release [0.68.1].
2
+
3
+ Revision ID: 0.68.1
4
+ Revises: 0.68.0
5
+ Create Date: 2024-10-28 10:34:17.307663
6
+
7
+ """
8
+
9
+ # revision identifiers, used by Alembic.
10
+ revision = "0.68.1"
11
+ down_revision = "0.68.0"
12
+ branch_labels = None
13
+ depends_on = None
14
+
15
+
16
+ def upgrade() -> None:
17
+ """Upgrade database schema and/or data, creating a new revision."""
18
+ pass
19
+
20
+
21
+ def downgrade() -> None:
22
+ """Downgrade database schema and/or data back to the previous revision."""
23
+ pass
@@ -0,0 +1,86 @@
1
+ """Add artifact unique constraints [c22561cbb3a9].
2
+
3
+ Revision ID: c22561cbb3a9
4
+ Revises: 0.68.1
5
+ Create Date: 2024-10-17 16:41:25.053677
6
+
7
+ """
8
+
9
+ from collections import defaultdict
10
+ from typing import Dict, Set
11
+
12
+ import sqlalchemy as sa
13
+ from alembic import op
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision = "c22561cbb3a9"
17
+ down_revision = "0.68.1"
18
+ branch_labels = None
19
+ depends_on = None
20
+
21
+
22
+ def resolve_duplicate_versions() -> None:
23
+ """Resolve duplicate artifact versions."""
24
+ connection = op.get_bind()
25
+
26
+ meta = sa.MetaData()
27
+ meta.reflect(
28
+ bind=op.get_bind(),
29
+ only=("artifact_version",),
30
+ )
31
+
32
+ artifact_version_table = sa.Table("artifact_version", meta)
33
+ query = sa.select(
34
+ artifact_version_table.c.id,
35
+ artifact_version_table.c.artifact_id,
36
+ artifact_version_table.c.version,
37
+ )
38
+
39
+ versions_per_artifact: Dict[str, Set[str]] = defaultdict(set)
40
+
41
+ for id, artifact_id, version in connection.execute(query).fetchall():
42
+ versions = versions_per_artifact[artifact_id]
43
+ if version in versions:
44
+ for suffix_length in range(4, len(id)):
45
+ new_version = f"{version}-{id[:suffix_length]}"
46
+ if new_version not in versions:
47
+ version = new_version
48
+ break
49
+
50
+ connection.execute(
51
+ sa.update(artifact_version_table)
52
+ .where(artifact_version_table.c.id == id)
53
+ .values(version=version)
54
+ )
55
+
56
+ versions.add(version)
57
+
58
+
59
+ def upgrade() -> None:
60
+ """Upgrade database schema and/or data, creating a new revision."""
61
+ # ### commands auto generated by Alembic - please adjust! ###
62
+ resolve_duplicate_versions()
63
+
64
+ with op.batch_alter_table("artifact", schema=None) as batch_op:
65
+ batch_op.create_unique_constraint("unique_artifact_name", ["name"])
66
+
67
+ with op.batch_alter_table("artifact_version", schema=None) as batch_op:
68
+ batch_op.create_unique_constraint(
69
+ "unique_version_for_artifact_id", ["version", "artifact_id"]
70
+ )
71
+
72
+ # ### end Alembic commands ###
73
+
74
+
75
+ def downgrade() -> None:
76
+ """Downgrade database schema and/or data back to the previous revision."""
77
+ # ### commands auto generated by Alembic - please adjust! ###
78
+ with op.batch_alter_table("artifact_version", schema=None) as batch_op:
79
+ batch_op.drop_constraint(
80
+ "unique_version_for_artifact_id", type_="unique"
81
+ )
82
+
83
+ with op.batch_alter_table("artifact", schema=None) as batch_op:
84
+ batch_op.drop_constraint("unique_artifact_name", type_="unique")
85
+
86
+ # ### end Alembic commands ###