wandb 0.19.8__py3-none-macosx_11_0_arm64.whl → 0.19.10__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 (154) hide show
  1. wandb/__init__.py +5 -1
  2. wandb/__init__.pyi +15 -8
  3. wandb/_pydantic/__init__.py +30 -0
  4. wandb/_pydantic/base.py +148 -0
  5. wandb/_pydantic/utils.py +66 -0
  6. wandb/_pydantic/v1_compat.py +284 -0
  7. wandb/apis/paginator.py +82 -38
  8. wandb/apis/public/__init__.py +2 -2
  9. wandb/apis/public/api.py +111 -53
  10. wandb/apis/public/artifacts.py +387 -639
  11. wandb/apis/public/automations.py +69 -0
  12. wandb/apis/public/files.py +2 -2
  13. wandb/apis/public/integrations.py +168 -0
  14. wandb/apis/public/projects.py +32 -2
  15. wandb/apis/public/reports.py +2 -2
  16. wandb/apis/public/runs.py +19 -11
  17. wandb/apis/public/utils.py +107 -1
  18. wandb/automations/__init__.py +81 -0
  19. wandb/automations/_filters/__init__.py +40 -0
  20. wandb/automations/_filters/expressions.py +179 -0
  21. wandb/automations/_filters/operators.py +267 -0
  22. wandb/automations/_filters/run_metrics.py +183 -0
  23. wandb/automations/_generated/__init__.py +184 -0
  24. wandb/automations/_generated/create_filter_trigger.py +21 -0
  25. wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
  26. wandb/automations/_generated/delete_trigger.py +19 -0
  27. wandb/automations/_generated/enums.py +33 -0
  28. wandb/automations/_generated/fragments.py +343 -0
  29. wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
  30. wandb/automations/_generated/get_triggers.py +24 -0
  31. wandb/automations/_generated/get_triggers_by_entity.py +24 -0
  32. wandb/automations/_generated/input_types.py +104 -0
  33. wandb/automations/_generated/integrations_by_entity.py +22 -0
  34. wandb/automations/_generated/operations.py +710 -0
  35. wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
  36. wandb/automations/_generated/update_filter_trigger.py +21 -0
  37. wandb/automations/_utils.py +123 -0
  38. wandb/automations/_validators.py +73 -0
  39. wandb/automations/actions.py +205 -0
  40. wandb/automations/automations.py +109 -0
  41. wandb/automations/events.py +235 -0
  42. wandb/automations/integrations.py +26 -0
  43. wandb/automations/scopes.py +76 -0
  44. wandb/beta/workflows.py +9 -10
  45. wandb/bin/gpu_stats +0 -0
  46. wandb/bin/wandb-core +0 -0
  47. wandb/cli/cli.py +3 -3
  48. wandb/integration/keras/keras.py +2 -1
  49. wandb/integration/langchain/wandb_tracer.py +2 -1
  50. wandb/integration/metaflow/metaflow.py +19 -17
  51. wandb/integration/sacred/__init__.py +1 -1
  52. wandb/jupyter.py +155 -133
  53. wandb/old/summary.py +0 -2
  54. wandb/proto/v3/wandb_internal_pb2.py +297 -292
  55. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  56. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  57. wandb/proto/v4/wandb_internal_pb2.py +292 -292
  58. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  59. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  60. wandb/proto/v5/wandb_internal_pb2.py +292 -292
  61. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  62. wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
  63. wandb/proto/v6/wandb_base_pb2.py +41 -0
  64. wandb/proto/v6/wandb_internal_pb2.py +393 -0
  65. wandb/proto/v6/wandb_server_pb2.py +78 -0
  66. wandb/proto/v6/wandb_settings_pb2.py +58 -0
  67. wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
  68. wandb/proto/wandb_base_pb2.py +2 -0
  69. wandb/proto/wandb_deprecated.py +10 -0
  70. wandb/proto/wandb_internal_pb2.py +3 -1
  71. wandb/proto/wandb_server_pb2.py +2 -0
  72. wandb/proto/wandb_settings_pb2.py +2 -0
  73. wandb/proto/wandb_telemetry_pb2.py +2 -0
  74. wandb/sdk/artifacts/_generated/__init__.py +248 -0
  75. wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
  76. wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
  77. wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
  78. wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
  79. wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
  80. wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
  81. wandb/sdk/artifacts/_generated/enums.py +17 -0
  82. wandb/sdk/artifacts/_generated/fragments.py +186 -0
  83. wandb/sdk/artifacts/_generated/input_types.py +16 -0
  84. wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
  85. wandb/sdk/artifacts/_generated/operations.py +510 -0
  86. wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
  87. wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
  88. wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
  89. wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
  90. wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
  91. wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
  92. wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
  93. wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
  94. wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
  95. wandb/sdk/artifacts/_graphql_fragments.py +56 -81
  96. wandb/sdk/artifacts/_validators.py +1 -0
  97. wandb/sdk/artifacts/artifact.py +110 -49
  98. wandb/sdk/artifacts/artifact_manifest_entry.py +2 -1
  99. wandb/sdk/artifacts/artifact_saver.py +16 -2
  100. wandb/sdk/artifacts/storage_handlers/azure_handler.py +1 -0
  101. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +23 -2
  102. wandb/sdk/data_types/audio.py +1 -3
  103. wandb/sdk/data_types/base_types/media.py +13 -7
  104. wandb/sdk/data_types/base_types/wb_value.py +34 -11
  105. wandb/sdk/data_types/html.py +36 -9
  106. wandb/sdk/data_types/image.py +56 -37
  107. wandb/sdk/data_types/molecule.py +1 -5
  108. wandb/sdk/data_types/object_3d.py +2 -1
  109. wandb/sdk/data_types/saved_model.py +7 -9
  110. wandb/sdk/data_types/table.py +5 -0
  111. wandb/sdk/data_types/trace_tree.py +2 -0
  112. wandb/sdk/data_types/utils.py +1 -1
  113. wandb/sdk/data_types/video.py +15 -30
  114. wandb/sdk/interface/interface.py +2 -0
  115. wandb/{apis/public → sdk/internal}/_generated/__init__.py +0 -6
  116. wandb/{apis/public → sdk/internal}/_generated/server_features_query.py +3 -3
  117. wandb/sdk/internal/internal_api.py +138 -47
  118. wandb/sdk/internal/profiler.py +6 -5
  119. wandb/sdk/internal/run.py +13 -6
  120. wandb/sdk/internal/sender.py +2 -0
  121. wandb/sdk/internal/sender_config.py +8 -11
  122. wandb/sdk/internal/settings_static.py +24 -2
  123. wandb/sdk/lib/apikey.py +40 -20
  124. wandb/sdk/lib/asyncio_compat.py +1 -1
  125. wandb/sdk/lib/deprecate.py +13 -22
  126. wandb/sdk/lib/disabled.py +2 -1
  127. wandb/sdk/lib/printer.py +37 -8
  128. wandb/sdk/lib/printer_asyncio.py +46 -0
  129. wandb/sdk/lib/redirect.py +10 -5
  130. wandb/sdk/lib/run_moment.py +4 -6
  131. wandb/sdk/lib/wb_logging.py +161 -0
  132. wandb/sdk/service/server_sock.py +19 -14
  133. wandb/sdk/service/service.py +9 -7
  134. wandb/sdk/service/streams.py +5 -0
  135. wandb/sdk/verify/verify.py +6 -3
  136. wandb/sdk/wandb_config.py +44 -43
  137. wandb/sdk/wandb_init.py +323 -141
  138. wandb/sdk/wandb_login.py +13 -4
  139. wandb/sdk/wandb_metadata.py +107 -91
  140. wandb/sdk/wandb_run.py +529 -325
  141. wandb/sdk/wandb_settings.py +422 -202
  142. wandb/sdk/wandb_setup.py +52 -1
  143. wandb/util.py +29 -29
  144. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/METADATA +7 -7
  145. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/RECORD +151 -94
  146. wandb/_globals.py +0 -19
  147. wandb/apis/public/_generated/base.py +0 -128
  148. wandb/apis/public/_generated/typing_compat.py +0 -14
  149. /wandb/{apis/public → sdk/internal}/_generated/enums.py +0 -0
  150. /wandb/{apis/public → sdk/internal}/_generated/input_types.py +0 -0
  151. /wandb/{apis/public → sdk/internal}/_generated/operations.py +0 -0
  152. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/WHEEL +0 -0
  153. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/entry_points.txt +0 -0
  154. {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/licenses/LICENSE +0 -0
wandb/jupyter.py CHANGED
@@ -1,160 +1,171 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
  import logging
3
5
  import os
4
6
  import re
5
7
  import shutil
6
8
  import sys
9
+ import traceback
7
10
  from base64 import b64encode
8
- from typing import Dict
11
+ from typing import Any
9
12
 
13
+ import IPython
14
+ import IPython.display
10
15
  import requests
16
+ from IPython.core.magic import Magics, line_cell_magic, magics_class
17
+ from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring
11
18
  from requests.compat import urljoin
12
19
 
13
20
  import wandb
14
21
  import wandb.util
22
+ from wandb.sdk import wandb_run, wandb_setup
15
23
  from wandb.sdk.lib import filesystem
16
24
 
17
- try:
18
- import IPython
19
- from IPython.core.magic import Magics, line_cell_magic, magics_class
20
- from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring
21
- except ImportError:
22
- wandb.termwarn("ipython is not supported in python 2.7, upgrade to 3.x")
25
+ logger = logging.getLogger(__name__)
23
26
 
24
- class Magics:
25
- pass
26
27
 
27
- def magics_class(*args, **kwargs):
28
- return lambda *args, **kwargs: None
28
+ def display_if_magic_is_used(run: wandb_run.Run) -> bool:
29
+ """Display a run's page if the cell has the %%wandb cell magic.
29
30
 
30
- def magic_arguments(*args, **kwargs):
31
- return lambda *args, **kwargs: None
31
+ Args:
32
+ run: The run to display.
32
33
 
33
- def argument(*args, **kwargs):
34
- return lambda *args, **kwargs: None
34
+ Returns:
35
+ Whether the %%wandb cell magic was present.
36
+ """
37
+ if not _current_cell_wandb_magic:
38
+ return False
35
39
 
36
- def line_cell_magic(*args, **kwargs):
37
- return lambda *args, **kwargs: None
40
+ _current_cell_wandb_magic.display_if_allowed(run)
41
+ return True
38
42
 
39
43
 
40
- logger = logging.getLogger(__name__)
44
+ class _WandbCellMagicState:
45
+ """State for a cell with the %%wandb cell magic."""
41
46
 
42
- __IFrame = None
47
+ def __init__(self, *, height: int) -> None:
48
+ """Initializes the %%wandb cell magic state.
43
49
 
50
+ Args:
51
+ height: The desired height for displayed iframes.
52
+ """
53
+ self._height = height
54
+ self._already_displayed = False
44
55
 
45
- def maybe_display():
46
- """Display a run if the user added cell magic and we have run."""
47
- if __IFrame is not None:
48
- return __IFrame.maybe_display()
49
- return False
56
+ def display_if_allowed(self, run: wandb_run.Run) -> None:
57
+ """Display a run's iframe if one is not already displayed.
50
58
 
59
+ Args:
60
+ run: The run to display.
61
+ """
62
+ if self._already_displayed:
63
+ return
64
+ self._already_displayed = True
51
65
 
52
- def quiet():
53
- if __IFrame is not None:
54
- return __IFrame.opts.get("quiet")
55
- return False
66
+ _display_wandb_run(run, height=self._height)
56
67
 
57
68
 
58
- class IFrame:
59
- def __init__(self, path=None, opts=None):
60
- self.path = path
61
- self.api = wandb.Api()
62
- self.opts = opts or {}
63
- self.displayed = False
64
- self.height = self.opts.get("height", 420)
69
+ _current_cell_wandb_magic: _WandbCellMagicState | None = None
65
70
 
66
- def maybe_display(self) -> bool:
67
- if not self.displayed and (self.path or wandb.run):
68
- IPython.display.display(self)
69
- return self.displayed
70
71
 
71
- def _repr_html_(self):
72
- try:
73
- self.displayed = True
74
- if self.opts.get("workspace", False):
75
- if self.path is None and wandb.run:
76
- self.path = wandb.run.path
77
- if isinstance(self.path, str):
78
- object = self.api.from_path(self.path)
79
- else:
80
- object = wandb.run
81
- if object is None:
82
- if wandb.Api().api_key is None:
83
- return "You must be logged in to render wandb in jupyter, run `wandb.login()`"
84
- else:
85
- object = self.api.project(
86
- "/".join(
87
- [
88
- wandb.Api().default_entity,
89
- wandb.util.auto_project_name(None),
90
- ]
91
- )
92
- )
93
- return object.to_html(self.height, hidden=False)
94
- except wandb.Error as e:
95
- return f"Can't display wandb interface<br/>{e}"
72
+ def _display_by_wandb_path(path: str, *, height: int) -> None:
73
+ """Display a wandb object (usually in an iframe) given its URI.
74
+
75
+ Args:
76
+ path: A path to a run, sweep, project, report, etc.
77
+ height: Height of the iframe in pixels.
78
+ """
79
+ api = wandb.Api()
80
+
81
+ try:
82
+ obj = api.from_path(path)
83
+
84
+ IPython.display.display_html(
85
+ obj.to_html(height=height),
86
+ raw=True,
87
+ )
88
+ except wandb.Error:
89
+ traceback.print_exc()
90
+ IPython.display.display_html(
91
+ f"Path {path!r} does not refer to a W&B object you can access.",
92
+ raw=True,
93
+ )
94
+
95
+
96
+ def _display_wandb_run(run: wandb_run.Run, *, height: int) -> None:
97
+ """Display a run (usually in an iframe).
98
+
99
+ Args:
100
+ run: The run to display.
101
+ height: Height of the iframe in pixels.
102
+ """
103
+ IPython.display.display_html(
104
+ run.to_html(height=height),
105
+ raw=True,
106
+ )
96
107
 
97
108
 
98
109
  @magics_class
99
110
  class WandBMagics(Magics):
100
- def __init__(self, shell, require_interaction=False):
111
+ def __init__(self, shell):
101
112
  super().__init__(shell)
102
- self.options = {}
103
113
 
104
114
  @magic_arguments()
105
115
  @argument(
106
116
  "path",
107
117
  default=None,
108
118
  nargs="?",
109
- help="A path to a resource you want to display, defaults to wandb.run.path",
110
- )
111
- @argument(
112
- "-w",
113
- "--workspace",
114
- default=False,
115
- action="store_true",
116
- help="Display the entire run project workspace",
117
- )
118
- @argument(
119
- "-q",
120
- "--quiet",
121
- default=False,
122
- action="store_true",
123
- help="Display the minimal amount of output",
119
+ help="The path to a resource you want to display.",
124
120
  )
125
121
  @argument(
126
122
  "-h",
127
123
  "--height",
128
124
  default=420,
129
125
  type=int,
130
- help="The height of the iframe in pixels",
126
+ help="The height of the iframe in pixels.",
131
127
  )
132
128
  @line_cell_magic
133
- def wandb(self, line, cell=None):
134
- """Display wandb resources in jupyter. This can be used as cell or line magic.
135
-
136
- %wandb USERNAME/PROJECT/runs/RUN_ID
137
- ---
138
- %%wandb -h 1024
139
- with wandb.init() as run:
140
- run.log({"loss": 1})
129
+ def wandb(self, line: str, cell: str | None = None) -> None:
130
+ """Display wandb resources in Jupyter.
131
+
132
+ This can be used as a line magic:
133
+
134
+ %wandb USERNAME/PROJECT/runs/RUN_ID
135
+
136
+ Or as a cell magic:
137
+
138
+ %%wandb -h 1024
139
+ with wandb.init() as run:
140
+ run.log({"loss": 1})
141
141
  """
142
- # Record options
142
+ global _current_cell_wandb_magic
143
+
143
144
  args = parse_argstring(self.wandb, line)
144
- self.options["height"] = args.height
145
- self.options["workspace"] = args.workspace
146
- self.options["quiet"] = args.quiet
147
- iframe = IFrame(args.path, opts=self.options)
148
- displayed = iframe.maybe_display()
149
- if cell is not None:
150
- if not displayed:
151
- # Store the IFrame globally and attempt to display if we have a run
152
- cell = (
153
- f"wandb.jupyter.__IFrame = wandb.jupyter.IFrame(opts={self.options})\n"
154
- + cell
155
- + "\nwandb.jupyter.__IFrame = None"
156
- )
145
+ path: str | None = args.path
146
+ height: int = args.height
147
+
148
+ if path:
149
+ _display_by_wandb_path(path, height=height)
150
+ displayed = True
151
+ elif run := wandb_setup._setup(start_service=False).most_recent_active_run:
152
+ _display_wandb_run(run, height=height)
153
+ displayed = True
154
+ else:
155
+ displayed = False
156
+
157
+ # If this is being used as a line magic ("%wandb"), we are done.
158
+ # When used as a cell magic ("%%wandb"), we must run the cell.
159
+ if cell is None:
160
+ return
161
+
162
+ if not displayed:
163
+ _current_cell_wandb_magic = _WandbCellMagicState(height=height)
164
+
165
+ try:
157
166
  IPython.get_ipython().run_cell(cell)
167
+ finally:
168
+ _current_cell_wandb_magic = None
158
169
 
159
170
 
160
171
  def notebook_metadata_from_jupyter_servers_and_kernel_id():
@@ -193,7 +204,7 @@ def notebook_metadata_from_jupyter_servers_and_kernel_id():
193
204
  return None
194
205
 
195
206
 
196
- def notebook_metadata(silent: bool) -> Dict[str, str]:
207
+ def notebook_metadata(silent: bool) -> dict[str, str]:
197
208
  """Attempt to query jupyter for the path and name of the notebook file.
198
209
 
199
210
  This can handle different jupyter environments, specifically:
@@ -205,8 +216,9 @@ def notebook_metadata(silent: bool) -> Dict[str, str]:
205
216
  5. Other?
206
217
  """
207
218
  error_message = (
208
- "Failed to detect the name of this notebook, you can set it manually with "
209
- "the WANDB_NOTEBOOK_NAME environment variable to enable code saving."
219
+ "Failed to detect the name of this notebook. You can set it manually"
220
+ " with the WANDB_NOTEBOOK_NAME environment variable to enable code"
221
+ " saving."
210
222
  )
211
223
  try:
212
224
  jupyter_metadata = notebook_metadata_from_jupyter_servers_and_kernel_id()
@@ -234,15 +246,11 @@ def notebook_metadata(silent: bool) -> Dict[str, str]:
234
246
 
235
247
  if jupyter_metadata:
236
248
  return jupyter_metadata
237
- if not silent:
238
- logger.error(error_message)
249
+ wandb.termerror(error_message)
239
250
  return {}
240
251
  except Exception:
241
- # TODO: report this exception
242
- # TODO: Fix issue this is not the logger initialized in in wandb.init()
243
- # since logger is not attached, outputs to notebook
244
- if not silent:
245
- logger.error(error_message)
252
+ wandb.termerror(error_message)
253
+ logger.exception(error_message)
246
254
  return {}
247
255
 
248
256
 
@@ -252,7 +260,7 @@ def jupyter_servers_and_kernel_id():
252
260
  Used to query for the name of the notebook.
253
261
  """
254
262
  try:
255
- import ipykernel
263
+ import ipykernel # type: ignore
256
264
 
257
265
  kernel_id = re.search(
258
266
  "kernel-(.*).json", ipykernel.connect.get_connection_file()
@@ -289,14 +297,18 @@ def attempt_kaggle_load_ipynb():
289
297
  parsed["metadata"]["name"] = "kaggle.ipynb"
290
298
  return parsed
291
299
  except Exception:
292
- logger.exception("Unable to load kaggle notebook")
300
+ wandb.termerror("Unable to load kaggle notebook.")
301
+ logger.exception("Unable to load kaggle notebook.")
293
302
  return None
294
303
 
295
304
 
296
- def attempt_colab_login(app_url):
305
+ def attempt_colab_login(
306
+ app_url: str,
307
+ referrer: str | None = None,
308
+ ):
297
309
  """This renders an iframe to wandb in the hopes it posts back an api key."""
298
- from google.colab import output
299
- from google.colab._message import MessageError
310
+ from google.colab import output # type: ignore
311
+ from google.colab._message import MessageError # type: ignore
300
312
  from IPython import display
301
313
 
302
314
  display.display(
@@ -318,7 +330,7 @@ def attempt_colab_login(app_url):
318
330
  document.body.appendChild(iframe)
319
331
  const handshake = new Postmate({{
320
332
  container: iframe,
321
- url: '{}/authorize'
333
+ url: '{}/authorize{}'
322
334
  }});
323
335
  const timeout = setTimeout(() => reject("Couldn't auto authenticate"), 5000)
324
336
  handshake.then(function(child) {{
@@ -329,7 +341,10 @@ def attempt_colab_login(app_url):
329
341
  }});
330
342
  }})
