wandb 0.19.7__py3-none-macosx_11_0_arm64.whl → 0.19.9__py3-none-macosx_11_0_arm64.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 (91) hide show
  1. wandb/__init__.py +5 -1
  2. wandb/__init__.pyi +43 -9
  3. wandb/_pydantic/__init__.py +23 -0
  4. wandb/_pydantic/base.py +113 -0
  5. wandb/_pydantic/v1_compat.py +262 -0
  6. wandb/apis/paginator.py +82 -38
  7. wandb/apis/public/api.py +10 -64
  8. wandb/apis/public/artifacts.py +73 -17
  9. wandb/apis/public/files.py +2 -2
  10. wandb/apis/public/projects.py +3 -2
  11. wandb/apis/public/reports.py +2 -2
  12. wandb/apis/public/runs.py +19 -11
  13. wandb/bin/gpu_stats +0 -0
  14. wandb/bin/wandb-core +0 -0
  15. wandb/data_types.py +1 -1
  16. wandb/filesync/dir_watcher.py +2 -1
  17. wandb/integration/metaflow/metaflow.py +19 -17
  18. wandb/integration/sacred/__init__.py +1 -1
  19. wandb/jupyter.py +18 -15
  20. wandb/proto/v3/wandb_internal_pb2.py +7 -3
  21. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  22. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  23. wandb/proto/v4/wandb_internal_pb2.py +3 -3
  24. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  25. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  26. wandb/proto/v5/wandb_internal_pb2.py +3 -3
  27. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  28. wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
  29. wandb/proto/wandb_deprecated.py +2 -0
  30. wandb/sdk/artifacts/_graphql_fragments.py +18 -20
  31. wandb/sdk/artifacts/_validators.py +1 -0
  32. wandb/sdk/artifacts/artifact.py +81 -46
  33. wandb/sdk/artifacts/artifact_saver.py +16 -2
  34. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +23 -2
  35. wandb/sdk/backend/backend.py +16 -5
  36. wandb/sdk/data_types/audio.py +1 -3
  37. wandb/sdk/data_types/base_types/media.py +11 -4
  38. wandb/sdk/data_types/image.py +44 -25
  39. wandb/sdk/data_types/molecule.py +1 -5
  40. wandb/sdk/data_types/object_3d.py +2 -1
  41. wandb/sdk/data_types/saved_model.py +7 -9
  42. wandb/sdk/data_types/video.py +1 -4
  43. wandb/sdk/interface/interface.py +65 -43
  44. wandb/sdk/interface/interface_queue.py +0 -7
  45. wandb/sdk/interface/interface_relay.py +6 -16
  46. wandb/sdk/interface/interface_shared.py +47 -40
  47. wandb/sdk/interface/interface_sock.py +1 -8
  48. wandb/sdk/interface/router.py +22 -54
  49. wandb/sdk/interface/router_queue.py +11 -10
  50. wandb/sdk/interface/router_relay.py +24 -12
  51. wandb/sdk/interface/router_sock.py +6 -11
  52. wandb/{apis/public → sdk/internal}/_generated/__init__.py +0 -6
  53. wandb/sdk/internal/_generated/base.py +226 -0
  54. wandb/{apis/public → sdk/internal}/_generated/server_features_query.py +3 -3
  55. wandb/{apis/public → sdk/internal}/_generated/typing_compat.py +1 -1
  56. wandb/sdk/internal/internal_api.py +138 -47
  57. wandb/sdk/internal/sender.py +5 -1
  58. wandb/sdk/internal/sender_config.py +8 -11
  59. wandb/sdk/internal/settings_static.py +24 -2
  60. wandb/sdk/lib/apikey.py +15 -16
  61. wandb/sdk/lib/console_capture.py +172 -0
  62. wandb/sdk/lib/redirect.py +102 -76
  63. wandb/sdk/lib/run_moment.py +4 -6
  64. wandb/sdk/lib/service_connection.py +37 -17
  65. wandb/sdk/lib/sock_client.py +2 -52
  66. wandb/sdk/lib/wb_logging.py +161 -0
  67. wandb/sdk/mailbox/__init__.py +3 -3
  68. wandb/sdk/mailbox/mailbox.py +31 -17
  69. wandb/sdk/mailbox/mailbox_handle.py +127 -0
  70. wandb/sdk/mailbox/{handles.py → response_handle.py} +34 -66
  71. wandb/sdk/mailbox/wait_with_progress.py +16 -15
  72. wandb/sdk/service/server_sock.py +4 -2
  73. wandb/sdk/service/streams.py +10 -5
  74. wandb/sdk/wandb_config.py +44 -43
  75. wandb/sdk/wandb_init.py +151 -92
  76. wandb/sdk/wandb_metadata.py +107 -91
  77. wandb/sdk/wandb_run.py +160 -54
  78. wandb/sdk/wandb_settings.py +410 -202
  79. wandb/sdk/wandb_setup.py +3 -1
  80. wandb/sdk/wandb_sync.py +1 -7
  81. {wandb-0.19.7.dist-info → wandb-0.19.9.dist-info}/METADATA +3 -3
  82. {wandb-0.19.7.dist-info → wandb-0.19.9.dist-info}/RECORD +88 -84
  83. wandb/apis/public/_generated/base.py +0 -128
  84. wandb/sdk/interface/message_future.py +0 -27
  85. wandb/sdk/interface/message_future_poll.py +0 -50
  86. /wandb/{apis/public → sdk/internal}/_generated/enums.py +0 -0
  87. /wandb/{apis/public → sdk/internal}/_generated/input_types.py +0 -0
  88. /wandb/{apis/public → sdk/internal}/_generated/operations.py +0 -0
  89. {wandb-0.19.7.dist-info → wandb-0.19.9.dist-info}/WHEEL +0 -0
  90. {wandb-0.19.7.dist-info → wandb-0.19.9.dist-info}/entry_points.txt +0 -0
  91. {wandb-0.19.7.dist-info → wandb-0.19.9.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_run.py CHANGED
@@ -44,7 +44,7 @@ from wandb.proto.wandb_internal_pb2 import (
44
44
  )
45
45
  from wandb.sdk.artifacts.artifact import Artifact
46
46
  from wandb.sdk.internal import job_builder
47
- from wandb.sdk.lib import asyncio_compat
47
+ from wandb.sdk.lib import asyncio_compat, wb_logging
48
48
  from wandb.sdk.lib.import_hooks import (
49
49
  register_post_import_hook,
50
50
  unregister_post_import_hook,
@@ -62,6 +62,7 @@ from wandb.util import (
62
62
 
63
63
  from . import wandb_config, wandb_metric, wandb_summary
64
64
  from .artifacts._validators import (
65
+ MAX_ARTIFACT_METADATA_KEYS,
65
66
  is_artifact_registry_project,
66
67
  validate_aliases,
67
68
  validate_tags,
@@ -157,19 +158,21 @@ class RunStatusChecker:
157
158
  """
158
159
 
159
160
  _stop_status_lock: threading.Lock
160
- _stop_status_handle: MailboxHandle | None
161
+ _stop_status_handle: MailboxHandle[Result] | None
161
162
  _network_status_lock: threading.Lock
162
- _network_status_handle: MailboxHandle | None
163
+ _network_status_handle: MailboxHandle[Result] | None
163
164
  _internal_messages_lock: threading.Lock
164
- _internal_messages_handle: MailboxHandle | None
165
+ _internal_messages_handle: MailboxHandle[Result] | None
165
166
 
166
167
  def __init__(
167
168
  self,
169
+ run_id: str,
168
170
  interface: InterfaceBase,
169
171
  stop_polling_interval: int = 15,
170
172
  retry_polling_interval: int = 5,
171
173
  internal_messages_polling_interval: int = 10,
172
174
  ) -> None:
175
+ self._run_id = run_id
173
176
  self._interface = interface
174
177
  self._stop_polling_interval = stop_polling_interval
175
178
  self._retry_polling_interval = retry_polling_interval
@@ -209,7 +212,7 @@ class RunStatusChecker:
209
212
  @staticmethod
210
213
  def _abandon_status_check(
211
214
  lock: threading.Lock,
212
- handle: MailboxHandle | None,
215
+ handle: MailboxHandle[Result] | None,
213
216
  ):
214
217
  with lock:
215
218
  if handle:
@@ -224,7 +227,7 @@ class RunStatusChecker:
224
227
  request: Any,
225
228
  process: Any,
226
229
  ) -> None:
227
- local_handle: MailboxHandle | None = None
230
+ local_handle: MailboxHandle[Result] | None = None
228
231
  join_requested = False
229
232
  while not join_requested:
230
233
  time_probe = time.monotonic()
@@ -275,19 +278,20 @@ class RunStatusChecker:
275
278
  )
276
279
  )
277
280
 
278
- try:
279
- self._loop_check_status(
280
- lock=self._network_status_lock,
281
- set_handle=lambda x: setattr(self, "_network_status_handle", x),
282
- timeout=self._retry_polling_interval,
283
- request=self._interface.deliver_network_status,
284
- process=_process_network_status,
285
- )
286
- except BrokenPipeError:
287
- self._abandon_status_check(
288
- self._network_status_lock,
289
- self._network_status_handle,
290
- )
281
+ with wb_logging.log_to_run(self._run_id):
282
+ try:
283
+ self._loop_check_status(
284
+ lock=self._network_status_lock,
285
+ set_handle=lambda x: setattr(self, "_network_status_handle", x),
286
+ timeout=self._retry_polling_interval,
287
+ request=self._interface.deliver_network_status,
288
+ process=_process_network_status,
289
+ )
290
+ except BrokenPipeError:
291
+ self._abandon_status_check(
292
+ self._network_status_lock,
293
+ self._network_status_handle,
294
+ )
291
295
 
292
296
  def check_stop_status(self) -> None:
293
297
  def _process_stop_status(result: Result) -> None:
@@ -299,19 +303,20 @@ class RunStatusChecker:
299
303
  interrupt.interrupt_main()
300
304
  return
301
305
 
302
- try:
303
- self._loop_check_status(
304
- lock=self._stop_status_lock,
305
- set_handle=lambda x: setattr(self, "_stop_status_handle", x),
306
- timeout=self._stop_polling_interval,
307
- request=self._interface.deliver_stop_status,
308
- process=_process_stop_status,
309
- )
310
- except BrokenPipeError:
311
- self._abandon_status_check(
312
- self._stop_status_lock,
313
- self._stop_status_handle,
314
- )
306
+ with wb_logging.log_to_run(self._run_id):
307
+ try:
308
+ self._loop_check_status(
309
+ lock=self._stop_status_lock,
310
+ set_handle=lambda x: setattr(self, "_stop_status_handle", x),
311
+ timeout=self._stop_polling_interval,
312
+ request=self._interface.deliver_stop_status,
313
+ process=_process_stop_status,
314
+ )
315
+ except BrokenPipeError:
316
+ self._abandon_status_check(
317
+ self._stop_status_lock,
318
+ self._stop_status_handle,
319
+ )
315
320
 
316
321
  def check_internal_messages(self) -> None:
317
322
  def _process_internal_messages(result: Result) -> None:
@@ -319,19 +324,20 @@ class RunStatusChecker:
319
324
  for msg in internal_messages.messages.warning:
320
325
  wandb.termwarn(msg)
321
326
 
322
- try:
323
- self._loop_check_status(
324
- lock=self._internal_messages_lock,
325
- set_handle=lambda x: setattr(self, "_internal_messages_handle", x),
326
- timeout=self._internal_messages_polling_interval,
327
- request=self._interface.deliver_internal_messages,
328
- process=_process_internal_messages,
329
- )
330
- except BrokenPipeError:
331
- self._abandon_status_check(
332
- self._internal_messages_lock,
333
- self._internal_messages_handle,
334
- )
327
+ with wb_logging.log_to_run(self._run_id):
328
+ try:
329
+ self._loop_check_status(
330
+ lock=self._internal_messages_lock,
331
+ set_handle=lambda x: setattr(self, "_internal_messages_handle", x),
332
+ timeout=self._internal_messages_polling_interval,
333
+ request=self._interface.deliver_internal_messages,
334
+ process=_process_internal_messages,
335
+ )
336
+ except BrokenPipeError:
337
+ self._abandon_status_check(
338
+ self._internal_messages_lock,
339
+ self._internal_messages_handle,
340
+ )
335
341
 
336
342
  def stop(self) -> None:
337
343
  self._join_event.set()
@@ -355,6 +361,34 @@ class RunStatusChecker:
355
361
  self._internal_messages_thread.join()
356
362
 
357
363
 
364
+ def _log_to_run(func: Callable) -> Callable:
365
+ """Decorate a Run method to set the run ID in the logging context.
366
+
367
+ Any logs during the execution of the method go to the run's log file
368
+ and not to other runs' log files.
369
+
370
+ This is meant for use on all public methods and some callbacks. Private
371
+ methods can be assumed to be called from some public method somewhere.
372
+ The general rule is to use it on methods that can be called from a
373
+ context that isn't specific to this run (such as all user code or
374
+ internal methods that aren't run-specific).
375
+ """
376
+
377
+ @functools.wraps(func)
378
+ def wrapper(self: Run, *args, **kwargs) -> Any:
379
+ # In "attach" usage, many properties of the Run are not initially
380
+ # populated.
381
+ if hasattr(self, "_settings"):
382
+ run_id = self._settings.run_id
383
+ else:
384
+ run_id = self._attach_id
385
+
386
+ with wb_logging.log_to_run(run_id):
387
+ return func(self, *args, **kwargs)
388
+
389
+ return wrapper
390
+
391
+
358
392
  class _run_decorator: # noqa: N801
359
393
  _is_attaching: str = ""
360
394
 
@@ -542,7 +576,7 @@ class Run:
542
576
 
543
577
  _sampled_history: SampledHistoryResponse | None
544
578
  _final_summary: GetSummaryResponse | None
545
- _poll_exit_handle: MailboxHandle | None
579
+ _poll_exit_handle: MailboxHandle[Result] | None
546
580
  _poll_exit_response: PollExitResponse | None
547
581
  _internal_messages_response: InternalMessagesResponse | None
548
582
 
@@ -811,29 +845,34 @@ class Run:
811
845
  return self._torch_history
812
846
 
813
847
  @property
848
+ @_log_to_run
814
849
  @_run_decorator._attach
815
850
  def settings(self) -> Settings:
816
851
  """A frozen copy of run's Settings object."""
817
852
  return self._settings.model_copy(deep=True)
818
853
 
819
854
  @property
855
+ @_log_to_run
820
856
  @_run_decorator._attach
821
857
  def dir(self) -> str:
822
858
  """The directory where files associated with the run are saved."""
823
859
  return self._settings.files_dir
824
860
 
825
861
  @property
862
+ @_log_to_run
826
863
  @_run_decorator._attach
827
864
  def config(self) -> wandb_config.Config:
828
865
  """Config object associated with this run."""
829
866
  return self._config
830
867
 
831
868
  @property
869
+ @_log_to_run
832
870
  @_run_decorator._attach
833
871
  def config_static(self) -> wandb_config.ConfigStatic:
834
872
  return wandb_config.ConfigStatic(self._config)
835
873
 
836
874
  @property
875
+ @_log_to_run
837
876
  @_run_decorator._attach
838
877
  def name(self) -> str | None:
839
878
  """Display name of the run.
@@ -846,6 +885,7 @@ class Run:
846
885
  return None
847
886
 
848
887
  @name.setter
888
+ @_log_to_run
849
889
  @_run_decorator._noop_on_finish()
850
890
  def name(self, name: str) -> None:
851
891
  with telemetry.context(run=self) as tel:
@@ -855,6 +895,7 @@ class Run:
855
895
  self._backend.interface.publish_run(self)
856
896
 
857
897
  @property
898
+ @_log_to_run
858
899
  @_run_decorator._attach
859
900
  def notes(self) -> str | None:
860
901
  """Notes associated with the run, if there are any.
@@ -865,6 +906,7 @@ class Run:
865
906
  return self._settings.run_notes
866
907
 
867
908
  @notes.setter
909
+ @_log_to_run
868
910
  @_run_decorator._noop_on_finish()
869
911
  def notes(self, notes: str) -> None:
870
912
  self._settings.run_notes = notes
@@ -872,12 +914,14 @@ class Run:
872
914
  self._backend.interface.publish_run(self)
873
915
 
874
916
  @property
917
+ @_log_to_run
875
918
  @_run_decorator._attach
876
919
  def tags(self) -> tuple | None:
877
920
  """Tags associated with the run, if there are any."""
878
921
  return self._settings.run_tags or ()
879
922
 
880
923
  @tags.setter
924
+ @_log_to_run
881
925
  @_run_decorator._noop_on_finish()
882
926
  def tags(self, tags: Sequence) -> None:
883
927
  with telemetry.context(run=self) as tel:
@@ -887,6 +931,7 @@ class Run:
887
931
  self._backend.interface.publish_run(self)
888
932
 
889
933
  @property
934
+ @_log_to_run
890
935
  @_run_decorator._attach
891
936
  def id(self) -> str:
892
937
  """Identifier for this run."""
@@ -895,6 +940,7 @@ class Run:
895
940
  return self._settings.run_id
896
941
 
897
942
  @property
943
+ @_log_to_run
898
944
  @_run_decorator._attach
899
945
  def sweep_id(self) -> str | None:
900
946
  """ID of the sweep associated with the run, if there is one."""
@@ -912,6 +958,7 @@ class Run:
912
958
  )
913
959
 
914
960
  @property
961
+ @_log_to_run
915
962
  @_run_decorator._attach
916
963
  def path(self) -> str:
917
964
  """Path to the run.
@@ -922,24 +969,28 @@ class Run:
922
969
  return self._get_path()
923
970
 
924
971
  @property
972
+ @_log_to_run
925
973
  @_run_decorator._attach
926
974
  def start_time(self) -> float:
927
975
  """Unix timestamp (in seconds) of when the run started."""
928
976
  return self._start_time
929
977
 
930
978
  @property
979
+ @_log_to_run
931
980
  @_run_decorator._attach
932
981
  def starting_step(self) -> int:
933
982
  """The first step of the run."""
934
983
  return self._starting_step
935
984
 
936
985
  @property
986
+ @_log_to_run
937
987
  @_run_decorator._attach
938
988
  def resumed(self) -> bool:
939
989
  """True if the run was resumed, False otherwise."""
940
990
  return self._settings.resumed
941
991
 
942
992
  @property
993
+ @_log_to_run
943
994
  @_run_decorator._attach
944
995
  def step(self) -> int:
945
996
  """Current value of the step.
@@ -949,6 +1000,7 @@ class Run:
949
1000
  return self._step
950
1001
 
951
1002
  @property
1003
+ @_log_to_run
952
1004
  @_run_decorator._attach
953
1005
  def mode(self) -> str:
954
1006
  """For compatibility with `0.9.x` and earlier, deprecate eventually."""
@@ -963,16 +1015,19 @@ class Run:
963
1015
  return "dryrun" if self._settings._offline else "run"
964
1016
 
965
1017
  @property
1018
+ @_log_to_run
966
1019
  @_run_decorator._attach
967
1020
  def offline(self) -> bool:
968
1021
  return self._settings._offline
969
1022
 
970
1023
  @property
1024
+ @_log_to_run
971
1025
  @_run_decorator._attach
972
1026
  def disabled(self) -> bool:
973
1027
  return self._settings._noop
974
1028
 
975
1029
  @property
1030
+ @_log_to_run
976
1031
  @_run_decorator._attach
977
1032
  def group(self) -> str:
978
1033
  """Name of the group associated with the run.
@@ -987,6 +1042,7 @@ class Run:
987
1042
  return self._settings.run_group or ""
988
1043
 
989
1044
  @property
1045
+ @_log_to_run
990
1046
  @_run_decorator._attach
991
1047
  def job_type(self) -> str:
992
1048
  return self._settings.run_job_type or ""
@@ -996,12 +1052,14 @@ class Run:
996
1052
  return self._settings.project or ""
997
1053
 
998
1054
  @property
1055
+ @_log_to_run
999
1056
  @_run_decorator._attach
1000
1057
  def project(self) -> str:
1001
1058
  """Name of the W&B project associated with the run."""
1002
1059
  return self.project_name()
1003
1060
 
1004
1061
  @_run_decorator._noop_on_finish()
1062
+ @_log_to_run
1005
1063
  @_run_decorator._attach
1006
1064
  def log_code(
1007
1065
  self,
@@ -1088,6 +1146,7 @@ class Run:
1088
1146
 
1089
1147
  return self._log_artifact(art)
1090
1148
 
1149
+ @_log_to_run
1091
1150
  def get_project_url(self) -> str | None:
1092
1151
  """Return the url for the W&B project associated with the run, if there is one.
1093
1152
 
@@ -1098,6 +1157,7 @@ class Run:
1098
1157
  return None
1099
1158
  return self._settings.project_url
1100
1159
 
1160
+ @_log_to_run
1101
1161
  def get_sweep_url(self) -> str | None:
1102
1162
  """Return the url for the sweep associated with the run, if there is one."""
1103
1163
  if self._settings._offline:
@@ -1105,6 +1165,7 @@ class Run:
1105
1165
  return None
1106
1166
  return self._settings.sweep_url
1107
1167
 
1168
+ @_log_to_run
1108
1169
  def get_url(self) -> str | None:
1109
1170
  """Return the url for the W&B run, if there is one.
1110
1171
 
@@ -1116,12 +1177,14 @@ class Run:
1116
1177
  return self._settings.run_url
1117
1178
 
1118
1179
  @property
1180
+ @_log_to_run
1119
1181
  @_run_decorator._attach
1120
1182
  def url(self) -> str | None:
1121
1183
  """The W&B url associated with the run."""
1122
1184
  return self.get_url()
1123
1185
 
1124
1186
  @property
1187
+ @_log_to_run
1125
1188
  @_run_decorator._attach
1126
1189
  def entity(self) -> str:
1127
1190
  """The name of the W&B entity associated with the run.
@@ -1216,6 +1279,7 @@ class Run:
1216
1279
  if lines:
1217
1280
  self._label_probe_lines(lines)
1218
1281
 
1282
+ @_log_to_run
1219
1283
  @_run_decorator._attach
1220
1284
  def display(self, height: int = 420, hidden: bool = False) -> bool:
1221
1285
  """Display this run in jupyter."""
@@ -1235,6 +1299,7 @@ class Run:
1235
1299
  wandb.termwarn(".display() only works in jupyter environments")
1236
1300
  return False
1237
1301
 
1302
+ @_log_to_run
1238
1303
  @_run_decorator._attach
1239
1304
  def to_html(self, height: int = 420, hidden: bool = False) -> str:
1240
1305
  """Generate HTML containing an iframe displaying the current run."""
@@ -1251,6 +1316,7 @@ class Run:
1251
1316
  ) -> dict[str, str]:
1252
1317
  return {"text/html": self.to_html(hidden=True)}
1253
1318
 
1319
+ @_log_to_run
1254
1320
  @_run_decorator._noop_on_finish()
1255
1321
  def _config_callback(
1256
1322
  self,
@@ -1262,6 +1328,7 @@ class Run:
1262
1328
  if self._backend and self._backend.interface:
1263
1329
  self._backend.interface.publish_config(key=key, val=val, data=data)
1264
1330
 
1331
+ @_log_to_run
1265
1332
  def _config_artifact_callback(
1266
1333
  self, key: str, val: str | Artifact | dict
1267
1334
  ) -> Artifact:
@@ -1301,6 +1368,7 @@ class Run:
1301
1368
  def _set_config_wandb(self, key: str, val: Any) -> None:
1302
1369
  self._config_callback(key=("_wandb", key), val=val)
1303
1370
 
1371
+ @_log_to_run
1304
1372
  @_run_decorator._noop_on_finish()
1305
1373
  def _summary_update_callback(self, summary_record: SummaryRecord) -> None:
1306
1374
  with telemetry.context(run=self) as tel:
@@ -1308,6 +1376,7 @@ class Run:
1308
1376
  if self._backend and self._backend.interface:
1309
1377
  self._backend.interface.publish_summary(self, summary_record)
1310
1378
 
1379
+ @_log_to_run
1311
1380
  def _summary_get_current_summary_callback(self) -> dict[str, Any]:
1312
1381
  if self._is_finished:
1313
1382
  # TODO: WB-18420: fetch summary from backend and stage it before run is finished
@@ -1325,14 +1394,16 @@ class Run:
1325
1394
  get_summary_response = result.response.get_summary_response
1326
1395
  return proto_util.dict_from_proto_list(get_summary_response.item)
1327
1396
 
1397
+ @_log_to_run
1328
1398
  def _metric_callback(self, metric_record: MetricRecord) -> None:
1329
1399
  if self._backend and self._backend.interface:
1330
1400
  self._backend.interface._publish_metric(metric_record)
1331
1401
 
1402
+ @_log_to_run
1332
1403
  def _datatypes_callback(self, fname: str) -> None:
1333
1404
  if not self._backend or not self._backend.interface:
1334
1405
  return
1335
- files: FilesDict = dict(files=[(GlobStr(glob.escape(fname)), "now")])
1406
+ files: FilesDict = dict(files=[(GlobStr(fname), "now")])
1336
1407
  self._backend.interface.publish_files(files)
1337
1408
 
1338
1409
  def _pop_all_charts(
@@ -1399,6 +1470,7 @@ class Run:
1399
1470
 
1400
1471
  return data
1401
1472
 
1473
+ @_log_to_run
1402
1474
  def _partial_history_callback(
1403
1475
  self,
1404
1476
  data: dict[str, Any],
@@ -1423,11 +1495,13 @@ class Run:
1423
1495
  publish_step=not_using_tensorboard,
1424
1496
  )
1425
1497
 
1498
+ @_log_to_run
1426
1499
  def _console_callback(self, name: str, data: str) -> None:
1427
1500
  # logger.info("console callback: %s, %s", name, data)
1428
1501
  if self._backend and self._backend.interface:
1429
1502
  self._backend.interface.publish_output(name, data)
1430
1503
 
1504
+ @_log_to_run
1431
1505
  @_run_decorator._noop_on_finish(only_warn=True)
1432
1506
  def _console_raw_callback(self, name: str, data: str) -> None:
1433
1507
  # logger.info("console callback: %s, %s", name, data)
@@ -1443,6 +1517,7 @@ class Run:
1443
1517
  if self._backend and self._backend.interface:
1444
1518
  self._backend.interface.publish_output_raw(name, data)
1445
1519
 
1520
+ @_log_to_run
1446
1521
  def _tensorboard_callback(
1447
1522
  self, logdir: str, save: bool = True, root_logdir: str = ""
1448
1523
  ) -> None:
@@ -1476,9 +1551,6 @@ class Run:
1476
1551
  # Grab the config from resuming
1477
1552
  if run_obj.config:
1478
1553
  c_dict = config_util.dict_no_value_from_proto_list(run_obj.config.update)
1479
- # TODO: Windows throws a wild error when this is set...
1480
- if "_wandb" in c_dict:
1481
- del c_dict["_wandb"]
1482
1554
  # We update the config object here without triggering the callback
1483
1555
  self._config._update(c_dict, allow_val_change=True, ignore_locked=True)
1484
1556
  # Update the summary, this will trigger an un-needed graphql request :(
@@ -1610,6 +1682,7 @@ class Run:
1610
1682
  if (step is None and commit is None) or commit:
1611
1683
  self._step += 1
1612
1684
 
1685
+ @_log_to_run
1613
1686
  @_run_decorator._noop
1614
1687
  @_run_decorator._noop_on_finish()
1615
1688
  @_run_decorator._attach
@@ -1645,7 +1718,7 @@ class Run:
1645
1718
  [guides to logging](https://docs.wandb.ai/guides/track/log) for examples,
1646
1719
  from 3D molecular structures and segmentation masks to PR curves and histograms.
1647
1720
  You can use `wandb.Table` to log structured data. See our
1648
- [guide to logging tables](https://docs.wandb.ai/guides/tables/tables-walkthrough)
1721
+ [guide to logging tables](https://docs.wandb.ai/guides/models/tables/tables-walkthrough)
1649
1722
  for details.
1650
1723
 
1651
1724
  The W&B UI organizes metrics with a forward slash (`/`) in their name
@@ -1872,6 +1945,7 @@ class Run:
1872
1945
  )
1873
1946
  self._log(data=data, step=step, commit=commit)
1874
1947
 
1948
+ @_log_to_run
1875
1949
  @_run_decorator._noop_on_finish()
1876
1950
  @_run_decorator._attach
1877
1951
  def save(
@@ -2057,6 +2131,7 @@ class Run:
2057
2131
 
2058
2132
  return [str(f) for f in globbed_files]
2059
2133
 
2134
+ @_log_to_run
2060
2135
  @_run_decorator._attach
2061
2136
  def restore(
2062
2137
  self,
@@ -2072,6 +2147,7 @@ class Run:
2072
2147
  root or self._settings.files_dir,
2073
2148
  )
2074
2149
 
2150
+ @_log_to_run
2075
2151
  @_run_decorator._noop
2076
2152
  @_run_decorator._attach
2077
2153
  def finish(
@@ -2105,6 +2181,7 @@ class Run:
2105
2181
  )
2106
2182
  return self._finish(exit_code)
2107
2183
 
2184
+ @_log_to_run
2108
2185
  def _finish(
2109
2186
  self,
2110
2187
  exit_code: int | None = None,
@@ -2145,6 +2222,7 @@ class Run:
2145
2222
  module.unset_globals()
2146
2223
  wandb._sentry.end_session()
2147
2224
 
2225
+ @_log_to_run
2148
2226
  @_run_decorator._noop
2149
2227
  @_run_decorator._attach
2150
2228
  def join(self, exit_code: int | None = None) -> None:
@@ -2158,6 +2236,7 @@ class Run:
2158
2236
  )
2159
2237
  self._finish(exit_code=exit_code)
2160
2238
 
2239
+ @_log_to_run
2161
2240
  @_run_decorator._noop_on_finish()
2162
2241
  @_run_decorator._attach
2163
2242
  def status(
@@ -2308,8 +2387,6 @@ class Run:
2308
2387
  raise ValueError("unhandled console")
2309
2388
  try:
2310
2389
  # save stdout and stderr before installing new write functions
2311
- out_redir.save()
2312
- err_redir.save()
2313
2390
  out_redir.install()
2314
2391
  err_redir.install()
2315
2392
  self._out_redir = out_redir
@@ -2412,7 +2489,9 @@ class Run:
2412
2489
  self._backend.interface.publish_python_packages(working_set())
2413
2490
 
2414
2491
  if self._backend and self._backend.interface and not self._settings._offline:
2492
+ assert self._settings.run_id
2415
2493
  self._run_status_checker = RunStatusChecker(
2494
+ self._settings.run_id,
2416
2495
  interface=self._backend.interface,
2417
2496
  )
2418
2497
  self._run_status_checker.start()
@@ -2659,6 +2738,7 @@ class Run:
2659
2738
  for module_name in import_telemetry_set:
2660
2739
  unregister_post_import_hook(module_name, run_id)
2661
2740
 
2741
+ @_log_to_run
2662
2742
  @_run_decorator._noop_on_finish()
2663
2743
  @_run_decorator._attach
2664
2744
  def define_metric(
@@ -2800,6 +2880,7 @@ class Run:
2800
2880
  m._commit()
2801
2881
  return m
2802
2882
 
2883
+ @_log_to_run
2803
2884
  @_run_decorator._attach
2804
2885
  def watch(
2805
2886
  self,
@@ -2837,6 +2918,7 @@ class Run:
2837
2918
  """
2838
2919
  wandb.sdk._watch(self, models, criterion, log, log_freq, idx, log_graph)
2839
2920
 
2921
+ @_log_to_run
2840
2922
  @_run_decorator._attach
2841
2923
  def unwatch(
2842
2924
  self, models: torch.nn.Module | Sequence[torch.nn.Module] | None = None
@@ -2887,6 +2969,7 @@ class Run:
2887
2969
  def _detach(self) -> None:
2888
2970
  pass
2889
2971
 
2972
+ @_log_to_run
2890
2973
  @_run_decorator._noop_on_finish()
2891
2974
  @_run_decorator._attach
2892
2975
  def link_artifact(
@@ -2952,6 +3035,7 @@ class Run:
2952
3035
  if response.error_message:
2953
3036
  wandb.termerror(response.error_message)
2954
3037
 
3038
+ @_log_to_run
2955
3039
  @_run_decorator._noop_on_finish()
2956
3040
  @_run_decorator._attach
2957
3041
  def use_artifact(
@@ -3023,6 +3107,8 @@ class Run:
3023
3107
  artifact.id,
3024
3108
  entity_name=self._settings.entity,
3025
3109
  project_name=self._settings.project,
3110
+ artifact_entity_name=artifact.entity,
3111
+ artifact_project_name=artifact.project,
3026
3112
  use_as=use_as or artifact_or_name,
3027
3113
  )
3028
3114
  else:
@@ -3055,7 +3141,10 @@ class Run:
3055
3141
  )
3056
3142
  artifact._use_as = use_as or artifact.name
3057
3143
  api.use_artifact(
3058
- artifact.id, use_as=use_as or artifact._use_as or artifact.name
3144
+ artifact.id,
3145
+ use_as=use_as or artifact._use_as or artifact.name,
3146
+ artifact_entity_name=artifact.entity,
3147
+ artifact_project_name=artifact.project,
3059
3148
  )
3060
3149
  else:
3061
3150
  raise ValueError(
@@ -3066,6 +3155,7 @@ class Run:
3066
3155
  self._backend.interface.publish_use_artifact(artifact)
3067
3156
  return artifact
3068
3157
 
3158
+ @_log_to_run
3069
3159
  @_run_decorator._noop_on_finish()
3070
3160
  @_run_decorator._attach
3071
3161
  def log_artifact(
@@ -3108,6 +3198,7 @@ class Run:
3108
3198
  tags=tags,
3109
3199
  )
3110
3200
 
3201
+ @_log_to_run
3111
3202
  @_run_decorator._noop_on_finish()
3112
3203
  @_run_decorator._attach
3113
3204
  def upsert_artifact(
@@ -3162,6 +3253,7 @@ class Run:
3162
3253
  finalize=False,
3163
3254
  )
3164
3255
 
3256
+ @_log_to_run
3165
3257
  @_run_decorator._noop_on_finish()
3166
3258
  @_run_decorator._attach
3167
3259
  def finish_artifact(
@@ -3246,6 +3338,12 @@ class Run:
3246
3338
  artifact, aliases = self._prepare_artifact(
3247
3339
  artifact_or_path, name, type, aliases
3248
3340
  )
3341
+
3342
+ if len(artifact.metadata) > MAX_ARTIFACT_METADATA_KEYS:
3343
+ raise ValueError(
3344
+ f"Artifact must not have more than {MAX_ARTIFACT_METADATA_KEYS} metadata keys."
3345
+ )
3346
+
3249
3347
  artifact.distributed_id = distributed_id
3250
3348
  self._assert_can_log_artifact(artifact)
3251
3349
  if self._backend and self._backend.interface:
@@ -3357,6 +3455,7 @@ class Run:
3357
3455
  artifact.finalize()
3358
3456
  return artifact, _resolve_aliases(aliases)
3359
3457
 
3458
+ @_log_to_run
3360
3459
  @_run_decorator._noop_on_finish()
3361
3460
  @_run_decorator._attach
3362
3461
  def log_model(
@@ -3408,6 +3507,7 @@ class Run:
3408
3507
  artifact_or_path=path, name=name, type="model", aliases=aliases
3409
3508
  )
3410
3509
 
3510
+ @_log_to_run
3411
3511
  @_run_decorator._noop_on_finish()
3412
3512
  @_run_decorator._attach
3413
3513
  def use_model(self, name: str) -> FilePathStr:
@@ -3465,6 +3565,7 @@ class Run:
3465
3565
  return FilePathStr(os.path.join(path, dir_list[0]))
3466
3566
  return path
3467
3567
 
3568
+ @_log_to_run
3468
3569
  @_run_decorator._noop_on_finish()
3469
3570
  @_run_decorator._attach
3470
3571
  def link_model(
@@ -3566,6 +3667,7 @@ class Run:
3566
3667
  )
3567
3668
  self.link_artifact(artifact=artifact, target_path=target_path, aliases=aliases)
3568
3669
 
3670
+ @_log_to_run
3569
3671
  @_run_decorator._noop_on_finish()
3570
3672
  @_run_decorator._attach
3571
3673
  def alert(
@@ -3617,6 +3719,7 @@ class Run:
3617
3719
  self._finish(exit_code=exit_code)
3618
3720
  return not exception_raised
3619
3721
 
3722
+ @_log_to_run
3620
3723
  @_run_decorator._noop_on_finish()
3621
3724
  @_run_decorator._attach
3622
3725
  def mark_preempting(self) -> None:
@@ -3628,6 +3731,7 @@ class Run:
3628
3731
  self._backend.interface.publish_preempting()
3629
3732
 
3630
3733
  @property
3734
+ @_log_to_run
3631
3735
  @_run_decorator._noop_on_finish()
3632
3736
  @_run_decorator._attach
3633
3737
  def _system_metrics(self) -> dict[str, list[tuple[datetime, float]]]:
@@ -3676,6 +3780,7 @@ class Run:
3676
3780
  return {}
3677
3781
 
3678
3782
  @property
3783
+ @_log_to_run
3679
3784
  @_run_decorator._attach
3680
3785
  @_run_decorator._noop_on_finish()
3681
3786
  def _metadata(self) -> Metadata | None:
@@ -3714,6 +3819,7 @@ class Run:
3714
3819
 
3715
3820
  return None
3716
3821
 
3822
+ @_log_to_run
3717
3823
  @_run_decorator._noop_on_finish()
3718
3824
  @_run_decorator._attach
3719
3825
  def _metadata_callback(