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.
Files changed (140) hide show
  1. wandb/__init__.py +16 -14
  2. wandb/__init__.pyi +450 -472
  3. wandb/agents/pyagent.py +41 -12
  4. wandb/analytics/sentry.py +7 -2
  5. wandb/apis/importers/mlflow.py +1 -1
  6. wandb/apis/internal.py +3 -0
  7. wandb/apis/paginator.py +17 -4
  8. wandb/apis/public/__init__.py +1 -1
  9. wandb/apis/public/api.py +606 -359
  10. wandb/apis/public/artifacts.py +214 -16
  11. wandb/apis/public/automations.py +19 -3
  12. wandb/apis/public/files.py +177 -38
  13. wandb/apis/public/history.py +67 -15
  14. wandb/apis/public/integrations.py +25 -2
  15. wandb/apis/public/jobs.py +90 -2
  16. wandb/apis/public/projects.py +161 -69
  17. wandb/apis/public/query_generator.py +11 -1
  18. wandb/apis/public/registries/registries_search.py +7 -15
  19. wandb/apis/public/reports.py +147 -13
  20. wandb/apis/public/runs.py +315 -128
  21. wandb/apis/public/sweeps.py +222 -22
  22. wandb/apis/public/teams.py +41 -4
  23. wandb/apis/public/users.py +45 -4
  24. wandb/automations/__init__.py +10 -10
  25. wandb/automations/_filters/run_metrics.py +0 -2
  26. wandb/automations/_utils.py +0 -2
  27. wandb/automations/actions.py +0 -2
  28. wandb/automations/automations.py +0 -2
  29. wandb/automations/events.py +0 -2
  30. wandb/beta/workflows.py +66 -30
  31. wandb/bin/gpu_stats +0 -0
  32. wandb/bin/wandb-core +0 -0
  33. wandb/cli/cli.py +80 -1
  34. wandb/env.py +8 -0
  35. wandb/errors/errors.py +4 -1
  36. wandb/integration/catboost/catboost.py +6 -2
  37. wandb/integration/kfp/kfp_patch.py +3 -1
  38. wandb/integration/lightning/fabric/logger.py +3 -4
  39. wandb/integration/metaflow/__init__.py +6 -0
  40. wandb/integration/metaflow/data_pandas.py +74 -0
  41. wandb/integration/metaflow/errors.py +13 -0
  42. wandb/integration/metaflow/metaflow.py +205 -190
  43. wandb/integration/openai/fine_tuning.py +1 -2
  44. wandb/integration/sb3/sb3.py +3 -3
  45. wandb/integration/ultralytics/callback.py +6 -2
  46. wandb/jupyter.py +5 -5
  47. wandb/plot/__init__.py +2 -0
  48. wandb/plot/bar.py +30 -29
  49. wandb/plot/confusion_matrix.py +75 -71
  50. wandb/plot/custom_chart.py +30 -7
  51. wandb/plot/histogram.py +26 -25
  52. wandb/plot/line.py +33 -32
  53. wandb/plot/line_series.py +100 -103
  54. wandb/plot/pr_curve.py +33 -32
  55. wandb/plot/roc_curve.py +38 -38
  56. wandb/plot/scatter.py +27 -27
  57. wandb/proto/v3/wandb_internal_pb2.py +366 -385
  58. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  59. wandb/proto/v3/wandb_telemetry_pb2.py +4 -4
  60. wandb/proto/v4/wandb_internal_pb2.py +352 -356
  61. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  62. wandb/proto/v4/wandb_telemetry_pb2.py +4 -4
  63. wandb/proto/v5/wandb_internal_pb2.py +352 -356
  64. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  65. wandb/proto/v5/wandb_telemetry_pb2.py +4 -4
  66. wandb/proto/v6/wandb_internal_pb2.py +352 -356
  67. wandb/proto/v6/wandb_settings_pb2.py +2 -2
  68. wandb/proto/v6/wandb_telemetry_pb2.py +4 -4
  69. wandb/proto/wandb_deprecated.py +6 -0
  70. wandb/sdk/artifacts/_generated/__init__.py +12 -1
  71. wandb/sdk/artifacts/_generated/input_types.py +20 -2
  72. wandb/sdk/artifacts/_generated/link_artifact.py +21 -0
  73. wandb/sdk/artifacts/_generated/operations.py +9 -0
  74. wandb/sdk/artifacts/_internal_artifact.py +19 -8
  75. wandb/sdk/artifacts/_validators.py +48 -2
  76. wandb/sdk/artifacts/artifact.py +269 -96
  77. wandb/sdk/data_types/audio.py +38 -10
  78. wandb/sdk/data_types/base_types/media.py +15 -63
  79. wandb/sdk/data_types/base_types/wb_value.py +6 -6
  80. wandb/sdk/data_types/graph.py +48 -14
  81. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +1 -3
  82. wandb/sdk/data_types/helper_types/image_mask.py +1 -3
  83. wandb/sdk/data_types/histogram.py +34 -21
  84. wandb/sdk/data_types/html.py +35 -12
  85. wandb/sdk/data_types/image.py +104 -68
  86. wandb/sdk/data_types/molecule.py +32 -19
  87. wandb/sdk/data_types/object_3d.py +36 -17
  88. wandb/sdk/data_types/plotly.py +18 -5
  89. wandb/sdk/data_types/saved_model.py +7 -9
  90. wandb/sdk/data_types/table.py +99 -70
  91. wandb/sdk/data_types/trace_tree.py +12 -12
  92. wandb/sdk/data_types/video.py +53 -26
  93. wandb/sdk/integration_utils/auto_logging.py +2 -2
  94. wandb/sdk/interface/interface.py +8 -19
  95. wandb/sdk/interface/interface_shared.py +7 -16
  96. wandb/sdk/internal/datastore.py +18 -18
  97. wandb/sdk/internal/handler.py +3 -5
  98. wandb/sdk/internal/internal_api.py +60 -0
  99. wandb/sdk/internal/job_builder.py +6 -0
  100. wandb/sdk/internal/sender.py +23 -3
  101. wandb/sdk/internal/sender_config.py +9 -0
  102. wandb/sdk/launch/_project_spec.py +3 -3
  103. wandb/sdk/launch/agent/agent.py +11 -4
  104. wandb/sdk/launch/agent/job_status_tracker.py +3 -1
  105. wandb/sdk/launch/agent/run_queue_item_file_saver.py +2 -2
  106. wandb/sdk/launch/create_job.py +3 -1
  107. wandb/sdk/launch/inputs/internal.py +3 -4
  108. wandb/sdk/launch/inputs/schema.py +1 -0
  109. wandb/sdk/launch/runner/kubernetes_monitor.py +1 -0
  110. wandb/sdk/launch/runner/kubernetes_runner.py +328 -1
  111. wandb/sdk/launch/sweeps/scheduler.py +2 -3
  112. wandb/sdk/launch/utils.py +3 -3
  113. wandb/sdk/lib/asyncio_compat.py +3 -0
  114. wandb/sdk/lib/console_capture.py +66 -19
  115. wandb/sdk/lib/deprecate.py +1 -7
  116. wandb/sdk/lib/disabled.py +1 -1
  117. wandb/sdk/lib/hashutil.py +14 -1
  118. wandb/sdk/lib/module.py +7 -13
  119. wandb/sdk/lib/progress.py +0 -19
  120. wandb/sdk/lib/sock_client.py +0 -4
  121. wandb/sdk/wandb_init.py +67 -93
  122. wandb/sdk/wandb_login.py +18 -14
  123. wandb/sdk/wandb_metric.py +2 -0
  124. wandb/sdk/wandb_require.py +0 -1
  125. wandb/sdk/wandb_run.py +429 -527
  126. wandb/sdk/wandb_settings.py +364 -74
  127. wandb/sdk/wandb_setup.py +28 -28
  128. wandb/sdk/wandb_sweep.py +14 -13
  129. wandb/sdk/wandb_watch.py +4 -6
  130. wandb/sync/sync.py +10 -0
  131. wandb/util.py +57 -0
  132. wandb/wandb_run.py +1 -2
  133. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/METADATA +1 -1
  134. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/RECORD +137 -137
  135. wandb/sdk/wandb_metadata.py +0 -623
  136. wandb/vendor/pynvml/__init__.py +0 -0
  137. wandb/vendor/pynvml/pynvml.py +0 -4779
  138. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/WHEEL +0 -0
  139. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/entry_points.txt +0 -0
  140. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.1.dist-info}/licenses/LICENSE +0 -0
