wandb 0.20.2rc20250616__py3-none-win32.whl → 0.21.0__py3-none-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +24 -23
  3. wandb/apis/internal.py +3 -0
  4. wandb/apis/paginator.py +17 -4
  5. wandb/apis/public/api.py +83 -2
  6. wandb/apis/public/artifacts.py +10 -8
  7. wandb/apis/public/files.py +5 -5
  8. wandb/apis/public/projects.py +44 -3
  9. wandb/apis/public/reports.py +64 -8
  10. wandb/apis/public/runs.py +16 -23
  11. wandb/automations/__init__.py +10 -10
  12. wandb/automations/_filters/run_metrics.py +0 -2
  13. wandb/automations/_utils.py +0 -2
  14. wandb/automations/actions.py +0 -2
  15. wandb/automations/automations.py +0 -2
  16. wandb/automations/events.py +0 -2
  17. wandb/bin/gpu_stats.exe +0 -0
  18. wandb/bin/wandb-core +0 -0
  19. wandb/integration/catboost/catboost.py +6 -2
  20. wandb/integration/kfp/kfp_patch.py +3 -1
  21. wandb/integration/sb3/sb3.py +3 -3
  22. wandb/integration/ultralytics/callback.py +6 -2
  23. wandb/plot/__init__.py +2 -0
  24. wandb/plot/bar.py +30 -29
  25. wandb/plot/confusion_matrix.py +75 -71
  26. wandb/plot/histogram.py +26 -25
  27. wandb/plot/line.py +33 -32
  28. wandb/plot/line_series.py +100 -103
  29. wandb/plot/pr_curve.py +33 -32
  30. wandb/plot/roc_curve.py +38 -38
  31. wandb/plot/scatter.py +27 -27
  32. wandb/proto/v3/wandb_internal_pb2.py +366 -385
  33. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  34. wandb/proto/v4/wandb_internal_pb2.py +352 -356
  35. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  36. wandb/proto/v5/wandb_internal_pb2.py +352 -356
  37. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  38. wandb/proto/v6/wandb_internal_pb2.py +352 -356
  39. wandb/proto/v6/wandb_settings_pb2.py +2 -2
  40. wandb/sdk/artifacts/_generated/__init__.py +12 -1
  41. wandb/sdk/artifacts/_generated/input_types.py +20 -2
  42. wandb/sdk/artifacts/_generated/link_artifact.py +21 -0
  43. wandb/sdk/artifacts/_generated/operations.py +9 -0
  44. wandb/sdk/artifacts/_validators.py +40 -2
  45. wandb/sdk/artifacts/artifact.py +163 -21
  46. wandb/sdk/data_types/base_types/media.py +9 -7
  47. wandb/sdk/data_types/base_types/wb_value.py +6 -6
  48. wandb/sdk/data_types/saved_model.py +3 -3
  49. wandb/sdk/data_types/table.py +41 -41
  50. wandb/sdk/data_types/trace_tree.py +12 -12
  51. wandb/sdk/interface/interface.py +8 -19
  52. wandb/sdk/interface/interface_shared.py +7 -16
  53. wandb/sdk/internal/datastore.py +18 -18
  54. wandb/sdk/internal/handler.py +3 -5
  55. wandb/sdk/internal/internal_api.py +54 -0
  56. wandb/sdk/internal/sender.py +23 -3
  57. wandb/sdk/internal/sender_config.py +9 -0
  58. wandb/sdk/launch/_project_spec.py +3 -3
  59. wandb/sdk/launch/agent/agent.py +3 -3
  60. wandb/sdk/launch/agent/job_status_tracker.py +3 -1
  61. wandb/sdk/launch/utils.py +3 -3
  62. wandb/sdk/lib/console_capture.py +66 -19
  63. wandb/sdk/wandb_init.py +1 -2
  64. wandb/sdk/wandb_require.py +0 -1
  65. wandb/sdk/wandb_run.py +23 -113
  66. wandb/sdk/wandb_settings.py +234 -72
  67. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/METADATA +1 -1
  68. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/RECORD +71 -71
  69. wandb/sdk/wandb_metadata.py +0 -623
  70. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/WHEEL +0 -0
  71. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/entry_points.txt +0 -0
  72. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/licenses/LICENSE +0 -0
@@ -25,17 +25,38 @@ In particular, it does not work with some combinations of pytest's
25
25
 
