wandb 0.19.10__py3-none-musllinux_1_2_aarch64.whl → 0.19.11__py3-none-musllinux_1_2_aarch64.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_triggers_by_entity.py → get_automations_by_entity.py} +7 -5
- 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 +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/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/events.py
CHANGED
@@ -7,11 +7,12 @@ from __future__ import annotations
|
|
7
7
|
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
|
8
8
|
|
9
9
|
from pydantic import Field
|
10
|
-
from typing_extensions import
|
10
|
+
from typing_extensions import Annotated, Self, get_args
|
11
11
|
|
12
12
|
from wandb._pydantic import (
|
13
13
|
GQLBase,
|
14
14
|
SerializedToJson,
|
15
|
+
ensure_json,
|
15
16
|
field_validator,
|
16
17
|
model_validator,
|
17
18
|
pydantic_isinstance,
|
@@ -19,26 +20,34 @@ from wandb._pydantic import (
|
|
19
20
|
|
20
21
|
from ._filters import And, MongoLikeFilter, Or
|
21
22
|
from ._filters.expressions import FilterableField
|
22
|
-
from ._filters.run_metrics import
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
)
|
28
|
-
from ._generated import EventTriggeringConditionType, FilterEventFields
|
29
|
-
from ._validators import simplify_op
|
30
|
-
from .actions import InputAction, InputActionTypes
|
31
|
-
from .scopes import ArtifactCollectionScope, InputScope, ProjectScope
|
23
|
+
from ._filters.run_metrics import MetricChangeFilter, MetricThresholdFilter, MetricVal
|
24
|
+
from ._generated import FilterEventFields
|
25
|
+
from ._validators import LenientStrEnum, simplify_op
|
26
|
+
from .actions import InputAction, InputActionTypes, SavedActionTypes
|
27
|
+
from .scopes import ArtifactCollectionScope, AutomationScope, ProjectScope
|
32
28
|
|
33
29
|
if TYPE_CHECKING:
|
34
30
|
from .automations import NewAutomation
|
35
31
|
|
36
32
|
|
37
33
|
# NOTE: Re-defined publicly with a more readable name for easier access
|
38
|
-
EventType
|
39
|
-
"""The type of event that triggers an automation."""
|
34
|
+
class EventType(LenientStrEnum):
|
35
|
+
"""The type of event that triggers an automation."""
|
36
|
+
|
37
|
+
# ---------------------------------------------------------------------------
|
38
|
+
# Events triggered by GraphQL mutations
|
39
|
+
UPDATE_ARTIFACT_ALIAS = "UPDATE_ARTIFACT_ALIAS" # NOTE: Avoid in new automations
|
40
40
|
|
41
|
-
|
41
|
+
CREATE_ARTIFACT = "CREATE_ARTIFACT"
|
42
|
+
ADD_ARTIFACT_ALIAS = "ADD_ARTIFACT_ALIAS"
|
43
|
+
LINK_ARTIFACT = "LINK_MODEL"
|
44
|
+
# Note: "LINK_MODEL" is the (legacy) value expected by the backend, but we
|
45
|
+
# name it "LINK_ARTIFACT" here in the public API for clarity and consistency.
|
46
|
+
|
47
|
+
# ---------------------------------------------------------------------------
|
48
|
+
# Events triggered by Run conditions
|
49
|
+
RUN_METRIC_THRESHOLD = "RUN_METRIC"
|
50
|
+
RUN_METRIC_CHANGE = "RUN_METRIC_CHANGE"
|
42
51
|
|
43
52
|
|
44
53
|
# ------------------------------------------------------------------------------
|
@@ -46,11 +55,11 @@ Agg = Agg
|
|
46
55
|
|
47
56
|
|
48
57
|
# Note: In GQL responses containing saved automation data, the filter is wrapped in an extra `filter` key.
|
49
|
-
class
|
50
|
-
filter: SerializedToJson[MongoLikeFilter] =
|
58
|
+
class _WrappedSavedEventFilter(GQLBase): # from: TriggeringFilterEvent
|
59
|
+
filter: SerializedToJson[MongoLikeFilter] = And()
|
51
60
|
|
52
61
|
|
53
|
-
class
|
62
|
+
class _WrappedMetricFilter(GQLBase): # from: RunMetricFilter
|
54
63
|
threshold_filter: Optional[MetricThresholdFilter] = None
|
55
64
|
change_filter: Optional[MetricChangeFilter] = None
|
56
65
|
|
@@ -65,58 +74,67 @@ class _InnerRunMetricFilter(GQLBase): # from `RunMetricFilter`
|
|
65
74
|
|
66
75
|
@model_validator(mode="after")
|
67
76
|
def _ensure_exactly_one_set(self) -> Self:
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
77
|
+
set_fields = [name for name, val in self if (val is not None)]
|
78
|
+
|
79
|
+
if not set_fields:
|
80
|
+
all_names = ", ".join(map(repr, type(self).model_fields))
|
81
|
+
raise ValueError(f"Expected one of: {all_names}")
|
82
|
+
|
83
|
+
if len(set_fields) > 1:
|
84
|
+
set_names = ", ".join(map(repr, set_fields))
|
85
|
+
raise ValueError(f"Expected exactly one metric filter, got: {set_names}")
|
86
|
+
|
74
87
|
return self
|
75
88
|
|
89
|
+
@property
|
90
|
+
def event_type(self) -> EventType:
|
91
|
+
if self.threshold_filter is not None:
|
92
|
+
return EventType.RUN_METRIC_THRESHOLD
|
93
|
+
if self.change_filter is not None:
|
94
|
+
return EventType.RUN_METRIC_CHANGE
|
95
|
+
raise RuntimeError("Expected one of: `threshold_filter` or `change_filter`")
|
96
|
+
|
97
|
+
|
98
|
+
class RunMetricFilter(GQLBase): # from: TriggeringRunMetricEvent
|
99
|
+
run: Annotated[SerializedToJson[MongoLikeFilter], Field(alias="run_filter")] = And()
|
100
|
+
metric: Annotated[_WrappedMetricFilter, Field(alias="run_metric_filter")]
|
76
101
|
|
77
|
-
|
78
|
-
|
79
|
-
|
102
|
+
# ------------------------------------------------------------------------------
|
103
|
+
legacy_metric_filter: Annotated[
|
104
|
+
Optional[SerializedToJson[MetricThresholdFilter]],
|
105
|
+
Field(alias="metric_filter", deprecated=True),
|
106
|
+
] = None
|
107
|
+
"""Deprecated legacy field that was previously used to define run metric threshold events.
|
80
108
|
|
81
|
-
|
82
|
-
|
83
|
-
default=None,
|
84
|
-
deprecated="The `metric_filter` field is deprecated: use `run_metric_filter` instead.",
|
85
|
-
)
|
109
|
+
For new automations, use the `metric` field (`run_metric_filter` JSON alias) instead.
|
110
|
+
"""
|
86
111
|
|
87
112
|
@model_validator(mode="before")
|
88
113
|
@classmethod
|
89
114
|
def _wrap_metric_filter(cls, v: Any) -> Any:
|
90
115
|
if pydantic_isinstance(v, (MetricThresholdFilter, MetricChangeFilter)):
|
91
|
-
# If
|
92
|
-
#
|
93
|
-
|
94
|
-
#
|
95
|
-
return cls(
|
116
|
+
# If only an (unnested) metric filter is given, nest it under the
|
117
|
+
# `metric` field, delegating to inner validator(s) for further
|
118
|
+
# wrapping/nesting, if needed.
|
119
|
+
# This is necessary to conform to the expected backend schema.
|
120
|
+
return cls(metric=v)
|
96
121
|
return v
|
97
122
|
|
98
|
-
@field_validator("
|
99
|
-
@classmethod
|
123
|
+
@field_validator("run", mode="after")
|
100
124
|
def _wrap_run_filter(cls, v: MongoLikeFilter) -> Any:
|
101
125
|
v_new = simplify_op(v)
|
102
|
-
return (
|
103
|
-
And.model_validate(v_new)
|
104
|
-
if pydantic_isinstance(v_new, And)
|
105
|
-
else And(and_=[v_new])
|
106
|
-
)
|
126
|
+
return v_new if pydantic_isinstance(v_new, And) else And(and_=[v_new])
|
107
127
|
|
108
128
|
|
109
|
-
#
|
110
|
-
|
129
|
+
class SavedEvent(FilterEventFields): # from: FilterEventTriggeringCondition
|
130
|
+
"""A triggering event from a saved automation."""
|
111
131
|
|
132
|
+
event_type: Annotated[EventType, Field(frozen=True)] # type: ignore[assignment]
|
112
133
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
# schema (and generated class) defines it as a JSONString (str), but we
|
118
|
-
# have more specific expectations for the structure of the JSON data.
|
119
|
-
filter: SerializedToJson[Union[SavedEventFilter, SavedRunMetricFilter]]
|
134
|
+
# We override the type of the `filter` field in order to enforce the expected
|
135
|
+
# structure for the JSON data when validating and serializing.
|
136
|
+
filter: SerializedToJson[Union[_WrappedSavedEventFilter, RunMetricFilter]]
|
137
|
+
"""The condition(s) under which this event triggers an automation."""
|
120
138
|
|
121
139
|
|
122
140
|
# ------------------------------------------------------------------------------
|
@@ -127,98 +145,123 @@ class SavedEvent(FilterEventFields): # from `FilterEventTriggeringCondition`
|
|
127
145
|
# eventFilter returned in responses for saved automations.
|
128
146
|
class _BaseEventInput(GQLBase):
|
129
147
|
event_type: EventType
|
130
|
-
|
148
|
+
|
149
|
+
scope: AutomationScope
|
150
|
+
"""The scope of the event."""
|
151
|
+
|
131
152
|
filter: SerializedToJson[Any]
|
132
153
|
|
133
|
-
def
|
134
|
-
"""Define
|
154
|
+
def then(self, action: InputAction) -> NewAutomation:
|
155
|
+
"""Define a new Automation in which this event triggers the given action."""
|
135
156
|
from .automations import NewAutomation
|
136
157
|
|
137
|
-
if isinstance(action, InputActionTypes):
|
138
|
-
return NewAutomation(
|
158
|
+
if isinstance(action, (InputActionTypes, SavedActionTypes)):
|
159
|
+
return NewAutomation(event=self, action=action)
|
139
160
|
|
140
161
|
raise TypeError(f"Expected a valid action, got: {type(action).__qualname__!r}")
|
141
162
|
|
142
163
|
def __rshift__(self, other: InputAction) -> NewAutomation:
|
143
|
-
"""
|
144
|
-
return self.
|
164
|
+
"""Implements `event >> action` to define an Automation with this event and action."""
|
165
|
+
return self.then(other)
|
145
166
|
|
146
167
|
|
168
|
+
# ------------------------------------------------------------------------------
|
169
|
+
# Events that trigger on specific mutations in the backend
|
147
170
|
class _BaseMutationEventInput(_BaseEventInput):
|
148
|
-
|
149
|
-
|
150
|
-
filter: SerializedToJson[MongoLikeFilter] = Field(default_factory=And)
|
171
|
+
filter: SerializedToJson[MongoLikeFilter] = And()
|
172
|
+
"""Additional condition(s), if any, that must be met for this event to trigger an automation."""
|
151
173
|
|
152
174
|
@field_validator("filter", mode="after")
|
153
|
-
@classmethod
|
154
175
|
def _wrap_filter(cls, v: Any) -> Any:
|
155
176
|
"""Ensure the given filter is wrapped like: `{"$or": [{"$and": [<original_filter>]}]}`.
|
156
177
|
|
157
178
|
This is awkward but necessary, because the frontend expects this format.
|
158
179
|
"""
|
159
180
|
v_new = simplify_op(v)
|
160
|
-
v_new = (
|
161
|
-
|
162
|
-
if pydantic_isinstance(v_new, And)
|
163
|
-
else And(and_=[v_new])
|
164
|
-
)
|
165
|
-
v_new = Or(or_=[v_new])
|
166
|
-
return v_new
|
181
|
+
v_new = v_new if pydantic_isinstance(v_new, And) else And(and_=[v_new])
|
182
|
+
return Or(or_=[v_new])
|
167
183
|
|
168
184
|
|
169
185
|
class OnLinkArtifact(_BaseMutationEventInput):
|
170
186
|
"""A new artifact is linked to a collection."""
|
171
187
|
|
172
|
-
event_type: Literal[EventType.
|
173
|
-
scope: InputScope
|
188
|
+
event_type: Literal[EventType.LINK_ARTIFACT] = EventType.LINK_ARTIFACT
|
174
189
|
|
175
190
|
|
176
191
|
class OnAddArtifactAlias(_BaseMutationEventInput):
|
177
192
|
"""A new alias is assigned to an artifact."""
|
178
193
|
|
179
194
|
event_type: Literal[EventType.ADD_ARTIFACT_ALIAS] = EventType.ADD_ARTIFACT_ALIAS
|
180
|
-
scope: InputScope
|
181
195
|
|
182
196
|
|
183
197
|
class OnCreateArtifact(_BaseMutationEventInput):
|
184
198
|
"""A new artifact is created."""
|
185
199
|
|
186
200
|
event_type: Literal[EventType.CREATE_ARTIFACT] = EventType.CREATE_ARTIFACT
|
187
|
-
scope: ArtifactCollectionScope
|
188
201
|
|
202
|
+
scope: ArtifactCollectionScope
|
203
|
+
"""The scope of the event: only artifact collections are valid scopes for this event."""
|
189
204
|
|
190
|
-
class OnRunMetric(_BaseEventInput):
|
191
|
-
"""A run metric satisfies a user-defined absolute threshold."""
|
192
205
|
|
193
|
-
|
206
|
+
# ------------------------------------------------------------------------------
|
207
|
+
# Events that trigger on run conditions
|
208
|
+
class _BaseRunEventInput(_BaseEventInput):
|
194
209
|
scope: ProjectScope
|
210
|
+
"""The scope of the event: only projects are valid scopes for this event."""
|
211
|
+
|
212
|
+
|
213
|
+
class OnRunMetric(_BaseRunEventInput):
|
214
|
+
"""A run metric satisfies a user-defined condition."""
|
215
|
+
|
216
|
+
event_type: Literal[EventType.RUN_METRIC_THRESHOLD, EventType.RUN_METRIC_CHANGE]
|
217
|
+
|
195
218
|
filter: SerializedToJson[RunMetricFilter]
|
219
|
+
"""Run and/or metric condition(s) that must be satisfied for this event to trigger an automation."""
|
220
|
+
|
221
|
+
@model_validator(mode="before")
|
222
|
+
@classmethod
|
223
|
+
def _infer_event_type(cls, data: Any) -> Any:
|
224
|
+
"""Infer the event type at validation time from the inner filter.
|
225
|
+
|
226
|
+
This allows this class to accommodate both "threshold" and "change" metric
|
227
|
+
filter types, which are can only be determined after parsing and validating
|
228
|
+
the inner JSON data.
|
229
|
+
"""
|
230
|
+
if isinstance(data, dict) and (raw_filter := data.get("filter")):
|
231
|
+
# At this point, `raw_filter` may or may not be JSON-serialized
|
232
|
+
parsed_filter = RunMetricFilter.model_validate_json(ensure_json(raw_filter))
|
233
|
+
return {**data, "event_type": parsed_filter.metric.event_type}
|
234
|
+
|
235
|
+
return data
|
196
236
|
|
197
237
|
|
198
238
|
# for type annotations
|
199
|
-
InputEvent =
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
239
|
+
InputEvent = Annotated[
|
240
|
+
Union[
|
241
|
+
OnLinkArtifact,
|
242
|
+
OnAddArtifactAlias,
|
243
|
+
OnCreateArtifact,
|
244
|
+
OnRunMetric,
|
245
|
+
],
|
246
|
+
Field(discriminator="event_type"),
|
204
247
|
]
|
205
248
|
# for runtime type checks
|
206
|
-
InputEventTypes: tuple[type, ...] = get_args(InputEvent)
|
249
|
+
InputEventTypes: tuple[type, ...] = get_args(InputEvent.__origin__) # type: ignore[attr-defined]
|
207
250
|
|
208
251
|
|
209
252
|
# ----------------------------------------------------------------------------
|
210
253
|
|
211
254
|
|
212
255
|
class RunEvent:
|
213
|
-
name = FilterableField("display_name")
|
256
|
+
name = FilterableField(server_name="display_name")
|
214
257
|
# `Run.name` is actually filtered on `Run.display_name` in the backend.
|
215
258
|
# We can't reasonably expect users to know this a priori, so
|
216
259
|
# automatically fix it here.
|
217
260
|
|
218
261
|
@staticmethod
|
219
|
-
def metric(name: str) ->
|
262
|
+
def metric(name: str) -> MetricVal:
|
220
263
|
"""Define a metric filter condition."""
|
221
|
-
return
|
264
|
+
return MetricVal(name=name)
|
222
265
|
|
223
266
|
|
224
267
|
class ArtifactEvent:
|
@@ -227,9 +270,18 @@ class ArtifactEvent:
|
|
227
270
|
|
228
271
|
MetricThresholdFilter.model_rebuild()
|
229
272
|
RunMetricFilter.model_rebuild()
|
230
|
-
|
273
|
+
_WrappedSavedEventFilter.model_rebuild()
|
231
274
|
|
232
275
|
OnLinkArtifact.model_rebuild()
|
233
276
|
OnAddArtifactAlias.model_rebuild()
|
234
277
|
OnCreateArtifact.model_rebuild()
|
235
278
|
OnRunMetric.model_rebuild()
|
279
|
+
|
280
|
+
__all__ = [
|
281
|
+
"EventType",
|
282
|
+
*(cls.__name__ for cls in InputEventTypes),
|
283
|
+
"RunEvent",
|
284
|
+
"ArtifactEvent",
|
285
|
+
"MetricThresholdFilter",
|
286
|
+
"MetricChangeFilter",
|
287
|
+
]
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import Union
|
2
2
|
|
3
3
|
from pydantic import Field
|
4
|
+
from typing_extensions import Annotated
|
4
5
|
|
5
6
|
from wandb._pydantic import GQLBase
|
6
7
|
from wandb.automations._generated import (
|
@@ -10,17 +11,35 @@ from wandb.automations._generated import (
|
|
10
11
|
|
11
12
|
|
12
13
|
class SlackIntegration(SlackIntegrationFields):
|
13
|
-
|
14
|
+
team_name: str
|
15
|
+
"""The name of the Slack workspace (not the W&B team) that this integration is associated with."""
|
16
|
+
|
17
|
+
channel_name: str
|
18
|
+
"""The name of the Slack channel that this integration will post messages to."""
|
14
19
|
|
15
20
|
|
16
21
|
class WebhookIntegration(GenericWebhookIntegrationFields):
|
17
|
-
|
22
|
+
name: str
|
23
|
+
"""The name of this webhook integration."""
|
24
|
+
|
25
|
+
url_endpoint: str
|
26
|
+
"""The URL that this webhook will POST events to."""
|
18
27
|
|
19
28
|
|
20
|
-
Integration =
|
29
|
+
Integration = Annotated[
|
30
|
+
Union[SlackIntegration, WebhookIntegration],
|
31
|
+
Field(discriminator="typename__"),
|
32
|
+
]
|
21
33
|
|
22
34
|
|
23
35
|
# For parsing integration instances from paginated responses
|
24
36
|
class _IntegrationEdge(GQLBase):
|
25
37
|
cursor: str
|
26
|
-
node: Integration
|
38
|
+
node: Integration
|
39
|
+
|
40
|
+
|
41
|
+
__all__ = [
|
42
|
+
"Integration",
|
43
|
+
"SlackIntegration",
|
44
|
+
"WebhookIntegration",
|
45
|
+
]
|
wandb/automations/scopes.py
CHANGED
@@ -14,26 +14,29 @@ from wandb.automations._generated import (
|
|
14
14
|
ProjectScopeFields,
|
15
15
|
)
|
16
16
|
|
17
|
-
from .
|
18
|
-
|
17
|
+
from ._validators import LenientStrEnum, to_scope
|
18
|
+
|
19
19
|
|
20
20
|
# NOTE: Re-defined publicly with a more readable name for easier access
|
21
|
-
ScopeType
|
22
|
-
"""The
|
21
|
+
class ScopeType(LenientStrEnum):
|
22
|
+
"""The kind of scope that triggers an automation."""
|
23
|
+
|
24
|
+
PROJECT = "PROJECT"
|
25
|
+
ARTIFACT_COLLECTION = "ARTIFACT_COLLECTION"
|
23
26
|
|
24
27
|
|
25
28
|
class _BaseScope(GQLBase):
|
26
|
-
scope_type: ScopeType
|
29
|
+
scope_type: Annotated[ScopeType, Field(frozen=True)]
|
27
30
|
|
28
31
|
|
29
32
|
class _ArtifactSequenceScope(_BaseScope, ArtifactSequenceScopeFields):
|
30
|
-
"""
|
33
|
+
"""An automation scope defined by a specific `ArtifactSequence`."""
|
31
34
|
|
32
35
|
scope_type: Literal[ScopeType.ARTIFACT_COLLECTION] = ScopeType.ARTIFACT_COLLECTION
|
33
36
|
|
34
37
|
|
35
38
|
class _ArtifactPortfolioScope(_BaseScope, ArtifactPortfolioScopeFields):
|
36
|
-
"""
|
39
|
+
"""An automation scope defined by a specific `ArtifactPortfolio` (e.g. a registry collection)."""
|
37
40
|
|
38
41
|
scope_type: Literal[ScopeType.ARTIFACT_COLLECTION] = ScopeType.ARTIFACT_COLLECTION
|
39
42
|
|
@@ -41,20 +44,19 @@ class _ArtifactPortfolioScope(_BaseScope, ArtifactPortfolioScopeFields):
|
|
41
44
|
# for type annotations
|
42
45
|
ArtifactCollectionScope = Annotated[
|
43
46
|
Union[_ArtifactSequenceScope, _ArtifactPortfolioScope],
|
44
|
-
BeforeValidator(
|
47
|
+
BeforeValidator(to_scope),
|
45
48
|
Field(discriminator="typename__"),
|
46
49
|
]
|
47
|
-
"""
|
50
|
+
"""An automation scope defined by a specific `ArtifactCollection`."""
|
48
51
|
|
49
52
|
# for runtime type checks
|
50
|
-
ArtifactCollectionScopeTypes: tuple[type, ...] = (
|
51
|
-
|
52
|
-
_ArtifactPortfolioScope,
|
53
|
+
ArtifactCollectionScopeTypes: tuple[type, ...] = get_args(
|
54
|
+
ArtifactCollectionScope.__origin__ # type: ignore[attr-defined]
|
53
55
|
)
|
54
56
|
|
55
57
|
|
56
58
|
class ProjectScope(_BaseScope, ProjectScopeFields):
|
57
|
-
"""
|
59
|
+
"""An automation scope defined by a specific `Project`."""
|
58
60
|
|
59
61
|
scope_type: Literal[ScopeType.PROJECT] = ScopeType.PROJECT
|
60
62
|
|
@@ -62,15 +64,15 @@ class ProjectScope(_BaseScope, ProjectScopeFields):
|
|
62
64
|
# for type annotations
|
63
65
|
AutomationScope: TypeAlias = Annotated[
|
64
66
|
Union[_ArtifactSequenceScope, _ArtifactPortfolioScope, ProjectScope],
|
65
|
-
BeforeValidator(
|
67
|
+
BeforeValidator(to_scope),
|
66
68
|
Field(discriminator="typename__"),
|
67
69
|
]
|
68
70
|
# for runtime type checks
|
69
|
-
AutomationScopeTypes: tuple[type, ...] = get_args(AutomationScope)
|
71
|
+
AutomationScopeTypes: tuple[type, ...] = get_args(AutomationScope.__origin__) # type: ignore[attr-defined]
|
70
72
|
|
71
|
-
# Aliases for naming clarity/consistency
|
72
|
-
SavedScope: TypeAlias = AutomationScope
|
73
|
-
InputScope: TypeAlias = AutomationScope
|
74
73
|
|
75
|
-
|
76
|
-
|
74
|
+
__all__ = [
|
75
|
+
"ScopeType",
|
76
|
+
"ArtifactCollectionScope",
|
77
|
+
"ProjectScope",
|
78
|
+
]
|
wandb/bin/gpu_stats
CHANGED
Binary file
|
wandb/bin/wandb-core
CHANGED
Binary file
|
wandb/env.py
CHANGED
@@ -88,6 +88,7 @@ LAUNCH_QUEUE_NAME = "WANDB_LAUNCH_QUEUE_NAME"
|
|
88
88
|
LAUNCH_QUEUE_ENTITY = "WANDB_LAUNCH_QUEUE_ENTITY"
|
89
89
|
LAUNCH_TRACE_ID = "WANDB_LAUNCH_TRACE_ID"
|
90
90
|
_REQUIRE_LEGACY_SERVICE = "WANDB_X_REQUIRE_LEGACY_SERVICE"
|
91
|
+
ENABLE_DCGM_PROFILING = "WANDB_ENABLE_DCGM_PROFILING"
|
91
92
|
|
92
93
|
# For testing, to be removed in future version
|
93
94
|
USE_V1_ARTIFACTS = "_WANDB_USE_V1_ARTIFACTS"
|
@@ -177,6 +178,16 @@ def ssl_disabled() -> bool:
|
|
177
178
|
return _env_as_bool(DISABLE_SSL, default="False")
|
178
179
|
|
179
180
|
|
181
|
+
def dcgm_profiling_enabled() -> bool:
|
182
|
+
"""Checks whether collecting profiling metrics for Nvidia GPUs using DCGM is requested.
|
183
|
+
|
184
|
+
Note: Enabling this feature can lead to increased resource usage
|
185
|
+
compared to standard monitoring.
|
186
|
+
Requires the `nvidia-dcgm` service to be running on the machine.
|
187
|
+
"""
|
188
|
+
return _env_as_bool(ENABLE_DCGM_PROFILING, default="False")
|
189
|
+
|
190
|
+
|
180
191
|
def get_error_reporting(
|
181
192
|
default: bool | str = True,
|
182
193
|
env: MutableMapping | None = None,
|
wandb/old/settings.py
CHANGED
@@ -146,6 +146,10 @@ class Settings:
|
|
146
146
|
try:
|
147
147
|
home_config_dir = os.path.join(os.path.expanduser("~"), ".config", "wandb")
|
148
148
|
|
149
|
+
if os.getenv(env.CONFIG_DIR):
|
150
|
+
try_create_dir(os.getenv(env.CONFIG_DIR))
|
151
|
+
return os.path.join(os.getenv(env.CONFIG_DIR), "settings")
|
152
|
+
|
149
153
|
if not try_create_dir(home_config_dir):
|
150
154
|
temp_config_dir = os.path.join(
|
151
155
|
tempfile.gettempdir(), ".config", "wandb"
|
@@ -162,7 +166,6 @@ class Settings:
|
|
162
166
|
else:
|
163
167
|
config_dir = home_config_dir
|
164
168
|
|
165
|
-
config_dir = os.environ.get(env.CONFIG_DIR, config_dir)
|
166
169
|
return os.path.join(config_dir, "settings")
|
167
170
|
except Exception:
|
168
171
|
return None
|