wandb 0.19.9__py3-none-musllinux_1_2_aarch64.whl → 0.19.10__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 +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 +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
wandb/__init__.py
CHANGED
wandb/__init__.pyi
CHANGED
@@ -106,7 +106,7 @@ if TYPE_CHECKING:
|
|
106
106
|
import wandb
|
107
107
|
from wandb.plot import CustomChart
|
108
108
|
|
109
|
-
__version__: str = "0.19.
|
109
|
+
__version__: str = "0.19.10"
|
110
110
|
|
111
111
|
run: Run | None
|
112
112
|
config: wandb_config.Config
|
@@ -229,6 +229,7 @@ def init(
|
|
229
229
|
"default",
|
230
230
|
"return_previous",
|
231
231
|
"finish_previous",
|
232
|
+
"create_new",
|
232
233
|
]
|
233
234
|
) = None,
|
234
235
|
resume: bool | Literal["allow", "never", "must", "auto"] | None = None,
|
@@ -476,6 +477,7 @@ def login(
|
|
476
477
|
force: Optional[bool] = None,
|
477
478
|
timeout: Optional[int] = None,
|
478
479
|
verify: bool = False,
|
480
|
+
referrer: Optional[str] = None,
|
479
481
|
) -> bool:
|
480
482
|
"""Set up W&B login credentials.
|
481
483
|
|
@@ -495,6 +497,7 @@ def login(
|
|
495
497
|
force: (bool, optional) If true, will force a relogin.
|
496
498
|
timeout: (int, optional) Number of seconds to wait for user input.
|
497
499
|
verify: (bool) Verify the credentials with the W&B server.
|
500
|
+
referrer: (string, optional) The referrer to use in the URL login request.
|
498
501
|
|
499
502
|
Returns:
|
500
503
|
bool: if key is configured
|
wandb/_pydantic/__init__.py
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
"""Internal utilities for working with pydantic."""
|
2
2
|
|
3
|
-
from .base import
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
from .base import (
|
4
|
+
Base,
|
5
|
+
CompatBaseModel,
|
6
|
+
GQLBase,
|
7
|
+
GQLId,
|
8
|
+
SerializedToJson,
|
9
|
+
Typename,
|
10
|
+
ensure_json,
|
10
11
|
)
|
12
|
+
from .utils import IS_PYDANTIC_V2, pydantic_isinstance, to_json
|
13
|
+
from .v1_compat import AliasChoices, computed_field, field_validator, model_validator
|
11
14
|
|
12
15
|
__all__ = [
|
13
16
|
"IS_PYDANTIC_V2",
|
17
|
+
"CompatBaseModel",
|
14
18
|
"Base",
|
15
19
|
"GQLBase",
|
16
20
|
"Typename",
|
@@ -20,4 +24,7 @@ __all__ = [
|
|
20
24
|
"computed_field",
|
21
25
|
"field_validator",
|
22
26
|
"model_validator",
|
27
|
+
"pydantic_isinstance",
|
28
|
+
"to_json",
|
29
|
+
"ensure_json",
|
23
30
|
]
|
wandb/_pydantic/base.py
CHANGED
@@ -4,9 +4,10 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar
|
6
6
|
|
7
|
-
from pydantic import BaseModel, ConfigDict, Field, Json
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, Json, StrictStr
|
8
8
|
from typing_extensions import Annotated, TypedDict, Unpack, override
|
9
9
|
|
10
|
+
from .utils import IS_PYDANTIC_V2, to_json
|
10
11
|
from .v1_compat import PydanticCompatMixin
|
11
12
|
|
12
13
|
if TYPE_CHECKING:
|
@@ -36,9 +37,14 @@ MODEL_DUMP_DEFAULTS = ModelDumpKwargs(
|
|
36
37
|
)
|
37
38
|
|
38
39
|
|
40
|
+
# v1-compatible base class for pydantic types.
|
41
|
+
class CompatBaseModel(PydanticCompatMixin, BaseModel):
|
42
|
+
__doc__ = None # Prevent subclasses from inheriting the BaseModel docstring
|
43
|
+
|
44
|
+
|
39
45
|
# Base class for all generated classes/types.
|
40
46
|
# Omitted from docstring to avoid inclusion in generated docs.
|
41
|
-
class Base(
|
47
|
+
class Base(CompatBaseModel):
|
42
48
|
model_config = ConfigDict(
|
43
49
|
populate_by_name=True,
|
44
50
|
validate_assignment=True,
|
@@ -83,17 +89,48 @@ class GQLBase(Base):
|
|
83
89
|
# Reusable annotations for field types
|
84
90
|
T = TypeVar("T")
|
85
91
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
92
|
+
if IS_PYDANTIC_V2:
|
93
|
+
GQLId = Annotated[
|
94
|
+
StrictStr,
|
95
|
+
Field(repr=False, frozen=True),
|
96
|
+
]
|
97
|
+
else:
|
98
|
+
# FIXME: Find a way to fix this for pydantic v1, which doesn't like when
|
99
|
+
# `Field(...)` used in the field assignment AND `Annotated[...]`.
|
100
|
+
# This is a problem for codegen, which can currently outputs e.g.
|
101
|
+
#
|
102
|
+
# class MyModel(GQLBase):
|
103
|
+
# my_id: GQLId = Field(alias="myID")
|
104
|
+
#
|
105
|
+
GQLId = StrictStr # type: ignore[misc]
|
90
106
|
|
91
107
|
Typename = Annotated[
|
92
108
|
T,
|
93
|
-
Field(repr=False, alias="__typename"
|
109
|
+
Field(repr=False, frozen=True, alias="__typename"),
|
94
110
|
]
|
95
111
|
|
96
112
|
|
113
|
+
def ensure_json(v: Any) -> Any:
|
114
|
+
"""In case the incoming value isn't serialized JSON, reserialize it.
|
115
|
+
|
116
|
+
This lets us use `Json[...]` fields with values that are already deserialized.
|
117
|
+
"""
|
118
|
+
# NOTE: Assumes that the deserialized type is not itself a string.
|
119
|
+
# Revisit this if we need to support deserialized types that are str/bytes.
|
120
|
+
return v if isinstance(v, (str, bytes)) else to_json(v)
|
121
|
+
|
122
|
+
|
123
|
+
if IS_PYDANTIC_V2 or TYPE_CHECKING:
|
124
|
+
from pydantic import BeforeValidator
|
125
|
+
|
126
|
+
SerializedToJson = Annotated[
|
127
|
+
Json[T],
|
128
|
+
# Allow lenient instantiation/validation: incoming data may already be deserialized.
|
129
|
+
BeforeValidator(ensure_json),
|
130
|
+
]
|
131
|
+
else:
|
132
|
+
SerializedToJson = Json[T] # type: ignore[misc]
|
133
|
+
|
97
134
|
# FIXME: Restore, modify, or replace this later after ensuring pydantic v1 compatibility.
|
98
135
|
# def validate_maybe_json(v: Any, handler: ValidatorFunctionWrapHandler) -> Any:
|
99
136
|
# """Wraps default Json[...] field validator to allow instantiation with an already-decoded value."""
|
@@ -109,5 +146,3 @@ Typename = Annotated[
|
|
109
146
|
# # Allow lenient instantiation/validation: incoming data may already be deserialized.
|
110
147
|
# WrapValidator(validate_maybe_json),
|
111
148
|
# ]
|
112
|
-
|
113
|
-
SerializedToJson = Json[T]
|
wandb/_pydantic/utils.py
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
"""Internal utilities for working with Pydantic types and data."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import json
|
6
|
+
import sys
|
7
|
+
from contextlib import suppress
|
8
|
+
from typing import Any, Type
|
9
|
+
|
10
|
+
import pydantic
|
11
|
+
from pydantic import BaseModel, ValidationError
|
12
|
+
from typing_extensions import TypeAlias
|
13
|
+
|
14
|
+
PYTHON_VERSION = sys.version_info
|
15
|
+
|
16
|
+
pydantic_major, *_ = pydantic.VERSION.split(".")
|
17
|
+
IS_PYDANTIC_V2: bool = int(pydantic_major) >= 2
|
18
|
+
|
19
|
+
|
20
|
+
BaseModelType: TypeAlias = Type[BaseModel]
|
21
|
+
|
22
|
+
|
23
|
+
if IS_PYDANTIC_V2:
|
24
|
+
import pydantic_core # pydantic_core is only installed by pydantic v2
|
25
|
+
|
26
|
+
def to_json(v: Any) -> str:
|
27
|
+
"""Serialize a Python object to a JSON string."""
|
28
|
+
return pydantic_core.to_json(v, by_alias=True, round_trip=True).decode("utf-8")
|
29
|
+
|
30
|
+
def pydantic_isinstance(
|
31
|
+
v: Any, classinfo: BaseModelType | tuple[BaseModelType, ...]
|
32
|
+
) -> bool:
|
33
|
+
"""Return True if the object could be parsed into the given Pydantic type.
|
34
|
+
|
35
|
+
This is like a more lenient version of `isinstance()` for use with Pydantic.
|
36
|
+
In Pydantic v2, should be fast since the underlying implementation is in Rust,
|
37
|
+
and it may be preferable over `try:...except ValidationError:...`.
|
38
|
+
|
39
|
+
See: https://docs.pydantic.dev/latest/api/pydantic_core/#pydantic_core.SchemaValidator.isinstance_python
|
40
|
+
"""
|
41
|
+
if isinstance(classinfo, tuple):
|
42
|
+
return any(
|
43
|
+
cls.__pydantic_validator__.isinstance_python(v) for cls in classinfo
|
44
|
+
)
|
45
|
+
cls = classinfo
|
46
|
+
return cls.__pydantic_validator__.isinstance_python(v)
|
47
|
+
|
48
|
+
else:
|
49
|
+
# Pydantic v1 fallback implementations.
|
50
|
+
# These may be noticeably slower, but their primary goal is to ensure
|
51
|
+
# compatibility with Pydantic v1 so long as we need to support it.
|
52
|
+
|
53
|
+
from pydantic.json import pydantic_encoder # Only valid in pydantic v1
|
54
|
+
|
55
|
+
def to_json(v: Any) -> str:
|
56
|
+
return json.dumps(v, default=pydantic_encoder)
|
57
|
+
|
58
|
+
def pydantic_isinstance(
|
59
|
+
v: Any, classinfo: BaseModelType | tuple[BaseModelType, ...]
|
60
|
+
) -> bool:
|
61
|
+
classes = classinfo if isinstance(classinfo, tuple) else (classinfo,)
|
62
|
+
for cls in classes:
|
63
|
+
with suppress(ValidationError):
|
64
|
+
cls.model_validate(v)
|
65
|
+
return True
|
66
|
+
return False
|
wandb/_pydantic/v1_compat.py
CHANGED
@@ -2,26 +2,29 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
import
|
6
|
-
from
|
7
|
-
from
|
8
|
-
|
9
|
-
|
10
|
-
Callable,
|
11
|
-
ClassVar,
|
12
|
-
Literal,
|
13
|
-
Mapping,
|
14
|
-
TypeVar,
|
15
|
-
overload,
|
16
|
-
)
|
5
|
+
import json
|
6
|
+
from functools import lru_cache
|
7
|
+
from inspect import signature
|
8
|
+
from operator import attrgetter
|
9
|
+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Literal, overload
|
17
10
|
|
18
11
|
import pydantic
|
19
|
-
|
12
|
+
|
13
|
+
from .utils import IS_PYDANTIC_V2, to_json
|
20
14
|
|
21
15
|
if TYPE_CHECKING:
|
22
16
|
from typing import Protocol
|
23
17
|
|
24
18
|
class V1Model(Protocol):
|
19
|
+
# ------------------------------------------------------------------------------
|
20
|
+
# NOTE: These aren't part of the original v1 BaseModel spec, but were added as
|
21
|
+
# internal helpers and are (re-)declared here to satisfy mypy checks.
|
22
|
+
@classmethod
|
23
|
+
def _dump_json_vals(cls, values: dict, by_alias: bool) -> dict: ...
|
24
|
+
|
25
|
+
# ------------------------------------------------------------------------------
|
26
|
+
# These methods are part of the original v1 BaseModel spec.
|
27
|
+
|
25
28
|
__config__: ClassVar[type]
|
26
29
|
__fields__: ClassVar[dict[str, Any]]
|
27
30
|
__fields_set__: set[str]
|
@@ -34,20 +37,10 @@ if TYPE_CHECKING:
|
|
34
37
|
def parse_obj(cls, *args: Any, **kwargs: Any) -> V1Model: ...
|
35
38
|
@classmethod
|
36
39
|
def parse_raw(cls, *args: Any, **kwargs: Any) -> V1Model: ...
|
37
|
-
def dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...
|
38
|
-
def json(self, *args: Any, **kwargs: Any) -> str: ...
|
39
|
-
def copy(self, *args: Any, **kwargs: Any) -> V1Model: ...
|
40
|
-
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
IS_PYDANTIC_V2: bool = int(pydantic_major_version) >= 2
|
46
|
-
|
47
|
-
|
48
|
-
ModelT = TypeVar("ModelT")
|
49
|
-
RT = TypeVar("RT")
|
50
|
-
P = ParamSpec("P")
|
41
|
+
def dict(self, **kwargs: Any) -> dict[str, Any]: ...
|
42
|
+
def json(self, **kwargs: Any) -> str: ...
|
43
|
+
def copy(self, **kwargs: Any) -> V1Model: ...
|
51
44
|
|
52
45
|
|
53
46
|
# Maps {v2 -> v1} model config keys that were renamed in v2.
|
@@ -66,11 +59,17 @@ _V1_CONFIG_KEYS = {
|
|
66
59
|
}
|
67
60
|
|
68
61
|
|
69
|
-
def
|
70
|
-
"""Return a copy of the v2 ConfigDict with renamed v1 keys."""
|
62
|
+
def convert_v2_config(v2_config: dict[str, Any]) -> dict[str, Any]:
|
63
|
+
"""Internal helper: Return a copy of the v2 ConfigDict with renamed v1 keys."""
|
71
64
|
return {_V1_CONFIG_KEYS.get(k, k): v for k, v in v2_config.items()}
|
72
65
|
|
73
66
|
|
67
|
+
@lru_cache(maxsize=None) # Reduce repeat introspection via `signature()`
|
68
|
+
def allowed_arg_names(func: Callable) -> set[str]:
|
69
|
+
"""Internal helper: Return the names of args accepted by the given function."""
|
70
|
+
return set(signature(func).parameters)
|
71
|
+
|
72
|
+
|
74
73
|
# Pydantic BaseModels are defined with a custom metaclass, but its namespace
|
75
74
|
# has changed between pydantic versions.
|
76
75
|
#
|
@@ -87,28 +86,22 @@ class V1MixinMetaclass(PydanticModelMetaclass):
|
|
87
86
|
namespace: dict[str, Any],
|
88
87
|
**kwargs: Any,
|
89
88
|
):
|
90
|
-
#
|
91
|
-
#
|
92
|
-
# class MyModel(BaseModel):
|
89
|
+
# In the class definition, convert the model config, if any:
|
90
|
+
# # BEFORE
|
91
|
+
# class MyModel(BaseModel): # v2 model with `ConfigDict`
|
93
92
|
# model_config = ConfigDict(populate_by_name=True)
|
94
93
|
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
# class MyModel(BaseModel):
|
94
|
+
# # AFTER
|
95
|
+
# class MyModel(BaseModel): # v1 model with inner `Config` class
|
98
96
|
# class Config:
|
99
97
|
# allow_population_by_field_name = True
|
100
|
-
#
|
101
98
|
if config_dict := namespace.pop("model_config", None):
|
102
|
-
namespace["Config"] = type("Config", (),
|
99
|
+
namespace["Config"] = type("Config", (), convert_v2_config(config_dict))
|
103
100
|
return super().__new__(cls, name, bases, namespace, **kwargs)
|
104
101
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
@property
|
110
|
-
def model_fields(self) -> dict[str, Any]:
|
111
|
-
return self.__fields__
|
102
|
+
@property
|
103
|
+
def model_fields(self) -> dict[str, Any]:
|
104
|
+
return self.__fields__
|
112
105
|
|
113
106
|
|
114
107
|
# Mixin to ensure compatibility of Pydantic models if Pydantic v1 is detected.
|
@@ -118,6 +111,23 @@ class V1MixinMetaclass(PydanticModelMetaclass):
|
|
118
111
|
# Whenever possible, users should strongly prefer upgrading to Pydantic v2 to
|
119
112
|
# ensure full compatibility.
|
120
113
|
class V1Mixin(metaclass=V1MixinMetaclass):
|
114
|
+
# Internal compat helpers
|
115
|
+
@classmethod
|
116
|
+
def _dump_json_vals(cls, values: dict[str, Any], by_alias: bool) -> dict[str, Any]:
|
117
|
+
"""Reserialize values from `Json`-typed fields after dumping the model to dict."""
|
118
|
+
# Get the expected keys (after `.model_dump()`) for `Json`-typed fields.
|
119
|
+
# Note: In v1, `Json` fields have `ModelField.parse_json == True`
|
120
|
+
json_fields = (f for f in cls.__fields__.values() if f.parse_json)
|
121
|
+
get_key = attrgetter("alias" if by_alias else "name")
|
122
|
+
json_field_keys = set(map(get_key, json_fields))
|
123
|
+
|
124
|
+
return {
|
125
|
+
# Only serialize `Json` fields with non-null values.
|
126
|
+
k: to_json(v) if ((v is not None) and (k in json_field_keys)) else v
|
127
|
+
for k, v in values.items()
|
128
|
+
}
|
129
|
+
|
130
|
+
# ------------------------------------------------------------------------------
|
121
131
|
@classmethod
|
122
132
|
def __try_update_forward_refs__(cls: type[V1Model], **localns: Any) -> None:
|
123
133
|
if hasattr(sup := super(), "__try_update_forward_refs__"):
|
@@ -139,23 +149,35 @@ class V1Mixin(metaclass=V1MixinMetaclass):
|
|
139
149
|
def model_validate_json(cls, *args: Any, **kwargs: Any) -> V1Model:
|
140
150
|
return cls.parse_raw(*args, **kwargs)
|
141
151
|
|
142
|
-
def model_dump(self: V1Model,
|
143
|
-
|
152
|
+
def model_dump(self: V1Model, **kwargs: Any) -> dict[str, Any]:
|
153
|
+
# Pass only kwargs that are allowed in the V1 method.
|
154
|
+
allowed_keys = allowed_arg_names(self.dict) & kwargs.keys()
|
155
|
+
dict_ = self.dict(**{k: kwargs[k] for k in allowed_keys})
|
156
|
+
|
157
|
+
# Ugly hack: Try to serialize `Json` fields correctly when `round_trip=True` in pydantic v1
|
158
|
+
if kwargs.get("round_trip", False):
|
159
|
+
by_alias: bool = kwargs.get("by_alias", False)
|
160
|
+
return self._dump_json_vals(dict_, by_alias=by_alias)
|
161
|
+
|
162
|
+
return dict_
|
144
163
|
|
145
|
-
def model_dump_json(self: V1Model,
|
146
|
-
|
164
|
+
def model_dump_json(self: V1Model, **kwargs: Any) -> str:
|
165
|
+
# Pass only kwargs that are allowed in the V1 method.
|
166
|
+
allowed_keys = allowed_arg_names(self.json) & kwargs.keys()
|
167
|
+
json_ = self.json(**{k: kwargs[k] for k in allowed_keys})
|
147
168
|
|
148
|
-
|
149
|
-
|
169
|
+
# Ugly hack: Try to serialize `Json` fields correctly when `round_trip=True` in pydantic v1
|
170
|
+
if kwargs.get("round_trip", False):
|
171
|
+
by_alias: bool = kwargs.get("by_alias", False)
|
172
|
+
dict_ = json.loads(json_)
|
173
|
+
return json.dumps(self._dump_json_vals(dict_, by_alias=by_alias))
|
150
174
|
|
151
|
-
|
152
|
-
# versions, so this will have to do until changes are needed.
|
153
|
-
if (3, 9) <= PYTHON_VERSION < (3, 13):
|
175
|
+
return json_
|
154
176
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
177
|
+
def model_copy(self: V1Model, **kwargs: Any) -> V1Model:
|
178
|
+
# Pass only kwargs that are allowed in the V1 method.
|
179
|
+
allowed_keys = allowed_arg_names(self.copy) & kwargs.keys()
|
180
|
+
return self.copy(**{k: kwargs[k] for k in allowed_keys})
|
159
181
|
|
160
182
|
@property
|
161
183
|
def model_fields_set(self: V1Model) -> set[str]:
|
wandb/apis/public/__init__.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
from wandb.apis.public.api import Api, RetryingClient, requests
|
2
2
|
from wandb.apis.public.artifacts import (
|
3
|
-
ARTIFACT_FILES_FRAGMENT,
|
4
|
-
ARTIFACTS_TYPES_FRAGMENT,
|
5
3
|
ArtifactCollection,
|
6
4
|
ArtifactCollections,
|
7
5
|
ArtifactFiles,
|
@@ -10,8 +8,10 @@ from wandb.apis.public.artifacts import (
|
|
10
8
|
ArtifactTypes,
|
11
9
|
RunArtifacts,
|
12
10
|
)
|
11
|
+
from wandb.apis.public.automations import Automations
|
13
12
|
from wandb.apis.public.files import FILE_FRAGMENT, File, Files
|
14
13
|
from wandb.apis.public.history import HistoryScan, SampledHistoryScan
|
14
|
+
from wandb.apis.public.integrations import SlackIntegrations, WebhookIntegrations
|
15
15
|
from wandb.apis.public.jobs import (
|
16
16
|
Job,
|
17
17
|
QueuedRun,
|
wandb/apis/public/api.py
CHANGED
@@ -15,7 +15,7 @@ import json
|
|
15
15
|
import logging
|
16
16
|
import os
|
17
17
|
import urllib
|
18
|
-
from typing import Any, Dict, List, Optional
|
18
|
+
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional
|
19
19
|
|
20
20
|
import requests
|
21
21
|
from wandb_gql import Client, gql
|
@@ -32,15 +32,19 @@ from wandb.apis.public.utils import (
|
|
32
32
|
fetch_org_from_settings_or_entity,
|
33
33
|
parse_org_from_registry_path,
|
34
34
|
)
|
35
|
+
from wandb.proto.wandb_deprecated import Deprecated
|
35
36
|
from wandb.proto.wandb_internal_pb2 import ServerFeature
|
36
37
|
from wandb.sdk.artifacts._validators import is_artifact_registry_project
|
37
38
|
from wandb.sdk.internal.internal_api import Api as InternalApi
|
38
39
|
from wandb.sdk.internal.thread_local_settings import _thread_local_api_settings
|
39
40
|
from wandb.sdk.launch.utils import LAUNCH_DEFAULT_PROJECT
|
40
41
|
from wandb.sdk.lib import retry, runid
|
41
|
-
from wandb.sdk.lib.deprecate import
|
42
|
+
from wandb.sdk.lib.deprecate import deprecate
|
42
43
|
from wandb.sdk.lib.gql_request import GraphQLSession
|
43
44
|
|
45
|
+
if TYPE_CHECKING:
|
46
|
+
from wandb.automations import Integration, SlackIntegration, WebhookIntegration
|
47
|
+
|
44
48
|
logger = logging.getLogger(__name__)
|
45
49
|
|
46
50
|
|
@@ -1517,3 +1521,111 @@ class Api:
|
|
1517
1521
|
self.settings, self.default_entity
|
1518
1522
|
)
|
1519
1523
|
return Registries(self.client, organization, filter)
|
1524
|
+
|
1525
|
+
def integrations(
|
1526
|
+
self,
|
1527
|
+
entity: Optional[str] = None,
|
1528
|
+
*,
|
1529
|
+
per_page: int = 50,
|
1530
|
+
) -> Iterator["Integration"]:
|
1531
|
+
"""Return an iterator of all integrations for an entity.
|
1532
|
+
|
1533
|
+
Args:
|
1534
|
+
entity (str, optional): The entity (e.g. team name) for which to
|
1535
|
+
fetch integrations. If not provided, the user's default entity
|
1536
|
+
will be used.
|
1537
|
+
per_page (int, optional): Number of integrations to fetch per page.
|
1538
|
+
Defaults to 50.
|
1539
|
+
|
1540
|
+
Yields:
|
1541
|
+
Iterator[SlackIntegration | WebhookIntegration]: An iterator of any supported integrations.
|
1542
|
+
"""
|
1543
|
+
from wandb.apis.public.integrations import Integrations
|
1544
|
+
|
1545
|
+
entity = entity or self.default_entity
|
1546
|
+
params = {"entityName": entity, "includeWebhook": True, "includeSlack": True}
|
1547
|
+
return Integrations(client=self.client, variables=params, per_page=per_page)
|
1548
|
+
|
1549
|
+
def webhook_integrations(
|
1550
|
+
self, entity: Optional[str] = None, *, per_page: int = 50
|
1551
|
+
) -> Iterator["WebhookIntegration"]:
|
1552
|
+
"""Return an iterator of webhook integrations for an entity.
|
1553
|
+
|
1554
|
+
Args:
|
1555
|
+
entity (str, optional): The entity (e.g. team name) for which to
|
1556
|
+
fetch integrations. If not provided, the user's default entity
|
1557
|
+
will be used.
|
1558
|
+
per_page (int, optional): Number of integrations to fetch per page.
|
1559
|
+
Defaults to 50.
|
1560
|
+
|
1561
|
+
Yields:
|
1562
|
+
Iterator[WebhookIntegration]: An iterator of webhook integrations.
|
1563
|
+
|
1564
|
+
Examples:
|
1565
|
+
Get all registered webhook integrations for the team "my-team":
|
1566
|
+
```python
|
1567
|
+
import wandb
|
1568
|
+
|
1569
|
+
api = wandb.Api()
|
1570
|
+
webhook_integrations = api.webhook_integrations(entity="my-team")
|
1571
|
+
```
|
1572
|
+
|
1573
|
+
Find only webhook integrations that post requests to "https://my-fake-url.com":
|
1574
|
+
```python
|
1575
|
+
webhook_integrations = api.webhook_integrations(entity="my-team")
|
1576
|
+
my_webhooks = [
|
1577
|
+
ig
|
1578
|
+
for ig in webhook_integrations
|
1579
|
+
if ig.url_endpoint.startswith("https://my-fake-url.com")
|
1580
|
+
]
|
1581
|
+
```
|
1582
|
+
"""
|
1583
|
+
from wandb.apis.public.integrations import WebhookIntegrations
|
1584
|
+
|
1585
|
+
entity = entity or self.default_entity
|
1586
|
+
params = {"entityName": entity, "includeWebhook": True}
|
1587
|
+
return WebhookIntegrations(
|
1588
|
+
client=self.client, variables=params, per_page=per_page
|
1589
|
+
)
|
1590
|
+
|
1591
|
+
def slack_integrations(
|
1592
|
+
self, entity: Optional[str] = None, *, per_page: int = 50
|
1593
|
+
) -> Iterator["SlackIntegration"]:
|
1594
|
+
"""Return an iterator of Slack integrations for an entity.
|
1595
|
+
|
1596
|
+
Args:
|
1597
|
+
entity (str, optional): The entity (e.g. team name) for which to
|
1598
|
+
fetch integrations. If not provided, the user's default entity
|
1599
|
+
will be used.
|
1600
|
+
per_page (int, optional): Number of integrations to fetch per page.
|
1601
|
+
Defaults to 50.
|
1602
|
+
|
1603
|
+
Yields:
|
1604
|
+
Iterator[SlackIntegration]: An iterator of Slack integrations.
|
1605
|
+
|
1606
|
+
Examples:
|
1607
|
+
Get all registered Slack integrations for the team "my-team":
|
1608
|
+
```python
|
1609
|
+
import wandb
|
1610
|
+
|
1611
|
+
api = wandb.Api()
|
1612
|
+
slack_integrations = api.slack_integrations(entity="my-team")
|
1613
|
+
```
|
1614
|
+
|
1615
|
+
Find only Slack integrations that post to channel names starting with "team-alerts-":
|
1616
|
+
```python
|
1617
|
+
slack_integrations = api.slack_integrations(entity="my-team")
|
1618
|
+
team_alert_integrations = [
|
1619
|
+
ig
|
1620
|
+
for ig in slack_integrations
|
1621
|
+
if ig.channel_name.startswith("team-alerts-")
|
1622
|
+
]
|
1623
|
+
```
|
1624
|
+
"""
|
1625
|
+
from wandb.apis.public.integrations import SlackIntegrations
|
1626
|
+
|
1627
|
+
entity = entity or self.default_entity
|
1628
|
+
params = {"entityName": entity, "includeSlack": True}
|
1629
|
+
return SlackIntegrations(
|
1630
|
+
client=self.client, variables=params, per_page=per_page
|
1631
|
+
)
|