wandb 0.19.1rc1__py3-none-win_amd64.whl → 0.19.2__py3-none-win_amd64.whl
Sign up to get free protection for your applications and to get access to all the features.
- wandb/__init__.py +1 -7
- 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/progress.py +7 -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 +6 -37
- 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.1rc1.dist-info → wandb-0.19.2.dist-info}/METADATA +3 -2
- {wandb-0.19.1rc1.dist-info → wandb-0.19.2.dist-info}/RECORD +80 -78
- {wandb-0.19.1rc1.dist-info → wandb-0.19.2.dist-info}/WHEEL +0 -0
- {wandb-0.19.1rc1.dist-info → wandb-0.19.2.dist-info}/entry_points.txt +0 -0
- {wandb-0.19.1rc1.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
@@ -305,7 +305,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
305
305
|
x_save_requirements: bool = True
|
306
306
|
x_service_transport: str | None = None
|
307
307
|
x_service_wait: float = 30.0
|
308
|
-
x_show_operation_stats: bool =
|
308
|
+
x_show_operation_stats: bool = True
|
309
309
|
# The start time of the run in seconds since the Unix epoch.
|
310
310
|
x_start_time: float | None = None
|
311
311
|
# PID of the process that started the wandb-core process to collect system stats for.
|
@@ -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
|
|