wandb 0.18.7__py3-none-any.whl → 0.19.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. package_readme.md +8 -0
  2. wandb/__init__.py +5 -7
  3. wandb/__init__.pyi +51 -30
  4. wandb/analytics/sentry.py +4 -10
  5. wandb/apis/importers/internals/internal.py +6 -6
  6. wandb/apis/importers/internals/protocols.py +11 -7
  7. wandb/apis/public/jobs.py +1 -7
  8. wandb/apis/public/reports.py +6 -17
  9. wandb/apis/public/runs.py +12 -10
  10. wandb/bin/gpu_stats +0 -0
  11. wandb/cli/cli.py +9 -45
  12. wandb/env.py +3 -5
  13. wandb/errors/links.py +1 -1
  14. wandb/errors/term.py +1 -6
  15. wandb/filesync/dir_watcher.py +3 -3
  16. wandb/filesync/step_upload.py +2 -5
  17. wandb/integration/fastai/__init__.py +1 -6
  18. wandb/integration/gym/__init__.py +1 -7
  19. wandb/integration/keras/callbacks/metrics_logger.py +1 -8
  20. wandb/integration/keras/callbacks/model_checkpoint.py +1 -8
  21. wandb/integration/keras/keras.py +3 -5
  22. wandb/integration/lightgbm/__init__.py +1 -1
  23. wandb/integration/sb3/sb3.py +1 -7
  24. wandb/integration/sklearn/utils.py +1 -1
  25. wandb/integration/tensorboard/log.py +1 -2
  26. wandb/integration/torch/wandb_torch.py +1 -1
  27. wandb/integration/ultralytics/bbox_utils.py +9 -2
  28. wandb/jupyter.py +4 -4
  29. wandb/proto/v3/wandb_internal_pb2.py +31 -31
  30. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  31. wandb/proto/v4/wandb_internal_pb2.py +31 -31
  32. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  33. wandb/proto/v5/wandb_internal_pb2.py +31 -31
  34. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  35. wandb/proto/wandb_deprecated.py +1 -11
  36. wandb/proto/wandb_generate_deprecated.py +3 -7
  37. wandb/sdk/artifacts/artifact.py +2 -10
  38. wandb/sdk/artifacts/artifact_file_cache.py +2 -5
  39. wandb/sdk/artifacts/artifact_saver.py +2 -6
  40. wandb/sdk/artifacts/storage_handlers/gcs_handler.py +2 -4
  41. wandb/sdk/artifacts/storage_handlers/local_file_handler.py +2 -4
  42. wandb/sdk/artifacts/storage_handlers/s3_handler.py +2 -4
  43. wandb/sdk/backend/backend.py +1 -1
  44. wandb/sdk/data_types/histogram.py +1 -3
  45. wandb/sdk/data_types/object_3d.py +2 -6
  46. wandb/sdk/data_types/table.py +1 -1
  47. wandb/sdk/data_types/utils.py +1 -2
  48. wandb/sdk/data_types/video.py +15 -4
  49. wandb/sdk/integration_utils/auto_logging.py +1 -8
  50. wandb/sdk/interface/interface.py +12 -5
  51. wandb/sdk/interface/interface_shared.py +9 -0
  52. wandb/sdk/internal/file_stream.py +1 -4
  53. wandb/sdk/internal/flow_control.py +1 -1
  54. wandb/sdk/internal/handler.py +7 -2
  55. wandb/sdk/internal/internal.py +3 -3
  56. wandb/sdk/internal/internal_api.py +3 -10
  57. wandb/sdk/internal/job_builder.py +20 -12
  58. wandb/sdk/internal/progress.py +1 -5
  59. wandb/sdk/internal/sender.py +9 -13
  60. wandb/sdk/internal/settings_static.py +4 -10
  61. wandb/sdk/internal/system/assets/cpu.py +2 -2
  62. wandb/sdk/internal/system/assets/disk.py +3 -3
  63. wandb/sdk/internal/system/assets/gpu.py +7 -7
  64. wandb/sdk/internal/system/assets/gpu_amd.py +1 -7
  65. wandb/sdk/internal/system/assets/interfaces.py +11 -13
  66. wandb/sdk/internal/system/assets/ipu.py +1 -1
  67. wandb/sdk/internal/system/assets/memory.py +2 -2
  68. wandb/sdk/internal/system/assets/open_metrics.py +2 -8
  69. wandb/sdk/internal/system/assets/trainium.py +3 -9
  70. wandb/sdk/internal/system/system_info.py +14 -13
  71. wandb/sdk/internal/system/system_monitor.py +5 -12
  72. wandb/sdk/internal/tb_watcher.py +1 -1
  73. wandb/sdk/internal/writer.py +1 -1
  74. wandb/sdk/launch/agent/run_queue_item_file_saver.py +1 -7
  75. wandb/sdk/launch/create_job.py +2 -3
  76. wandb/sdk/launch/runner/abstract.py +1 -6
  77. wandb/sdk/launch/runner/kubernetes_monitor.py +2 -4
  78. wandb/sdk/lib/apikey.py +2 -6
  79. wandb/sdk/lib/fsm.py +12 -6
  80. wandb/sdk/lib/ipython.py +1 -6
  81. wandb/sdk/lib/module.py +0 -3
  82. wandb/sdk/lib/progress.py +2 -3
  83. wandb/sdk/lib/run_moment.py +1 -7
  84. wandb/sdk/lib/server.py +10 -24
  85. wandb/sdk/service/server.py +1 -1
  86. wandb/sdk/service/service.py +5 -5
  87. wandb/sdk/wandb_init.py +215 -166
  88. wandb/sdk/wandb_login.py +17 -27
  89. wandb/sdk/wandb_run.py +90 -116
  90. wandb/sdk/wandb_settings.py +978 -1778
  91. wandb/sdk/wandb_setup.py +86 -89
  92. wandb/sdk/wandb_watch.py +1 -1
  93. wandb/sync/sync.py +1 -2
  94. wandb/util.py +6 -39
  95. wandb/wandb_controller.py +10 -12
  96. {wandb-0.18.7.dist-info → wandb-0.19.0.dist-info}/METADATA +13 -3
  97. {wandb-0.18.7.dist-info → wandb-0.19.0.dist-info}/RECORD +100 -105
  98. wandb/integration/magic.py +0 -556
  99. wandb/magic.py +0 -3
  100. wandb/sdk/lib/_settings_toposort_generate.py +0 -159
  101. wandb/sdk/lib/_settings_toposort_generated.py +0 -251
  102. wandb/sdk/lib/reporting.py +0 -99
  103. {wandb-0.18.7.dist-info → wandb-0.19.0.dist-info}/WHEEL +0 -0
  104. {wandb-0.18.7.dist-info → wandb-0.19.0.dist-info}/entry_points.txt +0 -0
  105. {wandb-0.18.7.dist-info → wandb-0.19.0.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_login.py CHANGED
@@ -5,13 +5,7 @@ This authenticates your machine to log data to your account.
5
5
 
6
6
  import enum
7
7
  import os
8
- import sys
9
- from typing import Optional, Tuple
10
-
11
- if sys.version_info >= (3, 8):
12
- from typing import Literal
13
- else:
14
- from typing_extensions import Literal
8
+ from typing import Literal, Optional, Tuple
15
9
 
16
10
  import click
17
11
 
@@ -124,7 +118,7 @@ class _WandbLogin:
124
118
  def setup(
125
119
  self,
126
120
  *,
127
- anonymous: Optional[Literal["must", "allow", "never"]] = None,
121
+ anonymous: Optional[Literal["allow", "must", "never"]] = None,
128
122
  key: Optional[str] = None,
129
123
  relogin: Optional[bool] = None,
130
124
  host: Optional[str] = None,
@@ -134,23 +128,20 @@ class _WandbLogin:
134
128
  """Updates login-related settings on the global setup object."""
135
129
  self._relogin = relogin
136
130
 
137
- # built up login settings
138
- login_settings: Settings = wandb.Settings()
139
- logger = wandb.setup()._get_logger()
140
-
141
- login_settings._apply_login(
142
- {
143
- "anonymous": anonymous,
144
- "key": key,
145
- "host": host,
146
- "force": force,
147
- "timeout": timeout,
148
- },
149
- _logger=logger,
150
- )
131
+ login_settings = {
132
+ "anonymous": anonymous,
133
+ "api_key": key,
134
+ "base_url": host,
135
+ "force": force,
136
+ "login_timeout": timeout,
137
+ }
151
138
 
152
139
  # make sure they are applied globally
153
- self._wl = wandb.setup(settings=login_settings)
140
+ self._wl = wandb.setup(
141
+ settings=wandb.Settings(
142
+ **{k: v for k, v in login_settings.items() if v is not None}
143
+ )
144
+ )
154
145
  self._settings = self._wl.settings
155
146
 
156
147
  def is_apikey_configured(self) -> bool:
@@ -232,7 +223,6 @@ class _WandbLogin:
232
223
 
233
224
  If we're online, this also pulls in user settings from the server.
234
225
  """
235
- _logger = wandb.setup()._get_logger()
236
226
  login_settings = dict()
237
227
  if status == ApiKeyStatus.OFFLINE:
238
228
  login_settings = dict(mode="offline")
@@ -240,7 +230,7 @@ class _WandbLogin:
240
230
  login_settings = dict(mode="disabled")
241
231
  elif key:
242
232
  login_settings = dict(api_key=key)
243
- self._wl._settings._apply_login(login_settings, _logger=_logger)
233
+ self._wl._settings.update_from_dict(login_settings)
244
234
  # Whenever the key changes, make sure to pull in user settings
245
235
  # from server.
246
236
  if not self._wl.settings._offline:
@@ -275,7 +265,7 @@ class _WandbLogin:
275
265
  if status == ApiKeyStatus.NOTTY:
276
266
  directive = (
277
267
  "wandb login [your_api_key]"
278
- if self._settings._cli_only_mode
268
+ if self._settings.x_cli_only_mode
279
269
  else "wandb.login(key=[your_api_key])"
280
270
  )
281
271
  raise UsageError("api_key not configured (no-tty). call " + directive)
@@ -286,7 +276,7 @@ class _WandbLogin:
286
276
 
287
277
  def _login(
288
278
  *,
289
- anonymous: Optional[Literal["must", "allow", "never"]] = None,
279
+ anonymous: Optional[Literal["allow", "must", "never"]] = None,
290
280
  key: Optional[str] = None,
291
281
  relogin: Optional[bool] = None,
292
282
  host: Optional[str] = None,
wandb/sdk/wandb_run.py CHANGED
@@ -19,18 +19,15 @@ from collections.abc import Mapping
19
19
  from dataclasses import dataclass, field
20
20
  from datetime import datetime, timedelta, timezone
21
21
  from enum import IntEnum
22
+ from functools import reduce
22
23
  from types import TracebackType
23
- from typing import TYPE_CHECKING, Any, Callable, NamedTuple, Sequence, TextIO
24
-
25
- if sys.version_info < (3, 8):
26
- from typing_extensions import Literal
27
- else:
28
- from typing import Literal
24
+ from typing import TYPE_CHECKING, Any, Callable, Literal, NamedTuple, Sequence, TextIO
29
25
 
30
26
  import requests
31
27
 
32
28
  import wandb
33
29
  import wandb.env
30
+ import wandb.util
34
31
  from wandb import trigger
35
32
  from wandb._globals import _datatypes_set_callback
36
33
  from wandb.apis import internal, public
@@ -39,7 +36,7 @@ from wandb.apis.public import Api as PublicApi
39
36
  from wandb.errors import CommError, UnsupportedError, UsageError
40
37
  from wandb.errors.links import url_registry
41
38
  from wandb.integration.torch import wandb_torch
42
- from wandb.plot import CustomChart, Visualize, plot_table
39
+ from wandb.plot import CustomChart, Visualize
43
40
  from wandb.proto.wandb_internal_pb2 import (
44
41
  MetricRecord,
45
42
  PollExitResponse,
@@ -89,23 +86,18 @@ from .lib.exit_hooks import ExitHooks
89
86
  from .lib.gitlib import GitRepo
90
87
  from .lib.mailbox import MailboxError, MailboxHandle, MailboxProbe, MailboxProgress
91
88
  from .lib.proto_util import message_to_dict
92
- from .lib.reporting import Reporter
93
89
  from .wandb_alerts import AlertLevel
94
90
  from .wandb_settings import Settings
95
91
  from .wandb_setup import _WandbSetup
96
92
 
97
93
  if TYPE_CHECKING:
98
- if sys.version_info >= (3, 8):
99
- from typing import TypedDict
100
- else:
101
- from typing_extensions import TypedDict
94
+ from typing import TypedDict
102
95
 
103
96
  import torch # type: ignore [import-not-found]
104
97
 
105
98
  import wandb.apis.public
106
99
  import wandb.sdk.backend.backend
107
100
  import wandb.sdk.interface.interface_queue
108
- from wandb.data_types import Table
109
101
  from wandb.proto.wandb_internal_pb2 import (
110
102
  GetSummaryResponse,
111
103
  InternalMessagesResponse,
@@ -440,7 +432,7 @@ class _run_decorator: # noqa: N801
440
432
  # - for fork case will use the settings of the parent process
441
433
  # - only point of inconsistent behavior from forked and non-forked cases
442
434
  settings = getattr(self, "_settings", None)
443
- if settings and settings["strict"]:
435
+ if settings and settings.strict:
444
436
  wandb.termerror(message, repeat=False)
445
437
  raise UnsupportedError(
446
438
  f"`{func.__name__}` does not support multiprocessing"
@@ -539,7 +531,6 @@ class Run:
539
531
  _sweep_id: str | None
540
532
 
541
533
  _run_obj: RunRecord | None
542
- # Use string literal annotation because of type reference loop
543
534
  _backend: wandb.sdk.backend.backend.Backend | None
544
535
  _internal_run_interface: wandb.sdk.interface.interface_queue.InterfaceQueue | None
545
536
  _wl: _WandbSetup | None
@@ -633,7 +624,6 @@ class Run:
633
624
 
634
625
  self._printer = printer.new_printer()
635
626
  self._wl = None
636
- self._reporter: Reporter | None = None
637
627
 
638
628
  self._entity = None
639
629
  self._project = None
@@ -749,7 +739,7 @@ class Run:
749
739
  self._attach_pid = os.getpid()
750
740
 
751
741
  # for now, use runid as attach id, this could/should be versioned in the future
752
- if not self._settings._disable_service:
742
+ if not self._settings.x_disable_service:
753
743
  self._attach_id = self._settings.run_id
754
744
 
755
745
  def _set_iface_pid(self, iface_pid: int) -> None:
@@ -894,7 +884,7 @@ class Run:
894
884
  def __getstate__(self) -> Any:
895
885
  """Return run state as a custom pickle."""
896
886
  # We only pickle in service mode
897
- if not self._settings or self._settings._disable_service:
887
+ if not self._settings or self._settings.x_disable_service:
898
888
  return
899
889
 
900
890
  _attach_id = self._attach_id
@@ -931,9 +921,7 @@ class Run:
931
921
  @_run_decorator._attach
932
922
  def settings(self) -> Settings:
933
923
  """A frozen copy of run's Settings object."""
934
- cp = self._settings.copy()
935
- cp.freeze()
936
- return cp
924
+ return self._settings.model_copy(deep=True)
937
925
 
938
926
  @property
939
927
  @_run_decorator._attach
@@ -1191,11 +1179,11 @@ class Run:
1191
1179
  notebook_name = None
1192
1180
  if self.settings.notebook_name:
1193
1181
  notebook_name = self.settings.notebook_name
1194
- elif self.settings._jupyter_path:
1195
- if self.settings._jupyter_path.startswith("fileId="):
1196
- notebook_name = self.settings._jupyter_name
1182
+ elif self.settings.x_jupyter_path:
1183
+ if self.settings.x_jupyter_path.startswith("fileId="):
1184
+ notebook_name = self.settings.x_jupyter_name
1197
1185
  else:
1198
- notebook_name = self.settings._jupyter_path
1186
+ notebook_name = self.settings.x_jupyter_path
1199
1187
  name_string = f"{self._project}-{notebook_name}"
1200
1188
  else:
1201
1189
  name_string = f"{self._project}-{self._settings.program_relpath}"
@@ -1557,9 +1545,6 @@ class Run:
1557
1545
  ) -> None:
1558
1546
  self._internal_run_interface = interface
1559
1547
 
1560
- def _set_reporter(self, reporter: Reporter) -> None:
1561
- self._reporter = reporter
1562
-
1563
1548
  def _set_teardown_hooks(self, hooks: list[TeardownHook]) -> None:
1564
1549
  self._teardown_hooks = hooks
1565
1550
 
@@ -1589,8 +1574,31 @@ class Run:
1589
1574
  self._step = self._get_starting_step()
1590
1575
 
1591
1576
  # update settings from run_obj
1592
- self._settings._apply_run_start(message_to_dict(self._run_obj))
1593
- self._update_settings(self._settings)
1577
+ run_start_settings = message_to_dict(self._run_obj)
1578
+ param_map = {
1579
+ "run_id": "run_id",
1580
+ "entity": "entity",
1581
+ "project": "project",
1582
+ "run_group": "run_group",
1583
+ "job_type": "run_job_type",
1584
+ "display_name": "run_name",
1585
+ "notes": "run_notes",
1586
+ "tags": "run_tags",
1587
+ "sweep_id": "sweep_id",
1588
+ "host": "host",
1589
+ "resumed": "resumed",
1590
+ "git.remote_url": "git_remote_url",
1591
+ "git.commit": "git_commit",
1592
+ }
1593
+ run_settings = {
1594
+ name: reduce(lambda d, k: d.get(k, {}), attr.split("."), run_start_settings)
1595
+ for attr, name in param_map.items()
1596
+ }
1597
+ run_settings = {key: value for key, value in run_settings.items() if value}
1598
+
1599
+ if run_settings:
1600
+ self._settings.update_from_dict(run_settings)
1601
+ self._update_settings(self._settings)
1594
1602
 
1595
1603
  wandb._sentry.configure_scope(
1596
1604
  process_context="user",
@@ -2034,7 +2042,7 @@ class Run:
2034
2042
  policy: PolicyName,
2035
2043
  ) -> list[str]:
2036
2044
  # Can't use is_relative_to() because that's added in Python 3.9,
2037
- # but we support down to Python 3.7.
2045
+ # but we support down to Python 3.8.
2038
2046
  if not str(glob_path).startswith(str(base_path)):
2039
2047
  raise ValueError("Glob may not walk above the base path")
2040
2048
 
@@ -2078,12 +2086,7 @@ class Run:
2078
2086
  target_path.parent.mkdir(parents=True, exist_ok=True)
2079
2087
 
2080
2088
  # Delete the symlink if it exists.
2081
- try:
2082
- target_path.unlink()
2083
- except FileNotFoundError:
2084
- # In Python 3.8, we would pass missing_ok=True, but as of now
2085
- # we support down to Python 3.7.
2086
- pass
2089
+ target_path.unlink(missing_ok=True)
2087
2090
 
2088
2091
  target_path.symlink_to(source_path)
2089
2092
 
@@ -2128,15 +2131,26 @@ class Run:
2128
2131
 
2129
2132
  @_run_decorator._noop
2130
2133
  @_run_decorator._attach
2131
- def finish(self, exit_code: int | None = None, quiet: bool | None = None) -> None:
2132
- """Mark a run as finished, and finish uploading all data.
2134
+ def finish(
2135
+ self,
2136
+ exit_code: int | None = None,
2137
+ quiet: bool | None = None,
2138
+ ) -> None:
2139
+ """Finish a run and upload any remaining data.
2133
2140
 
2134
- This is used when creating multiple runs in the same process. We automatically
2135
- call this method when your script exits or if you use the run context manager.
2141
+ Marks the completion of a W&B run and ensures all data is synced to the server.
2142
+ The run's final state is determined by its exit conditions and sync status.
2143
+
2144
+ Run States:
2145
+ - Running: Active run that is logging data and/or sending heartbeats.
2146
+ - Crashed: Run that stopped sending heartbeats unexpectedly.
2147
+ - Finished: Run completed successfully (`exit_code=0`) with all data synced.
2148
+ - Failed: Run completed with errors (`exit_code!=0`).
2136
2149
 
2137
2150
  Args:
2138
- exit_code: Set to something other than 0 to mark a run as failed
2139
- quiet: Deprecated, use `wandb.Settings(quiet=...)` to set this instead.
2151
+ exit_code: Integer indicating the run's exit status. Use 0 for success,
2152
+ any other value marks the run as failed.
2153
+ quiet: Deprecated. Configure logging verbosity using `wandb.Settings(quiet=...)`.
2140
2154
  """
2141
2155
  if quiet is not None:
2142
2156
  deprecate.deprecate(
@@ -2189,7 +2203,7 @@ class Run:
2189
2203
  #
2190
2204
  # TODO: Why not do this in _atexit_cleanup()?
2191
2205
  service = self._wl and self._wl.service
2192
- if service:
2206
+ if service and self._run_id:
2193
2207
  service.inform_finish(run_id=self._run_id)
2194
2208
 
2195
2209
  finally:
@@ -2234,31 +2248,6 @@ class Run:
2234
2248
  sync_time=sync_time,
2235
2249
  )
2236
2250
 
2237
- @staticmethod
2238
- def plot_table(
2239
- vega_spec_name: str,
2240
- data_table: Table,
2241
- fields: dict[str, Any],
2242
- string_fields: dict[str, Any] | None = None,
2243
- split_table: bool = False,
2244
- ) -> CustomChart:
2245
- """Create a custom plot on a table.
2246
-
2247
- Args:
2248
- vega_spec_name: the name of the spec for the plot
2249
- data_table: a wandb.Table object containing the data to
2250
- be used on the visualization
2251
- fields: a dict mapping from table keys to fields that the custom
2252
- visualization needs
2253
- string_fields: a dict that provides values for any string constants
2254
- the custom visualization needs
2255
- split_table: a boolean that indicates whether the table should be in
2256
- a separate section in the UI
2257
- """
2258
- return plot_table(
2259
- vega_spec_name, data_table, fields, string_fields or {}, split_table
2260
- )
2261
-
2262
2251
  def _add_panel(
2263
2252
  self, visualize_key: str, panel_type: str, panel_config: dict
2264
2253
  ) -> None:
@@ -2278,7 +2267,6 @@ class Run:
2278
2267
  use_artifact=self.use_artifact,
2279
2268
  log_artifact=self.log_artifact,
2280
2269
  define_metric=self.define_metric,
2281
- plot_table=self.plot_table,
2282
2270
  alert=self.alert,
2283
2271
  watch=self.watch,
2284
2272
  unwatch=self.unwatch,
@@ -2298,7 +2286,7 @@ class Run:
2298
2286
  console = self._settings.console
2299
2287
  # only use raw for service to minimize potential changes
2300
2288
  if console == "wrap":
2301
- if not self._settings._disable_service:
2289
+ if not self._settings.x_disable_service:
2302
2290
  console = "wrap_raw"
2303
2291
  else:
2304
2292
  console = "wrap_emu"
@@ -2447,7 +2435,6 @@ class Run:
2447
2435
  final_summary=self._final_summary,
2448
2436
  poll_exit_response=self._poll_exit_response,
2449
2437
  internal_messages_response=self._internal_messages_response,
2450
- reporter=self._reporter,
2451
2438
  settings=self._settings,
2452
2439
  printer=self._printer,
2453
2440
  )
@@ -2486,7 +2473,7 @@ class Run:
2486
2473
  if self._settings.save_code and self._settings.code_dir is not None:
2487
2474
  self.log_code(self._settings.code_dir)
2488
2475
 
2489
- if self._settings._save_requirements:
2476
+ if self._settings.x_save_requirements:
2490
2477
  if self._backend and self._backend.interface:
2491
2478
  from wandb.util import working_set
2492
2479
 
@@ -2530,6 +2517,8 @@ class Run:
2530
2517
 
2531
2518
  import_telemetry_set = telemetry.list_telemetry_imports()
2532
2519
  import_hook_fn = functools.partial(_telemetry_import_hook, self)
2520
+ if not self._run_id:
2521
+ return
2533
2522
  for module_name in import_telemetry_set:
2534
2523
  register_post_import_hook(
2535
2524
  import_hook_fn,
@@ -2670,7 +2659,11 @@ class Run:
2670
2659
 
2671
2660
  assert self._backend and self._backend.interface
2672
2661
 
2673
- exit_handle = self._backend.interface.deliver_exit(self._exit_code)
2662
+ if self._settings.x_update_finish_state:
2663
+ exit_handle = self._backend.interface.deliver_exit(self._exit_code)
2664
+ else:
2665
+ exit_handle = self._backend.interface.deliver_finish_without_exit()
2666
+
2674
2667
  exit_handle.add_probe(on_probe=self._on_probe_exit)
2675
2668
 
2676
2669
  with progress.progress_printer(
@@ -2722,7 +2715,8 @@ class Run:
2722
2715
  if self._run_status_checker:
2723
2716
  self._run_status_checker.join()
2724
2717
 
2725
- self._unregister_telemetry_import_hooks(self._run_id)
2718
+ if self._run_id:
2719
+ self._unregister_telemetry_import_hooks(self._run_id)
2726
2720
 
2727
2721
  @staticmethod
2728
2722
  def _unregister_telemetry_import_hooks(run_id: str) -> None:
@@ -2875,7 +2869,7 @@ class Run:
2875
2869
  def watch(
2876
2870
  self,
2877
2871
  models: torch.nn.Module | Sequence[torch.nn.Module],
2878
- criterion: torch.F | None = None,
2872
+ criterion: torch.F | None = None, # type: ignore
2879
2873
  log: Literal["gradients", "parameters", "all"] | None = "gradients",
2880
2874
  log_freq: int = 1000,
2881
2875
  idx: int | None = None,
@@ -3355,7 +3349,7 @@ class Run:
3355
3349
  return artifact
3356
3350
 
3357
3351
  def _public_api(self, overrides: dict[str, str] | None = None) -> PublicApi:
3358
- overrides = {"run": self._run_id}
3352
+ overrides = {"run": self._run_id} # type: ignore
3359
3353
  if not (self._settings._offline or self._run_obj is None):
3360
3354
  overrides["entity"] = self._run_obj.entity
3361
3355
  overrides["project"] = self._run_obj.project
@@ -3693,9 +3687,10 @@ class Run:
3693
3687
  Returns:
3694
3688
  A dictionary of system metrics.
3695
3689
  """
3690
+ from wandb.proto import wandb_internal_pb2
3696
3691
 
3697
3692
  def pb_to_dict(
3698
- system_metrics_pb: wandb.proto.wandb_internal_pb2.GetSystemMetricsResponse,
3693
+ system_metrics_pb: wandb_internal_pb2.GetSystemMetricsResponse,
3699
3694
  ) -> dict[str, list[tuple[datetime, float]]]:
3700
3695
  res = {}
3701
3696
 
@@ -3857,7 +3852,6 @@ class Run:
3857
3852
  final_summary: GetSummaryResponse | None = None,
3858
3853
  poll_exit_response: PollExitResponse | None = None,
3859
3854
  internal_messages_response: InternalMessagesResponse | None = None,
3860
- reporter: Reporter | None = None,
3861
3855
  *,
3862
3856
  settings: Settings,
3863
3857
  printer: printer.Printer,
@@ -3884,9 +3878,6 @@ class Run:
3884
3878
  settings=settings,
3885
3879
  printer=printer,
3886
3880
  )
