wandb 0.19.9__py3-none-musllinux_1_2_aarch64.whl → 0.19.10__py3-none-musllinux_1_2_aarch64.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 (128) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +4 -1
  3. wandb/_pydantic/__init__.py +14 -7
  4. wandb/_pydantic/base.py +44 -9
  5. wandb/_pydantic/utils.py +66 -0
  6. wandb/_pydantic/v1_compat.py +78 -56
  7. wandb/apis/public/__init__.py +2 -2
  8. wandb/apis/public/api.py +114 -2
  9. wandb/apis/public/artifacts.py +365 -673
  10. wandb/apis/public/automations.py +69 -0
  11. wandb/apis/public/integrations.py +168 -0
  12. wandb/apis/public/projects.py +29 -0
  13. wandb/apis/public/utils.py +107 -1
  14. wandb/automations/__init__.py +81 -0
  15. wandb/automations/_filters/__init__.py +40 -0
  16. wandb/automations/_filters/expressions.py +179 -0
  17. wandb/automations/_filters/operators.py +267 -0
  18. wandb/automations/_filters/run_metrics.py +183 -0
  19. wandb/automations/_generated/__init__.py +184 -0
  20. wandb/automations/_generated/create_filter_trigger.py +21 -0
  21. wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
  22. wandb/automations/_generated/delete_trigger.py +19 -0
  23. wandb/automations/_generated/enums.py +33 -0
  24. wandb/automations/_generated/fragments.py +343 -0
  25. wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
  26. wandb/automations/_generated/get_triggers.py +24 -0
  27. wandb/automations/_generated/get_triggers_by_entity.py +24 -0
  28. wandb/automations/_generated/input_types.py +104 -0
  29. wandb/automations/_generated/integrations_by_entity.py +22 -0
  30. wandb/automations/_generated/operations.py +710 -0
  31. wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
  32. wandb/automations/_generated/update_filter_trigger.py +21 -0
  33. wandb/automations/_utils.py +123 -0
  34. wandb/automations/_validators.py +73 -0
  35. wandb/automations/actions.py +205 -0
  36. wandb/automations/automations.py +109 -0
  37. wandb/automations/events.py +235 -0
  38. wandb/automations/integrations.py +26 -0
  39. wandb/automations/scopes.py +76 -0
  40. wandb/beta/workflows.py +9 -10
  41. wandb/bin/gpu_stats +0 -0
  42. wandb/bin/wandb-core +0 -0
  43. wandb/cli/cli.py +3 -3
  44. wandb/integration/keras/keras.py +2 -1
  45. wandb/integration/langchain/wandb_tracer.py +2 -1
  46. wandb/jupyter.py +137 -118
  47. wandb/old/summary.py +0 -2
  48. wandb/proto/v3/wandb_internal_pb2.py +293 -292
  49. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  50. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  51. wandb/proto/v4/wandb_internal_pb2.py +292 -292
  52. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  53. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  54. wandb/proto/v5/wandb_internal_pb2.py +292 -292
  55. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  56. wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
  57. wandb/proto/v6/wandb_base_pb2.py +41 -0
  58. wandb/proto/v6/wandb_internal_pb2.py +393 -0
  59. wandb/proto/v6/wandb_server_pb2.py +78 -0
  60. wandb/proto/v6/wandb_settings_pb2.py +58 -0
  61. wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
  62. wandb/proto/wandb_base_pb2.py +2 -0
  63. wandb/proto/wandb_deprecated.py +8 -0
  64. wandb/proto/wandb_internal_pb2.py +3 -1
  65. wandb/proto/wandb_server_pb2.py +2 -0
  66. wandb/proto/wandb_settings_pb2.py +2 -0
  67. wandb/proto/wandb_telemetry_pb2.py +2 -0
  68. wandb/sdk/artifacts/_generated/__init__.py +248 -0
  69. wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
  70. wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
  71. wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
  72. wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
  73. wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
  74. wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
  75. wandb/sdk/artifacts/_generated/enums.py +17 -0
  76. wandb/sdk/artifacts/_generated/fragments.py +186 -0
  77. wandb/sdk/artifacts/_generated/input_types.py +16 -0
  78. wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
  79. wandb/sdk/artifacts/_generated/operations.py +510 -0
  80. wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
  81. wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
  82. wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
  83. wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
  84. wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
  85. wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
  86. wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
  87. wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
  88. wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
  89. wandb/sdk/artifacts/_graphql_fragments.py +56 -79
  90. wandb/sdk/artifacts/artifact.py +40 -13
  91. wandb/sdk/artifacts/artifact_manifest_entry.py +2 -1
  92. wandb/sdk/artifacts/storage_handlers/azure_handler.py +1 -0
  93. wandb/sdk/data_types/base_types/media.py +2 -3
  94. wandb/sdk/data_types/base_types/wb_value.py +34 -11
  95. wandb/sdk/data_types/html.py +36 -9
  96. wandb/sdk/data_types/image.py +12 -12
  97. wandb/sdk/data_types/table.py +5 -0
  98. wandb/sdk/data_types/trace_tree.py +2 -0
  99. wandb/sdk/data_types/utils.py +1 -1
  100. wandb/sdk/data_types/video.py +14 -26
  101. wandb/sdk/interface/interface.py +2 -0
  102. wandb/sdk/internal/profiler.py +6 -5
  103. wandb/sdk/internal/run.py +13 -6
  104. wandb/sdk/lib/apikey.py +25 -4
  105. wandb/sdk/lib/asyncio_compat.py +1 -1
  106. wandb/sdk/lib/deprecate.py +13 -22
  107. wandb/sdk/lib/disabled.py +2 -1
  108. wandb/sdk/lib/printer.py +37 -8
  109. wandb/sdk/lib/printer_asyncio.py +46 -0
  110. wandb/sdk/lib/redirect.py +10 -5
  111. wandb/sdk/service/server_sock.py +19 -14
  112. wandb/sdk/service/service.py +9 -7
  113. wandb/sdk/service/streams.py +5 -0
  114. wandb/sdk/verify/verify.py +6 -3
  115. wandb/sdk/wandb_init.py +185 -65
  116. wandb/sdk/wandb_login.py +13 -4
  117. wandb/sdk/wandb_run.py +382 -286
  118. wandb/sdk/wandb_settings.py +21 -3
  119. wandb/sdk/wandb_setup.py +49 -0
  120. wandb/util.py +29 -29
  121. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/METADATA +5 -5
  122. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/RECORD +125 -72
  123. wandb/_globals.py +0 -19
  124. wandb/sdk/internal/_generated/base.py +0 -226
  125. wandb/sdk/internal/_generated/typing_compat.py +0 -14
  126. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/WHEEL +0 -0
  127. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/entry_points.txt +0 -0
  128. {wandb-0.19.9.dist-info → wandb-0.19.10.dist-info}/licenses/LICENSE +0 -0
