wandb 0.21.1__py3-none-win_amd64.whl → 0.21.2__py3-none-win_amd64.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.
Files changed (90) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +1 -1
  3. wandb/apis/public/api.py +1 -2
  4. wandb/apis/public/artifacts.py +3 -5
  5. wandb/apis/public/registries/_utils.py +14 -16
  6. wandb/apis/public/registries/registries_search.py +176 -289
  7. wandb/apis/public/reports.py +13 -10
  8. wandb/automations/_generated/delete_automation.py +1 -3
  9. wandb/automations/_generated/enums.py +13 -11
  10. wandb/bin/gpu_stats.exe +0 -0
  11. wandb/bin/wandb-core +0 -0
  12. wandb/cli/cli.py +47 -2
  13. wandb/integration/metaflow/data_pandas.py +2 -2
  14. wandb/integration/metaflow/data_pytorch.py +75 -0
  15. wandb/integration/metaflow/data_sklearn.py +76 -0
  16. wandb/integration/metaflow/metaflow.py +16 -87
  17. wandb/integration/weave/__init__.py +6 -0
  18. wandb/integration/weave/interface.py +49 -0
  19. wandb/integration/weave/weave.py +63 -0
  20. wandb/proto/v3/wandb_internal_pb2.py +3 -2
  21. wandb/proto/v4/wandb_internal_pb2.py +2 -2
  22. wandb/proto/v5/wandb_internal_pb2.py +2 -2
  23. wandb/proto/v6/wandb_internal_pb2.py +2 -2
  24. wandb/sdk/artifacts/_factories.py +17 -0
  25. wandb/sdk/artifacts/_generated/__init__.py +221 -13
  26. wandb/sdk/artifacts/_generated/artifact_by_id.py +17 -0
  27. wandb/sdk/artifacts/_generated/artifact_by_name.py +22 -0
  28. wandb/sdk/artifacts/_generated/artifact_collection_membership_file_urls.py +43 -0
  29. wandb/sdk/artifacts/_generated/artifact_created_by.py +47 -0
  30. wandb/sdk/artifacts/_generated/artifact_file_urls.py +22 -0
  31. wandb/sdk/artifacts/_generated/artifact_type.py +31 -0
  32. wandb/sdk/artifacts/_generated/artifact_used_by.py +43 -0
  33. wandb/sdk/artifacts/_generated/artifact_via_membership_by_name.py +26 -0
  34. wandb/sdk/artifacts/_generated/delete_artifact.py +28 -0
  35. wandb/sdk/artifacts/_generated/enums.py +5 -0
  36. wandb/sdk/artifacts/_generated/fetch_artifact_manifest.py +38 -0
  37. wandb/sdk/artifacts/_generated/fetch_registries.py +32 -0
  38. wandb/sdk/artifacts/_generated/fragments.py +279 -41
  39. wandb/sdk/artifacts/_generated/link_artifact.py +6 -0
  40. wandb/sdk/artifacts/_generated/operations.py +654 -51
  41. wandb/sdk/artifacts/_generated/registry_collections.py +34 -0
  42. wandb/sdk/artifacts/_generated/registry_versions.py +34 -0
  43. wandb/sdk/artifacts/_generated/unlink_artifact.py +25 -0
  44. wandb/sdk/artifacts/_graphql_fragments.py +3 -86
  45. wandb/sdk/artifacts/_validators.py +6 -4
  46. wandb/sdk/artifacts/artifact.py +406 -543
  47. wandb/sdk/artifacts/artifact_file_cache.py +10 -6
  48. wandb/sdk/artifacts/artifact_manifest.py +10 -9
  49. wandb/sdk/artifacts/artifact_manifest_entry.py +9 -10
  50. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +5 -3
  51. wandb/sdk/artifacts/storage_handlers/http_handler.py +1 -1
  52. wandb/sdk/artifacts/storage_handlers/s3_handler.py +1 -1
  53. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +1 -1
  54. wandb/sdk/data_types/video.py +2 -2
  55. wandb/sdk/interface/interface_queue.py +1 -4
  56. wandb/sdk/interface/interface_shared.py +26 -37
  57. wandb/sdk/interface/interface_sock.py +24 -14
  58. wandb/sdk/internal/settings_static.py +2 -3
  59. wandb/sdk/launch/create_job.py +12 -1
  60. wandb/sdk/launch/runner/kubernetes_runner.py +24 -29
  61. wandb/sdk/lib/asyncio_compat.py +16 -16
  62. wandb/sdk/lib/asyncio_manager.py +252 -0
  63. wandb/sdk/lib/hashutil.py +13 -4
  64. wandb/sdk/lib/printer.py +2 -2
  65. wandb/sdk/lib/printer_asyncio.py +3 -1
  66. wandb/sdk/lib/retry.py +185 -78
  67. wandb/sdk/lib/service/service_client.py +106 -0
  68. wandb/sdk/lib/service/service_connection.py +20 -26
  69. wandb/sdk/lib/service/service_token.py +30 -13
  70. wandb/sdk/mailbox/mailbox.py +13 -5
  71. wandb/sdk/mailbox/mailbox_handle.py +22 -13
  72. wandb/sdk/mailbox/response_handle.py +42 -106
  73. wandb/sdk/mailbox/wait_with_progress.py +7 -42
  74. wandb/sdk/wandb_init.py +11 -25
  75. wandb/sdk/wandb_login.py +1 -1
  76. wandb/sdk/wandb_run.py +91 -55
  77. wandb/sdk/wandb_settings.py +45 -32
  78. wandb/sdk/wandb_setup.py +176 -96
  79. wandb/util.py +1 -1
  80. {wandb-0.21.1.dist-info → wandb-0.21.2.dist-info}/METADATA +1 -1
  81. {wandb-0.21.1.dist-info → wandb-0.21.2.dist-info}/RECORD +84 -68
  82. wandb/sdk/interface/interface_relay.py +0 -38
  83. wandb/sdk/interface/router.py +0 -89
  84. wandb/sdk/interface/router_queue.py +0 -43
  85. wandb/sdk/interface/router_relay.py +0 -50
  86. wandb/sdk/interface/router_sock.py +0 -32
  87. wandb/sdk/lib/sock_client.py +0 -232
  88. {wandb-0.21.1.dist-info → wandb-0.21.2.dist-info}/WHEEL +0 -0
  89. {wandb-0.21.1.dist-info → wandb-0.21.2.dist-info}/entry_points.txt +0 -0
  90. {wandb-0.21.1.dist-info → wandb-0.21.2.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_setup.py CHANGED
@@ -28,12 +28,13 @@ import logging
28
28
  import os
29
29
  import pathlib
30
30
  import sys
31
+ import threading
31
32
  from typing import TYPE_CHECKING, Any, Union
32
33
 
33
34
  import wandb
34
35
  import wandb.integration.sagemaker as sagemaker
35
36
  from wandb.env import CONFIG_DIR
36
- from wandb.sdk.lib import import_hooks, wb_logging
37
+ from wandb.sdk.lib import asyncio_manager, import_hooks, wb_logging
37
38
 
38
39
  from . import wandb_settings
39
40
  from .lib import config_util, server
@@ -88,19 +89,16 @@ Logger = Union[logging.Logger, _EarlyLogger]
88
89
  class _WandbSetup:
89
90
  """W&B library singleton."""
90
91
 
91
- def __init__(
92
- self,
93
- pid: int,
94
- settings: Settings | None = None,
95
- environ: dict | None = None,
96
- ) -> None:
92
+ def __init__(self, pid: int) -> None:
93
+ self._asyncer = asyncio_manager.AsyncioManager()
94
+ self._asyncer.start()
95
+
97
96
  self._connection: ServiceConnection | None = None
98
97
 
99
98
  self._active_runs: list[wandb_run.Run] = []
99
+ self._active_runs_lock = threading.Lock()
100
100
 
101
- self._environ = environ or dict(os.environ)
102
101
  self._sweep_config: dict | None = None
103
- self._config: dict | None = None
104
102
  self._server: server.Server | None = None
105
103
  self._pid = pid
106
104
 
@@ -108,11 +106,13 @@ class _WandbSetup:
108
106
  # and logging is ready
109
107
  self._logger: Logger = _EarlyLogger()
110
108
 
111
- self._settings = self._settings_setup(settings)
109
+ self._settings: Settings | None = None
110
+ self._settings_environ: dict[str, str] | None = None
112
111
 
113
- wandb.termsetup(self._settings, None)
114
-
115
- self._setup()
112
+ @property
113
+ def asyncer(self) -> asyncio_manager.AsyncioManager:
114
+ """The internal asyncio thread used by wandb."""
115
+ return self._asyncer
116
116
 
117
117
  def add_active_run(self, run: wandb_run.Run) -> None:
118
118
  """Append a run to the active runs list.
@@ -122,8 +122,9 @@ class _WandbSetup:
122
122
  Args:
123
123
  run: A newly initialized run.
124
124
  """
125
- if run not in self._active_runs:
126
- self._active_runs.append(run)
125
+ with self._active_runs_lock:
126
+ if run not in self._active_runs:
127
+ self._active_runs.append(run)
127
128
 
128
129
  def remove_active_run(self, run: wandb_run.Run) -> None:
129
130
  """Remove the run from the active runs list.
@@ -134,17 +135,19 @@ class _WandbSetup:
134
135
  run: A run that is finished or crashed.
135
136
  """
136
137
  try:
137
- self._active_runs.remove(run)
138
+ with self._active_runs_lock:
139
+ self._active_runs.remove(run)
138
140
  except ValueError:
139
141
  pass # Removing a run multiple times is not an error.
140
142
 
141
143
  @property
142
144
  def most_recent_active_run(self) -> wandb_run.Run | None:
143
145
  """The most recently initialized run that is not yet finished."""
144
- if not self._active_runs:
145
- return None
146
+ with self._active_runs_lock:
147
+ if not self._active_runs:
148
+ return None
146
149
 
147
- return self._active_runs[-1]
150
+ return self._active_runs[-1]
148
151
 
149
152
  def finish_all_active_runs(self) -> None:
150
153
  """Finish all unfinished runs.
@@ -156,74 +159,131 @@ class _WandbSetup:
156
159
  default and only behavior, it does not seem worth optimizing.
157
160
  """
158
161
  # Take a snapshot as each call to `finish()` modifies `_active_runs`.
159
- runs_copy = list(self._active_runs)
162
+ with self._active_runs_lock:
163
+ runs_copy = list(self._active_runs)
164
+
160
165
  for run in runs_copy:
161
166
  run.finish()
162
167
 
163
- def _settings_setup(
168
+ def did_environment_change(self) -> bool:
169
+ """Check if os.environ has changed since settings were initialized."""
170
+ if not self._settings_environ:
171
+ return False
172
+
173
+ exclude_env_vars = {"WANDB_SERVICE", "WANDB_KUBEFLOW_URL"}
174
+ singleton_env = {
175
+ k: v
176
+ for k, v in self._settings_environ.items()
177
+ if k.startswith("WANDB_") and k not in exclude_env_vars
178
+ }
179
+ os_env = {
180
+ k: v
181
+ for k, v in os.environ.items()
182
+ if k.startswith("WANDB_") and k not in exclude_env_vars
183
+ }
184
+
185
+ return (
186
+ set(singleton_env.keys()) == set(os_env.keys()) #
187
+ and set(singleton_env.values()) == set(os_env.values())
188
+ )
189
+
190
+ def _load_settings(
164
191
  self,
165
- settings: Settings | None,
166
- ) -> wandb_settings.Settings:
167
- s = wandb_settings.Settings()
192
+ *,
193
+ system_settings_path: str | None,
194
+ disable_sagemaker: bool,
195
+ overrides: Settings | None = None,
196
+ ) -> None:
197
+ """Load settings from environment variables, config files, etc.
198
+
199
+ Args:
200
+ system_settings_path: Location of system settings file to use.
201
+ If not provided, reads the WANDB_CONFIG_DIR environment
202
+ variable or uses the default location.
203
+ disable_sagemaker: If true, skips modifying settings based on
204
+ SageMaker.
205
+ overrides: Additional settings to apply to the global settings.
206
+ """
207
+ self._settings = wandb_settings.Settings()
168
208
 
169
209
  # the pid of the process to monitor for system stats
170
210
  pid = os.getpid()
171
211
  self._logger.info(f"Current SDK version is {wandb.__version__}")
172
212
  self._logger.info(f"Configure stats pid to {pid}")
173
- s.x_stats_pid = pid
213
+ self._settings.x_stats_pid = pid
174
214
 
175
- if settings and settings.settings_system:
176
- s.settings_system = settings.settings_system
215
+ if system_settings_path:
216
+ self._settings.settings_system = system_settings_path
177
217
  elif config_dir_str := os.getenv(CONFIG_DIR, None):
178
218
  config_dir = pathlib.Path(config_dir_str).expanduser()
179
- s.settings_system = str(config_dir / "settings")
219
+ self._settings.settings_system = str(config_dir / "settings")
180
220
  else:
181
- s.settings_system = str(
221
+ self._settings.settings_system = str(
182
222
  pathlib.Path("~", ".config", "wandb", "settings").expanduser()
183
223
  )
184
224
 
185
225
  # load settings from the system config
186
- if s.settings_system:
187
- self._logger.info(f"Loading settings from {s.settings_system}")
188
- s.update_from_system_config_file()
226
+ if self._settings.settings_system:
227
+ self._logger.info(
228
+ f"Loading settings from {self._settings.settings_system}",
229
+ )
230
+ self._settings.update_from_system_config_file()
189
231
 
190
232
  # load settings from the workspace config
191
- if s.settings_workspace:
192
- self._logger.info(f"Loading settings from {s.settings_workspace}")
193
- s.update_from_workspace_config_file()
233
+ if self._settings.settings_workspace:
234
+ self._logger.info(
235
+ f"Loading settings from {self._settings.settings_workspace}",
236
+ )
237
+ self._settings.update_from_workspace_config_file()
194
238
 
195
239
  # load settings from the environment variables
196
240
  self._logger.info("Loading settings from environment variables")
197
- s.update_from_env_vars(self._environ)
241
+ self._settings_environ = os.environ.copy()
242
+ self._settings.update_from_env_vars(self._settings_environ)
198
243
 
199
244
  # infer settings from the system environment
200
- s.update_from_system_environment()
245
+ self._settings.update_from_system_environment()
201
246
 
202
247
  # load SageMaker settings
203
- check_sagemaker_env = not s.sagemaker_disable
204
- if settings and settings.sagemaker_disable:
205
- check_sagemaker_env = False
206
- if check_sagemaker_env and sagemaker.is_using_sagemaker():
248
+ if (
249
+ not self._settings.sagemaker_disable
250
+ and not disable_sagemaker
251
+ and sagemaker.is_using_sagemaker()
252
+ ):
207
253
  self._logger.info("Loading SageMaker settings")
208
- sagemaker.set_global_settings(s)
254
+ sagemaker.set_global_settings(self._settings)
209
255
 
210
256
  # load settings from the passed init/setup settings
211
- if settings:
212
- s.update_from_settings(settings)
257
+ if overrides:
258
+ self._settings.update_from_settings(overrides)
213
259
 
214
- return s
260
+ wandb.termsetup(self._settings, None)
215
261
 
216
- def _update(self, settings: Settings | None = None) -> None:
217
- if not settings:
218
- return
219
- self._settings.update_from_settings(settings)
262
+ def _update(self, settings: Settings | None) -> None:
263
+ """Update settings, initializing them if necessary.
220
264
 
221
- def _update_user_settings(self) -> None:
265
+ Args:
266
+ settings: Overrides to apply, if any.
267
+ """
268
+ if not self._settings:
269
+ system_settings_path = settings.settings_system if settings else None
270
+ disable_sagemaker = settings.sagemaker_disable if settings else False
271
+ self._load_settings(
272
+ system_settings_path=system_settings_path,
273
+ disable_sagemaker=disable_sagemaker,
274
+ overrides=settings,
275
+ )
276
+
277
+ # This is 'elif' because load_settings already applies overrides.
278
+ elif settings:
279
+ self._settings.update_from_settings(settings)
280
+
281
+ def update_user_settings(self) -> None:
222
282
  # Get rid of cached results to force a refresh.
223
283
  self._server = None
224
284
  user_settings = self._load_user_settings()
225
285
  if user_settings is not None:
226
- self._settings.update_from_dict(user_settings)
286
+ self.settings.update_from_dict(user_settings)
227
287
 
228
288
  def _early_logger_flush(self, new_logger: Logger) -> None:
229
289
  if self._logger is new_logger:
@@ -238,6 +298,22 @@ class _WandbSetup:
238
298
 
239
299
  @property
240
300
  def settings(self) -> wandb_settings.Settings:
301
+ """The global wandb settings.
302
+
303
+ Initializes settings if they have not yet been loaded.
304
+ """
305
+ if not self._settings:
306
+ self._load_settings(
307
+ system_settings_path=None,
308
+ disable_sagemaker=False,
309
+ )
310
+ assert self._settings
311
+
312
+ return self._settings
313
+
314
+ @property
315
+ def settings_if_loaded(self) -> wandb_settings.Settings | None:
316
+ """The global wandb settings, or None if not yet loaded."""
241
317
  return self._settings
242
318
 
243
319
  def _get_entity(self) -> str | None:
@@ -262,7 +338,7 @@ class _WandbSetup:
262
338
  @property
263
339
  def viewer(self) -> dict[str, Any]:
264
340
  if self._server is None:
265
- self._server = server.Server(settings=self._settings)
341
+ self._server = server.Server(settings=self.settings)
266
342
 
267
343
  return self._server.viewer
268
344
 
@@ -282,36 +358,36 @@ class _WandbSetup:
282
358
 
283
359
  return user_settings
284
360
 
285
- def _setup(self) -> None:
286
- sweep_path = self._settings.sweep_param_path
361
+ @property
362
+ def config(self) -> dict:
363
+ sweep_path = self.settings.sweep_param_path
287
364
  if sweep_path:
288
365
  self._sweep_config = config_util.dict_from_config_file(
289
366
  sweep_path, must_exist=True
290
367
  )
291
368
 
369
+ config = {}
370
+
292
371
  # if config_paths was set, read in config dict
293
- if self._settings.config_paths:
372
+ if self.settings.config_paths:
294
373
  # TODO(jhr): handle load errors, handle list of files
295
- for config_path in self._settings.config_paths:
374
+ for config_path in self.settings.config_paths:
296
375
  config_dict = config_util.dict_from_config_file(config_path)
297
- if config_dict is None:
298
- continue
299
- if self._config is not None:
300
- self._config.update(config_dict)
301
- else:
302
- self._config = config_dict
376
+ if config_dict:
377
+ config.update(config_dict)
378
+
379
+ return config
303
380
 
304
381
  def _teardown(self, exit_code: int | None = None) -> None:
305
382
  import_hooks.unregister_all_post_import_hooks()
306
383
 
307
- if not self._connection:
308
- return
384
+ if self._connection:
385
+ internal_exit_code = self._connection.teardown(exit_code or 0)
386
+ else:
387
+ internal_exit_code = None
309
388
 
310
- # Reset to None so that setup() creates a new connection.
311
- connection = self._connection
312
- self._connection = None
389
+ self._asyncer.join()
313
390
 
314
- internal_exit_code = connection.teardown(exit_code or 0)
315
391
  if internal_exit_code not in (None, 0):
316
392
  sys.exit(internal_exit_code)
317
393
 
@@ -322,7 +398,10 @@ class _WandbSetup:
322
398
 
323
399
  from wandb.sdk.lib.service import service_connection
324
400
 
325
- self._connection = service_connection.connect_to_service(self._settings)
401
+ self._connection = service_connection.connect_to_service(
402
+ self._asyncer,
403
+ self.settings,
404
+ )
326
405
  return self._connection
327
406
 
328
407
  def assert_service(self) -> ServiceConnection:
@@ -343,6 +422,8 @@ _singleton: _WandbSetup | None = None
343
422
  The value is invalid and must not be used if `os.getpid() != _singleton._pid`.
344
423
  """
345
424
 
425
+ _singleton_lock = threading.Lock()
426
+
346
427
 
347
428
  def singleton() -> _WandbSetup:
348
429
  """The W&B singleton for the current process.
@@ -351,29 +432,14 @@ def singleton() -> _WandbSetup:
351
432
  process) creates the singleton, and all subsequent calls return it
352
433
  until teardown(). This does not start the service process.
353
434
  """
354
- return _setup(start_service=False)
355
-
356
-
357
- def singleton_if_setup() -> _WandbSetup | None:
358
- """The W&B singleton for the current process or None if it isn't set up.
359
-
360
- Always prefer singleton() over this function.
361
-
362
- Unlike singleton(), this never creates the singleton and therefore never
363
- initializes global settings from the environment. This is useful only
364
- during tests, which may modify the environment after having imported wandb
365
- and called certain functions.
366
- """
367
- if _singleton and _singleton._pid == os.getpid():
368
- return _singleton
369
- else:
370
- return None
435
+ return _setup(start_service=False, load_settings=False)
371
436
 
372
437
 
373
438
  @wb_logging.log_to_all_runs()
374
439
  def _setup(
375
440
  settings: Settings | None = None,
376
441
  start_service: bool = True,
442
+ load_settings: bool = True,
377
443
  ) -> _WandbSetup:
378
444
  """Set up library context.
379
445
 
@@ -384,18 +450,31 @@ def _setup(
384
450
  NOTE: A service process will only be started if allowed by the
385
451
  global settings (after the given updates). The service will not
386
452
  start up if the mode resolves to "disabled".
453
+ load_settings: Whether to load settings from the environment
454
+ if creating a new singleton. If False, then settings and
455
+ start_service must be None.
387
456
  """
388
457
  global _singleton
389
458
 
459
+ if not load_settings and settings:
460
+ raise ValueError("Cannot pass settings if load_settings is False.")
461
+ if not load_settings and start_service:
462
+ raise ValueError("Cannot use start_service if load_settings is False.")
463
+
390
464
  pid = os.getpid()
465
+ with _singleton_lock:
466
+ if _singleton and _singleton._pid == pid:
467
+ current_singleton = _singleton
468
+ else:
469
+ current_singleton = _WandbSetup(pid=pid)
470
+
471
+ if load_settings:
472
+ current_singleton._update(settings)
391
473
 
392
- if _singleton and _singleton._pid == pid:
393
- _singleton._update(settings=settings)
394
- else:
395
- _singleton = _WandbSetup(settings=settings, pid=pid)
474
+ if start_service and not current_singleton.settings._noop:
475
+ current_singleton.ensure_service()
396
476
 
397
- if start_service and not _singleton.settings._noop:
398
- _singleton.ensure_service()
477
+ _singleton = current_singleton
399
478
 
400
479
  return _singleton
401
480
 
@@ -473,8 +552,9 @@ def teardown(exit_code: int | None = None) -> None:
473
552
  """
474
553
  global _singleton
475
554
 
476
- orig_singleton = _singleton
477
- _singleton = None
555
+ with _singleton_lock:
556
+ orig_singleton = _singleton
557
+ _singleton = None
478
558
 
479
- if orig_singleton:
480
- orig_singleton._teardown(exit_code=exit_code)
559
+ if orig_singleton:
560
+ orig_singleton._teardown(exit_code=exit_code)
wandb/util.py CHANGED
@@ -702,7 +702,7 @@ def json_friendly_val(val: Any) -> Any:
702
702
  return converted
703
703
  if is_dataclass(val) and not isinstance(val, type):
704
704
  converted = asdict(val)
705
- return converted
705
+ return json_friendly_val(converted)
706
706
  else:
707
707
  if val.__class__.__module__ not in ("builtins", "__builtin__"):
708
708
  val = str(val)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: wandb
3
- Version: 0.21.1
3
+ Version: 0.21.2
4
4
  Summary: A CLI and library for interacting with the Weights & Biases API.
5
5
  Project-URL: Source, https://github.com/wandb/wandb
6
6
  Project-URL: Bug Reports, https://github.com/wandb/wandb/issues