3887
- Run._footer_reporter_warn_err(
3888
- reporter=reporter, settings=settings, printer=printer
3889
- )
3890
3881
 
3891
3882
  @staticmethod
3892
3883
  def _footer_sync_info(
@@ -4035,7 +4026,7 @@ class Run:
4035
4026
  printer: printer.Printer,
4036
4027
  ) -> None:
4037
4028
  """Prints a message advertising the upcoming core release."""
4038
- if settings.quiet or not settings._require_legacy_service:
4029
+ if settings.quiet or not settings.x_require_legacy_service:
4039
4030
  return
4040
4031
 
4041
4032
  printer.display(
@@ -4045,33 +4036,6 @@ class Run:
4045
4036
  level="warn",
4046
4037
  )
4047
4038
 
4048
- @staticmethod
4049
- def _footer_reporter_warn_err(
4050
- reporter: Reporter | None = None,
4051
- *,
4052
- settings: Settings,
4053
- printer: printer.Printer,
4054
- ) -> None:
4055
- if settings.quiet or settings.silent:
4056
- return
4057
-
4058
- if not reporter:
4059
- return
4060
-
4061
- warning_lines = reporter.warning_lines
4062
- if warning_lines:
4063
- warnings = ["Warnings:"] + [f"{line}" for line in warning_lines]
4064
- if len(warning_lines) < reporter.warning_count:
4065
- warnings.append("More warnings...")
4066
- printer.display(warnings)
4067
-
4068
- error_lines = reporter.error_lines
4069
- if error_lines:
4070
- errors = ["Errors:"] + [f"{line}" for line in error_lines]
4071
- if len(error_lines) < reporter.error_count:
4072
- errors.append("More errors...")
4073
- printer.display(errors)
4074
-
4075
4039
 
