wandb 0.16.4__py3-none-any.whl → 0.16.5__py3-none-any.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 +2 -2
- wandb/agents/pyagent.py +1 -1
- wandb/apis/public/api.py +6 -6
- wandb/apis/reports/v2/interface.py +4 -8
- wandb/apis/reports/v2/internal.py +12 -45
- wandb/cli/cli.py +24 -3
- wandb/integration/ultralytics/callback.py +0 -1
- wandb/proto/v3/wandb_internal_pb2.py +332 -312
- wandb/proto/v3/wandb_settings_pb2.py +13 -3
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_internal_pb2.py +316 -312
- wandb/proto/v4/wandb_settings_pb2.py +5 -3
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/sdk/artifacts/artifact.py +67 -17
- wandb/sdk/artifacts/artifact_manifest_entry.py +6 -1
- wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -0
- wandb/sdk/artifacts/artifact_saver.py +1 -18
- wandb/sdk/artifacts/storage_handler.py +2 -1
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +13 -5
- wandb/sdk/interface/interface.py +42 -9
- wandb/sdk/interface/interface_shared.py +13 -7
- wandb/sdk/internal/file_stream.py +19 -0
- wandb/sdk/internal/handler.py +1 -4
- wandb/sdk/internal/internal_api.py +2 -0
- wandb/sdk/internal/job_builder.py +45 -17
- wandb/sdk/internal/sender.py +53 -28
- wandb/sdk/internal/settings_static.py +9 -0
- wandb/sdk/internal/system/system_info.py +4 -1
- wandb/sdk/launch/create_job.py +1 -0
- wandb/sdk/launch/runner/kubernetes_runner.py +20 -2
- wandb/sdk/launch/utils.py +5 -5
- wandb/sdk/lib/__init__.py +2 -5
- wandb/sdk/lib/_settings_toposort_generated.py +1 -0
- wandb/sdk/lib/filesystem.py +11 -1
- wandb/sdk/lib/run_moment.py +72 -0
- wandb/sdk/service/streams.py +1 -6
- wandb/sdk/wandb_init.py +12 -1
- wandb/sdk/wandb_login.py +43 -26
- wandb/sdk/wandb_run.py +158 -89
- wandb/sdk/wandb_settings.py +53 -16
- wandb/testing/relay.py +5 -6
- {wandb-0.16.4.dist-info → wandb-0.16.5.dist-info}/METADATA +1 -1
- {wandb-0.16.4.dist-info → wandb-0.16.5.dist-info}/RECORD +47 -46
- {wandb-0.16.4.dist-info → wandb-0.16.5.dist-info}/WHEEL +1 -1
- {wandb-0.16.4.dist-info → wandb-0.16.5.dist-info}/LICENSE +0 -0
- {wandb-0.16.4.dist-info → wandb-0.16.5.dist-info}/entry_points.txt +0 -0
- {wandb-0.16.4.dist-info → wandb-0.16.5.dist-info}/top_level.txt +0 -0
wandb/sdk/wandb_init.py
CHANGED
@@ -7,6 +7,7 @@ your evaluation script, and each step would be tracked as a run in W&B.
|
|
7
7
|
For more on using `wandb.init()`, including code snippets, check out our
|
8
8
|
[guide and FAQs](https://docs.wandb.ai/guides/track/launch).
|
9
9
|
"""
|
10
|
+
|
10
11
|
import copy
|
11
12
|
import json
|
12
13
|
import logging
|
@@ -828,7 +829,7 @@ class _WandbInit:
|
|
828
829
|
and self.settings.launch_config_path
|
829
830
|
and os.path.exists(self.settings.launch_config_path)
|
830
831
|
):
|
831
|
-
run.
|
832
|
+
run.save(self.settings.launch_config_path)
|
832
833
|
# put artifacts in run config here
|
833
834
|
# since doing so earlier will cause an error
|
834
835
|
# as the run is not upserted
|
@@ -961,6 +962,7 @@ def init(
|
|
961
962
|
monitor_gym: Optional[bool] = None,
|
962
963
|
save_code: Optional[bool] = None,
|
963
964
|
id: Optional[str] = None,
|
965
|
+
fork_from: Optional[str] = None,
|
964
966
|
settings: Union[Settings, Dict[str, Any], None] = None,
|
965
967
|
) -> Union[Run, RunDisabled, None]:
|
966
968
|
r"""Start a new run to track and log to W&B.
|
@@ -1122,6 +1124,10 @@ def init(
|
|
1122
1124
|
for saving hyperparameters to compare across runs. The ID cannot
|
1123
1125
|
contain the following special characters: `/\#?%:`.
|
1124
1126
|
See [our guide to resuming runs](https://docs.wandb.com/guides/runs/resuming).
|
1127
|
+
fork_from: (str, optional) A string with the format <run_id>?_step=<step> describing
|
1128
|
+
a moment in a previous run to fork a new run from. Creates a new run that picks up
|
1129
|
+
logging history from the specified run at the specified moment. The target run must
|
1130
|
+
be in the current project.
|
1125
1131
|
|
1126
1132
|
Examples:
|
1127
1133
|
### Set where the run is logged
|
@@ -1167,6 +1173,11 @@ def init(
|
|
1167
1173
|
error_seen = None
|
1168
1174
|
except_exit = None
|
1169
1175
|
run: Optional[Union[Run, RunDisabled]] = None
|
1176
|
+
|
1177
|
+
# convert fork_from into a version that can be passed to settings
|
1178
|
+
if fork_from is not None and resume is not None:
|
1179
|
+
raise ValueError("Cannot specify both `fork_from` and `resume`")
|
1180
|
+
|
1170
1181
|
try:
|
1171
1182
|
wi = _WandbInit()
|
1172
1183
|
wi.setup(kwargs)
|
wandb/sdk/wandb_login.py
CHANGED
@@ -22,7 +22,7 @@ from wandb.old.settings import Settings as OldSettings
|
|
22
22
|
from ..apis import InternalApi
|
23
23
|
from .internal.internal_api import Api
|
24
24
|
from .lib import apikey
|
25
|
-
from .wandb_settings import Settings
|
25
|
+
from .wandb_settings import Settings
|
26
26
|
|
27
27
|
|
28
28
|
def _handle_host_wandb_setting(host: Optional[str], cloud: bool = False) -> None:
|
@@ -80,11 +80,17 @@ def login(
|
|
80
80
|
_handle_host_wandb_setting(host)
|
81
81
|
if wandb.setup()._settings._noop:
|
82
82
|
return True
|
83
|
-
kwargs = dict(locals())
|
84
|
-
_verify = kwargs.pop("verify", False)
|
85
|
-
configured = _login(**kwargs)
|
86
83
|
|
87
|
-
|
84
|
+
configured = _login(
|
85
|
+
anonymous=anonymous,
|
86
|
+
key=key,
|
87
|
+
relogin=relogin,
|
88
|
+
host=host,
|
89
|
+
force=force,
|
90
|
+
timeout=timeout,
|
91
|
+
)
|
92
|
+
|
93
|
+
if verify:
|
88
94
|
from . import wandb_setup
|
89
95
|
|
90
96
|
singleton = wandb_setup._WandbSetup._instance
|
@@ -115,22 +121,32 @@ class _WandbLogin:
|
|
115
121
|
self._key = None
|
116
122
|
self._relogin = None
|
117
123
|
|
118
|
-
def setup(
|
119
|
-
self
|
124
|
+
def setup(
|
125
|
+
self,
|
126
|
+
*,
|
127
|
+
anonymous: Optional[Literal["must", "allow", "never"]] = None,
|
128
|
+
key: Optional[str] = None,
|
129
|
+
relogin: Optional[bool] = None,
|
130
|
+
host: Optional[str] = None,
|
131
|
+
force: Optional[bool] = None,
|
132
|
+
timeout: Optional[int] = None,
|
133
|
+
):
|
134
|
+
self._relogin = relogin
|
120
135
|
|
121
136
|
# built up login settings
|
122
137
|
login_settings: Settings = wandb.Settings()
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
138
|
+
logger = wandb.setup()._get_logger()
|
139
|
+
|
140
|
+
login_settings._apply_login(
|
141
|
+
{
|
142
|
+
"anonymous": anonymous,
|
143
|
+
"key": key,
|
144
|
+
"host": host,
|
145
|
+
"force": force,
|
146
|
+
"timeout": timeout,
|
147
|
+
},
|
148
|
+
_logger=logger,
|
149
|
+
)
|
134
150
|
|
135
151
|
# make sure they are applied globally
|
136
152
|
self._wl = wandb.setup(settings=login_settings)
|
@@ -259,6 +275,7 @@ class _WandbLogin:
|
|
259
275
|
|
260
276
|
|
261
277
|
def _login(
|
278
|
+
*,
|
262
279
|
anonymous: Optional[Literal["must", "allow", "never"]] = None,
|
263
280
|
key: Optional[str] = None,
|
264
281
|
relogin: Optional[bool] = None,
|
@@ -270,9 +287,6 @@ def _login(
|
|
270
287
|
_disable_warning: Optional[bool] = None,
|
271
288
|
_entity: Optional[str] = None,
|
272
289
|
):
|
273
|
-
kwargs = dict(locals())
|
274
|
-
_disable_warning = kwargs.pop("_disable_warning", None)
|
275
|
-
|
276
290
|
if wandb.run is not None:
|
277
291
|
if not _disable_warning:
|
278
292
|
wandb.termwarn("Calling wandb.login() after wandb.init() has no effect.")
|
@@ -280,20 +294,24 @@ def _login(
|
|
280
294
|
|
281
295
|
wlogin = _WandbLogin()
|
282
296
|
|
283
|
-
_backend = kwargs.pop("_backend", None)
|
284
297
|
if _backend:
|
285
298
|
wlogin.set_backend(_backend)
|
286
299
|
|
287
|
-
_silent = kwargs.pop("_silent", None)
|
288
300
|
if _silent:
|
289
301
|
wlogin.set_silent(_silent)
|
290
302
|
|
291
|
-
_entity = kwargs.pop("_entity", None)
|
292
303
|
if _entity:
|
293
304
|
wlogin.set_entity(_entity)
|
294
305
|
|
295
306
|
# configure login object
|
296
|
-
wlogin.setup(
|
307
|
+
wlogin.setup(
|
308
|
+
anonymous=anonymous,
|
309
|
+
key=key,
|
310
|
+
relogin=relogin,
|
311
|
+
host=host,
|
312
|
+
force=force,
|
313
|
+
timeout=timeout,
|
314
|
+
)
|
297
315
|
|
298
316
|
if wlogin._settings._offline:
|
299
317
|
return False
|
@@ -306,7 +324,6 @@ def _login(
|
|
306
324
|
# perform a login
|
307
325
|
logged_in = wlogin.login()
|
308
326
|
|
309
|
-
key = kwargs.get("key")
|
310
327
|
if key:
|
311
328
|
wlogin.configure_api_key(key)
|
312
329
|
|
wandb/sdk/wandb_run.py
CHANGED
@@ -6,6 +6,7 @@ import json
|
|
6
6
|
import logging
|
7
7
|
import numbers
|
8
8
|
import os
|
9
|
+
import pathlib
|
9
10
|
import re
|
10
11
|
import sys
|
11
12
|
import threading
|
@@ -42,7 +43,6 @@ from wandb.apis import internal, public
|
|
42
43
|
from wandb.apis.internal import Api
|
43
44
|
from wandb.apis.public import Api as PublicApi
|
44
45
|
from wandb.proto.wandb_internal_pb2 import (
|
45
|
-
JobInfoResponse,
|
46
46
|
MetricRecord,
|
47
47
|
PollExitResponse,
|
48
48
|
Result,
|
@@ -531,7 +531,6 @@ class Run:
|
|
531
531
|
_check_version: Optional["CheckVersionResponse"]
|
532
532
|
_sampled_history: Optional["SampledHistoryResponse"]
|
533
533
|
_final_summary: Optional["GetSummaryResponse"]
|
534
|
-
_job_info: Optional["JobInfoResponse"]
|
535
534
|
_poll_exit_handle: Optional[MailboxHandle]
|
536
535
|
_poll_exit_response: Optional[PollExitResponse]
|
537
536
|
_server_info_response: Optional[ServerInfoResponse]
|
@@ -642,7 +641,6 @@ class Run:
|
|
642
641
|
self._server_info_response = None
|
643
642
|
self._internal_messages_response = None
|
644
643
|
self._poll_exit_handle = None
|
645
|
-
self._job_info = None
|
646
644
|
|
647
645
|
# Initialize telemetry object
|
648
646
|
self._telemetry_obj = telemetry.TelemetryRecord()
|
@@ -673,6 +671,12 @@ class Run:
|
|
673
671
|
os.path.join("code", self._settings.program_relpath)
|
674
672
|
)
|
675
673
|
|
674
|
+
if self._settings.fork_from is not None:
|
675
|
+
config[wandb_key]["branch_point"] = {
|
676
|
+
"run_id": self._settings.fork_from.run,
|
677
|
+
"step": self._settings.fork_from.value,
|
678
|
+
}
|
679
|
+
|
676
680
|
self._config._update(config, ignore_locked=True)
|
677
681
|
|
678
682
|
if sweep_config:
|
@@ -734,7 +738,7 @@ class Run:
|
|
734
738
|
and self._settings.launch_config_path
|
735
739
|
and os.path.exists(self._settings.launch_config_path)
|
736
740
|
):
|
737
|
-
self.
|
741
|
+
self.save(self._settings.launch_config_path)
|
738
742
|
with open(self._settings.launch_config_path) as fp:
|
739
743
|
launch_config = json.loads(fp.read())
|
740
744
|
if launch_config.get("overrides", {}).get("artifacts") is not None:
|
@@ -1385,6 +1389,8 @@ class Run:
|
|
1385
1389
|
|
1386
1390
|
@_run_decorator._noop_on_finish()
|
1387
1391
|
def _summary_update_callback(self, summary_record: SummaryRecord) -> None:
|
1392
|
+
with telemetry.context(run=self) as tel:
|
1393
|
+
tel.feature.set_summary = True
|
1388
1394
|
if self._backend and self._backend.interface:
|
1389
1395
|
self._backend.interface.publish_summary(summary_record)
|
1390
1396
|
|
@@ -1811,6 +1817,10 @@ class Run:
|
|
1811
1817
|
ValueError: if invalid data is passed
|
1812
1818
|
|
1813
1819
|
"""
|
1820
|
+
if step is not None:
|
1821
|
+
with telemetry.context(run=self) as tel:
|
1822
|
+
tel.feature.set_step_log = True
|
1823
|
+
|
1814
1824
|
if sync is not None:
|
1815
1825
|
deprecate.deprecate(
|
1816
1826
|
field_name=deprecate.Deprecated.run__log_sync,
|
@@ -1831,20 +1841,53 @@ class Run:
|
|
1831
1841
|
@_run_decorator._attach
|
1832
1842
|
def save(
|
1833
1843
|
self,
|
1834
|
-
glob_str: Optional[str] = None,
|
1835
|
-
base_path: Optional[str] = None,
|
1844
|
+
glob_str: Optional[Union[str, os.PathLike]] = None,
|
1845
|
+
base_path: Optional[Union[str, os.PathLike]] = None,
|
1836
1846
|
policy: "PolicyName" = "live",
|
1837
1847
|
) -> Union[bool, List[str]]:
|
1838
|
-
"""
|
1848
|
+
"""Sync one or more files to W&B.
|
1849
|
+
|
1850
|
+
Relative paths are relative to the current working directory.
|
1851
|
+
|
1852
|
+
A Unix glob, such as "myfiles/*", is expanded at the time `save` is
|
1853
|
+
called regardless of the `policy`. In particular, new files are not
|
1854
|
+
picked up automatically.
|
1855
|
+
|
1856
|
+
A `base_path` may be provided to control the directory structure of
|
1857
|
+
uploaded files. It should be a prefix of `glob_str`, and the direcotry
|
1858
|
+
structure beneath it is preserved. It's best understood through
|
1859
|
+
examples:
|
1860
|
+
|
1861
|
+
```
|
1862
|
+
wandb.save("these/are/myfiles/*")
|
1863
|
+
# => Saves files in a "these/are/myfiles/" folder in the run.
|
1864
|
+
|
1865
|
+
wandb.save("these/are/myfiles/*", base_path="these")
|
1866
|
+
# => Saves files in an "are/myfiles/" folder in the run.
|
1867
|
+
|
1868
|
+
wandb.save("/User/username/Documents/run123/*.txt")
|
1869
|
+
# => Saves files in a "run123/" folder in the run.
|
1870
|
+
|
1871
|
+
wandb.save("/User/username/Documents/run123/*.txt", base_path="/User")
|
1872
|
+
# => Saves files in a "username/Documents/run123/" folder in the run.
|
1873
|
+
|
1874
|
+
wandb.save("files/*/saveme.txt")
|
1875
|
+
# => Saves each "saveme.txt" file in an appropriate subdirectory
|
1876
|
+
# of "files/".
|
1877
|
+
```
|
1839
1878
|
|
1840
1879
|
Arguments:
|
1841
|
-
glob_str:
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1880
|
+
glob_str: A relative or absolute path or Unix glob.
|
1881
|
+
base_path: A path to use to infer a directory structure; see examples.
|
1882
|
+
policy: One of `live`, `now`, or `end`.
|
1883
|
+
* live: upload the file as it changes, overwriting the previous version
|
1884
|
+
* now: upload the file once now
|
1885
|
+
* end: upload file when the run ends
|
1886
|
+
|
1887
|
+
Returns:
|
1888
|
+
Paths to the symlinks created for the matched files.
|
1889
|
+
|
1890
|
+
For historical reasons, this may return a boolean in legacy code.
|
1848
1891
|
"""
|
1849
1892
|
if glob_str is None:
|
1850
1893
|
# noop for historical reasons, run.save() may be called in legacy code
|
@@ -1857,77 +1900,116 @@ class Run:
|
|
1857
1900
|
)
|
1858
1901
|
return True
|
1859
1902
|
|
1860
|
-
|
1903
|
+
if isinstance(glob_str, bytes):
|
1904
|
+
# Preserved for backward compatibility: allow bytes inputs.
|
1905
|
+
glob_str = glob_str.decode("utf-8")
|
1906
|
+
if isinstance(glob_str, str) and (
|
1907
|
+
glob_str.startswith("gs://") or glob_str.startswith("s3://")
|
1908
|
+
):
|
1909
|
+
# Provide a better error message for a common misuse.
|
1910
|
+
wandb.termlog(f"{glob_str} is a cloud storage url, can't save file to W&B.")
|
1911
|
+
return []
|
1912
|
+
glob_path = pathlib.Path(glob_str)
|
1913
|
+
|
1914
|
+
if base_path is not None:
|
1915
|
+
base_path = pathlib.Path(base_path)
|
1916
|
+
elif not glob_path.is_absolute():
|
1917
|
+
base_path = pathlib.Path(".")
|
1918
|
+
else:
|
1919
|
+
# Absolute glob paths with no base path get special handling.
|
1920
|
+
wandb.termwarn(
|
1921
|
+
"Saving files without folders. If you want to preserve "
|
1922
|
+
"subdirectories pass base_path to wandb.save, i.e. "
|
1923
|
+
'wandb.save("/mnt/folder/file.h5", base_path="/mnt")',
|
1924
|
+
repeat=False,
|
1925
|
+
)
|
1926
|
+
base_path = glob_path.resolve().parent.parent
|
1861
1927
|
|
1862
|
-
def _save(
|
1863
|
-
self,
|
1864
|
-
glob_str: Optional[str] = None,
|
1865
|
-
base_path: Optional[str] = None,
|
1866
|
-
policy: "PolicyName" = "live",
|
1867
|
-
) -> Union[bool, List[str]]:
|
1868
1928
|
if policy not in ("live", "end", "now"):
|
1869
1929
|
raise ValueError(
|
1870
|
-
'Only "live" "end" and "now" policies are currently supported.'
|
1930
|
+
'Only "live", "end" and "now" policies are currently supported.'
|
1871
1931
|
)
|
1872
|
-
if isinstance(glob_str, bytes):
|
1873
|
-
glob_str = glob_str.decode("utf-8")
|
1874
|
-
if not isinstance(glob_str, str):
|
1875
|
-
raise ValueError("Must call wandb.save(glob_str) with glob_str a str")
|
1876
1932
|
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1933
|
+
resolved_glob_path = glob_path.resolve()
|
1934
|
+
resolved_base_path = base_path.resolve()
|
1935
|
+
|
1936
|
+
return self._save(
|
1937
|
+
resolved_glob_path,
|
1938
|
+
resolved_base_path,
|
1939
|
+
policy,
|
1940
|
+
)
|
1941
|
+
|
1942
|
+
def _save(
|
1943
|
+
self,
|
1944
|
+
glob_path: pathlib.Path,
|
1945
|
+
base_path: pathlib.Path,
|
1946
|
+
policy: "PolicyName",
|
1947
|
+
) -> List[str]:
|
1948
|
+
# Can't use is_relative_to() because that's added in Python 3.9,
|
1949
|
+
# but we support down to Python 3.7.
|
1950
|
+
if not str(glob_path).startswith(str(base_path)):
|
1951
|
+
raise ValueError("Glob may not walk above the base path")
|
1952
|
+
|
1953
|
+
if glob_path == base_path:
|
1954
|
+
raise ValueError("Glob cannot be the same as the base path")
|
1955
|
+
|
1956
|
+
relative_glob = glob_path.relative_to(base_path)
|
1957
|
+
if relative_glob.parts[0] == "*":
|
1958
|
+
raise ValueError("Glob may not start with '*' relative to the base path")
|
1959
|
+
relative_glob_str = GlobStr(str(relative_glob))
|
1891
1960
|
|
1892
1961
|
with telemetry.context(run=self) as tel:
|
1893
1962
|
tel.feature.save = True
|
1894
1963
|
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
1917
|
-
|
1918
|
-
|
1964
|
+
# Paths to the symlinks created for the globbed files.
|
1965
|
+
wandb_files = [
|
1966
|
+
str(path)
|
1967
|
+
for path in pathlib.Path(
|
1968
|
+
self._settings.files_dir,
|
1969
|
+
).glob(relative_glob_str)
|
1970
|
+
]
|
1971
|
+
|
1972
|
+
had_symlinked_files = len(wandb_files) > 0
|
1973
|
+
is_star_glob = "*" in relative_glob_str
|
1974
|
+
|
1975
|
+
# The base_path may itself be a glob, so we can't do
|
1976
|
+
# base_path.glob(relative_glob_str)
|
1977
|
+
for path_str in glob.glob(str(base_path / relative_glob_str)):
|
1978
|
+
path = pathlib.Path(path_str).absolute()
|
1979
|
+
|
1980
|
+
# We can't use relative_to() because base_path may be a glob.
|
1981
|
+
saved_path = pathlib.Path(*path.parts[len(base_path.parts) :])
|
1982
|
+
|
1983
|
+
wandb_path = pathlib.Path(self._settings.files_dir, saved_path)
|
1984
|
+
|
1985
|
+
wandb_files.append(str(wandb_path))
|
1986
|
+
wandb_path.parent.mkdir(parents=True, exist_ok=True)
|
1987
|
+
|
1988
|
+
# Delete the symlink if it exists.
|
1989
|
+
try:
|
1990
|
+
wandb_path.unlink()
|
1991
|
+
except FileNotFoundError:
|
1992
|
+
# In Python 3.8, we would pass missing_ok=True, but as of now
|
1993
|
+
# we support down to Python 3.7.
|
1994
|
+
pass
|
1995
|
+
|
1996
|
+
wandb_path.symlink_to(path)
|
1997
|
+
|
1998
|
+
# Inform users that new files aren't detected automatically.
|
1999
|
+
if not had_symlinked_files and is_star_glob:
|
2000
|
+
file_str = f"{len(wandb_files)} file"
|
2001
|
+
if len(wandb_files) > 1:
|
1919
2002
|
file_str += "s"
|
1920
2003
|
wandb.termwarn(
|
1921
|
-
|
1922
|
-
|
1923
|
-
"call wandb.save again to sync new files."
|
1924
|
-
)
|
1925
|
-
% file_str
|
2004
|
+
f"Symlinked {file_str} into the W&B run directory, "
|
2005
|
+
"call wandb.save again to sync new files."
|
1926
2006
|
)
|
1927
|
-
|
2007
|
+
|
2008
|
+
files_dict: FilesDict = {"files": [(relative_glob_str, policy)]}
|
1928
2009
|
if self._backend and self._backend.interface:
|
1929
2010
|
self._backend.interface.publish_files(files_dict)
|
1930
|
-
|
2011
|
+
|
2012
|
+
return wandb_files
|
1931
2013
|
|
1932
2014
|
@_run_decorator._attach
|
1933
2015
|
def restore(
|
@@ -2485,7 +2567,6 @@ class Run:
|
|
2485
2567
|
sampled_history_handle = (
|
2486
2568
|
self._backend.interface.deliver_request_sampled_history()
|
2487
2569
|
)
|
2488
|
-
job_info_handle = self._backend.interface.deliver_request_job_info()
|
2489
2570
|
|
2490
2571
|
result = server_info_handle.wait(timeout=-1)
|
2491
2572
|
assert result
|
@@ -2499,10 +2580,6 @@ class Run:
|
|
2499
2580
|
assert result
|
2500
2581
|
self._final_summary = result.response.get_summary_response
|
2501
2582
|
|
2502
|
-
result = job_info_handle.wait(timeout=-1)
|
2503
|
-
assert result
|
2504
|
-
self._job_info = result.response.job_info_response
|
2505
|
-
|
2506
2583
|
if self._backend:
|
2507
2584
|
self._backend.cleanup()
|
2508
2585
|
|
@@ -2525,7 +2602,6 @@ class Run:
|
|
2525
2602
|
server_info_response=self._server_info_response,
|
2526
2603
|
check_version_response=self._check_version,
|
2527
2604
|
internal_messages_response=self._internal_messages_response,
|
2528
|
-
job_info=self._job_info,
|
2529
2605
|
reporter=self._reporter,
|
2530
2606
|
quiet=self._quiet,
|
2531
2607
|
settings=self._settings,
|
@@ -3509,7 +3585,7 @@ class Run:
|
|
3509
3585
|
if settings._offline or settings.silent:
|
3510
3586
|
return
|
3511
3587
|
|
3512
|
-
|
3588
|
+
workspace_url = f"{settings.run_url}/workspace"
|
3513
3589
|
project_url = settings.project_url
|
3514
3590
|
sweep_url = settings.sweep_url
|
3515
3591
|
|
@@ -3520,7 +3596,7 @@ class Run:
|
|
3520
3596
|
|
3521
3597
|
if printer._html:
|
3522
3598
|
if not wandb.jupyter.maybe_display():
|
3523
|
-
run_line = f"<strong>{printer.link(
|
3599
|
+
run_line = f"<strong>{printer.link(workspace_url, run_name)}</strong>"
|
3524
3600
|
project_line, sweep_line = "", ""
|
3525
3601
|
|
3526
3602
|
# TODO(settings): make settings the source of truth
|
@@ -3552,7 +3628,7 @@ class Run:
|
|
3552
3628
|
f'{printer.emoji("broom")} View sweep at {printer.link(sweep_url)}'
|
3553
3629
|
)
|
3554
3630
|
printer.display(
|
3555
|
-
f'{printer.emoji("rocket")} View run at {printer.link(
|
3631
|
+
f'{printer.emoji("rocket")} View run at {printer.link(workspace_url)}',
|
3556
3632
|
)
|
3557
3633
|
|
3558
3634
|
# TODO(settings) use `wandb_settings` (if self.settings.anonymous == "true":)
|
@@ -3576,7 +3652,6 @@ class Run:
|
|
3576
3652
|
server_info_response: Optional[ServerInfoResponse] = None,
|
3577
3653
|
check_version_response: Optional["CheckVersionResponse"] = None,
|
3578
3654
|
internal_messages_response: Optional["InternalMessagesResponse"] = None,
|
3579
|
-
job_info: Optional["JobInfoResponse"] = None,
|
3580
3655
|
reporter: Optional[Reporter] = None,
|
3581
3656
|
quiet: Optional[bool] = None,
|
3582
3657
|
*,
|
@@ -3593,7 +3668,6 @@ class Run:
|
|
3593
3668
|
|
3594
3669
|
Run._footer_sync_info(
|
3595
3670
|
poll_exit_response=poll_exit_response,
|
3596
|
-
job_info=job_info,
|
3597
3671
|
quiet=quiet,
|
3598
3672
|
settings=settings,
|
3599
3673
|
printer=printer,
|
@@ -3778,7 +3852,6 @@ class Run:
|
|
3778
3852
|
@staticmethod
|
3779
3853
|
def _footer_sync_info(
|
3780
3854
|
poll_exit_response: Optional[PollExitResponse] = None,
|
3781
|
-
job_info: Optional["JobInfoResponse"] = None,
|
3782
3855
|
quiet: Optional[bool] = None,
|
3783
3856
|
*,
|
3784
3857
|
settings: "Settings",
|
@@ -3798,14 +3871,10 @@ class Run:
|
|
3798
3871
|
else:
|
3799
3872
|
info = []
|
3800
3873
|
if settings.run_name and settings.run_url:
|
3874
|
+
run_workspace = f"{settings.run_url}/workspace"
|
3801
3875
|
info = [
|
3802
|
-
f"{printer.emoji('rocket')} View run {printer.name(settings.run_name)} at: {printer.link(
|
3876
|
+
f"{printer.emoji('rocket')} View run {printer.name(settings.run_name)} at: {printer.link(run_workspace)}"
|
3803
3877
|
]
|
3804
|
-
if job_info and job_info.version and job_info.sequenceId:
|
3805
|
-
link = f"{settings.project_url}/jobs/{job_info.sequenceId}/version_details/{job_info.version}"
|
3806
|
-
info.append(
|
3807
|
-
f"{printer.emoji('lightning')} View job at {printer.link(link)}",
|
3808
|
-
)
|
3809
3878
|
if poll_exit_response and poll_exit_response.file_counts:
|
3810
3879
|
logger.info("logging synced files")
|
3811
3880
|
file_counts = poll_exit_response.file_counts
|