wandb 0.19.4rc1__py3-none-musllinux_1_2_aarch64.whl → 0.19.5__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 +1 -8
- wandb/_iterutils.py +46 -0
- wandb/apis/internal.py +4 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +9 -2
- wandb/sdk/artifacts/artifact.py +87 -1
- wandb/sdk/backend/backend.py +7 -11
- wandb/sdk/data_types/base_types/wb_value.py +10 -10
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +2 -2
- wandb/sdk/data_types/helper_types/image_mask.py +2 -2
- wandb/sdk/data_types/image.py +0 -3
- wandb/sdk/data_types/utils.py +2 -6
- wandb/sdk/interface/interface.py +26 -12
- wandb/sdk/interface/interface_sock.py +7 -11
- wandb/sdk/internal/internal_api.py +9 -1
- wandb/sdk/internal/system/assets/cpu.py +1 -1
- wandb/sdk/lib/apikey.py +4 -17
- wandb/sdk/lib/mailbox.py +0 -10
- wandb/sdk/lib/server.py +20 -0
- wandb/sdk/lib/service_connection.py +2 -2
- wandb/sdk/wandb_init.py +60 -45
- wandb/sdk/wandb_login.py +86 -110
- wandb/sdk/wandb_metadata.py +57 -31
- wandb/sdk/wandb_run.py +32 -45
- wandb/sdk/wandb_settings.py +26 -10
- wandb/sdk/wandb_setup.py +10 -22
- {wandb-0.19.4rc1.dist-info → wandb-0.19.5.dist-info}/METADATA +1 -1
- {wandb-0.19.4rc1.dist-info → wandb-0.19.5.dist-info}/RECORD +680 -679
- {wandb-0.19.4rc1.dist-info → wandb-0.19.5.dist-info}/WHEEL +0 -0
- {wandb-0.19.4rc1.dist-info → wandb-0.19.5.dist-info}/entry_points.txt +0 -0
- {wandb-0.19.4rc1.dist-info → wandb-0.19.5.dist-info}/licenses/LICENSE +0 -0
wandb/__init__.py
CHANGED
wandb/__init__.pyi
CHANGED
@@ -103,7 +103,7 @@ if TYPE_CHECKING:
|
|
103
103
|
import wandb
|
104
104
|
from wandb.plot import CustomChart
|
105
105
|
|
106
|
-
__version__: str = "0.19.
|
106
|
+
__version__: str = "0.19.5"
|
107
107
|
|
108
108
|
run: Run | None
|
109
109
|
config: wandb_config.Config
|
@@ -595,7 +595,6 @@ def log(
|
|
595
595
|
[our guides to logging](https://docs.wandb.com/guides/track/log).
|
596
596
|
|
597
597
|
### Basic usage
|
598
|
-
<!--yeadoc-test:init-and-log-basic-->
|
599
598
|
```python
|
600
599
|
import wandb
|
601
600
|
|
@@ -604,7 +603,6 @@ def log(
|
|
604
603
|
```
|
605
604
|
|
606
605
|
### Incremental logging
|
607
|
-
<!--yeadoc-test:init-and-log-incremental-->
|
608
606
|
```python
|
609
607
|
import wandb
|
610
608
|
|
@@ -615,7 +613,6 @@ def log(
|
|
615
613
|
```
|
616
614
|
|
617
615
|
### Histogram
|
618
|
-
<!--yeadoc-test:init-and-log-histogram-->
|
619
616
|
```python
|
620
617
|
import numpy as np
|
621
618
|
import wandb
|
@@ -627,7 +624,6 @@ def log(
|
|
627
624
|
```
|
628
625
|
|
629
626
|
### Image from numpy
|
630
|
-
<!--yeadoc-test:init-and-log-image-numpy-->
|
631
627
|
```python
|
632
628
|
import numpy as np
|
633
629
|
import wandb
|
@@ -642,7 +638,6 @@ def log(
|
|
642
638
|
```
|
643
639
|
|
644
640
|
### Image from PIL
|
645
|
-
<!--yeadoc-test:init-and-log-image-pillow-->
|
646
641
|
```python
|
647
642
|
import numpy as np
|
648
643
|
from PIL import Image as PILImage
|
@@ -664,7 +659,6 @@ def log(
|
|
664
659
|
```
|
665
660
|
|
666
661
|
### Video from numpy
|
667
|
-
<!--yeadoc-test:init-and-log-video-numpy-->
|
668
662
|
```python
|
669
663
|
import numpy as np
|
670
664
|
import wandb
|
@@ -681,7 +675,6 @@ def log(
|
|
681
675
|
```
|
682
676
|
|
683
677
|
### Matplotlib Plot
|
684
|
-
<!--yeadoc-test:init-and-log-matplotlib-->
|
685
678
|
```python
|
686
679
|
from matplotlib import pyplot as plt
|
687
680
|
import numpy as np
|
wandb/_iterutils.py
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import Iterable, TypeVar
|
4
|
+
|
5
|
+
T = TypeVar("T")
|
6
|
+
|
7
|
+
|
8
|
+
def one(
|
9
|
+
iterable: Iterable[T],
|
10
|
+
too_short: Exception | None = None,
|
11
|
+
too_long: Exception | None = None,
|
12
|
+
) -> T:
|
13
|
+
"""Return the only item in the iterable.
|
14
|
+
|
15
|
+
Note:
|
16
|
+
This is intended **only** as an internal helper/convenience function,
|
17
|
+
and its implementation is directly adapted from `more_itertools.one`.
|
18
|
+
Users needing similar functionality are strongly encouraged to use
|
19
|
+
that library instead:
|
20
|
+
https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.one
|
21
|
+
|
22
|
+
Args:
|
23
|
+
iterable: The iterable to get the only item from.
|
24
|
+
too_short: Custom exception to raise if the iterable has no items.
|
25
|
+
too_long: Custom exception to raise if the iterable has multiple items.
|
26
|
+
|
27
|
+
Raises:
|
28
|
+
ValueError or `too_short`: If the iterable has no items.
|
29
|
+
ValueError or `too_long`: If the iterable has multiple items.
|
30
|
+
"""
|
31
|
+
# For a general iterable, avoid inadvertently iterating through all values,
|
32
|
+
# which may be costly or impossible (e.g. if infinite). Only check that:
|
33
|
+
|
34
|
+
# ... the first item exists
|
35
|
+
it = iter(iterable)
|
36
|
+
try:
|
37
|
+
obj = next(it)
|
38
|
+
except StopIteration as e:
|
39
|
+
raise too_short or ValueError("Expected 1 item in iterable, got 0") from e
|
40
|
+
|
41
|
+
# ...the second item doesn't
|
42
|
+
try:
|
43
|
+
_ = next(it)
|
44
|
+
except StopIteration:
|
45
|
+
return obj
|
46
|
+
raise too_long or ValueError("Expected 1 item in iterable, got multiple")
|
wandb/apis/internal.py
CHANGED
@@ -63,6 +63,10 @@ class Api:
|
|
63
63
|
def git(self):
|
64
64
|
return self.api.git
|
65
65
|
|
66
|
+
def validate_api_key(self) -> bool:
|
67
|
+
"""Returns whether the API key stored on initialization is valid."""
|
68
|
+
return self.api.validate_api_key()
|
69
|
+
|
66
70
|
def file_current(self, *args):
|
67
71
|
return self.api.file_current(*args)
|
68
72
|
|
wandb/bin/wandb-core
CHANGED
Binary file
|
wandb/cli/cli.py
CHANGED
@@ -217,12 +217,19 @@ def projects(entity, display=True):
|
|
217
217
|
@cli.command(context_settings=CONTEXT, help="Login to Weights & Biases")
|
218
218
|
@click.argument("key", nargs=-1)
|
219
219
|
@click.option("--cloud", is_flag=True, help="Login to the cloud instead of local")
|
220
|
-
@click.option(
|
220
|
+
@click.option(
|
221
|
+
"--host", "--base-url", default=None, help="Login to a specific instance of W&B"
|
222
|
+
)
|
221
223
|
@click.option(
|
222
224
|
"--relogin", default=None, is_flag=True, help="Force relogin if already logged in."
|
223
225
|
)
|
224
226
|
@click.option("--anonymously", default=False, is_flag=True, help="Log in anonymously")
|
225
|
-
@click.option(
|
227
|
+
@click.option(
|
228
|
+
"--verify/--no-verify",
|
229
|
+
default=False,
|
230
|
+
is_flag=True,
|
231
|
+
help="Verify login credentials",
|
232
|
+
)
|
226
233
|
@display_error
|
227
234
|
def login(key, host, cloud, relogin, anonymously, verify, no_offline=False):
|
228
235
|
# TODO: move CLI to wandb-core backend
|
wandb/sdk/artifacts/artifact.py
CHANGED
@@ -19,7 +19,7 @@ from datetime import datetime, timedelta
|
|
19
19
|
from functools import partial
|
20
20
|
from pathlib import PurePosixPath
|
21
21
|
from typing import IO, TYPE_CHECKING, Any, Dict, Iterator, Literal, Sequence, Type, cast
|
22
|
-
from urllib.parse import urlparse
|
22
|
+
from urllib.parse import quote, urljoin, urlparse
|
23
23
|
|
24
24
|
import requests
|
25
25
|
|
@@ -32,6 +32,7 @@ from wandb.errors.term import termerror, termlog, termwarn
|
|
32
32
|
from wandb.sdk.artifacts._validators import (
|
33
33
|
ensure_logged,
|
34
34
|
ensure_not_finalized,
|
35
|
+
is_artifact_registry_project,
|
35
36
|
validate_aliases,
|
36
37
|
validate_tags,
|
37
38
|
)
|
@@ -532,6 +533,91 @@ class Artifact:
|
|
532
533
|
"""The artifact's type. Common types include `dataset` or `model`."""
|
533
534
|
return self._type
|
534
535
|
|
536
|
+
@property
|
537
|
+
@ensure_logged
|
538
|
+
def url(self) -> str:
|
539
|
+
"""
|
540
|
+
Constructs the URL of the artifact.
|
541
|
+
|
542
|
+
Returns:
|
543
|
+
str: The URL of the artifact.
|
544
|
+
"""
|
545
|
+
try:
|
546
|
+
base_url = self._client.app_url # type: ignore[union-attr]
|
547
|
+
except AttributeError:
|
548
|
+
return ""
|
549
|
+
|
550
|
+
if self.collection.is_sequence():
|
551
|
+
return self._construct_standard_url(base_url)
|
552
|
+
if is_artifact_registry_project(self.project):
|
553
|
+
return self._construct_registry_url(base_url)
|
554
|
+
if self._type == "model" or self.project == "model-registry":
|
555
|
+
return self._construct_model_registry_url(base_url)
|
556
|
+
return self._construct_standard_url(base_url)
|
557
|
+
|
558
|
+
def _construct_standard_url(self, base_url: str) -> str:
|
559
|
+
if not all(
|
560
|
+
[
|
561
|
+
base_url,
|
562
|
+
self.entity,
|
563
|
+
self.project,
|
564
|
+
self._type,
|
565
|
+
self.collection.name,
|
566
|
+
self._version,
|
567
|
+
]
|
568
|
+
):
|
569
|
+
return ""
|
570
|
+
return urljoin(
|
571
|
+
base_url,
|
572
|
+
f"{self.entity}/{self.project}/artifacts/{quote(self._type)}/{quote(self.collection.name)}/{self._version}",
|
573
|
+
)
|
574
|
+
|
575
|
+
def _construct_registry_url(self, base_url: str) -> str:
|
576
|
+
if not all(
|
577
|
+
[
|
578
|
+
base_url,
|
579
|
+
self.entity,
|
580
|
+
self.project,
|
581
|
+
self.collection.name,
|
582
|
+
self._version,
|
583
|
+
]
|
584
|
+
):
|
585
|
+
return ""
|
586
|
+
|
587
|
+
try:
|
588
|
+
org, *_ = InternalApi()._fetch_orgs_and_org_entities_from_entity(
|
589
|
+
self.entity
|
590
|
+
)
|
591
|
+
except ValueError:
|
592
|
+
return ""
|
593
|
+
|
594
|
+
selection_path = quote(
|
595
|
+
f"{self.entity}/{self.project}/{self.collection.name}", safe=""
|
596
|
+
)
|
597
|
+
return urljoin(
|
598
|
+
base_url,
|
599
|
+
f"orgs/{org.display_name}/registry/{self._type}?selectionPath={selection_path}&view=membership&version={self._version}",
|
600
|
+
)
|
601
|
+
|
602
|
+
def _construct_model_registry_url(self, base_url: str) -> str:
|
603
|
+
if not all(
|
604
|
+
[
|
605
|
+
base_url,
|
606
|
+
self.entity,
|
607
|
+
self.project,
|
608
|
+
self.collection.name,
|
609
|
+
self._version,
|
610
|
+
]
|
611
|
+
):
|
612
|
+
return ""
|
613
|
+
selection_path = quote(
|
614
|
+
f"{self.entity}/{self.project}/{self.collection.name}", safe=""
|
615
|
+
)
|
616
|
+
return urljoin(
|
617
|
+
base_url,
|
618
|
+
f"{self.entity}/registry/model?selectionPath={selection_path}&view=membership&version={self._version}",
|
619
|
+
)
|
620
|
+
|
535
621
|
@property
|
536
622
|
def description(self) -> str | None:
|
537
623
|
"""A description of the artifact."""
|
wandb/sdk/backend/backend.py
CHANGED
@@ -25,8 +25,6 @@ if TYPE_CHECKING:
|
|
25
25
|
from wandb.proto.wandb_internal_pb2 import Record, Result
|
26
26
|
from wandb.sdk.lib import service_connection
|
27
27
|
|
28
|
-
from ..wandb_run import Run
|
29
|
-
|
30
28
|
RecordQueue = Union["queue.Queue[Record]", multiprocessing.Queue[Record]]
|
31
29
|
ResultQueue = Union["queue.Queue[Result]", multiprocessing.Queue[Result]]
|
32
30
|
|
@@ -54,7 +52,7 @@ class Backend:
|
|
54
52
|
interface: Optional[InterfaceBase]
|
55
53
|
_internal_pid: Optional[int]
|
56
54
|
wandb_process: Optional[multiprocessing.process.BaseProcess]
|
57
|
-
_settings:
|
55
|
+
_settings: Settings
|
58
56
|
record_q: Optional["RecordQueue"]
|
59
57
|
result_q: Optional["ResultQueue"]
|
60
58
|
_mailbox: Mailbox
|
@@ -62,7 +60,7 @@ class Backend:
|
|
62
60
|
def __init__(
|
63
61
|
self,
|
64
62
|
mailbox: Mailbox,
|
65
|
-
settings:
|
63
|
+
settings: Settings,
|
66
64
|
log_level: Optional[int] = None,
|
67
65
|
service: "Optional[service_connection.ServiceConnection]" = None,
|
68
66
|
) -> None:
|
@@ -84,12 +82,7 @@ class Backend:
|
|
84
82
|
self._save_mod_path: Optional[str] = None
|
85
83
|
self._save_mod_spec = None
|
86
84
|
|
87
|
-
def _hack_set_run(self, run: "Run") -> None:
|
88
|
-
assert self.interface
|
89
|
-
self.interface._hack_set_run(run)
|
90
|
-
|
91
85
|
def _multiprocessing_setup(self) -> None:
|
92
|
-
assert self._settings
|
93
86
|
if self._settings.start_method == "thread":
|
94
87
|
return
|
95
88
|
|
@@ -141,10 +134,13 @@ class Backend:
|
|
141
134
|
def ensure_launched(self) -> None:
|
142
135
|
"""Launch backend worker if not running."""
|
143
136
|
if self._service:
|
144
|
-
|
137
|
+
assert self._settings.run_id
|
138
|
+
self.interface = self._service.make_interface(
|
139
|
+
self._mailbox,
|
140
|
+
stream_id=self._settings.run_id,
|
141
|
+
)
|
145
142
|
return
|
146
143
|
|
147
|
-
assert self._settings
|
148
144
|
settings = self._settings.model_copy()
|
149
145
|
settings.x_log_level = self._log_level or logging.DEBUG
|
150
146
|
|
@@ -24,16 +24,16 @@ def _server_accepts_client_ids() -> bool:
|
|
24
24
|
# The latest SDK version that is < "0.11.0" was released on 2021/06/29.
|
25
25
|
# AS OF NOW, 2024/11/06, we assume that all customer's server deployments accept
|
26
26
|
# client IDs.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
|
28
|
+
if util._is_offline():
|
29
|
+
# If there are any users with issues on an older backend, customers can disable the
|
30
|
+
# setting `allow_offline_artifacts` to revert the SDK's behavior back to not
|
31
|
+
# using client IDs in offline mode.
|
32
|
+
if wandb.run and not wandb.run.settings.allow_offline_artifacts:
|
33
|
+
return False
|
34
|
+
# Assume client IDs are accepted
|
35
|
+
else:
|
36
|
+
return True
|
37
37
|
|
38
38
|
# If the script is online, request the max_cli_version and ensure the server
|
39
39
|
# is of a high enough version.
|
@@ -48,7 +48,7 @@ class BoundingBoxes2D(JSONMetadata):
|
|
48
48
|
|
49
49
|
Examples:
|
50
50
|
### Log bounding boxes for a single image
|
51
|
-
|
51
|
+
|
52
52
|
```python
|
53
53
|
import numpy as np
|
54
54
|
import wandb
|
@@ -94,7 +94,7 @@ class BoundingBoxes2D(JSONMetadata):
|
|
94
94
|
```
|
95
95
|
|
96
96
|
### Log a bounding box overlay to a Table
|
97
|
-
|
97
|
+
|
98
98
|
```python
|
99
99
|
import numpy as np
|
100
100
|
import wandb
|
@@ -33,7 +33,7 @@ class ImageMask(Media):
|
|
33
33
|
|
34
34
|
Examples:
|
35
35
|
### Logging a single masked image
|
36
|
-
|
36
|
+
|
37
37
|
```python
|
38
38
|
import numpy as np
|
39
39
|
import wandb
|
@@ -69,7 +69,7 @@ class ImageMask(Media):
|
|
69
69
|
```
|
70
70
|
|
71
71
|
### Log a masked image inside a Table
|
72
|
-
|
72
|
+
|
73
73
|
```python
|
74
74
|
import numpy as np
|
75
75
|
import wandb
|
wandb/sdk/data_types/image.py
CHANGED
@@ -77,7 +77,6 @@ class Image(BatchableMedia):
|
|
77
77
|
|
78
78
|
Examples:
|
79
79
|
### Create a wandb.Image from a numpy array
|
80
|
-
<!--yeadoc-test:log-image-numpy-->
|
81
80
|
```python
|
82
81
|
import numpy as np
|
83
82
|
import wandb
|
@@ -92,7 +91,6 @@ class Image(BatchableMedia):
|
|
92
91
|
```
|
93
92
|
|
94
93
|
### Create a wandb.Image from a PILImage
|
95
|
-
<!--yeadoc-test:log-image-pillow-->
|
96
94
|
```python
|
97
95
|
import numpy as np
|
98
96
|
from PIL import Image as PILImage
|
@@ -111,7 +109,6 @@ class Image(BatchableMedia):
|
|
111
109
|
```
|
112
110
|
|
113
111
|
### log .jpg rather than .png (default)
|
114
|
-
<!--yeadoc-test:log-image-format-->
|
115
112
|
```python
|
116
113
|
import numpy as np
|
117
114
|
import wandb
|
wandb/sdk/data_types/utils.py
CHANGED
@@ -148,12 +148,8 @@ def val_to_json(
|
|
148
148
|
"partitioned-table",
|
149
149
|
"joined-table",
|
150
150
|
]:
|
151
|
-
#
|
152
|
-
|
153
|
-
# files in an artifact
|
154
|
-
# we sanitize the key to meet the constraints
|
155
|
-
# in this case, leaving only alphanumerics or underscores.
|
156
|
-
sanitized_key = re.sub(r"[^a-zA-Z0-9_]+", "", key)
|
151
|
+
# Sanitize the key to meet the constraints of artifact names.
|
152
|
+
sanitized_key = re.sub(r"[^a-zA-Z0-9_\-.]+", "", key)
|
157
153
|
art = wandb.Artifact(f"run-{run.id}-{sanitized_key}", "run_table")
|
158
154
|
art.add(val, key)
|
159
155
|
run.log_artifact(art)
|
wandb/sdk/interface/interface.py
CHANGED
@@ -90,16 +90,11 @@ def file_enum_to_policy(enum: "pb.FilesItem.PolicyType.V") -> "PolicyName":
|
|
90
90
|
|
91
91
|
|
92
92
|
class InterfaceBase:
|
93
|
-
_run: Optional["Run"]
|
94
93
|
_drop: bool
|
95
94
|
|
96
95
|
def __init__(self) -> None:
|
97
|
-
self._run = None
|
98
96
|
self._drop = False
|
99
97
|
|
100
|
-
def _hack_set_run(self, run: "Run") -> None:
|
101
|
-
self._run = run
|
102
|
-
|
103
98
|
def publish_header(self) -> None:
|
104
99
|
header = pb.HeaderRecord()
|
105
100
|
self._publish_header(header)
|
@@ -232,7 +227,12 @@ class InterfaceBase:
|
|
232
227
|
update.value_json = json.dumps(v)
|
233
228
|
return summary
|
234
229
|
|
235
|
-
def _summary_encode(
|
230
|
+
def _summary_encode(
|
231
|
+
self,
|
232
|
+
value: Any,
|
233
|
+
path_from_root: str,
|
234
|
+
run: "Run",
|
235
|
+
) -> dict:
|
236
236
|
"""Normalize, compress, and encode sub-objects for backend storage.
|
237
237
|
|
238
238
|
value: Object to encode.
|
@@ -250,12 +250,14 @@ class InterfaceBase:
|
|
250
250
|
json_value = {}
|
251
251
|
for key, value in value.items(): # noqa: B020
|
252
252
|
json_value[key] = self._summary_encode(
|
253
|
-
value,
|
253
|
+
value,
|
254
|
+
path_from_root + "." + key,
|
255
|
+
run=run,
|
254
256
|
)
|
255
257
|
return json_value
|
256
258
|
else:
|
257
259
|
friendly_value, converted = json_friendly(
|
258
|
-
val_to_json(
|
260
|
+
val_to_json(run, path_from_root, value, namespace="summary")
|
259
261
|
)
|
260
262
|
json_value, compressed = maybe_compress_summary(
|
261
263
|
friendly_value, get_h5_typename(value)
|
@@ -267,7 +269,11 @@ class InterfaceBase:
|
|
267
269
|
|
268
270
|
return json_value
|
269
271
|
|
270
|
-
def _make_summary(
|
272
|
+
def _make_summary(
|
273
|
+
self,
|
274
|
+
summary_record: sr.SummaryRecord,
|
275
|
+
run: "Run",
|
276
|
+
) -> pb.SummaryRecord:
|
271
277
|
pb_summary_record = pb.SummaryRecord()
|
272
278
|
|
273
279
|
for item in summary_record.update:
|
@@ -282,7 +288,11 @@ class InterfaceBase:
|
|
282
288
|
pb_summary_item.key = item.key[0]
|
283
289
|
|
284
290
|
path_from_root = ".".join(item.key)
|
285
|
-
json_value = self._summary_encode(
|
291
|
+
json_value = self._summary_encode(
|
292
|
+
item.value,
|
293
|
+
path_from_root,
|
294
|
+
run=run,
|
295
|
+
)
|
286
296
|
json_value, _ = json_friendly(json_value) # type: ignore
|
287
297
|
|
288
298
|
pb_summary_item.value_json = json.dumps(
|
@@ -303,8 +313,12 @@ class InterfaceBase:
|
|
303
313
|
|
304
314
|
return pb_summary_record
|
305
315
|
|
306
|
-
def publish_summary(
|
307
|
-
|
316
|
+
def publish_summary(
|
317
|
+
self,
|
318
|
+
run: "Run",
|
319
|
+
summary_record: sr.SummaryRecord,
|
320
|
+
) -> None:
|
321
|
+
pb_summary_record = self._make_summary(summary_record, run=run)
|
308
322
|
self._publish_summary(pb_summary_record)
|
309
323
|
|
310
324
|
@abstractmethod
|
@@ -16,32 +16,28 @@ from .router_sock import MessageSockRouter
|
|
16
16
|
if TYPE_CHECKING:
|
17
17
|
from wandb.proto import wandb_internal_pb2 as pb
|
18
18
|
|
19
|
-
from ..wandb_run import Run
|
20
|
-
|
21
19
|
|
22
20
|
logger = logging.getLogger("wandb")
|
23
21
|
|
24
22
|
|
25
23
|
class InterfaceSock(InterfaceShared):
|
26
|
-
_stream_id: Optional[str]
|
27
|
-
_sock_client: SockClient
|
28
24
|
_mailbox: Mailbox
|
29
25
|
|
30
|
-
def __init__(
|
26
|
+
def __init__(
|
27
|
+
self,
|
28
|
+
sock_client: SockClient,
|
29
|
+
mailbox: Mailbox,
|
30
|
+
stream_id: str,
|
31
|
+
) -> None:
|
31
32
|
# _sock_client is used when abstract method _init_router() is called by constructor
|
32
33
|
self._sock_client = sock_client
|
33
34
|
super().__init__(mailbox=mailbox)
|
34
35
|
self._process_check = False
|
35
|
-
self._stream_id =
|
36
|
+
self._stream_id = stream_id
|
36
37
|
|
37
38
|
def _init_router(self) -> None:
|
38
39
|
self._router = MessageSockRouter(self._sock_client, mailbox=self._mailbox)
|
39
40
|
|
40
|
-
def _hack_set_run(self, run: "Run") -> None:
|
41
|
-
super()._hack_set_run(run)
|
42
|
-
assert run._settings.run_id
|
43
|
-
self._stream_id = run._settings.run_id
|
44
|
-
|
45
41
|
def _assign(self, record: Any) -> None:
|
46
42
|
assert self._stream_id
|
47
43
|
record._info.stream_id = self._stream_id
|
@@ -243,6 +243,7 @@ class Api:
|
|
243
243
|
),
|
244
244
|
environ: MutableMapping = os.environ,
|
245
245
|
retry_callback: Optional[Callable[[int, str], Any]] = None,
|
246
|
+
api_key: Optional[str] = None,
|
246
247
|
) -> None:
|
247
248
|
self._environ = environ
|
248
249
|
self._global_context = context.Context()
|
@@ -284,7 +285,9 @@ class Api:
|
|
284
285
|
self._extra_http_headers.update(_thread_local_api_settings.headers or {})
|
285
286
|
|
286
287
|
auth = None
|
287
|
-
if
|
288
|
+
if api_key:
|
289
|
+
auth = ("api", api_key)
|
290
|
+
elif self.access_token is not None:
|
288
291
|
self._extra_http_headers["Authorization"] = f"Bearer {self.access_token}"
|
289
292
|
elif _thread_local_api_settings.cookies is None:
|
290
293
|
auth = ("api", self.api_key or "")
|
@@ -400,6 +403,11 @@ class Api:
|
|
400
403
|
wandb.termerror(f"Error while calling W&B API: {error} ({response})")
|
401
404
|
raise
|
402
405
|
|
406
|
+
def validate_api_key(self) -> bool:
|
407
|
+
"""Returns whether the API key stored on initialization is valid."""
|
408
|
+
res = self.execute(gql("query { viewer { id } }"))
|
409
|
+
return res is not None and res["viewer"] is not None
|
410
|
+
|
403
411
|
def set_current_run_id(self, run_id: str) -> None:
|
404
412
|
self._current_run_id = run_id
|
405
413
|
|
@@ -118,7 +118,7 @@ class CPU:
|
|
118
118
|
self.name: str = self.__class__.__name__.lower()
|
119
119
|
self.metrics: List[Metric] = [
|
120
120
|
ProcessCpuPercent(settings.x_stats_pid),
|
121
|
-
CpuPercent(),
|
121
|
+
# CpuPercent(),
|
122
122
|
ProcessCpuThreads(settings.x_stats_pid),
|
123
123
|
]
|
124
124
|
self.metrics_monitor: MetricsMonitor = MetricsMonitor(
|
wandb/sdk/lib/apikey.py
CHANGED
@@ -104,7 +104,6 @@ def prompt_api_key( # noqa: C901
|
|
104
104
|
log_string = term.LOG_STRING_NOCOLOR
|
105
105
|
key = wandb.jupyter.attempt_colab_login(app_url) # type: ignore
|
106
106
|
if key is not None:
|
107
|
-
write_key(settings, key, api=api)
|
108
107
|
return key # type: ignore
|
109
108
|
|
110
109
|
if anon_mode == "must":
|
@@ -123,24 +122,19 @@ def prompt_api_key( # noqa: C901
|
|
123
122
|
choices, input_timeout=settings.login_timeout, jupyter=jupyter
|
124
123
|
)
|
125
124
|
|
125
|
+
key = None
|
126
126
|
api_ask = (
|
127
127
|
f"{log_string}: Paste an API key from your profile and hit enter, "
|
128
128
|
"or press ctrl+c to quit"
|
129
129
|
)
|
130
130
|
if result == LOGIN_CHOICE_ANON:
|
131
131
|
key = api.create_anonymous_api_key()
|
132
|
-
|
133
|
-
write_key(settings, key, api=api, anonymous=True)
|
134
|
-
return key # type: ignore
|
135
132
|
elif result == LOGIN_CHOICE_NEW:
|
136
133
|
key = browser_callback(signup=True) if browser_callback else None
|
137
134
|
|
138
135
|
if not key:
|
139
136
|
wandb.termlog(f"Create an account here: {app_url}/authorize?signup=true")
|
140
137
|
key = input_callback(api_ask).strip()
|
141
|
-
|
142
|
-
write_key(settings, key, api=api)
|
143
|
-
return key # type: ignore
|
144
138
|
elif result == LOGIN_CHOICE_EXISTS:
|
145
139
|
key = browser_callback() if browser_callback else None
|
146
140
|
|
@@ -158,8 +152,6 @@ def prompt_api_key( # noqa: C901
|
|
158
152
|
f"You can find your API key in your browser here: {app_url}/authorize"
|
159
153
|
)
|
160
154
|
key = input_callback(api_ask).strip()
|
161
|
-
write_key(settings, key, api=api)
|
162
|
-
return key # type: ignore
|
163
155
|
elif result == LOGIN_CHOICE_NOTTY:
|
164
156
|
# TODO: Needs refactor as this needs to be handled by caller
|
165
157
|
return False
|
@@ -172,8 +164,9 @@ def prompt_api_key( # noqa: C901
|
|
172
164
|
browser_callback() if jupyter and browser_callback else (None, False)
|
173
165
|
)
|
174
166
|
|
175
|
-
|
176
|
-
|
167
|
+
if not key:
|
168
|
+
raise ValueError("No API key specified.")
|
169
|
+
return key
|
177
170
|
|
178
171
|
|
179
172
|
def write_netrc(host: str, entity: str, key: str) -> Optional[bool]:
|
@@ -232,7 +225,6 @@ def write_key(
|
|
232
225
|
settings: "Settings",
|
233
226
|
key: Optional[str],
|
234
227
|
api: Optional["InternalApi"] = None,
|
235
|
-
anonymous: bool = False,
|
236
228
|
) -> None:
|
237
229
|
if not key:
|
238
230
|
raise ValueError("No API key specified.")
|
@@ -249,11 +241,6 @@ def write_key(
|
|
249
241
|
"API key must be 40 characters long, yours was {}".format(len(key))
|
250
242
|
)
|
251
243
|
|
252
|
-
if anonymous:
|
253
|
-
api.set_setting("anonymous", "must", globally=True, persist=True)
|
254
|
-
else:
|
255
|
-
api.clear_setting("anonymous", globally=True, persist=True)
|
256
|
-
|
257
244
|
write_netrc(settings.base_url, "user", key)
|
258
245
|
|
259
246
|
|