wandb 0.21.0__py3-none-win_amd64.whl → 0.21.2__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.
Files changed (153) hide show
  1. wandb/__init__.py +16 -14
  2. wandb/__init__.pyi +427 -450
  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/public/__init__.py +1 -1
  7. wandb/apis/public/api.py +525 -360
  8. wandb/apis/public/artifacts.py +207 -13
  9. wandb/apis/public/automations.py +19 -3
  10. wandb/apis/public/files.py +172 -33
  11. wandb/apis/public/history.py +67 -15
  12. wandb/apis/public/integrations.py +25 -2
  13. wandb/apis/public/jobs.py +90 -2
  14. wandb/apis/public/projects.py +130 -79
  15. wandb/apis/public/query_generator.py +11 -1
  16. wandb/apis/public/registries/_utils.py +14 -16
  17. wandb/apis/public/registries/registries_search.py +183 -304
  18. wandb/apis/public/reports.py +96 -15
  19. wandb/apis/public/runs.py +299 -105
  20. wandb/apis/public/sweeps.py +222 -22
  21. wandb/apis/public/teams.py +41 -4
  22. wandb/apis/public/users.py +45 -4
  23. wandb/automations/_generated/delete_automation.py +1 -3
  24. wandb/automations/_generated/enums.py +13 -11
  25. wandb/beta/workflows.py +66 -30
  26. wandb/bin/gpu_stats.exe +0 -0
  27. wandb/bin/wandb-core +0 -0
  28. wandb/cli/cli.py +127 -3
  29. wandb/env.py +8 -0
  30. wandb/errors/errors.py +4 -1
  31. wandb/integration/lightning/fabric/logger.py +3 -4
  32. wandb/integration/metaflow/__init__.py +6 -0
  33. wandb/integration/metaflow/data_pandas.py +74 -0
  34. wandb/integration/metaflow/data_pytorch.py +75 -0
  35. wandb/integration/metaflow/data_sklearn.py +76 -0
  36. wandb/integration/metaflow/errors.py +13 -0
  37. wandb/integration/metaflow/metaflow.py +167 -223
  38. wandb/integration/openai/fine_tuning.py +1 -2
  39. wandb/integration/weave/__init__.py +6 -0
  40. wandb/integration/weave/interface.py +49 -0
  41. wandb/integration/weave/weave.py +63 -0
  42. wandb/jupyter.py +5 -5
  43. wandb/plot/custom_chart.py +30 -7
  44. wandb/proto/v3/wandb_internal_pb2.py +281 -280
  45. wandb/proto/v3/wandb_telemetry_pb2.py +4 -4
  46. wandb/proto/v4/wandb_internal_pb2.py +280 -280
  47. wandb/proto/v4/wandb_telemetry_pb2.py +4 -4
  48. wandb/proto/v5/wandb_internal_pb2.py +280 -280
  49. wandb/proto/v5/wandb_telemetry_pb2.py +4 -4
  50. wandb/proto/v6/wandb_internal_pb2.py +280 -280
  51. wandb/proto/v6/wandb_telemetry_pb2.py +4 -4
  52. wandb/proto/wandb_deprecated.py +6 -0
  53. wandb/sdk/artifacts/_factories.py +17 -0
  54. wandb/sdk/artifacts/_generated/__init__.py +221 -13
  55. wandb/sdk/artifacts/_generated/artifact_by_id.py +17 -0
  56. wandb/sdk/artifacts/_generated/artifact_by_name.py +22 -0
  57. wandb/sdk/artifacts/_generated/artifact_collection_membership_file_urls.py +43 -0
  58. wandb/sdk/artifacts/_generated/artifact_created_by.py +47 -0
  59. wandb/sdk/artifacts/_generated/artifact_file_urls.py +22 -0
  60. wandb/sdk/artifacts/_generated/artifact_type.py +31 -0
  61. wandb/sdk/artifacts/_generated/artifact_used_by.py +43 -0
  62. wandb/sdk/artifacts/_generated/artifact_via_membership_by_name.py +26 -0
  63. wandb/sdk/artifacts/_generated/delete_artifact.py +28 -0
  64. wandb/sdk/artifacts/_generated/enums.py +5 -0
  65. wandb/sdk/artifacts/_generated/fetch_artifact_manifest.py +38 -0
  66. wandb/sdk/artifacts/_generated/fetch_registries.py +32 -0
  67. wandb/sdk/artifacts/_generated/fragments.py +279 -41
  68. wandb/sdk/artifacts/_generated/link_artifact.py +6 -0
  69. wandb/sdk/artifacts/_generated/operations.py +654 -51
  70. wandb/sdk/artifacts/_generated/registry_collections.py +34 -0
  71. wandb/sdk/artifacts/_generated/registry_versions.py +34 -0
  72. wandb/sdk/artifacts/_generated/unlink_artifact.py +25 -0
  73. wandb/sdk/artifacts/_graphql_fragments.py +3 -86
  74. wandb/sdk/artifacts/_internal_artifact.py +19 -8
  75. wandb/sdk/artifacts/_validators.py +14 -4
  76. wandb/sdk/artifacts/artifact.py +512 -618
  77. wandb/sdk/artifacts/artifact_file_cache.py +10 -6
  78. wandb/sdk/artifacts/artifact_manifest.py +10 -9
  79. wandb/sdk/artifacts/artifact_manifest_entry.py +9 -10
  80. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +5 -3
  81. wandb/sdk/artifacts/storage_handlers/http_handler.py +1 -1
  82. wandb/sdk/artifacts/storage_handlers/s3_handler.py +1 -1
  83. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +1 -1
  84. wandb/sdk/data_types/audio.py +38 -10
  85. wandb/sdk/data_types/base_types/media.py +6 -56
  86. wandb/sdk/data_types/graph.py +48 -14
  87. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +1 -3
  88. wandb/sdk/data_types/helper_types/image_mask.py +1 -3
  89. wandb/sdk/data_types/histogram.py +34 -21
  90. wandb/sdk/data_types/html.py +35 -12
  91. wandb/sdk/data_types/image.py +104 -68
  92. wandb/sdk/data_types/molecule.py +32 -19
  93. wandb/sdk/data_types/object_3d.py +36 -17
  94. wandb/sdk/data_types/plotly.py +18 -5
  95. wandb/sdk/data_types/saved_model.py +4 -6
  96. wandb/sdk/data_types/table.py +59 -30
  97. wandb/sdk/data_types/video.py +53 -26
  98. wandb/sdk/integration_utils/auto_logging.py +2 -2
  99. wandb/sdk/interface/interface_queue.py +1 -4
  100. wandb/sdk/interface/interface_shared.py +26 -37
  101. wandb/sdk/interface/interface_sock.py +24 -14
  102. wandb/sdk/internal/internal_api.py +6 -0
  103. wandb/sdk/internal/job_builder.py +6 -0
  104. wandb/sdk/internal/settings_static.py +2 -3
  105. wandb/sdk/launch/agent/agent.py +8 -1
  106. wandb/sdk/launch/agent/run_queue_item_file_saver.py +2 -2
  107. wandb/sdk/launch/create_job.py +15 -2
  108. wandb/sdk/launch/inputs/internal.py +3 -4
  109. wandb/sdk/launch/inputs/schema.py +1 -0
  110. wandb/sdk/launch/runner/kubernetes_monitor.py +1 -0
  111. wandb/sdk/launch/runner/kubernetes_runner.py +323 -1
  112. wandb/sdk/launch/sweeps/scheduler.py +2 -3
  113. wandb/sdk/lib/asyncio_compat.py +19 -16
  114. wandb/sdk/lib/asyncio_manager.py +252 -0
  115. wandb/sdk/lib/deprecate.py +1 -7
  116. wandb/sdk/lib/disabled.py +1 -1
  117. wandb/sdk/lib/hashutil.py +27 -5
  118. wandb/sdk/lib/module.py +7 -13
  119. wandb/sdk/lib/printer.py +2 -2
  120. wandb/sdk/lib/printer_asyncio.py +3 -1
  121. wandb/sdk/lib/progress.py +0 -19
  122. wandb/sdk/lib/retry.py +185 -78
  123. wandb/sdk/lib/service/service_client.py +106 -0
  124. wandb/sdk/lib/service/service_connection.py +20 -26
  125. wandb/sdk/lib/service/service_token.py +30 -13
  126. wandb/sdk/mailbox/mailbox.py +13 -5
  127. wandb/sdk/mailbox/mailbox_handle.py +22 -13
  128. wandb/sdk/mailbox/response_handle.py +42 -106
  129. wandb/sdk/mailbox/wait_with_progress.py +7 -42
  130. wandb/sdk/wandb_init.py +77 -116
  131. wandb/sdk/wandb_login.py +19 -15
  132. wandb/sdk/wandb_metric.py +2 -0
  133. wandb/sdk/wandb_run.py +497 -469
  134. wandb/sdk/wandb_settings.py +145 -4
  135. wandb/sdk/wandb_setup.py +204 -124
  136. wandb/sdk/wandb_sweep.py +14 -13
  137. wandb/sdk/wandb_watch.py +4 -6
  138. wandb/sync/sync.py +10 -0
  139. wandb/util.py +58 -1
  140. wandb/wandb_run.py +1 -2
  141. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/METADATA +1 -1
  142. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/RECORD +145 -129
  143. wandb/sdk/interface/interface_relay.py +0 -38
  144. wandb/sdk/interface/router.py +0 -89
  145. wandb/sdk/interface/router_queue.py +0 -43
  146. wandb/sdk/interface/router_relay.py +0 -50
  147. wandb/sdk/interface/router_sock.py +0 -32
  148. wandb/sdk/lib/sock_client.py +0 -236
  149. wandb/vendor/pynvml/__init__.py +0 -0
  150. wandb/vendor/pynvml/pynvml.py +0 -4779
  151. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/WHEEL +0 -0
  152. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/entry_points.txt +0 -0
  153. {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/licenses/LICENSE +0 -0
@@ -23,7 +23,6 @@ if TYPE_CHECKING:
23
23
  from typing_extensions import Self
24
24
 
25
25
  from wandb.sdk.artifacts.artifact import Artifact
26
- from wandb.sdk.wandb_run import Run as LocalRun
27
26
 
28
27
 
29
28
  DEBUG_MODE = False
@@ -137,15 +136,14 @@ class _SavedModel(WBValue, Generic[SavedModelObjType]):
137
136
  # and specified adapter.
138
137
  return cls(dl_path)
139
138
 
140
- def to_json(self, run_or_artifact: LocalRun | Artifact) -> dict:
139
+ def to_json(self, run_or_artifact: wandb.Run | Artifact) -> dict:
141
140
  # Unlike other data types, we do not allow adding to a Run directly. There is a
142
141
  # bit of tech debt in the other data types which requires the input to `to_json`
143
142
  # to accept a Run or Artifact. However, Run additions should be deprecated in the future.
144
143
  # This check helps ensure we do not add to the debt.
145
- from wandb.sdk.wandb_run import Run
146
-
147
- if isinstance(run_or_artifact, Run):
144
+ if isinstance(run_or_artifact, wandb.Run):
148
145
  raise TypeError("SavedModel cannot be added to run - must use artifact")
146
+
149
147
  artifact = run_or_artifact
150
148
  json_obj = {
151
149
  "type": self._log_type,
@@ -329,7 +327,7 @@ class _PicklingSavedModel(_SavedModel[SavedModelObjType]):
329
327
 
330
328
  return inst # type: ignore
331
329
 
332
- def to_json(self, run_or_artifact: LocalRun | Artifact) -> dict:
330
+ def to_json(self, run_or_artifact: wandb.Run | Artifact) -> dict:
333
331
  json_obj = super().to_json(run_or_artifact)
334
332
  assert isinstance(run_or_artifact, wandb.Artifact)
335
333
  if self._dep_py_files_path is not None:
@@ -203,7 +203,7 @@ 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 W&B Tables
206
+ This class is the primary class used to generate W&B Tables
207
207
  https://docs.wandb.ai/guides/models/tables/.
208
208
  """
209
209
 
@@ -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
@@ -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
 
@@ -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
@@ -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(
@@ -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
+ settings = wandb_setup.singleton().settings_if_loaded
29
+ if settings and (settings.quiet or 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
@@ -8,8 +8,6 @@ import logging
8
8
  from multiprocessing.process import BaseProcess
9
9
  from typing import TYPE_CHECKING, Optional
10
10
 
11
- from wandb.sdk.mailbox import Mailbox
12
-
13
11
  from .interface_shared import InterfaceShared
14
12
 
15
13
  if TYPE_CHECKING:
@@ -27,12 +25,11 @@ class InterfaceQueue(InterfaceShared):
27
25
  record_q: Optional["Queue[pb.Record]"] = None,
28
26
  result_q: Optional["Queue[pb.Result]"] = None,
29
27
  process: Optional[BaseProcess] = None,
30
- mailbox: Optional[Mailbox] = None,
31
28
  ) -> None:
32
29
  self.record_q = record_q
33
30
  self.result_q = result_q
34
31
  self._process = process
35
- super().__init__(mailbox=mailbox)
32
+ super().__init__()
36
33
 
37
34
  def _publish(self, record: "pb.Record", local: Optional[bool] = None) -> None:
38
35
  if self._process and not self._process.is_alive():
@@ -10,7 +10,7 @@ from typing import Any, Optional, cast
10
10
 
11
11
  from wandb.proto import wandb_internal_pb2 as pb
12
12
  from wandb.proto import wandb_telemetry_pb2 as tpb
13
- from wandb.sdk.mailbox import Mailbox, MailboxHandle
13
+ from wandb.sdk.mailbox import MailboxHandle
14
14
  from wandb.util import json_dumps_safer, json_friendly
15
15
 
16
16
  from .interface import InterfaceBase
@@ -19,9 +19,8 @@ logger = logging.getLogger("wandb")
19
19
 
20
20
 
21
21
  class InterfaceShared(InterfaceBase):
22
- def __init__(self, mailbox: Optional[Mailbox] = None) -> None:
22
+ def __init__(self) -> None:
23
23
  super().__init__()
24
- self._mailbox = mailbox
25
24
 
26
25
  def _publish_output(self, outdata: pb.OutputRecord) -> None:
27
26
  rec = pb.Record()
@@ -67,7 +66,7 @@ class InterfaceShared(InterfaceBase):
67
66
  self, job_input: pb.JobInputRequest
68
67
  ) -> MailboxHandle[pb.Result]:
69
68
  record = self._make_request(job_input=job_input)
70
- return self._deliver_record(record)
69
+ return self._deliver(record)
71
70
 
72
71
  def _make_stats(self, stats_dict: dict) -> pb.StatsRecord:
73
72
  stats = pb.StatsRecord()
@@ -263,6 +262,9 @@ class InterfaceShared(InterfaceBase):
263
262
  def _publish(self, record: pb.Record, local: Optional[bool] = None) -> None:
264
263
  raise NotImplementedError
265
264
 
265
+ def _deliver(self, record: pb.Record) -> "MailboxHandle[pb.Result]":
266
+ raise NotImplementedError
267
+
266
268
  def _publish_defer(self, state: "pb.DeferRequest.DeferState.V") -> None:
267
269
  defer = pb.DeferRequest(state=state)
268
270
  rec = self._make_request(defer=defer)
@@ -333,19 +335,19 @@ class InterfaceShared(InterfaceBase):
333
335
  log_artifact: pb.LogArtifactRequest,
334
336
  ) -> MailboxHandle[pb.Result]:
335
337
  rec = self._make_request(log_artifact=log_artifact)
336
- return self._deliver_record(rec)
338
+ return self._deliver(rec)
337
339
 
338
340
  def _deliver_download_artifact(
339
341
  self, download_artifact: pb.DownloadArtifactRequest
340
342
  ) -> MailboxHandle[pb.Result]:
341
343
  rec = self._make_request(download_artifact=download_artifact)
342
- return self._deliver_record(rec)
344
+ return self._deliver(rec)
343
345
 
344
346
  def _deliver_link_artifact(
345
347
  self, link_artifact: pb.LinkArtifactRequest
346
348
  ) -> MailboxHandle[pb.Result]:
347
349
  rec = self._make_request(link_artifact=link_artifact)
348
- return self._deliver_record(rec)
350
+ return self._deliver(rec)
349
351
 
350
352
  def _publish_artifact(self, proto_artifact: pb.ArtifactRecord) -> None:
351
353
  rec = self._make_record(artifact=proto_artifact)
@@ -360,7 +362,7 @@ class InterfaceShared(InterfaceBase):
360
362
  status: pb.StatusRequest,
361
363
  ) -> MailboxHandle[pb.Result]:
362
364
  req = self._make_request(status=status)
363
- return self._deliver_record(req)
365
+ return self._deliver(req)
364
366
 
365
367
  def _publish_exit(self, exit_data: pb.RunExitRecord) -> None:
366
368
  rec = self._make_record(exit=exit_data)
@@ -373,110 +375,97 @@ class InterfaceShared(InterfaceBase):
373
375
  def _deliver_shutdown(self) -> MailboxHandle[pb.Result]:
374
376
  request = pb.Request(shutdown=pb.ShutdownRequest())
375
377
  record = self._make_record(request=request)
376
- return self._deliver_record(record)
377
-
378
- def _get_mailbox(self) -> Mailbox:
379
- mailbox = self._mailbox
380
- assert mailbox
381
- return mailbox
382
-
383
- def _deliver_record(self, record: pb.Record) -> MailboxHandle[pb.Result]:
384
- mailbox = self._get_mailbox()
385
-
386
- handle = mailbox.require_response(record)
387
- self._publish(record)
388
-
389
- return handle.map(lambda resp: resp.result_communicate)
378
+ return self._deliver(record)
390
379
 
391
380
  def _deliver_run(self, run: pb.RunRecord) -> MailboxHandle[pb.Result]:
392
381
  record = self._make_record(run=run)
393
- return self._deliver_record(record)
382
+ return self._deliver(record)
394
383
 
395
384
  def _deliver_finish_sync(
396
385
  self,
397
386
  sync_finish: pb.SyncFinishRequest,
398
387
  ) -> MailboxHandle[pb.Result]:
399
388
  record = self._make_request(sync_finish=sync_finish)
400
- return self._deliver_record(record)
389
+ return self._deliver(record)
401
390
 
402
391
  def _deliver_run_start(
403
392
  self,
404
393
  run_start: pb.RunStartRequest,
405
394
  ) -> MailboxHandle[pb.Result]:
406
395
  record = self._make_request(run_start=run_start)
407
- return self._deliver_record(record)
396
+ return self._deliver(record)
408
397
 
409
398
  def _deliver_get_summary(
410
399
  self,
411
400
  get_summary: pb.GetSummaryRequest,
412
401
  ) -> MailboxHandle[pb.Result]:
413
402
  record = self._make_request(get_summary=get_summary)
414
- return self._deliver_record(record)
403
+ return self._deliver(record)
415
404
 
416
405
  def _deliver_get_system_metrics(
417
406
  self, get_system_metrics: pb.GetSystemMetricsRequest
418
407
  ) -> MailboxHandle[pb.Result]:
419
408
  record = self._make_request(get_system_metrics=get_system_metrics)
420
- return self._deliver_record(record)
409
+ return self._deliver(record)
421
410
 
422
411
  def _deliver_exit(
423
412
  self,
424
413
  exit_data: pb.RunExitRecord,
425
414
  ) -> MailboxHandle[pb.Result]:
426
415
  record = self._make_record(exit=exit_data)
427
- return self._deliver_record(record)
416
+ return self._deliver(record)
428
417
 
429
418
  def deliver_operation_stats(self):
430
419
  record = self._make_request(operation_stats=pb.OperationStatsRequest())
431
- return self._deliver_record(record)
420
+ return self._deliver(record)
432
421
 
433
422
  def _deliver_poll_exit(
434
423
  self,
435
424
  poll_exit: pb.PollExitRequest,
436
425
  ) -> MailboxHandle[pb.Result]:
437
426
  record = self._make_request(poll_exit=poll_exit)
438
- return self._deliver_record(record)
427
+ return self._deliver(record)
439
428
 
440
429
  def _deliver_finish_without_exit(
441
430
  self, run_finish_without_exit: pb.RunFinishWithoutExitRequest
442
431
  ) -> MailboxHandle[pb.Result]:
443
432
  record = self._make_request(run_finish_without_exit=run_finish_without_exit)
444
- return self._deliver_record(record)
433
+ return self._deliver(record)
445
434
 
446
435
  def _deliver_stop_status(
447
436
  self,
448
437
  stop_status: pb.StopStatusRequest,
449
438
  ) -> MailboxHandle[pb.Result]:
450
439
  record = self._make_request(stop_status=stop_status)
451
- return self._deliver_record(record)
440
+ return self._deliver(record)
452
441
 
453
442
  def _deliver_attach(
454
443
  self,
455
444
  attach: pb.AttachRequest,
456
445
  ) -> MailboxHandle[pb.Result]:
457
446
  record = self._make_request(attach=attach)
458
- return self._deliver_record(record)
447
+ return self._deliver(record)
459
448
 
460
449
  def _deliver_network_status(
461
450
  self, network_status: pb.NetworkStatusRequest
462
451
  ) -> MailboxHandle[pb.Result]:
463
452
  record = self._make_request(network_status=network_status)
464
- return self._deliver_record(record)
453
+ return self._deliver(record)
465
454
 
466
455
  def _deliver_internal_messages(
467
456
  self, internal_message: pb.InternalMessagesRequest
468
457
  ) -> MailboxHandle[pb.Result]:
469
458
  record = self._make_request(internal_messages=internal_message)
470
- return self._deliver_record(record)
459
+ return self._deliver(record)
471
460
 
472
461
  def _deliver_request_sampled_history(
473
462
  self, sampled_history: pb.SampledHistoryRequest
474
463
  ) -> MailboxHandle[pb.Result]:
475
464
  record = self._make_request(sampled_history=sampled_history)
476
- return self._deliver_record(record)
465
+ return self._deliver(record)
477
466
 
478
467
  def _deliver_request_run_status(
479
468
  self, run_status: pb.RunStatusRequest
480
469
  ) -> MailboxHandle[pb.Result]:
481
470
  record = self._make_request(run_status=run_status)
482
- return self._deliver_record(record)
471
+ return self._deliver(record)