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.
- wandb/__init__.py +5 -1
- wandb/__init__.pyi +15 -8
- wandb/_pydantic/__init__.py +30 -0
- wandb/_pydantic/base.py +148 -0
- wandb/_pydantic/utils.py +66 -0
- wandb/_pydantic/v1_compat.py +284 -0
- wandb/apis/paginator.py +82 -38
- wandb/apis/public/__init__.py +2 -2
- wandb/apis/public/api.py +111 -53
- wandb/apis/public/artifacts.py +387 -639
- wandb/apis/public/automations.py +69 -0
- wandb/apis/public/files.py +2 -2
- wandb/apis/public/integrations.py +168 -0
- wandb/apis/public/projects.py +32 -2
- wandb/apis/public/reports.py +2 -2
- wandb/apis/public/runs.py +19 -11
- wandb/apis/public/utils.py +107 -1
- wandb/automations/__init__.py +81 -0
- wandb/automations/_filters/__init__.py +40 -0
- wandb/automations/_filters/expressions.py +179 -0
- wandb/automations/_filters/operators.py +267 -0
- wandb/automations/_filters/run_metrics.py +183 -0
- wandb/automations/_generated/__init__.py +184 -0
- wandb/automations/_generated/create_filter_trigger.py +21 -0
- wandb/automations/_generated/create_generic_webhook_integration.py +43 -0
- wandb/automations/_generated/delete_trigger.py +19 -0
- wandb/automations/_generated/enums.py +33 -0
- wandb/automations/_generated/fragments.py +343 -0
- wandb/automations/_generated/generic_webhook_integrations_by_entity.py +22 -0
- wandb/automations/_generated/get_triggers.py +24 -0
- wandb/automations/_generated/get_triggers_by_entity.py +24 -0
- wandb/automations/_generated/input_types.py +104 -0
- wandb/automations/_generated/integrations_by_entity.py +22 -0
- wandb/automations/_generated/operations.py +710 -0
- wandb/automations/_generated/slack_integrations_by_entity.py +22 -0
- wandb/automations/_generated/update_filter_trigger.py +21 -0
- wandb/automations/_utils.py +123 -0
- wandb/automations/_validators.py +73 -0
- wandb/automations/actions.py +205 -0
- wandb/automations/automations.py +109 -0
- wandb/automations/events.py +235 -0
- wandb/automations/integrations.py +26 -0
- wandb/automations/scopes.py +76 -0
- wandb/beta/workflows.py +9 -10
- wandb/bin/gpu_stats +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +3 -3
- wandb/integration/keras/keras.py +2 -1
- wandb/integration/langchain/wandb_tracer.py +2 -1
- wandb/integration/metaflow/metaflow.py +19 -17
- wandb/integration/sacred/__init__.py +1 -1
- wandb/jupyter.py +155 -133
- wandb/old/summary.py +0 -2
- wandb/proto/v3/wandb_internal_pb2.py +297 -292
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v4/wandb_internal_pb2.py +292 -292
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v5/wandb_internal_pb2.py +292 -292
- wandb/proto/v5/wandb_settings_pb2.py +2 -2
- wandb/proto/v5/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v6/wandb_base_pb2.py +41 -0
- wandb/proto/v6/wandb_internal_pb2.py +393 -0
- wandb/proto/v6/wandb_server_pb2.py +78 -0
- wandb/proto/v6/wandb_settings_pb2.py +58 -0
- wandb/proto/v6/wandb_telemetry_pb2.py +52 -0
- wandb/proto/wandb_base_pb2.py +2 -0
- wandb/proto/wandb_deprecated.py +10 -0
- wandb/proto/wandb_internal_pb2.py +3 -1
- wandb/proto/wandb_server_pb2.py +2 -0
- wandb/proto/wandb_settings_pb2.py +2 -0
- wandb/proto/wandb_telemetry_pb2.py +2 -0
- wandb/sdk/artifacts/_generated/__init__.py +248 -0
- wandb/sdk/artifacts/_generated/artifact_collection_membership_files.py +43 -0
- wandb/sdk/artifacts/_generated/artifact_version_files.py +36 -0
- wandb/sdk/artifacts/_generated/create_artifact_collection_tag_assignments.py +36 -0
- wandb/sdk/artifacts/_generated/delete_artifact_collection_tag_assignments.py +25 -0
- wandb/sdk/artifacts/_generated/delete_artifact_portfolio.py +35 -0
- wandb/sdk/artifacts/_generated/delete_artifact_sequence.py +35 -0
- wandb/sdk/artifacts/_generated/enums.py +17 -0
- wandb/sdk/artifacts/_generated/fragments.py +186 -0
- wandb/sdk/artifacts/_generated/input_types.py +16 -0
- wandb/sdk/artifacts/_generated/move_artifact_collection.py +35 -0
- wandb/sdk/artifacts/_generated/operations.py +510 -0
- wandb/sdk/artifacts/_generated/project_artifact_collection.py +101 -0
- wandb/sdk/artifacts/_generated/project_artifact_collections.py +33 -0
- wandb/sdk/artifacts/_generated/project_artifact_type.py +24 -0
- wandb/sdk/artifacts/_generated/project_artifact_types.py +24 -0
- wandb/sdk/artifacts/_generated/project_artifacts.py +42 -0
- wandb/sdk/artifacts/_generated/run_input_artifacts.py +51 -0
- wandb/sdk/artifacts/_generated/run_output_artifacts.py +51 -0
- wandb/sdk/artifacts/_generated/update_artifact_portfolio.py +35 -0
- wandb/sdk/artifacts/_generated/update_artifact_sequence.py +35 -0
- wandb/sdk/artifacts/_graphql_fragments.py +56 -81
- wandb/sdk/artifacts/_validators.py +1 -0
- wandb/sdk/artifacts/artifact.py +110 -49
- wandb/sdk/artifacts/artifact_manifest_entry.py +2 -1
- wandb/sdk/artifacts/artifact_saver.py +16 -2
- wandb/sdk/artifacts/storage_handlers/azure_handler.py +1 -0
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +23 -2
- wandb/sdk/data_types/audio.py +1 -3
- wandb/sdk/data_types/base_types/media.py +13 -7
- wandb/sdk/data_types/base_types/wb_value.py +34 -11
- wandb/sdk/data_types/html.py +36 -9
- wandb/sdk/data_types/image.py +56 -37
- wandb/sdk/data_types/molecule.py +1 -5
- wandb/sdk/data_types/object_3d.py +2 -1
- wandb/sdk/data_types/saved_model.py +7 -9
- wandb/sdk/data_types/table.py +5 -0
- wandb/sdk/data_types/trace_tree.py +2 -0
- wandb/sdk/data_types/utils.py +1 -1
- wandb/sdk/data_types/video.py +15 -30
- wandb/sdk/interface/interface.py +2 -0
- wandb/{apis/public → sdk/internal}/_generated/__init__.py +0 -6
- wandb/{apis/public → sdk/internal}/_generated/server_features_query.py +3 -3
- wandb/sdk/internal/internal_api.py +138 -47
- wandb/sdk/internal/profiler.py +6 -5
- wandb/sdk/internal/run.py +13 -6
- wandb/sdk/internal/sender.py +2 -0
- wandb/sdk/internal/sender_config.py +8 -11
- wandb/sdk/internal/settings_static.py +24 -2
- wandb/sdk/lib/apikey.py +40 -20
- wandb/sdk/lib/asyncio_compat.py +1 -1
- wandb/sdk/lib/deprecate.py +13 -22
- wandb/sdk/lib/disabled.py +2 -1
- wandb/sdk/lib/printer.py +37 -8
- wandb/sdk/lib/printer_asyncio.py +46 -0
- wandb/sdk/lib/redirect.py +10 -5
- wandb/sdk/lib/run_moment.py +4 -6
- wandb/sdk/lib/wb_logging.py +161 -0
- wandb/sdk/service/server_sock.py +19 -14
- wandb/sdk/service/service.py +9 -7
- wandb/sdk/service/streams.py +5 -0
- wandb/sdk/verify/verify.py +6 -3
- wandb/sdk/wandb_config.py +44 -43
- wandb/sdk/wandb_init.py +323 -141
- wandb/sdk/wandb_login.py +13 -4
- wandb/sdk/wandb_metadata.py +107 -91
- wandb/sdk/wandb_run.py +529 -325
- wandb/sdk/wandb_settings.py +422 -202
- wandb/sdk/wandb_setup.py +52 -1
- wandb/util.py +29 -29
- {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/METADATA +7 -7
- {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/RECORD +151 -94
- wandb/_globals.py +0 -19
- wandb/apis/public/_generated/base.py +0 -128
- wandb/apis/public/_generated/typing_compat.py +0 -14
- /wandb/{apis/public → sdk/internal}/_generated/enums.py +0 -0
- /wandb/{apis/public → sdk/internal}/_generated/input_types.py +0 -0
- /wandb/{apis/public → sdk/internal}/_generated/operations.py +0 -0
- {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/WHEEL +0 -0
- {wandb-0.19.8.dist-info → wandb-0.19.10.dist-info}/entry_points.txt +0 -0
- {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
|
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
|
-
|
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
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
31
|
+
Args:
|
32
|
+
run: The run to display.
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
Returns:
|
35
|
+
Whether the %%wandb cell magic was present.
|
36
|
+
"""
|
37
|
+
if not _current_cell_wandb_magic:
|
38
|
+
return False
|
35
39
|
|
36
|
-
|
37
|
-
|
40
|
+
_current_cell_wandb_magic.display_if_allowed(run)
|
41
|
+
return True
|
38
42
|
|
39
43
|
|
40
|
-
|
44
|
+
class _WandbCellMagicState:
|
45
|
+
"""State for a cell with the %%wandb cell magic."""
|
41
46
|
|
42
|
-
|
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
|
46
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
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="
|
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
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
142
|
+
global _current_cell_wandb_magic
|
143
|
+
|
143
144
|
args = parse_argstring(self.wandb, line)
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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) ->
|
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
|
209
|
-
"the WANDB_NOTEBOOK_NAME environment variable to enable code
|
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
|
-
|
238
|
-
logger.error(error_message)
|
249
|
+
wandb.termerror(error_message)
|
239
250
|
return {}
|
240
251
|
except Exception:
|
241
|
-
|
242
|
-
|
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
|
-
|
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(
|
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(
|
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
|
392
|
-
|
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
|
-
|
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
|
-
|
501
|
-
filesystem.mkdir_exists_ok(os.path.join(
|
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(
|
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)
|
513
|
-
|
533
|
+
except (OSError, validator.NotebookValidationError):
|
534
|
+
wandb.termerror("Unable to save notebook session history.")
|
535
|
+
logger.exception("Unable to save notebook session history.")
|