@@ -5,6 +5,7 @@ import time
5
5
  from typing import TYPE_CHECKING, Any, Callable, Dict, Optional
6
6
 
7
7
  import wandb
8
+ from wandb.proto import wandb_internal_pb2 as pb
8
9
  from wandb.proto import wandb_server_pb2 as spb
9
10
  from wandb.sdk.internal.settings_static import SettingsStatic
10
11
 
@@ -156,27 +157,31 @@ class SockServerReadThread(threading.Thread):
156
157
  inform_attach_response=inform_attach_response,
157
158
  )
158
159
  self._sock_client.send_server_response(response)
159
- iface = self._mux.get_stream(stream_id).interface
160
-
161
- assert iface
162
160
 
163
161
  def server_record_communicate(self, sreq: "spb.ServerRequest") -> None:
164
- record = sreq.record_communicate
165
- # encode relay information so the right socket picks up the data
166
- record.control.relay_id = self._sock_client._sockid
167
- stream_id = record._info.stream_id
168
- iface = self._mux.get_stream(stream_id).interface
169
- assert iface.record_q
170
- iface.record_q.put(record)
162
+ self._put_record(sreq.record_communicate)
171
163
 
172
164
  def server_record_publish(self, sreq: "spb.ServerRequest") -> None:
173
- record = sreq.record_publish
165
+ self._put_record(sreq.record_publish)
166
+
167
+ def _put_record(self, record: "pb.Record") -> None:
174
168
  # encode relay information so the right socket picks up the data
175
169
  record.control.relay_id = self._sock_client._sockid
176
170
  stream_id = record._info.stream_id
177
- iface = self._mux.get_stream(stream_id).interface
178
- assert iface.record_q
179
- iface.record_q.put(record)
171
+
172
+ try:
173
+ iface = self._mux.get_stream(stream_id).interface
174
+
175
+ except KeyError:
176
+ # We should log the error but cannot because it may print to console
177
+ # due to how logging is set up. This error usually happens if
178
+ # a record is sent when no run is active, but during this time the
179
+ # logger prints to the console.
180
+ pass
181
+
182
+ else:
183
+ assert iface.record_q
184
+ iface.record_q.put(record)
180
185
 
181
186
  def server_inform_finish(self, sreq: "spb.ServerRequest") -> None:
182
187
  request = sreq.inform_finish
@@ -14,10 +14,10 @@ import tempfile
14
14
  import time
15
15
  from typing import TYPE_CHECKING, Any, Dict, Optional
