wandb 0.17.6__py3-none-any.whl → 0.17.8__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- package_readme.md +47 -53
- wandb/__init__.py +10 -19
- wandb/__init__.pyi +964 -0
- wandb/agents/pyagent.py +1 -2
- wandb/bin/nvidia_gpu_stats +0 -0
- wandb/cli/cli.py +21 -0
- wandb/data_types.py +4 -3
- wandb/env.py +13 -0
- wandb/integration/keras/__init__.py +2 -5
- wandb/integration/keras/callbacks/metrics_logger.py +10 -4
- wandb/integration/keras/callbacks/model_checkpoint.py +0 -5
- wandb/integration/keras/keras.py +11 -0
- wandb/integration/kfp/wandb_logging.py +1 -1
- wandb/integration/lightning/fabric/logger.py +1 -1
- wandb/integration/openai/fine_tuning.py +13 -5
- wandb/integration/ultralytics/pose_utils.py +0 -1
- wandb/proto/v3/wandb_internal_pb2.py +24 -24
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +12 -12
- wandb/proto/v4/wandb_internal_pb2.py +24 -24
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +12 -12
- wandb/proto/v5/wandb_internal_pb2.py +24 -24
- wandb/proto/v5/wandb_settings_pb2.py +2 -2
- wandb/proto/v5/wandb_telemetry_pb2.py +12 -12
- wandb/proto/wandb_deprecated.py +2 -0
- wandb/sdk/artifacts/artifact.py +22 -26
- wandb/sdk/artifacts/artifact_manifest_entry.py +10 -2
- wandb/sdk/artifacts/storage_handlers/gcs_handler.py +31 -0
- wandb/sdk/data_types/_dtypes.py +5 -5
- wandb/sdk/data_types/base_types/media.py +3 -1
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +3 -1
- wandb/sdk/data_types/helper_types/image_mask.py +3 -1
- wandb/sdk/data_types/image.py +3 -1
- wandb/sdk/data_types/saved_model.py +3 -1
- wandb/sdk/data_types/video.py +2 -2
- wandb/sdk/interface/interface.py +17 -16
- wandb/sdk/interface/interface_shared.py +6 -9
- wandb/sdk/internal/datastore.py +1 -1
- wandb/sdk/internal/handler.py +5 -3
- wandb/sdk/internal/internal.py +1 -1
- wandb/sdk/internal/job_builder.py +5 -2
- wandb/sdk/internal/tb_watcher.py +2 -2
- wandb/sdk/internal/update.py +2 -2
- wandb/sdk/launch/builder/kaniko_builder.py +13 -5
- wandb/sdk/launch/create_job.py +2 -0
- wandb/sdk/lib/_settings_toposort_generated.py +1 -0
- wandb/sdk/lib/apikey.py +1 -1
- wandb/sdk/service/service.py +7 -2
- wandb/sdk/service/streams.py +2 -4
- wandb/sdk/wandb_config.py +4 -1
- wandb/sdk/wandb_init.py +59 -8
- wandb/sdk/wandb_manager.py +0 -3
- wandb/sdk/wandb_require.py +22 -1
- wandb/sdk/wandb_run.py +137 -92
- wandb/sdk/wandb_settings.py +26 -2
- wandb/sdk/wandb_setup.py +69 -3
- wandb/sdk/wandb_sweep.py +5 -2
- wandb/testing/relay.py +7 -1
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/METADATA +48 -54
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/RECORD +64 -63
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/WHEEL +0 -0
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/entry_points.txt +0 -0
- {wandb-0.17.6.dist-info → wandb-0.17.8.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/data_types/_dtypes.py
CHANGED
@@ -56,7 +56,7 @@ class TypeRegistry:
|
|
56
56
|
# but will be ultimately treated as a None. Ignoring type since
|
57
57
|
# mypy does not trust that py_obj is a float by the time it is
|
58
58
|
# passed to isnan.
|
59
|
-
if py_obj.__class__
|
59
|
+
if py_obj.__class__ is float and math.isnan(py_obj): # type: ignore
|
60
60
|
return NoneType()
|
61
61
|
|
62
62
|
# TODO: generalize this to handle other config input types
|
@@ -134,7 +134,7 @@ def _params_obj_to_json_obj(
|
|
134
134
|
artifact: t.Optional["Artifact"] = None,
|
135
135
|
) -> t.Any:
|
136
136
|
"""Helper method."""
|
137
|
-
if params_obj.__class__
|
137
|
+
if params_obj.__class__ is dict:
|
138
138
|
return {
|
139
139
|
key: _params_obj_to_json_obj(params_obj[key], artifact)
|
140
140
|
for key in params_obj
|
@@ -151,7 +151,7 @@ def _json_obj_to_params_obj(
|
|
151
151
|
json_obj: t.Any, artifact: t.Optional["Artifact"] = None
|
152
152
|
) -> t.Any:
|
153
153
|
"""Helper method."""
|
154
|
-
if json_obj.__class__
|
154
|
+
if json_obj.__class__ is dict:
|
155
155
|
if "wb_type" in json_obj:
|
156
156
|
return TypeRegistry.type_from_dict(json_obj, artifact)
|
157
157
|
else:
|
@@ -159,7 +159,7 @@ def _json_obj_to_params_obj(
|
|
159
159
|
key: _json_obj_to_params_obj(json_obj[key], artifact)
|
160
160
|
for key in json_obj
|
161
161
|
}
|
162
|
-
elif json_obj.__class__
|
162
|
+
elif json_obj.__class__ is list:
|
163
163
|
return [_json_obj_to_params_obj(item, artifact) for item in json_obj]
|
164
164
|
else:
|
165
165
|
return json_obj
|
@@ -533,7 +533,7 @@ class UnionType(Type):
|
|
533
533
|
self,
|
534
534
|
allowed_types: t.Optional[t.Sequence[ConvertibleToType]] = None,
|
535
535
|
):
|
536
|
-
assert allowed_types is None or (allowed_types.__class__
|
536
|
+
assert allowed_types is None or (allowed_types.__class__ is list)
|
537
537
|
if allowed_types is None:
|
538
538
|
wb_types = []
|
539
539
|
else:
|
@@ -159,9 +159,11 @@ class Media(WBValue):
|
|
159
159
|
# into Media itself we should get rid of them
|
160
160
|
from wandb import Image
|
161
161
|
from wandb.data_types import Audio
|
162
|
+
from wandb.sdk.wandb_run import Run
|
162
163
|
|
163
164
|
json_obj = {}
|
164
|
-
|
165
|
+
|
166
|
+
if isinstance(run, Run):
|
165
167
|
json_obj.update(
|
166
168
|
{
|
167
169
|
"_type": "file", # TODO(adrian): This isn't (yet) a real media type we support on the frontend.
|
@@ -276,7 +276,9 @@ class BoundingBoxes2D(JSONMetadata):
|
|
276
276
|
return True
|
277
277
|
|
278
278
|
def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
|
279
|
-
|
279
|
+
from wandb.sdk.wandb_run import Run
|
280
|
+
|
281
|
+
if isinstance(run_or_artifact, Run):
|
280
282
|
return super().to_json(run_or_artifact)
|
281
283
|
elif isinstance(run_or_artifact, wandb.Artifact):
|
282
284
|
# TODO (tim): I would like to log out a proper dictionary representing this object, but don't
|
@@ -191,9 +191,11 @@ class ImageMask(Media):
|
|
191
191
|
)
|
192
192
|
|
193
193
|
def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
|
194
|
+
from wandb.sdk.wandb_run import Run
|
195
|
+
|
194
196
|
json_dict = super().to_json(run_or_artifact)
|
195
197
|
|
196
|
-
if isinstance(run_or_artifact,
|
198
|
+
if isinstance(run_or_artifact, Run):
|
197
199
|
json_dict["_type"] = self.type_name()
|
198
200
|
return json_dict
|
199
201
|
elif isinstance(run_or_artifact, wandb.Artifact):
|
wandb/sdk/data_types/image.py
CHANGED
@@ -418,6 +418,8 @@ class Image(BatchableMedia):
|
|
418
418
|
)
|
419
419
|
|
420
420
|
def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
|
421
|
+
from wandb.sdk.wandb_run import Run
|
422
|
+
|
421
423
|
json_dict = super().to_json(run_or_artifact)
|
422
424
|
json_dict["_type"] = Image._log_type
|
423
425
|
json_dict["format"] = self.format
|
@@ -456,7 +458,7 @@ class Image(BatchableMedia):
|
|
456
458
|
"digest": classes_entry.digest,
|
457
459
|
}
|
458
460
|
|
459
|
-
elif not isinstance(run_or_artifact,
|
461
|
+
elif not isinstance(run_or_artifact, Run):
|
460
462
|
raise ValueError("to_json accepts wandb_run.Run or wandb_artifact.Artifact")
|
461
463
|
|
462
464
|
if self._boxes:
|
@@ -148,7 +148,9 @@ class _SavedModel(WBValue, Generic[SavedModelObjType]):
|
|
148
148
|
# bit of tech debt in the other data types which requires the input to `to_json`
|
149
149
|
# to accept a Run or Artifact. However, Run additions should be deprecated in the future.
|
150
150
|
# This check helps ensure we do not add to the debt.
|
151
|
-
|
151
|
+
from wandb.sdk.wandb_run import Run
|
152
|
+
|
153
|
+
if isinstance(run_or_artifact, Run):
|
152
154
|
raise ValueError("SavedModel cannot be added to run - must use artifact")
|
153
155
|
artifact = run_or_artifact
|
154
156
|
json_obj = {
|
wandb/sdk/data_types/video.py
CHANGED
@@ -214,9 +214,9 @@ class Video(BatchableMedia):
|
|
214
214
|
n_rows = 2 ** ((b.bit_length() - 1) // 2)
|
215
215
|
n_cols = video.shape[0] // n_rows
|
216
216
|
|
217
|
-
video =
|
217
|
+
video = video.reshape(n_rows, n_cols, t, c, h, w)
|
218
218
|
video = np.transpose(video, axes=(2, 0, 4, 1, 5, 3))
|
219
|
-
video =
|
219
|
+
video = video.reshape(t, n_rows * h, n_cols * w, c)
|
220
220
|
return video
|
221
221
|
|
222
222
|
@classmethod
|
wandb/sdk/interface/interface.py
CHANGED
@@ -54,18 +54,20 @@ MANIFEST_FILE_SIZE_THRESHOLD = 100_000
|
|
54
54
|
|
55
55
|
GlobStr = NewType("GlobStr", str)
|
56
56
|
|
57
|
-
if
|
58
|
-
from
|
57
|
+
if sys.version_info >= (3, 8):
|
58
|
+
from typing import Literal, TypedDict
|
59
|
+
else:
|
60
|
+
from typing_extensions import Literal, TypedDict
|
61
|
+
|
62
|
+
PolicyName = Literal["now", "live", "end"]
|
59
63
|
|
60
|
-
if sys.version_info >= (3, 8):
|
61
|
-
from typing import Literal, TypedDict
|
62
|
-
else:
|
63
|
-
from typing_extensions import Literal, TypedDict
|
64
64
|
|
65
|
-
|
65
|
+
class FilesDict(TypedDict):
|
66
|
+
files: Iterable[Tuple[GlobStr, PolicyName]]
|
66
67
|
|
67
|
-
|
68
|
-
|
68
|
+
|
69
|
+
if TYPE_CHECKING:
|
70
|
+
from ..wandb_run import Run
|
69
71
|
|
70
72
|
|
71
73
|
logger = logging.getLogger("wandb")
|
@@ -112,15 +114,14 @@ class InterfaceBase:
|
|
112
114
|
def _publish_header(self, header: pb.HeaderRecord) -> None:
|
113
115
|
raise NotImplementedError
|
114
116
|
|
115
|
-
def
|
116
|
-
|
117
|
-
resp = self._communicate_status(status)
|
118
|
-
return resp
|
117
|
+
def deliver_status(self) -> MailboxHandle:
|
118
|
+
return self._deliver_status(pb.StatusRequest())
|
119
119
|
|
120
120
|
@abstractmethod
|
121
|
-
def
|
122
|
-
self,
|
123
|
-
|
121
|
+
def _deliver_status(
|
122
|
+
self,
|
123
|
+
status: pb.StatusRequest,
|
124
|
+
) -> MailboxHandle:
|
124
125
|
raise NotImplementedError
|
125
126
|
|
126
127
|
def _make_config(
|
@@ -299,7 +299,7 @@ class InterfaceShared(InterfaceBase):
|
|
299
299
|
raise NotImplementedError
|
300
300
|
|
301
301
|
def _communicate(
|
302
|
-
self, rec: pb.Record, timeout: Optional[int] =
|
302
|
+
self, rec: pb.Record, timeout: Optional[int] = 30, local: Optional[bool] = None
|
303
303
|
) -> Optional[pb.Result]:
|
304
304
|
return self._communicate_async(rec, local=local).get(timeout=timeout)
|
305
305
|
|
@@ -421,15 +421,12 @@ class InterfaceShared(InterfaceBase):
|
|
421
421
|
rec = self._make_record(alert=proto_alert)
|
422
422
|
self._publish(rec)
|
423
423
|
|
424
|
-
def
|
425
|
-
self,
|
426
|
-
|
424
|
+
def _deliver_status(
|
425
|
+
self,
|
426
|
+
status: pb.StatusRequest,
|
427
|
+
) -> MailboxHandle:
|
427
428
|
req = self._make_request(status=status)
|
428
|
-
|
429
|
-
if resp is None:
|
430
|
-
return None
|
431
|
-
assert resp.response.status_response
|
432
|
-
return resp.response.status_response
|
429
|
+
return self._deliver_record(req)
|
433
430
|
|
434
431
|
def _publish_exit(self, exit_data: pb.RunExitRecord) -> None:
|
435
432
|
rec = self._make_record(exit=exit_data)
|
wandb/sdk/internal/datastore.py
CHANGED
wandb/sdk/internal/handler.py
CHANGED
@@ -660,7 +660,11 @@ class HandleManager:
|
|
660
660
|
self._dispatch_record(record)
|
661
661
|
|
662
662
|
def handle_request_check_version(self, record: Record) -> None:
|
663
|
-
self.
|
663
|
+
if self._settings._offline:
|
664
|
+
result = proto_util._result_from_record(record)
|
665
|
+
self._respond_result(result)
|
666
|
+
else:
|
667
|
+
self._dispatch_record(record)
|
664
668
|
|
665
669
|
def handle_request_attach(self, record: Record) -> None:
|
666
670
|
result = proto_util._result_from_record(record)
|
@@ -745,8 +749,6 @@ class HandleManager:
|
|
745
749
|
self._respond_result(result)
|
746
750
|
|
747
751
|
def handle_request_status(self, record: Record) -> None:
|
748
|
-
# TODO(mempressure): do something better?
|
749
|
-
assert record.control.req_resp
|
750
752
|
result = proto_util._result_from_record(record)
|
751
753
|
self._respond_result(result)
|
752
754
|
|
wandb/sdk/internal/internal.py
CHANGED
@@ -423,15 +423,18 @@ class JobBuilder:
|
|
423
423
|
api: Api,
|
424
424
|
build_context: Optional[str] = None,
|
425
425
|
dockerfile: Optional[str] = None,
|
426
|
+
base_image: Optional[str] = None,
|
426
427
|
) -> Optional[Artifact]:
|
427
428
|
"""Build a job artifact from the current run.
|
428
429
|
|
429
430
|
Arguments:
|
431
|
+
api (Api): The API object to use to create the job artifact.
|
430
432
|
build_context (Optional[str]): Path within the job source code to
|
431
433
|
the image build context. Saved as part of the job for future
|
432
434
|
builds.
|
433
435
|
dockerfile (Optional[str]): Path within the build context the
|
434
436
|
Dockerfile. Saved as part of the job for future builds.
|
437
|
+
base_image (Optional[str]): The base image used to run the job code.
|
435
438
|
|
436
439
|
Returns:
|
437
440
|
Optional[Artifact]: The job artifact if it was successfully built,
|
@@ -467,8 +470,6 @@ class JobBuilder:
|
|
467
470
|
"warn",
|
468
471
|
)
|
469
472
|
return None
|
470
|
-
metadata["dockerfile"] = dockerfile
|
471
|
-
metadata["build_context"] = build_context
|
472
473
|
|
473
474
|
runtime: Optional[str] = metadata.get("python")
|
474
475
|
# can't build a job without a python version
|
@@ -520,6 +521,8 @@ class JobBuilder:
|
|
520
521
|
source["build_context"] = build_context # type: ignore[typeddict-item]
|
521
522
|
if dockerfile:
|
522
523
|
source["dockerfile"] = dockerfile # type: ignore[typeddict-item]
|
524
|
+
if base_image:
|
525
|
+
source["base_image"] = base_image # type: ignore[typeddict-item]
|
523
526
|
|
524
527
|
# Pop any keys that are initialized to None. The current TypedDict
|
525
528
|
# system for source dicts requires all keys to be present, but we
|
wandb/sdk/internal/tb_watcher.py
CHANGED
@@ -123,7 +123,7 @@ class TBWatcher:
|
|
123
123
|
self._force = force
|
124
124
|
# TODO(jhr): do we need locking in this queue?
|
125
125
|
self._watcher_queue = queue.PriorityQueue()
|
126
|
-
wandb.tensorboard.reset_state()
|
126
|
+
wandb.tensorboard.reset_state() # type: ignore
|
127
127
|
|
128
128
|
def _calculate_namespace(self, logdir: str, rootdir: str) -> Optional[str]:
|
129
129
|
namespace: Optional[str]
|
@@ -430,7 +430,7 @@ class TBEventConsumer:
|
|
430
430
|
def _handle_event(
|
431
431
|
self, event: "ProtoEvent", history: Optional["TBHistory"] = None
|
432
432
|
) -> None:
|
433
|
-
wandb.tensorboard._log(
|
433
|
+
wandb.tensorboard._log( # type: ignore
|
434
434
|
event.event,
|
435
435
|
step=event.event.step,
|
436
436
|
namespace=event.namespace,
|
wandb/sdk/internal/update.py
CHANGED
@@ -10,7 +10,7 @@ def _find_available(
|
|
10
10
|
) -> Optional[Tuple[str, bool, bool, bool, Optional[str]]]:
|
11
11
|
from wandb.util import parse_version
|
12
12
|
|
13
|
-
pypi_url =
|
13
|
+
pypi_url = "https://pypi.org/pypi/wandb/json"
|
14
14
|
|
15
15
|
yanked_dict = {}
|
16
16
|
try:
|
@@ -78,7 +78,7 @@ def check_available(current_version: str) -> Optional[Dict[str, Optional[str]]]:
|
|
78
78
|
if not package_info:
|
79
79
|
return None
|
80
80
|
|
81
|
-
wandb_module_name = wandb
|
81
|
+
wandb_module_name = "wandb"
|
82
82
|
|
83
83
|
latest_version, pip_prerelease, deleted, yanked, yanked_reason = package_info
|
84
84
|
upgrade_message = (
|
@@ -63,6 +63,13 @@ else:
|
|
63
63
|
NAMESPACE = "wandb"
|
64
64
|
|
65
65
|
|
66
|
+
def get_pod_name_safe(job: client.V1Job):
|
67
|
+
try:
|
68
|
+
return job.spec.template.metadata.name
|
69
|
+
except AttributeError:
|
70
|
+
return None
|
71
|
+
|
72
|
+
|
66
73
|
async def _wait_for_completion(
|
67
74
|
batch_client: client.BatchV1Api, job_name: str, deadline_secs: Optional[int] = None
|
68
75
|
) -> bool:
|
@@ -319,17 +326,18 @@ class KanikoBuilder(AbstractBuilder):
|
|
319
326
|
await self._create_docker_ecr_config_map(
|
320
327
|
build_job_name, core_v1, repo_uri
|
321
328
|
)
|
322
|
-
await batch_v1.create_namespaced_job(NAMESPACE, build_job)
|
323
|
-
|
329
|
+
k8s_job = await batch_v1.create_namespaced_job(NAMESPACE, build_job)
|
324
330
|
# wait for double the job deadline since it might take time to schedule
|
325
331
|
if not await _wait_for_completion(
|
326
332
|
batch_v1, build_job_name, 3 * _DEFAULT_BUILD_TIMEOUT_SECS
|
327
333
|
):
|
328
334
|
if job_tracker:
|
329
335
|
job_tracker.set_err_stage("build")
|
330
|
-
|
331
|
-
|
332
|
-
|
336
|
+
msg = f"Failed to build image in kaniko for job {run_id}."
|
337
|
+
pod_name = get_pod_name_safe(k8s_job)
|
338
|
+
if pod_name:
|
339
|
+
msg += f" View logs with `kubectl logs -n {NAMESPACE} {pod_name}`."
|
340
|
+
raise Exception(msg)
|
333
341
|
try:
|
334
342
|
pods_from_job = await core_v1.list_namespaced_pod(
|
335
343
|
namespace=NAMESPACE, label_selector=f"job-name={build_job_name}"
|
wandb/sdk/launch/create_job.py
CHANGED
@@ -114,6 +114,7 @@ def _create_job(
|
|
114
114
|
git_hash: Optional[str] = None,
|
115
115
|
build_context: Optional[str] = None,
|
116
116
|
dockerfile: Optional[str] = None,
|
117
|
+
base_image: Optional[str] = None,
|
117
118
|
) -> Tuple[Optional[Artifact], str, List[str]]:
|
118
119
|
wandb.termlog(f"Creating launch job of type: {job_type}...")
|
119
120
|
|
@@ -188,6 +189,7 @@ def _create_job(
|
|
188
189
|
api.api,
|
189
190
|
dockerfile=dockerfile,
|
190
191
|
build_context=build_context,
|
192
|
+
base_image=base_image,
|
191
193
|
)
|
192
194
|
if not artifact:
|
193
195
|
wandb.termerror("JobBuilder failed to build a job")
|
wandb/sdk/lib/apikey.py
CHANGED
@@ -107,7 +107,7 @@ def prompt_api_key( # noqa: C901
|
|
107
107
|
|
108
108
|
if jupyter and "google.colab" in sys.modules:
|
109
109
|
log_string = term.LOG_STRING_NOCOLOR
|
110
|
-
key = wandb.jupyter.attempt_colab_login(app_url)
|
110
|
+
key = wandb.jupyter.attempt_colab_login(app_url) # type: ignore
|
111
111
|
if key is not None:
|
112
112
|
write_key(settings, key, api=api)
|
113
113
|
return key # type: ignore
|
wandb/sdk/service/service.py
CHANGED
@@ -15,7 +15,12 @@ import time
|
|
15
15
|
from typing import TYPE_CHECKING, Any, Dict, Optional
|
16
16
|
|
17
17
|
from wandb import _sentry, termlog
|
18
|
-
from wandb.env import
|
18
|
+
from wandb.env import (
|
19
|
+
core_debug,
|
20
|
+
core_error_reporting_enabled,
|
21
|
+
is_require_core,
|
22
|
+
is_require_legacy_service,
|
23
|
+
)
|
19
24
|
from wandb.errors import Error, WandbCoreNotAvailableError
|
20
25
|
from wandb.sdk.lib.wburls import wburls
|
21
26
|
from wandb.util import get_core_path, get_module
|
@@ -164,7 +169,7 @@ class _Service:
|
|
164
169
|
|
165
170
|
service_args = []
|
166
171
|
|
167
|
-
if is_require_core():
|
172
|
+
if is_require_core() and not is_require_legacy_service():
|
168
173
|
try:
|
169
174
|
core_path = get_core_path()
|
170
175
|
except WandbCoreNotAvailableError as e:
|
wandb/sdk/service/streams.py
CHANGED
@@ -81,9 +81,7 @@ class StreamRecord:
|
|
81
81
|
self._wait_thread_active()
|
82
82
|
|
83
83
|
def _wait_thread_active(self) -> None:
|
84
|
-
|
85
|
-
# TODO: using the default communicate timeout, is that enough? retries?
|
86
|
-
assert result
|
84
|
+
self._iface.deliver_status().wait(timeout=-1)
|
87
85
|
|
88
86
|
def join(self) -> None:
|
89
87
|
self._iface.join()
|
@@ -212,7 +210,7 @@ class StreamMux:
|
|
212
210
|
# run_id = action.stream_id # will want to fix if a streamid != runid
|
213
211
|
settings = action._data
|
214
212
|
thread = StreamThread(
|
215
|
-
target=wandb.wandb_sdk.internal.internal.wandb_internal,
|
213
|
+
target=wandb.wandb_sdk.internal.internal.wandb_internal, # type: ignore
|
216
214
|
kwargs=dict(
|
217
215
|
settings=settings,
|
218
216
|
record_q=stream._record_q,
|
wandb/sdk/wandb_config.py
CHANGED
@@ -61,7 +61,7 @@ class Config:
|
|
61
61
|
|
62
62
|
Using absl flags
|
63
63
|
```
|
64
|
-
flags.DEFINE_string(
|
64
|
+
flags.DEFINE_string("model", None, "model to run") # name, default, help
|
65
65
|
wandb.config.update(flags.FLAGS) # adds all absl flags to config
|
66
66
|
```
|
67
67
|
|
@@ -129,6 +129,9 @@ class Config:
|
|
129
129
|
def __getitem__(self, key):
|
130
130
|
return self._items[key]
|
131
131
|
|
132
|
+
def __iter__(self):
|
133
|
+
return iter(self._items)
|
134
|
+
|
132
135
|
def _check_locked(self, key, ignore_locked=False) -> bool:
|
133
136
|
locked = self._locked.get(key)
|
134
137
|
if locked is not None:
|
wandb/sdk/wandb_init.py
CHANGED
@@ -15,6 +15,7 @@ import os
|
|
15
15
|
import platform
|
16
16
|
import sys
|
17
17
|
import tempfile
|
18
|
+
import time
|
18
19
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union
|
19
20
|
|
20
21
|
import wandb
|
@@ -174,7 +175,9 @@ class _WandbInit:
|
|
174
175
|
# we add this logic to be backward compatible with the old behavior of disable
|
175
176
|
# where it would disable the service if the mode was set to disabled
|
176
177
|
mode = kwargs.get("mode")
|
177
|
-
settings_mode = (kwargs.get("settings") or {}).get("mode")
|
178
|
+
settings_mode = (kwargs.get("settings") or {}).get("mode") or os.environ.get(
|
179
|
+
"WANDB_MODE"
|
180
|
+
)
|
178
181
|
_disable_service = mode == "disabled" or settings_mode == "disabled"
|
179
182
|
setup_settings = {"_disable_service": _disable_service}
|
180
183
|
|
@@ -262,7 +265,7 @@ class _WandbInit:
|
|
262
265
|
|
263
266
|
monitor_gym = kwargs.pop("monitor_gym", None)
|
264
267
|
if monitor_gym and len(wandb.patched["gym"]) == 0:
|
265
|
-
wandb.gym.monitor()
|
268
|
+
wandb.gym.monitor() # type: ignore
|
266
269
|
|
267
270
|
if wandb.patched["tensorboard"]:
|
268
271
|
with telemetry.context(obj=self._init_telemetry_obj) as tel:
|
@@ -271,7 +274,7 @@ class _WandbInit:
|
|
271
274
|
tensorboard = kwargs.pop("tensorboard", None)
|
272
275
|
sync_tensorboard = kwargs.pop("sync_tensorboard", None)
|
273
276
|
if tensorboard or sync_tensorboard and len(wandb.patched["tensorboard"]) == 0:
|
274
|
-
wandb.tensorboard.patch()
|
277
|
+
wandb.tensorboard.patch() # type: ignore
|
275
278
|
with telemetry.context(obj=self._init_telemetry_obj) as tel:
|
276
279
|
tel.feature.tensorboard_sync = True
|
277
280
|
|
@@ -459,7 +462,7 @@ class _WandbInit:
|
|
459
462
|
|
460
463
|
def _jupyter_setup(self, settings: Settings) -> None:
|
461
464
|
"""Add hooks, and session history saving."""
|
462
|
-
self.notebook = wandb.jupyter.Notebook(settings)
|
465
|
+
self.notebook = wandb.jupyter.Notebook(settings) # type: ignore
|
463
466
|
ipython = self.notebook.shell
|
464
467
|
|
465
468
|
# Monkey patch ipython publish to capture displayed outputs
|
@@ -522,17 +525,62 @@ class _WandbInit:
|
|
522
525
|
logger.info(f"Logging internal logs to {settings.log_internal}")
|
523
526
|
|
524
527
|
def _make_run_disabled(self) -> Run:
|
528
|
+
"""Returns a Run-like object where all methods are no-ops.
|
529
|
+
|
530
|
+
This method is used when wandb.init(mode="disabled") is called or WANDB_MODE=disabled
|
531
|
+
is set. It creates a Run object that mimics the behavior of a normal Run but doesn't
|
532
|
+
communicate with the W&B servers.
|
533
|
+
|
534
|
+
The returned Run object has all expected attributes and methods, but they are
|
535
|
+
no-op versions that don't perform any actual logging or communication.
|
536
|
+
"""
|
525
537
|
drun = Run(settings=Settings(mode="disabled", files_dir=tempfile.gettempdir()))
|
526
|
-
|
538
|
+
# config and summary objects
|
539
|
+
drun._config = wandb.sdk.wandb_config.Config()
|
527
540
|
drun._config.update(self.sweep_config)
|
528
541
|
drun._config.update(self.config)
|
529
542
|
drun.summary = SummaryDisabled() # type: ignore
|
543
|
+
# methods
|
530
544
|
drun.log = lambda data, *_, **__: drun.summary.update(data) # type: ignore
|
531
545
|
drun.finish = lambda *_, **__: module.unset_globals() # type: ignore
|
546
|
+
drun.join = drun.finish # type: ignore
|
547
|
+
drun.define_metric = lambda *_, **__: wandb.sdk.wandb_metric.Metric("dummy") # type: ignore
|
548
|
+
drun.save = lambda *_, **__: False # type: ignore
|
549
|
+
for symbol in (
|
550
|
+
"alert",
|
551
|
+
"finish_artifact",
|
552
|
+
"get_project_url",
|
553
|
+
"get_sweep_url",
|
554
|
+
"get_url",
|
555
|
+
"link_artifact",
|
556
|
+
"link_model",
|
557
|
+
"use_artifact",
|
558
|
+
"log_artifact",
|
559
|
+
"log_code",
|
560
|
+
"log_model",
|
561
|
+
"use_model",
|
562
|
+
"mark_preempting",
|
563
|
+
"plot_table",
|
564
|
+
"restore",
|
565
|
+
"status",
|
566
|
+
"watch",
|
567
|
+
"unwatch",
|
568
|
+
"upsert_artifact",
|
569
|
+
):
|
570
|
+
setattr(drun, symbol, lambda *_, **__: None) # type: ignore
|
571
|
+
# attributes
|
532
572
|
drun._step = 0
|
573
|
+
drun._attach_id = None
|
533
574
|
drun._run_obj = None
|
534
575
|
drun._run_id = runid.generate_id()
|
535
576
|
drun._name = "dummy-" + drun.id
|
577
|
+
drun._project = "dummy"
|
578
|
+
drun._entity = "dummy"
|
579
|
+
drun._tags = tuple()
|
580
|
+
drun._notes = None
|
581
|
+
drun._group = None
|
582
|
+
drun._start_time = time.time()
|
583
|
+
drun._starting_step = 0
|
536
584
|
module.set_global(
|
537
585
|
run=drun,
|
538
586
|
config=drun.config,
|
@@ -688,7 +736,10 @@ class _WandbInit:
|
|
688
736
|
tel.feature.flow_control_disabled = True
|
689
737
|
if self.settings._flow_control_custom:
|
690
738
|
tel.feature.flow_control_custom = True
|
691
|
-
if
|
739
|
+
if (
|
740
|
+
self.settings._require_core
|
741
|
+
and not self.settings._require_legacy_service
|
742
|
+
):
|
692
743
|
tel.feature.core = True
|
693
744
|
if self.settings._shared:
|
694
745
|
wandb.termwarn(
|
@@ -868,7 +919,7 @@ def _attach(
|
|
868
919
|
raise UsageError(
|
869
920
|
"Either `attach_id` or `run_id` must be specified or `run` must have `_attach_id`"
|
870
921
|
)
|
871
|
-
wandb._assert_is_user_process()
|
922
|
+
wandb._assert_is_user_process() # type: ignore
|
872
923
|
|
873
924
|
_wl = wandb_setup._setup()
|
874
925
|
assert _wl
|
@@ -1157,7 +1208,7 @@ def init(
|
|
1157
1208
|
Returns:
|
1158
1209
|
A `Run` object.
|
1159
1210
|
"""
|
1160
|
-
wandb._assert_is_user_process()
|
1211
|
+
wandb._assert_is_user_process() # type: ignore
|
1161
1212
|
|
1162
1213
|
kwargs = dict(locals())
|
1163
1214
|
|
wandb/sdk/wandb_manager.py
CHANGED
@@ -13,7 +13,6 @@ import wandb
|
|
13
13
|
from wandb import env, trigger
|
14
14
|
from wandb.errors import Error
|
15
15
|
from wandb.sdk.lib.exit_hooks import ExitHooks
|
16
|
-
from wandb.sdk.lib.import_hooks import unregister_all_post_import_hooks
|
17
16
|
|
18
17
|
if TYPE_CHECKING:
|
19
18
|
from wandb.proto import wandb_settings_pb2
|
@@ -163,8 +162,6 @@ class _Manager:
|
|
163
162
|
This sends a teardown record to the process. An exception is raised if
|
164
163
|
the process has already been shut down.
|
165
164
|
"""
|
166
|
-
unregister_all_post_import_hooks()
|
167
|
-
|
168
165
|
if self._atexit_lambda:
|
169
166
|
atexit.unregister(self._atexit_lambda)
|
170
167
|
self._atexit_lambda = None
|
wandb/sdk/wandb_require.py
CHANGED
@@ -13,7 +13,12 @@ import os
|
|
13
13
|
from typing import Optional, Sequence, Union
|
14
14
|
|
15
15
|
import wandb
|
16
|
-
from wandb.env import
|
16
|
+
from wandb.env import (
|
17
|
+
_REQUIRE_CORE,
|
18
|
+
_REQUIRE_LEGACY_SERVICE,
|
19
|
+
is_require_core,
|
20
|
+
is_require_legacy_service,
|
21
|
+
)
|
17
22
|
from wandb.errors import UnsupportedError
|
18
23
|
from wandb.sdk import wandb_run
|
19
24
|
from wandb.sdk.lib.wburls import wburls
|
@@ -41,8 +46,24 @@ class _Requires:
|
|
41
46
|
self._require_service()
|
42
47
|
|
43
48
|
def require_core(self) -> None:
|
49
|
+
if is_require_legacy_service():
|
50
|
+
raise UnsupportedError(
|
51
|
+
'Cannot use wandb.require("core") because legacy-service'
|
52
|
+
" is already required--did you use"
|
53
|
+
' wandb.require("legacy-service") or set the'
|
54
|
+
" WANDB__REQUIRE_LEGACY_SERVICE environment variable?"
|
55
|
+
)
|
44
56
|
os.environ[_REQUIRE_CORE] = "true"
|
45
57
|
|
58
|
+
def require_legacy_service(self) -> None:
|
59
|
+
if is_require_core():
|
60
|
+
raise UnsupportedError(
|
61
|
+
'Cannot use wandb.require("legacy-service") because core'
|
62
|
+
' is already required--did you use wandb.require("core")'
|
63
|
+
" or set the WANDB__REQUIRE_CORE environment variable?"
|
64
|
+
)
|
65
|
+
os.environ[_REQUIRE_LEGACY_SERVICE] = "true"
|
66
|
+
|
46
67
|
def apply(self) -> None:
|
47
68
|
"""Call require_* method for supported features."""
|
48
69
|
last_message: str = ""
|