wandb 0.19.1__py3-none-win32.whl → 0.19.2__py3-none-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wandb/__init__.py +1 -1
- wandb/__init__.pyi +3 -5
- wandb/agents/pyagent.py +1 -1
- wandb/apis/importers/wandb.py +1 -1
- wandb/apis/public/files.py +1 -1
- wandb/apis/public/jobs.py +1 -1
- wandb/apis/public/runs.py +2 -7
- wandb/apis/reports/v1/__init__.py +1 -1
- wandb/apis/reports/v2/__init__.py +1 -1
- wandb/apis/workspaces/__init__.py +1 -1
- wandb/bin/gpu_stats.exe +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/beta.py +7 -4
- wandb/cli/cli.py +5 -7
- wandb/docker/__init__.py +4 -4
- wandb/integration/fastai/__init__.py +4 -6
- wandb/integration/keras/keras.py +5 -3
- wandb/integration/metaflow/metaflow.py +7 -7
- wandb/integration/prodigy/prodigy.py +3 -11
- wandb/integration/sagemaker/__init__.py +5 -3
- wandb/integration/sagemaker/config.py +17 -8
- wandb/integration/sagemaker/files.py +0 -1
- wandb/integration/sagemaker/resources.py +47 -18
- wandb/integration/torch/wandb_torch.py +1 -1
- wandb/proto/v3/wandb_internal_pb2.py +273 -235
- wandb/proto/v4/wandb_internal_pb2.py +222 -214
- wandb/proto/v5/wandb_internal_pb2.py +222 -214
- wandb/sdk/artifacts/artifact.py +3 -9
- wandb/sdk/backend/backend.py +1 -1
- wandb/sdk/data_types/base_types/wb_value.py +1 -1
- wandb/sdk/data_types/graph.py +2 -2
- wandb/sdk/data_types/saved_model.py +1 -1
- wandb/sdk/data_types/video.py +1 -1
- wandb/sdk/interface/interface.py +25 -25
- wandb/sdk/interface/interface_shared.py +21 -5
- wandb/sdk/internal/handler.py +19 -1
- wandb/sdk/internal/internal.py +1 -1
- wandb/sdk/internal/internal_api.py +4 -5
- wandb/sdk/internal/sample.py +2 -2
- wandb/sdk/internal/sender.py +1 -2
- wandb/sdk/internal/settings_static.py +3 -1
- wandb/sdk/internal/system/assets/disk.py +4 -4
- wandb/sdk/internal/system/assets/gpu.py +1 -1
- wandb/sdk/internal/system/assets/memory.py +1 -1
- wandb/sdk/internal/system/system_info.py +1 -1
- wandb/sdk/internal/system/system_monitor.py +3 -1
- wandb/sdk/internal/tb_watcher.py +1 -1
- wandb/sdk/launch/_project_spec.py +3 -3
- wandb/sdk/launch/builder/abstract.py +1 -1
- wandb/sdk/lib/apikey.py +2 -3
- wandb/sdk/lib/fsm.py +1 -1
- wandb/sdk/lib/gitlib.py +1 -1
- wandb/sdk/lib/gql_request.py +1 -1
- wandb/sdk/lib/interrupt.py +37 -0
- wandb/sdk/lib/lazyloader.py +1 -1
- wandb/sdk/lib/service_connection.py +1 -1
- wandb/sdk/lib/telemetry.py +1 -1
- wandb/sdk/service/_startup_debug.py +1 -1
- wandb/sdk/service/server_sock.py +3 -2
- wandb/sdk/service/service.py +1 -1
- wandb/sdk/service/streams.py +19 -17
- wandb/sdk/verify/verify.py +13 -13
- wandb/sdk/wandb_init.py +95 -104
- wandb/sdk/wandb_login.py +1 -1
- wandb/sdk/wandb_metadata.py +547 -0
- wandb/sdk/wandb_run.py +127 -35
- wandb/sdk/wandb_settings.py +5 -36
- wandb/sdk/wandb_setup.py +83 -82
- wandb/sdk/wandb_sweep.py +2 -2
- wandb/sdk/wandb_sync.py +15 -18
- wandb/sync/sync.py +10 -10
- wandb/util.py +11 -3
- wandb/wandb_agent.py +11 -16
- wandb/wandb_controller.py +7 -7
- {wandb-0.19.1.dist-info → wandb-0.19.2.dist-info}/METADATA +3 -2
- {wandb-0.19.1.dist-info → wandb-0.19.2.dist-info}/RECORD +79 -77
- {wandb-0.19.1.dist-info → wandb-0.19.2.dist-info}/WHEEL +0 -0
- {wandb-0.19.1.dist-info → wandb-0.19.2.dist-info}/entry_points.txt +0 -0
- {wandb-0.19.1.dist-info → wandb-0.19.2.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_run.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import _thread as thread
|
4
3
|
import atexit
|
5
4
|
import functools
|
6
5
|
import glob
|
@@ -37,6 +36,7 @@ from wandb.errors.links import url_registry
|
|
37
36
|
from wandb.integration.torch import wandb_torch
|
38
37
|
from wandb.plot import CustomChart, Visualize
|
39
38
|
from wandb.proto.wandb_internal_pb2 import (
|
39
|
+
MetadataRequest,
|
40
40
|
MetricRecord,
|
41
41
|
PollExitResponse,
|
42
42
|
Result,
|
@@ -73,6 +73,7 @@ from .lib import (
|
|
73
73
|
deprecate,
|
74
74
|
filenames,
|
75
75
|
filesystem,
|
76
|
+
interrupt,
|
76
77
|
ipython,
|
77
78
|
module,
|
78
79
|
printer,
|
@@ -84,6 +85,7 @@ from .lib import (
|
|
84
85
|
from .lib.exit_hooks import ExitHooks
|
85
86
|
from .lib.mailbox import MailboxError, MailboxHandle, MailboxProbe, MailboxProgress
|
86
87
|
from .wandb_alerts import AlertLevel
|
88
|
+
from .wandb_metadata import Metadata
|
87
89
|
from .wandb_settings import Settings
|
88
90
|
from .wandb_setup import _WandbSetup
|
89
91
|
|
@@ -287,7 +289,7 @@ class RunStatusChecker:
|
|
287
289
|
# TODO(frz): This check is required
|
288
290
|
# until WB-3606 is resolved on server side.
|
289
291
|
if not wandb.agents.pyagent.is_running(): # type: ignore
|
290
|
-
|
292
|
+
interrupt.interrupt_main()
|
291
293
|
return
|
292
294
|
|
293
295
|
try:
|
@@ -595,15 +597,17 @@ class Run:
|
|
595
597
|
self._config._set_artifact_callback(self._config_artifact_callback)
|
596
598
|
self._config._set_settings(self._settings)
|
597
599
|
|
598
|
-
#
|
600
|
+
# TODO: perhaps this should be a property that is a noop on a finished run
|
599
601
|
self.summary = wandb_summary.Summary(
|
600
602
|
self._summary_get_current_summary_callback,
|
601
603
|
)
|
602
604
|
self.summary._set_update_callback(self._summary_update_callback)
|
603
605
|
|
606
|
+
self.__metadata: Metadata | None = None
|
607
|
+
|
604
608
|
self._step = 0
|
605
609
|
self._starting_step = 0
|
606
|
-
#
|
610
|
+
# TODO: eventually would be nice to make this configurable using self._settings._start_time
|
607
611
|
# need to test (jhr): if you set start time to 2 days ago and run a test for 15 minutes,
|
608
612
|
# does the total time get calculated right (not as 2 days and 15 minutes)?
|
609
613
|
self._start_time = time.time()
|
@@ -1359,32 +1363,68 @@ class Run:
|
|
1359
1363
|
files: FilesDict = dict(files=[(GlobStr(glob.escape(fname)), "now")])
|
1360
1364
|
self._backend.interface.publish_files(files)
|
1361
1365
|
|
1362
|
-
def
|
1363
|
-
|
1364
|
-
|
1366
|
+
def _pop_all_charts(
|
1367
|
+
self,
|
1368
|
+
data: dict[str, Any],
|
1369
|
+
key_prefix: str | None = None,
|
1370
|
+
) -> dict[str, Any]:
|
1371
|
+
"""Pops all charts from a dictionary including nested charts.
|
1365
1372
|
|
1366
|
-
|
1373
|
+
This function will return a mapping of the charts and a dot-separated
|
1374
|
+
key for each chart. Indicating the path to the chart in the data dictionary.
|
1375
|
+
"""
|
1376
|
+
keys_to_remove = set()
|
1377
|
+
charts: dict[str, Any] = {}
|
1367
1378
|
for k, v in data.items():
|
1379
|
+
key = f"{key_prefix}.{k}" if key_prefix else k
|
1368
1380
|
if isinstance(v, Visualize):
|
1369
|
-
|
1370
|
-
v
|
1371
|
-
self._config_callback(
|
1372
|
-
val=v.spec.config_value,
|
1373
|
-
key=v.spec.config_key,
|
1374
|
-
)
|
1381
|
+
keys_to_remove.add(k)
|
1382
|
+
charts[key] = v
|
1375
1383
|
elif isinstance(v, CustomChart):
|
1376
|
-
|
1377
|
-
v
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1384
|
+
keys_to_remove.add(k)
|
1385
|
+
charts[key] = v
|
1386
|
+
elif isinstance(v, dict):
|
1387
|
+
nested_charts = self._pop_all_charts(v, key)
|
1388
|
+
charts.update(nested_charts)
|
1389
|
+
|
1390
|
+
for k in keys_to_remove:
|
1391
|
+
data.pop(k)
|
1392
|
+
|
1393
|
+
return charts
|
1394
|
+
|
1395
|
+
def _serialize_custom_charts(
|
1396
|
+
self,
|
1397
|
+
data: dict[str, Any],
|
1398
|
+
) -> dict[str, Any]:
|
1399
|
+
"""Process and replace chart objects with their underlying table values.
|
1400
|
+
|
1401
|
+
This processes the chart objects passed to `run.log()`, replacing their entries
|
1402
|
+
in the given dictionary (which is saved to the run's history) and adding them
|
1403
|
+
to the run's config.
|
1404
|
+
|
1405
|
+
Args:
|
1406
|
+
data: Dictionary containing data that may include plot objects
|
1407
|
+
Plot objects can be nested in dictionaries, which will be processed recursively.
|
1408
|
+
|
1409
|
+
Returns:
|
1410
|
+
The processed dictionary with custom charts transformed into tables.
|
1411
|
+
"""
|
1412
|
+
if not data:
|
1413
|
+
return data
|
1414
|
+
|
1415
|
+
charts = self._pop_all_charts(data)
|
1416
|
+
for k, v in charts.items():
|
1417
|
+
v.set_key(k)
|
1418
|
+
self._config_callback(
|
1419
|
+
val=v.spec.config_value,
|
1420
|
+
key=v.spec.config_key,
|
1421
|
+
)
|
1382
1422
|
|
1383
|
-
for k in chart_keys:
|
1384
|
-
# remove the chart key from the row
|
1385
|
-
v = data.pop(k)
|
1386
1423
|
if isinstance(v, CustomChart):
|
1387
1424
|
data[v.spec.table_key] = v.table
|
1425
|
+
elif isinstance(v, Visualize):
|
1426
|
+
data[k] = v.table
|
1427
|
+
|
1388
1428
|
return data
|
1389
1429
|
|
1390
1430
|
def _partial_history_callback(
|
@@ -2133,8 +2173,9 @@ class Run:
|
|
2133
2173
|
# Inform the service that we're done sending messages for this run.
|
2134
2174
|
#
|
2135
2175
|
# TODO: Why not do this in _atexit_cleanup()?
|
2136
|
-
|
2137
|
-
|
2176
|
+
if self._settings.run_id:
|
2177
|
+
assert self._wl
|
2178
|
+
service = self._wl.assert_service()
|
2138
2179
|
service.inform_finish(run_id=self._settings.run_id)
|
2139
2180
|
|
2140
2181
|
finally:
|
@@ -2313,7 +2354,7 @@ class Run:
|
|
2313
2354
|
self._err_redir = err_redir
|
2314
2355
|
logger.info("Redirects installed.")
|
2315
2356
|
except Exception as e:
|
2316
|
-
|
2357
|
+
wandb.termwarn(f"Failed to redirect: {e}")
|
2317
2358
|
logger.error("Failed to redirect.", exc_info=e)
|
2318
2359
|
return
|
2319
2360
|
|
@@ -2374,8 +2415,7 @@ class Run:
|
|
2374
2415
|
logger.info("atexit reg")
|
2375
2416
|
self._hooks = ExitHooks()
|
2376
2417
|
|
2377
|
-
|
2378
|
-
if not service:
|
2418
|
+
if self.settings.x_disable_service:
|
2379
2419
|
self._hooks.hook()
|
2380
2420
|
# NB: manager will perform atexit hook like behavior for outstanding runs
|
2381
2421
|
atexit.register(lambda: self._atexit_cleanup())
|
@@ -2388,10 +2428,6 @@ class Run:
|
|
2388
2428
|
self._output_writer.close()
|
2389
2429
|
self._output_writer = None
|
2390
2430
|
|
2391
|
-
def _on_init(self) -> None:
|
2392
|
-
if self._settings._offline:
|
2393
|
-
return
|
2394
|
-
|
2395
2431
|
def _on_start(self) -> None:
|
2396
2432
|
# would like to move _set_global to _on_ready to unify _on_start and _on_attach
|
2397
2433
|
# (we want to do the set globals after attach)
|
@@ -3231,7 +3267,7 @@ class Run:
|
|
3231
3267
|
use_after_commit: bool = False,
|
3232
3268
|
) -> Artifact:
|
3233
3269
|
api = internal.Api()
|
3234
|
-
if api.settings().get("anonymous")
|
3270
|
+
if api.settings().get("anonymous") in ["allow", "must"]:
|
3235
3271
|
wandb.termwarn(
|
3236
3272
|
"Artifacts logged anonymously cannot be claimed and expire after 7 days."
|
3237
3273
|
)
|
@@ -3665,6 +3701,62 @@ class Run:
|
|
3665
3701
|
logger.error("Error getting system metrics: %s", e)
|
3666
3702
|
return {}
|
3667
3703
|
|
3704
|
+
@property
|
3705
|
+
@_run_decorator._attach
|
3706
|
+
@_run_decorator._noop_on_finish()
|
3707
|
+
def _metadata(self) -> Metadata | None:
|
3708
|
+
"""The metadata associated with this run.
|
3709
|
+
|
3710
|
+
NOTE: Automatically collected metadata can be overridden by the user.
|
3711
|
+
"""
|
3712
|
+
if not self._backend or not self._backend.interface:
|
3713
|
+
return self.__metadata
|
3714
|
+
|
3715
|
+
# Initialize the metadata object if it doesn't exist.
|
3716
|
+
if self.__metadata is None:
|
3717
|
+
self.__metadata = Metadata()
|
3718
|
+
self.__metadata._set_callback(self._metadata_callback)
|
3719
|
+
|
3720
|
+
handle = self._backend.interface.deliver_get_system_metadata()
|
3721
|
+
result = handle.wait(timeout=1)
|
3722
|
+
|
3723
|
+
if not result:
|
3724
|
+
logger.error("Error getting run metadata: no result")
|
3725
|
+
return None
|
3726
|
+
|
3727
|
+
try:
|
3728
|
+
response = result.response.get_system_metadata_response
|
3729
|
+
|
3730
|
+
# Temporarily disable the callback to prevent triggering
|
3731
|
+
# an update call to wandb-core with the callback.
|
3732
|
+
with self.__metadata.disable_callback():
|
3733
|
+
# Values stored in the metadata object take precedence.
|
3734
|
+
self.__metadata.update_from_proto(response.metadata, skip_existing=True)
|
3735
|
+
|
3736
|
+
return self.__metadata
|
3737
|
+
except Exception as e:
|
3738
|
+
logger.error("Error getting run metadata: %s", e)
|
3739
|
+
|
3740
|
+
return None
|
3741
|
+
|
3742
|
+
@_run_decorator._noop_on_finish()
|
3743
|
+
@_run_decorator._attach
|
3744
|
+
def _metadata_callback(
|
3745
|
+
self,
|
3746
|
+
metadata: MetadataRequest,
|
3747
|
+
) -> None:
|
3748
|
+
"""Callback to publish Metadata to wandb-core upon user updates."""
|
3749
|
+
# ignore updates if the attached to another run
|
3750
|
+
if self._is_attached:
|
3751
|
+
wandb.termwarn(
|
3752
|
+
"Metadata updates are ignored when attached to another run.",
|
3753
|
+
repeat=False,
|
3754
|
+
)
|
3755
|
+
return
|
3756
|
+
|
3757
|
+
if self._backend and self._backend.interface:
|
3758
|
+
self._backend.interface.publish_metadata(metadata)
|
3759
|
+
|
3668
3760
|
# ------------------------------------------------------------------------------
|
3669
3761
|
# HEADER
|
3670
3762
|
# ------------------------------------------------------------------------------
|
@@ -3772,8 +3864,8 @@ class Run:
|
|
3772
3864
|
f'{printer.emoji("rocket")} View run at {printer.link(run_url)}',
|
3773
3865
|
)
|
3774
3866
|
|
3775
|
-
# TODO(settings) use `wandb_settings` (if self.settings.anonymous
|
3776
|
-
if run_name and Api().api.settings().get("anonymous")
|
3867
|
+
# TODO(settings) use `wandb_settings` (if self.settings.anonymous in ["allow", "must"]:)
|
3868
|
+
if run_name and Api().api.settings().get("anonymous") in ["allow", "must"]:
|
3777
3869
|
printer.display(
|
3778
3870
|
(
|
3779
3871
|
"Do NOT share these links with anyone."
|
wandb/sdk/wandb_settings.py
CHANGED
@@ -349,7 +349,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
349
349
|
@model_validator(mode="before")
|
350
350
|
@classmethod
|
351
351
|
def catch_private_settings(cls, values):
|
352
|
-
"""Check if a private field is provided and assign to the
|
352
|
+
"""Check if a private field is provided and assign to the corresponding public one.
|
353
353
|
|
354
354
|
This is a compatibility layer to handle previous versions of the settings.
|
355
355
|
"""
|
@@ -961,7 +961,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
961
961
|
# The Settings class does not track the source of the settings,
|
962
962
|
# so it is up to the developer to ensure that the settings are applied
|
963
963
|
# in the correct order. Most of the updates are done in
|
964
|
-
# wandb/sdk/wandb_setup.py::
|
964
|
+
# wandb/sdk/wandb_setup.py::_WandbSetup._settings_setup.
|
965
965
|
|
966
966
|
def update_from_system_config_file(self):
|
967
967
|
"""Update settings from the system config file."""
|
@@ -1063,7 +1063,8 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1063
1063
|
)
|
1064
1064
|
self.x_executable = _executable
|
1065
1065
|
|
1066
|
-
self.docker
|
1066
|
+
if self.docker is None:
|
1067
|
+
self.docker = env.get_docker(util.image_id_from_k8s())
|
1067
1068
|
|
1068
1069
|
# proceed if not in CLI mode
|
1069
1070
|
if self.x_cli_only_mode:
|
@@ -1176,38 +1177,6 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1176
1177
|
with open(self.resume_fname, "w") as f:
|
1177
1178
|
f.write(json.dumps({"run_id": self.run_id}))
|
1178
1179
|
|
1179
|
-
def handle_sweep_logic(self):
|
1180
|
-
"""Update settings based on sweep context.
|
1181
|
-
|
1182
|
-
When running a sweep, the project, entity, and run_id are handled externally,
|
1183
|
-
and should be ignored if they are set.
|
1184
|
-
"""
|
1185
|
-
if self.sweep_id is None:
|
1186
|
-
return
|
1187
|
-
|
1188
|
-
for key in ("project", "entity", "run_id"):
|
1189
|
-
value = getattr(self, key)
|
1190
|
-
if value is not None:
|
1191
|
-
wandb.termwarn(f"Ignoring {key} {value!r} when running a sweep.")
|
1192
|
-
setattr(self, key, None)
|
1193
|
-
|
1194
|
-
def handle_launch_logic(self):
|
1195
|
-
"""Update settings based on launch context.
|
1196
|
-
|
1197
|
-
When running in a launch context, the project, entity, and run_id are handled
|
1198
|
-
externally, and should be ignored if they are set.
|
1199
|
-
"""
|
1200
|
-
if not self.launch:
|
1201
|
-
return
|
1202
|
-
|
1203
|
-
for key in ("project", "entity", "run_id"):
|
1204
|
-
value = getattr(self, key)
|
1205
|
-
if value is not None:
|
1206
|
-
wandb.termwarn(
|
1207
|
-
f"Ignoring {key} {value!r} when running from wandb launch context."
|
1208
|
-
)
|
1209
|
-
setattr(self, key, None)
|
1210
|
-
|
1211
1180
|
@staticmethod
|
1212
1181
|
def validate_url(url: str) -> None:
|
1213
1182
|
"""Validate a URL string."""
|
@@ -1293,7 +1262,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1293
1262
|
def _get_url_query_string(self) -> str:
|
1294
1263
|
"""Construct the query string for project, run, and sweep URLs."""
|
1295
1264
|
# TODO: remove dependency on Api()
|
1296
|
-
if Api().settings().get("anonymous")
|
1265
|
+
if Api().settings().get("anonymous") not in ["allow", "must"]:
|
1297
1266
|
return ""
|
1298
1267
|
|
1299
1268
|
api_key = apikey.api_key(settings=self)
|
wandb/sdk/wandb_setup.py
CHANGED
@@ -20,6 +20,7 @@ import threading
|
|
20
20
|
from typing import TYPE_CHECKING, Any, Union
|
21
21
|
|
22
22
|
import wandb
|
23
|
+
import wandb.integration.sagemaker as sagemaker
|
23
24
|
from wandb.sdk.lib import import_hooks
|
24
25
|
|
25
26
|
from . import wandb_settings
|
@@ -61,29 +62,19 @@ class _EarlyLogger:
|
|
61
62
|
def log(self, level: str, msg: str, *args: Any, **kwargs: Any) -> None:
|
62
63
|
self._log.append((level, msg, args, kwargs))
|
63
64
|
|
64
|
-
def _flush(self) -> None:
|
65
|
-
assert self is not
|
66
|
-
assert logger is not None
|
65
|
+
def _flush(self, new_logger: Logger) -> None:
|
66
|
+
assert self is not new_logger
|
67
67
|
for level, msg, args, kwargs in self._log:
|
68
|
-
|
68
|
+
new_logger.log(level, msg, *args, **kwargs)
|
69
69
|
for msg, args, kwargs in self._exception:
|
70
|
-
|
70
|
+
new_logger.exception(msg, *args, **kwargs)
|
71
71
|
|
72
72
|
|
73
73
|
Logger = Union[logging.Logger, _EarlyLogger]
|
74
74
|
|
75
|
-
# logger will be configured to be either a standard logger instance or _EarlyLogger
|
76
|
-
logger: Logger | None = None
|
77
75
|
|
78
|
-
|
79
|
-
|
80
|
-
"""Configure module logger."""
|
81
|
-
global logger
|
82
|
-
logger = log_object
|
83
|
-
|
84
|
-
|
85
|
-
class _WandbSetup__WandbSetup: # noqa: N801
|
86
|
-
"""Inner class of _WandbSetup."""
|
76
|
+
class _WandbSetup:
|
77
|
+
"""W&B library singleton."""
|
87
78
|
|
88
79
|
def __init__(
|
89
80
|
self,
|
@@ -104,48 +95,52 @@ class _WandbSetup__WandbSetup: # noqa: N801
|
|
104
95
|
|
105
96
|
# TODO(jhr): defer strict checks until settings are fully initialized
|
106
97
|
# and logging is ready
|
107
|
-
self.
|
108
|
-
_set_logger(self._early_logger)
|
98
|
+
self._logger: Logger = _EarlyLogger()
|
109
99
|
|
110
|
-
self._settings = self._settings_setup(settings
|
100
|
+
self._settings = self._settings_setup(settings)
|
111
101
|
|
112
|
-
wandb.termsetup(self._settings,
|
102
|
+
wandb.termsetup(self._settings, None)
|
113
103
|
|
114
104
|
self._check()
|
115
105
|
self._setup()
|
116
106
|
|
117
107
|
def _settings_setup(
|
118
108
|
self,
|
119
|
-
settings: Settings | None
|
120
|
-
early_logger: _EarlyLogger | None = None,
|
109
|
+
settings: Settings | None,
|
121
110
|
) -> wandb_settings.Settings:
|
122
111
|
s = wandb_settings.Settings()
|
123
112
|
|
124
113
|
# the pid of the process to monitor for system stats
|
125
114
|
pid = os.getpid()
|
126
|
-
|
127
|
-
|
128
|
-
early_logger.info(f"Configure stats pid to {pid}")
|
115
|
+
self._logger.info(f"Current SDK version is {wandb.__version__}")
|
116
|
+
self._logger.info(f"Configure stats pid to {pid}")
|
129
117
|
s.x_stats_pid = pid
|
130
118
|
|
131
119
|
# load settings from the system config
|
132
|
-
if s.settings_system
|
133
|
-
|
120
|
+
if s.settings_system:
|
121
|
+
self._logger.info(f"Loading settings from {s.settings_system}")
|
134
122
|
s.update_from_system_config_file()
|
135
123
|
|
136
124
|
# load settings from the workspace config
|
137
|
-
if s.settings_workspace
|
138
|
-
|
125
|
+
if s.settings_workspace:
|
126
|
+
self._logger.info(f"Loading settings from {s.settings_workspace}")
|
139
127
|
s.update_from_workspace_config_file()
|
140
128
|
|
141
129
|
# load settings from the environment variables
|
142
|
-
|
143
|
-
early_logger.info("Loading settings from environment variables")
|
130
|
+
self._logger.info("Loading settings from environment variables")
|
144
131
|
s.update_from_env_vars(self._environ)
|
145
132
|
|
146
133
|
# infer settings from the system environment
|
147
134
|
s.update_from_system_environment()
|
148
135
|
|
136
|
+
# load SageMaker settings
|
137
|
+
check_sagemaker_env = not s.sagemaker_disable
|
138
|
+
if settings and settings.sagemaker_disable:
|
139
|
+
check_sagemaker_env = False
|
140
|
+
if check_sagemaker_env and sagemaker.is_using_sagemaker():
|
141
|
+
self._logger.info("Loading SageMaker settings")
|
142
|
+
sagemaker.set_global_settings(s)
|
143
|
+
|
149
144
|
# load settings from the passed init/setup settings
|
150
145
|
if settings:
|
151
146
|
s.update_from_settings(settings)
|
@@ -165,13 +160,15 @@ class _WandbSetup__WandbSetup: # noqa: N801
|
|
165
160
|
self._settings.update_from_dict(user_settings)
|
166
161
|
|
167
162
|
def _early_logger_flush(self, new_logger: Logger) -> None:
|
168
|
-
if
|
163
|
+
if self._logger is new_logger:
|
169
164
|
return
|
170
|
-
_set_logger(new_logger)
|
171
|
-
self._early_logger._flush()
|
172
165
|
|
173
|
-
|
174
|
-
|
166
|
+
if isinstance(self._logger, _EarlyLogger):
|
167
|
+
self._logger._flush(new_logger)
|
168
|
+
self._logger = new_logger
|
169
|
+
|
170
|
+
def _get_logger(self) -> Logger:
|
171
|
+
return self._logger
|
175
172
|
|
176
173
|
@property
|
177
174
|
def settings(self) -> wandb_settings.Settings:
|
@@ -236,16 +233,11 @@ class _WandbSetup__WandbSetup: # noqa: N801
|
|
236
233
|
if threading.current_thread() is not threading.main_thread():
|
237
234
|
pass
|
238
235
|
elif threading.current_thread().name != "MainThread":
|
239
|
-
|
236
|
+
wandb.termwarn(f"bad thread2: {threading.current_thread().name}")
|
240
237
|
if getattr(sys, "frozen", False):
|
241
|
-
|
238
|
+
wandb.termwarn("frozen, could be trouble")
|
242
239
|
|
243
240
|
def _setup(self) -> None:
|
244
|
-
if not self._settings._noop and not self._settings.x_disable_service:
|
245
|
-
from wandb.sdk.lib import service_connection
|
246
|
-
|
247
|
-
self._connection = service_connection.connect_to_service(self._settings)
|
248
|
-
|
249
241
|
sweep_path = self._settings.sweep_param_path
|
250
242
|
if sweep_path:
|
251
243
|
self._sweep_config = config_util.dict_from_config_file(
|
@@ -278,53 +270,61 @@ class _WandbSetup__WandbSetup: # noqa: N801
|
|
278
270
|
if internal_exit_code != 0:
|
279
271
|
sys.exit(internal_exit_code)
|
280
272
|
|
281
|
-
|
282
|
-
|
283
|
-
|
273
|
+
def ensure_service(self) -> ServiceConnection:
|
274
|
+
"""Returns a connection to the service process creating it if needed."""
|
275
|
+
if self._connection:
|
276
|
+
return self._connection
|
277
|
+
|
278
|
+
from wandb.sdk.lib import service_connection
|
279
|
+
|
280
|
+
self._connection = service_connection.connect_to_service(self._settings)
|
284
281
|
return self._connection
|
285
282
|
|
283
|
+
def assert_service(self) -> ServiceConnection:
|
284
|
+
"""Returns a connection to the service process, asserting it exists.
|
286
285
|
|
287
|
-
|
288
|
-
|
286
|
+
Unlike ensure_service(), this will not start up a service process
|
287
|
+
if it didn't already exist.
|
288
|
+
"""
|
289
|
+
if not self._connection:
|
290
|
+
raise AssertionError("Expected service process to exist.")
|
289
291
|
|
290
|
-
|
291
|
-
(Forked processes will get a new copy of the object)
|
292
|
-
"""
|
292
|
+
return self._connection
|
293
293
|
|
294
|
-
_instance: _WandbSetup__WandbSetup | None = None
|
295
294
|
|
296
|
-
|
297
|
-
|
298
|
-
if _WandbSetup._instance and _WandbSetup._instance._pid == pid:
|
299
|
-
_WandbSetup._instance._update(settings=settings)
|
300
|
-
return
|
301
|
-
_WandbSetup._instance = _WandbSetup__WandbSetup(settings=settings, pid=pid)
|
295
|
+
_singleton: _WandbSetup | None = None
|
296
|
+
"""The W&B library singleton, or None if not yet set up.
|
302
297
|
|
303
|
-
|
304
|
-
|
305
|
-
"""Returns a connection to the service process, if it exists."""
|
306
|
-
if not self._instance:
|
307
|
-
return None
|
308
|
-
return self._instance.service
|
298
|
+
The value is invalid and must not be used if `os.getpid() != _singleton._pid`.
|
299
|
+
"""
|
309
300
|
|
310
|
-
def __getattr__(self, name: str) -> Any:
|
311
|
-
return getattr(self._instance, name)
|
312
301
|
|
302
|
+
def singleton() -> _WandbSetup | None:
|
303
|
+
"""Returns the W&B singleton if it exists for the current process.
|
313
304
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
if _reset:
|
320
|
-
teardown()
|
305
|
+
Unlike setup(), this does not create the singleton if it doesn't exist.
|
306
|
+
"""
|
307
|
+
if _singleton and _singleton._pid == os.getpid():
|
308
|
+
return _singleton
|
309
|
+
else:
|
321
310
|
return None
|
322
311
|
|
323
|
-
wl = _WandbSetup(settings=settings)
|
324
|
-
return wl
|
325
312
|
|
313
|
+
def _setup(settings: Settings | None = None) -> _WandbSetup:
|
314
|
+
"""Set up library context."""
|
315
|
+
global _singleton
|
316
|
+
|
317
|
+
pid = os.getpid()
|
326
318
|
|
327
|
-
|
319
|
+
if _singleton and _singleton._pid == pid:
|
320
|
+
_singleton._update(settings=settings)
|
321
|
+
return _singleton
|
322
|
+
else:
|
323
|
+
_singleton = _WandbSetup(settings=settings, pid=pid)
|
324
|
+
return _singleton
|
325
|
+
|
326
|
+
|
327
|
+
def setup(settings: Settings | None = None) -> _WandbSetup:
|
328
328
|
"""Prepares W&B for use in the current process and its children.
|
329
329
|
|
330
330
|
You can usually ignore this as it is implicitly called by `wandb.init()`.
|
@@ -380,8 +380,7 @@ def setup(settings: Settings | None = None) -> _WandbSetup | None:
|
|
380
380
|
wandb.teardown()
|
381
381
|
```
|
382
382
|
"""
|
383
|
-
|
384
|
-
return ret
|
383
|
+
return _setup(settings=settings)
|
385
384
|
|
386
385
|
|
387
386
|
def teardown(exit_code: int | None = None) -> None:
|
@@ -395,8 +394,10 @@ def teardown(exit_code: int | None = None) -> None:
|
|
395
394
|
in an `atexit` hook, but this is not reliable in certain setups
|
396
395
|
such as when using Python's `multiprocessing` module.
|
397
396
|
"""
|
398
|
-
|
399
|
-
|
397
|
+
global _singleton
|
398
|
+
|
399
|
+
orig_singleton = _singleton
|
400
|
+
_singleton = None
|
400
401
|
|
401
|
-
if
|
402
|
-
|
402
|
+
if orig_singleton:
|
403
|
+
orig_singleton._teardown(exit_code=exit_code)
|
wandb/sdk/wandb_sweep.py
CHANGED
@@ -85,10 +85,10 @@ def sweep(
|
|
85
85
|
api = InternalApi()
|
86
86
|
sweep_id, warnings = api.upsert_sweep(sweep, prior_runs=prior_runs)
|
87
87
|
handle_sweep_config_violations(warnings)
|
88
|
-
print("Create sweep with ID:", sweep_id)
|
88
|
+
print("Create sweep with ID:", sweep_id) # noqa: T201
|
89
89
|
sweep_url = _get_sweep_url(api, sweep_id)
|
90
90
|
if sweep_url:
|
91
|
-
print("Sweep URL:", sweep_url)
|
91
|
+
print("Sweep URL:", sweep_url) # noqa: T201
|
92
92
|
return sweep_id
|
93
93
|
|
94
94
|
|