16
16
 
17
- from wandb import _sentry, termlog
17
+ from wandb import _sentry
18
18
  from wandb.env import core_debug, error_reporting_enabled, is_require_legacy_service
19
19
  from wandb.errors import Error, WandbCoreNotAvailableError
20
- from wandb.errors.links import url_registry
20
+ from wandb.errors.term import termlog, termwarn
21
21
  from wandb.util import get_core_path, get_module
22
22
 
23
23
  from . import _startup_debug, port_file
@@ -163,13 +163,15 @@ class _Service:
163
163
  service_args.extend(["--log-level", "-4"])
164
164
 
165
165
  exec_cmd_list = []
166
- termlog(
167
- "Using wandb-core as the SDK backend. Please refer to "
168
- f"{url_registry.url('wandb-core')} for more information.",
169
- repeat=False,
170
- )
171
166
  else:
172
167
  service_args.extend(["wandb", "service", "--debug"])
168
+ termwarn(
169
+ "Using legacy-service, which is deprecated. If this is"
170
+ " unintentional, you can fix it by ensuring you do not call"
171
+ " `wandb.require('legacy-service')` and do not set the"
172
+ " WANDB_X_REQUIRE_LEGACY_SERVICE environment"
173
+ " variable."
174
+ )
173
175
 
174
176
  service_args += [
175
177
  "--port-filename",
@@ -198,6 +198,11 @@ class StreamMux:
198
198
  return stream_id in self._streams
199
199
 
200
200
  def get_stream(self, stream_id: str) -> StreamRecord:
201
+ """Returns the StreamRecord for the ID.
202
+
203
+ Raises:
204
+ KeyError: If a corresponding StreamRecord does not exist.
205
+ """
201
206
  with self._streams_lock:
202
207
  stream = self._streams[stream_id]
203
208
  return stream
@@ -132,7 +132,10 @@ def check_run(api: Api) -> bool:
132
132
  f.close()
133
133
 
134
134
  with wandb.init(
135
- id=nice_id("check_run"), reinit=True, config=config, project=PROJECT_NAME
135
+ id=nice_id("check_run"),
136
+ reinit=True,
137
+ config=config,
138
+ project=PROJECT_NAME,
136
139
  ) as run:
137
140
  run_id = run.id
138
141
  entity = run.entity
@@ -155,7 +158,7 @@ def check_run(api: Api) -> bool:
155
158
  "Failed to log to media. Contact W&B for support."
156
159
  )
157
160
 
158
- wandb.save(filepath)
161
+ run.save(filepath)
159
162
  public_api = wandb.Api()
160
163
  prev_run = public_api.run(f"{entity}/{PROJECT_NAME}/{run_id}")
161
164
  # raise Exception(prev_run.__dict__)
@@ -379,7 +382,7 @@ def check_graphql_put(api: Api, host: str) -> Tuple[bool, Optional[str]]:
379
382
  project=PROJECT_NAME,
380
383
  config={"test": "put to graphql"},
381
384
  ) as run:
382
- wandb.save(gql_fp)
385
+ run.save(gql_fp)
383
386
  public_api = wandb.Api()
384
387
  prev_run = public_api.run(f"{run.entity}/{PROJECT_NAME}/{run.id}")
385
388
  if prev_run is None:
wandb/sdk/wandb_init.py CHANGED
@@ -21,7 +21,7 @@ import platform
21
21
  import sys
22
22
  import tempfile
23
23
  import time
24
- from typing import Any, Iterator, Literal, Sequence
24
+ from typing import TYPE_CHECKING, Any, Iterable, Iterator, Literal, Protocol, Sequence
25
25
 
26
26
  if sys.version_info >= (3, 11):
27
27
  from typing import Self
@@ -35,6 +35,7 @@ from wandb.errors import CommError, Error, UsageError
35
35
  from wandb.errors.links import url_registry
36
36
  from wandb.errors.util import ProtobufErrorHandler
37
37
  from wandb.integration import sagemaker
38
+ from wandb.proto.wandb_deprecated import Deprecated
38
39
  from wandb.sdk.lib import ipython as wb_ipython
39
40
  from wandb.sdk.lib import progress, runid, wb_logging
40
41
  from wandb.sdk.lib.paths import StrPath
@@ -43,12 +44,15 @@ from wandb.util import _is_artifact_representation
43
44
  from . import wandb_login, wandb_setup
44
45
  from .backend.backend import Backend
45
46
  from .lib import SummaryDisabled, filesystem, module, paths, printer, telemetry
46
- from .lib.deprecate import Deprecated, deprecate
47
+ from .lib.deprecate import deprecate
47
48
  from .mailbox import wait_with_progress
