wandb 0.19.8__py3-none-win32.whl → 0.19.10__py3-none-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. wandb/__init__.py +5 -1
  2. wandb/__init__.pyi +15 -8
  3. wandb/_pydantic/__init__.py +30 -0
  4. wandb/_pydantic/base.py +148 -0
  5. wandb/_pydantic/utils.py +66 -0
  6. wandb/_pydantic/v1_compat.py +284 -0
  7. wandb/apis/paginator.py +82 -38
  8. wandb/apis/public/__init__.py +2 -2
  9. wandb/apis/public/api.py +111 -53
  10. wandb/apis/public/artifacts.py +387 -639
  11. wandb/apis/public/automations.py +69 -0
  12. wandb/apis/public/files.py +2 -2
  13. wandb/apis/public/integrations.py +168 -0
  14. wandb/apis/public/projects.py +32 -2
  15. wandb/apis/public/reports.py +2 -2
  16. wandb/apis/public/runs.py +19 -11
  17. wandb/apis/public/utils.py +107 -1
  18. wandb/automations/__init__.py +81 -0
  19. wandb/automations/_filters/__init__.py +40 -0
  20. wandb/automations/_filters/expressions.py +179 -0
  21. wandb/automations/_filters/operators.py +267 -0
  22. wandb/automations/_filters/run_metrics.py +183 -0
  23. wandb/automations/_generated/__init__.py +184 -0
  24. wandb/automations/_generated/create_filter_trigger.py +21 -0
  25. wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
  26. wandb/automations/_generated/delete_trigger.py +19 -0
  27. wandb/automations/_generated/enums.py +33 -0
  28. wandb/automations/_generated/fragments.py +343 -0
  29. wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
  30. wandb/automations/_generated/get_triggers.py +24 -0
  31. wandb/automations/_generated/get_triggers_by_entity.py +24 -0
  32. wandb/automations/_generated/input_types.py +104 -0
  33. wandb/automations/_generated/integrations_by_entity.py +22 -0
  34. wandb/automations/_generated/operations.py +710 -0
  35. wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
  36. wandb/automations/_generated/update_filter_trigger.py +21 -0
  37. wandb/automations/_utils.py +123 -0
  38. wandb/automations/_validators.py +73 -0
  39. wandb/automations/actions.py +205 -0
  40. wandb/automations/automations.py +109 -0
  41. wandb/automations/events.py +235 -0
  42. wandb/automations/integrations.py +26 -0
  43. wandb/automations/scopes.py +76 -0
  44. wandb/beta/workflows.py +9 -10
  45. wandb/bin/gpu_stats.exe +0 -0
  46. wandb/bin/wandb-core +0 -0
  47. wandb/cli/cli.py +3 -3
  48. wandb/integration/keras/keras.py +2 -1
  49. wandb/integration/langchain/wandb_tracer.py +2 -1
  50. wandb/integration/metaflow/metaflow.py +19 -17
  51. wandb/integration/sacred/__init__.py +1 -1
  52. wandb/jupyter.py +155 -133
  53. wandb/old/summary.py +0 -2
  54. wandb/proto/v3/wandb_internal_pb2.py +297 -292
  55. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  56. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  57. wandb/proto/v4/wandb_internal_pb2.py +292 -292
  58. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  59. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  60. wandb/proto/v5/wandb_internal_pb2.py +292 -292
  61. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  62. wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
  63. wandb/proto/v6/wandb_base_pb2.py +41 -0
  64. wandb/proto/v6/wandb_internal_pb2.py +393 -0
  65. wandb/proto/v6/wandb_server_pb2.py +78 -0
  66. wandb/proto/v6/wandb_settings_pb2.py +58 -0
  67. wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
  68. wandb/proto/wandb_base_pb2.py +2 -0
  69. wandb/proto/wandb_deprecated.py +10 -0
  70. wandb/proto/wandb_internal_pb2.py +3 -1
  71. wandb/proto/wandb_server_pb2.py +2 -0
  72. wandb/proto/wandb_settings_pb2.py +2 -0
  73. wandb/proto/wandb_telemetry_pb2.py +2 -0
  74. wandb/sdk/artifacts/_generated/__init__.py +248 -0
  75. wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
  76. wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
  77. wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
  78. wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
  79. wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
  80. wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
  81. wandb/sdk/artifacts/_generated/enums.py +17 -0
  82. wandb/sdk/artifacts/_generated/fragments.py +186 -0
  83. wandb/sdk/artifacts/_generated/input_types.py +16 -0
  84. wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
  85. wandb/sdk/artifacts/_generated/operations.py +510 -0
  86. wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
  87. wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
  88. wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
  89. wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
  90. wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
  91. wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
  92. wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
  93. wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
  94. wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
  95. wandb/sdk/artifacts/_graphql_fragments.py +56 -81
  96. wandb/sdk/artifacts/_validators.py +1 -0
  97. wandb/sdk/artifacts/artifact.py +110 -49
  98. wandb/sdk/artifacts/artifact_manifest_entry.py +2 -1
  99. wandb/sdk/artifacts/artifact_saver.py +16 -2
  100. wandb/sdk/artifacts/storage_handlers/azure_handler.py +1 -0
  101. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +23 -2
  102. wandb/sdk/data_types/audio.py +1 -3
  103. wandb/sdk/data_types/base_types/media.py +13 -7
  104. wandb/sdk/data_types/base_types/wb_value.py +34 -11
  105. wandb/sdk/data_types/html.py +36 -9
  106. wandb/sdk/data_types/image.py +56 -37
  107. wandb/sdk/data_types/molecule.py +1 -5
  108. wandb/sdk/data_types/object_3d.py +2 -1
  109. wandb/sdk/data_types/saved_model.py +7 -9
  110. wandb/sdk/data_types/table.py +5 -0
  111. wandb/sdk/data_types/trace_tree.py +2 -0
  112. wandb/sdk/data_types/utils.py +1 -1
  113. wandb/sdk/data_types/video.py +15 -30
  114. wandb/sdk/interface/interface.py +2 -0
  115. wandb/{apis/public → sdk/internal}/_generated/__init__.py +0 -6
  116. wandb/{apis/public → sdk/internal}/_generated/server_features_query.py +3 -3
  117. wandb/sdk/internal/internal_api.py +138 -47
  118. wandb/sdk/internal/profiler.py +6 -5
  119. wandb/sdk/internal/run.py +13 -6
  120. wandb/sdk/internal/sender.py +2 -0
  121. wandb/sdk/internal/sender_config.py +8 -11
  122. wandb/sdk/internal/settings_static.py +24 -2
  123. wandb/sdk/lib/apikey.py +40 -20
  124. wandb/sdk/lib/asyncio_compat.py +1 -1
  125. wandb/sdk/lib/deprecate.py +13 -22
  126. wandb/sdk/lib/disabled.py +2 -1
  127. wandb/sdk/lib/printer.py +37 -8
  128. wandb/sdk/lib/printer_asyncio.py +46 -0
  129. wandb/sdk/lib/redirect.py +10 -5
  130. wandb/sdk/lib/run_moment.py +4 -6
  131. wandb/sdk/lib/wb_logging.py +161 -0
  132. wandb/sdk/service/server_sock.py +19 -14
  133. wandb/sdk/service/service.py +9 -7
  134. wandb/sdk/service/streams.py +5 -0
  135. wandb/sdk/verify/verify.py +6 -3
  136. wandb/sdk/wandb_config.py +44 -43
  137. wandb/sdk/wandb_init.py +323 -141
  138. wandb/sdk/wandb_login.py +13 -4
  139. wandb/sdk/wandb_metadata.py +107 -91
  140. wandb/sdk/wandb_run.py +529 -325
  141. wandb/sdk/wandb_settings.py +422 -202
  142. wandb/sdk/wandb_setup.py +52 -1
  143. wandb/util.py +29 -29
  144. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/METADATA +7 -7
  145. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/RECORD +151 -94
  146. wandb/_globals.py +0 -19
  147. wandb/apis/public/_generated/base.py +0 -128
  148. wandb/apis/public/_generated/typing_compat.py +0 -14
  149. /wandb/{apis/public → sdk/internal}/_generated/enums.py +0 -0
  150. /wandb/{apis/public → sdk/internal}/_generated/input_types.py +0 -0
  151. /wandb/{apis/public → sdk/internal}/_generated/operations.py +0 -0
  152. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/WHEEL +0 -0
  153. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/entry_points.txt +0 -0
  154. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/licenses/LICENSE +0 -0