26
26
  from __future__ import annotations
27
27
 
28
+ import logging
28
29
  import sys
29
30
  import threading
30
31
  from typing import IO, AnyStr, Callable, Protocol
31
32
 
33
+ from . import wb_logging
34
+
35
+ _logger = logging.getLogger(__name__)
36
+
32
37
 
33
38
  class CannotCaptureConsoleError(Exception):
34
39
  """The module failed to patch stdout or stderr."""
35
40
 
36
41
 
37
42
  class _WriteCallback(Protocol):
38
- """A callback that receives intercepted bytes or string data."""
43
+ """A callback that receives intercepted bytes or string data.
44
+
45
+ This may be called from any thread, but is only called from one thread
46
+ at a time.
47
+
48
+ Note on errors: Any error raised during the callback will clear all
49
+ callbacks. This means that if a user presses Ctrl-C at an unlucky time
50
+ during a run, we will stop uploading console output---but it's not
51
+ likely to be a problem unless something catches the KeyboardInterrupt.
52
+
53
+ Regular Exceptions are caught and logged instead of bubbling up to the
54
+ user's print() statements; other exceptions like KeyboardInterrupt are
55
+ re-raised.
56
+
57
+ Callbacks should handle all exceptions---a callback that raises any
58
+ Exception is considered buggy.
59
+ """
39
60
 
40
61
  def __call__(
41
62
  self,
@@ -45,6 +66,8 @@ class _WriteCallback(Protocol):
45
66
  ) -> None:
46
67
  """Intercept data passed to `write()`.
47
68
 
69
+ See the protocol docstring for information about exceptions.
70
+
48
71
  Args:
49
72
  data: The object passed to stderr's or stdout's `write()`.
50
73
  written: The number of bytes or characters written.
@@ -52,7 +75,9 @@ class _WriteCallback(Protocol):
52
75
  """
53
76
 
54
77
 
55
- _module_lock = threading.Lock()
78
+ # A reentrant lock is used to catch callbacks that write to stderr/stdout.
79
+ _module_rlock = threading.RLock()
80
+ _is_writing = False
56
81
 
57
82
  _patch_exception: CannotCaptureConsoleError | None = None
58
83
 
@@ -67,9 +92,6 @@ def capture_stdout(callback: _WriteCallback) -> Callable[[], None]:
67
92
 
68
93
  Args:
69
94
  callback: A callback to invoke after running `sys.stdout.write`.
70
- This may be called from any thread, so it must be thread-safe.
71
- Exceptions are propagated to the caller of `write`.
72
- See `_WriteCallback` for the exact protocol.
73
95
 
74
96
  Returns:
75
97
  A function to uninstall the callback.
@@ -77,7 +99,7 @@ def capture_stdout(callback: _WriteCallback) -> Callable[[], None]:
77
99
  Raises:
78
100
  CannotCaptureConsoleError: If patching failed on import.
79
101
  """
80
- with _module_lock:
102
+ with _module_rlock:
81
103
  if _patch_exception:
82
104
  raise _patch_exception
83
105
 
@@ -92,9 +114,6 @@ def capture_stderr(callback: _WriteCallback) -> Callable[[], None]:
92
114
 
93
115
  Args:
94
116
  callback: A callback to invoke after running `sys.stderr.write`.
95
- This may be called from any thread, so it must be thread-safe.
96
- Exceptions are propagated to the caller of `write`.
97
- See `_WriteCallback` for the exact protocol.
98
117
 
99
118
  Returns:
100
119
  A function to uninstall the callback.
@@ -102,7 +121,7 @@ def capture_stderr(callback: _WriteCallback) -> Callable[[], None]:
102
121
  Raises:
103
122
  CannotCaptureConsoleError: If patching failed on import.
104
123
  """
105
- with _module_lock:
124
+ with _module_rlock:
106
125
  if _patch_exception:
107
126
  raise _patch_exception
108
127
 