48
49
  from .wandb_helper import parse_config
49
50
  from .wandb_run import Run, TeardownHook, TeardownStage
50
51
  from .wandb_settings import Settings
51
52
 
53
+ if TYPE_CHECKING:
54
+ import wandb.jupyter
55
+
52
56
 
53
57
  def _huggingface_version() -> str | None:
54
58
  if "transformers" in sys.modules:
@@ -124,6 +128,34 @@ class _ConfigParts:
124
128
  """
125
129
 
126
130
 
131
+ class _PrinterCallback(Protocol):
132
+ """A callback for displaying messages after a printer is configured.
133
+
134
+ This is used for a few messages that may be generated before run settings
135
+ are computed, which are necessary for creating a printer.
136
+ """
137
+
138
+ def __call__(self, run_printer: printer.Printer) -> None:
139
+ """Display information through the given printer."""
140
+
141
+
142
+ def _noop_printer_callback() -> _PrinterCallback:
143
+ """A printer callback that does not print anything."""
144
+ return lambda _: None
145
+
146
+
147
+ def _concat_printer_callbacks(
148
+ cbs: Iterable[_PrinterCallback],
149
+ ) -> _PrinterCallback:
150
+ """Returns a printer callback that runs the given callbacks in order."""
151
+
152
+ def do_callbacks(run_printer: printer.Printer) -> None:
153
+ for cb in cbs:
154
+ cb(run_printer)
155
+
156
+ return do_callbacks
157
+
158
+
127
159
  class _WandbInit:
128
160
  def __init__(
129
161
  self,
@@ -143,8 +175,7 @@ class _WandbInit:
143
175
  self.backend: Backend | None = None
144
176
 
145
177
  self._teardown_hooks: list[TeardownHook] = []
146
- self.notebook: wandb.jupyter.Notebook | None = None # type: ignore
147
- self.printer = printer.new_printer()
178
+ self.notebook: wandb.jupyter.Notebook | None = None
148
179
 
149
180
  self.deprecated_features_used: dict[str, str] = dict()
150
181
 
@@ -176,20 +207,21 @@ class _WandbInit:
176
207
 
177
208
  wandb_login._login(
178
209
  anonymous=run_settings.anonymous,
210
+ host=run_settings.base_url,
179
211
  force=run_settings.force,
180
212
  _disable_warning=True,
181
213
  _silent=run_settings.quiet or run_settings.silent,
182
214
  )
183
215
 
184
- def warn_env_vars_change_after_setup(self) -> None:
185
- """Warn if environment variables change after wandb singleton is initialized.
216
+ def warn_env_vars_change_after_setup(self) -> _PrinterCallback:
217
+ """Warn if environment variables changed after `wandb.setup()`.
186
218
 
187
- Any settings from environment variables set after the singleton is initialized
188
- (via login/setup/etc.) will be ignored.
219
+ Returns:
220
+ A callback to print any generated warnings.
189
221
  """
190
222
  singleton = wandb_setup.singleton()
191
223
  if singleton is None:
192
- return
224
+ return _noop_printer_callback()
193
225
 
194
226
  exclude_env_vars = {"WANDB_SERVICE", "WANDB_KUBEFLOW_URL"}
195
227
  # check if environment variables have changed
@@ -203,26 +235,36 @@ class _WandbInit:
203
235
  for k, v in os.environ.items()
204
236
  if k.startswith("WANDB_") and k not in exclude_env_vars
205
237
  }
206
- if set(singleton_env.keys()) != set(os_env.keys()) or set(
207
- singleton_env.values()
208
- ) != set(os_env.values()):
238
+
239
+ if (
240
+ set(singleton_env.keys()) == set(os_env.keys()) #
241
+ and set(singleton_env.values()) == set(os_env.values())
242
+ ):
243
+ return _noop_printer_callback()
244
+
245
+ def print_warning(run_printer: printer.Printer) -> None:
209
246
  line = (
210
247
  "Changes to your `wandb` environment variables will be ignored "
211
248
  "because your `wandb` session has already started. "
212
249
  "For more information on how to modify your settings with "
213
250
  "`wandb.init()` arguments, please refer to "
214
- f"{self.printer.link(url_registry.url('wandb-init'), 'the W&B docs')}."
251
+ f"{run_printer.link(url_registry.url('wandb-init'), 'the W&B docs')}."
215
252
  )
216
- self.printer.display(line, level="warn")
253
+ run_printer.display(line, level="warn")
254
+
255
+ return print_warning
217
256
 