wandb/apis/paginator.py CHANGED
@@ -1,75 +1,103 @@
1
- from typing import TYPE_CHECKING, Any, MutableMapping, Optional
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ ClassVar,
8
+ Iterator,
9
+ Mapping,
10
+ Protocol,
11
+ Sized,
12
+ TypeVar,
13
+ overload,
14
+ )
2
15
 
3
16
  if TYPE_CHECKING:
4
- from wandb_gql import Client
17
+ from wandb_graphql.language.ast import Document
18
+
19
+ T = TypeVar("T")
20
+
21
+
22
+ # Structural type hint for the client instance
23
+ class _Client(Protocol):
24
+ def execute(self, *args: Any, **kwargs: Any) -> dict[str, Any]: ...
25
+
5
26
 
27
+ class Paginator(Iterator[T]):
28
+ """An iterator for paginated objects from GraphQL requests."""
6
29
 
7
- class Paginator:
8
- QUERY = None
30
+ QUERY: ClassVar[Document | None] = None
9
31
 
10
32
  def __init__(
11
33
  self,
12
- client: "Client",
13
- variables: MutableMapping[str, Any],
14
- per_page: Optional[int] = None,
34
+ client: _Client,
35
+ variables: Mapping[str, Any],
36
+ per_page: int = 50, # We don't allow unbounded paging
15
37
  ):