331
343
  }});
332
- """.format(app_url.replace("http:", "https:"))
344
+ """.format(
345
+ app_url.replace("http:", "https:"),
346
+ f"?ref={referrer}" if referrer else "",
347
+ )
333
348
  )
334
349
  )
335
350
  try:
@@ -339,8 +354,8 @@ def attempt_colab_login(app_url):
339
354
 
340
355
 
341
356
  class Notebook:
342
- def __init__(self, settings):
343
- self.outputs = {}
357
+ def __init__(self, settings: wandb.Settings) -> None:
358
+ self.outputs: dict[int, Any] = {}
344
359
  self.settings = settings
345
360
  self.shell = IPython.get_ipython()
346
361
 
@@ -388,8 +403,9 @@ class Notebook:
388
403
  ret = False
389
404
  try:
390
405
  ret = self._save_ipynb()
391
- except Exception as e:
392
- logger.info(f"Problem saving notebook: {repr(e)}")
406
+ except Exception:
407
+ wandb.termerror("Failed to save notebook.")
408
+ logger.exception("Problem saving notebook.")
393
409
  return ret
394
410
 
395
411
  def _save_ipynb(self) -> bool:
@@ -442,12 +458,15 @@ class Notebook:
442
458
 
443
459
  return False
444
460
 