218
257
  def clear_run_path_if_sweep_or_launch(
219
258
  self,
220
259
  init_settings: Settings,
221
- ) -> None:
260
+ ) -> _PrinterCallback:
222
261
  """Clear project/entity/run_id keys if in a Sweep or a Launch context.
223
262
 
224
263
  Args:
225
264
  init_settings: Settings specified in the call to `wandb.init()`.
265
+
266
+ Returns:
267
+ A callback to print any generated warnings.
226
268
  """
227
269
  when_doing_thing = ""
228
270
 
@@ -232,13 +274,12 @@ class _WandbInit:
232
274
  when_doing_thing = "when running from a wandb launch context"
233
275
 
234
276
  if not when_doing_thing:
235
- return
277
+ return _noop_printer_callback()
278
+
279
+ warnings = []
236
280
 
237
281
  def warn(key: str, value: str) -> None:
238
- self.printer.display(
239
- f"Ignoring {key} {value!r} {when_doing_thing}.",
240
- level="warn",
241
- )
282
+ warnings.append(f"Ignoring {key} {value!r} {when_doing_thing}.")
242
283
 
243
284
  if init_settings.project is not None:
244
285
  warn("project", init_settings.project)
@@ -250,16 +291,26 @@ class _WandbInit:
250
291
  warn("run_id", init_settings.run_id)
251
292
  init_settings.run_id = None
252
293
 
253
- def make_run_settings(self, init_settings: Settings) -> Settings:
254
- """Returns the run's settings.
294
+ def print_warnings(run_printer: printer.Printer) -> None:
295
+ for warning in warnings:
296
+ run_printer.display(warning, level="warn")
297
+
298
+ return print_warnings
299
+
300
+ def make_run_settings(
301
+ self,
302
+ init_settings: Settings,
303
+ ) -> tuple[Settings, _PrinterCallback]:
304
+ """Returns the run's settings and any warnings.
255
305
 
256
306
  Args:
257
307
  init_settings: Settings passed to `wandb.init()` or set via
258
308
  keyword arguments.
259
309
  """
260
- self.warn_env_vars_change_after_setup()
261
-
262
- self.clear_run_path_if_sweep_or_launch(init_settings)
310
+ warning_callbacks: list[_PrinterCallback] = [
311
+ self.warn_env_vars_change_after_setup(),
312
+ self.clear_run_path_if_sweep_or_launch(init_settings),
313
+ ]
263
314
 
264
315
  # Inherit global settings.
265
316
  settings = self._wl.settings.model_copy()
@@ -305,7 +356,7 @@ class _WandbInit:
305
356
  label = runid.generate_id()
306
357
  settings.x_label = f"{prefix}-{label}" if prefix else label
307
358
 
308
- return settings
359
+ return settings, _concat_printer_callbacks(warning_callbacks)
309
360
 
310
361
  def _load_autoresume_run_id(self, resume_file: pathlib.Path) -> str | None:
311
362
  """Returns the run_id stored in the auto-resume file, if any.
@@ -533,62 +584,73 @@ class _WandbInit:
533
584
  except OSError:
534
585
  pass
535
586
 
536
- def _pause_backend(self, *args: Any, **kwargs: Any) -> None: # noqa
537
- if self.backend is None:
538
- return None
587
+ def _pre_run_cell_hook(self, *args, **kwargs) -> None:
588
+ """Hook for the IPython pre_run_cell event.
589
+
590
+ This pauses a run, preventing system metrics from being collected
591
+ the run's runtime from increasing. It also uploads the notebook's code.
592
+ """
593
+ if not self.backend:
594
+ return
539
595
 
540
- # Attempt to save the code on every execution
541
- if self.notebook.save_ipynb(): # type: ignore
596
+ if self.notebook and self.notebook.save_ipynb():
542
597
  assert self.run is not None
543
598
  res = self.run.log_code(root=None)
544
- self._logger.info("saved code: %s", res) # type: ignore
599
+ self._logger.info("saved code: %s", res)
600
+
545
601
  if self.backend.interface is not None:
546
- self._logger.info("pausing backend") # type: ignore
602
+ self._logger.info("pausing backend")
547
603
  self.backend.interface.publish_pause()
548
604
 
549
- def _resume_backend(self, *args: Any, **kwargs: Any) -> None: # noqa
550
- if self.backend is not None and self.backend.interface is not None:
551
- self._logger.info("resuming backend") # type: ignore
552
- self.backend.interface.publish_resume()
605
+ def _post_run_cell_hook(self, *args, **kwargs) -> None:
606
+ """Hook for the IPython post_run_cell event.
607
+
608
+ Resumes collection of system metrics and the run's timer.
609
+ """
610
+ if self.backend is None or self.backend.interface is None:
611
+ return
612
+
613
+ self._logger.info("resuming backend")
614
+ self.backend.interface.publish_resume()
553
615
 
554
616
  def _jupyter_teardown(self) -> None:
555
617
  """Teardown hooks and display saving, called with wandb.finish."""
556
618
  assert self.notebook
557
619
  ipython = self.notebook.shell
558
- self.notebook.save_history()
620
+
621
+ if self.run:
622
+ self.notebook.save_history(self.run)
623
+
559
624
  if self.notebook.save_ipynb():
560
625
  assert self.run is not None
561
626
  res = self.run.log_code(root=None)
562
- self._logger.info("saved code and history: %s", res) # type: ignore
563
- self._logger.info("cleaning up jupyter logic") # type: ignore
564
- # because of how we bind our methods we manually find them to unregister
565
- for hook in ipython.events.callbacks["pre_run_cell"]:
566
- if "_resume_backend" in hook.__name__:
567
- ipython.events.unregister("pre_run_cell", hook)
568
- for hook in ipython.events.callbacks["post_run_cell"]:
569
- if "_pause_backend" in hook.__name__:
570
- ipython.events.unregister("post_run_cell", hook)
627
+ self._logger.info("saved code and history: %s", res)
628
+ self._logger.info("cleaning up jupyter logic")
629
+
630
+ ipython.events.unregister("pre_run_cell", self._pre_run_cell_hook)
631
+ ipython.events.unregister("post_run_cell", self._post_run_cell_hook)
632
+
571
633
  ipython.display_pub.publish = ipython.display_pub._orig_publish
572
634
  del ipython.display_pub._orig_publish
573
635
 
574
636
  def monkeypatch_ipython(self, settings: Settings) -> None:
575
637
  """Add hooks, and session history saving."""
576
- self.notebook = wandb.jupyter.Notebook(settings) # type: ignore
638
+ self.notebook = wandb.jupyter.Notebook(settings)
577
639
  ipython = self.notebook.shell
578
640
 
579
641
  # Monkey patch ipython publish to capture displayed outputs
580
642
  if not hasattr(ipython.display_pub, "_orig_publish"):
581
- self._logger.info("configuring jupyter hooks %s", self) # type: ignore
643
+ self._logger.info("configuring jupyter hooks %s", self)
582
644
  ipython.display_pub._orig_publish = ipython.display_pub.publish
583
- # Registering resume and pause hooks
584
645
 
585
- ipython.events.register("pre_run_cell", self._resume_backend)
586
- ipython.events.register("post_run_cell", self._pause_backend)
646
+ ipython.events.register("pre_run_cell", self._pre_run_cell_hook)
647
+ ipython.events.register("post_run_cell", self._post_run_cell_hook)
648
+
587
649
  self._teardown_hooks.append(
588
650
  TeardownHook(self._jupyter_teardown, TeardownStage.EARLY)
589
651
  )
590
652
 
591
- def publish(data, metadata=None, **kwargs) -> None: # type: ignore
653
+ def publish(data, metadata=None, **kwargs) -> None:
592
654
  ipython.display_pub._orig_publish(data, metadata=metadata, **kwargs)
593
655
  assert self.notebook is not None
594
656
  self.notebook.save_display(
@@ -729,6 +791,10 @@ class _WandbInit:
729
791
  ):
730
792
  setattr(drun, symbol, lambda *_, **__: None) # type: ignore
731
793
 
794
+ # set properties to None
795
+ for attr in ("url", "project_url", "sweep_url"):
796
+ setattr(type(drun), attr, property(lambda _: None))
797
+
732
798
  class _ChainableNoOp:
733
799
  """An object that allows chaining arbitrary attributes and method calls."""
734
800
 
@@ -753,7 +819,7 @@ class _WandbInit:
753
819
  def __call__(self, *args: Any, **kwargs: Any) -> _ChainableNoOp:
754
820
  return _ChainableNoOp()
755
821
 
756
- drun.log_artifact = _ChainableNoOpField() # type: ignore[method-assign]
822
+ drun.log_artifact = _ChainableNoOpField() # type: ignore
757
823
  # attributes
758
824
  drun._start_time = time.time()
759
825
  drun._starting_step = 0
@@ -777,7 +843,12 @@ class _WandbInit:
777
843
  )
778
844
  return drun
779
845
 
780
- def init(self, settings: Settings, config: _ConfigParts) -> Run: # noqa: C901
846
+ def init( # noqa: C901
847
+ self,
848
+ settings: Settings,
849
+ config: _ConfigParts,
850
+ run_printer: printer.Printer,
851
+ ) -> Run:
781
852
  self._logger.info("calling init triggers")
782
853
  trigger.call("on_init")
783
854
 
@@ -788,23 +859,36 @@ class _WandbInit:
788
859
  f"\nconfig: {config.base_no_artifacts}"
789
860
  )
790
861
 
