wandb 0.20.2rc20250616__py3-none-win_amd64.whl → 0.21.1__py3-none-win_amd64.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.exe +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/data_types/table.py
CHANGED
@@ -203,8 +203,8 @@ class Table(Media):
|
|
203
203
|
This means you can embed `Images`, `Video`, `Audio`, and other sorts of rich, annotated media
|
204
204
|
directly in Tables, alongside other traditional scalar values.
|
205
205
|
|
206
|
-
This class is the primary class used to generate
|
207
|
-
|
206
|
+
This class is the primary class used to generate W&B Tables
|
207
|
+
https://docs.wandb.ai/guides/models/tables/.
|
208
208
|
"""
|
209
209
|
|
210
210
|
MAX_ROWS = 10000
|
@@ -236,6 +236,7 @@ class Table(Media):
|
|
236
236
|
data: (List[List[any]]) 2D row-oriented array of values.
|
237
237
|
dataframe: (pandas.DataFrame) DataFrame object used to create the table.
|
238
238
|
When set, `data` and `columns` arguments are ignored.
|
239
|
+
rows: (List[List[any]]) 2D row-oriented array of values.
|
239
240
|
optional: (Union[bool,List[bool]]) Determines if `None` values are allowed. Default to True
|
240
241
|
- If a singular bool value, then the optionality is enforced for all
|
241
242
|
columns specified at construction time
|
@@ -292,9 +293,9 @@ class Table(Media):
|
|
292
293
|
self._init_from_list([], columns, optional, dtype)
|
293
294
|
|
294
295
|
def _validate_log_mode(self, log_mode):
|
295
|
-
assert (
|
296
|
-
log_mode
|
297
|
-
)
|
296
|
+
assert log_mode in _SUPPORTED_LOGGING_MODES, (
|
297
|
+
f"Invalid log_mode: {log_mode}. Must be one of {_SUPPORTED_LOGGING_MODES}"
|
298
|
+
)
|
298
299
|
|
299
300
|
@staticmethod
|
300
301
|
def _assert_valid_columns(columns):
|
@@ -314,9 +315,9 @@ class Table(Media):
|
|
314
315
|
self.add_data(*row)
|
315
316
|
|
316
317
|
def _init_from_ndarray(self, ndarray, columns, optional=True, dtype=None):
|
317
|
-
assert util.is_numpy_array(
|
318
|
-
ndarray
|
319
|
-
)
|
318
|
+
assert util.is_numpy_array(ndarray), (
|
319
|
+
"ndarray argument expects a `numpy.ndarray` object"
|
320
|
+
)
|
320
321
|
self.data = []
|
321
322
|
self._assert_valid_columns(columns)
|
322
323
|
self.columns = columns
|
@@ -325,9 +326,9 @@ class Table(Media):
|
|
325
326
|
self.add_data(*row)
|
326
327
|
|
327
328
|
def _init_from_dataframe(self, dataframe, columns, optional=True, dtype=None):
|
328
|
-
assert util.is_pandas_data_frame(
|
329
|
-
dataframe
|
330
|
-
)
|
329
|
+
assert util.is_pandas_data_frame(dataframe), (
|
330
|
+
"dataframe argument expects a `pandas.core.frame.DataFrame` object"
|
331
|
+
)
|
331
332
|
self.data = []
|
332
333
|
columns = list(dataframe.columns)
|
333
334
|
self._assert_valid_columns(columns)
|
@@ -410,13 +411,15 @@ class Table(Media):
|
|
410
411
|
def cast(self, col_name, dtype, optional=False):
|
411
412
|
"""Casts a column to a specific data type.
|
412
413
|
|
413
|
-
This can be one of the normal python classes, an internal W&B type,
|
414
|
-
example object, like an instance of wandb.Image or
|
414
|
+
This can be one of the normal python classes, an internal W&B type,
|
415
|
+
or an example object, like an instance of wandb.Image or
|
416
|
+
wandb.Classes.
|
415
417
|
|
416
418
|
Args:
|
417
|
-
col_name
|
418
|
-
dtype
|
419
|
-
|
419
|
+
col_name (str): The name of the column to cast.
|
420
|
+
dtype (class, wandb.wandb_sdk.interface._dtypes.Type, any): The
|
421
|
+
target dtype.
|
422
|
+
optional (bool): If the column should allow Nones.
|
420
423
|
"""
|
421
424
|
assert col_name in self.columns
|
422
425
|
|
@@ -440,17 +443,17 @@ class Table(Media):
|
|
440
443
|
is_fk = isinstance(wbtype, _ForeignKeyType)
|
441
444
|
is_fi = isinstance(wbtype, _ForeignIndexType)
|
442
445
|
if is_pk or is_fk or is_fi:
|
443
|
-
assert (
|
444
|
-
|
445
|
-
)
|
446
|
+
assert not optional, (
|
447
|
+
"Primary keys, foreign keys, and foreign indexes cannot be optional."
|
448
|
+
)
|
446
449
|
|
447
450
|
if (is_fk or is_fk) and id(wbtype.params["table"]) == id(self):
|
448
451
|
raise AssertionError("Cannot set a foreign table reference to same table.")
|
449
452
|
|
450
453
|
if is_pk:
|
451
|
-
assert (
|
452
|
-
self._pk_col is
|
453
|
-
)
|
454
|
+
assert self._pk_col is None, (
|
455
|
+
f"Cannot have multiple primary keys - {self._pk_col} is already set as the primary key."
|
456
|
+
)
|
454
457
|
|
455
458
|
# Update the column type
|
456
459
|
self._column_types.params["type_map"][col_name] = wbtype
|
@@ -464,21 +467,21 @@ class Table(Media):
|
|
464
467
|
|
465
468
|
def _eq_debug(self, other, should_assert=False):
|
466
469
|
eq = isinstance(other, Table)
|
467
|
-
assert (
|
468
|
-
|
469
|
-
)
|
470
|
+
assert not should_assert or eq, (
|
471
|
+
f"Found type {other.__class__}, expected {Table}"
|
472
|
+
)
|
470
473
|
eq = eq and len(self.data) == len(other.data)
|
471
|
-
assert (
|
472
|
-
|
473
|
-
)
|
474
|
+
assert not should_assert or eq, (
|
475
|
+
f"Found {len(other.data)} rows, expected {len(self.data)}"
|
476
|
+
)
|
474
477
|
eq = eq and self.columns == other.columns
|
475
|
-
assert (
|
476
|
-
|
477
|
-
)
|
478
|
+
assert not should_assert or eq, (
|
479
|
+
f"Found columns {other.columns}, expected {self.columns}"
|
480
|
+
)
|
478
481
|
eq = eq and self._column_types == other._column_types
|
479
|
-
assert (
|
480
|
-
|
481
|
-
)
|
482
|
+
assert not should_assert or eq, (
|
483
|
+
f"Found column type {other._column_types}, expected column type {self._column_types}"
|
484
|
+
)
|
482
485
|
if eq:
|
483
486
|
for row_ndx in range(len(self.data)):
|
484
487
|
for col_ndx in range(len(self.data[row_ndx])):
|
@@ -487,9 +490,9 @@ class Table(Media):
|
|
487
490
|
if util.is_numpy_array(_eq):
|
488
491
|
_eq = ((_eq * -1) + 1).sum() == 0
|
489
492
|
eq = eq and _eq
|
490
|
-
assert (
|
491
|
-
|
492
|
-
)
|
493
|
+
assert not should_assert or eq, (
|
494
|
+
f"Unequal data at row_ndx {row_ndx} col_ndx {col_ndx}: found {other.data[row_ndx][col_ndx]}, expected {self.data[row_ndx][col_ndx]}"
|
495
|
+
)
|
493
496
|
if not eq:
|
494
497
|
return eq
|
495
498
|
return eq
|
@@ -499,14 +502,17 @@ class Table(Media):
|
|
499
502
|
|
500
503
|
@allow_relogging_after_mutation
|
501
504
|
def add_row(self, *row):
|
502
|
-
"""Deprecated
|
505
|
+
"""Deprecated. Use `Table.add_data` method instead."""
|
503
506
|
logging.warning("add_row is deprecated, use add_data")
|
504
507
|
self.add_data(*row)
|
505
508
|
|
506
509
|
@allow_relogging_after_mutation
|
507
510
|
@allow_incremental_logging_after_append
|
508
511
|
def add_data(self, *data):
|
509
|
-
"""Adds a new row of data to the table.
|
512
|
+
"""Adds a new row of data to the table.
|
513
|
+
|
514
|
+
The maximum amount ofrows in a table is determined by
|
515
|
+
`wandb.Table.MAX_ARTIFACT_ROWS`.
|
510
516
|
|
511
517
|
The length of the data should match the length of the table column.
|
512
518
|
"""
|
@@ -589,6 +595,10 @@ class Table(Media):
|
|
589
595
|
return {"columns": self.columns, "data": self.data[:max_rows]}
|
590
596
|
|
591
597
|
def bind_to_run(self, *args, **kwargs):
|
598
|
+
"""Bind this object to a run.
|
599
|
+
|
600
|
+
<!-- lazydoc-ignore: internal -->
|
601
|
+
"""
|
592
602
|
# We set `warn=False` since Tables will now always be logged to both
|
593
603
|
# files and artifacts. The file limit will never practically matter and
|
594
604
|
# this code path will be ultimately removed. The 10k limit warning confuses
|
@@ -603,10 +613,18 @@ class Table(Media):
|
|
603
613
|
|
604
614
|
@classmethod
|
605
615
|
def get_media_subdir(cls):
|
616
|
+
"""Get media subdirectory.
|
617
|
+
|
618
|
+
<!-- lazydoc-ignore-classmethod: internal -->
|
619
|
+
"""
|
606
620
|
return os.path.join("media", "table")
|
607
621
|
|
608
622
|
@classmethod
|
609
623
|
def from_json(cls, json_obj, source_artifact: "artifact.Artifact"):
|
624
|
+
"""Deserialize JSON object into it's class representation.
|
625
|
+
|
626
|
+
<!-- lazydoc-ignore-classmethod: internal -->
|
627
|
+
"""
|
610
628
|
data = []
|
611
629
|
column_types = None
|
612
630
|
np_deserialized_columns = {}
|
@@ -690,6 +708,10 @@ class Table(Media):
|
|
690
708
|
return new_obj
|
691
709
|
|
692
710
|
def to_json(self, run_or_artifact):
|
711
|
+
"""Returns the JSON representation expected by the backend.
|
712
|
+
|
713
|
+
<!-- lazydoc-ignore: internal -->
|
714
|
+
"""
|
693
715
|
json_dict = super().to_json(run_or_artifact)
|
694
716
|
|
695
717
|
if self.log_mode == "INCREMENTAL":
|
@@ -705,7 +727,7 @@ class Table(Media):
|
|
705
727
|
}
|
706
728
|
)
|
707
729
|
|
708
|
-
if isinstance(run_or_artifact, wandb.
|
730
|
+
if isinstance(run_or_artifact, wandb.Run):
|
709
731
|
if self.log_mode == "INCREMENTAL":
|
710
732
|
wbvalue_type = "incremental-table-file"
|
711
733
|
else:
|
@@ -799,11 +821,11 @@ class Table(Media):
|
|
799
821
|
|
800
822
|
Yields:
|
801
823
|
------
|
802
|
-
index
|
803
|
-
The index of the row. Using this value in other W&B tables
|
824
|
+
index: The index of the row. Using this value in other W&B tables
|
804
825
|
will automatically build a relationship between the tables
|
805
|
-
row
|
806
|
-
|
826
|
+
row: The data of the row.
|
827
|
+
|
828
|
+
<!-- lazydoc-ignore: internal -->
|
807
829
|
"""
|
808
830
|
for ndx in range(len(self.data)):
|
809
831
|
index = _TableIndex(ndx)
|
@@ -812,12 +834,20 @@ class Table(Media):
|
|
812
834
|
|
813
835
|
@allow_relogging_after_mutation
|
814
836
|
def set_pk(self, col_name):
|
837
|
+
"""Set primary key type for Table object.
|
838
|
+
|
839
|
+
<!-- lazydoc-ignore: internal -->
|
840
|
+
"""
|
815
841
|
# TODO: Docs
|
816
842
|
assert col_name in self.columns
|
817
843
|
self.cast(col_name, _PrimaryKeyType())
|
818
844
|
|
819
845
|
@allow_relogging_after_mutation
|
820
846
|
def set_fk(self, col_name, table, table_col):
|
847
|
+
"""Set foreign key type for Table object.
|
848
|
+
|
849
|
+
<!-- lazydoc-ignore: internal -->
|
850
|
+
"""
|
821
851
|
# TODO: Docs
|
822
852
|
assert col_name in self.columns
|
823
853
|
assert col_name != self._pk_col
|
@@ -932,9 +962,9 @@ class Table(Media):
|
|
932
962
|
assert isinstance(data, list) or is_np
|
933
963
|
assert isinstance(optional, bool)
|
934
964
|
is_first_col = len(self.columns) == 0
|
935
|
-
assert is_first_col or len(data) == len(
|
936
|
-
self.data
|
937
|
-
)
|
965
|
+
assert is_first_col or len(data) == len(self.data), (
|
966
|
+
f"Expected length {len(self.data)}, found {len(data)}"
|
967
|
+
)
|
938
968
|
|
939
969
|
# Add the new data
|
940
970
|
for ndx in range(max(len(data), len(self.data))):
|
@@ -1003,7 +1033,10 @@ class Table(Media):
|
|
1003
1033
|
return pd.DataFrame.from_records(self.data, columns=self.columns)
|
1004
1034
|
|
1005
1035
|
def index_ref(self, index):
|
1006
|
-
"""Gets a reference of the index of a row in the table.
|
1036
|
+
"""Gets a reference of the index of a row in the table.
|
1037
|
+
|
1038
|
+
<!-- lazydoc-ignore: internal -->
|
1039
|
+
"""
|
1007
1040
|
assert index < len(self.data)
|
1008
1041
|
_index = _TableIndex(index)
|
1009
1042
|
_index.set_table(self)
|
@@ -1015,14 +1048,12 @@ class Table(Media):
|
|
1015
1048
|
"""Adds one or more computed columns based on existing data.
|
1016
1049
|
|
1017
1050
|
Args:
|
1018
|
-
fn: A function which accepts one or two parameters, ndx (int) and
|
1019
|
-
which is expected to return a dict representing
|
1020
|
-
by the new column names.
|
1021
|
-
|
1022
|
-
`ndx` is an integer representing the index of the row. Only included if `include_ndx`
|
1051
|
+
fn: A function which accepts one or two parameters, ndx (int) and
|
1052
|
+
row (dict), which is expected to return a dict representing
|
1053
|
+
new columns for that row, keyed by the new column names.
|
1054
|
+
- `ndx` is an integer representing the index of the row. Only included if `include_ndx`
|
1023
1055
|
is set to `True`.
|
1024
|
-
|
1025
|
-
`row` is a dictionary keyed by existing columns
|
1056
|
+
- `row` is a dictionary keyed by existing columns
|
1026
1057
|
"""
|
1027
1058
|
new_columns = {}
|
1028
1059
|
for ndx, row in self.iterrows():
|
@@ -1056,7 +1087,8 @@ class _PartitionTablePartEntry:
|
|
1056
1087
|
class PartitionedTable(Media):
|
1057
1088
|
"""A table which is composed of multiple sub-tables.
|
1058
1089
|
|
1059
|
-
Currently, PartitionedTable is designed to point to a directory within an
|
1090
|
+
Currently, PartitionedTable is designed to point to a directory within an
|
1091
|
+
artifact.
|
1060
1092
|
"""
|
1061
1093
|
|
1062
1094
|
_log_type = "partitioned-table"
|
@@ -1075,7 +1107,7 @@ class PartitionedTable(Media):
|
|
1075
1107
|
json_obj = {
|
1076
1108
|
"_type": PartitionedTable._log_type,
|
1077
1109
|
}
|
1078
|
-
if isinstance(artifact_or_run, wandb.
|
1110
|
+
if isinstance(artifact_or_run, wandb.Run):
|
1079
1111
|
artifact_entry_url = self._get_artifact_entry_ref_url()
|
1080
1112
|
if artifact_entry_url is None:
|
1081
1113
|
raise ValueError(
|
@@ -1099,12 +1131,9 @@ class PartitionedTable(Media):
|
|
1099
1131
|
def iterrows(self):
|
1100
1132
|
"""Iterate over rows as (ndx, row).
|
1101
1133
|
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
The index of the row.
|
1106
|
-
row : List[any]
|
1107
|
-
The data of the row.
|
1134
|
+
Args:
|
1135
|
+
index (int): The index of the row.
|
1136
|
+
row (List[any]): The data of the row.
|
1108
1137
|
"""
|
1109
1138
|
columns = None
|
1110
1139
|
ndx = 0
|
@@ -1233,7 +1262,7 @@ class JoinedTable(Media):
|
|
1233
1262
|
json_obj = {
|
1234
1263
|
"_type": JoinedTable._log_type,
|
1235
1264
|
}
|
1236
|
-
if isinstance(artifact_or_run, wandb.
|
1265
|
+
if isinstance(artifact_or_run, wandb.Run):
|
1237
1266
|
artifact_entry_url = self._get_artifact_entry_ref_url()
|
1238
1267
|
if artifact_entry_url is None:
|
1239
1268
|
raise ValueError(
|
@@ -1257,13 +1286,13 @@ class JoinedTable(Media):
|
|
1257
1286
|
|
1258
1287
|
def _eq_debug(self, other, should_assert=False):
|
1259
1288
|
eq = isinstance(other, JoinedTable)
|
1260
|
-
assert (
|
1261
|
-
|
1262
|
-
)
|
1289
|
+
assert not should_assert or eq, (
|
1290
|
+
f"Found type {other.__class__}, expected {JoinedTable}"
|
1291
|
+
)
|
1263
1292
|
eq = eq and self._join_key == other._join_key
|
1264
|
-
assert (
|
1265
|
-
|
1266
|
-
)
|
1293
|
+
assert not should_assert or eq, (
|
1294
|
+
f"Found {other._join_key} join key, expected {self._join_key}"
|
1295
|
+
)
|
1267
1296
|
eq = eq and self._table1._eq_debug(other._table1, should_assert)
|
1268
1297
|
eq = eq and self._table2._eq_debug(other._table2, should_assert)
|
1269
1298
|
return eq
|
@@ -261,14 +261,14 @@ class Trace:
|
|
261
261
|
A Span object.
|
262
262
|
"""
|
263
263
|
if kind is not None:
|
264
|
-
assert (
|
265
|
-
kind
|
266
|
-
)
|
264
|
+
assert kind.upper() in SpanKind.__members__, (
|
265
|
+
"Invalid span kind, can be one of 'LLM', 'AGENT', 'CHAIN', 'TOOL'"
|
266
|
+
)
|
267
267
|
kind = SpanKind(kind.upper())
|
268
268
|
if status_code is not None:
|
269
|
-
assert (
|
270
|
-
|
271
|
-
)
|
269
|
+
assert status_code.upper() in StatusCode.__members__, (
|
270
|
+
"Invalid status code, can be one of 'SUCCESS' or 'ERROR'"
|
271
|
+
)
|
272
272
|
status_code = StatusCode(status_code.upper())
|
273
273
|
if inputs is not None:
|
274
274
|
assert isinstance(inputs, dict), "Inputs must be a dictionary"
|
@@ -419,9 +419,9 @@ class Trace:
|
|
419
419
|
Args:
|
420
420
|
value: The kind of the trace to be set.
|
421
421
|
"""
|
422
|
-
assert (
|
423
|
-
|
424
|
-
)
|
422
|
+
assert value.upper() in SpanKind.__members__, (
|
423
|
+
"Invalid span kind, can be one of 'LLM', 'AGENT', 'CHAIN', 'TOOL'"
|
424
|
+
)
|
425
425
|
self._span.span_kind = SpanKind(value.upper())
|
426
426
|
|
427
427
|
def log(self, name: str) -> None:
|
@@ -433,8 +433,8 @@ class Trace:
|
|
433
433
|
trace_tree = WBTraceTree(self._span, self._model_dict)
|
434
434
|
# NOTE: Does not work for reinit="create_new" runs.
|
435
435
|
# This method should be deprecated and users should call run.log().
|
436
|
-
assert (
|
437
|
-
wandb.
|
438
|
-
)
|
436
|
+
assert wandb.run is not None, (
|
437
|
+
"You must call wandb.init() before logging a trace"
|
438
|
+
)
|
439
439
|
assert len(name.strip()) > 0, "You must provide a valid name to log the trace"
|
440
440
|
wandb.run.log({name: trace_tree})
|
wandb/sdk/data_types/video.py
CHANGED
@@ -6,7 +6,8 @@ from io import BytesIO
|
|
6
6
|
from typing import TYPE_CHECKING, Any, Literal, Optional, Sequence, Type, Union
|
7
7
|
|
8
8
|
import wandb
|
9
|
-
from wandb import util
|
9
|
+
from wandb import env, util
|
10
|
+
from wandb.sdk import wandb_setup
|
10
11
|
from wandb.sdk.lib import filesystem, printer, printer_asyncio, runid
|
11
12
|
|
12
13
|
from . import _dtypes
|
@@ -23,6 +24,14 @@ if TYPE_CHECKING: # pragma: no cover
|
|
23
24
|
from ..wandb_run import Run as LocalRun
|
24
25
|
|
25
26
|
|
27
|
+
def _should_print_spinner() -> bool:
|
28
|
+
singleton = wandb_setup.singleton_if_setup()
|
29
|
+
if singleton and (singleton.settings.quiet or singleton.settings.silent):
|
30
|
+
return False
|
31
|
+
|
32
|
+
return not env.is_quiet() and not env.is_silent()
|
33
|
+
|
34
|
+
|
26
35
|
# This helper function is a workaround for the issue discussed here:
|
27
36
|
# https://github.com/wandb/wandb/issues/3472
|
28
37
|
#
|
@@ -80,40 +89,38 @@ class Video(BatchableMedia):
|
|
80
89
|
"""Initialize a W&B Video object.
|
81
90
|
|
82
91
|
Args:
|
83
|
-
data_or_path:
|
84
|
-
Video can be initialized with a
|
85
|
-
|
86
|
-
The numpy tensor must be either 4 dimensional or 5 dimensional.
|
92
|
+
data_or_path: Video can be initialized with a path to a file or an io object.
|
93
|
+
Video can be initialized with a numpy tensor. The numpy tensor
|
94
|
+
must be either 4 dimensional or 5 dimensional.
|
87
95
|
The dimensions should be (number of frames, channel, height, width) or
|
88
96
|
(batch, number of frames, channel, height, width)
|
89
97
|
The format parameter must be specified with the format argument
|
90
98
|
when initializing with a numpy array
|
91
99
|
or io object.
|
92
100
|
caption: Caption associated with the video for display.
|
93
|
-
fps:
|
94
|
-
The frame rate to use when encoding raw video frames.
|
101
|
+
fps: The frame rate to use when encoding raw video frames.
|
95
102
|
Default value is 4.
|
96
103
|
This parameter has no effect when data_or_path is a string, or bytes.
|
97
|
-
format:
|
98
|
-
Format of video, necessary if initializing with a numpy array
|
104
|
+
format: Format of video, necessary if initializing with a numpy array
|
99
105
|
or io object. This parameter will be used to determine the format
|
100
106
|
to use when encoding the video data. Accepted values are "gif",
|
101
107
|
"mp4", "webm", or "ogg".
|
102
108
|
If no value is provided, the default format will be "gif".
|
103
109
|
|
104
110
|
Examples:
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
)
|
115
|
-
|
116
|
-
|
111
|
+
Log a numpy array as a video
|
112
|
+
|
113
|
+
```python
|
114
|
+
import numpy as np
|
115
|
+
import wandb
|
116
|
+
|
117
|
+
with wandb.init() as run:
|
118
|
+
# axes are (number of frames, channel, height, width)
|
119
|
+
frames = np.random.randint(
|
120
|
+
low=0, high=256, size=(10, 3, 100, 100), dtype=np.uint8
|
121
|
+
)
|
122
|
+
run.log({"video": wandb.Video(frames, format="mp4", fps=4)})
|
123
|
+
```
|
117
124
|
"""
|
118
125
|
super().__init__(caption=caption)
|
119
126
|
|
@@ -167,13 +174,21 @@ class Video(BatchableMedia):
|
|
167
174
|
"wandb.Video accepts a file path or numpy like data as input"
|
168
175
|
)
|
169
176
|
fps = fps or 4
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
177
|
+
|
178
|
+
if _should_print_spinner():
|
179
|
+
printer_asyncio.run_async_with_spinner(
|
180
|
+
printer.new_printer(),
|
181
|
+
"Encoding video...",
|
182
|
+
functools.partial(self.encode, fps=fps),
|
183
|
+
)
|
184
|
+
else:
|
185
|
+
self.encode(fps=fps)
|
175
186
|
|
176
187
|
def encode(self, fps: int = 4) -> None:
|
188
|
+
"""Encode the video data to a file.
|
189
|
+
|
190
|
+
<!-- lazydoc-ignore: internal -->
|
191
|
+
"""
|
177
192
|
# import ImageSequenceClip from the appropriate MoviePy module
|
178
193
|
mpy = util.get_module(
|
179
194
|
"moviepy.video.io.ImageSequenceClip",
|
@@ -199,9 +214,17 @@ class Video(BatchableMedia):
|
|
199
214
|
|
200
215
|
@classmethod
|
201
216
|
def get_media_subdir(cls: Type["Video"]) -> str:
|
217
|
+
"""Get media subdirectory for video files.
|
218
|
+
|
219
|
+
<!-- lazydoc-ignore-classmethod: internal -->
|
220
|
+
"""
|
202
221
|
return os.path.join("media", "videos")
|
203
222
|
|
204
223
|
def to_json(self, run_or_artifact: Union["LocalRun", "Artifact"]) -> dict:
|
224
|
+
"""Returns the JSON representation expected by the backend.
|
225
|
+
|
226
|
+
<!-- lazydoc-ignore: internal -->
|
227
|
+
"""
|
205
228
|
json_dict = super().to_json(run_or_artifact)
|
206
229
|
json_dict["_type"] = self._log_type
|
207
230
|
|
@@ -256,6 +279,10 @@ class Video(BatchableMedia):
|
|
256
279
|
key: str,
|
257
280
|
step: Union[int, str],
|
258
281
|
) -> dict:
|
282
|
+
"""Convert a sequence of Video objects to a JSON representation.
|
283
|
+
|
284
|
+
<!-- lazydoc-ignore-classmethod: internal -->
|
285
|
+
"""
|
259
286
|
base_path = os.path.join(run.dir, cls.get_media_subdir())
|
260
287
|
filesystem.mkdir_exists_ok(base_path)
|
261
288
|
|
@@ -71,7 +71,7 @@ class PatchAPI:
|
|
71
71
|
)
|
72
72
|
return self._api
|
73
73
|
|
74
|
-
def patch(self, run: "wandb.
|
74
|
+
def patch(self, run: "wandb.Run") -> None:
|
75
75
|
"""Patches the API to log media or metrics to W&B."""
|
76
76
|
for symbol in self.symbols:
|
77
77
|
# split on dots, e.g. "Client.generate" -> ["Client", "generate"]
|
@@ -163,7 +163,7 @@ class AutologAPI:
|
|
163
163
|
resolver=resolver,
|
164
164
|
)
|
165
165
|
self._name = self._patch_api.name
|
166
|
-
self._run: Optional[wandb.
|
166
|
+
self._run: Optional[wandb.Run] = None
|
167
167
|
self.__run_created_by_autolog: bool = False
|
168
168
|
|
169
169
|
@property
|
wandb/sdk/interface/interface.py
CHANGED
@@ -150,8 +150,7 @@ class InterfaceBase:
|
|
150
150
|
if run._settings.run_notes is not None:
|
151
151
|
proto_run.notes = run._settings.run_notes
|
152
152
|
if run._settings.run_tags is not None:
|
153
|
-
|
154
|
-
proto_run.tags.append(tag)
|
153
|
+
proto_run.tags.extend(run._settings.run_tags)
|
155
154
|
if run._start_time is not None:
|
156
155
|
proto_run.start_time.FromMicroseconds(int(run._start_time * 1e6))
|
157
156
|
if run._starting_step is not None:
|
@@ -217,13 +216,6 @@ class InterfaceBase:
|
|
217
216
|
def _publish_config(self, cfg: pb.ConfigRecord) -> None:
|
218
217
|
raise NotImplementedError
|
219
218
|
|
220
|
-
def publish_metadata(self, metadata: pb.MetadataRequest) -> None:
|
221
|
-
self._publish_metadata(metadata)
|
222
|
-
|
223
|
-
@abstractmethod
|
224
|
-
def _publish_metadata(self, metadata: pb.MetadataRequest) -> None:
|
225
|
-
raise NotImplementedError
|
226
|
-
|
227
219
|
@abstractmethod
|
228
220
|
def _publish_metric(self, metric: pb.MetricRecord) -> None:
|
229
221
|
raise NotImplementedError
|
@@ -671,6 +663,13 @@ class InterfaceBase:
|
|
671
663
|
def _publish_telemetry(self, telem: tpb.TelemetryRecord) -> None:
|
672
664
|
raise NotImplementedError
|
673
665
|
|
666
|
+
def publish_environment(self, environment: pb.EnvironmentRecord) -> None:
|
667
|
+
self._publish_environment(environment)
|
668
|
+
|
669
|
+
@abstractmethod
|
670
|
+
def _publish_environment(self, environment: pb.EnvironmentRecord) -> None:
|
671
|
+
raise NotImplementedError
|
672
|
+
|
674
673
|
def publish_partial_history(
|
675
674
|
self,
|
676
675
|
run: "Run",
|
@@ -1000,16 +999,6 @@ class InterfaceBase:
|
|
1000
999
|
) -> MailboxHandle[pb.Result]:
|
1001
1000
|
raise NotImplementedError
|
1002
1001
|
|
1003
|
-
def deliver_get_system_metadata(self) -> MailboxHandle[pb.Result]:
|
1004
|
-
get_system_metadata = pb.GetSystemMetadataRequest()
|
1005
|
-
return self._deliver_get_system_metadata(get_system_metadata)
|
1006
|
-
|
1007
|
-
@abstractmethod
|
1008
|
-
def _deliver_get_system_metadata(
|
1009
|
-
self, get_system_metadata: pb.GetSystemMetadataRequest
|
1010
|
-
) -> MailboxHandle[pb.Result]:
|
1011
|
-
raise NotImplementedError
|
1012
|
-
|
1013
1002
|
def deliver_exit(self, exit_code: Optional[int]) -> MailboxHandle[pb.Result]:
|
1014
1003
|
exit_data = self._make_exit(exit_code)
|
1015
1004
|
return self._deliver_exit(exit_data)
|