16
- self.client = client
17
- self.variables = variables
18
- # We don't allow unbounded paging
19
- self.per_page = per_page
20
- if self.per_page is None:
21
- self.per_page = 50
22
- self.objects = []
23
- self.index = -1
24
- self.last_response = None
38
+ self.client: _Client = client
25
39
 
26
- def __iter__(self):
27
- self.index = -1
28
- return self
40
+ # shallow copy partly guards against mutating the original input
41
+ self.variables: dict[str, Any] = dict(variables)
29
42
 
30
- def __len__(self):
31
- if self.length is None:
32
- self._load_page()
33
- if self.length is None:
34
- raise ValueError("Object doesn't provide length")
35
- return self.length
43
+ self.per_page: int = per_page
44
+ self.objects: list[T] = []
45
+ self.index: int = -1
46
+ self.last_response: object | None = None
36
47
 
37
- @property
38
- def length(self):
39
- raise NotImplementedError
48
+ def __iter__(self) -> Iterator[T]:
49
+ self.index = -1
50
+ return self
40
51
 
41
52
  @property
42
- def more(self):
53
+ @abstractmethod
54
+ def more(self) -> bool:
55
+ """Whether there are more pages to be fetched."""
43
56
  raise NotImplementedError
44
57
 
45
58
  @property
46
- def cursor(self):
59
+ @abstractmethod
60
+ def cursor(self) -> str | None:
61
+ """The start cursor to use for the next fetched page."""
47
62
  raise NotImplementedError
48
63
 
49
- def convert_objects(self):
64
+ @abstractmethod
65
+ def convert_objects(self) -> list[T]:
66
+ """Convert the last fetched response data into the iterated objects."""
50
67
  raise NotImplementedError
51
68
 
52
- def update_variables(self):
69
+ def update_variables(self) -> None:
70
+ """Update the query variables for the next page fetch."""
53
71
  self.variables.update({"perPage": self.per_page, "cursor": self.cursor})
54
72
 
55
- def _load_page(self):
56
- if not self.more:
57
- return False
58
- self.update_variables()
73
+ def _update_response(self) -> None:
74
+ """Fetch and store the response data for the next page."""
59
75
  self.last_response = self.client.execute(
60
76
  self.QUERY, variable_values=self.variables
61
77
  )
78
+
79
+ def _load_page(self) -> bool:
80
+ """Fetch the next page, if any, returning True and storing the response if there was one."""
81
+ if not self.more:
82
+ return False
83
+ self.update_variables()
84
+ self._update_response()
62
85
  self.objects.extend(self.convert_objects())
63
86
  return True
64
87
 
65
- def __getitem__(self, index):
88
+ @overload
89
+ def __getitem__(self, index: int) -> T: ...
90
+ @overload
91
+ def __getitem__(self, index: slice) -> list[T]: ...
92
+
93
+ def __getitem__(self, index: int | slice) -> T | list[T]:
66
94
  loaded = True
67
95
  stop = index.stop if isinstance(index, slice) else index
68
96
  while loaded and stop > len(self.objects) - 1:
69
97
  loaded = self._load_page()
70
98
  return self.objects[index]
71
99
 
72
- def __next__(self):
100
+ def __next__(self) -> T:
73
101
  self.index += 1
74
102
  if len(self.objects) <= self.index:
75
103
  if not self._load_page():
@@ -79,3 +107,19 @@ class Paginator:
79
107
  return self.objects[self.index]
80
108
 
81
109
  next = __next__
