wandb 0.19.6rc4__py3-none-win_amd64.whl → 0.19.7__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.
Files changed (72) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +25 -5
  3. wandb/apis/public/_generated/__init__.py +21 -0
  4. wandb/apis/public/_generated/base.py +128 -0
  5. wandb/apis/public/_generated/enums.py +4 -0
  6. wandb/apis/public/_generated/input_types.py +4 -0
  7. wandb/apis/public/_generated/operations.py +15 -0
  8. wandb/apis/public/_generated/server_features_query.py +27 -0
  9. wandb/apis/public/_generated/typing_compat.py +14 -0
  10. wandb/apis/public/api.py +192 -6
  11. wandb/apis/public/artifacts.py +13 -45
  12. wandb/apis/public/registries.py +573 -0
  13. wandb/apis/public/utils.py +36 -0
  14. wandb/bin/gpu_stats.exe +0 -0
  15. wandb/bin/wandb-core +0 -0
  16. wandb/cli/cli.py +11 -20
  17. wandb/env.py +10 -0
  18. wandb/proto/v3/wandb_internal_pb2.py +243 -222
  19. wandb/proto/v3/wandb_server_pb2.py +4 -4
  20. wandb/proto/v3/wandb_settings_pb2.py +1 -1
  21. wandb/proto/v4/wandb_internal_pb2.py +226 -222
  22. wandb/proto/v4/wandb_server_pb2.py +4 -4
  23. wandb/proto/v4/wandb_settings_pb2.py +1 -1
  24. wandb/proto/v5/wandb_internal_pb2.py +226 -222
  25. wandb/proto/v5/wandb_server_pb2.py +4 -4
  26. wandb/proto/v5/wandb_settings_pb2.py +1 -1
  27. wandb/sdk/artifacts/_graphql_fragments.py +126 -0
  28. wandb/sdk/artifacts/artifact.py +43 -88
  29. wandb/sdk/backend/backend.py +1 -1
  30. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +14 -6
  31. wandb/sdk/data_types/helper_types/image_mask.py +12 -6
  32. wandb/sdk/data_types/saved_model.py +35 -46
  33. wandb/sdk/data_types/video.py +7 -16
  34. wandb/sdk/interface/interface.py +26 -10
  35. wandb/sdk/interface/interface_queue.py +5 -8
  36. wandb/sdk/interface/interface_relay.py +1 -6
  37. wandb/sdk/interface/interface_shared.py +21 -99
  38. wandb/sdk/interface/interface_sock.py +2 -13
  39. wandb/sdk/interface/router.py +21 -15
  40. wandb/sdk/interface/router_queue.py +2 -1
  41. wandb/sdk/interface/router_relay.py +2 -1
  42. wandb/sdk/interface/router_sock.py +5 -4
  43. wandb/sdk/internal/handler.py +4 -3
  44. wandb/sdk/internal/internal_api.py +12 -1
  45. wandb/sdk/internal/sender.py +0 -18
  46. wandb/sdk/lib/apikey.py +87 -26
  47. wandb/sdk/lib/asyncio_compat.py +210 -0
  48. wandb/sdk/lib/progress.py +78 -16
  49. wandb/sdk/lib/service_connection.py +1 -1
  50. wandb/sdk/lib/sock_client.py +7 -7
  51. wandb/sdk/mailbox/__init__.py +23 -0
  52. wandb/sdk/mailbox/handles.py +199 -0
  53. wandb/sdk/mailbox/mailbox.py +121 -0
  54. wandb/sdk/mailbox/wait_with_progress.py +134 -0
  55. wandb/sdk/service/server_sock.py +5 -1
  56. wandb/sdk/service/streams.py +66 -74
  57. wandb/sdk/verify/verify.py +54 -2
  58. wandb/sdk/wandb_init.py +61 -61
  59. wandb/sdk/wandb_login.py +7 -4
  60. wandb/sdk/wandb_metadata.py +65 -34
  61. wandb/sdk/wandb_require.py +14 -8
  62. wandb/sdk/wandb_run.py +82 -87
  63. wandb/sdk/wandb_settings.py +3 -3
  64. wandb/sdk/wandb_setup.py +19 -8
  65. wandb/sdk/wandb_sync.py +2 -4
  66. wandb/util.py +3 -1
  67. {wandb-0.19.6rc4.dist-info → wandb-0.19.7.dist-info}/METADATA +2 -2
  68. {wandb-0.19.6rc4.dist-info → wandb-0.19.7.dist-info}/RECORD +71 -58
  69. wandb/sdk/lib/mailbox.py +0 -442
  70. {wandb-0.19.6rc4.dist-info → wandb-0.19.7.dist-info}/WHEEL +0 -0
  71. {wandb-0.19.6rc4.dist-info → wandb-0.19.7.dist-info}/entry_points.txt +0 -0
  72. {wandb-0.19.6rc4.dist-info → wandb-0.19.7.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,573 @@
1
+ """Public API: registries."""
2
+
3
+ import json
4
+ from typing import TYPE_CHECKING, Any, Dict, Mapping, Optional, Sequence
5
+
6
+ if TYPE_CHECKING:
7
+ from wandb_gql import Client
8
+
9
+ from wandb_gql import gql
10
+
11
+ import wandb
12
+ from wandb.apis.paginator import Paginator
13
+ from wandb.apis.public.artifacts import ArtifactCollection
14
+ from wandb.sdk.artifacts._graphql_fragments import (
15
+ _gql_artifact_fragment,
16
+ _gql_registry_fragment,
17
+ )
18
+ from wandb.sdk.artifacts._validators import REGISTRY_PREFIX
19
+
20
+
21
+ class Registries(Paginator):
22
+ """Iterator that returns Registries."""
23
+
24
+ QUERY = gql(
25
+ """
26
+ query Registries($organization: String!, $filters: JSONString, $cursor: String, $perPage: Int) {
27
+ organization(name: $organization) {
28
+ orgEntity {
29
+ name
30
+ projects(filters: $filters, after: $cursor, first: $perPage) {
31
+ pageInfo {
32
+ endCursor
33
+ hasNextPage
34
+ }
35
+ edges {
36
+ node {
37
+ ...RegistryFragment
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ """
45
+ + _gql_registry_fragment()
46
+ )
47
+
48
+ def __init__(
49
+ self,
50
+ client: "Client",
51
+ organization: str,
52
+ filter: Optional[Dict[str, Any]] = None,
53
+ per_page: Optional[int] = 100,
54
+ ):
55
+ self.client = client
56
+ self.organization = organization
57
+ self.filter = _ensure_registry_prefix_on_names(filter or {})
58
+ variables = {
59
+ "organization": organization,
60
+ "filters": json.dumps(self.filter),
61
+ }
62
+
63
+ super().__init__(client, variables, per_page)
64
+
65
+ def __bool__(self):
66
+ return len(self) > 0 or len(self.objects) > 0
67
+
68
+ def __next__(self):
69
+ # Implement custom next since its possible to load empty pages because of auth
70
+ self.index += 1
71
+ while len(self.objects) <= self.index:
72
+ if not self._load_page():
73
+ raise StopIteration
74
+ return self.objects[self.index]
75
+
76
+ def collections(self, filter: Optional[Dict[str, Any]] = None) -> "Collections":
77
+ return Collections(
78
+ self.client,
79
+ self.organization,
80
+ registry_filter=self.filter,
81
+ collection_filter=filter,
82
+ )
83
+
84
+ def versions(self, filter: Optional[Dict[str, Any]] = None) -> "Versions":
85
+ return Versions(
86
+ self.client,
87
+ self.organization,
88
+ registry_filter=self.filter,
89
+ collection_filter=None,
90
+ artifact_filter=filter,
91
+ )
92
+
93
+ @property
94
+ def length(self):
95
+ if self.last_response:
96
+ return len(
97
+ self.last_response["organization"]["orgEntity"]["projects"]["edges"]
98
+ )
99
+ else:
100
+ return None
101
+
102
+ @property
103
+ def more(self):
104
+ if self.last_response:
105
+ return self.last_response["organization"]["orgEntity"]["projects"][
106
+ "pageInfo"
107
+ ]["hasNextPage"]
108
+ else:
109
+ return True
110
+
111
+ @property
112
+ def cursor(self):
113
+ if self.last_response:
114
+ return self.last_response["organization"]["orgEntity"]["projects"][
115
+ "pageInfo"
116
+ ]["endCursor"]
117
+ else:
118
+ return None
119
+
120
+ def convert_objects(self):
121
+ if not self.last_response:
122
+ return []
123
+ if (
124
+ not self.last_response["organization"]
125
+ or not self.last_response["organization"]["orgEntity"]
126
+ ):
127
+ raise ValueError(
128
+ f"Organization '{self.organization}' not found. Please verify the organization name is correct"
129
+ )
130
+
131
+ return [
132
+ Registry(
133
+ self.client,
134
+ self.organization,
135
+ self.last_response["organization"]["orgEntity"]["name"],
136
+ r["node"]["name"],
137
+ r["node"],
138
+ )
139
+ for r in self.last_response["organization"]["orgEntity"]["projects"][
140
+ "edges"
141
+ ]
142
+ ]
143
+
144
+
145
+ class Registry:
146
+ """A single registry in the Registry."""
147
+
148
+ def __init__(
149
+ self,
150
+ client: "Client",
151
+ organization: str,
152
+ entity: str,
153
+ full_name: str,
154
+ attrs: Dict[str, Any],
155
+ ):
156
+ self.client = client
157
+ self._full_name = full_name
158
+ self._name = full_name.replace(REGISTRY_PREFIX, "")
159
+ self._entity = entity
160
+ self._organization = organization
161
+ self._description = attrs.get("description", "")
162
+ self._allow_all_artifact_types = attrs.get(
163
+ "allowAllArtifactTypesInRegistry", False
164
+ )
165
+ self._artifact_types = [
166
+ t["node"]["name"] for t in attrs.get("artifactTypes", {}).get("edges", [])
167
+ ]
168
+ self._id = attrs.get("id", "")
169
+ self._created_at = attrs.get("createdAt", "")
170
+ self._updated_at = attrs.get("updatedAt", "")
171
+
172
+ @property
173
+ def full_name(self):
174
+ return self._full_name
175
+
176
+ @property
177
+ def name(self):
178
+ return self._name
179
+
180
+ @property
181
+ def entity(self):
182
+ return self._entity
183
+
184
+ @property
185
+ def organization(self):
186
+ return self._organization
187
+
188
+ @property
189
+ def description(self):
190
+ return self._description
191
+
192
+ @property
193
+ def allow_all_artifact_types(self):
194
+ return self._allow_all_artifact_types
195
+
196
+ @property
197
+ def artifact_types(self):
198
+ return self._artifact_types
199
+
200
+ @property
201
+ def created_at(self):
202
+ return self._created_at
203
+
204
+ @property
205
+ def updated_at(self):
206
+ return self._updated_at
207
+
208
+ @property
209
+ def path(self):
210
+ return [self.entity, self.name]
211
+
212
+ def collections(self, filter: Optional[Dict[str, Any]] = None):
213
+ registry_filter = {
214
+ "name": self.full_name,
215
+ }
216
+ return Collections(self.client, self.organization, registry_filter, filter)
217
+
218
+ def versions(self, filter: Optional[Dict[str, Any]] = None):
219
+ registry_filter = {
220
+ "name": self.full_name,
221
+ }
222
+ return Versions(self.client, self.organization, registry_filter, None, filter)
223
+
224
+
225
+ class Collections(Paginator):
226
+ """Iterator that returns Artifact collections in the Registry."""
227
+
228
+ QUERY = gql(
229
+ """
230
+ query Collections(
231
+ $organization: String!,
232
+ $registryFilter: JSONString,
233
+ $collectionFilter: JSONString,
234
+ $collectionTypes: [ArtifactCollectionType!],
235
+ $cursor: String,
236
+ $perPage: Int
237
+ ) {
238
+ organization(name: $organization) {
239
+ orgEntity {
240
+ name
241
+ artifactCollections(
242
+ projectFilters: $registryFilter,
243
+ filters: $collectionFilter,
244
+ collectionTypes: $collectionTypes,
245
+ after: $cursor,
246
+ first: $perPage
247
+ ) {
248
+ totalCount
249
+ pageInfo {
250
+ endCursor
251
+ hasNextPage
252
+ }
253
+ edges {
254
+ cursor
255
+ node {
256
+ id
257
+ name
258
+ description
259
+ createdAt
260
+ tags {
261
+ edges {
262
+ node {
263
+ name
264
+ }
265
+ }
266
+ }
267
+ project {
268
+ name
269
+ entity {
270
+ name
271
+ }
272
+ }
273
+ defaultArtifactType {
274
+ name
275
+ }
276
+ aliases {
277
+ edges {
278
+ node {
279
+ alias
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ }
288
+ }
289
+ """
290
+ )
291
+
292
+ def __init__(
293
+ self,
294
+ client: "Client",
295
+ organization: str,
296
+ registry_filter: Optional[Dict[str, Any]] = None,
297
+ collection_filter: Optional[Dict[str, Any]] = None,
298
+ per_page: Optional[int] = 100,
299
+ ):
300
+ self.client = client
301
+ self.organization = organization
302
+ self.registry_filter = registry_filter
303
+ self.collection_filter = collection_filter or {}
304
+
305
+ variables = {
306
+ "registryFilter": json.dumps(self.registry_filter)
307
+ if self.registry_filter
308
+ else None,
309
+ "collectionFilter": json.dumps(self.collection_filter)
310
+ if self.collection_filter
311
+ else None,
312
+ "organization": self.organization,
313
+ "collectionTypes": ["PORTFOLIO"],
314
+ "perPage": per_page,
315
+ }
316
+
317
+ super().__init__(client, variables, per_page)
318
+
319
+ def __bool__(self):
320
+ return len(self) > 0 or len(self.objects) > 0
321
+
322
+ def __next__(self):
323
+ # Implement custom next since its possible to load empty pages because of auth
324
+ self.index += 1
325
+ while len(self.objects) <= self.index:
326
+ if not self._load_page():
327
+ raise StopIteration
328
+ return self.objects[self.index]
329
+
330
+ def versions(self, filter: Optional[Dict[str, Any]] = None) -> "Versions":
331
+ return Versions(
332
+ self.client,
333
+ self.organization,
334
+ registry_filter=self.registry_filter,
335
+ collection_filter=self.collection_filter,
336
+ artifact_filter=filter,
337
+ )
338
+
339
+ @property
340
+ def length(self):
341
+ if self.last_response:
342
+ return self.last_response["organization"]["orgEntity"][
343
+ "artifactCollections"
344
+ ]["totalCount"]
345
+ else:
346
+ return None
347
+
348
+ @property
349
+ def more(self):
350
+ if self.last_response:
351
+ return self.last_response["organization"]["orgEntity"][
352
+ "artifactCollections"
353
+ ]["pageInfo"]["hasNextPage"]
354
+ else:
355
+ return True
356
+
357
+ @property
358
+ def cursor(self):
359
+ if self.last_response:
360
+ return self.last_response["organization"]["orgEntity"][
361
+ "artifactCollections"
362
+ ]["pageInfo"]["endCursor"]
363
+ else:
364
+ return None
365
+
366
+ def convert_objects(self):
367
+ if not self.last_response:
368
+ return []
369
+ if (
370
+ not self.last_response["organization"]
371
+ or not self.last_response["organization"]["orgEntity"]
372
+ ):
373
+ raise ValueError(
374
+ f"Organization '{self.organization}' not found. Please verify the organization name is correct"
375
+ )
376
+
377
+ return [
378
+ ArtifactCollection(
379
+ self.client,
380
+ r["node"]["project"]["entity"]["name"],
381
+ r["node"]["project"]["name"],
382
+ r["node"]["name"],
383
+ r["node"]["defaultArtifactType"]["name"],
384
+ self.organization,
385
+ r["node"],
386
+ )
387
+ for r in self.last_response["organization"]["orgEntity"][
388
+ "artifactCollections"
389
+ ]["edges"]
390
+ ]
391
+
392
+
393
+ class Versions(Paginator):
394
+ """Iterator that returns Artifact versions in the Registry."""
395
+
396
+ def __init__(
397
+ self,
398
+ client: "Client",
399
+ organization: str,
400
+ registry_filter: Optional[Dict[str, Any]] = None,
401
+ collection_filter: Optional[Dict[str, Any]] = None,
402
+ artifact_filter: Optional[Dict[str, Any]] = None,
403
+ per_page: int = 100,
404
+ ):
405
+ self.client = client
406
+ self.organization = organization
407
+ self.registry_filter = registry_filter
408
+ self.collection_filter = collection_filter
409
+ self.artifact_filter = artifact_filter or {}
410
+ self.QUERY = gql(
411
+ """
412
+ query Versions(
413
+ $organization: String!,
414
+ $registryFilter: JSONString,
415
+ $collectionFilter: JSONString,
416
+ $artifactFilter: JSONString,
417
+ $cursor: String,
418
+ $perPage: Int
419
+ ) {
420
+ organization(name: $organization) {
421
+ orgEntity {
422
+ name
423
+ artifactMemberships(
424
+ projectFilters: $registryFilter,
425
+ collectionFilters: $collectionFilter,
426
+ filters: $artifactFilter,
427
+ after: $cursor,
428
+ first: $perPage
429
+ ) {
430
+ pageInfo {
431
+ endCursor
432
+ hasNextPage
433
+ }
434
+ edges {
435
+ node {
436
+ artifactCollection {
437
+ project {
438
+ name
439
+ entity {
440
+ name
441
+ }
442
+ }
443
+ name
444
+ }
445
+ versionIndex
446
+ artifact {
447
+ ...ArtifactFragment
448
+ }
449
+ aliases {
450
+ alias
451
+ }
452
+ }
453
+ }
454
+ }
455
+ }
456
+ }
457
+ }
458
+ """
459
+ + _gql_artifact_fragment(include_aliases=False)
460
+ )
461
+
462
+ variables = {
463
+ "registryFilter": json.dumps(self.registry_filter)
464
+ if self.registry_filter
465
+ else None,
466
+ "collectionFilter": json.dumps(self.collection_filter)
467
+ if self.collection_filter
468
+ else None,
469
+ "artifactFilter": json.dumps(self.artifact_filter)
470
+ if self.artifact_filter
471
+ else None,
472
+ "organization": self.organization,
473
+ }
474
+
475
+ super().__init__(client, variables, per_page)
476
+
477
+ def __next__(self):
478
+ # Implement custom next since its possible to load empty pages because of auth
479
+ self.index += 1
480
+ while len(self.objects) <= self.index:
481
+ if not self._load_page():
482
+ raise StopIteration
483
+ return self.objects[self.index]
484
+
485
+ def __bool__(self):
486
+ return len(self) > 0 or len(self.objects) > 0
487
+
488
+ @property
489
+ def length(self):
490
+ if self.last_response:
491
+ return len(
492
+ self.last_response["organization"]["orgEntity"]["artifactMemberships"][
493
+ "edges"
494
+ ]
495
+ )
496
+ else:
497
+ return None
498
+
499
+ @property
500
+ def more(self):
501
+ if self.last_response:
502
+ return self.last_response["organization"]["orgEntity"][
503
+ "artifactMemberships"
504
+ ]["pageInfo"]["hasNextPage"]
505
+ else:
506
+ return True
507
+
508
+ @property
509
+ def cursor(self):
510
+ if self.last_response:
511
+ return self.last_response["organization"]["orgEntity"][
512
+ "artifactMemberships"
513
+ ]["pageInfo"]["endCursor"]
514
+ else:
515
+ return None
516
+
517
+ def convert_objects(self):
518
+ if not self.last_response:
519
+ return []
520
+ if (
521
+ not self.last_response["organization"]
522
+ or not self.last_response["organization"]["orgEntity"]
523
+ ):
524
+ raise ValueError(
525
+ f"Organization '{self.organization}' not found. Please verify the organization name is correct"
526
+ )
527
+
528
+ artifacts = (
529
+ wandb.Artifact._from_attrs(
530
+ a["node"]["artifactCollection"]["project"]["entity"]["name"],
531
+ a["node"]["artifactCollection"]["project"]["name"],
532
+ a["node"]["artifactCollection"]["name"]
533
+ + ":v"
534
+ + str(a["node"]["versionIndex"]),
535
+ a["node"]["artifact"],
536
+ self.client,
537
+ [alias["alias"] for alias in a["node"]["aliases"]],
538
+ )
539
+ for a in self.last_response["organization"]["orgEntity"][
540
+ "artifactMemberships"
541
+ ]["edges"]
542
+ )
543
+ return artifacts
544
+
545
+
546
+ def _ensure_registry_prefix_on_names(query, in_name=False):
547
+ """Traverse the filter to prepend the `name` key value with the registry prefix unless the value is a regex.
548
+
549
+ - in_name: True if we are under a "name" key (or propagating from one).
550
+
551
+ EX: {"name": "model"} -> {"name": "wandb-registry-model"}
552
+ """
553
+ if isinstance((txt := query), str):
554
+ if in_name:
555
+ return txt if txt.startswith(REGISTRY_PREFIX) else f"{REGISTRY_PREFIX}{txt}"
556
+ return txt
557
+ if isinstance((dct := query), Mapping):
558
+ new_dict = {}
559
+ for key, obj in dct.items():
560
+ if key == "name":
561
+ new_dict[key] = _ensure_registry_prefix_on_names(obj, in_name=True)
562
+ elif key == "$regex":
563
+ # For regex operator, we skip transformation of its value.
564
+ new_dict[key] = obj
565
+ else:
566
+ # For any other key, propagate the in_name and skip_transform flags as-is.
567
+ new_dict[key] = _ensure_registry_prefix_on_names(obj, in_name=in_name)
568
+ return new_dict
569
+ if isinstance((objs := query), Sequence):
570
+ return list(
571
+ map(lambda x: _ensure_registry_prefix_on_names(x, in_name=in_name), objs)
572
+ )
573
+ return query
@@ -1,8 +1,11 @@
1
1
  import re
2
2
  from enum import Enum
3
+ from typing import Optional
3
4
  from urllib.parse import urlparse
4
5
 
6
+ from wandb._iterutils import one
5
7
  from wandb.sdk.artifacts._validators import is_artifact_registry_project
8
+ from wandb.sdk.internal.internal_api import Api as InternalApi
6
9
 
7
10
 
8
11
  def parse_s3_url_to_s3_uri(url) -> str:
@@ -66,3 +69,36 @@ def parse_org_from_registry_path(path: str, path_type: PathType) -> str:
66
69
  if is_artifact_registry_project(project):
67
70
  return org
68
71
  return ""
72
+
73
+
74
+ def fetch_org_from_settings_or_entity(
75
+ settings: dict, default_entity: Optional[str] = None
76
+ ) -> str:
77
+ """Fetch the org from either the settings or deriving it from the entity.
78
+
79
+ Returns the org from the settings if available. If no org is passed in or set, the entity is used to fetch the org.
80
+
81
+ Args:
82
+ organization (str | None): The organization to fetch the org for.
83
+ settings (dict): The settings to fetch the org for.
84
+ default_entity (str | None): The default entity to fetch the org for.
85
+ """
86
+ if (organization := settings.get("organization")) is None:
87
+ # Fetch the org via the Entity. Won't work if default entity is a personal entity and belongs to multiple orgs
88
+ entity = settings.get("entity") or default_entity
89
+ if entity is None:
90
+ raise ValueError(
91
+ "No entity specified and can't fetch organization from the entity"
92
+ )
93
+ entity_orgs = InternalApi()._fetch_orgs_and_org_entities_from_entity(entity)
94
+ entity_org = one(
95
+ entity_orgs,
96
+ too_short=ValueError(
97
+ "No organizations found for entity. Please specify an organization in the settings."
98
+ ),
99
+ too_long=ValueError(
100
+ "Multiple organizations found for entity. Please specify an organization in the settings."
101
+ ),
102
+ )
103
+ organization = entity_org.display_name
104
+ return organization
wandb/bin/gpu_stats.exe CHANGED
Binary file
wandb/bin/wandb-core CHANGED
Binary file
wandb/cli/cli.py CHANGED
@@ -241,32 +241,21 @@ def login(key, host, cloud, relogin, anonymously, verify, no_offline=False):
241
241
  wandb_sdk.wandb_login._handle_host_wandb_setting(host, cloud)
242
242
  # A change in click or the test harness means key can be none...
243
243
  key = key[0] if key is not None and len(key) > 0 else None
244
- if key:
245
- relogin = True
244
+ relogin = True if key or relogin else False
246
245
 
247
- login_settings = dict(
248
- x_cli_only_mode=True,
249
- x_disable_viewer=relogin and not verify,
250
- anonymous=anon_mode,
251
- base_url=host,
252
- )
253
-
254
- try:
255
- wandb.setup(
256
- settings=wandb.Settings(
257
- **{k: v for k, v in login_settings.items() if v is not None}
258
- )
246
+ wandb.setup(
247
+ settings=wandb.Settings(
248
+ x_cli_only_mode=True,
249
+ x_disable_viewer=relogin and not verify,
259
250
  )
260
- except TypeError as e:
261
- wandb.termerror(str(e))
262
- sys.exit(1)
251
+ )
263
252
 
264
253
  wandb.login(
265
- relogin=relogin,
266
- key=key,
267
254
  anonymous=anon_mode,
268
- host=host,
269
255
  force=True,
256
+ host=host,
257
+ key=key,
258
+ relogin=relogin,
270
259
  verify=verify,
271
260
  )
272
261
 
@@ -2805,11 +2794,13 @@ def verify(host):
2805
2794
  wandb_verify.check_wandb_version(api)
2806
2795
  check_run_success = wandb_verify.check_run(api)
2807
2796
  check_artifacts_success = wandb_verify.check_artifacts()
2797
+ check_sweeps_success = wandb_verify.check_sweeps(api)
2808
2798
  if not (
2809
2799
  check_artifacts_success
2810
2800
  and check_run_success
2811
2801
  and large_post_success
2812
2802
  and url_success
2803
+ and check_sweeps_success
2813
2804
  ):
2814
2805
  sys.exit(1)
2815
2806
 
wandb/env.py CHANGED
@@ -34,6 +34,7 @@ USERNAME = "WANDB_USERNAME"
34
34
  USER_EMAIL = "WANDB_USER_EMAIL"
35
35
  PROJECT = "WANDB_PROJECT"
36
36
  ENTITY = "WANDB_ENTITY"
37
+ ORGANIZATION = "WANDB_ORGANIZATION"
37
38
  BASE_URL = "WANDB_BASE_URL"
38
39
  APP_URL = "WANDB_APP_URL"
39
40
  PROGRAM = "WANDB_PROGRAM"
@@ -284,6 +285,15 @@ def get_entity(
284
285
  return env.get(ENTITY, default)
285
286
 
286
287
 
288
+ def get_organization(
289
+ default: str | None = None, env: MutableMapping | None = None
290
+ ) -> str | None:
291
+ if env is None:
292
+ env = os.environ
293
+
294
+ return env.get(ORGANIZATION, default)
295
+
296
+
287
297
  def get_base_url(
288
298
  default: str | None = None, env: MutableMapping | None = None
289
299
  ) -> str | None: