wandb 0.13.10__py3-none-any.whl → 0.14.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- wandb/__init__.py +2 -3
- wandb/apis/__init__.py +1 -3
- wandb/apis/importers/__init__.py +4 -0
- wandb/apis/importers/base.py +312 -0
- wandb/apis/importers/mlflow.py +113 -0
- wandb/apis/internal.py +29 -2
- wandb/apis/normalize.py +6 -5
- wandb/apis/public.py +163 -180
- wandb/apis/reports/_templates.py +6 -12
- wandb/apis/reports/report.py +1 -1
- wandb/apis/reports/runset.py +1 -3
- wandb/apis/reports/util.py +12 -10
- wandb/beta/workflows.py +57 -34
- wandb/catboost/__init__.py +1 -2
- wandb/cli/cli.py +215 -133
- wandb/data_types.py +63 -56
- wandb/docker/__init__.py +78 -16
- wandb/docker/auth.py +21 -22
- wandb/env.py +0 -1
- wandb/errors/__init__.py +8 -116
- wandb/errors/term.py +1 -1
- wandb/fastai/__init__.py +1 -2
- wandb/filesync/dir_watcher.py +8 -5
- wandb/filesync/step_prepare.py +76 -75
- wandb/filesync/step_upload.py +1 -2
- wandb/integration/catboost/__init__.py +1 -3
- wandb/integration/catboost/catboost.py +8 -14
- wandb/integration/fastai/__init__.py +7 -13
- wandb/integration/gym/__init__.py +35 -4
- wandb/integration/keras/__init__.py +3 -3
- wandb/integration/keras/callbacks/metrics_logger.py +9 -8
- wandb/integration/keras/callbacks/model_checkpoint.py +9 -9
- wandb/integration/keras/callbacks/tables_builder.py +31 -19
- wandb/integration/kfp/kfp_patch.py +20 -17
- wandb/integration/kfp/wandb_logging.py +1 -2
- wandb/integration/lightgbm/__init__.py +21 -19
- wandb/integration/prodigy/prodigy.py +6 -7
- wandb/integration/sacred/__init__.py +9 -12
- wandb/integration/sagemaker/__init__.py +1 -3
- wandb/integration/sagemaker/auth.py +0 -1
- wandb/integration/sagemaker/config.py +1 -1
- wandb/integration/sagemaker/resources.py +1 -1
- wandb/integration/sb3/sb3.py +8 -4
- wandb/integration/tensorboard/__init__.py +1 -3
- wandb/integration/tensorboard/log.py +8 -8
- wandb/integration/tensorboard/monkeypatch.py +11 -9
- wandb/integration/tensorflow/__init__.py +1 -3
- wandb/integration/xgboost/__init__.py +4 -6
- wandb/integration/yolov8/__init__.py +7 -0
- wandb/integration/yolov8/yolov8.py +250 -0
- wandb/jupyter.py +31 -35
- wandb/lightgbm/__init__.py +1 -2
- wandb/old/settings.py +2 -2
- wandb/plot/bar.py +1 -2
- wandb/plot/confusion_matrix.py +1 -3
- wandb/plot/histogram.py +1 -2
- wandb/plot/line.py +1 -2
- wandb/plot/line_series.py +4 -4
- wandb/plot/pr_curve.py +17 -20
- wandb/plot/roc_curve.py +1 -3
- wandb/plot/scatter.py +1 -2
- wandb/proto/v3/wandb_server_pb2.py +85 -39
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_server_pb2.py +51 -39
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/sdk/__init__.py +1 -3
- wandb/sdk/backend/backend.py +1 -1
- wandb/sdk/data_types/_dtypes.py +38 -30
- wandb/sdk/data_types/base_types/json_metadata.py +1 -3
- wandb/sdk/data_types/base_types/media.py +17 -17
- wandb/sdk/data_types/base_types/wb_value.py +33 -26
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +91 -125
- wandb/sdk/data_types/helper_types/classes.py +1 -1
- wandb/sdk/data_types/helper_types/image_mask.py +12 -12
- wandb/sdk/data_types/histogram.py +5 -4
- wandb/sdk/data_types/html.py +1 -2
- wandb/sdk/data_types/image.py +11 -11
- wandb/sdk/data_types/molecule.py +3 -6
- wandb/sdk/data_types/object_3d.py +1 -2
- wandb/sdk/data_types/plotly.py +1 -2
- wandb/sdk/data_types/saved_model.py +10 -8
- wandb/sdk/data_types/video.py +1 -1
- wandb/sdk/integration_utils/data_logging.py +5 -5
- wandb/sdk/interface/artifacts.py +288 -266
- wandb/sdk/interface/interface.py +2 -3
- wandb/sdk/interface/interface_grpc.py +1 -1
- wandb/sdk/interface/interface_queue.py +1 -1
- wandb/sdk/interface/interface_relay.py +1 -1
- wandb/sdk/interface/interface_shared.py +1 -2
- wandb/sdk/interface/interface_sock.py +1 -1
- wandb/sdk/interface/message_future.py +1 -1
- wandb/sdk/interface/message_future_poll.py +1 -1
- wandb/sdk/interface/router.py +1 -1
- wandb/sdk/interface/router_queue.py +1 -1
- wandb/sdk/interface/router_relay.py +1 -1
- wandb/sdk/interface/router_sock.py +1 -1
- wandb/sdk/interface/summary_record.py +1 -1
- wandb/sdk/internal/artifacts.py +1 -1
- wandb/sdk/internal/datastore.py +2 -3
- wandb/sdk/internal/file_pusher.py +5 -3
- wandb/sdk/internal/file_stream.py +22 -19
- wandb/sdk/internal/handler.py +5 -4
- wandb/sdk/internal/internal.py +1 -1
- wandb/sdk/internal/internal_api.py +115 -55
- wandb/sdk/internal/job_builder.py +1 -3
- wandb/sdk/internal/profiler.py +1 -1
- wandb/sdk/internal/progress.py +4 -6
- wandb/sdk/internal/sample.py +1 -3
- wandb/sdk/internal/sender.py +28 -16
- wandb/sdk/internal/settings_static.py +5 -5
- wandb/sdk/internal/system/assets/__init__.py +1 -0
- wandb/sdk/internal/system/assets/cpu.py +3 -9
- wandb/sdk/internal/system/assets/disk.py +2 -4
- wandb/sdk/internal/system/assets/gpu.py +6 -18
- wandb/sdk/internal/system/assets/gpu_apple.py +2 -4
- wandb/sdk/internal/system/assets/interfaces.py +50 -22
- wandb/sdk/internal/system/assets/ipu.py +1 -3
- wandb/sdk/internal/system/assets/memory.py +7 -13
- wandb/sdk/internal/system/assets/network.py +4 -8
- wandb/sdk/internal/system/assets/open_metrics.py +283 -0
- wandb/sdk/internal/system/assets/tpu.py +1 -4
- wandb/sdk/internal/system/assets/trainium.py +26 -14
- wandb/sdk/internal/system/system_info.py +2 -3
- wandb/sdk/internal/system/system_monitor.py +52 -20
- wandb/sdk/internal/tb_watcher.py +12 -13
- wandb/sdk/launch/_project_spec.py +54 -65
- wandb/sdk/launch/agent/agent.py +374 -90
- wandb/sdk/launch/builder/abstract.py +61 -7
- wandb/sdk/launch/builder/build.py +81 -110
- wandb/sdk/launch/builder/docker_builder.py +181 -0
- wandb/sdk/launch/builder/kaniko_builder.py +419 -0
- wandb/sdk/launch/builder/noop.py +31 -12
- wandb/sdk/launch/builder/templates/_wandb_bootstrap.py +70 -20
- wandb/sdk/launch/environment/abstract.py +28 -0
- wandb/sdk/launch/environment/aws_environment.py +276 -0
- wandb/sdk/launch/environment/gcp_environment.py +271 -0
- wandb/sdk/launch/environment/local_environment.py +65 -0
- wandb/sdk/launch/github_reference.py +3 -8
- wandb/sdk/launch/launch.py +38 -29
- wandb/sdk/launch/launch_add.py +6 -8
- wandb/sdk/launch/loader.py +230 -0
- wandb/sdk/launch/registry/abstract.py +54 -0
- wandb/sdk/launch/registry/elastic_container_registry.py +163 -0
- wandb/sdk/launch/registry/google_artifact_registry.py +203 -0
- wandb/sdk/launch/registry/local_registry.py +62 -0
- wandb/sdk/launch/runner/abstract.py +1 -16
- wandb/sdk/launch/runner/{kubernetes.py → kubernetes_runner.py} +83 -95
- wandb/sdk/launch/runner/local_container.py +46 -22
- wandb/sdk/launch/runner/local_process.py +1 -4
- wandb/sdk/launch/runner/{aws.py → sagemaker_runner.py} +53 -212
- wandb/sdk/launch/runner/{gcp_vertex.py → vertex_runner.py} +38 -55
- wandb/sdk/launch/sweeps/__init__.py +3 -2
- wandb/sdk/launch/sweeps/scheduler.py +132 -39
- wandb/sdk/launch/sweeps/scheduler_sweep.py +80 -89
- wandb/sdk/launch/utils.py +101 -30
- wandb/sdk/launch/wandb_reference.py +2 -7
- wandb/sdk/lib/_settings_toposort_generate.py +166 -0
- wandb/sdk/lib/_settings_toposort_generated.py +201 -0
- wandb/sdk/lib/apikey.py +2 -4
- wandb/sdk/lib/config_util.py +4 -1
- wandb/sdk/lib/console.py +1 -3
- wandb/sdk/lib/deprecate.py +3 -3
- wandb/sdk/lib/file_stream_utils.py +7 -5
- wandb/sdk/lib/filenames.py +1 -1
- wandb/sdk/lib/filesystem.py +61 -5
- wandb/sdk/lib/git.py +1 -3
- wandb/sdk/lib/import_hooks.py +4 -7
- wandb/sdk/lib/ipython.py +8 -5
- wandb/sdk/lib/lazyloader.py +1 -3
- wandb/sdk/lib/mailbox.py +14 -4
- wandb/sdk/lib/proto_util.py +10 -5
- wandb/sdk/lib/redirect.py +15 -22
- wandb/sdk/lib/reporting.py +1 -3
- wandb/sdk/lib/retry.py +4 -5
- wandb/sdk/lib/runid.py +1 -3
- wandb/sdk/lib/server.py +15 -9
- wandb/sdk/lib/sock_client.py +1 -1
- wandb/sdk/lib/sparkline.py +1 -1
- wandb/sdk/lib/wburls.py +1 -1
- wandb/sdk/service/port_file.py +1 -2
- wandb/sdk/service/service.py +36 -13
- wandb/sdk/service/service_base.py +12 -1
- wandb/sdk/verify/verify.py +5 -7
- wandb/sdk/wandb_artifacts.py +142 -177
- wandb/sdk/wandb_config.py +5 -8
- wandb/sdk/wandb_helper.py +1 -1
- wandb/sdk/wandb_init.py +24 -13
- wandb/sdk/wandb_login.py +9 -9
- wandb/sdk/wandb_manager.py +39 -4
- wandb/sdk/wandb_metric.py +2 -6
- wandb/sdk/wandb_require.py +4 -15
- wandb/sdk/wandb_require_helpers.py +1 -9
- wandb/sdk/wandb_run.py +95 -141
- wandb/sdk/wandb_save.py +1 -3
- wandb/sdk/wandb_settings.py +149 -54
- wandb/sdk/wandb_setup.py +66 -46
- wandb/sdk/wandb_summary.py +13 -10
- wandb/sdk/wandb_sweep.py +6 -7
- wandb/sdk/wandb_watch.py +1 -1
- wandb/sklearn/calculate/confusion_matrix.py +1 -1
- wandb/sklearn/calculate/learning_curve.py +1 -1
- wandb/sklearn/calculate/summary_metrics.py +1 -3
- wandb/sklearn/plot/__init__.py +1 -1
- wandb/sklearn/plot/classifier.py +27 -18
- wandb/sklearn/plot/clusterer.py +4 -5
- wandb/sklearn/plot/regressor.py +4 -4
- wandb/sklearn/plot/shared.py +2 -2
- wandb/sync/__init__.py +1 -3
- wandb/sync/sync.py +4 -5
- wandb/testing/relay.py +11 -10
- wandb/trigger.py +1 -1
- wandb/util.py +106 -81
- wandb/viz.py +4 -4
- wandb/wandb_agent.py +50 -50
- wandb/wandb_controller.py +2 -3
- wandb/wandb_run.py +1 -2
- wandb/wandb_torch.py +1 -1
- wandb/xgboost/__init__.py +1 -2
- {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/METADATA +6 -2
- {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/RECORD +224 -209
- {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/WHEEL +1 -1
- wandb/sdk/launch/builder/docker.py +0 -80
- wandb/sdk/launch/builder/kaniko.py +0 -393
- wandb/sdk/launch/builder/loader.py +0 -32
- wandb/sdk/launch/runner/loader.py +0 -50
- {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/LICENSE +0 -0
- {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/entry_points.txt +0 -0
- {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/top_level.txt +0 -0
wandb/sdk/wandb_save.py
CHANGED
wandb/sdk/wandb_settings.py
CHANGED
@@ -37,6 +37,7 @@ from wandb import util
|
|
37
37
|
from wandb.apis.internal import Api
|
38
38
|
from wandb.errors import UsageError
|
39
39
|
from wandb.sdk.lib import filesystem
|
40
|
+
from wandb.sdk.lib._settings_toposort_generated import SETTINGS_TOPOLOGICALLY_SORTED
|
40
41
|
from wandb.sdk.wandb_config import Config
|
41
42
|
from wandb.sdk.wandb_setup import _EarlyLogger
|
42
43
|
|
@@ -62,8 +63,7 @@ else:
|
|
62
63
|
|
63
64
|
|
64
65
|
def _get_wandb_dir(root_dir: str) -> str:
|
65
|
-
"""
|
66
|
-
Get the full path to the wandb directory.
|
66
|
+
"""Get the full path to the wandb directory.
|
67
67
|
|
68
68
|
The setting exposed to users as `dir=` or `WANDB_DIR` is the `root_dir`.
|
69
69
|
We add the `__stage_dir__` to it to get the full `wandb_dir`
|
@@ -87,9 +87,7 @@ def _get_wandb_dir(root_dir: str) -> str:
|
|
87
87
|
|
88
88
|
# todo: should either return bool or error out. fix once confident.
|
89
89
|
def _str_as_bool(val: Union[str, bool]) -> bool:
|
90
|
-
"""
|
91
|
-
Parse a string as a bool.
|
92
|
-
"""
|
90
|
+
"""Parse a string as a bool."""
|
93
91
|
if isinstance(val, bool):
|
94
92
|
return val
|
95
93
|
try:
|
@@ -106,6 +104,30 @@ def _str_as_bool(val: Union[str, bool]) -> bool:
|
|
106
104
|
raise UsageError(f"Could not parse value {val} as a bool.")
|
107
105
|
|
108
106
|
|
107
|
+
def _str_as_dict(val: Union[str, Dict[str, Any]]) -> Dict[str, Any]:
|
108
|
+
"""Parse a string as a dict."""
|
109
|
+
if isinstance(val, dict):
|
110
|
+
return val
|
111
|
+
try:
|
112
|
+
return dict(json.loads(val))
|
113
|
+
except (AttributeError, ValueError):
|
114
|
+
pass
|
115
|
+
|
116
|
+
# todo: remove this and only raise error once we are confident.
|
117
|
+
wandb.termwarn(
|
118
|
+
f"Could not parse value {val} as a dict. ",
|
119
|
+
repeat=False,
|
120
|
+
)
|
121
|
+
raise UsageError(f"Could not parse value {val} as a dict.")
|
122
|
+
|
123
|
+
|
124
|
+
def _str_as_tuple(val: Union[str, Sequence[str]]) -> Tuple[str, ...]:
|
125
|
+
"""Parse a (potentially comma-separated) string as a tuple."""
|
126
|
+
if isinstance(val, str):
|
127
|
+
return tuple(val.split(","))
|
128
|
+
return tuple(val)
|
129
|
+
|
130
|
+
|
109
131
|
def _redact_dict(
|
110
132
|
d: Dict[str, Any],
|
111
133
|
unsafe_keys: Union[Set[str], FrozenSet[str]] = frozenset({"api_key"}),
|
@@ -119,7 +141,7 @@ def _redact_dict(
|
|
119
141
|
return safe_dict
|
120
142
|
|
121
143
|
|
122
|
-
def _get_program() -> Optional[
|
144
|
+
def _get_program() -> Optional[str]:
|
123
145
|
program = os.getenv(wandb.env.PROGRAM)
|
124
146
|
if program is not None:
|
125
147
|
return program
|
@@ -186,16 +208,15 @@ class SettingsConsole(enum.IntEnum):
|
|
186
208
|
|
187
209
|
|
188
210
|
class Property:
|
189
|
-
"""
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
E.g. if `is_policy` is True, the smallest `Source` value takes precedence.
|
211
|
+
"""A class to represent attributes (individual settings) of the Settings object.
|
212
|
+
|
213
|
+
- Encapsulates the logic of how to preprocess and validate values of settings
|
214
|
+
throughout the lifetime of a class instance.
|
215
|
+
- Allows for runtime modification of settings with hooks, e.g. in the case when
|
216
|
+
a setting depends on another setting.
|
217
|
+
- The update() method is used to update the value of a setting.
|
218
|
+
- The `is_policy` attribute determines the source priority when updating the property value.
|
219
|
+
E.g. if `is_policy` is True, the smallest `Source` value takes precedence.
|
199
220
|
"""
|
200
221
|
|
201
222
|
# todo: this is a temporary measure to bypass validation of the settings
|
@@ -356,9 +377,7 @@ class Property:
|
|
356
377
|
|
357
378
|
|
358
379
|
class Settings:
|
359
|
-
"""
|
360
|
-
Settings for the wandb client.
|
361
|
-
"""
|
380
|
+
"""Settings for the wandb client."""
|
362
381
|
|
363
382
|
# settings are declared as class attributes for static type checking purposes
|
364
383
|
# and to help with IDE autocomplete.
|
@@ -369,6 +388,7 @@ class Settings:
|
|
369
388
|
_console: SettingsConsole
|
370
389
|
_cuda: str
|
371
390
|
_disable_meta: bool
|
391
|
+
_disable_service: bool
|
372
392
|
_disable_stats: bool
|
373
393
|
_disable_viewer: bool # Prevent early viewer query
|
374
394
|
_except_exit: bool
|
@@ -392,11 +412,10 @@ class Settings:
|
|
392
412
|
_os: str
|
393
413
|
_platform: str
|
394
414
|
_python: str
|
395
|
-
_require_service: str
|
396
415
|
_runqueue_item_id: str
|
397
416
|
_save_requirements: bool
|
398
417
|
_service_transport: str
|
399
|
-
_service_wait:
|
418
|
+
_service_wait: float
|
400
419
|
_start_datetime: datetime
|
401
420
|
_start_time: float
|
402
421
|
_stats_pid: int # (internal) base pid for system stats
|
@@ -404,6 +423,9 @@ class Settings:
|
|
404
423
|
_stats_samples_to_average: int
|
405
424
|
_stats_join_assets: bool # join metrics from different assets before sending to backend
|
406
425
|
_stats_neuron_monitor_config_path: str # path to place config file for neuron-monitor (AWS Trainium)
|
426
|
+
_stats_open_metrics_endpoints: Mapping[str, str] # open metrics endpoint names/urls
|
427
|
+
# open metrics filters {"metric regex pattern": {"label": "label value regex pattern"}}
|
428
|
+
_stats_open_metrics_filters: Mapping[str, Mapping[str, str]]
|
407
429
|
_tmp_code_dir: str
|
408
430
|
_tracelog: str
|
409
431
|
_unsaved_keys: Sequence[str]
|
@@ -491,20 +513,25 @@ class Settings:
|
|
491
513
|
sync_symlink_latest: str
|
492
514
|
system_sample: int
|
493
515
|
system_sample_seconds: int
|
516
|
+
table_raise_on_max_row_limit_exceeded: bool
|
494
517
|
timespec: str
|
495
518
|
tmp_dir: str
|
496
519
|
username: str
|
497
520
|
wandb_dir: str
|
498
|
-
table_raise_on_max_row_limit_exceeded: bool
|
499
521
|
|
500
522
|
def _default_props(self) -> Dict[str, Dict[str, Any]]:
|
501
|
-
"""
|
502
|
-
|
503
|
-
|
523
|
+
"""Initialize instance attributes (individual settings) as Property objects.
|
524
|
+
|
525
|
+
Helper method that is used in `__init__` together with the class attributes.
|
504
526
|
Note that key names must be the same as the class attribute names.
|
505
527
|
"""
|
506
|
-
|
528
|
+
props: Dict[str, Dict[str, Any]] = dict(
|
507
529
|
_disable_meta={"preprocessor": _str_as_bool},
|
530
|
+
_disable_service={
|
531
|
+
"value": False,
|
532
|
+
"preprocessor": _str_as_bool,
|
533
|
+
"is_policy": True,
|
534
|
+
},
|
508
535
|
_disable_stats={"preprocessor": _str_as_bool},
|
509
536
|
_disable_viewer={"preprocessor": _str_as_bool},
|
510
537
|
_network_buffer={"preprocessor": int},
|
@@ -540,13 +567,39 @@ class Settings:
|
|
540
567
|
_sync={"value": False},
|
541
568
|
_platform={"value": util.get_platform_name()},
|
542
569
|
_save_requirements={"value": True, "preprocessor": _str_as_bool},
|
543
|
-
_service_wait={
|
544
|
-
|
545
|
-
|
570
|
+
_service_wait={
|
571
|
+
"value": 30,
|
572
|
+
"preprocessor": float,
|
573
|
+
"validator": self._validate__service_wait,
|
574
|
+
},
|
575
|
+
_stats_sample_rate_seconds={
|
576
|
+
"value": 2.0,
|
577
|
+
"preprocessor": float,
|
578
|
+
"validator": self._validate__stats_sample_rate_seconds,
|
579
|
+
},
|
580
|
+
_stats_samples_to_average={
|
581
|
+
"value": 15,
|
582
|
+
"preprocessor": int,
|
583
|
+
"validator": self._validate__stats_samples_to_average,
|
584
|
+
},
|
546
585
|
_stats_join_assets={"value": True, "preprocessor": _str_as_bool},
|
547
586
|
_stats_neuron_monitor_config_path={
|
548
587
|
"hook": lambda x: self._path_convert(x),
|
549
588
|
},
|
589
|
+
_stats_open_metrics_endpoints={
|
590
|
+
# todo: opt-in to this feature
|
591
|
+
# "value": {
|
592
|
+
# "DCGM": "http://localhost:9400/metrics", # NVIDIA DCGM Exporter
|
593
|
+
# },
|
594
|
+
"preprocessor": _str_as_dict,
|
595
|
+
},
|
596
|
+
_stats_open_metrics_filters={
|
597
|
+
# capture all metrics by default
|
598
|
+
"value": {
|
599
|
+
".*": {},
|
600
|
+
},
|
601
|
+
"preprocessor": _str_as_dict,
|
602
|
+
},
|
550
603
|
_tmp_code_dir={
|
551
604
|
"value": "code",
|
552
605
|
"hook": lambda x: self._path_convert(self.tmp_dir, x),
|
@@ -562,6 +615,7 @@ class Settings:
|
|
562
615
|
"preprocessor": lambda x: str(x).strip().rstrip("/"),
|
563
616
|
"validator": self._validate_base_url,
|
564
617
|
},
|
618
|
+
config_paths={"prepocessor": _str_as_tuple},
|
565
619
|
console={"value": "auto", "validator": self._validate_console},
|
566
620
|
deployment={
|
567
621
|
"hook": lambda _: "local" if self.is_local else "cloud",
|
@@ -719,14 +773,14 @@ class Settings:
|
|
719
773
|
"auto_hook": True,
|
720
774
|
},
|
721
775
|
)
|
776
|
+
return props
|
722
777
|
|
723
778
|
# helper methods for validating values
|
724
779
|
@staticmethod
|
725
780
|
def _validator_factory(hint: Any) -> Callable[[Any], bool]:
|
726
|
-
"""
|
727
|
-
|
728
|
-
|
729
|
-
that checks if the argument is of the correct type
|
781
|
+
"""Return a factory for type validators.
|
782
|
+
|
783
|
+
Given a type hint for a setting into a function that type checks the argument.
|
730
784
|
"""
|
731
785
|
origin, args = get_origin(hint), get_args(hint)
|
732
786
|
|
@@ -816,6 +870,7 @@ class Settings:
|
|
816
870
|
if len(value) > len(value.strip()):
|
817
871
|
raise UsageError("API key cannot start or end with whitespace")
|
818
872
|
|
873
|
+
# todo: move this check to the post-init validation step
|
819
874
|
# if value.startswith("local") and not self.is_local:
|
820
875
|
# raise UsageError(
|
821
876
|
# "Attempting to use a local API key to connect to https://api.wandb.ai"
|
@@ -826,8 +881,7 @@ class Settings:
|
|
826
881
|
|
827
882
|
@staticmethod
|
828
883
|
def _validate_base_url(value: Optional[str]) -> bool:
|
829
|
-
"""
|
830
|
-
Validate the base url of the wandb server.
|
884
|
+
"""Validate the base url of the wandb server.
|
831
885
|
|
832
886
|
param value: URL to validate
|
833
887
|
|
@@ -927,12 +981,28 @@ class Settings:
|
|
927
981
|
|
928
982
|
return True
|
929
983
|
|
984
|
+
@staticmethod
|
985
|
+
def _validate__service_wait(value: float) -> bool:
|
986
|
+
if value <= 0:
|
987
|
+
raise UsageError("_service_wait must be a positive number")
|
988
|
+
return True
|
989
|
+
|
990
|
+
@staticmethod
|
991
|
+
def _validate__stats_sample_rate_seconds(value: float) -> bool:
|
992
|
+
if value < 0.1:
|
993
|
+
raise UsageError("_stats_sample_rate_seconds must be >= 0.1")
|
994
|
+
return True
|
995
|
+
|
996
|
+
@staticmethod
|
997
|
+
def _validate__stats_samples_to_average(value: int) -> bool:
|
998
|
+
if value < 1 or value > 30:
|
999
|
+
raise UsageError("_stats_samples_to_average must be between 1 and 30")
|
1000
|
+
return True
|
1001
|
+
|
930
1002
|
# other helper methods
|
931
1003
|
@staticmethod
|
932
1004
|
def _path_convert(*args: str) -> str:
|
933
|
-
"""
|
934
|
-
Join path and apply os.path.expanduser to it.
|
935
|
-
"""
|
1005
|
+
"""Join path and apply os.path.expanduser to it."""
|
936
1006
|
return os.path.expanduser(os.path.join(*args))
|
937
1007
|
|
938
1008
|
def _convert_console(self) -> SettingsConsole:
|
@@ -948,7 +1018,7 @@ class Settings:
|
|
948
1018
|
if (
|
949
1019
|
self._jupyter
|
950
1020
|
or (self.start_method == "thread")
|
951
|
-
or self.
|
1021
|
+
or not self._disable_service
|
952
1022
|
or self._windows
|
953
1023
|
):
|
954
1024
|
console = "wrap"
|
@@ -983,9 +1053,7 @@ class Settings:
|
|
983
1053
|
return f"{project_url}{query}"
|
984
1054
|
|
985
1055
|
def _run_url(self) -> str:
|
986
|
-
"""
|
987
|
-
Return the run url.
|
988
|
-
"""
|
1056
|
+
"""Return the run url."""
|
989
1057
|
project_url = self._project_url_base()
|
990
1058
|
if not all([project_url, self.run_id]):
|
991
1059
|
return ""
|
@@ -994,8 +1062,8 @@ class Settings:
|
|
994
1062
|
return f"{project_url}/runs/{quote(self.run_id)}{query}"
|
995
1063
|
|
996
1064
|
def _set_run_start_time(self, source: int = Source.BASE) -> None:
|
997
|
-
"""
|
998
|
-
|
1065
|
+
"""Set the time stamps for the settings.
|
1066
|
+
|
999
1067
|
Called once the run is initialized.
|
1000
1068
|
"""
|
1001
1069
|
time_stamp: float = time.time()
|
@@ -1009,9 +1077,7 @@ class Settings:
|
|
1009
1077
|
)
|
1010
1078
|
|
1011
1079
|
def _sweep_url(self) -> str:
|
1012
|
-
"""
|
1013
|
-
Return the sweep url.
|
1014
|
-
"""
|
1080
|
+
"""Return the sweep url."""
|
1015
1081
|
project_url = self._project_url_base()
|
1016
1082
|
if not all([project_url, self.sweep_id]):
|
1017
1083
|
return ""
|
@@ -1023,6 +1089,8 @@ class Settings:
|
|
1023
1089
|
self.__frozen: bool = False
|
1024
1090
|
self.__initialized: bool = False
|
1025
1091
|
|
1092
|
+
self.__modification_order = SETTINGS_TOPOLOGICALLY_SORTED
|
1093
|
+
|
1026
1094
|
# todo: this is collect telemetry on validation errors and unexpected args
|
1027
1095
|
# values are stored as strings to avoid potential json serialization errors down the line
|
1028
1096
|
self.__preprocessing_warnings: Dict[str, str] = dict()
|
@@ -1083,7 +1151,6 @@ class Settings:
|
|
1083
1151
|
unexpected_arguments = [k for k in kwargs.keys() if k not in self.__dict__]
|
1084
1152
|
# allow only explicitly defined arguments
|
1085
1153
|
if unexpected_arguments:
|
1086
|
-
|
1087
1154
|
# todo: remove this and raise error instead once we are confident
|
1088
1155
|
self.__unexpected_args.update(unexpected_arguments)
|
1089
1156
|
wandb.termwarn(
|
@@ -1095,6 +1162,14 @@ class Settings:
|
|
1095
1162
|
|
1096
1163
|
# raise TypeError(f"Got unexpected arguments: {unexpected_arguments}")
|
1097
1164
|
|
1165
|
+
# automatically inspect setting validators and runtime hooks and topologically sort them
|
1166
|
+
# so that we can safely update them. throw error if there are cycles.
|
1167
|
+
for prop in self.__modification_order:
|
1168
|
+
if prop in kwargs:
|
1169
|
+
source = Source.RUN if self.__dict__[prop].is_policy else Source.BASE
|
1170
|
+
self.update({prop: kwargs[prop]}, source=source)
|
1171
|
+
kwargs.pop(prop)
|
1172
|
+
|
1098
1173
|
for k, v in kwargs.items():
|
1099
1174
|
# todo: double-check this logic:
|
1100
1175
|
source = Source.RUN if self.__dict__[k].is_policy else Source.BASE
|
@@ -1130,14 +1205,19 @@ class Settings:
|
|
1130
1205
|
return f"<Settings {representation}>"
|
1131
1206
|
|
1132
1207
|
def __copy__(self) -> "Settings":
|
1133
|
-
"""
|
1134
|
-
Ensure that a copy of the settings object is a truly deep copy
|
1208
|
+
"""Ensure that a copy of the settings object is a truly deep copy.
|
1135
1209
|
|
1136
1210
|
Note that the copied object will not be frozen todo? why is this needed?
|
1137
1211
|
"""
|
1138
1212
|
# get attributes that are instances of the Property class:
|
1139
1213
|
attributes = {k: v for k, v in self.__dict__.items() if isinstance(v, Property)}
|
1140
1214
|
new = Settings()
|
1215
|
+
# update properties that have deps or are dependent on in the topologically-sorted order
|
1216
|
+
for prop in self.__modification_order:
|
1217
|
+
new.update({prop: attributes[prop]._value}, source=attributes[prop].source)
|
1218
|
+
attributes.pop(prop)
|
1219
|
+
|
1220
|
+
# update the remaining attributes
|
1141
1221
|
for k, v in attributes.items():
|
1142
1222
|
# make sure to use the raw property value (v._value),
|
1143
1223
|
# not the potential result of runtime hooks applied to it (v.value)
|
@@ -1152,7 +1232,7 @@ class Settings:
|
|
1152
1232
|
# attribute access methods
|
1153
1233
|
@no_type_check # this is a hack to make mypy happy
|
1154
1234
|
def __getattribute__(self, name: str) -> Any:
|
1155
|
-
"""Expose attribute.value if attribute is a Property."""
|
1235
|
+
"""Expose `attribute.value` if `attribute` is a Property."""
|
1156
1236
|
item = object.__getattribute__(self, name)
|
1157
1237
|
if isinstance(item, Property):
|
1158
1238
|
return item.value
|
@@ -1187,7 +1267,7 @@ class Settings:
|
|
1187
1267
|
source: int = Source.OVERRIDE,
|
1188
1268
|
**kwargs: Any,
|
1189
1269
|
) -> None:
|
1190
|
-
"""Update individual settings
|
1270
|
+
"""Update individual settings."""
|
1191
1271
|
if "_Settings__frozen" in self.__dict__ and self.__frozen:
|
1192
1272
|
raise TypeError("Settings object is frozen")
|
1193
1273
|
|
@@ -1226,9 +1306,20 @@ class Settings:
|
|
1226
1306
|
if unknown_properties:
|
1227
1307
|
raise KeyError(f"Unknown settings: {unknown_properties}")
|
1228
1308
|
# only if all keys are valid, update them
|
1309
|
+
|
1310
|
+
# store settings to be updated in a dict to preserve stats on preprocessing and validation errors
|
1311
|
+
updated_settings = settings.copy()
|
1312
|
+
|
1313
|
+
# update properties that have deps or are dependent on in the topologically-sorted order
|
1314
|
+
for key in self.__modification_order:
|
1315
|
+
if key in settings:
|
1316
|
+
self.__dict__[key].update(settings.pop(key), source=source)
|
1317
|
+
|
1318
|
+
# update the remaining properties
|
1229
1319
|
for key, value in settings.items():
|
1230
1320
|
self.__dict__[key].update(value, source)
|
1231
1321
|
|
1322
|
+
for key in updated_settings.keys():
|
1232
1323
|
# todo: this is to collect stats on preprocessing and validation errors
|
1233
1324
|
if self.__dict__[key].__dict__["_Property__failed_preprocessing"]:
|
1234
1325
|
self.__preprocessing_warnings[key] = str(self.__dict__[key]._value)
|
@@ -1276,6 +1367,11 @@ class Settings:
|
|
1276
1367
|
attributes = {
|
1277
1368
|
k: v for k, v in settings.__dict__.items() if isinstance(v, Property)
|
1278
1369
|
}
|
1370
|
+
# update properties that have deps or are dependent on in the topologically-sorted order
|
1371
|
+
for prop in self.__modification_order:
|
1372
|
+
self.update({prop: attributes[prop]._value}, source=attributes[prop].source)
|
1373
|
+
attributes.pop(prop)
|
1374
|
+
# update the remaining properties
|
1279
1375
|
for k, v in attributes.items():
|
1280
1376
|
# note that only the same/higher priority settings are propagated
|
1281
1377
|
self.update({k: v._value}, source=v.source)
|
@@ -1329,7 +1425,7 @@ class Settings:
|
|
1329
1425
|
env_prefix: str = "WANDB_"
|
1330
1426
|
special_env_var_names = {
|
1331
1427
|
"WANDB_TRACELOG": "_tracelog",
|
1332
|
-
"
|
1428
|
+
"WANDB_DISABLE_SERVICE": "_disable_service",
|
1333
1429
|
"WANDB_SERVICE_TRANSPORT": "_service_transport",
|
1334
1430
|
"WANDB_DIR": "root_dir",
|
1335
1431
|
"WANDB_NAME": "run_name",
|
@@ -1365,7 +1461,6 @@ class Settings:
|
|
1365
1461
|
self, _logger: Optional[_EarlyLogger] = None
|
1366
1462
|
) -> None:
|
1367
1463
|
"""Modify settings based on environment (for runs and cli)."""
|
1368
|
-
|
1369
1464
|
settings: Dict[str, Union[bool, str, Sequence, None]] = dict()
|
1370
1465
|
# disable symlinks if on windows (requires admin or developer setup)
|
1371
1466
|
settings["symlink"] = True
|