wandb 0.17.0rc1__py3-none-win_amd64.whl → 0.17.1__py3-none-win_amd64.whl
Sign up to get free protection for your applications and to get access to all the features.
- wandb/__init__.py +1 -2
- wandb/apis/importers/internals/internal.py +0 -1
- wandb/apis/importers/wandb.py +12 -7
- wandb/apis/internal.py +0 -3
- wandb/apis/public/api.py +213 -79
- wandb/apis/public/artifacts.py +335 -100
- wandb/apis/public/files.py +9 -9
- wandb/apis/public/jobs.py +16 -4
- wandb/apis/public/projects.py +26 -28
- wandb/apis/public/query_generator.py +1 -1
- wandb/apis/public/runs.py +163 -65
- wandb/apis/public/sweeps.py +2 -2
- wandb/apis/reports/__init__.py +1 -7
- wandb/apis/reports/v1/__init__.py +5 -27
- wandb/apis/reports/v2/__init__.py +7 -19
- wandb/apis/workspaces/__init__.py +8 -0
- wandb/beta/workflows.py +8 -3
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +131 -59
- wandb/data_types.py +6 -3
- wandb/docker/__init__.py +2 -2
- wandb/env.py +3 -3
- wandb/errors/term.py +10 -2
- wandb/filesync/step_checksum.py +1 -4
- wandb/filesync/step_prepare.py +4 -24
- wandb/filesync/step_upload.py +5 -107
- wandb/filesync/upload_job.py +0 -76
- wandb/integration/gym/__init__.py +35 -15
- wandb/integration/huggingface/resolver.py +2 -2
- wandb/integration/keras/callbacks/metrics_logger.py +1 -1
- wandb/integration/keras/keras.py +1 -1
- wandb/integration/openai/fine_tuning.py +21 -3
- wandb/integration/prodigy/prodigy.py +1 -1
- wandb/jupyter.py +16 -17
- wandb/old/summary.py +1 -1
- wandb/plot/confusion_matrix.py +1 -1
- wandb/plot/pr_curve.py +2 -1
- wandb/plot/roc_curve.py +2 -1
- wandb/{plots → plot}/utils.py +13 -25
- wandb/proto/v3/wandb_internal_pb2.py +54 -54
- 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 +54 -54
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
- wandb/proto/v5/wandb_base_pb2.py +30 -0
- wandb/proto/v5/wandb_internal_pb2.py +355 -0
- wandb/proto/v5/wandb_server_pb2.py +63 -0
- wandb/proto/v5/wandb_settings_pb2.py +45 -0
- wandb/proto/v5/wandb_telemetry_pb2.py +41 -0
- wandb/proto/wandb_base_pb2.py +2 -0
- wandb/proto/wandb_deprecated.py +9 -1
- wandb/proto/wandb_generate_deprecated.py +34 -0
- wandb/proto/{wandb_internal_codegen.py → wandb_generate_proto.py} +1 -35
- wandb/proto/wandb_internal_pb2.py +2 -0
- 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/artifact.py +68 -22
- wandb/sdk/artifacts/artifact_manifest.py +1 -1
- wandb/sdk/artifacts/artifact_manifest_entry.py +6 -3
- wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -1
- wandb/sdk/artifacts/artifact_saver.py +1 -10
- wandb/sdk/artifacts/storage_handlers/local_file_handler.py +6 -2
- wandb/sdk/artifacts/storage_handlers/multi_handler.py +1 -1
- wandb/sdk/artifacts/storage_handlers/tracking_handler.py +6 -4
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +2 -42
- wandb/sdk/artifacts/storage_policy.py +1 -12
- wandb/sdk/data_types/_dtypes.py +8 -8
- wandb/sdk/data_types/image.py +2 -2
- wandb/sdk/data_types/video.py +5 -3
- wandb/sdk/integration_utils/data_logging.py +5 -5
- wandb/sdk/interface/interface.py +14 -1
- wandb/sdk/interface/interface_shared.py +1 -1
- wandb/sdk/internal/file_pusher.py +2 -5
- wandb/sdk/internal/file_stream.py +6 -19
- wandb/sdk/internal/internal_api.py +148 -136
- wandb/sdk/internal/job_builder.py +208 -136
- wandb/sdk/internal/progress.py +0 -28
- wandb/sdk/internal/sender.py +102 -39
- wandb/sdk/internal/settings_static.py +8 -1
- wandb/sdk/internal/system/assets/trainium.py +3 -3
- wandb/sdk/internal/system/system_info.py +4 -2
- wandb/sdk/internal/update.py +1 -1
- wandb/sdk/launch/__init__.py +9 -1
- wandb/sdk/launch/_launch.py +4 -24
- wandb/sdk/launch/_launch_add.py +1 -3
- wandb/sdk/launch/_project_spec.py +187 -225
- wandb/sdk/launch/agent/agent.py +59 -19
- wandb/sdk/launch/agent/config.py +0 -3
- wandb/sdk/launch/builder/abstract.py +68 -1
- wandb/sdk/launch/builder/build.py +165 -576
- wandb/sdk/launch/builder/context_manager.py +235 -0
- wandb/sdk/launch/builder/docker_builder.py +7 -23
- wandb/sdk/launch/builder/kaniko_builder.py +12 -25
- wandb/sdk/launch/builder/templates/dockerfile.py +92 -0
- wandb/sdk/launch/create_job.py +51 -45
- wandb/sdk/launch/environment/aws_environment.py +26 -1
- wandb/sdk/launch/inputs/files.py +148 -0
- wandb/sdk/launch/inputs/internal.py +224 -0
- wandb/sdk/launch/inputs/manage.py +95 -0
- wandb/sdk/launch/registry/google_artifact_registry.py +1 -1
- wandb/sdk/launch/runner/abstract.py +2 -2
- wandb/sdk/launch/runner/kubernetes_monitor.py +45 -12
- wandb/sdk/launch/runner/kubernetes_runner.py +6 -8
- wandb/sdk/launch/runner/local_container.py +2 -3
- wandb/sdk/launch/runner/local_process.py +8 -29
- wandb/sdk/launch/runner/sagemaker_runner.py +20 -14
- wandb/sdk/launch/runner/vertex_runner.py +8 -7
- wandb/sdk/launch/sweeps/scheduler.py +5 -3
- wandb/sdk/launch/sweeps/scheduler_sweep.py +1 -1
- wandb/sdk/launch/sweeps/utils.py +4 -4
- wandb/sdk/launch/utils.py +16 -138
- wandb/sdk/lib/_settings_toposort_generated.py +2 -5
- wandb/sdk/lib/apikey.py +4 -2
- wandb/sdk/lib/config_util.py +3 -3
- wandb/sdk/lib/import_hooks.py +1 -1
- wandb/sdk/lib/proto_util.py +22 -1
- wandb/sdk/lib/redirect.py +20 -15
- wandb/sdk/lib/tracelog.py +1 -1
- wandb/sdk/service/service.py +2 -1
- wandb/sdk/service/streams.py +5 -5
- wandb/sdk/wandb_init.py +25 -59
- wandb/sdk/wandb_login.py +28 -25
- wandb/sdk/wandb_run.py +123 -53
- wandb/sdk/wandb_settings.py +33 -64
- wandb/sdk/wandb_setup.py +1 -1
- wandb/sdk/wandb_watch.py +1 -1
- wandb/sklearn/plot/classifier.py +10 -12
- wandb/sklearn/plot/clusterer.py +1 -1
- wandb/sync/sync.py +2 -2
- wandb/testing/relay.py +32 -17
- wandb/util.py +36 -37
- wandb/wandb_agent.py +3 -3
- wandb/wandb_controller.py +5 -4
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/METADATA +8 -10
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/RECORD +140 -162
- wandb/apis/reports/v1/_blocks.py +0 -1406
- wandb/apis/reports/v1/_helpers.py +0 -70
- wandb/apis/reports/v1/_panels.py +0 -1282
- wandb/apis/reports/v1/_templates.py +0 -478
- wandb/apis/reports/v1/blocks.py +0 -27
- wandb/apis/reports/v1/helpers.py +0 -2
- wandb/apis/reports/v1/mutations.py +0 -66
- wandb/apis/reports/v1/panels.py +0 -17
- wandb/apis/reports/v1/report.py +0 -268
- wandb/apis/reports/v1/runset.py +0 -144
- wandb/apis/reports/v1/templates.py +0 -7
- wandb/apis/reports/v1/util.py +0 -406
- wandb/apis/reports/v1/validators.py +0 -131
- wandb/apis/reports/v2/blocks.py +0 -25
- wandb/apis/reports/v2/expr_parsing.py +0 -257
- wandb/apis/reports/v2/gql.py +0 -68
- wandb/apis/reports/v2/interface.py +0 -1911
- wandb/apis/reports/v2/internal.py +0 -867
- wandb/apis/reports/v2/metrics.py +0 -6
- wandb/apis/reports/v2/panels.py +0 -15
- wandb/catboost/__init__.py +0 -9
- wandb/fastai/__init__.py +0 -9
- wandb/keras/__init__.py +0 -19
- wandb/lightgbm/__init__.py +0 -9
- wandb/plots/__init__.py +0 -6
- wandb/plots/explain_text.py +0 -36
- wandb/plots/heatmap.py +0 -81
- wandb/plots/named_entity.py +0 -43
- wandb/plots/part_of_speech.py +0 -50
- wandb/plots/plot_definitions.py +0 -768
- wandb/plots/precision_recall.py +0 -121
- wandb/plots/roc.py +0 -103
- wandb/sacred/__init__.py +0 -3
- wandb/xgboost/__init__.py +0 -9
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/WHEEL +0 -0
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/entry_points.txt +0 -0
- {wandb-0.17.0rc1.dist-info → wandb-0.17.1.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_login.py
CHANGED
@@ -6,7 +6,7 @@ This authenticates your machine to log data to your account.
|
|
6
6
|
import enum
|
7
7
|
import os
|
8
8
|
import sys
|
9
|
-
from typing import
|
9
|
+
from typing import Optional, Tuple
|
10
10
|
|
11
11
|
if sys.version_info >= (3, 8):
|
12
12
|
from typing import Literal
|
@@ -112,11 +112,10 @@ class ApiKeyStatus(enum.Enum):
|
|
112
112
|
|
113
113
|
class _WandbLogin:
|
114
114
|
def __init__(self):
|
115
|
-
self.kwargs: Optional[Dict] = None
|
116
115
|
self._settings: Optional[Settings] = None
|
117
116
|
self._backend = None
|
118
|
-
self._silent = None
|
119
|
-
self._entity = None
|
117
|
+
self._silent: Optional[bool] = None
|
118
|
+
self._entity: Optional[str] = None
|
120
119
|
self._wl = None
|
121
120
|
self._key = None
|
122
121
|
self._relogin = None
|
@@ -130,7 +129,8 @@ class _WandbLogin:
|
|
130
129
|
host: Optional[str] = None,
|
131
130
|
force: Optional[bool] = None,
|
132
131
|
timeout: Optional[int] = None,
|
133
|
-
):
|
132
|
+
) -> None:
|
133
|
+
"""Updates login-related settings on the global setup object."""
|
134
134
|
self._relogin = relogin
|
135
135
|
|
136
136
|
# built up login settings
|
@@ -152,19 +152,24 @@ class _WandbLogin:
|
|
152
152
|
self._wl = wandb.setup(settings=login_settings)
|
153
153
|
self._settings = self._wl.settings
|
154
154
|
|
155
|
-
def is_apikey_configured(self):
|
155
|
+
def is_apikey_configured(self) -> bool:
|
156
|
+
"""Returns whether an API key is set or can be inferred."""
|
156
157
|
return apikey.api_key(settings=self._settings) is not None
|
157
158
|
|
158
159
|
def set_backend(self, backend):
|
159
160
|
self._backend = backend
|
160
161
|
|
161
|
-
def set_silent(self, silent: bool):
|
162
|
+
def set_silent(self, silent: bool) -> None:
|
162
163
|
self._silent = silent
|
163
164
|
|
164
|
-
def set_entity(self, entity: str):
|
165
|
+
def set_entity(self, entity: str) -> None:
|
165
166
|
self._entity = entity
|
166
167
|
|
167
|
-
def login(self):
|
168
|
+
def login(self) -> bool:
|
169
|
+
"""Returns whether the user is logged in (i.e. an API key exists).
|
170
|
+
|
171
|
+
If the user is logged in, this also prints an informational message.
|
172
|
+
"""
|
168
173
|
apikey_configured = self.is_apikey_configured()
|
169
174
|
if self._settings.relogin or self._relogin:
|
170
175
|
apikey_configured = False
|
@@ -172,11 +177,12 @@ class _WandbLogin:
|
|
172
177
|
return False
|
173
178
|
|
174
179
|
if not self._silent:
|
175
|
-
self.
|
180
|
+
self._print_logged_in_message()
|
176
181
|
|
177
182
|
return apikey_configured
|
178
183
|
|
179
|
-
def
|
184
|
+
def _print_logged_in_message(self) -> None:
|
185
|
+
"""Prints a message telling the user they are logged in."""
|
180
186
|
username = self._wl._get_username()
|
181
187
|
|
182
188
|
if username:
|
@@ -200,7 +206,8 @@ class _WandbLogin:
|
|
200
206
|
repeat=False,
|
201
207
|
)
|
202
208
|
|
203
|
-
def configure_api_key(self, key):
|
209
|
+
def configure_api_key(self, key: str) -> None:
|
210
|
+
"""Saves the API key and updates the the global setup object."""
|
204
211
|
if self._settings._notebook and not self._settings.silent:
|
205
212
|
wandb.termwarn(
|
206
213
|
"If you're specifying your api key in code, ensure this "
|
@@ -213,8 +220,14 @@ class _WandbLogin:
|
|
213
220
|
self._key = key
|
214
221
|
|
215
222
|
def update_session(
|
216
|
-
self,
|
223
|
+
self,
|
224
|
+
key: Optional[str],
|
225
|
+
status: ApiKeyStatus = ApiKeyStatus.VALID,
|
217
226
|
) -> None:
|
227
|
+
"""Updates mode and API key settings on the global setup object.
|
228
|
+
|
229
|
+
If we're online, this also pulls in user settings from the server.
|
230
|
+
"""
|
218
231
|
_logger = wandb.setup()._get_logger()
|
219
232
|
login_settings = dict()
|
220
233
|
if status == ApiKeyStatus.OFFLINE:
|
@@ -252,7 +265,8 @@ class _WandbLogin:
|
|
252
265
|
return None, ApiKeyStatus.OFFLINE
|
253
266
|
return key, ApiKeyStatus.VALID
|
254
267
|
|
255
|
-
def prompt_api_key(self):
|
268
|
+
def prompt_api_key(self) -> None:
|
269
|
+
"""Updates the global API key by prompting the user."""
|
256
270
|
key, status = self._prompt_api_key()
|
257
271
|
if status == ApiKeyStatus.NOTTY:
|
258
272
|
directive = (
|
@@ -265,14 +279,6 @@ class _WandbLogin:
|
|
265
279
|
self.update_session(key, status=status)
|
266
280
|
self._key = key
|
267
281
|
|
268
|
-
def propogate_login(self):
|
269
|
-
# TODO(jhr): figure out if this is really necessary
|
270
|
-
if self._backend:
|
271
|
-
# TODO: calling this twice is gross, this deserves a refactor
|
272
|
-
# Make sure our backend picks up the new creds
|
273
|
-
# _ = self._backend.interface.communicate_login(key, anonymous)
|
274
|
-
pass
|
275
|
-
|
276
282
|
|
277
283
|
def _login(
|
278
284
|
*,
|
@@ -333,7 +339,4 @@ def _login(
|
|
333
339
|
if not key:
|
334
340
|
wlogin.prompt_api_key()
|
335
341
|
|
336
|
-
# make sure login credentials get to the backend
|
337
|
-
wlogin.propogate_login()
|
338
|
-
|
339
342
|
return wlogin._key or False
|
wandb/sdk/wandb_run.py
CHANGED
@@ -207,6 +207,15 @@ class RunStatusChecker:
|
|
207
207
|
self._network_status_thread.start()
|
208
208
|
self._internal_messages_thread.start()
|
209
209
|
|
210
|
+
@staticmethod
|
211
|
+
def _abandon_status_check(
|
212
|
+
lock: threading.Lock,
|
213
|
+
handle: Optional[MailboxHandle],
|
214
|
+
):
|
215
|
+
with lock:
|
216
|
+
if handle:
|
217
|
+
handle.abandon()
|
218
|
+
|
210
219
|
def _loop_check_status(
|
211
220
|
self,
|
212
221
|
*,
|
@@ -247,7 +256,7 @@ class RunStatusChecker:
|
|
247
256
|
local_handle = None
|
248
257
|
|
249
258
|
time_elapsed = time.monotonic() - time_probe
|
250
|
-
wait_time = max(
|
259
|
+
wait_time = max(timeout - time_elapsed, 0)
|
251
260
|
join_requested = self._join_event.wait(timeout=wait_time)
|
252
261
|
|
253
262
|
def check_network_status(self) -> None:
|
@@ -265,13 +274,19 @@ class RunStatusChecker:
|
|
265
274
|
)
|
266
275
|
)
|
267
276
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
277
|
+
try:
|
278
|
+
self._loop_check_status(
|
279
|
+
lock=self._network_status_lock,
|
280
|
+
set_handle=lambda x: setattr(self, "_network_status_handle", x),
|
281
|
+
timeout=self._retry_polling_interval,
|
282
|
+
request=self._interface.deliver_network_status,
|
283
|
+
process=_process_network_status,
|
284
|
+
)
|
285
|
+
except BrokenPipeError:
|
286
|
+
self._abandon_status_check(
|
287
|
+
self._network_status_lock,
|
288
|
+
self._network_status_handle,
|
289
|
+
)
|
275
290
|
|
276
291
|
def check_stop_status(self) -> None:
|
277
292
|
def _process_stop_status(result: Result) -> None:
|
@@ -283,13 +298,19 @@ class RunStatusChecker:
|
|
283
298
|
thread.interrupt_main()
|
284
299
|
return
|
285
300
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
301
|
+
try:
|
302
|
+
self._loop_check_status(
|
303
|
+
lock=self._stop_status_lock,
|
304
|
+
set_handle=lambda x: setattr(self, "_stop_status_handle", x),
|
305
|
+
timeout=self._stop_polling_interval,
|
306
|
+
request=self._interface.deliver_stop_status,
|
307
|
+
process=_process_stop_status,
|
308
|
+
)
|
309
|
+
except BrokenPipeError:
|
310
|
+
self._abandon_status_check(
|
311
|
+
self._stop_status_lock,
|
312
|
+
self._stop_status_handle,
|
313
|
+
)
|
293
314
|
|
294
315
|
def check_internal_messages(self) -> None:
|
295
316
|
def _process_internal_messages(result: Result) -> None:
|
@@ -297,25 +318,34 @@ class RunStatusChecker:
|
|
297
318
|
for msg in internal_messages.messages.warning:
|
298
319
|
wandb.termwarn(msg)
|
299
320
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
321
|
+
try:
|
322
|
+
self._loop_check_status(
|
323
|
+
lock=self._internal_messages_lock,
|
324
|
+
set_handle=lambda x: setattr(self, "_internal_messages_handle", x),
|
325
|
+
timeout=1,
|
326
|
+
request=self._interface.deliver_internal_messages,
|
327
|
+
process=_process_internal_messages,
|
328
|
+
)
|
329
|
+
except BrokenPipeError:
|
330
|
+
self._abandon_status_check(
|
331
|
+
self._internal_messages_lock,
|
332
|
+
self._internal_messages_handle,
|
333
|
+
)
|
307
334
|
|
308
335
|
def stop(self) -> None:
|
309
336
|
self._join_event.set()
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
337
|
+
self._abandon_status_check(
|
338
|
+
self._stop_status_lock,
|
339
|
+
self._stop_status_handle,
|
340
|
+
)
|
341
|
+
self._abandon_status_check(
|
342
|
+
self._network_status_lock,
|
343
|
+
self._network_status_handle,
|
344
|
+
)
|
345
|
+
self._abandon_status_check(
|
346
|
+
self._internal_messages_lock,
|
347
|
+
self._internal_messages_handle,
|
348
|
+
)
|
319
349
|
|
320
350
|
def join(self) -> None:
|
321
351
|
self.stop()
|
@@ -676,6 +706,12 @@ class Run:
|
|
676
706
|
"step": self._settings.fork_from.value,
|
677
707
|
}
|
678
708
|
|
709
|
+
if self._settings.resume_from is not None:
|
710
|
+
config[wandb_key]["branch_point"] = {
|
711
|
+
"run_id": self._settings.resume_from.run,
|
712
|
+
"step": self._settings.resume_from.value,
|
713
|
+
}
|
714
|
+
|
679
715
|
self._config._update(config, ignore_locked=True)
|
680
716
|
|
681
717
|
if sweep_config:
|
@@ -1400,6 +1436,10 @@ class Run:
|
|
1400
1436
|
# self._printer.display(line)
|
1401
1437
|
|
1402
1438
|
def _summary_get_current_summary_callback(self) -> Dict[str, Any]:
|
1439
|
+
if self._is_finished:
|
1440
|
+
# TODO: WB-18420: fetch summary from backend and stage it before run is finished
|
1441
|
+
wandb.termwarn("Summary data not available in finished run")
|
1442
|
+
return {}
|
1403
1443
|
if not self._backend or not self._backend.interface:
|
1404
1444
|
return {}
|
1405
1445
|
handle = self._backend.interface.deliver_get_summary()
|
@@ -1792,7 +1832,7 @@ class Run:
|
|
1792
1832
|
import wandb
|
1793
1833
|
|
1794
1834
|
run = wandb.init()
|
1795
|
-
run.log({"pr": wandb.
|
1835
|
+
run.log({"pr": wandb.plot.pr_curve(y_test, y_probas, labels)})
|
1796
1836
|
```
|
1797
1837
|
|
1798
1838
|
### 3D Object
|
@@ -1853,7 +1893,7 @@ class Run:
|
|
1853
1893
|
picked up automatically.
|
1854
1894
|
|
1855
1895
|
A `base_path` may be provided to control the directory structure of
|
1856
|
-
uploaded files. It should be a prefix of `glob_str`, and the
|
1896
|
+
uploaded files. It should be a prefix of `glob_str`, and the directory
|
1857
1897
|
structure beneath it is preserved. It's best understood through
|
1858
1898
|
examples:
|
1859
1899
|
|
@@ -1911,7 +1951,11 @@ class Run:
|
|
1911
1951
|
# Provide a better error message for a common misuse.
|
1912
1952
|
wandb.termlog(f"{glob_str} is a cloud storage url, can't save file to W&B.")
|
1913
1953
|
return []
|
1914
|
-
|
1954
|
+
# NOTE: We use PurePath instead of Path because WindowsPath doesn't
|
1955
|
+
# like asterisks and errors out in resolve(). It also makes logical
|
1956
|
+
# sense: globs aren't real paths, they're just path-like strings.
|
1957
|
+
glob_path = pathlib.PurePath(glob_str)
|
1958
|
+
resolved_glob_path = pathlib.PurePath(os.path.abspath(glob_path))
|
1915
1959
|
|
1916
1960
|
if base_path is not None:
|
1917
1961
|
base_path = pathlib.Path(base_path)
|
@@ -1925,15 +1969,14 @@ class Run:
|
|
1925
1969
|
'wandb.save("/mnt/folder/file.h5", base_path="/mnt")',
|
1926
1970
|
repeat=False,
|
1927
1971
|
)
|
1928
|
-
base_path =
|
1972
|
+
base_path = resolved_glob_path.parent.parent
|
1929
1973
|
|
1930
1974
|
if policy not in ("live", "end", "now"):
|
1931
1975
|
raise ValueError(
|
1932
1976
|
'Only "live", "end" and "now" policies are currently supported.'
|
1933
1977
|
)
|
1934
1978
|
|
1935
|
-
|
1936
|
-
resolved_base_path = base_path.resolve()
|
1979
|
+
resolved_base_path = pathlib.PurePath(os.path.abspath(base_path))
|
1937
1980
|
|
1938
1981
|
return self._save(
|
1939
1982
|
resolved_glob_path,
|
@@ -1943,8 +1986,8 @@ class Run:
|
|
1943
1986
|
|
1944
1987
|
def _save(
|
1945
1988
|
self,
|
1946
|
-
glob_path: pathlib.
|
1947
|
-
base_path: pathlib.
|
1989
|
+
glob_path: pathlib.PurePath,
|
1990
|
+
base_path: pathlib.PurePath,
|
1948
1991
|
policy: "PolicyName",
|
1949
1992
|
) -> List[str]:
|
1950
1993
|
# Can't use is_relative_to() because that's added in Python 3.9,
|
@@ -2440,6 +2483,8 @@ class Run:
|
|
2440
2483
|
self._telemetry_obj_active = True
|
2441
2484
|
self._telemetry_flush()
|
2442
2485
|
|
2486
|
+
self._detect_and_apply_job_inputs()
|
2487
|
+
|
2443
2488
|
# object is about to be returned to the user, don't let them modify it
|
2444
2489
|
self._freeze()
|
2445
2490
|
|
@@ -2447,6 +2492,12 @@ class Run:
|
|
2447
2492
|
if os.path.exists(self._settings.resume_fname):
|
2448
2493
|
os.remove(self._settings.resume_fname)
|
2449
2494
|
|
2495
|
+
def _detect_and_apply_job_inputs(self) -> None:
|
2496
|
+
"""If the user has staged launch inputs, apply them to the run."""
|
2497
|
+
from wandb.sdk.launch.inputs.internal import StagedLaunchInputs
|
2498
|
+
|
2499
|
+
StagedLaunchInputs().apply(self)
|
2500
|
+
|
2450
2501
|
def _make_job_source_reqs(self) -> Tuple[List[str], Dict[str, Any], Dict[str, Any]]:
|
2451
2502
|
from wandb.util import working_set
|
2452
2503
|
|
@@ -2552,6 +2603,14 @@ class Run:
|
|
2552
2603
|
self._console_stop() # TODO: there's a race here with jupyter console logging
|
2553
2604
|
|
2554
2605
|
assert self._backend and self._backend.interface
|
2606
|
+
|
2607
|
+
# get the server info before starting the defer state machine as
|
2608
|
+
# it will stop communication with the server
|
2609
|
+
server_info_handle = self._backend.interface.deliver_request_server_info()
|
2610
|
+
result = server_info_handle.wait(timeout=-1)
|
2611
|
+
assert result
|
2612
|
+
self._server_info_response = result.response.server_info_response
|
2613
|
+
|
2555
2614
|
exit_handle = self._backend.interface.deliver_exit(self._exit_code)
|
2556
2615
|
exit_handle.add_probe(on_probe=self._on_probe_exit)
|
2557
2616
|
|
@@ -2560,6 +2619,7 @@ class Run:
|
|
2560
2619
|
# self._exit_code, settings=self._settings, printer=self._printer
|
2561
2620
|
# )
|
2562
2621
|
|
2622
|
+
# wait for the exit to complete
|
2563
2623
|
_ = exit_handle.wait(timeout=-1, on_progress=self._on_progress_exit)
|
2564
2624
|
|
2565
2625
|
poll_exit_handle = self._backend.interface.deliver_poll_exit()
|
@@ -2577,16 +2637,11 @@ class Run:
|
|
2577
2637
|
|
2578
2638
|
# dispatch all our final requests
|
2579
2639
|
|
2580
|
-
server_info_handle = self._backend.interface.deliver_request_server_info()
|
2581
2640
|
final_summary_handle = self._backend.interface.deliver_get_summary()
|
2582
2641
|
sampled_history_handle = (
|
2583
2642
|
self._backend.interface.deliver_request_sampled_history()
|
2584
2643
|
)
|
2585
2644
|
|
2586
|
-
result = server_info_handle.wait(timeout=-1)
|
2587
|
-
assert result
|
2588
|
-
self._server_info_response = result.response.server_info_response
|
2589
|
-
|
2590
2645
|
result = sampled_history_handle.wait(timeout=-1)
|
2591
2646
|
assert result
|
2592
2647
|
self._sampled_history = result.response.sampled_history_response
|
@@ -2705,12 +2760,23 @@ class Run:
|
|
2705
2760
|
if i not in valid:
|
2706
2761
|
raise wandb.Error(f"Unhandled define_metric() arg: summary op: {i}")
|
2707
2762
|
summary_ops.append(i)
|
2763
|
+
with telemetry.context(run=self) as tel:
|
2764
|
+
tel.feature.metric_summary = True
|
2708
2765
|
goal_cleaned: Optional[str] = None
|
2709
2766
|
if goal is not None:
|
2710
2767
|
goal_cleaned = goal[:3].lower()
|
2711
2768
|
valid_goal = {"min", "max"}
|
2712
2769
|
if goal_cleaned not in valid_goal:
|
2713
2770
|
raise wandb.Error(f"Unhandled define_metric() arg: goal: {goal}")
|
2771
|
+
with telemetry.context(run=self) as tel:
|
2772
|
+
tel.feature.metric_goal = True
|
2773
|
+
if hidden:
|
2774
|
+
with telemetry.context(run=self) as tel:
|
2775
|
+
tel.feature.metric_hidden = True
|
2776
|
+
if step_sync:
|
2777
|
+
with telemetry.context(run=self) as tel:
|
2778
|
+
tel.feature.metric_step_sync = True
|
2779
|
+
|
2714
2780
|
m = wandb_metric.Metric(
|
2715
2781
|
name=name,
|
2716
2782
|
step_metric=step_metric,
|
@@ -2895,6 +2961,7 @@ class Run:
|
|
2895
2961
|
api.use_artifact(
|
2896
2962
|
artifact.id,
|
2897
2963
|
entity_name=r.entity,
|
2964
|
+
project_name=r.project,
|
2898
2965
|
use_as=use_as or artifact_or_name,
|
2899
2966
|
)
|
2900
2967
|
else:
|
@@ -2957,8 +3024,7 @@ class Run:
|
|
2957
3024
|
- `s3://bucket/path`
|
2958
3025
|
You can also pass an Artifact object created by calling
|
2959
3026
|
`wandb.Artifact`.
|
2960
|
-
name: (str, optional) An artifact name.
|
2961
|
-
Valid names can be in the following forms:
|
3027
|
+
name: (str, optional) An artifact name. Valid names can be in the following forms:
|
2962
3028
|
- name:version
|
2963
3029
|
- name:alias
|
2964
3030
|
- digest
|
@@ -3604,7 +3670,11 @@ class Run:
|
|
3604
3670
|
project_url = settings.project_url
|
3605
3671
|
sweep_url = settings.sweep_url
|
3606
3672
|
|
3607
|
-
run_state_str =
|
3673
|
+
run_state_str = (
|
3674
|
+
"Resuming run"
|
3675
|
+
if settings.resumed or settings.resume_from
|
3676
|
+
else "Syncing run"
|
3677
|
+
)
|
3608
3678
|
run_name = settings.run_name
|
3609
3679
|
if not run_name:
|
3610
3680
|
return
|
@@ -3658,7 +3728,7 @@ class Run:
|
|
3658
3728
|
# FOOTER
|
3659
3729
|
# ------------------------------------------------------------------------------
|
3660
3730
|
# Note: All the footer methods are static methods since we want to share the printing logic
|
3661
|
-
# with the service execution path that doesn't have
|
3731
|
+
# with the service execution path that doesn't have access to the run instance
|
3662
3732
|
@staticmethod
|
3663
3733
|
def _footer(
|
3664
3734
|
sampled_history: Optional["SampledHistoryResponse"] = None,
|
@@ -3961,11 +4031,11 @@ class Run:
|
|
3961
4031
|
|
3962
4032
|
# Render summary if available
|
3963
4033
|
if summary:
|
3964
|
-
final_summary = {
|
3965
|
-
|
3966
|
-
|
3967
|
-
|
3968
|
-
|
4034
|
+
final_summary = {}
|
4035
|
+
for item in summary.item:
|
4036
|
+
if item.key.startswith("_") or len(item.nested_key) > 0:
|
4037
|
+
continue
|
4038
|
+
final_summary[item.key] = json.loads(item.value_json)
|
3969
4039
|
|
3970
4040
|
logger.info("rendering summary")
|
3971
4041
|
summary_rows = []
|