wandb 0.21.1__py3-none-musllinux_1_2_aarch64.whl → 0.21.3__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.
Files changed (94) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +1 -1
  3. wandb/apis/public/api.py +1 -2
  4. wandb/apis/public/artifacts.py +3 -5
  5. wandb/apis/public/registries/_utils.py +14 -16
  6. wandb/apis/public/registries/registries_search.py +176 -289
  7. wandb/apis/public/reports.py +13 -10
  8. wandb/automations/_generated/delete_automation.py +1 -3
  9. wandb/automations/_generated/enums.py +13 -11
  10. wandb/bin/gpu_stats +0 -0
  11. wandb/bin/wandb-core +0 -0
  12. wandb/cli/cli.py +47 -2
  13. wandb/integration/metaflow/data_pandas.py +2 -2
  14. wandb/integration/metaflow/data_pytorch.py +75 -0
  15. wandb/integration/metaflow/data_sklearn.py +76 -0
  16. wandb/integration/metaflow/metaflow.py +16 -87
  17. wandb/integration/weave/__init__.py +6 -0
  18. wandb/integration/weave/interface.py +49 -0
  19. wandb/integration/weave/weave.py +63 -0
  20. wandb/proto/v3/wandb_internal_pb2.py +3 -2
  21. wandb/proto/v4/wandb_internal_pb2.py +2 -2
  22. wandb/proto/v5/wandb_internal_pb2.py +2 -2
  23. wandb/proto/v6/wandb_internal_pb2.py +2 -2
  24. wandb/sdk/artifacts/_factories.py +17 -0
  25. wandb/sdk/artifacts/_generated/__init__.py +221 -13
  26. wandb/sdk/artifacts/_generated/artifact_by_id.py +17 -0
  27. wandb/sdk/artifacts/_generated/artifact_by_name.py +22 -0
  28. wandb/sdk/artifacts/_generated/artifact_collection_membership_file_urls.py +43 -0
  29. wandb/sdk/artifacts/_generated/artifact_created_by.py +47 -0
  30. wandb/sdk/artifacts/_generated/artifact_file_urls.py +22 -0
  31. wandb/sdk/artifacts/_generated/artifact_type.py +31 -0
  32. wandb/sdk/artifacts/_generated/artifact_used_by.py +43 -0
  33. wandb/sdk/artifacts/_generated/artifact_via_membership_by_name.py +26 -0
  34. wandb/sdk/artifacts/_generated/delete_artifact.py +28 -0
  35. wandb/sdk/artifacts/_generated/enums.py +5 -0
  36. wandb/sdk/artifacts/_generated/fetch_artifact_manifest.py +38 -0
  37. wandb/sdk/artifacts/_generated/fetch_registries.py +32 -0
  38. wandb/sdk/artifacts/_generated/fragments.py +279 -41
  39. wandb/sdk/artifacts/_generated/link_artifact.py +6 -0
  40. wandb/sdk/artifacts/_generated/operations.py +654 -51
  41. wandb/sdk/artifacts/_generated/registry_collections.py +34 -0
  42. wandb/sdk/artifacts/_generated/registry_versions.py +34 -0
  43. wandb/sdk/artifacts/_generated/unlink_artifact.py +25 -0
  44. wandb/sdk/artifacts/_graphql_fragments.py +3 -86
  45. wandb/sdk/artifacts/_validators.py +6 -4
  46. wandb/sdk/artifacts/artifact.py +410 -547
  47. wandb/sdk/artifacts/artifact_file_cache.py +11 -7
  48. wandb/sdk/artifacts/artifact_manifest.py +10 -9
  49. wandb/sdk/artifacts/artifact_manifest_entry.py +15 -18
  50. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +5 -3
  51. wandb/sdk/artifacts/storage_handlers/gcs_handler.py +1 -1
  52. wandb/sdk/artifacts/storage_handlers/http_handler.py +1 -1
  53. wandb/sdk/artifacts/storage_handlers/s3_handler.py +1 -1
  54. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +1 -1
  55. wandb/sdk/data_types/video.py +2 -2
  56. wandb/sdk/interface/interface_queue.py +1 -4
  57. wandb/sdk/interface/interface_shared.py +26 -37
  58. wandb/sdk/interface/interface_sock.py +24 -14
  59. wandb/sdk/internal/settings_static.py +2 -3
  60. wandb/sdk/launch/create_job.py +12 -1
  61. wandb/sdk/launch/inputs/internal.py +25 -24
  62. wandb/sdk/launch/inputs/schema.py +31 -1
  63. wandb/sdk/launch/runner/kubernetes_runner.py +24 -29
  64. wandb/sdk/lib/asyncio_compat.py +16 -16
  65. wandb/sdk/lib/asyncio_manager.py +252 -0
  66. wandb/sdk/lib/hashutil.py +13 -4
  67. wandb/sdk/lib/paths.py +23 -21
  68. wandb/sdk/lib/printer.py +2 -2
  69. wandb/sdk/lib/printer_asyncio.py +3 -1
  70. wandb/sdk/lib/retry.py +185 -78
  71. wandb/sdk/lib/service/service_client.py +106 -0
  72. wandb/sdk/lib/service/service_connection.py +20 -26
  73. wandb/sdk/lib/service/service_token.py +30 -13
  74. wandb/sdk/mailbox/mailbox.py +13 -5
  75. wandb/sdk/mailbox/mailbox_handle.py +22 -13
  76. wandb/sdk/mailbox/response_handle.py +42 -106
  77. wandb/sdk/mailbox/wait_with_progress.py +7 -42
  78. wandb/sdk/wandb_init.py +11 -25
  79. wandb/sdk/wandb_login.py +1 -1
  80. wandb/sdk/wandb_run.py +92 -56
  81. wandb/sdk/wandb_settings.py +45 -32
  82. wandb/sdk/wandb_setup.py +176 -96
  83. wandb/util.py +1 -1
  84. {wandb-0.21.1.dist-info → wandb-0.21.3.dist-info}/METADATA +2 -2
  85. {wandb-0.21.1.dist-info → wandb-0.21.3.dist-info}/RECORD +88 -72
  86. wandb/sdk/interface/interface_relay.py +0 -38
  87. wandb/sdk/interface/router.py +0 -89
  88. wandb/sdk/interface/router_queue.py +0 -43
  89. wandb/sdk/interface/router_relay.py +0 -50
  90. wandb/sdk/interface/router_sock.py +0 -32
  91. wandb/sdk/lib/sock_client.py +0 -232
  92. {wandb-0.21.1.dist-info → wandb-0.21.3.dist-info}/WHEEL +0 -0
  93. {wandb-0.21.1.dist-info → wandb-0.21.3.dist-info}/entry_points.txt +0 -0
  94. {wandb-0.21.1.dist-info → wandb-0.21.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,57 +1,53 @@
1
1
  """Public API: registries search."""
2
2
 
3
- import json
4
- from typing import TYPE_CHECKING, Any, Dict, Optional
3
+ from __future__ import annotations
5
4
 
6
- if TYPE_CHECKING:
7
- from wandb_gql import Client
5
+ import json
6
+ from typing import TYPE_CHECKING, Any
8
7
 
8
+ from pydantic import ValidationError
9
+ from typing_extensions import override
9
10
  from wandb_gql import gql
10
11
 
11
- import wandb
12
12
  from wandb.apis.paginator import Paginator
13
- from wandb.sdk.artifacts._graphql_fragments import (
14
- _gql_artifact_fragment,
15
- _gql_registry_fragment,
13
+ from wandb.apis.public.utils import gql_compat
14
+ from wandb.sdk.artifacts._generated import (
15
+ FETCH_REGISTRIES_GQL,
16
+ REGISTRY_COLLECTIONS_GQL,
17
+ REGISTRY_VERSIONS_GQL,
18
+ ArtifactCollectionType,
19
+ FetchRegistries,
20
+ RegistriesPage,
21
+ RegistryCollections,
22
+ RegistryCollectionsPage,
23
+ RegistryVersions,
24
+ RegistryVersionsPage,
16
25
  )
26
+ from wandb.sdk.artifacts._graphql_fragments import omit_artifact_fields
17
27
  from wandb.sdk.artifacts._validators import remove_registry_prefix
18
28
 
19
29
  from ._utils import ensure_registry_prefix_on_names
20
30
 
31
+ if TYPE_CHECKING:
32
+ from wandb_gql import Client
33
+
34
+ from wandb.sdk.artifacts.artifact import Artifact
35
+
21
36
 
22
37
  class Registries(Paginator):
23
38
  """An lazy iterator of `Registry` objects."""
24
39
 
25
- QUERY = gql(
26
- """
27
- query Registries($organization: String!, $filters: JSONString, $cursor: String, $perPage: Int) {
28
- organization(name: $organization) {
29
- orgEntity {
30
- name
31
- projects(filters: $filters, after: $cursor, first: $perPage) {
32
- pageInfo {
33
- endCursor
34
- hasNextPage
35
- }
36
- edges {
37
- node {
38
- ...RegistryFragment
39
- }
40
- }
41
- }
42
- }
43
- }
44
- }
45
- """
46
- + _gql_registry_fragment()
47
- )
40
+ QUERY = gql(FETCH_REGISTRIES_GQL)
41
+
42
+ last_response: RegistriesPage | None
43
+ _last_org_entity: str | None
48
44
 
49
45
  def __init__(
50
46
  self,
51
- client: "Client",
47
+ client: Client,
52
48
  organization: str,
53
- filter: Optional[Dict[str, Any]] = None,
54
- per_page: Optional[int] = 100,
49
+ filter: dict[str, Any] | None = None,
50
+ per_page: int | None = 100,
55
51
  ):
56
52
  self.client = client
57
53
  self.organization = organization
@@ -63,6 +59,8 @@ class Registries(Paginator):
63
59
 
64
60
  super().__init__(client, variables, per_page)
65
61
 
62
+ self._last_org_entity = None
63
+
66
64
  def __next__(self):
67
65
  # Implement custom next since its possible to load empty pages because of auth
68
66
  self.index += 1
@@ -71,18 +69,18 @@ class Registries(Paginator):
71
69
  raise StopIteration
72
70
  return self.objects[self.index]
73
71
 
74
- def collections(self, filter: Optional[Dict[str, Any]] = None) -> "Collections":
72
+ def collections(self, filter: dict[str, Any] | None = None) -> Collections:
75
73
  return Collections(
76
- self.client,
77
- self.organization,
74
+ client=self.client,
75
+ organization=self.organization,
78
76
  registry_filter=self.filter,
79
77
  collection_filter=filter,
80
78
  )
81
79
 
82
- def versions(self, filter: Optional[Dict[str, Any]] = None) -> "Versions":
80
+ def versions(self, filter: dict[str, Any] | None = None) -> Versions:
83
81
  return Versions(
84
- self.client,
85
- self.organization,
82
+ client=self.client,
83
+ organization=self.organization,
86
84
  registry_filter=self.filter,
87
85
  collection_filter=None,
88
86
  artifact_filter=filter,
@@ -90,132 +88,71 @@ class Registries(Paginator):
90
88
 
91
89
  @property
92
90
  def length(self):
93
- if self.last_response:
94
- return len(
95
- self.last_response["organization"]["orgEntity"]["projects"]["edges"]
96
- )
97
- else:
91
+ if self.last_response is None:
98
92
  return None
93
+ return len(self.last_response.edges)
99
94
 
100
95
  @property
101
96
  def more(self):
102
- if self.last_response:
103
- return self.last_response["organization"]["orgEntity"]["projects"][
104
- "pageInfo"
105
- ]["hasNextPage"]
106
- else:
97
+ if self.last_response is None:
107
98
  return True
99
+ return self.last_response.page_info.has_next_page
108
100
 
109
101
  @property
110
102
  def cursor(self):
111
- if self.last_response:
112
- return self.last_response["organization"]["orgEntity"]["projects"][
113
- "pageInfo"
114
- ]["endCursor"]
115
- else:
103
+ if self.last_response is None:
116
104
  return None
105
+ return self.last_response.page_info.end_cursor
117
106
 
118
- def convert_objects(self):
119
- if not self.last_response:
120
- return []
121
- if (
122
- not self.last_response["organization"]
123
- or not self.last_response["organization"]["orgEntity"]
124
- ):
107
+ @override
108
+ def _update_response(self) -> None:
109
+ data = self.client.execute(self.QUERY, variable_values=self.variables)
110
+ result = FetchRegistries.model_validate(data)
111
+ if not ((org := result.organization) and (org_entity := org.org_entity)):
125
112
  raise ValueError(
126
- f"Organization '{self.organization}' not found. Please verify the organization name is correct"
113
+ f"Organization {self.organization!r} not found. Please verify the organization name is correct."
127
114
  )
128
115
 
116
+ try:
117
+ page_data = org_entity.projects
118
+ self.last_response = RegistriesPage.model_validate(page_data)
119
+ self._last_org_entity = org_entity.name
120
+ except (LookupError, AttributeError, ValidationError) as e:
121
+ raise ValueError("Unexpected response data") from e
122
+
123
+ def convert_objects(self):
129
124
  from wandb.apis.public.registries.registry import Registry
130
125
 
126
+ if (self.last_response is None) or (self._last_org_entity is None):
127
+ return []
128
+
129
+ nodes = (e.node for e in self.last_response.edges)
131
130
  return [
132
131
  Registry(
133
- self.client,
134
- self.organization,
135
- self.last_response["organization"]["orgEntity"]["name"],
136
- remove_registry_prefix(r["node"]["name"]),
137
- r["node"],
132
+ client=self.client,
133
+ organization=self.organization,
134
+ entity=self._last_org_entity,
135
+ name=remove_registry_prefix(node.name),
136
+ attrs=node.model_dump(),
138
137
  )
139
- for r in self.last_response["organization"]["orgEntity"]["projects"][
140
- "edges"
141
- ]
138
+ for node in nodes
142
139
  ]
143
140
 
144
141
 
145
142
  class Collections(Paginator["ArtifactCollection"]):
146
143
  """An lazy iterator of `ArtifactCollection` objects in a Registry."""
147
144
 
148
- QUERY = gql(
149
- """
150
- query Collections(
151
- $organization: String!,
152
- $registryFilter: JSONString,
153
- $collectionFilter: JSONString,
154
- $collectionTypes: [ArtifactCollectionType!],
155
- $cursor: String,
156
- $perPage: Int
157
- ) {
158
- organization(name: $organization) {
159
- orgEntity {
160
- name
161
- artifactCollections(
162
- projectFilters: $registryFilter,
163
- filters: $collectionFilter,
164
- collectionTypes: $collectionTypes,
165
- after: $cursor,
166
- first: $perPage
167
- ) {
168
- totalCount
169
- pageInfo {
170
- endCursor
171
- hasNextPage
172
- }
173
- edges {
174
- cursor
175
- node {
176
- id
177
- name
178
- description
179
- createdAt
180
- tags {
181
- edges {
182
- node {
183
- name
184
- }
185
- }
186
- }
187
- project {
188
- name
189
- entity {
190
- name
191
- }
192
- }
193
- defaultArtifactType {
194
- name
195
- }
196
- aliases {
197
- edges {
198
- node {
199
- alias
200
- }
201
- }
202
- }
203
- }
204
- }
205
- }
206
- }
207
- }
208
- }
209
- """
210
- )
145
+ QUERY = gql(REGISTRY_COLLECTIONS_GQL)
146
+
147
+ last_response: RegistryCollectionsPage | None
211
148
 
212
149
  def __init__(
213
150
  self,
214
- client: "Client",
151
+ client: Client,
215
152
  organization: str,
216
- registry_filter: Optional[Dict[str, Any]] = None,
217
- collection_filter: Optional[Dict[str, Any]] = None,
218
- per_page: Optional[int] = 100,
153
+ registry_filter: dict[str, Any] | None = None,
154
+ collection_filter: dict[str, Any] | None = None,
155
+ per_page: int | None = 100,
219
156
  ):
220
157
  self.client = client
221
158
  self.organization = organization
@@ -223,14 +160,10 @@ class Collections(Paginator["ArtifactCollection"]):
223
160
  self.collection_filter = collection_filter or {}
224
161
 
225
162
  variables = {
226
- "registryFilter": (
227
- json.dumps(self.registry_filter) if self.registry_filter else None
228
- ),
229
- "collectionFilter": (
230
- json.dumps(self.collection_filter) if self.collection_filter else None
231
- ),
232
- "organization": self.organization,
233
- "collectionTypes": ["PORTFOLIO"],
163
+ "registryFilter": json.dumps(f) if (f := registry_filter) else None,
164
+ "collectionFilter": json.dumps(f) if (f := collection_filter) else None,
165
+ "organization": organization,
166
+ "collectionTypes": [ArtifactCollectionType.PORTFOLIO],
234
167
  "perPage": per_page,
235
168
  }
236
169
 
@@ -244,10 +177,10 @@ class Collections(Paginator["ArtifactCollection"]):
244
177
  raise StopIteration
245
178
  return self.objects[self.index]
246
179
 
247
- def versions(self, filter: Optional[Dict[str, Any]] = None) -> "Versions":
180
+ def versions(self, filter: dict[str, Any] | None = None) -> Versions:
248
181
  return Versions(
249
- self.client,
250
- self.organization,
182
+ client=self.client,
183
+ organization=self.organization,
251
184
  registry_filter=self.registry_filter,
252
185
  collection_filter=self.collection_filter,
253
186
  artifact_filter=filter,
@@ -255,71 +188,75 @@ class Collections(Paginator["ArtifactCollection"]):
255
188
 
256
189
  @property
257
190
  def length(self):
258
- if self.last_response:
259
- return self.last_response["organization"]["orgEntity"][
260
- "artifactCollections"
261
- ]["totalCount"]
262
- else:
191
+ if self.last_response is None:
263
192
  return None
193
+ return self.last_response.total_count
264
194
 
265
195
  @property
266
196
  def more(self):
267
- if self.last_response:
268
- return self.last_response["organization"]["orgEntity"][
269
- "artifactCollections"
270
- ]["pageInfo"]["hasNextPage"]
271
- else:
197
+ if self.last_response is None:
272
198
  return True
199
+ return self.last_response.page_info.has_next_page
273
200
 
274
201
  @property
275
202
  def cursor(self):
276
- if self.last_response:
277
- return self.last_response["organization"]["orgEntity"][
278
- "artifactCollections"
279
- ]["pageInfo"]["endCursor"]
280
- else:
203
+ if self.last_response is None:
281
204
  return None
205
+ return self.last_response.page_info.end_cursor
206
+
207
+ @override
208
+ def _update_response(self) -> None:
209
+ data = self.client.execute(self.QUERY, variable_values=self.variables)
210
+ result = RegistryCollections.model_validate(data)
211
+ if not (
212
+ (org_data := result.organization)
213
+ and (org_entity_data := org_data.org_entity)
214
+ ):
215
+ raise ValueError(
216
+ f"Organization {self.organization!r} not found. Please verify the organization name is correct."
217
+ )
218
+
219
+ try:
220
+ page_data = org_entity_data.artifact_collections
221
+ self.last_response = RegistryCollectionsPage.model_validate(page_data)
222
+ except (LookupError, AttributeError, ValidationError) as e:
223
+ raise ValueError("Unexpected response data") from e
282
224
 
283
225
  def convert_objects(self):
284
226
  from wandb.apis.public import ArtifactCollection
285
227
 
286
- if not self.last_response:
228
+ if self.last_response is None:
287
229
  return []
288
- if (
289
- not self.last_response["organization"]
290
- or not self.last_response["organization"]["orgEntity"]
291
- ):
292
- raise ValueError(
293
- f"Organization '{self.organization}' not found. Please verify the organization name is correct"
294
- )
295
230
 
231
+ nodes = (e.node for e in self.last_response.edges)
296
232
  return [
297
233
  ArtifactCollection(
298
- self.client,
299
- r["node"]["project"]["entity"]["name"],
300
- r["node"]["project"]["name"],
301
- r["node"]["name"],
302
- r["node"]["defaultArtifactType"]["name"],
303
- self.organization,
304
- r["node"],
234
+ client=self.client,
235
+ entity=project.entity.name,
236
+ project=project.name,
237
+ name=node.name,
238
+ type=node.default_artifact_type.name,
239
+ organization=self.organization,
240
+ attrs=node.model_dump(),
305
241
  is_sequence=False,
306
242
  )
307
- for r in self.last_response["organization"]["orgEntity"][
308
- "artifactCollections"
309
- ]["edges"]
243
+ for node in nodes
244
+ if (project := node.project)
310
245
  ]
311
246
 
312
247
 
313
248
  class Versions(Paginator["Artifact"]):
314
249
  """An lazy iterator of `Artifact` objects in a Registry."""
315
250
 
251
+ last_response: RegistryVersionsPage | None
252
+
316
253
  def __init__(
317
254
  self,
318
- client: "Client",
255
+ client: Client,
319
256
  organization: str,
320
- registry_filter: Optional[Dict[str, Any]] = None,
321
- collection_filter: Optional[Dict[str, Any]] = None,
322
- artifact_filter: Optional[Dict[str, Any]] = None,
257
+ registry_filter: dict[str, Any] | None = None,
258
+ collection_filter: dict[str, Any] | None = None,
259
+ artifact_filter: dict[str, Any] | None = None,
323
260
  per_page: int = 100,
324
261
  ):
325
262
  self.client = client
@@ -327,69 +264,16 @@ class Versions(Paginator["Artifact"]):
327
264
  self.registry_filter = registry_filter
328
265
  self.collection_filter = collection_filter
329
266
  self.artifact_filter = artifact_filter or {}
330
- self.QUERY = gql(
331
- """
332
- query Versions(
333
- $organization: String!,
334
- $registryFilter: JSONString,
335
- $collectionFilter: JSONString,
336
- $artifactFilter: JSONString,
337
- $cursor: String,
338
- $perPage: Int
339
- ) {
340
- organization(name: $organization) {
341
- orgEntity {
342
- name
343
- artifactMemberships(
344
- projectFilters: $registryFilter,
345
- collectionFilters: $collectionFilter,
346
- filters: $artifactFilter,
347
- after: $cursor,
348
- first: $perPage
349
- ) {
350
- pageInfo {
351
- endCursor
352
- hasNextPage
353
- }
354
- edges {
355
- node {
356
- artifactCollection {
357
- project {
358
- name
359
- entity {
360
- name
361
- }
362
- }
363
- name
364
- }
365
- versionIndex
366
- artifact {
367
- ...ArtifactFragment
368
- }
369
- aliases {
370
- alias
371
- }
372
- }
373
- }
374
- }
375
- }
376
- }
377
- }
378
- """
379
- + _gql_artifact_fragment(include_aliases=False)
267
+
268
+ self.QUERY = gql_compat(
269
+ REGISTRY_VERSIONS_GQL, omit_fields=omit_artifact_fields()
380
270
  )
381
271
 
382
272
  variables = {
383
- "registryFilter": (
384
- json.dumps(self.registry_filter) if self.registry_filter else None
385
- ),
386
- "collectionFilter": (
387
- json.dumps(self.collection_filter) if self.collection_filter else None
388
- ),
389
- "artifactFilter": (
390
- json.dumps(self.artifact_filter) if self.artifact_filter else None
391
- ),
392
- "organization": self.organization,
273
+ "registryFilter": json.dumps(f) if (f := registry_filter) else None,
274
+ "collectionFilter": json.dumps(f) if (f := collection_filter) else None,
275
+ "artifactFilter": json.dumps(f) if (f := artifact_filter) else None,
276
+ "organization": organization,
393
277
  }
394
278
 
395
279
  super().__init__(client, variables, per_page)
@@ -403,58 +287,61 @@ class Versions(Paginator["Artifact"]):
403
287
  return self.objects[self.index]
404
288
 
405
289
  @property
406
- def length(self):
407
- if self.last_response:
408
- return len(
409
- self.last_response["organization"]["orgEntity"]["artifactMemberships"][
410
- "edges"
411
- ]
412
- )
413
- else:
290
+ def length(self) -> int | None:
291
+ if self.last_response is None:
414
292
  return None
293
+ return len(self.last_response.edges)
415
294
 
416
295
  @property
417
- def more(self):
418
- if self.last_response:
419
- return self.last_response["organization"]["orgEntity"][
420
- "artifactMemberships"
421
- ]["pageInfo"]["hasNextPage"]
422
- else:
296
+ def more(self) -> bool:
297
+ if self.last_response is None:
423
298
  return True
299
+ return self.last_response.page_info.has_next_page
424
300
 
425
301
  @property
426
- def cursor(self):
427
- if self.last_response:
428
- return self.last_response["organization"]["orgEntity"][
429
- "artifactMemberships"
430
- ]["pageInfo"]["endCursor"]
431
- else:
302
+ def cursor(self) -> str | None:
303
+ if self.last_response is None:
432
304
  return None
433
-
434
- def convert_objects(self):
435
- if not self.last_response:
436
- return []
437
- if (
438
- not self.last_response["organization"]
439
- or not self.last_response["organization"]["orgEntity"]
305
+ return self.last_response.page_info.end_cursor
306
+
307
+ @override
308
+ def _update_response(self) -> None:
309
+ data = self.client.execute(self.QUERY, variable_values=self.variables)
310
+ result = RegistryVersions.model_validate(data)
311
+ if not (
312
+ (org_data := result.organization)
313
+ and (org_entity_data := org_data.org_entity)
440
314
  ):
441
315
  raise ValueError(
442
- f"Organization '{self.organization}' not found. Please verify the organization name is correct"
316
+ f"Organization {self.organization!r} not found. Please verify the organization name is correct."
443
317
  )
444
318
 
445
- artifacts = (
446
- wandb.Artifact._from_attrs(
447
- a["node"]["artifactCollection"]["project"]["entity"]["name"],
448
- a["node"]["artifactCollection"]["project"]["name"],
449
- a["node"]["artifactCollection"]["name"]
450
- + ":v"
451
- + str(a["node"]["versionIndex"]),
452
- a["node"]["artifact"],
453
- self.client,
454
- [alias["alias"] for alias in a["node"]["aliases"]],
319
+ try:
320
+ page_data = org_entity_data.artifact_memberships
321
+ self.last_response = RegistryVersionsPage.model_validate(page_data)
322
+ except (LookupError, AttributeError, ValidationError) as e:
323
+ raise ValueError("Unexpected response data") from e
324
+
325
+ def convert_objects(self) -> list[Artifact]:
326
+ from wandb.sdk.artifacts.artifact import Artifact
327
+
328
+ if self.last_response is None:
329
+ return []
330
+
331
+ nodes = (e.node for e in self.last_response.edges)
332
+ return [
333
+ Artifact._from_attrs(
334
+ entity=project.entity.name,
335
+ project=project.name,
336
+ name=f"{collection.name}:v{node.version_index}",
337
+ attrs=artifact,
338
+ client=self.client,
339
+ aliases=[alias.alias for alias in node.aliases],
455
340
  )
456
- for a in self.last_response["organization"]["orgEntity"][
457
- "artifactMemberships"
458
- ]["edges"]
459
- )
460
- return artifacts
341
+ for node in nodes
342
+ if (
343
+ (collection := node.artifact_collection)
344
+ and (project := collection.project)
345
+ and (artifact := node.artifact)
346
+ )
347
+ ]
@@ -141,18 +141,21 @@ class Reports(SizedPaginator["BetaReport"]):
141
141
  class BetaReport(Attrs):
142
142
  """BetaReport is a class associated with reports created in W&B.
143
143
 
144
- WARNING: this API will likely change in a future release
144
+ Provides access to report attributes (name, description, user, spec,
145
+ timestamps) and methods for retrieving associated runs,
146
+ sections, and for rendering the report as HTML.
145
147
 
146
148
  Attributes:
147
- id (string): unique identifier of the report
148
- name (string): report name
149
- display_name (string): display name of the report
150
- description (string): report description
151
- user (User): the user that created the report (contains username and email)
152
- spec (dict): the spec of the report
153
- url (string): the url of the report
154
- updated_at (string): timestamp of last update
155
- created_at (string): timestamp when the report was created
149
+ id (string): Unique identifier of the report.
150
+ display_name (string): Human-readable display name of the report.
151
+ name (string): The name of the report. Use `display_name` for a more user-friendly name.
152
+ description (string): Description of the report.
153
+ user (User): Dictionary containing user info (username, email) who
154
+ created the report.
155
+ spec (dict): The spec of the report.
156
+ url (string): The URL of the report.
157
+ updated_at (string): Timestamp of last update.
158
+ created_at (string): Timestamp when the report was created.
156
159
  """
157
160
 
158
161
  def __init__(self, client, attrs, entity=None, project=None):
@@ -3,15 +3,13 @@
3
3
 
4
4
  from __future__ import annotations
5
5
 
6
- from typing import Optional
7
-
8
6
  from wandb._pydantic import GQLBase
9
7
 
10
8
  from .fragments import DeleteAutomationResult
11
9
 
12
10
 
13
11
  class DeleteAutomation(GQLBase):
14
- result: Optional[DeleteAutomationResult]
12
+ result: DeleteAutomationResult
15
13
 
16
14
 
17
15
  DeleteAutomation.model_rebuild()