4076
4040
  # We define this outside of the run context to support restoring before init
4077
4041
  def restore(
@@ -4137,15 +4101,25 @@ except AttributeError:
4137
4101
  pass
4138
4102
 
4139
4103
 
4140
- def finish(exit_code: int | None = None, quiet: bool | None = None) -> None:
4141
- """Mark a run as finished, and finish uploading all data.
4104
+ def finish(
4105
+ exit_code: int | None = None,
4106
+ quiet: bool | None = None,
4107
+ ) -> None:
4108
+ """Finish a run and upload any remaining data.
4109
+
4110
+ Marks the completion of a W&B run and ensures all data is synced to the server.
4111
+ The run's final state is determined by its exit conditions and sync status.
4142
4112
 
4143
- This is used when creating multiple runs in the same process.
4144
- We automatically call this method when your script exits.
4113
+ Run States:
4114
+ - Running: Active run that is logging data and/or sending heartbeats.
4115
+ - Crashed: Run that stopped sending heartbeats unexpectedly.
4116
+ - Finished: Run completed successfully (`exit_code=0`) with all data synced.
4117
+ - Failed: Run completed with errors (`exit_code!=0`).
4145
4118
 
4146
4119
  Args:
4147
- exit_code: Set to something other than 0 to mark a run as failed
4148
- quiet: Deprecated, use `wandb.Settings(quiet=...)` to set this instead.
4120
+ exit_code: Integer indicating the run's exit status. Use 0 for success,
4121
+ any other value marks the run as failed.
4122
+ quiet: Deprecated. Configure logging verbosity using `wandb.Settings(quiet=...)`.
4149
4123
  """
4150
4124
  if wandb.run:
4151
4125
  wandb.run.finish(exit_code=exit_code, quiet=quiet)