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.
Files changed (228) hide show
  1. wandb/__init__.py +2 -3
  2. wandb/apis/__init__.py +1 -3
  3. wandb/apis/importers/__init__.py +4 -0
  4. wandb/apis/importers/base.py +312 -0
  5. wandb/apis/importers/mlflow.py +113 -0
  6. wandb/apis/internal.py +29 -2
  7. wandb/apis/normalize.py +6 -5
  8. wandb/apis/public.py +163 -180
  9. wandb/apis/reports/_templates.py +6 -12
  10. wandb/apis/reports/report.py +1 -1
  11. wandb/apis/reports/runset.py +1 -3
  12. wandb/apis/reports/util.py +12 -10
  13. wandb/beta/workflows.py +57 -34
  14. wandb/catboost/__init__.py +1 -2
  15. wandb/cli/cli.py +215 -133
  16. wandb/data_types.py +63 -56
  17. wandb/docker/__init__.py +78 -16
  18. wandb/docker/auth.py +21 -22
  19. wandb/env.py +0 -1
  20. wandb/errors/__init__.py +8 -116
  21. wandb/errors/term.py +1 -1
  22. wandb/fastai/__init__.py +1 -2
  23. wandb/filesync/dir_watcher.py +8 -5
  24. wandb/filesync/step_prepare.py +76 -75
  25. wandb/filesync/step_upload.py +1 -2
  26. wandb/integration/catboost/__init__.py +1 -3
  27. wandb/integration/catboost/catboost.py +8 -14
  28. wandb/integration/fastai/__init__.py +7 -13
  29. wandb/integration/gym/__init__.py +35 -4
  30. wandb/integration/keras/__init__.py +3 -3
  31. wandb/integration/keras/callbacks/metrics_logger.py +9 -8
  32. wandb/integration/keras/callbacks/model_checkpoint.py +9 -9
  33. wandb/integration/keras/callbacks/tables_builder.py +31 -19
  34. wandb/integration/kfp/kfp_patch.py +20 -17
  35. wandb/integration/kfp/wandb_logging.py +1 -2
  36. wandb/integration/lightgbm/__init__.py +21 -19
  37. wandb/integration/prodigy/prodigy.py +6 -7
  38. wandb/integration/sacred/__init__.py +9 -12
  39. wandb/integration/sagemaker/__init__.py +1 -3
  40. wandb/integration/sagemaker/auth.py +0 -1
  41. wandb/integration/sagemaker/config.py +1 -1
  42. wandb/integration/sagemaker/resources.py +1 -1
  43. wandb/integration/sb3/sb3.py +8 -4
  44. wandb/integration/tensorboard/__init__.py +1 -3
  45. wandb/integration/tensorboard/log.py +8 -8
  46. wandb/integration/tensorboard/monkeypatch.py +11 -9
  47. wandb/integration/tensorflow/__init__.py +1 -3
  48. wandb/integration/xgboost/__init__.py +4 -6
  49. wandb/integration/yolov8/__init__.py +7 -0
  50. wandb/integration/yolov8/yolov8.py +250 -0
  51. wandb/jupyter.py +31 -35
  52. wandb/lightgbm/__init__.py +1 -2
  53. wandb/old/settings.py +2 -2
  54. wandb/plot/bar.py +1 -2
  55. wandb/plot/confusion_matrix.py +1 -3
  56. wandb/plot/histogram.py +1 -2
  57. wandb/plot/line.py +1 -2
  58. wandb/plot/line_series.py +4 -4
  59. wandb/plot/pr_curve.py +17 -20
  60. wandb/plot/roc_curve.py +1 -3
  61. wandb/plot/scatter.py +1 -2
  62. wandb/proto/v3/wandb_server_pb2.py +85 -39
  63. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  64. wandb/proto/v4/wandb_server_pb2.py +51 -39
  65. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  66. wandb/sdk/__init__.py +1 -3
  67. wandb/sdk/backend/backend.py +1 -1
  68. wandb/sdk/data_types/_dtypes.py +38 -30
  69. wandb/sdk/data_types/base_types/json_metadata.py +1 -3
  70. wandb/sdk/data_types/base_types/media.py +17 -17
  71. wandb/sdk/data_types/base_types/wb_value.py +33 -26
  72. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +91 -125
  73. wandb/sdk/data_types/helper_types/classes.py +1 -1
  74. wandb/sdk/data_types/helper_types/image_mask.py +12 -12
  75. wandb/sdk/data_types/histogram.py +5 -4
  76. wandb/sdk/data_types/html.py +1 -2
  77. wandb/sdk/data_types/image.py +11 -11
  78. wandb/sdk/data_types/molecule.py +3 -6
  79. wandb/sdk/data_types/object_3d.py +1 -2
  80. wandb/sdk/data_types/plotly.py +1 -2
  81. wandb/sdk/data_types/saved_model.py +10 -8
  82. wandb/sdk/data_types/video.py +1 -1
  83. wandb/sdk/integration_utils/data_logging.py +5 -5
  84. wandb/sdk/interface/artifacts.py +288 -266
  85. wandb/sdk/interface/interface.py +2 -3
  86. wandb/sdk/interface/interface_grpc.py +1 -1
  87. wandb/sdk/interface/interface_queue.py +1 -1
  88. wandb/sdk/interface/interface_relay.py +1 -1
  89. wandb/sdk/interface/interface_shared.py +1 -2
  90. wandb/sdk/interface/interface_sock.py +1 -1
  91. wandb/sdk/interface/message_future.py +1 -1
  92. wandb/sdk/interface/message_future_poll.py +1 -1
  93. wandb/sdk/interface/router.py +1 -1
  94. wandb/sdk/interface/router_queue.py +1 -1
  95. wandb/sdk/interface/router_relay.py +1 -1
  96. wandb/sdk/interface/router_sock.py +1 -1
  97. wandb/sdk/interface/summary_record.py +1 -1
  98. wandb/sdk/internal/artifacts.py +1 -1
  99. wandb/sdk/internal/datastore.py +2 -3
  100. wandb/sdk/internal/file_pusher.py +5 -3
  101. wandb/sdk/internal/file_stream.py +22 -19
  102. wandb/sdk/internal/handler.py +5 -4
  103. wandb/sdk/internal/internal.py +1 -1
  104. wandb/sdk/internal/internal_api.py +115 -55
  105. wandb/sdk/internal/job_builder.py +1 -3
  106. wandb/sdk/internal/profiler.py +1 -1
  107. wandb/sdk/internal/progress.py +4 -6
  108. wandb/sdk/internal/sample.py +1 -3
  109. wandb/sdk/internal/sender.py +28 -16
  110. wandb/sdk/internal/settings_static.py +5 -5
  111. wandb/sdk/internal/system/assets/__init__.py +1 -0
  112. wandb/sdk/internal/system/assets/cpu.py +3 -9
  113. wandb/sdk/internal/system/assets/disk.py +2 -4
  114. wandb/sdk/internal/system/assets/gpu.py +6 -18
  115. wandb/sdk/internal/system/assets/gpu_apple.py +2 -4
  116. wandb/sdk/internal/system/assets/interfaces.py +50 -22
  117. wandb/sdk/internal/system/assets/ipu.py +1 -3
  118. wandb/sdk/internal/system/assets/memory.py +7 -13
  119. wandb/sdk/internal/system/assets/network.py +4 -8
  120. wandb/sdk/internal/system/assets/open_metrics.py +283 -0
  121. wandb/sdk/internal/system/assets/tpu.py +1 -4
  122. wandb/sdk/internal/system/assets/trainium.py +26 -14
  123. wandb/sdk/internal/system/system_info.py +2 -3
  124. wandb/sdk/internal/system/system_monitor.py +52 -20
  125. wandb/sdk/internal/tb_watcher.py +12 -13
  126. wandb/sdk/launch/_project_spec.py +54 -65
  127. wandb/sdk/launch/agent/agent.py +374 -90
  128. wandb/sdk/launch/builder/abstract.py +61 -7
  129. wandb/sdk/launch/builder/build.py +81 -110
  130. wandb/sdk/launch/builder/docker_builder.py +181 -0
  131. wandb/sdk/launch/builder/kaniko_builder.py +419 -0
  132. wandb/sdk/launch/builder/noop.py +31 -12
  133. wandb/sdk/launch/builder/templates/_wandb_bootstrap.py +70 -20
  134. wandb/sdk/launch/environment/abstract.py +28 -0
  135. wandb/sdk/launch/environment/aws_environment.py +276 -0
  136. wandb/sdk/launch/environment/gcp_environment.py +271 -0
  137. wandb/sdk/launch/environment/local_environment.py +65 -0
  138. wandb/sdk/launch/github_reference.py +3 -8
  139. wandb/sdk/launch/launch.py +38 -29
  140. wandb/sdk/launch/launch_add.py +6 -8
  141. wandb/sdk/launch/loader.py +230 -0
  142. wandb/sdk/launch/registry/abstract.py +54 -0
  143. wandb/sdk/launch/registry/elastic_container_registry.py +163 -0
  144. wandb/sdk/launch/registry/google_artifact_registry.py +203 -0
  145. wandb/sdk/launch/registry/local_registry.py +62 -0
  146. wandb/sdk/launch/runner/abstract.py +1 -16
  147. wandb/sdk/launch/runner/{kubernetes.py → kubernetes_runner.py} +83 -95
  148. wandb/sdk/launch/runner/local_container.py +46 -22
  149. wandb/sdk/launch/runner/local_process.py +1 -4
  150. wandb/sdk/launch/runner/{aws.py → sagemaker_runner.py} +53 -212
  151. wandb/sdk/launch/runner/{gcp_vertex.py → vertex_runner.py} +38 -55
  152. wandb/sdk/launch/sweeps/__init__.py +3 -2
  153. wandb/sdk/launch/sweeps/scheduler.py +132 -39
  154. wandb/sdk/launch/sweeps/scheduler_sweep.py +80 -89
  155. wandb/sdk/launch/utils.py +101 -30
  156. wandb/sdk/launch/wandb_reference.py +2 -7
  157. wandb/sdk/lib/_settings_toposort_generate.py +166 -0
  158. wandb/sdk/lib/_settings_toposort_generated.py +201 -0
  159. wandb/sdk/lib/apikey.py +2 -4
  160. wandb/sdk/lib/config_util.py +4 -1
  161. wandb/sdk/lib/console.py +1 -3
  162. wandb/sdk/lib/deprecate.py +3 -3
  163. wandb/sdk/lib/file_stream_utils.py +7 -5
  164. wandb/sdk/lib/filenames.py +1 -1
  165. wandb/sdk/lib/filesystem.py +61 -5
  166. wandb/sdk/lib/git.py +1 -3
  167. wandb/sdk/lib/import_hooks.py +4 -7
  168. wandb/sdk/lib/ipython.py +8 -5
  169. wandb/sdk/lib/lazyloader.py +1 -3
  170. wandb/sdk/lib/mailbox.py +14 -4
  171. wandb/sdk/lib/proto_util.py +10 -5
  172. wandb/sdk/lib/redirect.py +15 -22
  173. wandb/sdk/lib/reporting.py +1 -3
  174. wandb/sdk/lib/retry.py +4 -5
  175. wandb/sdk/lib/runid.py +1 -3
  176. wandb/sdk/lib/server.py +15 -9
  177. wandb/sdk/lib/sock_client.py +1 -1
  178. wandb/sdk/lib/sparkline.py +1 -1
  179. wandb/sdk/lib/wburls.py +1 -1
  180. wandb/sdk/service/port_file.py +1 -2
  181. wandb/sdk/service/service.py +36 -13
  182. wandb/sdk/service/service_base.py +12 -1
  183. wandb/sdk/verify/verify.py +5 -7
  184. wandb/sdk/wandb_artifacts.py +142 -177
  185. wandb/sdk/wandb_config.py +5 -8
  186. wandb/sdk/wandb_helper.py +1 -1
  187. wandb/sdk/wandb_init.py +24 -13
  188. wandb/sdk/wandb_login.py +9 -9
  189. wandb/sdk/wandb_manager.py +39 -4
  190. wandb/sdk/wandb_metric.py +2 -6
  191. wandb/sdk/wandb_require.py +4 -15
  192. wandb/sdk/wandb_require_helpers.py +1 -9
  193. wandb/sdk/wandb_run.py +95 -141
  194. wandb/sdk/wandb_save.py +1 -3
  195. wandb/sdk/wandb_settings.py +149 -54
  196. wandb/sdk/wandb_setup.py +66 -46
  197. wandb/sdk/wandb_summary.py +13 -10
  198. wandb/sdk/wandb_sweep.py +6 -7
  199. wandb/sdk/wandb_watch.py +1 -1
  200. wandb/sklearn/calculate/confusion_matrix.py +1 -1
  201. wandb/sklearn/calculate/learning_curve.py +1 -1
  202. wandb/sklearn/calculate/summary_metrics.py +1 -3
  203. wandb/sklearn/plot/__init__.py +1 -1
  204. wandb/sklearn/plot/classifier.py +27 -18
  205. wandb/sklearn/plot/clusterer.py +4 -5
  206. wandb/sklearn/plot/regressor.py +4 -4
  207. wandb/sklearn/plot/shared.py +2 -2
  208. wandb/sync/__init__.py +1 -3
  209. wandb/sync/sync.py +4 -5
  210. wandb/testing/relay.py +11 -10
  211. wandb/trigger.py +1 -1
  212. wandb/util.py +106 -81
  213. wandb/viz.py +4 -4
  214. wandb/wandb_agent.py +50 -50
  215. wandb/wandb_controller.py +2 -3
  216. wandb/wandb_run.py +1 -2
  217. wandb/wandb_torch.py +1 -1
  218. wandb/xgboost/__init__.py +1 -2
  219. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/METADATA +6 -2
  220. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/RECORD +224 -209
  221. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/WHEEL +1 -1
  222. wandb/sdk/launch/builder/docker.py +0 -80
  223. wandb/sdk/launch/builder/kaniko.py +0 -393
  224. wandb/sdk/launch/builder/loader.py +0 -32
  225. wandb/sdk/launch/runner/loader.py +0 -50
  226. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/LICENSE +0 -0
  227. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/entry_points.txt +0 -0
  228. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/top_level.txt +0 -0
wandb/sdk/wandb_save.py CHANGED
@@ -1,7 +1,5 @@
1
1
  #
2
- """
3
- save.
4
- """
2
+ """save."""
5
3
 
6
4
  import logging
7
5
 
@@ -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[Any]:
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
- A class to represent attributes (individual settings) of the Settings object.
191
-
192
- - Encapsulates the logic of how to preprocess and validate values of settings
193
- throughout the lifetime of a class instance.
194
- - Allows for runtime modification of settings with hooks, e.g. in the case when
195
- a setting depends on another setting.
196
- - The update() method is used to update the value of a setting.
197
- - The `is_policy` attribute determines the source priority when updating the property value.
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: int
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
- Helper method that is used in `__init__` together with the class attributes
503
- to initialize instance attributes (individual settings) as Property objects.
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
- return dict(
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={"value": 30, "preprocessor": int},
544
- _stats_sample_rate_seconds={"value": 2.0, "preprocessor": float},
545
- _stats_samples_to_average={"value": 15},
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
- Factory for type validators, given a type hint:
728
- Convert the type hint of a setting into a function
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._require_service
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
- Set the time stamps for the settings.
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 using the Property.update() method."""
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
- "WANDB_REQUIRE_SERVICE": "_require_service",
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