791
- if wandb.run is not None and os.getpid() == wandb.run._init_pid:
862
+ if previous_run := self._wl.most_recent_active_run:
792
863
  if (
793
864
  settings.reinit in (True, "finish_previous")
794
865
  # calling wandb.init() in notebooks finishes previous runs
795
866
  # by default for user convenience.
796
867
  or (settings.reinit == "default" and wb_ipython.in_notebook())
797
868
  ):
798
- self._logger.info("finishing previous run: %s", wandb.run.id)
799
- wandb.run.finish()
869
+ run_printer.display(
870
+ "Finishing previous runs because reinit is set"
871
+ f" to {settings.reinit!r}."
872
+ )
873
+ self._wl.finish_all_active_runs()
874
+
875
+ elif settings.reinit == "create_new":
876
+ self._logger.info(
877
+ "wandb.init() called while a run is active,"
878
+ " and reinit is set to 'create_new', so continuing"
879
+ )
880
+
800
881
  else:
801
- self._logger.info("wandb.init() called while a run is active")
882
+ run_printer.display(
883
+ "wandb.init() called while a run is active and reinit is"
884
+ f" set to {settings.reinit!r}, so returning the previous"
885
+ " run."
886
+ )
802
887
 
803
- # NOTE: Updates telemetry on the pre-existing run.
804
- with telemetry.context() as tel:
888
+ with telemetry.context(run=previous_run) as tel:
805
889
  tel.feature.init_return_run = True
806
890
 
807
- return wandb.run
891
+ return previous_run
808
892
 
809
893
  self._logger.info("starting backend")
810
894
 
@@ -897,6 +981,9 @@ class _WandbInit:
897
981
  )
898
982
  tel.feature.shared_mode = True
899
983
 
984
+ if settings.x_label:
985
+ tel.feature.user_provided_label = True
986
+
900
987
  tel.env.maybe_mp = _maybe_mp_process(backend)
901
988
 
902
989
  if not settings.label_disable:
@@ -946,7 +1033,7 @@ class _WandbInit:
946
1033
  assert backend.interface
947
1034
 
948
1035
  with progress.progress_printer(
949
- self.printer,
1036
+ run_printer,
950
1037
  default_text="Waiting for wandb.init()...",
951
1038
  ) as progress_printer:
