wandb 0.19.10__py3-none-win_amd64.whl → 0.19.11__py3-none-win_amd64.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.
- wandb/__init__.py +1 -1
- wandb/__init__.pyi +3 -3
- wandb/_pydantic/__init__.py +2 -3
- wandb/_pydantic/base.py +11 -31
- wandb/_pydantic/utils.py +8 -1
- wandb/_pydantic/v1_compat.py +3 -3
- wandb/apis/public/api.py +590 -22
- wandb/apis/public/artifacts.py +13 -5
- wandb/apis/public/automations.py +1 -1
- wandb/apis/public/integrations.py +22 -10
- wandb/apis/public/registries/__init__.py +0 -0
- wandb/apis/public/registries/_freezable_list.py +179 -0
- wandb/apis/public/{registries.py → registries/registries_search.py} +22 -129
- wandb/apis/public/registries/registry.py +357 -0
- wandb/apis/public/registries/utils.py +140 -0
- wandb/apis/public/runs.py +58 -56
- wandb/automations/__init__.py +16 -24
- wandb/automations/_filters/expressions.py +12 -10
- wandb/automations/_filters/operators.py +10 -19
- wandb/automations/_filters/run_metrics.py +231 -82
- wandb/automations/_generated/__init__.py +27 -34
- wandb/automations/_generated/create_automation.py +17 -0
- wandb/automations/_generated/delete_automation.py +17 -0
- wandb/automations/_generated/fragments.py +40 -25
- wandb/automations/_generated/{get_triggers.py → get_automations.py} +5 -5
- wandb/automations/_generated/get_automations_by_entity.py +26 -0
- wandb/automations/_generated/operations.py +35 -98
- wandb/automations/_generated/update_automation.py +17 -0
- wandb/automations/_utils.py +178 -64
- wandb/automations/_validators.py +94 -2
- wandb/automations/actions.py +113 -98
- wandb/automations/automations.py +47 -69
- wandb/automations/events.py +139 -87
- wandb/automations/integrations.py +23 -4
- wandb/automations/scopes.py +22 -20
- wandb/bin/gpu_stats.exe +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/env.py +11 -0
- wandb/old/settings.py +4 -1
- wandb/proto/v3/wandb_internal_pb2.py +240 -236
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_internal_pb2.py +236 -236
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v5/wandb_internal_pb2.py +236 -236
- wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v6/wandb_internal_pb2.py +236 -236
- wandb/proto/v6/wandb_telemetry_pb2.py +10 -10
- wandb/sdk/artifacts/_generated/__init__.py +42 -1
- wandb/sdk/artifacts/_generated/add_aliases.py +21 -0
- wandb/sdk/artifacts/_generated/delete_aliases.py +21 -0
- wandb/sdk/artifacts/_generated/fetch_linked_artifacts.py +67 -0
- wandb/sdk/artifacts/_generated/fragments.py +35 -0
- wandb/sdk/artifacts/_generated/input_types.py +12 -0
- wandb/sdk/artifacts/_generated/operations.py +101 -0
- wandb/sdk/artifacts/_generated/update_artifact.py +26 -0
- wandb/sdk/artifacts/_graphql_fragments.py +1 -0
- wandb/sdk/artifacts/_validators.py +120 -1
- wandb/sdk/artifacts/artifact.py +380 -203
- wandb/sdk/artifacts/artifact_file_cache.py +4 -6
- wandb/sdk/artifacts/artifact_manifest_entry.py +11 -2
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +182 -1
- wandb/sdk/artifacts/storage_policy.py +3 -0
- wandb/sdk/data_types/video.py +46 -32
- wandb/sdk/interface/interface.py +2 -3
- wandb/sdk/internal/internal_api.py +21 -31
- wandb/sdk/internal/sender.py +5 -2
- wandb/sdk/launch/sweeps/utils.py +8 -0
- wandb/sdk/projects/_generated/__init__.py +47 -0
- wandb/sdk/projects/_generated/delete_project.py +22 -0
- wandb/sdk/projects/_generated/enums.py +4 -0
- wandb/sdk/projects/_generated/fetch_registry.py +22 -0
- wandb/sdk/projects/_generated/fragments.py +41 -0
- wandb/sdk/projects/_generated/input_types.py +13 -0
- wandb/sdk/projects/_generated/operations.py +88 -0
- wandb/sdk/projects/_generated/rename_project.py +27 -0
- wandb/sdk/projects/_generated/upsert_registry_project.py +27 -0
- wandb/sdk/service/service.py +9 -1
- wandb/sdk/wandb_init.py +32 -5
- wandb/sdk/wandb_run.py +37 -9
- wandb/sdk/wandb_settings.py +6 -7
- wandb/sdk/wandb_setup.py +12 -0
- wandb/util.py +7 -3
- {wandb-0.19.10.dist-info → wandb-0.19.11.dist-info}/METADATA +1 -1
- {wandb-0.19.10.dist-info → wandb-0.19.11.dist-info}/RECORD +87 -70
- wandb/automations/_generated/create_filter_trigger.py +0 -21
- wandb/automations/_generated/delete_trigger.py +0 -19
- wandb/automations/_generated/get_triggers_by_entity.py +0 -24
- wandb/automations/_generated/update_filter_trigger.py +0 -21
- {wandb-0.19.10.dist-info → wandb-0.19.11.dist-info}/WHEEL +0 -0
- {wandb-0.19.10.dist-info → wandb-0.19.11.dist-info}/entry_points.txt +0 -0
- {wandb-0.19.10.dist-info → wandb-0.19.11.dist-info}/licenses/LICENSE +0 -0
wandb/automations/actions.py
CHANGED
@@ -4,17 +4,12 @@
|
|
4
4
|
|
5
5
|
from __future__ import annotations
|
6
6
|
|
7
|
-
from typing import Any,
|
7
|
+
from typing import Any, Literal, Optional, Union
|
8
8
|
|
9
|
-
from pydantic import Field
|
10
|
-
from typing_extensions import
|
9
|
+
from pydantic import BeforeValidator, Field
|
10
|
+
from typing_extensions import Annotated, Self, get_args
|
11
11
|
|
12
|
-
from wandb._pydantic import
|
13
|
-
SerializedToJson,
|
14
|
-
field_validator,
|
15
|
-
model_validator,
|
16
|
-
pydantic_isinstance,
|
17
|
-
)
|
12
|
+
from wandb._pydantic import GQLBase, GQLId, SerializedToJson, Typename
|
18
13
|
|
19
14
|
from ._generated import (
|
20
15
|
AlertSeverity,
|
@@ -25,26 +20,25 @@ from ._generated import (
|
|
25
20
|
NotificationActionFields,
|
26
21
|
NotificationActionInput,
|
27
22
|
QueueJobActionFields,
|
28
|
-
|
23
|
+
)
|
24
|
+
from ._validators import (
|
25
|
+
LenientStrEnum,
|
26
|
+
default_if_none,
|
27
|
+
to_input_action,
|
28
|
+
to_saved_action,
|
29
|
+
upper_if_str,
|
29
30
|
)
|
30
31
|
from .integrations import SlackIntegration, WebhookIntegration
|
31
32
|
|
32
|
-
# Note: Pydantic doesn't like `list['JsonValue']` or `dict[str, 'JsonValue']`,
|
33
|
-
# which causes a RecursionError.
|
34
|
-
JsonValue: TypeAlias = Union[
|
35
|
-
List[Any],
|
36
|
-
Dict[str, Any],
|
37
|
-
# NOTE: For now, we're not expecting any doubly-serialized strings, as this makes validation logic easier, but revisit and revise if needed.
|
38
|
-
# str,
|
39
|
-
bool,
|
40
|
-
int,
|
41
|
-
float,
|
42
|
-
None,
|
43
|
-
]
|
44
33
|
|
45
34
|
# NOTE: Name shortened for readability and defined publicly for easier access
|
46
|
-
ActionType
|
47
|
-
"""The type of action triggered by an automation."""
|
35
|
+
class ActionType(LenientStrEnum):
|
36
|
+
"""The type of action triggered by an automation."""
|
37
|
+
|
38
|
+
QUEUE_JOB = "QUEUE_JOB" # NOTE: Deprecated for creation
|
39
|
+
NOTIFICATION = "NOTIFICATION"
|
40
|
+
GENERIC_WEBHOOK = "GENERIC_WEBHOOK"
|
41
|
+
NO_OP = "NO_OP"
|
48
42
|
|
49
43
|
|
50
44
|
# ------------------------------------------------------------------------------
|
@@ -58,69 +52,99 @@ class SavedLaunchJobAction(QueueJobActionFields):
|
|
58
52
|
action_type: Literal[ActionType.QUEUE_JOB] = ActionType.QUEUE_JOB
|
59
53
|
|
60
54
|
|
55
|
+
# FIXME: Find a better place to put these OR a better way to handle the
|
56
|
+
# conversion from `InputAction` -> `SavedAction`.
|
57
|
+
#
|
58
|
+
# Necessary placeholder class defs for converting:
|
59
|
+
# - `SendNotification -> SavedNotificationAction`
|
60
|
+
# - `SendWebhook -> SavedWebhookAction`
|
61
|
+
#
|
62
|
+
# The "input" types (`Send{Notification,Webhook}`) will only have an `integration_id`,
|
63
|
+
# and we don't want/need to fetch the other `{Slack,Webhook}Integration` fields if
|
64
|
+
# we can avoid it.
|
65
|
+
class _SavedActionSlackIntegration(GQLBase, extra="allow"):
|
66
|
+
typename__: Typename[Literal["SlackIntegration"]] = "SlackIntegration"
|
67
|
+
id: GQLId
|
68
|
+
|
69
|
+
|
70
|
+
class _SavedActionWebhookIntegration(GQLBase, extra="allow"):
|
71
|
+
typename__: Typename[Literal["GenericWebhookIntegration"]] = (
|
72
|
+
"GenericWebhookIntegration"
|
73
|
+
)
|
74
|
+
id: GQLId
|
75
|
+
|
76
|
+
|
61
77
|
class SavedNotificationAction(NotificationActionFields):
|
62
78
|
action_type: Literal[ActionType.NOTIFICATION] = ActionType.NOTIFICATION
|
79
|
+
integration: _SavedActionSlackIntegration
|
63
80
|
|
64
81
|
|
65
82
|
class SavedWebhookAction(GenericWebhookActionFields):
|
66
83
|
action_type: Literal[ActionType.GENERIC_WEBHOOK] = ActionType.GENERIC_WEBHOOK
|
84
|
+
integration: _SavedActionWebhookIntegration
|
67
85
|
|
68
86
|
# We override the type of the `requestPayload` field since the original GraphQL
|
69
87
|
# schema (and generated class) effectively defines it as a string, when we know
|
70
88
|
# and need to anticipate the expected structure of the JSON-serialized data.
|
71
|
-
request_payload:
|
72
|
-
|
73
|
-
|
89
|
+
request_payload: Annotated[
|
90
|
+
Optional[SerializedToJson[dict[str, Any]]],
|
91
|
+
Field(alias="requestPayload"),
|
92
|
+
] = None # type: ignore[assignment]
|
74
93
|
|
75
94
|
|
76
|
-
class SavedNoOpAction(NoOpActionFields):
|
95
|
+
class SavedNoOpAction(NoOpActionFields, frozen=True):
|
77
96
|
action_type: Literal[ActionType.NO_OP] = ActionType.NO_OP
|
78
97
|
|
98
|
+
no_op: Annotated[bool, BeforeValidator(default_if_none)] = True
|
99
|
+
"""Placeholder field, only needed to conform to schema requirements.
|
100
|
+
|
101
|
+
There should never be a need to set this field explicitly, as its value is ignored.
|
102
|
+
"""
|
103
|
+
|
79
104
|
|
80
105
|
# for type annotations
|
81
|
-
SavedAction =
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
106
|
+
SavedAction = Annotated[
|
107
|
+
Union[
|
108
|
+
SavedLaunchJobAction,
|
109
|
+
SavedNotificationAction,
|
110
|
+
SavedWebhookAction,
|
111
|
+
SavedNoOpAction,
|
112
|
+
],
|
113
|
+
BeforeValidator(to_saved_action),
|
114
|
+
Field(discriminator="typename__"),
|
86
115
|
]
|
87
116
|
# for runtime type checks
|
88
|
-
SavedActionTypes: tuple[type, ...] = get_args(SavedAction)
|
117
|
+
SavedActionTypes: tuple[type, ...] = get_args(SavedAction.__origin__) # type: ignore[attr-defined]
|
89
118
|
|
90
119
|
|
91
120
|
# ------------------------------------------------------------------------------
|
92
121
|
# Input types: for creating or updating automations
|
93
|
-
class
|
94
|
-
|
122
|
+
class _BaseActionInput(GQLBase):
|
123
|
+
action_type: Annotated[ActionType, Field(frozen=True)]
|
124
|
+
"""The kind of action to be triggered."""
|
125
|
+
|
126
|
+
|
127
|
+
class SendNotification(_BaseActionInput, NotificationActionInput):
|
128
|
+
"""Defines an automation action that sends a (Slack) notification."""
|
95
129
|
|
96
130
|
action_type: Literal[ActionType.NOTIFICATION] = ActionType.NOTIFICATION
|
97
131
|
|
98
|
-
|
99
|
-
|
100
|
-
title: str = Field(default="", validation_alias="title")
|
101
|
-
message: str = Field(default="", validation_alias="text")
|
102
|
-
severity: AlertSeverity = Field(
|
103
|
-
default=AlertSeverity.INFO, validation_alias="level"
|
104
|
-
)
|
132
|
+
integration_id: GQLId
|
133
|
+
"""The ID of the Slack integration that will be used to send the notification."""
|
105
134
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
# Be helpful by accepting case-insensitive strings
|
110
|
-
return v.upper() if isinstance(v, str) else v
|
135
|
+
# Note: Validation aliases are meant to provide continuity with prior `wandb.alert()` API.
|
136
|
+
title: str = ""
|
137
|
+
"""The title of the sent notification."""
|
111
138
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
severity=v.severity,
|
122
|
-
)
|
123
|
-
return v
|
139
|
+
message: Annotated[str, Field(validation_alias="text")] = ""
|
140
|
+
"""The message body of the sent notification."""
|
141
|
+
|
142
|
+
severity: Annotated[
|
143
|
+
AlertSeverity,
|
144
|
+
BeforeValidator(upper_if_str), # Be helpful by ensuring uppercase strings
|
145
|
+
Field(validation_alias="level"),
|
146
|
+
] = AlertSeverity.INFO
|
147
|
+
"""The severity (`INFO`, `WARN`, `ERROR`) of the sent notification."""
|
124
148
|
|
125
149
|
@classmethod
|
126
150
|
def from_integration(
|
@@ -132,7 +156,6 @@ class DoNotification(NotificationActionInput):
|
|
132
156
|
level: AlertSeverity = AlertSeverity.INFO,
|
133
157
|
) -> Self:
|
134
158
|
"""Define a notification action that sends to the given (Slack) integration."""
|
135
|
-
integration = SlackIntegration.model_validate(integration)
|
136
159
|
return cls(
|
137
160
|
integration_id=integration.id,
|
138
161
|
title=title,
|
@@ -141,65 +164,57 @@ class DoNotification(NotificationActionInput):
|
|
141
164
|
)
|
142
165
|
|
143
166
|
|
144
|
-
class
|
145
|
-
"""
|
167
|
+
class SendWebhook(_BaseActionInput, GenericWebhookActionInput):
|
168
|
+
"""Defines an automation action that sends a webhook request."""
|
146
169
|
|
147
170
|
action_type: Literal[ActionType.GENERIC_WEBHOOK] = ActionType.GENERIC_WEBHOOK
|
148
171
|
|
172
|
+
integration_id: GQLId
|
173
|
+
"""The ID of the webhook integration that will be used to send the request."""
|
174
|
+
|
149
175
|
# overrides the generated field type to parse/serialize JSON strings
|
150
|
-
request_payload: Optional[SerializedToJson[
|
176
|
+
request_payload: Optional[SerializedToJson[dict[str, Any]]] = Field( # type: ignore[assignment]
|
151
177
|
default=None, alias="requestPayload"
|
152
178
|
)
|
153
|
-
|
154
|
-
@model_validator(mode="before")
|
155
|
-
@classmethod
|
156
|
-
def _from_saved(cls, v: Any) -> Any:
|
157
|
-
"""Convert an action on a saved automation to a new/input action."""
|
158
|
-
if pydantic_isinstance(v, SavedWebhookAction):
|
159
|
-
return cls(
|
160
|
-
integration_id=v.integration.id,
|
161
|
-
request_payload=v.request_payload,
|
162
|
-
)
|
163
|
-
return v
|
179
|
+
"""The payload, possibly with template variables, to send in the webhook request."""
|
164
180
|
|
165
181
|
@classmethod
|
166
182
|
def from_integration(
|
167
183
|
cls,
|
168
184
|
integration: WebhookIntegration,
|
169
185
|
*,
|
170
|
-
|
186
|
+
payload: Optional[SerializedToJson[dict[str, Any]]] = None,
|
171
187
|
) -> Self:
|
172
188
|
"""Define a webhook action that sends to the given (webhook) integration."""
|
173
|
-
integration =
|
174
|
-
return cls(integration_id=integration.id, request_payload=request_payload)
|
189
|
+
return cls(integration_id=integration.id, request_payload=payload)
|
175
190
|
|
176
191
|
|
177
|
-
class DoNothing(NoOpTriggeredActionInput):
|
178
|
-
"""
|
192
|
+
class DoNothing(_BaseActionInput, NoOpTriggeredActionInput, frozen=True):
|
193
|
+
"""Defines an automation action that intentionally does nothing."""
|
179
194
|
|
180
195
|
action_type: Literal[ActionType.NO_OP] = ActionType.NO_OP
|
181
196
|
|
182
|
-
no_op: bool = True
|
183
|
-
|
184
|
-
@field_validator("no_op", mode="before")
|
185
|
-
@classmethod
|
186
|
-
def _ensure_nonnull(cls, v: Any) -> Any:
|
187
|
-
# Ensuring the value isn't None complies with validation and
|
188
|
-
# prevents the field (and action data) from getting excluded on
|
189
|
-
# `.model_dump(exclude_none=True)`
|
190
|
-
return True if (v is None) else v
|
191
|
-
|
197
|
+
no_op: Annotated[bool, BeforeValidator(default_if_none)] = True
|
198
|
+
"""Placeholder field which exists only to satisfy backend schema requirements.
|
192
199
|
|
193
|
-
|
194
|
-
|
195
|
-
DoNothing.model_rebuild()
|
200
|
+
There should never be a need to set this field explicitly, as its value is ignored.
|
201
|
+
"""
|
196
202
|
|
197
203
|
|
198
204
|
# for type annotations
|
199
|
-
InputAction =
|
200
|
-
|
201
|
-
|
202
|
-
|
205
|
+
InputAction = Annotated[
|
206
|
+
Union[
|
207
|
+
SendNotification,
|
208
|
+
SendWebhook,
|
209
|
+
DoNothing,
|
210
|
+
],
|
211
|
+
BeforeValidator(to_input_action),
|
212
|
+
Field(discriminator="action_type"),
|
203
213
|
]
|
204
214
|
# for runtime type checks
|
205
|
-
InputActionTypes: tuple[type, ...] = get_args(InputAction)
|
215
|
+
InputActionTypes: tuple[type, ...] = get_args(InputAction.__origin__) # type: ignore[attr-defined]
|
216
|
+
|
217
|
+
__all__ = [
|
218
|
+
"ActionType",
|
219
|
+
*(cls.__name__ for cls in InputActionTypes),
|
220
|
+
]
|
wandb/automations/automations.py
CHANGED
@@ -3,19 +3,17 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
from datetime import datetime
|
6
|
-
from typing import
|
6
|
+
from typing import Optional
|
7
7
|
|
8
8
|
from pydantic import Field
|
9
|
+
from typing_extensions import Annotated
|
9
10
|
|
10
|
-
from wandb._pydantic import
|
11
|
+
from wandb._pydantic import GQLBase, GQLId
|
11
12
|
|
12
|
-
from ._generated import TriggerFields
|
13
|
+
from ._generated import TriggerFields
|
13
14
|
from .actions import InputAction, SavedAction
|
14
15
|
from .events import InputEvent, SavedEvent
|
15
|
-
from .scopes import
|
16
|
-
|
17
|
-
if TYPE_CHECKING:
|
18
|
-
pass
|
16
|
+
from .scopes import AutomationScope
|
19
17
|
|
20
18
|
|
21
19
|
# ------------------------------------------------------------------------------
|
@@ -25,85 +23,65 @@ class Automation(TriggerFields):
|
|
25
23
|
|
26
24
|
id: GQLId
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
created_at: Annotated[datetime, Field(repr=False, frozen=True, alias="createdAt")]
|
27
|
+
"""The date and time when this automation was created."""
|
28
|
+
|
29
|
+
updated_at: Annotated[
|
30
|
+
Optional[datetime], Field(repr=False, frozen=True, alias="updatedAt")
|
31
|
+
] = None
|
32
|
+
"""The date and time when this automation was last updated, if applicable."""
|
31
33
|
|
32
34
|
name: str
|
33
|
-
|
35
|
+
"""The name of this automation."""
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
action: SavedAction = Field(discriminator="typename__", alias="triggeredAction")
|
37
|
+
description: Optional[str]
|
38
|
+
"""An optional description of this automation."""
|
38
39
|
|
39
40
|
enabled: bool
|
41
|
+
"""Whether this automation is enabled. Only enabled automations will trigger."""
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
# ) -> Automation:
|
44
|
-
# """Save this existing automation to the server, applying any local changes.
|
45
|
-
|
46
|
-
# Args:
|
47
|
-
# api: The API instance to use. If not provided, the default API instance is used.
|
48
|
-
# updates:
|
49
|
-
# Any final updates to apply to the automation before
|
50
|
-
# saving it. These override previously-set values, if any.
|
51
|
-
|
52
|
-
# Returns:
|
53
|
-
# The updated automation.
|
54
|
-
# """
|
55
|
-
# from wandb import Api
|
56
|
-
|
57
|
-
# return (api or Api()).update_automation(self, **updates)
|
58
|
-
|
59
|
-
# def delete(self, api: Api | None = None) -> DeleteTriggerResult:
|
60
|
-
# """Delete this automation from the server.
|
43
|
+
event: SavedEvent
|
44
|
+
"""The event that will trigger this automation."""
|
61
45
|
|
62
|
-
|
63
|
-
|
64
|
-
# """
|
65
|
-
# from wandb import Api
|
46
|
+
scope: AutomationScope
|
47
|
+
"""The scope in which the triggering event must occur."""
|
66
48
|
|
67
|
-
|
49
|
+
action: SavedAction
|
50
|
+
"""The action that will execute when this automation is triggered."""
|
68
51
|
|
69
52
|
|
70
|
-
class NewAutomation(
|
71
|
-
"""
|
53
|
+
class NewAutomation(GQLBase, extra="forbid", validate_default=False):
|
54
|
+
"""A new automation to be created."""
|
72
55
|
|
73
56
|
name: Optional[str] = None
|
74
|
-
|
75
|
-
enabled: bool = True
|
76
|
-
|
77
|
-
scope: Optional[InputScope] = Field(discriminator="typename__", default=None)
|
78
|
-
event: Optional[InputEvent] = Field(discriminator="event_type", default=None)
|
79
|
-
action: Optional[InputAction] = Field(discriminator="action_type", default=None)
|
57
|
+
"""The name of this automation."""
|
80
58
|
|
81
|
-
|
82
|
-
|
83
|
-
# ) -> Automation:
|
84
|
-
# """Create this automation by saving it to the server.
|
59
|
+
description: Optional[str] = None
|
60
|
+
"""An optional description of this automation."""
|
85
61
|
|
86
|
-
|
87
|
-
|
88
|
-
# updates:
|
89
|
-
# Any final updates to apply to the automation before
|
90
|
-
# saving it. These override previously-set values, if any.
|
62
|
+
enabled: Optional[bool] = None
|
63
|
+
"""Whether this automation is enabled. Only enabled automations will trigger."""
|
91
64
|
|
92
|
-
|
93
|
-
|
94
|
-
# """
|
95
|
-
# from wandb import Api
|
65
|
+
event: Optional[InputEvent] = None
|
66
|
+
"""The event that will trigger this automation."""
|
96
67
|
|
97
|
-
#
|
68
|
+
# Ensure that the event and its scope are always consistent, if the event is set.
|
69
|
+
@property
|
70
|
+
def scope(self) -> Optional[AutomationScope]:
|
71
|
+
"""The scope in which the triggering event must occur."""
|
72
|
+
return self.event.scope if self.event else None
|
98
73
|
|
74
|
+
@scope.setter
|
75
|
+
def scope(self, value: AutomationScope) -> None:
|
76
|
+
if self.event is None:
|
77
|
+
raise ValueError("Cannot set `scope` for an automation with no `event`")
|
78
|
+
self.event.scope = value
|
99
79
|
|
100
|
-
|
101
|
-
"""
|
80
|
+
action: Optional[InputAction] = None
|
81
|
+
"""The action that will execute when this automation is triggered."""
|
102
82
|
|
103
|
-
name: str
|
104
|
-
description: Optional[str] = None
|
105
|
-
enabled: bool = True
|
106
83
|
|
107
|
-
|
108
|
-
|
109
|
-
|
84
|
+
__all__ = [
|
85
|
+
"Automation",
|
86
|
+
"NewAutomation",
|
87
|
+
]
|