wandb 0.20.2rc20250616__py3-none-macosx_11_0_arm64.whl → 0.21.1__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 +16 -14
- wandb/__init__.pyi +450 -472
- wandb/agents/pyagent.py +41 -12
- wandb/analytics/sentry.py +7 -2
- wandb/apis/importers/mlflow.py +1 -1
- wandb/apis/internal.py +3 -0
- wandb/apis/paginator.py +17 -4
- wandb/apis/public/__init__.py +1 -1
- wandb/apis/public/api.py +606 -359
- wandb/apis/public/artifacts.py +214 -16
- wandb/apis/public/automations.py +19 -3
- wandb/apis/public/files.py +177 -38
- wandb/apis/public/history.py +67 -15
- wandb/apis/public/integrations.py +25 -2
- wandb/apis/public/jobs.py +90 -2
- wandb/apis/public/projects.py +161 -69
- wandb/apis/public/query_generator.py +11 -1
- wandb/apis/public/registries/registries_search.py +7 -15
- wandb/apis/public/reports.py +147 -13
- wandb/apis/public/runs.py +315 -128
- wandb/apis/public/sweeps.py +222 -22
- wandb/apis/public/teams.py +41 -4
- wandb/apis/public/users.py +45 -4
- wandb/automations/__init__.py +10 -10
- wandb/automations/_filters/run_metrics.py +0 -2
- wandb/automations/_utils.py +0 -2
- wandb/automations/actions.py +0 -2
- wandb/automations/automations.py +0 -2
- wandb/automations/events.py +0 -2
- wandb/beta/workflows.py +66 -30
- wandb/bin/gpu_stats +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +80 -1
- wandb/env.py +8 -0
- wandb/errors/errors.py +4 -1
- wandb/integration/catboost/catboost.py +6 -2
- wandb/integration/kfp/kfp_patch.py +3 -1
- wandb/integration/lightning/fabric/logger.py +3 -4
- wandb/integration/metaflow/__init__.py +6 -0
- wandb/integration/metaflow/data_pandas.py +74 -0
- wandb/integration/metaflow/errors.py +13 -0
- wandb/integration/metaflow/metaflow.py +205 -190
- wandb/integration/openai/fine_tuning.py +1 -2
- wandb/integration/sb3/sb3.py +3 -3
- wandb/integration/ultralytics/callback.py +6 -2
- wandb/jupyter.py +5 -5
- wandb/plot/__init__.py +2 -0
- wandb/plot/bar.py +30 -29
- wandb/plot/confusion_matrix.py +75 -71
- wandb/plot/custom_chart.py +30 -7
- wandb/plot/histogram.py +26 -25
- wandb/plot/line.py +33 -32
- wandb/plot/line_series.py +100 -103
- wandb/plot/pr_curve.py +33 -32
- wandb/plot/roc_curve.py +38 -38
- wandb/plot/scatter.py +27 -27
- wandb/proto/v3/wandb_internal_pb2.py +366 -385
- wandb/proto/v3/wandb_settings_pb2.py +2 -2
- wandb/proto/v3/wandb_telemetry_pb2.py +4 -4
- wandb/proto/v4/wandb_internal_pb2.py +352 -356
- wandb/proto/v4/wandb_settings_pb2.py +2 -2
- wandb/proto/v4/wandb_telemetry_pb2.py +4 -4
- wandb/proto/v5/wandb_internal_pb2.py +352 -356
- wandb/proto/v5/wandb_settings_pb2.py +2 -2
- wandb/proto/v5/wandb_telemetry_pb2.py +4 -4
- wandb/proto/v6/wandb_internal_pb2.py +352 -356
- wandb/proto/v6/wandb_settings_pb2.py +2 -2
- wandb/proto/v6/wandb_telemetry_pb2.py +4 -4
- wandb/proto/wandb_deprecated.py +6 -0
- wandb/sdk/artifacts/_generated/__init__.py +12 -1
- wandb/sdk/artifacts/_generated/input_types.py +20 -2
- wandb/sdk/artifacts/_generated/link_artifact.py +21 -0
- wandb/sdk/artifacts/_generated/operations.py +9 -0
- wandb/sdk/artifacts/_internal_artifact.py +19 -8
- wandb/sdk/artifacts/_validators.py +48 -2
- wandb/sdk/artifacts/artifact.py +269 -96
- wandb/sdk/data_types/audio.py +38 -10
- wandb/sdk/data_types/base_types/media.py +15 -63
- wandb/sdk/data_types/base_types/wb_value.py +6 -6
- wandb/sdk/data_types/graph.py +48 -14
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +1 -3
- wandb/sdk/data_types/helper_types/image_mask.py +1 -3
- wandb/sdk/data_types/histogram.py +34 -21
- wandb/sdk/data_types/html.py +35 -12
- wandb/sdk/data_types/image.py +104 -68
- wandb/sdk/data_types/molecule.py +32 -19
- wandb/sdk/data_types/object_3d.py +36 -17
- wandb/sdk/data_types/plotly.py +18 -5
- wandb/sdk/data_types/saved_model.py +7 -9
- wandb/sdk/data_types/table.py +99 -70
- wandb/sdk/data_types/trace_tree.py +12 -12
- wandb/sdk/data_types/video.py +53 -26
- wandb/sdk/integration_utils/auto_logging.py +2 -2
- wandb/sdk/interface/interface.py +8 -19
- wandb/sdk/interface/interface_shared.py +7 -16
- wandb/sdk/internal/datastore.py +18 -18
- wandb/sdk/internal/handler.py +3 -5
- wandb/sdk/internal/internal_api.py +60 -0
- wandb/sdk/internal/job_builder.py +6 -0
- wandb/sdk/internal/sender.py +23 -3
- wandb/sdk/internal/sender_config.py +9 -0
- wandb/sdk/launch/_project_spec.py +3 -3
- wandb/sdk/launch/agent/agent.py +11 -4
- wandb/sdk/launch/agent/job_status_tracker.py +3 -1
- wandb/sdk/launch/agent/run_queue_item_file_saver.py +2 -2
- wandb/sdk/launch/create_job.py +3 -1
- wandb/sdk/launch/inputs/internal.py +3 -4
- wandb/sdk/launch/inputs/schema.py +1 -0
- wandb/sdk/launch/runner/kubernetes_monitor.py +1 -0
- wandb/sdk/launch/runner/kubernetes_runner.py +328 -1
- wandb/sdk/launch/sweeps/scheduler.py +2 -3
- wandb/sdk/launch/utils.py +3 -3
- wandb/sdk/lib/asyncio_compat.py +3 -0
- wandb/sdk/lib/console_capture.py +66 -19
- wandb/sdk/lib/deprecate.py +1 -7
- wandb/sdk/lib/disabled.py +1 -1
- wandb/sdk/lib/hashutil.py +14 -1
- wandb/sdk/lib/module.py +7 -13
- wandb/sdk/lib/progress.py +0 -19
- wandb/sdk/lib/sock_client.py +0 -4
- wandb/sdk/wandb_init.py +67 -93
- wandb/sdk/wandb_login.py +18 -14
- wandb/sdk/wandb_metric.py +2 -0
- wandb/sdk/wandb_require.py +0 -1
- wandb/sdk/wandb_run.py +429 -527
- wandb/sdk/wandb_settings.py +364 -74
- wandb/sdk/wandb_setup.py +28 -28
- wandb/sdk/wandb_sweep.py +14 -13
- wandb/sdk/wandb_watch.py +4 -6
- wandb/sync/sync.py +10 -0
- wandb/util.py +57 -0
- wandb/wandb_run.py +1 -2
- {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/METADATA +1 -1
- {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/RECORD +137 -137
- wandb/sdk/wandb_metadata.py +0 -623
- wandb/vendor/pynvml/__init__.py +0 -0
- wandb/vendor/pynvml/pynvml.py +0 -4779
- {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/WHEEL +0 -0
- {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/entry_points.txt +0 -0
- {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/artifacts/artifact.py
CHANGED
@@ -34,6 +34,7 @@ from wandb.apis.public import ArtifactCollection, ArtifactFiles, Run
|
|
34
34
|
from wandb.apis.public.utils import gql_compat
|
35
35
|
from wandb.data_types import WBValue
|
36
36
|
from wandb.errors import CommError
|
37
|
+
from wandb.errors.errors import UnsupportedError
|
37
38
|
from wandb.errors.term import termerror, termlog, termwarn
|
38
39
|
from wandb.proto import wandb_internal_pb2 as pb
|
39
40
|
from wandb.proto.wandb_deprecated import Deprecated
|
@@ -61,20 +62,25 @@ from ._generated import (
|
|
61
62
|
ADD_ALIASES_GQL,
|
62
63
|
DELETE_ALIASES_GQL,
|
63
64
|
FETCH_LINKED_ARTIFACTS_GQL,
|
65
|
+
LINK_ARTIFACT_GQL,
|
64
66
|
UPDATE_ARTIFACT_GQL,
|
65
67
|
ArtifactAliasInput,
|
66
68
|
ArtifactCollectionAliasInput,
|
67
69
|
FetchLinkedArtifacts,
|
70
|
+
LinkArtifact,
|
71
|
+
LinkArtifactInput,
|
68
72
|
TagInput,
|
69
73
|
UpdateArtifact,
|
70
74
|
)
|
71
75
|
from ._graphql_fragments import _gql_artifact_fragment, omit_artifact_fields
|
72
76
|
from ._validators import (
|
73
77
|
LINKED_ARTIFACT_COLLECTION_TYPE,
|
78
|
+
ArtifactPath,
|
74
79
|
_LinkArtifactFields,
|
75
80
|
ensure_logged,
|
76
81
|
ensure_not_finalized,
|
77
82
|
is_artifact_registry_project,
|
83
|
+
remove_registry_prefix,
|
78
84
|
validate_aliases,
|
79
85
|
validate_artifact_name,
|
80
86
|
validate_artifact_type,
|
@@ -126,25 +132,26 @@ class Artifact:
|
|
126
132
|
|
127
133
|
Construct an empty W&B Artifact. Populate an artifacts contents with methods that
|
128
134
|
begin with `add`. Once the artifact has all the desired files, you can call
|
129
|
-
`
|
135
|
+
`run.log_artifact()` to log it.
|
130
136
|
|
131
137
|
Args:
|
132
|
-
name: A human-readable name for the artifact. Use the name to identify
|
138
|
+
name (str): A human-readable name for the artifact. Use the name to identify
|
133
139
|
a specific artifact in the W&B App UI or programmatically. You can
|
134
140
|
interactively reference an artifact with the `use_artifact` Public API.
|
135
141
|
A name can contain letters, numbers, underscores, hyphens, and dots.
|
136
142
|
The name must be unique across a project.
|
137
|
-
type: The artifact's type. Use the type of an artifact to both organize
|
143
|
+
type (str): The artifact's type. Use the type of an artifact to both organize
|
138
144
|
and differentiate artifacts. You can use any string that contains letters,
|
139
145
|
numbers, underscores, hyphens, and dots. Common types include `dataset` or `model`.
|
140
|
-
|
141
|
-
|
142
|
-
|
146
|
+
Include `model` within your type string if you want to link the artifact
|
147
|
+
to the W&B Model Registry. Note that some types reserved for internal use
|
148
|
+
and cannot be set by users. Such types include `job` and types that start with `wandb-`.
|
149
|
+
description (str | None) = None: A description of the artifact. For Model or Dataset Artifacts,
|
143
150
|
add documentation for your standardized team model or dataset card. View
|
144
151
|
an artifact's description programmatically with the `Artifact.description`
|
145
152
|
attribute or programmatically with the W&B App UI. W&B renders the
|
146
153
|
description as markdown in the W&B App.
|
147
|
-
metadata: Additional information about an artifact. Specify metadata as a
|
154
|
+
metadata (dict[str, Any] | None) = None: Additional information about an artifact. Specify metadata as a
|
148
155
|
dictionary of key-value pairs. You can specify no more than 100 total keys.
|
149
156
|
incremental: Use `Artifact.new_draft()` method instead to modify an
|
150
157
|
existing artifact.
|
@@ -277,6 +284,87 @@ class Artifact:
|
|
277
284
|
name = "{}:v{}".format(src_collection["name"], attrs["versionIndex"])
|
278
285
|
return cls._from_attrs(entity_name, project_name, name, attrs, client)
|
279
286
|
|
287
|
+
@classmethod
|
288
|
+
def _membership_from_name(
|
289
|
+
cls,
|
290
|
+
*,
|
291
|
+
entity: str,
|
292
|
+
project: str,
|
293
|
+
name: str,
|
294
|
+
client: RetryingClient,
|
295
|
+
) -> Artifact:
|
296
|
+
if not InternalApi()._server_supports(
|
297
|
+
pb.ServerFeature.PROJECT_ARTIFACT_COLLECTION_MEMBERSHIP
|
298
|
+
):
|
299
|
+
raise UnsupportedError(
|
300
|
+
"querying for the artifact collection membership is not supported "
|
301
|
+
"by this version of wandb server. Consider updating to the latest version."
|
302
|
+
)
|
303
|
+
|
304
|
+
query = gql(
|
305
|
+
f"""
|
306
|
+
query ArtifactByName($entityName: String!, $projectName: String!, $name: String!) {{
|
307
|
+
project(name: $projectName, entityName: $entityName) {{
|
308
|
+
artifactCollectionMembership(name: $name) {{
|
309
|
+
id
|
310
|
+
artifactCollection {{
|
311
|
+
id
|
312
|
+
name
|
313
|
+
project {{
|
314
|
+
id
|
315
|
+
entityName
|
316
|
+
name
|
317
|
+
}}
|
318
|
+
}}
|
319
|
+
artifact {{
|
320
|
+
...ArtifactFragment
|
321
|
+
}}
|
322
|
+
}}
|
323
|
+
}}
|
324
|
+
}}
|
325
|
+
{_gql_artifact_fragment()}
|
326
|
+
"""
|
327
|
+
)
|
328
|
+
|
329
|
+
query_variable_values: dict[str, Any] = {
|
330
|
+
"entityName": entity,
|
331
|
+
"projectName": project,
|
332
|
+
"name": name,
|
333
|
+
}
|
334
|
+
response = client.execute(
|
335
|
+
query,
|
336
|
+
variable_values=query_variable_values,
|
337
|
+
)
|
338
|
+
if not (project_attrs := response.get("project")):
|
339
|
+
raise ValueError(f"project {project!r} not found under entity {entity!r}")
|
340
|
+
if not (acm_attrs := project_attrs.get("artifactCollectionMembership")):
|
341
|
+
entity_project = f"{entity}/{project}"
|
342
|
+
raise ValueError(
|
343
|
+
f"artifact membership {name!r} not found in {entity_project!r}"
|
344
|
+
)
|
345
|
+
if not (ac_attrs := acm_attrs.get("artifactCollection")):
|
346
|
+
raise ValueError("artifact collection not found")
|
347
|
+
if not (
|
348
|
+
(ac_name := ac_attrs.get("name"))
|
349
|
+
and (ac_project_attrs := ac_attrs.get("project"))
|
350
|
+
):
|
351
|
+
raise ValueError("artifact collection project not found")
|
352
|
+
ac_project = ac_project_attrs.get("name")
|
353
|
+
ac_entity = ac_project_attrs.get("entityName")
|
354
|
+
if is_artifact_registry_project(ac_project) and project == "model-registry":
|
355
|
+
wandb.termwarn(
|
356
|
+
"This model registry has been migrated and will be discontinued. "
|
357
|
+
f"Your request was redirected to the corresponding artifact `{ac_name}` in the new registry. "
|
358
|
+
f"Please update your paths to point to the migrated registry directly, `{ac_project}/{ac_name}`."
|
359
|
+
)
|
360
|
+
entity = ac_entity
|
361
|
+
project = ac_project
|
362
|
+
if not (attrs := acm_attrs.get("artifact")):
|
363
|
+
entity_project = f"{entity}/{project}"
|
364
|
+
raise ValueError(f"artifact {name!r} not found in {entity_project!r}")
|
365
|
+
|
366
|
+
return cls._from_attrs(entity, project, name, attrs, client)
|
367
|
+
|
280
368
|
@classmethod
|
281
369
|
def _from_name(
|
282
370
|
cls,
|
@@ -287,14 +375,31 @@ class Artifact:
|
|
287
375
|
client: RetryingClient,
|
288
376
|
enable_tracking: bool = False,
|
289
377
|
) -> Artifact:
|
378
|
+
if InternalApi()._server_supports(
|
379
|
+
pb.ServerFeature.PROJECT_ARTIFACT_COLLECTION_MEMBERSHIP
|
380
|
+
):
|
381
|
+
return cls._membership_from_name(
|
382
|
+
entity=entity,
|
383
|
+
project=project,
|
384
|
+
name=name,
|
385
|
+
client=client,
|
386
|
+
)
|
387
|
+
|
388
|
+
query_variable_values: dict[str, Any] = {
|
389
|
+
"entityName": entity,
|
390
|
+
"projectName": project,
|
391
|
+
"name": name,
|
392
|
+
}
|
393
|
+
query_vars = ["$entityName: String!", "$projectName: String!", "$name: String!"]
|
394
|
+
query_args = ["name: $name"]
|
395
|
+
|
290
396
|
server_supports_enabling_artifact_usage_tracking = (
|
291
397
|
InternalApi().server_project_type_introspection()
|
292
398
|
)
|
293
|
-
query_vars = ["$entityName: String!", "$projectName: String!", "$name: String!"]
|
294
|
-
query_args = ["name: $name"]
|
295
399
|
if server_supports_enabling_artifact_usage_tracking:
|
296
400
|
query_vars.append("$enableTracking: Boolean")
|
297
401
|
query_args.append("enableTracking: $enableTracking")
|
402
|
+
query_variable_values["enableTracking"] = enable_tracking
|
298
403
|
|
299
404
|
vars_str = ", ".join(query_vars)
|
300
405
|
args_str = ", ".join(query_args)
|
@@ -311,14 +416,6 @@ class Artifact:
|
|
311
416
|
{_gql_artifact_fragment()}
|
312
417
|
"""
|
313
418
|
)
|
314
|
-
query_variable_values: dict[str, Any] = {
|
315
|
-
"entityName": entity,
|
316
|
-
"projectName": project,
|
317
|
-
"name": name,
|
318
|
-
}
|
319
|
-
if server_supports_enabling_artifact_usage_tracking:
|
320
|
-
query_variable_values["enableTracking"] = enable_tracking
|
321
|
-
|
322
419
|
response = client.execute(
|
323
420
|
query,
|
324
421
|
variable_values=query_variable_values,
|
@@ -329,6 +426,7 @@ class Artifact:
|
|
329
426
|
attrs = project_attrs.get("artifact")
|
330
427
|
if not attrs:
|
331
428
|
raise ValueError(f"artifact '{name}' not found in '{entity}/{project}'")
|
429
|
+
|
332
430
|
return cls._from_attrs(entity, project, name, attrs, client)
|
333
431
|
|
334
432
|
@classmethod
|
@@ -743,7 +841,7 @@ class Artifact:
|
|
743
841
|
)
|
744
842
|
return urljoin(
|
745
843
|
base_url,
|
746
|
-
f"orgs/{org.display_name}/registry/{self.
|
844
|
+
f"orgs/{org.display_name}/registry/{remove_registry_prefix(self.project)}?selectionPath={selection_path}&view=membership&version={self.version}",
|
747
845
|
)
|
748
846
|
|
749
847
|
def _construct_model_registry_url(self, base_url: str) -> str:
|
@@ -828,7 +926,8 @@ class Artifact:
|
|
828
926
|
TTL and there is no custom policy set on an artifact.
|
829
927
|
|
830
928
|
Raises:
|
831
|
-
ArtifactNotLoggedError: Unable to fetch inherited TTL if the
|
929
|
+
ArtifactNotLoggedError: Unable to fetch inherited TTL if the
|
930
|
+
artifact has not been logged or saved.
|
832
931
|
"""
|
833
932
|
if self._ttl_is_inherited and (self.is_draft() or self._ttl_changed):
|
834
933
|
raise ArtifactNotLoggedError(f"{type(self).__name__}.ttl", self)
|
@@ -880,7 +979,9 @@ class Artifact:
|
|
880
979
|
@property
|
881
980
|
@ensure_logged
|
882
981
|
def aliases(self) -> list[str]:
|
883
|
-
"""List of one or more semantically-friendly references or
|
982
|
+
"""List of one or more semantically-friendly references or
|
983
|
+
|
984
|
+
identifying "nicknames" assigned to an artifact version.
|
884
985
|
|
885
986
|
Aliases are mutable references that you can programmatically reference.
|
886
987
|
Change an artifact's alias with the W&B App UI or programmatically.
|
@@ -916,6 +1017,10 @@ class Artifact:
|
|
916
1017
|
|
917
1018
|
@property
|
918
1019
|
def distributed_id(self) -> str | None:
|
1020
|
+
"""The distributed ID of the artifact.
|
1021
|
+
|
1022
|
+
<!-- lazydoc-ignore: internal -->
|
1023
|
+
"""
|
919
1024
|
return self._distributed_id
|
920
1025
|
|
921
1026
|
@distributed_id.setter
|
@@ -924,6 +1029,10 @@ class Artifact:
|
|
924
1029
|
|
925
1030
|
@property
|
926
1031
|
def incremental(self) -> bool:
|
1032
|
+
"""Boolean flag indicating if the artifact is an incremental artifact.
|
1033
|
+
|
1034
|
+
<!-- lazydoc-ignore: internal -->
|
1035
|
+
"""
|
927
1036
|
return self._incremental
|
928
1037
|
|
929
1038
|
@property
|
@@ -1043,15 +1152,15 @@ class Artifact:
|
|
1043
1152
|
"""The nearest step at which history metrics were logged for the source run of the artifact.
|
1044
1153
|
|
1045
1154
|
Examples:
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1155
|
+
```python
|
1156
|
+
run = artifact.logged_by()
|
1157
|
+
if run and (artifact.history_step is not None):
|
1158
|
+
history = run.sample_history(
|
1159
|
+
min_step=artifact.history_step,
|
1160
|
+
max_step=artifact.history_step + 1,
|
1161
|
+
keys=["my_metric"],
|
1162
|
+
)
|
1163
|
+
```
|
1055
1164
|
"""
|
1056
1165
|
if self._history_step is None:
|
1057
1166
|
return None
|
@@ -1072,7 +1181,8 @@ class Artifact:
|
|
1072
1181
|
def is_draft(self) -> bool:
|
1073
1182
|
"""Check if artifact is not saved.
|
1074
1183
|
|
1075
|
-
Returns:
|
1184
|
+
Returns:
|
1185
|
+
Boolean. `False` if artifact is saved. `True` if artifact is not saved.
|
1076
1186
|
"""
|
1077
1187
|
return self._state == ArtifactState.PENDING
|
1078
1188
|
|
@@ -1320,7 +1430,7 @@ class Artifact:
|
|
1320
1430
|
name: The artifact relative name to get.
|
1321
1431
|
|
1322
1432
|
Returns:
|
1323
|
-
W&B object that can be logged with `
|
1433
|
+
W&B object that can be logged with `run.log()` and visualized in the W&B UI.
|
1324
1434
|
|
1325
1435
|
Raises:
|
1326
1436
|
ArtifactNotLoggedError: If the artifact isn't logged or the run is offline.
|
@@ -1338,8 +1448,9 @@ class Artifact:
|
|
1338
1448
|
The added manifest entry
|
1339
1449
|
|
1340
1450
|
Raises:
|
1341
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1342
|
-
version because it is finalized. Log a new artifact
|
1451
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1452
|
+
artifact version because it is finalized. Log a new artifact
|
1453
|
+
version instead.
|
1343
1454
|
"""
|
1344
1455
|
return self.add(item, name)
|
1345
1456
|
|
@@ -1356,12 +1467,13 @@ class Artifact:
|
|
1356
1467
|
encoding: The encoding used to open the new file.
|
1357
1468
|
|
1358
1469
|
Returns:
|
1359
|
-
A new file object that can be written to. Upon closing, the file
|
1360
|
-
automatically added to the artifact.
|
1470
|
+
A new file object that can be written to. Upon closing, the file
|
1471
|
+
is automatically added to the artifact.
|
1361
1472
|
|
1362
1473
|
Raises:
|
1363
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1364
|
-
version because it is finalized. Log a new artifact
|
1474
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1475
|
+
artifact version because it is finalized. Log a new artifact
|
1476
|
+
version instead.
|
1365
1477
|
"""
|
1366
1478
|
overwrite: bool = "x" not in mode
|
1367
1479
|
|
@@ -1400,22 +1512,26 @@ class Artifact:
|
|
1400
1512
|
|
1401
1513
|
Args:
|
1402
1514
|
local_path: The path to the file being added.
|
1403
|
-
name: The path within the artifact to use for the file being added.
|
1404
|
-
to the basename of the file.
|
1515
|
+
name: The path within the artifact to use for the file being added.
|
1516
|
+
Defaults to the basename of the file.
|
1405
1517
|
is_tmp: If true, then the file is renamed deterministically to avoid
|
1406
1518
|
collisions.
|
1407
|
-
skip_cache: If `True`,
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1519
|
+
skip_cache: If `True`, do not copy files to the cache
|
1520
|
+
after uploading.
|
1521
|
+
policy: By default, set to "mutable". If set to "mutable",
|
1522
|
+
create a temporary copy of the file to prevent corruption
|
1523
|
+
during upload. If set to "immutable", disable
|
1524
|
+
protection and rely on the user not to delete or change the
|
1525
|
+
file.
|
1411
1526
|
overwrite: If `True`, overwrite the file if it already exists.
|
1412
1527
|
|
1413
1528
|
Returns:
|
1414
1529
|
The added manifest entry.
|
1415
1530
|
|
1416
1531
|
Raises:
|
1417
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1418
|
-
|
1532
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1533
|
+
artifact version because it is finalized. Log a new artifact
|
1534
|
+
version instead.
|
1419
1535
|
ValueError: Policy must be "mutable" or "immutable"
|
1420
1536
|
"""
|
1421
1537
|
if not os.path.isfile(local_path):
|
@@ -1452,21 +1568,23 @@ class Artifact:
|
|
1452
1568
|
|
1453
1569
|
Args:
|
1454
1570
|
local_path: The path of the local directory.
|
1455
|
-
name: The subdirectory name within an artifact. The name you
|
1456
|
-
in the W&B App UI nested by artifact's `type`.
|
1571
|
+
name: The subdirectory name within an artifact. The name you
|
1572
|
+
specify appears in the W&B App UI nested by artifact's `type`.
|
1457
1573
|
Defaults to the root of the artifact.
|
1458
|
-
skip_cache: If set to `True`, W&B will not copy/move files to
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1574
|
+
skip_cache: If set to `True`, W&B will not copy/move files to
|
1575
|
+
the cache while uploading
|
1576
|
+
policy: By default, "mutable".
|
1577
|
+
- mutable: Create a temporary copy of the file to prevent corruption during upload.
|
1578
|
+
- immutable: Disable protection, rely on the user not to delete or change the file.
|
1462
1579
|
merge: If `False` (default), throws ValueError if a file was already added in a previous add_dir call
|
1463
1580
|
and its content has changed. If `True`, overwrites existing files with changed content.
|
1464
1581
|
Always adds new files and never removes files. To replace an entire directory, pass a name when adding the directory
|
1465
1582
|
using `add_dir(local_path, name=my_prefix)` and call `remove(my_prefix)` to remove the directory, then add it again.
|
1466
1583
|
|
1467
1584
|
Raises:
|
1468
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1469
|
-
|
1585
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1586
|
+
artifact version because it is finalized. Log a new artifact
|
1587
|
+
version instead.
|
1470
1588
|
ValueError: Policy must be "mutable" or "immutable"
|
1471
1589
|
"""
|
1472
1590
|
if not os.path.isdir(local_path):
|
@@ -1525,13 +1643,14 @@ class Artifact:
|
|
1525
1643
|
|
1526
1644
|
- http(s): The size and digest of the file will be inferred by the
|
1527
1645
|
`Content-Length` and the `ETag` response headers returned by the server.
|
1528
|
-
- s3: The checksum and size are pulled from the object metadata.
|
1529
|
-
versioning is enabled, then the version ID is also tracked.
|
1646
|
+
- s3: The checksum and size are pulled from the object metadata.
|
1647
|
+
If bucket versioning is enabled, then the version ID is also tracked.
|
1530
1648
|
- gs: The checksum and size are pulled from the object metadata. If bucket
|
1531
1649
|
versioning is enabled, then the version ID is also tracked.
|
1532
|
-
- https, domain matching `*.blob.core.windows.net`
|
1533
|
-
|
1534
|
-
enabled, then the version ID is
|
1650
|
+
- https, domain matching `*.blob.core.windows.net`
|
1651
|
+
- Azure: The checksum and size are be pulled from the blob metadata.
|
1652
|
+
If storage account versioning is enabled, then the version ID is
|
1653
|
+
also tracked.
|
1535
1654
|
- file: The checksum and size are pulled from the file system. This scheme
|
1536
1655
|
is useful if you have an NFS share or other externally mounted volume
|
1537
1656
|
containing files you wish to track but not necessarily upload.
|
@@ -1552,16 +1671,18 @@ class Artifact:
|
|
1552
1671
|
setting `checksum=False` when adding reference objects, in which case
|
1553
1672
|
a new version will only be created if the reference URI changes.
|
1554
1673
|
max_objects: The maximum number of objects to consider when adding a
|
1555
|
-
reference that points to directory or bucket store prefix.
|
1556
|
-
the maximum number of objects allowed for Amazon S3,
|
1557
|
-
GCS, Azure, and local files is 10,000,000. Other URI schemas
|
1674
|
+
reference that points to directory or bucket store prefix.
|
1675
|
+
By default, the maximum number of objects allowed for Amazon S3,
|
1676
|
+
GCS, Azure, and local files is 10,000,000. Other URI schemas
|
1677
|
+
do not have a maximum.
|
1558
1678
|
|
1559
1679
|
Returns:
|
1560
1680
|
The added manifest entries.
|
1561
1681
|
|
1562
1682
|
Raises:
|
1563
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1564
|
-
version because it is finalized. Log a new artifact
|
1683
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1684
|
+
artifact version because it is finalized. Log a new artifact
|
1685
|
+
version instead.
|
1565
1686
|
"""
|
1566
1687
|
if name is not None:
|
1567
1688
|
name = LogicalPath(name)
|
@@ -1598,17 +1719,19 @@ class Artifact:
|
|
1598
1719
|
|
1599
1720
|
Args:
|
1600
1721
|
obj: The object to add. Currently support one of Bokeh, JoinedTable,
|
1601
|
-
PartitionedTable, Table, Classes, ImageMask, BoundingBoxes2D,
|
1602
|
-
Image, Video, Html, Object3D
|
1722
|
+
PartitionedTable, Table, Classes, ImageMask, BoundingBoxes2D,
|
1723
|
+
Audio, Image, Video, Html, Object3D
|
1603
1724
|
name: The path within the artifact to add the object.
|
1604
|
-
overwrite: If True, overwrite existing objects with the same file
|
1725
|
+
overwrite: If True, overwrite existing objects with the same file
|
1726
|
+
path if applicable.
|
1605
1727
|
|
1606
1728
|
Returns:
|
1607
1729
|
The added manifest entry
|
1608
1730
|
|
1609
1731
|
Raises:
|
1610
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1611
|
-
version because it is finalized. Log a new artifact
|
1732
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1733
|
+
artifact version because it is finalized. Log a new artifact
|
1734
|
+
version instead.
|
1612
1735
|
"""
|
1613
1736
|
name = LogicalPath(name)
|
1614
1737
|
|
@@ -1723,13 +1846,14 @@ class Artifact:
|
|
1723
1846
|
"""Remove an item from the artifact.
|
1724
1847
|
|
1725
1848
|
Args:
|
1726
|
-
item: The item to remove. Can be a specific manifest entry
|
1727
|
-
artifact-relative path. If the item
|
1728
|
-
that directory will be removed.
|
1849
|
+
item: The item to remove. Can be a specific manifest entry
|
1850
|
+
or the name of an artifact-relative path. If the item
|
1851
|
+
matches a directory all items in that directory will be removed.
|
1729
1852
|
|
1730
1853
|
Raises:
|
1731
|
-
ArtifactFinalizedError: You cannot make changes to the current
|
1732
|
-
|
1854
|
+
ArtifactFinalizedError: You cannot make changes to the current
|
1855
|
+
artifact version because it is finalized. Log a new artifact
|
1856
|
+
version instead.
|
1733
1857
|
FileNotFoundError: If the item isn't found in the artifact.
|
1734
1858
|
"""
|
1735
1859
|
if isinstance(item, ArtifactManifestEntry):
|
@@ -1785,10 +1909,12 @@ class Artifact:
|
|
1785
1909
|
name: The artifact relative name to retrieve.
|
1786
1910
|
|
1787
1911
|
Returns:
|
1788
|
-
W&B object that can be logged with `
|
1912
|
+
W&B object that can be logged with `run.log()` and
|
1913
|
+
visualized in the W&B UI.
|
1789
1914
|
|
1790
1915
|
Raises:
|
1791
|
-
ArtifactNotLoggedError: if the artifact isn't logged or the
|
1916
|
+
ArtifactNotLoggedError: if the artifact isn't logged or the
|
1917
|
+
run is offline.
|
1792
1918
|
"""
|
1793
1919
|
entry, wb_class = self._get_obj_entry(name)
|
1794
1920
|
if entry is None or wb_class is None:
|
@@ -2224,7 +2350,7 @@ class Artifact:
|
|
2224
2350
|
|
2225
2351
|
Args:
|
2226
2352
|
root: The root directory to store the file. Defaults to
|
2227
|
-
|
2353
|
+
`./artifacts/self.name/`.
|
2228
2354
|
|
2229
2355
|
Returns:
|
2230
2356
|
The full path of the downloaded file.
|
@@ -2290,16 +2416,16 @@ class Artifact:
|
|
2290
2416
|
def delete(self, delete_aliases: bool = False) -> None:
|
2291
2417
|
"""Delete an artifact and its files.
|
2292
2418
|
|
2293
|
-
If called on a linked artifact
|
2419
|
+
If called on a linked artifact, only the link is deleted, and the
|
2294
2420
|
source artifact is unaffected.
|
2295
2421
|
|
2296
2422
|
Use `artifact.unlink()` instead of `artifact.delete()` to remove a link between a source artifact and a linked artifact.
|
2297
2423
|
|
2298
2424
|
Args:
|
2299
|
-
delete_aliases: If set to `True`, deletes all aliases associated
|
2300
|
-
Otherwise, this raises an exception if
|
2301
|
-
aliases.
|
2302
|
-
|
2425
|
+
delete_aliases: If set to `True`, deletes all aliases associated
|
2426
|
+
with the artifact. Otherwise, this raises an exception if
|
2427
|
+
the artifact has existing aliases. This parameter is ignored
|
2428
|
+
if the artifact is linked (a member of a portfolio collection).
|
2303
2429
|
|
2304
2430
|
Raises:
|
2305
2431
|
ArtifactNotLoggedError: If the artifact is not logged.
|
@@ -2352,8 +2478,8 @@ class Artifact:
|
|
2352
2478
|
portfolio inside a project, set `target_path` to the following
|
2353
2479
|
schema `{"model-registry"}/{Registered Model Name}` or
|
2354
2480
|
`{entity}/{"model-registry"}/{Registered Model Name}`.
|
2355
|
-
aliases: A list of strings that uniquely identifies the artifact
|
2356
|
-
specified portfolio.
|
2481
|
+
aliases: A list of strings that uniquely identifies the artifact
|
2482
|
+
inside the specified portfolio.
|
2357
2483
|
|
2358
2484
|
Raises:
|
2359
2485
|
ArtifactNotLoggedError: If the artifact is not logged.
|
@@ -2361,33 +2487,80 @@ class Artifact:
|
|
2361
2487
|
Returns:
|
2362
2488
|
The linked artifact if linking was successful, otherwise None.
|
2363
2489
|
"""
|
2490
|
+
from wandb import Api
|
2491
|
+
|
2364
2492
|
if self.is_link:
|
2365
2493
|
wandb.termwarn(
|
2366
2494
|
"Linking to a link artifact will result in directly linking to the source artifact of that link artifact."
|
2367
2495
|
)
|
2368
2496
|
|
2369
|
-
if
|
2370
|
-
|
2371
|
-
|
2497
|
+
if self._client is None:
|
2498
|
+
raise ValueError("Client not initialized for artifact mutations")
|
2499
|
+
|
2500
|
+
# Save the artifact first if necessary
|
2501
|
+
if self.is_draft():
|
2502
|
+
if not self._is_draft_save_started():
|
2503
|
+
self.save(project=self.source_project)
|
2504
|
+
|
2505
|
+
# Wait until the artifact is committed before trying to link it.
|
2506
|
+
self.wait()
|
2507
|
+
|
2508
|
+
api = Api(overrides={"entity": self.source_entity})
|
2509
|
+
|
2510
|
+
target = ArtifactPath.from_str(target_path).with_defaults(
|
2511
|
+
project=api.settings.get("project") or "uncategorized",
|
2512
|
+
)
|
2513
|
+
|
2514
|
+
# Parse the entity (first part of the path) appropriately,
|
2515
|
+
# depending on whether we're linking to a registry
|
2516
|
+
if target.project and is_artifact_registry_project(target.project):
|
2517
|
+
# In a Registry linking, the entity is used to fetch the organization of the artifact
|
2518
|
+
# therefore the source artifact's entity is passed to the backend
|
2519
|
+
organization = target.prefix or api.settings.get("organization") or ""
|
2372
2520
|
|
2521
|
+
target.prefix = InternalApi()._resolve_org_entity_name(
|
2522
|
+
self.source_entity, organization
|
2523
|
+
)
|
2373
2524
|
else:
|
2374
|
-
|
2375
|
-
entity=self._source_entity,
|
2376
|
-
project=self._source_project,
|
2377
|
-
job_type="auto",
|
2378
|
-
settings=wandb.Settings(silent="true"),
|
2379
|
-
) as run:
|
2380
|
-
return run.link_artifact(self, target_path, aliases)
|
2525
|
+
target = target.with_defaults(prefix=self.source_entity)
|
2381
2526
|
|
2382
|
-
|
2527
|
+
# Prepare the validated GQL input, send it
|
2528
|
+
alias_inputs = [
|
2529
|
+
ArtifactAliasInput(artifact_collection_name=target.name, alias=a)
|
2530
|
+
for a in (aliases or [])
|
2531
|
+
]
|
2532
|
+
gql_input = LinkArtifactInput(
|
2533
|
+
artifact_id=self.id,
|
2534
|
+
artifact_portfolio_name=target.name,
|
2535
|
+
entity_name=target.prefix,
|
2536
|
+
project_name=target.project,
|
2537
|
+
aliases=alias_inputs,
|
2538
|
+
)
|
2539
|
+
gql_vars = {"input": gql_input.model_dump(exclude_none=True)}
|
2540
|
+
gql_op = gql(LINK_ARTIFACT_GQL)
|
2541
|
+
data = self._client.execute(gql_op, variable_values=gql_vars)
|
2542
|
+
|
2543
|
+
result = LinkArtifact.model_validate(data).link_artifact
|
2544
|
+
if not (result and (version_idx := result.version_index) is not None):
|
2545
|
+
raise ValueError("Unable to parse linked artifact version from response")
|
2546
|
+
|
2547
|
+
# Fetch the linked artifact to return it
|
2548
|
+
linked_path = f"{target.to_str()}:v{version_idx}"
|
2549
|
+
|
2550
|
+
try:
|
2551
|
+
return api._artifact(linked_path)
|
2552
|
+
except Exception as e:
|
2553
|
+
wandb.termerror(f"Error fetching link artifact after linking: {e}")
|
2554
|
+
return None
|
2383
2555
|
|
2384
2556
|
@ensure_logged
|
2385
2557
|
def unlink(self) -> None:
|
2386
|
-
"""Unlink this artifact if it is currently a member of a
|
2558
|
+
"""Unlink this artifact if it is currently a member of a promoted collection of artifacts.
|
2387
2559
|
|
2388
2560
|
Raises:
|
2389
2561
|
ArtifactNotLoggedError: If the artifact is not logged.
|
2390
|
-
ValueError: If the artifact is not linked,
|
2562
|
+
ValueError: If the artifact is not linked, in other words,
|
2563
|
+
it is not a member of a portfolio collection.
|
2391
2564
|
"""
|
2392
2565
|
# Fail early if this isn't a linked artifact to begin with
|
2393
2566
|
if not self.is_link:
|