wandb 0.19.9__py3-none-win_amd64.whl → 0.19.10__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 +4 -1
- wandb/_pydantic/__init__.py +14 -7
- wandb/_pydantic/base.py +44 -9
- wandb/_pydantic/utils.py +66 -0
- wandb/_pydantic/v1_compat.py +78 -56
- wandb/apis/public/__init__.py +2 -2
- wandb/apis/public/api.py +114 -2
- wandb/apis/public/artifacts.py +365 -673
- wandb/apis/public/automations.py +69 -0
- wandb/apis/public/integrations.py +168 -0
- wandb/apis/public/projects.py +29 -0
- wandb/apis/public/utils.py +107 -1
- wandb/automations/__init__.py +81 -0
- wandb/automations/_filters/__init__.py +40 -0
- wandb/automations/_filters/expressions.py +179 -0
- wandb/automations/_filters/operators.py +267 -0
- wandb/automations/_filters/run_metrics.py +183 -0
- wandb/automations/_generated/__init__.py +184 -0
- wandb/automations/_generated/create_filter_trigger.py +21 -0
- wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
- wandb/automations/_generated/delete_trigger.py +19 -0
- wandb/automations/_generated/enums.py +33 -0
- wandb/automations/_generated/fragments.py +343 -0
- wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
- wandb/automations/_generated/get_triggers.py +24 -0
- wandb/automations/_generated/get_triggers_by_entity.py +24 -0
- wandb/automations/_generated/input_types.py +104 -0
- wandb/automations/_generated/integrations_by_entity.py +22 -0
- wandb/automations/_generated/operations.py +710 -0
- wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
- wandb/automations/_generated/update_filter_trigger.py +21 -0
- wandb/automations/_utils.py +123 -0
- wandb/automations/_validators.py +73 -0
- wandb/automations/actions.py +205 -0
- wandb/automations/automations.py +109 -0
- wandb/automations/events.py +235 -0
- wandb/automations/integrations.py +26 -0
- wandb/automations/scopes.py +76 -0
- wandb/beta/workflows.py +9 -10
- wandb/bin/gpu_stats.exe +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +3 -3
- wandb/integration/keras/keras.py +2 -1
- wandb/integration/langchain/wandb_tracer.py +2 -1
- wandb/jupyter.py +137 -118
- wandb/old/summary.py +0 -2
- wandb/proto/v3/wandb_internal_pb2.py +293 -292
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_internal_pb2.py +292 -292
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v5/wandb_internal_pb2.py +292 -292
- wandb/proto/v5/wandb_settings_pb2.py +2 -2
- wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v6/wandb_base_pb2.py +41 -0
- wandb/proto/v6/wandb_internal_pb2.py +393 -0
- wandb/proto/v6/wandb_server_pb2.py +78 -0
- wandb/proto/v6/wandb_settings_pb2.py +58 -0
- wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
- wandb/proto/wandb_base_pb2.py +2 -0
- wandb/proto/wandb_deprecated.py +8 -0
- wandb/proto/wandb_internal_pb2.py +3 -1
- wandb/proto/wandb_server_pb2.py +2 -0
- wandb/proto/wandb_settings_pb2.py +2 -0
- wandb/proto/wandb_telemetry_pb2.py +2 -0
- wandb/sdk/artifacts/_generated/__init__.py +248 -0
- wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
- wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
- wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
- wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
- wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
- wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
- wandb/sdk/artifacts/_generated/enums.py +17 -0
- wandb/sdk/artifacts/_generated/fragments.py +186 -0
- wandb/sdk/artifacts/_generated/input_types.py +16 -0
- wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
- wandb/sdk/artifacts/_generated/operations.py +510 -0
- wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
- wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
- wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
- wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
- wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
- wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
- wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
- wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
- wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
- wandb/sdk/artifacts/_graphql_fragments.py +56 -79
- wandb/sdk/artifacts/artifact.py +40 -13
- wandb/sdk/artifacts/artifact_manifest_entry.py +2 -1
- wandb/sdk/artifacts/storage_handlers/azure_handler.py +1 -0
- wandb/sdk/data_types/base_types/media.py +2 -3
- wandb/sdk/data_types/base_types/wb_value.py +34 -11
- wandb/sdk/data_types/html.py +36 -9
- wandb/sdk/data_types/image.py +12 -12
- wandb/sdk/data_types/table.py +5 -0
- wandb/sdk/data_types/trace_tree.py +2 -0
- wandb/sdk/data_types/utils.py +1 -1
- wandb/sdk/data_types/video.py +14 -26
- wandb/sdk/interface/interface.py +2 -0
- wandb/sdk/internal/profiler.py +6 -5
- wandb/sdk/internal/run.py +13 -6
- wandb/sdk/lib/apikey.py +25 -4
- wandb/sdk/lib/asyncio_compat.py +1 -1
- wandb/sdk/lib/deprecate.py +13 -22
- wandb/sdk/lib/disabled.py +2 -1
- wandb/sdk/lib/printer.py +37 -8
- wandb/sdk/lib/printer_asyncio.py +46 -0
- wandb/sdk/lib/redirect.py +10 -5
- wandb/sdk/service/server_sock.py +19 -14
- wandb/sdk/service/service.py +9 -7
- wandb/sdk/service/streams.py +5 -0
- wandb/sdk/verify/verify.py +6 -3
- wandb/sdk/wandb_init.py +185 -65
- wandb/sdk/wandb_login.py +13 -4
- wandb/sdk/wandb_run.py +382 -286
- wandb/sdk/wandb_settings.py +21 -3
- wandb/sdk/wandb_setup.py +49 -0
- wandb/util.py +29 -29
- {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/METADATA +5 -5
- {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/RECORD +125 -72
- wandb/_globals.py +0 -19
- wandb/sdk/internal/_generated/base.py +0 -226
- wandb/sdk/internal/_generated/typing_compat.py +0 -14
- {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/WHEEL +0 -0
- {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/entry_points.txt +0 -0
- {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,267 @@
|
|
1
|
+
"""Types that represent operators in MongoDB filter expressions."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import TYPE_CHECKING, Any, Dict, Iterable, Tuple, TypeVar, Union, overload
|
6
|
+
|
7
|
+
from pydantic import ConfigDict, Field, StrictBool, StrictFloat, StrictInt, StrictStr
|
8
|
+
from typing_extensions import TypeAlias, get_args
|
9
|
+
|
10
|
+
from wandb._pydantic import Base
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from wandb.automations._filters.run_metrics import MetricThresholdFilter
|
14
|
+
from wandb.automations.events import RunMetricFilter
|
15
|
+
|
16
|
+
|
17
|
+
# for type annotations
|
18
|
+
Scalar = Union[StrictStr, StrictInt, StrictFloat, StrictBool]
|
19
|
+
# for runtime type checks
|
20
|
+
ScalarTypes = get_args(Scalar)
|
21
|
+
|
22
|
+
# See: https://rich.readthedocs.io/en/stable/pretty.html#rich-repr-protocol
|
23
|
+
RichReprResult: TypeAlias = Iterable[
|
24
|
+
Union[
|
25
|
+
Any,
|
26
|
+
Tuple[Any],
|
27
|
+
Tuple[str, Any],
|
28
|
+
Tuple[str, Any, Any],
|
29
|
+
]
|
30
|
+
]
|
31
|
+
|
32
|
+
T = TypeVar("T")
|
33
|
+
TupleOf: TypeAlias = Tuple[T, ...]
|
34
|
+
|
35
|
+
|
36
|
+
# NOTE: Wherever class descriptions that are not docstrings, this is deliberate.
|
37
|
+
# This is done to ensure the descriptions are omitted from generated API docs.
|
38
|
+
|
39
|
+
|
40
|
+
# Mixin to support syntactic sugar for MongoDB expressions with (bitwise) logical operators,
|
41
|
+
# e.g. `a | b` -> `{"$or": [a, b]}` or `~a` -> `{"$not": a}`.
|
42
|
+
class SupportsLogicalOpSyntax:
|
43
|
+
def __or__(self, other: Any) -> Or:
|
44
|
+
"""Syntactic sugar for: `a | b` -> `Or(a, b)`."""
|
45
|
+
return Or(or_=[self, other])
|
46
|
+
|
47
|
+
@overload
|
48
|
+
def __and__(self, other: MetricThresholdFilter) -> RunMetricFilter: ...
|
49
|
+
@overload
|
50
|
+
def __and__(self, other: Any) -> And: ...
|
51
|
+
def __and__(self, other: Any) -> Any:
|
52
|
+
"""Syntactic sugar for: `a & b` -> `And(a, b)`."""
|
53
|
+
from wandb.automations._filters.run_metrics import MetricThresholdFilter
|
54
|
+
|
55
|
+
# Special handling `run_filter & metric_filter`
|
56
|
+
if isinstance(other, MetricThresholdFilter):
|
57
|
+
return other.__and__(self)
|
58
|
+
return And(and_=[self, other])
|
59
|
+
|
60
|
+
def __invert__(self) -> Not:
|
61
|
+
"""Syntactic sugar for: `~a` -> `Not(a)`."""
|
62
|
+
return Not(not_=self)
|
63
|
+
|
64
|
+
|
65
|
+
# Base class for parsed MongoDB filter/query operators, e.g. `{"$and": [...]}`.
|
66
|
+
class BaseOp(Base, SupportsLogicalOpSyntax):
|
67
|
+
model_config = ConfigDict(
|
68
|
+
frozen=True, # Make pseudo-immutable for easier comparison and hashing
|
69
|
+
)
|
70
|
+
|
71
|
+
def __repr__(self) -> str:
|
72
|
+
# Display operand as a positional arg
|
73
|
+
values_repr = ", ".join(map(repr, self.model_dump().values()))
|
74
|
+
return f"{type(self).__name__}({values_repr})"
|
75
|
+
|
76
|
+
def __rich_repr__(self) -> RichReprResult: # type: ignore[override]
|
77
|
+
# Display field values as positional args:
|
78
|
+
# https://rich.readthedocs.io/en/stable/pretty.html
|
79
|
+
yield from ((None, v) for v in self.model_dump().values())
|
80
|
+
|
81
|
+
|
82
|
+
# Logical operator(s)
|
83
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/and/
|
84
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/or/
|
85
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/nor/
|
86
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/not/
|
87
|
+
class And(BaseOp):
|
88
|
+
and_: TupleOf[Any] = Field(default=(), alias="$and")
|
89
|
+
|
90
|
+
|
91
|
+
class Or(BaseOp):
|
92
|
+
or_: TupleOf[Any] = Field(default=(), alias="$or")
|
93
|
+
|
94
|
+
def __invert__(self) -> Nor:
|
95
|
+
"""Syntactic sugar for: `~Or(a, b)` -> `Nor(a, b)`."""
|
96
|
+
return Nor(nor_=self.or_)
|
97
|
+
|
98
|
+
|
99
|
+
class Nor(BaseOp):
|
100
|
+
nor_: TupleOf[Any] = Field(default=(), alias="$nor")
|
101
|
+
|
102
|
+
def __invert__(self) -> Or:
|
103
|
+
"""Syntactic sugar for: `~Nor(a, b)` -> `Or(a, b)`."""
|
104
|
+
return Or(or_=self.nor_)
|
105
|
+
|
106
|
+
|
107
|
+
class Not(BaseOp):
|
108
|
+
not_: Any = Field(alias="$not")
|
109
|
+
|
110
|
+
def __invert__(self) -> Any:
|
111
|
+
"""Syntactic sugar for: `~Not(a)` -> `a`."""
|
112
|
+
return self.not_
|
113
|
+
|
114
|
+
|
115
|
+
# Comparison operator(s)
|
116
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/lt/
|
117
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/gt/
|
118
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/lte/
|
119
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/gte/
|
120
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/eq/
|
121
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/ne/
|
122
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/in/
|
123
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/nin/
|
124
|
+
class Lt(BaseOp):
|
125
|
+
lt_: Scalar = Field(alias="$lt")
|
126
|
+
|
127
|
+
def __invert__(self) -> Gte:
|
128
|
+
"""Syntactic sugar for: `~Lt(a)` -> `Gte(a)`."""
|
129
|
+
return Gte(gte_=self.lt_)
|
130
|
+
|
131
|
+
|
132
|
+
class Gt(BaseOp):
|
133
|
+
gt_: Scalar = Field(alias="$gt")
|
134
|
+
|
135
|
+
def __invert__(self) -> Lte:
|
136
|
+
"""Syntactic sugar for: `~Gt(a)` -> `Lte(a)`."""
|
137
|
+
return Lte(lte_=self.gt_)
|
138
|
+
|
139
|
+
|
140
|
+
class Lte(BaseOp):
|
141
|
+
lte_: Scalar = Field(alias="$lte")
|
142
|
+
|
143
|
+
def __invert__(self) -> Gt:
|
144
|
+
"""Syntactic sugar for: `~Lte(a)` -> `Gt(a)`."""
|
145
|
+
return Gt(gt_=self.lte_)
|
146
|
+
|
147
|
+
|
148
|
+
class Gte(BaseOp):
|
149
|
+
gte_: Scalar = Field(alias="$gte")
|
150
|
+
|
151
|
+
def __invert__(self) -> Lt:
|
152
|
+
"""Syntactic sugar for: `~Gte(a)` -> `Lt(a)`."""
|
153
|
+
return Lt(lt_=self.gte_)
|
154
|
+
|
155
|
+
|
156
|
+
class Eq(BaseOp):
|
157
|
+
eq_: Scalar = Field(alias="$eq")
|
158
|
+
|
159
|
+
def __invert__(self) -> Ne:
|
160
|
+
"""Syntactic sugar for: `~Eq(a)` -> `Ne(a)`."""
|
161
|
+
return Ne(ne_=self.eq_)
|
162
|
+
|
163
|
+
|
164
|
+
class Ne(BaseOp):
|
165
|
+
ne_: Scalar = Field(alias="$ne")
|
166
|
+
|
167
|
+
def __invert__(self) -> Eq:
|
168
|
+
"""Syntactic sugar for: `~Ne(a)` -> `Eq(a)`."""
|
169
|
+
return Eq(eq_=self.ne_)
|
170
|
+
|
171
|
+
|
172
|
+
class In(BaseOp):
|
173
|
+
in_: TupleOf[Scalar] = Field(default=(), alias="$in")
|
174
|
+
|
175
|
+
def __invert__(self) -> NotIn:
|
176
|
+
"""Syntactic sugar for: `~In(a)` -> `NotIn(a)`."""
|
177
|
+
return NotIn(nin_=self.in_)
|
178
|
+
|
179
|
+
|
180
|
+
class NotIn(BaseOp):
|
181
|
+
nin_: TupleOf[Scalar] = Field(default=(), alias="$nin")
|
182
|
+
|
183
|
+
def __invert__(self) -> In:
|
184
|
+
"""Syntactic sugar for: `~NotIn(a)` -> `In(a)`."""
|
185
|
+
return In(in_=self.nin_)
|
186
|
+
|
187
|
+
|
188
|
+
# Element operator(s)
|
189
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/exists/
|
190
|
+
class Exists(BaseOp):
|
191
|
+
exists_: bool = Field(alias="$exists")
|
192
|
+
|
193
|
+
|
194
|
+
# Evaluation operator(s)
|
195
|
+
# https://www.mongodb.com/docs/manual/reference/operator/query/regex/
|
196
|
+
#
|
197
|
+
# Note: "$contains" is NOT a formal MongoDB operator, but the backend recognizes and
|
198
|
+
# executes it as a substring-match filter.
|
199
|
+
class Regex(BaseOp):
|
200
|
+
regex_: str = Field(alias="$regex") #: The regex expression to match against.
|
201
|
+
|
202
|
+
|
203
|
+
class Contains(BaseOp):
|
204
|
+
contains_: str = Field(alias="$contains") #: The substring to match against.
|
205
|
+
|
206
|
+
|
207
|
+
And.model_rebuild()
|
208
|
+
Or.model_rebuild()
|
209
|
+
Not.model_rebuild()
|
210
|
+
Lt.model_rebuild()
|
211
|
+
Gt.model_rebuild()
|
212
|
+
Lte.model_rebuild()
|
213
|
+
Gte.model_rebuild()
|
214
|
+
Eq.model_rebuild()
|
215
|
+
Ne.model_rebuild()
|
216
|
+
In.model_rebuild()
|
217
|
+
NotIn.model_rebuild()
|
218
|
+
Exists.model_rebuild()
|
219
|
+
Regex.model_rebuild()
|
220
|
+
Contains.model_rebuild()
|
221
|
+
|
222
|
+
|
223
|
+
# ------------------------------------------------------------------------------
|
224
|
+
# Convenience helpers, constants, and utils for supported MongoDB operators
|
225
|
+
# ------------------------------------------------------------------------------
|
226
|
+
KEY_TO_OP: dict[str, type[BaseOp]] = {
|
227
|
+
"$and": And,
|
228
|
+
"$or": Or,
|
229
|
+
"$nor": Nor,
|
230
|
+
"$not": Not,
|
231
|
+
"$lt": Lt,
|
232
|
+
"$gt": Gt,
|
233
|
+
"$lte": Lte,
|
234
|
+
"$gte": Gte,
|
235
|
+
"$eq": Eq,
|
236
|
+
"$ne": Ne,
|
237
|
+
"$in": In,
|
238
|
+
"$nin": NotIn,
|
239
|
+
"$exists": Exists,
|
240
|
+
"$regex": Regex,
|
241
|
+
"$contains": Contains,
|
242
|
+
}
|
243
|
+
|
244
|
+
|
245
|
+
KnownOp = Union[
|
246
|
+
And,
|
247
|
+
Or,
|
248
|
+
Nor,
|
249
|
+
Not,
|
250
|
+
Lt,
|
251
|
+
Gt,
|
252
|
+
Lte,
|
253
|
+
Gte,
|
254
|
+
Eq,
|
255
|
+
Ne,
|
256
|
+
In,
|
257
|
+
NotIn,
|
258
|
+
Exists,
|
259
|
+
Regex,
|
260
|
+
Contains,
|
261
|
+
]
|
262
|
+
UnknownOp = Dict[str, Any]
|
263
|
+
|
264
|
+
# for type annotations
|
265
|
+
Op = Union[KnownOp, UnknownOp]
|
266
|
+
# for runtime type checks
|
267
|
+
OpTypes: tuple[type, ...] = (*get_args(KnownOp), dict)
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# ruff: noqa: UP007
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from enum import Enum
|
6
|
+
from typing import TYPE_CHECKING, Any, Final, Literal, Optional, Union, overload
|
7
|
+
|
8
|
+
from pydantic import Field, PositiveInt, StrictFloat, StrictInt, field_validator
|
9
|
+
from typing_extensions import Self, override
|
10
|
+
|
11
|
+
from wandb._pydantic.base import Base, GQLBase
|
12
|
+
|
13
|
+
from .expressions import FilterExpr
|
14
|
+
from .operators import BaseOp, RichReprResult
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from wandb.automations.events import RunMetricFilter
|
18
|
+
|
19
|
+
# Maps MongoDB comparison operators -> Python literal (str) representations
|
20
|
+
MONGO2PY_OPS: Final[dict[str, str]] = {
|
21
|
+
"$eq": "==",
|
22
|
+
"$ne": "!=",
|
23
|
+
"$gt": ">",
|
24
|
+
"$lt": "<",
|
25
|
+
"$gte": ">=",
|
26
|
+
"$lte": "<=",
|
27
|
+
}
|
28
|
+
# Reverse mapping from Python literal (str) -> MongoDB operator key
|
29
|
+
PY2MONGO_OPS: Final[dict[str, str]] = {v: k for k, v in MONGO2PY_OPS.items()}
|
30
|
+
|
31
|
+
|
32
|
+
class Agg(str, Enum): # from `Aggregation`
|
33
|
+
"""Supported run metric aggregation operations."""
|
34
|
+
|
35
|
+
MAX = "MAX"
|
36
|
+
MIN = "MIN"
|
37
|
+
AVERAGE = "AVERAGE"
|
38
|
+
|
39
|
+
|
40
|
+
class ChangeType(str, Enum): # from `RunMetricChangeType`
|
41
|
+
"""Describes the metric change as absolute (arithmetic difference) or relative (decimal percentage)."""
|
42
|
+
|
43
|
+
ABSOLUTE = "ABSOLUTE"
|
44
|
+
RELATIVE = "RELATIVE"
|
45
|
+
|
46
|
+
|
47
|
+
class ChangeDirection(str, Enum): # from `RunMetricChangeDirection`
|
48
|
+
"""Describes the direction of the metric change."""
|
49
|
+
|
50
|
+
INCREASE = "INCREASE"
|
51
|
+
DECREASE = "DECREASE"
|
52
|
+
ANY = "ANY"
|
53
|
+
|
54
|
+
|
55
|
+
class _BaseMetricFilter(GQLBase):
|
56
|
+
name: str
|
57
|
+
"""Name of the observed metric."""
|
58
|
+
|
59
|
+
agg: Optional[Agg]
|
60
|
+
"""Aggregation operation, if any, to apply over the window size."""
|
61
|
+
|
62
|
+
window: PositiveInt
|
63
|
+
"""Size of the window over which the metric is aggregated."""
|
64
|
+
|
65
|
+
# ------------------------------------------------------------------------------
|
66
|
+
|
67
|
+
threshold: Union[StrictInt, StrictFloat]
|
68
|
+
"""Threshold value to compare against."""
|
69
|
+
|
70
|
+
@field_validator("agg", mode="before")
|
71
|
+
@classmethod
|
72
|
+
def _validate_agg(cls, v: Any) -> Any:
|
73
|
+
# Be helpful: e.g. "min" -> "MIN"
|
74
|
+
return v.strip().upper() if isinstance(v, str) else v
|
75
|
+
|
76
|
+
@overload
|
77
|
+
def __and__(self, other: BaseOp | FilterExpr) -> RunMetricFilter: ...
|
78
|
+
@overload
|
79
|
+
def __and__(self, other: Any) -> Any: ...
|
80
|
+
def __and__(self, other: BaseOp | FilterExpr | Any) -> RunMetricFilter | Any:
|
81
|
+
"""Supports syntactic sugar for defining a triggering RunMetricEvent from `run_metric_filter & run_filter`."""
|
82
|
+
from wandb.automations.events import RunMetricFilter, _InnerRunMetricFilter
|
83
|
+
|
84
|
+
if isinstance(run_filter := other, (BaseOp, FilterExpr)):
|
85
|
+
# Assume `other` is a run filter, and we are building a RunMetricEvent.
|
86
|
+
# For the metric filter, delegate to the inner validator(s) to further wrap/nest as appropriate.
|
87
|
+
metric_filter = _InnerRunMetricFilter.model_validate(self)
|
88
|
+
return RunMetricFilter(
|
89
|
+
run_metric_filter=metric_filter, run_filter=run_filter
|
90
|
+
)
|
91
|
+
return other.__and__(self) # Try switching the order of operands
|
92
|
+
|
93
|
+
|
94
|
+
class MetricThresholdFilter(_BaseMetricFilter): # from `RunMetricThresholdFilter`
|
95
|
+
"""For run events, defines a metric filter comparing a metric against a user-defined threshold value."""
|
96
|
+
|
97
|
+
name: str
|
98
|
+
agg: Optional[Agg] = Field(default=None, alias="agg_op")
|
99
|
+
window: PositiveInt = Field(default=1, alias="window_size")
|
100
|
+
|
101
|
+
cmp: Literal["$gte", "$gt", "$lt", "$lte"] = Field(alias="cmp_op")
|
102
|
+
"""Comparison operator used to compare the metric value (left) vs. the threshold value (right)."""
|
103
|
+
|
104
|
+
threshold: Union[StrictInt, StrictFloat]
|
105
|
+
|
106
|
+
@field_validator("cmp", mode="before")
|
107
|
+
@classmethod
|
108
|
+
def _validate_cmp(cls, v: Any) -> Any:
|
109
|
+
# Be helpful: e.g. ">" -> "$gt"
|
110
|
+
return PY2MONGO_OPS.get(v.strip(), v) if isinstance(v, str) else v
|
111
|
+
|
112
|
+
def __repr__(self) -> str:
|
113
|
+
metric = f"{self.agg.value}({self.name})" if self.agg else self.name
|
114
|
+
op = MONGO2PY_OPS.get(self.cmp, self.cmp)
|
115
|
+
expr = rf"{metric} {op} {self.threshold}"
|
116
|
+
return repr(expr)
|
117
|
+
|
118
|
+
@override
|
119
|
+
def __rich_repr__(self) -> RichReprResult: # type: ignore[override]
|
120
|
+
yield None, repr(self)
|
121
|
+
|
122
|
+
|
123
|
+
class MetricChangeFilter(_BaseMetricFilter): # from `RunMetricChangeFilter`
|
124
|
+
# FIXME:
|
125
|
+
# - `prior_window` should be optional and default to `window` if not provided.
|
126
|
+
# - implement declarative syntax for `MetricChangeFilter` similar to `MetricThresholdFilter`.
|
127
|
+
# - split this into tagged union of relative/absolute change filters.
|
128
|
+
|
129
|
+
name: str
|
130
|
+
agg: Optional[Agg] = Field(default=None, alias="agg_op")
|
131
|
+
|
132
|
+
# FIXME: Set the `prior_window` to `window` if it's not provided, for convenience.
|
133
|
+
window: PositiveInt = Field(alias="current_window_size")
|
134
|
+
prior_window: PositiveInt = Field(alias="prior_window_size")
|
135
|
+
"""Size of the preceding window over which the metric is aggregated."""
|
136
|
+
|
137
|
+
# NOTE: `cmp_op` isn't a field here. In the backend, it's effectively `cmp_op` = "$gte"
|
138
|
+
|
139
|
+
change_type: ChangeType = Field(alias="change_type")
|
140
|
+
change_direction: ChangeDirection = Field(alias="change_dir")
|
141
|
+
|
142
|
+
threshold: Union[StrictInt, StrictFloat] = Field(alias="change_amount")
|
143
|
+
|
144
|
+
|
145
|
+
class MetricOperand(Base):
|
146
|
+
name: str
|
147
|
+
agg: Optional[Agg] = Field(default=None, alias="agg_op")
|
148
|
+
window: PositiveInt = Field(default=1, alias="window_size")
|
149
|
+
|
150
|
+
def _agg(self, op: Agg, window: int) -> Self:
|
151
|
+
if self.agg is None: # Prevent overwriting an existing aggregation operator
|
152
|
+
return self.model_copy(update={"agg": op, "window": window})
|
153
|
+
raise ValueError(f"Aggregation operator already set as: {self.agg!r}")
|
154
|
+
|
155
|
+
def max(self, window: int) -> Self:
|
156
|
+
return self._agg(Agg.MAX, window)
|
157
|
+
|
158
|
+
def min(self, window: int) -> Self:
|
159
|
+
return self._agg(Agg.MIN, window)
|
160
|
+
|
161
|
+
def average(self, window: int) -> Self:
|
162
|
+
return self._agg(Agg.AVERAGE, window)
|
163
|
+
|
164
|
+
# Aliased method for users familiar with e.g. torch/tf/numpy/pandas/polars/etc.
|
165
|
+
def mean(self, window: int) -> Self:
|
166
|
+
return self.average(window=window)
|
167
|
+
|
168
|
+
def gt(self, other: int | float) -> MetricThresholdFilter:
|
169
|
+
return MetricThresholdFilter(**dict(self), cmp="$gt", threshold=other)
|
170
|
+
|
171
|
+
def lt(self, other: int | float) -> MetricThresholdFilter:
|
172
|
+
return MetricThresholdFilter(**dict(self), cmp="$lt", threshold=other)
|
173
|
+
|
174
|
+
def gte(self, other: int | float) -> MetricThresholdFilter:
|
175
|
+
return MetricThresholdFilter(**dict(self), cmp="$gte", threshold=other)
|
176
|
+
|
177
|
+
def lte(self, other: int | float) -> MetricThresholdFilter:
|
178
|
+
return MetricThresholdFilter(**dict(self), cmp="$lte", threshold=other)
|
179
|
+
|
180
|
+
__gt__ = gt
|
181
|
+
__lt__ = lt
|
182
|
+
__ge__ = gte
|
183
|
+
__le__ = lte
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# Generated by ariadne-codegen
|
2
|
+
|
3
|
+
from .create_filter_trigger import CreateFilterTrigger
|
4
|
+
from .create_generic_webhook_integration import (
|
5
|
+
CreateGenericWebhookIntegration,
|
6
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegration,
|
7
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationGenericWebhookIntegration,
|
8
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationIntegration,
|
9
|
+
)
|
10
|
+
from .delete_trigger import DeleteTrigger
|
11
|
+
from .enums import (
|
12
|
+
AlertSeverity,
|
13
|
+
EventTriggeringConditionType,
|
14
|
+
TriggeredActionType,
|
15
|
+
TriggerScopeType,
|
16
|
+
)
|
17
|
+
from .fragments import (
|
18
|
+
ArtifactPortfolioScopeFields,
|
19
|
+
ArtifactSequenceScopeFields,
|
20
|
+
CreateFilterTriggerResult,
|
21
|
+
DeleteTriggerResult,
|
22
|
+
FilterEventFields,
|
23
|
+
GenericWebhookActionFields,
|
24
|
+
GenericWebhookActionFieldsIntegrationGenericWebhookIntegration,
|
25
|
+
GenericWebhookActionFieldsIntegrationIntegration,
|
26
|
+
GenericWebhookIntegrationConnectionFields,
|
27
|
+
GenericWebhookIntegrationConnectionFieldsEdges,
|
28
|
+
GenericWebhookIntegrationConnectionFieldsEdgesNodeGenericWebhookIntegration,
|
29
|
+
GenericWebhookIntegrationConnectionFieldsEdgesNodeIntegration,
|
30
|
+
GenericWebhookIntegrationFields,
|
31
|
+
GithubIntegrationFields,
|
32
|
+
IntegrationConnectionFields,
|
33
|
+
IntegrationConnectionFieldsEdges,
|
34
|
+
IntegrationConnectionFieldsEdgesNodeGenericWebhookIntegration,
|
35
|
+
IntegrationConnectionFieldsEdgesNodeIntegration,
|
36
|
+
IntegrationConnectionFieldsEdgesNodeSlackIntegration,
|
37
|
+
NoOpActionFields,
|
38
|
+
NotificationActionFields,
|
39
|
+
NotificationActionFieldsIntegrationIntegration,
|
40
|
+
NotificationActionFieldsIntegrationSlackIntegration,
|
41
|
+
PageInfoFields,
|
42
|
+
ProjectConnectionFields,
|
43
|
+
ProjectConnectionFieldsEdges,
|
44
|
+
ProjectConnectionFieldsEdgesNode,
|
45
|
+
ProjectScopeFields,
|
46
|
+
QueueJobActionFields,
|
47
|
+
RunQueueFields,
|
48
|
+
SlackIntegrationConnectionFields,
|
49
|
+
SlackIntegrationConnectionFieldsEdges,
|
50
|
+
SlackIntegrationConnectionFieldsEdgesNodeIntegration,
|
51
|
+
SlackIntegrationConnectionFieldsEdgesNodeSlackIntegration,
|
52
|
+
SlackIntegrationFields,
|
53
|
+
TriggerFields,
|
54
|
+
TriggerFieldsActionGenericWebhookTriggeredAction,
|
55
|
+
TriggerFieldsActionNoOpTriggeredAction,
|
56
|
+
TriggerFieldsActionNotificationTriggeredAction,
|
57
|
+
TriggerFieldsActionQueueJobTriggeredAction,
|
58
|
+
TriggerFieldsEventFilterEventTriggeringCondition,
|
59
|
+
TriggerFieldsScopeArtifactPortfolio,
|
60
|
+
TriggerFieldsScopeArtifactSequence,
|
61
|
+
TriggerFieldsScopeProject,
|
62
|
+
UpdateFilterTriggerResult,
|
63
|
+
UserFields,
|
64
|
+
)
|
65
|
+
from .generic_webhook_integrations_by_entity import (
|
66
|
+
GenericWebhookIntegrationsByEntity,
|
67
|
+
GenericWebhookIntegrationsByEntityEntity,
|
68
|
+
)
|
69
|
+
from .get_triggers import GetTriggers, GetTriggersSearchScope
|
70
|
+
from .get_triggers_by_entity import GetTriggersByEntity, GetTriggersByEntitySearchScope
|
71
|
+
from .input_types import (
|
72
|
+
CreateFilterTriggerInput,
|
73
|
+
CreateGenericWebhookIntegrationInput,
|
74
|
+
GenericWebhookActionInput,
|
75
|
+
NoOpTriggeredActionInput,
|
76
|
+
NotificationActionInput,
|
77
|
+
QueueJobActionInput,
|
78
|
+
TriggeredActionConfig,
|
79
|
+
UpdateFilterTriggerInput,
|
80
|
+
)
|
81
|
+
from .integrations_by_entity import IntegrationsByEntity, IntegrationsByEntityEntity
|
82
|
+
from .operations import (
|
83
|
+
CREATE_FILTER_TRIGGER_GQL,
|
84
|
+
CREATE_GENERIC_WEBHOOK_INTEGRATION_GQL,
|
85
|
+
DELETE_TRIGGER_GQL,
|
86
|
+
GENERIC_WEBHOOK_INTEGRATIONS_BY_ENTITY_GQL,
|
87
|
+
GET_TRIGGERS_BY_ENTITY_GQL,
|
88
|
+
GET_TRIGGERS_GQL,
|
89
|
+
INTEGRATIONS_BY_ENTITY_GQL,
|
90
|
+
SLACK_INTEGRATIONS_BY_ENTITY_GQL,
|
91
|
+
UPDATE_FILTER_TRIGGER_GQL,
|
92
|
+
)
|
93
|
+
from .slack_integrations_by_entity import (
|
94
|
+
SlackIntegrationsByEntity,
|
95
|
+
SlackIntegrationsByEntityEntity,
|
96
|
+
)
|
97
|
+
from .update_filter_trigger import UpdateFilterTrigger
|
98
|
+
|
99
|
+
__all__ = [
|
100
|
+
"CREATE_FILTER_TRIGGER_GQL",
|
101
|
+
"CREATE_GENERIC_WEBHOOK_INTEGRATION_GQL",
|
102
|
+
"DELETE_TRIGGER_GQL",
|
103
|
+
"GENERIC_WEBHOOK_INTEGRATIONS_BY_ENTITY_GQL",
|
104
|
+
"GET_TRIGGERS_BY_ENTITY_GQL",
|
105
|
+
"GET_TRIGGERS_GQL",
|
106
|
+
"INTEGRATIONS_BY_ENTITY_GQL",
|
107
|
+
"SLACK_INTEGRATIONS_BY_ENTITY_GQL",
|
108
|
+
"UPDATE_FILTER_TRIGGER_GQL",
|
109
|
+
"GetTriggers",
|
110
|
+
"GetTriggersSearchScope",
|
111
|
+
"GetTriggersByEntity",
|
112
|
+
"GetTriggersByEntitySearchScope",
|
113
|
+
"CreateFilterTrigger",
|
114
|
+
"UpdateFilterTrigger",
|
115
|
+
"DeleteTrigger",
|
116
|
+
"IntegrationsByEntity",
|
117
|
+
"IntegrationsByEntityEntity",
|
118
|
+
"SlackIntegrationsByEntity",
|
119
|
+
"SlackIntegrationsByEntityEntity",
|
120
|
+
"GenericWebhookIntegrationsByEntity",
|
121
|
+
"GenericWebhookIntegrationsByEntityEntity",
|
122
|
+
"CreateGenericWebhookIntegration",
|
123
|
+
"CreateGenericWebhookIntegrationCreateGenericWebhookIntegration",
|
124
|
+
"CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationGenericWebhookIntegration",
|
125
|
+
"CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationIntegration",
|
126
|
+
"CreateFilterTriggerInput",
|
127
|
+
"CreateGenericWebhookIntegrationInput",
|
128
|
+
"GenericWebhookActionInput",
|
129
|
+
"NoOpTriggeredActionInput",
|
130
|
+
"NotificationActionInput",
|
131
|
+
"QueueJobActionInput",
|
132
|
+
"TriggeredActionConfig",
|
133
|
+
"UpdateFilterTriggerInput",
|
134
|
+
"ArtifactPortfolioScopeFields",
|
135
|
+
"ArtifactSequenceScopeFields",
|
136
|
+
"CreateFilterTriggerResult",
|
137
|
+
"DeleteTriggerResult",
|
138
|
+
"FilterEventFields",
|
139
|
+
"GenericWebhookActionFields",
|
140
|
+
"GenericWebhookActionFieldsIntegrationGenericWebhookIntegration",
|
141
|
+
"GenericWebhookActionFieldsIntegrationIntegration",
|
142
|
+
"GenericWebhookIntegrationConnectionFields",
|
143
|
+
"GenericWebhookIntegrationConnectionFieldsEdges",
|
144
|
+
"GenericWebhookIntegrationConnectionFieldsEdgesNodeGenericWebhookIntegration",
|
145
|
+
"GenericWebhookIntegrationConnectionFieldsEdgesNodeIntegration",
|
146
|
+
"GenericWebhookIntegrationFields",
|
147
|
+
"GithubIntegrationFields",
|
148
|
+
"IntegrationConnectionFields",
|
149
|
+
"IntegrationConnectionFieldsEdges",
|
150
|
+
"IntegrationConnectionFieldsEdgesNodeGenericWebhookIntegration",
|
151
|
+
"IntegrationConnectionFieldsEdgesNodeIntegration",
|
152
|
+
"IntegrationConnectionFieldsEdgesNodeSlackIntegration",
|
153
|
+
"NoOpActionFields",
|
154
|
+
"NotificationActionFields",
|
155
|
+
"NotificationActionFieldsIntegrationIntegration",
|
156
|
+
"NotificationActionFieldsIntegrationSlackIntegration",
|
157
|
+
"PageInfoFields",
|
158
|
+
"ProjectConnectionFields",
|
159
|
+
"ProjectConnectionFieldsEdges",
|
160
|
+
"ProjectConnectionFieldsEdgesNode",
|
161
|
+
"ProjectScopeFields",
|
162
|
+
"QueueJobActionFields",
|
163
|
+
"RunQueueFields",
|
164
|
+
"SlackIntegrationConnectionFields",
|
165
|
+
"SlackIntegrationConnectionFieldsEdges",
|
166
|
+
"SlackIntegrationConnectionFieldsEdgesNodeIntegration",
|
167
|
+
"SlackIntegrationConnectionFieldsEdgesNodeSlackIntegration",
|
168
|
+
"SlackIntegrationFields",
|
169
|
+
"TriggerFields",
|
170
|
+
"TriggerFieldsActionGenericWebhookTriggeredAction",
|
171
|
+
"TriggerFieldsActionNoOpTriggeredAction",
|
172
|
+
"TriggerFieldsActionNotificationTriggeredAction",
|
173
|
+
"TriggerFieldsActionQueueJobTriggeredAction",
|
174
|
+
"TriggerFieldsEventFilterEventTriggeringCondition",
|
175
|
+
"TriggerFieldsScopeArtifactPortfolio",
|
176
|
+
"TriggerFieldsScopeArtifactSequence",
|
177
|
+
"TriggerFieldsScopeProject",
|
178
|
+
"UpdateFilterTriggerResult",
|
179
|
+
"UserFields",
|
180
|
+
"AlertSeverity",
|
181
|
+
"EventTriggeringConditionType",
|
182
|
+
"TriggerScopeType",
|
183
|
+
"TriggeredActionType",
|
184
|
+
]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Generated by ariadne-codegen
|
2
|
+
# Source: tools/graphql_codegen/automations/
|
3
|
+
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
from typing import Optional
|
7
|
+
|
8
|
+
from pydantic import Field
|
9
|
+
|
10
|
+
from wandb._pydantic import GQLBase
|
11
|
+
|
12
|
+
from .fragments import CreateFilterTriggerResult
|
13
|
+
|
14
|
+
|
15
|
+
class CreateFilterTrigger(GQLBase):
|
16
|
+
create_filter_trigger: Optional[CreateFilterTriggerResult] = Field(
|
17
|
+
alias="createFilterTrigger"
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
CreateFilterTrigger.model_rebuild()
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Generated by ariadne-codegen
|
2
|
+
# Source: tools/graphql_codegen/automations/
|
3
|
+
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
from typing import Literal, Optional, Union
|
7
|
+
|
8
|
+
from pydantic import Field
|
9
|
+
|
10
|
+
from wandb._pydantic import GQLBase, Typename
|
11
|
+
|
12
|
+
from .fragments import GenericWebhookIntegrationFields
|
13
|
+
|
14
|
+
|
15
|
+
class CreateGenericWebhookIntegration(GQLBase):
|
16
|
+
create_generic_webhook_integration: Optional[
|
17
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegration
|
18
|
+
] = Field(alias="createGenericWebhookIntegration")
|
19
|
+
|
20
|
+
|
21
|
+
class CreateGenericWebhookIntegrationCreateGenericWebhookIntegration(GQLBase):
|
22
|
+
integration: Union[
|
23
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationIntegration,
|
24
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationGenericWebhookIntegration,
|
25
|
+
] = Field(discriminator="typename__")
|
26
|
+
|
27
|
+
|
28
|
+
class CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationIntegration(
|
29
|
+
GQLBase
|
30
|
+
):
|
31
|
+
typename__: Typename[
|
32
|
+
Literal["GitHubOAuthIntegration", "Integration", "SlackIntegration"]
|
33
|
+
]
|
34
|
+
|
35
|
+
|
36
|
+
class CreateGenericWebhookIntegrationCreateGenericWebhookIntegrationIntegrationGenericWebhookIntegration(
|
37
|
+
GenericWebhookIntegrationFields
|
38
|
+
):
|
39
|
+
typename__: Typename[Literal["GenericWebhookIntegration"]]
|
40
|
+
|
41
|
+
|
42
|
+
CreateGenericWebhookIntegration.model_rebuild()
|
43
|
+
CreateGenericWebhookIntegrationCreateGenericWebhookIntegration.model_rebuild()
|