445
- def save_history(self):
461
+ def save_history(self, run: wandb_run.Run):
446
462
  """This saves all cell executions in the current session as a new notebook."""
447
463
  try:
448
- from nbformat import v4, validator, write
464
+ from nbformat import v4, validator, write # type: ignore
449
465
  except ImportError:
450
- logger.error("Run pip install nbformat to save notebook history")
466
+ wandb.termerror(
467
+ "The nbformat package was not found."
468
+ " It is required to save notebook history."
469
+ )
451
470
  return
452
471
  # TODO: some tests didn't patch ipython properly?
453
472
  if self.shell is None:
@@ -497,8 +516,8 @@ class Notebook:
497
516
  },
498
517
  )
499
518
  state_path = os.path.join("code", "_session_history.ipynb")
500
- wandb.run._set_config_wandb("session_history", state_path)
501
- filesystem.mkdir_exists_ok(os.path.join(wandb.run.dir, "code"))
519
+ run._set_config_wandb("session_history", state_path)
520
+ filesystem.mkdir_exists_ok(os.path.join(self.settings.files_dir, "code"))
502
521
  with open(
503
522
  os.path.join(self.settings._tmp_code_dir, "_session_history.ipynb"),
504
523
  "w",
@@ -506,8 +525,11 @@ class Notebook:
506
525
  ) as f:
507
526
  write(nb, f, version=4)
508
527
  with open(
509
- os.path.join(wandb.run.dir, state_path), "w", encoding="utf-8"
528
+ os.path.join(self.settings.files_dir, state_path),
529
+ "w",
530
+ encoding="utf-8",
510
531
  ) as f:
511
532
  write(nb, f, version=4)
512
- except (OSError, validator.NotebookValidationError) as e:
513
- logger.error("Unable to save ipython session history:\n%s", e)
533
+ except (OSError, validator.NotebookValidationError):
534
+ wandb.termerror("Unable to save notebook session history.")
535
+ logger.exception("Unable to save notebook session history.")
wandb/old/summary.py CHANGED
@@ -379,8 +379,6 @@ class FileSummary(Summary):
379
379
  if self._h5:
380
380
  self._h5.close()
381
381
  self._h5 = None
382
- if wandb.run and wandb.run._jupyter_agent:
383
- wandb.run._jupyter_agent.start()
384
382
 
385
383
 
386
384
  class HTTPSummary(Summary):