110
+
111
+
112
+ class SizedPaginator(Paginator[T], Sized):
113
+ """A Paginator for objects with a known total count."""
114
+
115
+ def __len__(self) -> int:
116
+ if self.length is None:
117
+ self._load_page()
118
+ if self.length is None:
119
+ raise ValueError("Object doesn't provide length")
120
+ return self.length
121
+
122
+ @property
123
+ @abstractmethod
124
+ def length(self) -> int | None:
125
+ raise NotImplementedError
@@ -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
@@ -25,7 +25,6 @@ import wandb
25
25
  from wandb import env, util
26
26
  from wandb.apis import public
27
27
  from wandb.apis.normalize import normalize_exceptions
28
- from wandb.apis.public._generated import SERVER_FEATURES_QUERY_GQL, ServerFeaturesQuery
29
28
  from wandb.apis.public.const import RETRY_TIMEDELTA
30
29
  from wandb.apis.public.registries import Registries
31
30
  from wandb.apis.public.utils import (
@@ -33,15 +32,19 @@ from wandb.apis.public.utils import (
33
32
  fetch_org_from_settings_or_entity,
34
33
  parse_org_from_registry_path,
35
34
  )
35
+ from wandb.proto.wandb_deprecated import Deprecated
36
36
  from wandb.proto.wandb_internal_pb2 import ServerFeature
37
37
  from wandb.sdk.artifacts._validators import is_artifact_registry_project
38
38
  from wandb.sdk.internal.internal_api import Api as InternalApi
39
39
  from wandb.sdk.internal.thread_local_settings import _thread_local_api_settings
40
40
  from wandb.sdk.launch.utils import LAUNCH_DEFAULT_PROJECT
41
41
  from wandb.sdk.lib import retry, runid
42
- from wandb.sdk.lib.deprecate import Deprecated, deprecate
42
+ from wandb.sdk.lib.deprecate import deprecate
43
43
  from wandb.sdk.lib.gql_request import GraphQLSession
44
44
 
45
+ if TYPE_CHECKING:
46
+ from wandb.automations import Integration, SlackIntegration, WebhookIntegration
47
+
45
48
  logger = logging.getLogger(__name__)
46
49
 
47
50
 
@@ -289,7 +292,7 @@ class Api:
289
292
  )
290
293
  )
291
294
  self._client = RetryingClient(self._base_client)
292
- self._server_features_cache = None
295
+ self._server_features_cache: Optional[dict[str, bool]] = None
293
296
 
294
297
  def create_project(self, name: str, entity: str) -> None:
295
298
  """Create a new project.
@@ -757,15 +760,14 @@ class Api:
757
760
  return parts
758
761
 
759
762
  def projects(
760
- self, entity: Optional[str] = None, per_page: Optional[int] = 200
763
+ self, entity: Optional[str] = None, per_page: int = 200
761
764
  ) -> "public.Projects":
762
765
  """Get projects for a given entity.
763
766
 
764
767
  Args:
765
768
  entity: (str) Name of the entity requested. If None, will fall back to the
766
769
  default entity passed to `Api`. If no default entity, will raise a `ValueError`.
767
- per_page: (int) Sets the page size for query pagination. None will use the default size.
768
- Usually there is no reason to change this.
770
+ per_page: (int) Sets the page size for query pagination. Usually there is no reason to change this.
769
771
 
770
772
  Returns:
771
773
  A `Projects` object which is an iterable collection of `Project` objects.
@@ -808,7 +810,7 @@ class Api:
808
810
  return public.Project(self.client, entity, name, {})
809
811
 
810
812
  def reports(
811
- self, path: str = "", name: Optional[str] = None, per_page: Optional[int] = 50
813
+ self, path: str = "", name: Optional[str] = None, per_page: int = 50
812
814
  ) -> "public.Reports":
813
815
  """Get reports for a given project path.
814
816
 
@@ -817,8 +819,7 @@ class Api:
817
819
  Args:
818
820
  path: (str) path to project the report resides in, should be in the form: "entity/project"
819
821
  name: (str, optional) optional name of the report requested.
820
- per_page: (int) Sets the page size for query pagination. None will use the default size.
821
- Usually there is no reason to change this.
822
+ per_page: (int) Sets the page size for query pagination. Usually there is no reason to change this.
822
823
 
823
824
  Returns:
824
825
  A `Reports` object which is an iterable collection of `BetaReport` objects.
@@ -1153,15 +1154,14 @@ class Api:
1153
1154
 
1154
1155
  @normalize_exceptions
1155
1156
  def artifact_collections(
1156
- self, project_name: str, type_name: str, per_page: Optional[int] = 50
1157
+ self, project_name: str, type_name: str, per_page: int = 50
1157
1158
  ) -> "public.ArtifactCollections":
1158
1159
  """Return a collection of matching artifact collections.