952
1039
  await progress.loop_printing_operation_stats(
@@ -1052,6 +1139,10 @@ class _WandbInit:
1052
1139
  run.use_artifact(job_artifact)
1053
1140
 
1054
1141
  self.backend = backend
1142
+
1143
+ if settings.reinit != "create_new":
1144
+ _set_global_run(run)
1145
+
1055
1146
  run._on_start()
1056
1147
  self._logger.info("run started, returning control to user process")
1057
1148
  return run
@@ -1128,10 +1219,36 @@ def _attach(
1128
1219
  raise UsageError(f"Failed to attach to run: {attach_response.error.message}")
1129
1220
 
1130
1221
  run._set_run_obj(attach_response.run)
1222
+ _set_global_run(run)
1131
1223
  run._on_attach()
1132
1224
  return run
1133
1225
 
1134
1226
 
1227
+ def _set_global_run(run: Run) -> None:
1228
+ """Set `wandb.run` and point some top-level functions to its methods.
1229
+
1230
+ Args:
1231
+ run: The run to make global.
1232
+ """
1233
+ module.set_global(
1234
+ run=run,
1235
+ config=run.config,
1236
+ log=run.log,
1237
+ summary=run.summary,
1238
+ save=run.save,
1239
+ use_artifact=run.use_artifact,
1240
+ log_artifact=run.log_artifact,
1241
+ define_metric=run.define_metric,
1242
+ alert=run.alert,
1243
+ watch=run.watch,
1244
+ unwatch=run.unwatch,
1245
+ mark_preempting=run.mark_preempting,
1246
+ log_model=run.log_model,
1247
+ use_model=run.use_model,
1248
+ link_model=run.link_model,
1249
+ )
1250
+
1251
+
1135
1252
  def _monkeypatch_openai_gym() -> None:
1136
1253
  """Patch OpenAI gym to log to the global `wandb.run`."""
1137
1254
  if len(wandb.patched["gym"]) > 0:
@@ -1199,6 +1316,7 @@ def init( # noqa: C901
1199
1316
  "default",
1200
1317
  "return_previous",
1201
1318
  "finish_previous",
1319
+ "create_new",
1202
1320
  ]
1203
1321
  ) = None,
1204
1322
  resume: bool | Literal["allow", "never", "must", "auto"] | None = None,
@@ -1476,7 +1594,7 @@ def init( # noqa: C901
1476
1594
  wi = _WandbInit(wl, init_telemetry)
1477
1595
 
1478
1596
  wi.maybe_login(init_settings)
1479
- run_settings = wi.make_run_settings(init_settings)
1597
+ run_settings, show_warnings = wi.make_run_settings(init_settings)
1480
1598
 
1481
1599
  if isinstance(run_settings.reinit, bool):
1482
1600
  wi.deprecated_features_used["run__reinit_bool"] = (
@@ -1494,6 +1612,8 @@ def init( # noqa: C901
1494
1612
  init_telemetry.feature.offline = True
1495
1613
 
1496
1614
  wi.set_run_id(run_settings)
1615
+ run_printer = printer.new_printer(run_settings)
1616
+ show_warnings(run_printer)
1497
1617
 
1498
1618
  with contextlib.ExitStack() as exit_stack:
1499
1619
  exit_stack.enter_context(wb_logging.log_to_run(run_settings.run_id))
@@ -1527,7 +1647,7 @@ def init( # noqa: C901
1527
1647
  if run_settings.x_server_side_derived_summary:
1528
1648
  init_telemetry.feature.server_side_derived_summary = True
1529
1649
 
1530
- return wi.init(run_settings, run_config)
1650
+ return wi.init(run_settings, run_config, run_printer)
1531
1651
 
1532
1652
  except KeyboardInterrupt as e:
1533
1653
  if wl:
wandb/sdk/wandb_login.py CHANGED
@@ -45,6 +45,7 @@ def login(
45
45
  force: Optional[bool] = None,
46
46
  timeout: Optional[int] = None,
47
47
  verify: bool = False,
48
+ referrer: Optional[str] = None,
48
49
  ) -> bool:
49
50
  """Set up W&B login credentials.
50
51
 
@@ -64,6 +65,7 @@ def login(
64
65
  force: (bool, optional) If true, will force a relogin.
65
66
  timeout: (int, optional) Number of seconds to wait for user input.
66
67
  verify: (bool) Verify the credentials with the W&B server.
68
+ referrer: (string, optional) The referrer to use in the URL login request.
67
69
 
68
70
  Returns:
69
71
  bool: if key is configured
@@ -81,6 +83,7 @@ def login(
81
83
  force=force,
82
84
  timeout=timeout,
83
85
  verify=verify,
86
+ referrer=referrer,
84
87
  )
85
88
 
86
89
 
@@ -199,7 +202,9 @@ class _WandbLogin:
199
202
  if not self._wandb_setup.settings._offline:
200
203
  self._wandb_setup._update_user_settings()
201
204
 
202
- def _prompt_api_key(self) -> Tuple[Optional[str], ApiKeyStatus]:
205
+ def _prompt_api_key(
206
+ self, referrer: Optional[str] = None
207
+ ) -> Tuple[Optional[str], ApiKeyStatus]:
203
208
  api = Api(self._settings)
204
209
  while True:
205
210
  try:
@@ -208,6 +213,7 @@ class _WandbLogin:
208
213
  api=api,
209
214
  no_offline=self._settings.force if self._settings else None,
210
215
  no_create=self._settings.force if self._settings else None,
216
+ referrer=referrer,
211
217
  )
212
218
  except ValueError as e:
213
219
  # invalid key provided, try again
@@ -222,9 +228,11 @@ class _WandbLogin:
222
228
  return None, ApiKeyStatus.OFFLINE
223
229
  return key, ApiKeyStatus.VALID
224
230
 
225
- def prompt_api_key(self) -> Tuple[Optional[str], ApiKeyStatus]:
231
+ def prompt_api_key(
232
+ self, referrer: Optional[str] = None
233
+ ) -> Tuple[Optional[str], ApiKeyStatus]:
226
234
  """Updates the global API key by prompting the user."""
227
- key, status = self._prompt_api_key()
235
+ key, status = self._prompt_api_key(referrer)
228
236
  if status == ApiKeyStatus.NOTTY:
229
237
  directive = (
230
238
  "wandb login [your_api_key]"
@@ -262,6 +270,7 @@ def _login(
262
270
  force: Optional[bool] = None,
263
271
  timeout: Optional[int] = None,
264
272
  verify: bool = False,
273
+ referrer: str = "models",
265
274
  _silent: Optional[bool] = None,
266
275
  _disable_warning: Optional[bool] = None,
267
276
  ) -> bool:
@@ -302,7 +311,7 @@ def _login(
302
311
  if key and not relogin:
303
312
  key_is_pre_configured = True
304
313
  else:
305
- key, key_status = wlogin.prompt_api_key()
314
+ key, key_status = wlogin.prompt_api_key(referrer=referrer)
306
315
 
307
316
  if verify:
308
317
  wlogin._verify_login(key)