@@ -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 the Table Visualizer
207
- in the UI: https://docs.wandb.ai/guides/data-vis/tables.
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 in _SUPPORTED_LOGGING_MODES
297
- ), f"Invalid log_mode: {log_mode}. Must be one of {_SUPPORTED_LOGGING_MODES}"
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
- ), "ndarray argument expects a `numpy.ndarray` object"
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
- ), "dataframe argument expects a `pandas.core.frame.DataFrame` object"
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, or an
414
- example object, like an instance of wandb.Image or wandb.Classes.
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: (str) - The name of the column to cast.
418
- dtype: (class, wandb.wandb_sdk.interface._dtypes.Type, any) - The target dtype.
419
- optional: (bool) - If the column should allow Nones.
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
- not optional
445
- ), "Primary keys, foreign keys, and foreign indexes cannot be optional."
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 None
453
- ), f"Cannot have multiple primary keys - {self._pk_col} is already set as the primary key."
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
- not should_assert or eq
469
- ), f"Found type {other.__class__}, expected {Table}"
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
- not should_assert or eq
473
- ), f"Found {len(other.data)} rows, expected {len(self.data)}"
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
- not should_assert or eq
477
- ), f"Found columns {other.columns}, expected {self.columns}"
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
- not should_assert or eq
481
- ), f"Found column type {other._column_types}, expected column type {self._column_types}"
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
- not should_assert or eq
492
- ), 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]}"
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; use add_data instead."""
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. The maximum amount of rows in a table is determined by `wandb.Table.MAX_ARTIFACT_ROWS`.
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.wandb_sdk.wandb_run.Run):
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 : int
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 : List[any]
806
- The data of the row.
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
- ), f"Expected length {len(self.data)}, found {len(data)}"
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 row (dict),
1019
- which is expected to return a dict representing new columns for that row, keyed
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 artifact.
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.wandb_sdk.wandb_run.Run):
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
- Yields:
1103
- ------
1104
- index : int
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.wandb_sdk.wandb_run.Run):
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
- not should_assert or eq
1262
- ), f"Found type {other.__class__}, expected {JoinedTable}"
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
- not should_assert or eq
1266
- ), f"Found {other._join_key} join key, expected {self._join_key}"
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.upper() in SpanKind.__members__
266
- ), "Invalid span kind, can be one of 'LLM', 'AGENT', 'CHAIN', 'TOOL'"
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
- status_code.upper() in StatusCode.__members__
271
- ), "Invalid status code, can be one of 'SUCCESS' or 'ERROR'"
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
- value.upper() in SpanKind.__members__
424
- ), "Invalid span kind, can be one of 'LLM', 'AGENT', 'CHAIN', 'TOOL'"
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.run is not None
438
- ), "You must call wandb.init() before logging a trace"
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})
@@ -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 path to a file or an io object.
85
- Video can be initialized with a numpy tensor.
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
- ### Log a numpy array as a video
106
- ```python
107
- import numpy as np
108
- import wandb
109
-
110
- with wandb.init() as run:
111
- # axes are (number of frames, channel, height, width)
112
- frames = np.random.randint(
113
- low=0, high=256, size=(10, 3, 100, 100), dtype=np.uint8
114
- )
115
- run.log({"video": wandb.Video(frames, format="mp4", fps=4)})
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
- printer_asyncio.run_async_with_spinner(
171
- printer.new_printer(),
172
- "Encoding video...",
173
- functools.partial(self.encode, fps=fps),
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.sdk.wandb_run.Run") -> None:
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.sdk.wandb_run.Run] = None
166
+ self._run: Optional[wandb.Run] = None
167
167
  self.__run_created_by_autolog: bool = False
168
168
 
169
169
  @property
@@ -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
- for tag in run._settings.run_tags:
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)