@@ -125,11 +144,11 @@ def _insert_disposably(
125
144
  def dispose() -> None:
126
145
  nonlocal disposed
127
146
 
128
- with _module_lock:
147
+ with _module_rlock:
129
148
  if disposed:
130
149
  return
131
150
 
132
- del callback_dict[id]
151
+ callback_dict.pop(id, None)
133
152
 
134
153
  disposed = True
135
154
 
@@ -143,16 +162,44 @@ def _patch(
143
162
  ) -> None:
144
163
  orig_write: Callable[[AnyStr], int]
145
164
 
165
+ @wb_logging.log_to_all_runs()
146
166
  def write_with_callbacks(s: AnyStr, /) -> int:
167
+ global _is_writing
147
168
  n = orig_write(s)
148
169
 
149
- # We make a copy here because callbacks could, in theory, modify
150
- # the list of callbacks.
151
- with _module_lock:
152
- callbacks_copy = list(callbacks.values())
153
-
154
- for cb in callbacks_copy:
155
- cb(s, n)
170
+ # NOTE: Since _module_rlock is reentrant, this is safe. It will not
171
+ # deadlock if a callback invokes write() again.
172
+ with _module_rlock:
173
+ if _is_writing:
174
+ return n
175
+
176
+ _is_writing = True
177
+ try:
178
+ for cb in callbacks.values():
179
+ cb(s, n)
180
+
181
+ except BaseException as e:
182
+ # Clear all callbacks on any exception to avoid infinite loops:
183
+ #
184
+ # * If we re-raise, an exception handler is likely to print
185
+ # the exception to the console and trigger callbacks again
186
+ # * If we log, we can't guarantee that this doesn't print
187
+ # to console.
188
+ #
189
+ # This is especially important for KeyboardInterrupt.
190
+ _stderr_callbacks.clear()
191
+ _stdout_callbacks.clear()
192
+
193
+ if isinstance(e, Exception):
194
+ # We suppress Exceptions so that bugs in W&B code don't
195
+ # cause the user's print() statements to raise errors.
196
+ _logger.exception("Error in console callback, clearing all!")
197
+ else:
198
+ # Re-raise errors like KeyboardInterrupt.
199
+ raise
200
+
201
+ finally:
202
+ _is_writing = False
156
203
 
157
204
  return n
158
205
 
wandb/sdk/wandb_init.py CHANGED
@@ -740,7 +740,6 @@ class _WandbInit:
740
740
  drun._config.update(config.sweep_no_artifacts)
741
741
  drun._config.update(config.base_no_artifacts)
742
742
  drun.summary = SummaryDisabled() # type: ignore
743
- drun._Run__metadata = wandb.sdk.wandb_metadata.Metadata()
744
743
 
745
744
  # methods
746
745
  drun.log = lambda data, *_, **__: drun.summary.update(data) # type: ignore[method-assign]
@@ -1365,7 +1364,7 @@ def init( # noqa: C901
1365
1364
  the UI.
1366
1365
  If resuming a run, the tags provided here will replace any existing
1367
1366
  tags. To add tags to a resumed run without overwriting the current
1368
- tags, use `run.tags += ["new_tag"]` after calling `run = wandb.init()`.
1367
+ tags, use `run.tags += ("new_tag",)` after calling `run = wandb.init()`.
1369
1368
  config: Sets `wandb.config`, a dictionary-like object for storing input
1370
1369
  parameters to your run, such as model hyperparameters or data
1371
1370
  preprocessing settings.
@@ -60,7 +60,6 @@ class _Requires:
60
60
  func()
61
61
 
62
62
  if last_message:
63
- wandb.termwarn("Supported requirements are: `legacy-service`, `service`.")
64
63
  raise UnsupportedError(last_message)
65
64
 
66
65
 
wandb/sdk/wandb_run.py CHANGED
@@ -35,13 +35,13 @@ from wandb.integration.torch import wandb_torch
35
35
  from wandb.plot import CustomChart, Visualize
36
36
  from wandb.proto.wandb_deprecated import Deprecated
37
37
  from wandb.proto.wandb_internal_pb2 import (
38
- MetadataRequest,
39
38
  MetricRecord,
40
39
  PollExitResponse,
41
40
  Result,
42
41
  RunRecord,
43
42
  )
44
43
  from wandb.sdk.artifacts._internal_artifact import InternalArtifact
44
+ from wandb.sdk.artifacts._validators import is_artifact_registry_project
45
45
  from wandb.sdk.artifacts.artifact import Artifact
46
46
  from wandb.sdk.internal import job_builder
47
47
  from wandb.sdk.lib import asyncio_compat, wb_logging
@@ -63,7 +63,7 @@ from wandb.util import (
63
63
  from . import wandb_config, wandb_metric, wandb_summary
64
64
  from .artifacts._validators import (
65
65
  MAX_ARTIFACT_METADATA_KEYS,
66
- is_artifact_registry_project,
66
+ ArtifactPath,
67
67
  validate_aliases,
68
68
  validate_tags,
69
69
  )
@@ -92,7 +92,6 @@ from .mailbox import (
92
92
  wait_with_progress,
93
93
  )
94
94
  from .wandb_alerts import AlertLevel
95
- from .wandb_metadata import Metadata
96
95
  from .wandb_settings import Settings
97
96
  from .wandb_setup import _WandbSetup
98
97
 
@@ -168,6 +167,7 @@ class RunStatusChecker:
168
167
  self,
169
168
  run_id: str,
170
169
  interface: InterfaceBase,
170
+ settings: Settings,
171
171
  stop_polling_interval: int = 15,
172
172
  retry_polling_interval: int = 5,
173
173
  internal_messages_polling_interval: int = 10,
@@ -177,6 +177,7 @@ class RunStatusChecker:
177
177
  self._stop_polling_interval = stop_polling_interval
178
178
  self._retry_polling_interval = retry_polling_interval
179
179
  self._internal_messages_polling_interval = internal_messages_polling_interval
180
+ self._settings = settings
180
181
 
181
182
  self._join_event = threading.Event()
182
183
 
@@ -318,9 +319,15 @@ class RunStatusChecker:
318
319
 
319
320
  def check_internal_messages(self) -> None:
320
321
  def _process_internal_messages(result: Result) -> None:
322
+ if (
323
+ not self._settings.show_warnings
324
+ or self._settings.quiet
325
+ or self._settings.silent
326
+ ):
327
+ return
321
328
  internal_messages = result.response.internal_messages_response
322
329
  for msg in internal_messages.messages.warning:
323
- wandb.termwarn(msg)
330
+ wandb.termwarn(msg, repeat=False)
324
331
 
325
332
  with wb_logging.log_to_run(self._run_id):
326
333
  try:
@@ -620,8 +627,6 @@ class Run:
620
627
  )
621
628
  self.summary._set_update_callback(self._summary_update_callback)
622
629
 
623
- self.__metadata: Metadata | None = None
624
-
625
630
  self._step = 0
626
631
  self._starting_step = 0
627
632
  self._start_runtime = 0
@@ -1647,7 +1652,7 @@ class Run:
1647
1652
  def _populate_git_info(self) -> None:
1648
1653
  from .lib.gitlib import GitRepo
1649
1654
 
1650
- # Use user provided git info if available otherwise resolve it from the environment
1655
+ # Use user-provided git info if available, otherwise resolve it from the environment
1651
1656
  try:
1652
1657
  repo = GitRepo(
1653
1658
  root=self._settings.git_root,
@@ -2481,6 +2486,7 @@ class Run:
2481
2486
  self._run_status_checker = RunStatusChecker(
2482
2487
  self._settings.run_id,
2483
2488
  interface=self._backend.interface,
2489
+ settings=self._settings,
2484
2490
  )
2485
2491
  self._run_status_checker.start()
2486
2492
 
@@ -2947,13 +2953,6 @@ class Run:
2947
2953
  The linked artifact if linking was successful, otherwise None.
2948
2954
 
2949
2955
  """
2950
- portfolio, project, entity = wandb.util._parse_entity_project_item(target_path)
2951
- if aliases is None:
2952
- aliases = []
2953
-
2954
- if not self._backend or not self._backend.interface:
2955
- return None
2956
-
2957
2956
  if artifact.is_draft() and not artifact._is_draft_save_started():
2958
2957
  artifact = self._log_artifact(artifact)
2959
2958
 
@@ -2961,52 +2960,17 @@ class Run:
2961
2960
  # TODO: implement offline mode + sync
2962
2961
  raise NotImplementedError
2963
2962
 
2964
- # Wait until the artifact is committed before trying to link it.
2965
- artifact.wait()
2966
-
2967
- organization = ""
2968
- if is_artifact_registry_project(project):
2969
- organization = entity or self.settings.organization or ""
2970
- # In a Registry linking, the entity is used to fetch the organization of the artifact
2971
- # therefore the source artifact's entity is passed to the backend
2972
- entity = artifact._source_entity
2973
- project = project or self.project
2974
- entity = entity or self.entity
2975
- handle = self._backend.interface.deliver_link_artifact(
2976
- artifact,
2977
- portfolio,
2978
- aliases,
2979
- entity,
2980
- project,
2981
- organization,
2982
- )
2983
- if artifact._ttl_duration_seconds is not None:
2984
- wandb.termwarn(
2985
- "Artifact TTL will be disabled for source artifacts that are linked to portfolios."
2986
- )
2987
- result = handle.wait_or(timeout=None)
2988
- response = result.response.link_artifact_response
2989
- if response.error_message:
2990
- wandb.termerror(response.error_message)
2991
- return None
2992
- if response.version_index is None:
2993
- wandb.termerror(
2994
- "Error fetching the linked artifact's version index after linking"
2995
- )
2996
- return None
2963
+ # Normalize the target "entity/project/collection" with defaults
2964
+ # inferred from this run's entity and project, if needed.
2965
+ #
2966
+ # HOWEVER, if the target path is a registry collection, avoid setting
2967
+ # the target entity to the run's entity. Instead, delegate to
2968
+ # Artifact.link() to resolve the required org entity.
2969
+ target = ArtifactPath.from_str(target_path)
2970
+ if not (target.project and is_artifact_registry_project(target.project)):
2971
+ target = target.with_defaults(prefix=self.entity, project=self.project)
2997
2972
 
2998
- try:
2999
- artifact_name = f"{entity}/{project}/{portfolio}:v{response.version_index}"
3000
- if is_artifact_registry_project(project):
3001
- if organization:
3002
- artifact_name = f"{organization}/{project}/{portfolio}:v{response.version_index}"
3003
- else:
3004
- artifact_name = f"{project}/{portfolio}:v{response.version_index}"
3005
- linked_artifact = self._public_api()._artifact(artifact_name)
3006
- except Exception as e:
3007
- wandb.termerror(f"Error fetching link artifact after linking: {e}")
3008
- return None
3009
- return linked_artifact
2973
+ return artifact.link(target.to_str(), aliases)
3010
2974
 
3011
2975
  @_log_to_run
3012
2976
  @_raise_if_finished
@@ -3734,60 +3698,6 @@ class Run:
3734
3698
  logger.exception("Error getting system metrics.")
3735
3699
  return {}
3736
3700
 
3737
- @property
3738
- @_log_to_run
3739
- @_attach
3740
- @_raise_if_finished
3741
- def _metadata(self) -> Metadata | None:
3742
- """The metadata associated with this run.
3743
-
3744
- NOTE: Automatically collected metadata can be overridden by the user.
3745
- """
3746
- if not self._backend or not self._backend.interface:
3747
- return self.__metadata
3748
-
3749
- # Initialize the metadata object if it doesn't exist.
3750
- if self.__metadata is None:
3751
- self.__metadata = Metadata()
3752
- self.__metadata._set_callback(self._metadata_callback)
3753
-
3754
- handle = self._backend.interface.deliver_get_system_metadata()
3755
-
3756
- try:
3757
- result = handle.wait_or(timeout=1)
3758
- except TimeoutError:
3759
- logger.exception("Timeout getting run metadata.")
3760
- return None
3761
-
3762
- response = result.response.get_system_metadata_response
3763
-
3764
- # Temporarily disable the callback to prevent triggering
3765
- # an update call to wandb-core with the callback.
3766
- with self.__metadata.disable_callback():
3767
- # Values stored in the metadata object take precedence.
3768
- self.__metadata.update_from_proto(response.metadata, skip_existing=True)
3769
-
3770
- return self.__metadata
3771
-
3772
- @_log_to_run
3773
- @_raise_if_finished
3774
- @_attach
3775
- def _metadata_callback(
3776
- self,
3777
- metadata: MetadataRequest,
3778
- ) -> None:
3779
- """Callback to publish Metadata to wandb-core upon user updates."""
3780
- # ignore updates if the attached to another run
3781
- if self._is_attached:
3782
- wandb.termwarn(
3783
- "Metadata updates are ignored when attached to another run.",
3784
- repeat=False,
3785
- )
3786
- return
3787
-
3788
- if self._backend and self._backend.interface:
3789
- self._backend.interface.publish_metadata(metadata)
3790
-
3791
3701
  # ------------------------------------------------------------------------------
3792
3702
  # HEADER
3793
3703
  # ------------------------------------------------------------------------------