1159
1160
 
1160
1161
  Args:
1161
1162
  project_name: (str) The name of the project to filter on.
1162
1163
  type_name: (str) The name of the artifact type to filter on.
1163
- per_page: (int, optional) Sets the page size for query pagination. None will use the default size.
1164
- Usually there is no reason to change this.
1164
+ per_page: (int) Sets the page size for query pagination. Usually there is no reason to change this.
1165
1165
 
1166
1166
  Returns:
1167
1167
  An iterable `ArtifactCollections` object.
@@ -1226,7 +1226,7 @@ class Api:
1226
1226
  self,
1227
1227
  type_name: str,
1228
1228
  name: str,
1229
- per_page: Optional[int] = 50,
1229
+ per_page: int = 50,
1230
1230
  tags: Optional[List[str]] = None,
1231
1231
  ) -> "public.Artifacts":
1232
1232
  """Return an `Artifacts` collection from the given parameters.
@@ -1234,8 +1234,7 @@ class Api:
1234
1234
  Args:
1235
1235
  type_name: (str) The type of artifacts to fetch.
1236
1236
  name: (str) An artifact collection name. May be prefixed with entity/project.
1237
- per_page: (int, optional) Sets the page size for query pagination. None will use the default size.
1238
- Usually there is no reason to change this.
1237
+ per_page: (int) Sets the page size for query pagination. Usually there is no reason to change this.
1239
1238
  tags: (list[str], optional) Only return artifacts with all of these tags.
1240
1239
 
1241
1240
  Returns:
@@ -1510,7 +1509,7 @@ class Api:
1510
1509
  Returns:
1511
1510
  A registry iterator.
1512
1511
  """
1513
- if not self._check_server_feature_with_fallback(
1512
+ if not InternalApi()._check_server_feature_with_fallback(
1514
1513
  ServerFeature.ARTIFACT_REGISTRY_SEARCH
1515
1514
  ):
1516
1515
  raise RuntimeError(
@@ -1523,51 +1522,110 @@ class Api:
1523
1522
  )
1524
1523
  return Registries(self.client, organization, filter)
1525
1524
 
1526
- def _check_server_feature(self, feature: ServerFeature) -> bool:
1527
- """Check if a server feature is enabled.
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.
1528
1532
 
1529
1533
  Args:
1530
- feature (ServerFeature): The feature to check.
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
1531
1544
 
1532
- Returns:
1533
- bool: True if the feature is enabled, False otherwise.
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)
1534
1548
 
1535
- Raises:
1536
- Exception: If server doesn't support feature queries or other errors occur
1537
- """
1538
- if self._server_features_cache is None:
1539
- response = self.client.execute(gql(SERVER_FEATURES_QUERY_GQL))
1540
- self._server_features_cache = ServerFeaturesQuery.model_validate(response)
1541
-
1542
- feature_name = ServerFeature.Name(feature)
1543
- if (
1544
- self._server_features_cache
1545
- and self._server_features_cache.server_info
1546
- and self._server_features_cache.server_info.features
1547
- ):
1548
- for feature_info in self._server_features_cache.server_info.features:
1549
- if feature_info and feature_info.name == feature_name:
1550
- return feature_info.is_enabled
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.
1551
1560
 
1552
- return False
1561
+ Yields:
1562
+ Iterator[WebhookIntegration]: An iterator of webhook integrations.
1553
1563
 
1554
- def _check_server_feature_with_fallback(self, feature: ServerFeature) -> bool:
1555
- """Wrapper around check_server_feature that warns and returns False for older unsupported servers.
1564
+ Examples:
1565
+ Get all registered webhook integrations for the team "my-team":
1566
+ ```python
1567
+ import wandb
1556
1568
 
1557
- Good to use for features that have a fallback mechanism for older servers.
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.
1558
1595
 
1559
1596
  Args:
1560
- feature (ServerFeature): The feature to check.
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.
1561
1602
 
1562
- Returns:
1563
- bool: True if the feature is enabled, False otherwise.
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
+ ```
1564
1614
 
1565
- Exceptions:
1566
- Exception: If an error other than the server not supporting feature queries occurs.
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
+ ```
1567
1624
  """
1568
- try:
1569
- return self._check_server_feature(feature)
1570
- except Exception as e:
1571
- if 'Cannot query field "features" on type "ServerInfo".' in str(e):
1572
- return False
1573
- raise e
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
+ )