wandb 0.13.10__py3-none-any.whl → 0.14.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. wandb/__init__.py +2 -3
  2. wandb/apis/__init__.py +1 -3
  3. wandb/apis/importers/__init__.py +4 -0
  4. wandb/apis/importers/base.py +312 -0
  5. wandb/apis/importers/mlflow.py +113 -0
  6. wandb/apis/internal.py +29 -2
  7. wandb/apis/normalize.py +6 -5
  8. wandb/apis/public.py +163 -180
  9. wandb/apis/reports/_templates.py +6 -12
  10. wandb/apis/reports/report.py +1 -1
  11. wandb/apis/reports/runset.py +1 -3
  12. wandb/apis/reports/util.py +12 -10
  13. wandb/beta/workflows.py +57 -34
  14. wandb/catboost/__init__.py +1 -2
  15. wandb/cli/cli.py +215 -133
  16. wandb/data_types.py +63 -56
  17. wandb/docker/__init__.py +78 -16
  18. wandb/docker/auth.py +21 -22
  19. wandb/env.py +0 -1
  20. wandb/errors/__init__.py +8 -116
  21. wandb/errors/term.py +1 -1
  22. wandb/fastai/__init__.py +1 -2
  23. wandb/filesync/dir_watcher.py +8 -5
  24. wandb/filesync/step_prepare.py +76 -75
  25. wandb/filesync/step_upload.py +1 -2
  26. wandb/integration/catboost/__init__.py +1 -3
  27. wandb/integration/catboost/catboost.py +8 -14
  28. wandb/integration/fastai/__init__.py +7 -13
  29. wandb/integration/gym/__init__.py +35 -4
  30. wandb/integration/keras/__init__.py +3 -3
  31. wandb/integration/keras/callbacks/metrics_logger.py +9 -8
  32. wandb/integration/keras/callbacks/model_checkpoint.py +9 -9
  33. wandb/integration/keras/callbacks/tables_builder.py +31 -19
  34. wandb/integration/kfp/kfp_patch.py +20 -17
  35. wandb/integration/kfp/wandb_logging.py +1 -2
  36. wandb/integration/lightgbm/__init__.py +21 -19
  37. wandb/integration/prodigy/prodigy.py +6 -7
  38. wandb/integration/sacred/__init__.py +9 -12
  39. wandb/integration/sagemaker/__init__.py +1 -3
  40. wandb/integration/sagemaker/auth.py +0 -1
  41. wandb/integration/sagemaker/config.py +1 -1
  42. wandb/integration/sagemaker/resources.py +1 -1
  43. wandb/integration/sb3/sb3.py +8 -4
  44. wandb/integration/tensorboard/__init__.py +1 -3
  45. wandb/integration/tensorboard/log.py +8 -8
  46. wandb/integration/tensorboard/monkeypatch.py +11 -9
  47. wandb/integration/tensorflow/__init__.py +1 -3
  48. wandb/integration/xgboost/__init__.py +4 -6
  49. wandb/integration/yolov8/__init__.py +7 -0
  50. wandb/integration/yolov8/yolov8.py +250 -0
  51. wandb/jupyter.py +31 -35
  52. wandb/lightgbm/__init__.py +1 -2
  53. wandb/old/settings.py +2 -2
  54. wandb/plot/bar.py +1 -2
  55. wandb/plot/confusion_matrix.py +1 -3
  56. wandb/plot/histogram.py +1 -2
  57. wandb/plot/line.py +1 -2
  58. wandb/plot/line_series.py +4 -4
  59. wandb/plot/pr_curve.py +17 -20
  60. wandb/plot/roc_curve.py +1 -3
  61. wandb/plot/scatter.py +1 -2
  62. wandb/proto/v3/wandb_server_pb2.py +85 -39
  63. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  64. wandb/proto/v4/wandb_server_pb2.py +51 -39
  65. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  66. wandb/sdk/__init__.py +1 -3
  67. wandb/sdk/backend/backend.py +1 -1
  68. wandb/sdk/data_types/_dtypes.py +38 -30
  69. wandb/sdk/data_types/base_types/json_metadata.py +1 -3
  70. wandb/sdk/data_types/base_types/media.py +17 -17
  71. wandb/sdk/data_types/base_types/wb_value.py +33 -26
  72. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +91 -125
  73. wandb/sdk/data_types/helper_types/classes.py +1 -1
  74. wandb/sdk/data_types/helper_types/image_mask.py +12 -12
  75. wandb/sdk/data_types/histogram.py +5 -4
  76. wandb/sdk/data_types/html.py +1 -2
  77. wandb/sdk/data_types/image.py +11 -11
  78. wandb/sdk/data_types/molecule.py +3 -6
  79. wandb/sdk/data_types/object_3d.py +1 -2
  80. wandb/sdk/data_types/plotly.py +1 -2
  81. wandb/sdk/data_types/saved_model.py +10 -8
  82. wandb/sdk/data_types/video.py +1 -1
  83. wandb/sdk/integration_utils/data_logging.py +5 -5
  84. wandb/sdk/interface/artifacts.py +288 -266
  85. wandb/sdk/interface/interface.py +2 -3
  86. wandb/sdk/interface/interface_grpc.py +1 -1
  87. wandb/sdk/interface/interface_queue.py +1 -1
  88. wandb/sdk/interface/interface_relay.py +1 -1
  89. wandb/sdk/interface/interface_shared.py +1 -2
  90. wandb/sdk/interface/interface_sock.py +1 -1
  91. wandb/sdk/interface/message_future.py +1 -1
  92. wandb/sdk/interface/message_future_poll.py +1 -1
  93. wandb/sdk/interface/router.py +1 -1
  94. wandb/sdk/interface/router_queue.py +1 -1
  95. wandb/sdk/interface/router_relay.py +1 -1
  96. wandb/sdk/interface/router_sock.py +1 -1
  97. wandb/sdk/interface/summary_record.py +1 -1
  98. wandb/sdk/internal/artifacts.py +1 -1
  99. wandb/sdk/internal/datastore.py +2 -3
  100. wandb/sdk/internal/file_pusher.py +5 -3
  101. wandb/sdk/internal/file_stream.py +22 -19
  102. wandb/sdk/internal/handler.py +5 -4
  103. wandb/sdk/internal/internal.py +1 -1
  104. wandb/sdk/internal/internal_api.py +115 -55
  105. wandb/sdk/internal/job_builder.py +1 -3
  106. wandb/sdk/internal/profiler.py +1 -1
  107. wandb/sdk/internal/progress.py +4 -6
  108. wandb/sdk/internal/sample.py +1 -3
  109. wandb/sdk/internal/sender.py +28 -16
  110. wandb/sdk/internal/settings_static.py +5 -5
  111. wandb/sdk/internal/system/assets/__init__.py +1 -0
  112. wandb/sdk/internal/system/assets/cpu.py +3 -9
  113. wandb/sdk/internal/system/assets/disk.py +2 -4
  114. wandb/sdk/internal/system/assets/gpu.py +6 -18
  115. wandb/sdk/internal/system/assets/gpu_apple.py +2 -4
  116. wandb/sdk/internal/system/assets/interfaces.py +50 -22
  117. wandb/sdk/internal/system/assets/ipu.py +1 -3
  118. wandb/sdk/internal/system/assets/memory.py +7 -13
  119. wandb/sdk/internal/system/assets/network.py +4 -8
  120. wandb/sdk/internal/system/assets/open_metrics.py +283 -0
  121. wandb/sdk/internal/system/assets/tpu.py +1 -4
  122. wandb/sdk/internal/system/assets/trainium.py +26 -14
  123. wandb/sdk/internal/system/system_info.py +2 -3
  124. wandb/sdk/internal/system/system_monitor.py +52 -20
  125. wandb/sdk/internal/tb_watcher.py +12 -13
  126. wandb/sdk/launch/_project_spec.py +54 -65
  127. wandb/sdk/launch/agent/agent.py +374 -90
  128. wandb/sdk/launch/builder/abstract.py +61 -7
  129. wandb/sdk/launch/builder/build.py +81 -110
  130. wandb/sdk/launch/builder/docker_builder.py +181 -0
  131. wandb/sdk/launch/builder/kaniko_builder.py +419 -0
  132. wandb/sdk/launch/builder/noop.py +31 -12
  133. wandb/sdk/launch/builder/templates/_wandb_bootstrap.py +70 -20
  134. wandb/sdk/launch/environment/abstract.py +28 -0
  135. wandb/sdk/launch/environment/aws_environment.py +276 -0
  136. wandb/sdk/launch/environment/gcp_environment.py +271 -0
  137. wandb/sdk/launch/environment/local_environment.py +65 -0
  138. wandb/sdk/launch/github_reference.py +3 -8
  139. wandb/sdk/launch/launch.py +38 -29
  140. wandb/sdk/launch/launch_add.py +6 -8
  141. wandb/sdk/launch/loader.py +230 -0
  142. wandb/sdk/launch/registry/abstract.py +54 -0
  143. wandb/sdk/launch/registry/elastic_container_registry.py +163 -0
  144. wandb/sdk/launch/registry/google_artifact_registry.py +203 -0
  145. wandb/sdk/launch/registry/local_registry.py +62 -0
  146. wandb/sdk/launch/runner/abstract.py +1 -16
  147. wandb/sdk/launch/runner/{kubernetes.py → kubernetes_runner.py} +83 -95
  148. wandb/sdk/launch/runner/local_container.py +46 -22
  149. wandb/sdk/launch/runner/local_process.py +1 -4
  150. wandb/sdk/launch/runner/{aws.py → sagemaker_runner.py} +53 -212
  151. wandb/sdk/launch/runner/{gcp_vertex.py → vertex_runner.py} +38 -55
  152. wandb/sdk/launch/sweeps/__init__.py +3 -2
  153. wandb/sdk/launch/sweeps/scheduler.py +132 -39
  154. wandb/sdk/launch/sweeps/scheduler_sweep.py +80 -89
  155. wandb/sdk/launch/utils.py +101 -30
  156. wandb/sdk/launch/wandb_reference.py +2 -7
  157. wandb/sdk/lib/_settings_toposort_generate.py +166 -0
  158. wandb/sdk/lib/_settings_toposort_generated.py +201 -0
  159. wandb/sdk/lib/apikey.py +2 -4
  160. wandb/sdk/lib/config_util.py +4 -1
  161. wandb/sdk/lib/console.py +1 -3
  162. wandb/sdk/lib/deprecate.py +3 -3
  163. wandb/sdk/lib/file_stream_utils.py +7 -5
  164. wandb/sdk/lib/filenames.py +1 -1
  165. wandb/sdk/lib/filesystem.py +61 -5
  166. wandb/sdk/lib/git.py +1 -3
  167. wandb/sdk/lib/import_hooks.py +4 -7
  168. wandb/sdk/lib/ipython.py +8 -5
  169. wandb/sdk/lib/lazyloader.py +1 -3
  170. wandb/sdk/lib/mailbox.py +14 -4
  171. wandb/sdk/lib/proto_util.py +10 -5
  172. wandb/sdk/lib/redirect.py +15 -22
  173. wandb/sdk/lib/reporting.py +1 -3
  174. wandb/sdk/lib/retry.py +4 -5
  175. wandb/sdk/lib/runid.py +1 -3
  176. wandb/sdk/lib/server.py +15 -9
  177. wandb/sdk/lib/sock_client.py +1 -1
  178. wandb/sdk/lib/sparkline.py +1 -1
  179. wandb/sdk/lib/wburls.py +1 -1
  180. wandb/sdk/service/port_file.py +1 -2
  181. wandb/sdk/service/service.py +36 -13
  182. wandb/sdk/service/service_base.py +12 -1
  183. wandb/sdk/verify/verify.py +5 -7
  184. wandb/sdk/wandb_artifacts.py +142 -177
  185. wandb/sdk/wandb_config.py +5 -8
  186. wandb/sdk/wandb_helper.py +1 -1
  187. wandb/sdk/wandb_init.py +24 -13
  188. wandb/sdk/wandb_login.py +9 -9
  189. wandb/sdk/wandb_manager.py +39 -4
  190. wandb/sdk/wandb_metric.py +2 -6
  191. wandb/sdk/wandb_require.py +4 -15
  192. wandb/sdk/wandb_require_helpers.py +1 -9
  193. wandb/sdk/wandb_run.py +95 -141
  194. wandb/sdk/wandb_save.py +1 -3
  195. wandb/sdk/wandb_settings.py +149 -54
  196. wandb/sdk/wandb_setup.py +66 -46
  197. wandb/sdk/wandb_summary.py +13 -10
  198. wandb/sdk/wandb_sweep.py +6 -7
  199. wandb/sdk/wandb_watch.py +1 -1
  200. wandb/sklearn/calculate/confusion_matrix.py +1 -1
  201. wandb/sklearn/calculate/learning_curve.py +1 -1
  202. wandb/sklearn/calculate/summary_metrics.py +1 -3
  203. wandb/sklearn/plot/__init__.py +1 -1
  204. wandb/sklearn/plot/classifier.py +27 -18
  205. wandb/sklearn/plot/clusterer.py +4 -5
  206. wandb/sklearn/plot/regressor.py +4 -4
  207. wandb/sklearn/plot/shared.py +2 -2
  208. wandb/sync/__init__.py +1 -3
  209. wandb/sync/sync.py +4 -5
  210. wandb/testing/relay.py +11 -10
  211. wandb/trigger.py +1 -1
  212. wandb/util.py +106 -81
  213. wandb/viz.py +4 -4
  214. wandb/wandb_agent.py +50 -50
  215. wandb/wandb_controller.py +2 -3
  216. wandb/wandb_run.py +1 -2
  217. wandb/wandb_torch.py +1 -1
  218. wandb/xgboost/__init__.py +1 -2
  219. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/METADATA +6 -2
  220. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/RECORD +224 -209
  221. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/WHEEL +1 -1
  222. wandb/sdk/launch/builder/docker.py +0 -80
  223. wandb/sdk/launch/builder/kaniko.py +0 -393
  224. wandb/sdk/launch/builder/loader.py +0 -32
  225. wandb/sdk/launch/runner/loader.py +0 -50
  226. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/LICENSE +0 -0
  227. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/entry_points.txt +0 -0
  228. {wandb-0.13.10.dist-info → wandb-0.14.0.dist-info}/top_level.txt +0 -0
wandb/data_types.py CHANGED
@@ -148,7 +148,7 @@ def _json_helper(val, artifact):
148
148
 
149
149
 
150
150
  class Table(Media):
151
- """The Table class is used to display and analyze tabular data.
151
+ """The Table class used to display and analyze tabular data.
152
152
 
153
153
  Unlike traditional spreadsheets, Tables support numerous types of data:
154
154
  scalar values, strings, numpy arrays, and most subclasses of `wandb.data_types.Media`.
@@ -257,7 +257,10 @@ class Table(Media):
257
257
  optional=True,
258
258
  allow_mixed_types=False,
259
259
  ):
260
- """rows is kept for legacy reasons, we use data to mimic the Pandas api"""
260
+ """Initialize a Table object.
261
+
262
+ Rows is kept for legacy reasons, we use data to mimic the Pandas api.
263
+ """
261
264
  super().__init__()
262
265
  self._pk_col = None
263
266
  self._fk_cols = set()
@@ -344,7 +347,7 @@ class Table(Media):
344
347
  self.cast(col_name, dt, opt)
345
348
 
346
349
  def cast(self, col_name, dtype, optional=False):
347
- """Casts a column to a specific type
350
+ """Cast a column to a specific type.
348
351
 
349
352
  Arguments:
350
353
  col_name: (str) - name of the column to cast
@@ -445,12 +448,15 @@ class Table(Media):
445
448
  return self._eq_debug(other)
446
449
 
447
450
  def add_row(self, *row):
448
- """add_row is deprecated. Please use add_data"""
451
+ """Deprecated: use add_data instead."""
449
452
  logging.warning("add_row is deprecated, use add_data")
450
453
  self.add_data(*row)
451
454
 
452
455
  def add_data(self, *data):
453
- """Add a row of data to the table. Argument length should match column length"""
456
+ """Add a row of data to the table.
457
+
458
+ Argument length should match column length.
459
+ """
454
460
  if len(data) != len(self.columns):
455
461
  raise ValueError(
456
462
  "This table expects {} columns: {}, found {}".format(
@@ -482,8 +488,11 @@ class Table(Media):
482
488
  self._update_keys(force_last=True)
483
489
 
484
490
  def _get_updated_result_type(self, row):
485
- """Returns an updated result type based on incoming row. Raises error if
486
- the assignment is invalid"""
491
+ """Return an updated result type based on incoming row.
492
+
493
+ Raises:
494
+ TypeError: if the assignment is invalid.
495
+ """
487
496
  incoming_row_dict = {
488
497
  col_key: row[ndx] for ndx, col_key in enumerate(self.columns)
489
498
  }
@@ -695,14 +704,15 @@ class Table(Media):
695
704
  return json_dict
696
705
 
697
706
  def iterrows(self):
698
- """Iterate over rows as (ndx, row)
699
- Yields
707
+ """Iterate over rows as (ndx, row).
708
+
709
+ Yields:
700
710
  ------
701
711
  index : int
702
712
  The index of the row. Using this value in other WandB tables
703
713
  will automatically build a relationship between the tables
704
714
  row : List[any]
705
- The data of the row
715
+ The data of the row.
706
716
  """
707
717
  for ndx in range(len(self.data)):
708
718
  index = _TableIndex(ndx)
@@ -721,13 +731,14 @@ class Table(Media):
721
731
  self.cast(col_name, _ForeignKeyType(table, table_col))
722
732
 
723
733
  def _update_keys(self, force_last=False):
724
- """Updates the known key-like columns based on the current
725
- column types. If the state has been updated since
726
- the last update, we wrap the data appropriately in the Key classes
734
+ """Update the known key-like columns based on the current column types.
735
+
736
+ If the state has been updated since the last update, we wrap the data
737
+ appropriately in the Key classes.
727
738
 
728
739
  Arguments:
729
- force_last: (bool) Determines wrapping the last column of data even if
730
- there are no key updates.
740
+ force_last: (bool) Determines wrapping the last column of data even if there
741
+ are no key updates.
731
742
  """
732
743
  _pk_col = None
733
744
  _fk_cols = set()
@@ -767,7 +778,7 @@ class Table(Media):
767
778
  self._apply_key_updates(not has_update)
768
779
 
769
780
  def _apply_key_updates(self, only_last=False):
770
- """Appropriately wraps the underlying data in special key classes.
781
+ """Appropriately wrap the underlying data in special key classes.
771
782
 
772
783
  Arguments:
773
784
  only_last: only apply the updates to the last row (used for performance when
@@ -818,7 +829,7 @@ class Table(Media):
818
829
  def add_column(self, name, data, optional=False):
819
830
  """Add a column of data to the table.
820
831
 
821
- Arguments
832
+ Arguments:
822
833
  name: (str) - the unique name of the column
823
834
  data: (list | np.array) - a column of homogenous data
824
835
  optional: (bool) - if null-like values are permitted
@@ -857,9 +868,9 @@ class Table(Media):
857
868
  raise err
858
869
 
859
870
  def get_column(self, name, convert_to=None):
860
- """Retrieves a column of data from the table
871
+ """Retrieve a column of data from the table.
861
872
 
862
- Arguments
873
+ Arguments:
863
874
  name: (str) - the name of the column
864
875
  convert_to: (str, optional)
865
876
  - "numpy": will convert the underlying data to numpy object
@@ -882,7 +893,7 @@ class Table(Media):
882
893
  return col
883
894
 
884
895
  def get_index(self):
885
- """Returns an array of row indexes which can be used in other tables to create links"""
896
+ """Return an array of row indexes for use in other tables to create links."""
886
897
  ndxs = []
887
898
  for ndx in range(len(self.data)):
888
899
  index = _TableIndex(ndx)
@@ -891,14 +902,14 @@ class Table(Media):
891
902
  return ndxs
892
903
 
893
904
  def index_ref(self, index):
894
- """Get a reference to a particular row index in the table"""
905
+ """Get a reference to a particular row index in the table."""
895
906
  assert index < len(self.data)
896
907
  _index = _TableIndex(index)
897
908
  _index.set_table(self)
898
909
  return _index
899
910
 
900
911
  def add_computed_columns(self, fn):
901
- """Adds one or more computed columns based on existing data
912
+ """Add one or more computed columns based on existing data.
902
913
 
903
914
  Args:
904
915
  fn: A function which accepts one or two parameters, ndx (int) and row (dict),
@@ -923,7 +934,7 @@ class Table(Media):
923
934
 
924
935
 
925
936
  class _PartitionTablePartEntry:
926
- """Helper class for PartitionTable to track its parts"""
937
+ """Helper class for PartitionTable to track its parts."""
927
938
 
928
939
  def __init__(self, entry, source_artifact):
929
940
  self.entry = entry
@@ -940,17 +951,18 @@ class _PartitionTablePartEntry:
940
951
 
941
952
 
942
953
  class PartitionedTable(Media):
943
- """PartitionedTable represents a table which is composed
944
- by the union of multiple sub-tables. Currently, PartitionedTable
945
- is designed to point to a directory within an artifact.
954
+ """A table which is composed of multiple sub-tables.
955
+
956
+ Currently, PartitionedTable is designed to point to a directory within an artifact.
946
957
  """
947
958
 
948
959
  _log_type = "partitioned-table"
949
960
 
950
961
  def __init__(self, parts_path):
951
- """
962
+ """Initialize a PartitionedTable.
963
+
952
964
  Args:
953
- parts_path (str): path to a directory of tables in the artifact
965
+ parts_path (str): path to a directory of tables in the artifact.
954
966
  """
955
967
  super().__init__()
956
968
  self.parts_path = parts_path
@@ -982,13 +994,14 @@ class PartitionedTable(Media):
982
994
  return instance
983
995
 
984
996
  def iterrows(self):
985
- """Iterate over rows as (ndx, row)
986
- Yields
997
+ """Iterate over rows as (ndx, row).
998
+
999
+ Yields:
987
1000
  ------
988
1001
  index : int
989
1002
  The index of the row.
990
1003
  row : List[any]
991
- The data of the row
1004
+ The data of the row.
992
1005
  """
993
1006
  columns = None
994
1007
  ndx = 0
@@ -1024,8 +1037,7 @@ class PartitionedTable(Media):
1024
1037
 
1025
1038
 
1026
1039
  class Audio(BatchableMedia):
1027
- """
1028
- Wandb class for audio clips.
1040
+ """Wandb class for audio clips.
1029
1041
 
1030
1042
  Arguments:
1031
1043
  data_or_path: (string or numpy array) A path to an audio file
@@ -1038,7 +1050,7 @@ class Audio(BatchableMedia):
1038
1050
  _log_type = "audio-file"
1039
1051
 
1040
1052
  def __init__(self, data_or_path, sample_rate=None, caption=None):
1041
- """Accepts a path to an audio file or a numpy array of audio data."""
1053
+ """Accept a path to an audio file or a numpy array of audio data."""
1042
1054
  super().__init__()
1043
1055
  self._duration = None
1044
1056
  self._sample_rate = sample_rate
@@ -1172,7 +1184,7 @@ class Audio(BatchableMedia):
1172
1184
 
1173
1185
 
1174
1186
  class JoinedTable(Media):
1175
- """Joins two tables for visualization in the Artifact UI
1187
+ """Join two tables for visualization in the Artifact UI.
1176
1188
 
1177
1189
  Arguments:
1178
1190
  table1 (str, wandb.Table, ArtifactManifestEntry):
@@ -1227,7 +1239,7 @@ class JoinedTable(Media):
1227
1239
 
1228
1240
  @staticmethod
1229
1241
  def _validate_table_input(table):
1230
- """Helper method to validate that the table input is one of the 3 supported types"""
1242
+ """Helper method to validate that the table input is one of the 3 supported types."""
1231
1243
  return (
1232
1244
  (type(table) == str and table.endswith(".table.json"))
1233
1245
  or isinstance(table, Table)
@@ -1236,7 +1248,7 @@ class JoinedTable(Media):
1236
1248
  )
1237
1249
 
1238
1250
  def _ensure_table_in_artifact(self, table, artifact, table_ndx):
1239
- """Helper method to add the table to the incoming artifact. Returns the path"""
1251
+ """Helper method to add the table to the incoming artifact. Returns the path."""
1240
1252
  if isinstance(table, Table) or isinstance(table, PartitionedTable):
1241
1253
  table_name = f"t{table_ndx}_{str(id(self))}"
1242
1254
  if (
@@ -1310,8 +1322,7 @@ class JoinedTable(Media):
1310
1322
 
1311
1323
 
1312
1324
  class Bokeh(Media):
1313
- """
1314
- Wandb class for Bokeh plots.
1325
+ """Wandb class for Bokeh plots.
1315
1326
 
1316
1327
  Arguments:
1317
1328
  val: Bokeh plot
@@ -1373,7 +1384,7 @@ def _nest(thing):
1373
1384
 
1374
1385
 
1375
1386
  class Graph(Media):
1376
- """Wandb class for graphs
1387
+ """Wandb class for graphs.
1377
1388
 
1378
1389
  This class is typically used for saving and diplaying neural net models. It
1379
1390
  represents the graph as an array of nodes and edges. The nodes can have
@@ -1537,9 +1548,7 @@ class Graph(Media):
1537
1548
 
1538
1549
 
1539
1550
  class Node(WBValue):
1540
- """
1541
- Node used in `Graph`
1542
- """
1551
+ """Node used in `Graph`."""
1543
1552
 
1544
1553
  def __init__(
1545
1554
  self,
@@ -1589,7 +1598,7 @@ class Node(WBValue):
1589
1598
 
1590
1599
  @property
1591
1600
  def id(self):
1592
- """Must be unique in the graph"""
1601
+ """Must be unique in the graph."""
1593
1602
  return self._attributes.get("id")
1594
1603
 
1595
1604
  @id.setter
@@ -1599,7 +1608,7 @@ class Node(WBValue):
1599
1608
 
1600
1609
  @property
1601
1610
  def name(self):
1602
- """Usually the type of layer or sublayer"""
1611
+ """Usually the type of layer or sublayer."""
1603
1612
  return self._attributes.get("name")
1604
1613
 
1605
1614
  @name.setter
@@ -1609,7 +1618,7 @@ class Node(WBValue):
1609
1618
 
1610
1619
  @property
1611
1620
  def class_name(self):
1612
- """Usually the type of layer or sublayer"""
1621
+ """Usually the type of layer or sublayer."""
1613
1622
  return self._attributes.get("class_name")
1614
1623
 
1615
1624
  @class_name.setter
@@ -1641,7 +1650,7 @@ class Node(WBValue):
1641
1650
 
1642
1651
  @size.setter
1643
1652
  def size(self, val):
1644
- """Tensor size"""
1653
+ """Tensor size."""
1645
1654
  self._attributes["size"] = tuple(val)
1646
1655
  return val
1647
1656
 
@@ -1651,7 +1660,7 @@ class Node(WBValue):
1651
1660
 
1652
1661
  @output_shape.setter
1653
1662
  def output_shape(self, val):
1654
- """Tensor output_shape"""
1663
+ """Tensor output_shape."""
1655
1664
  self._attributes["output_shape"] = val
1656
1665
  return val
1657
1666
 
@@ -1661,7 +1670,7 @@ class Node(WBValue):
1661
1670
 
1662
1671
  @is_output.setter
1663
1672
  def is_output(self, val):
1664
- """Tensor is_output"""
1673
+ """Tensor is_output."""
1665
1674
  self._attributes["is_output"] = val
1666
1675
  return val
1667
1676
 
@@ -1671,7 +1680,7 @@ class Node(WBValue):
1671
1680
 
1672
1681
  @num_parameters.setter
1673
1682
  def num_parameters(self, val):
1674
- """Tensor num_parameters"""
1683
+ """Tensor num_parameters."""
1675
1684
  self._attributes["num_parameters"] = val
1676
1685
  return val
1677
1686
 
@@ -1681,7 +1690,7 @@ class Node(WBValue):
1681
1690
 
1682
1691
  @child_parameters.setter
1683
1692
  def child_parameters(self, val):
1684
- """Tensor child_parameters"""
1693
+ """Tensor child_parameters."""
1685
1694
  self._attributes["child_parameters"] = val
1686
1695
  return val
1687
1696
 
@@ -1691,7 +1700,7 @@ class Node(WBValue):
1691
1700
 
1692
1701
  @is_constant.setter
1693
1702
  def is_constant(self, val):
1694
- """Tensor is_constant"""
1703
+ """Tensor is_constant."""
1695
1704
  self._attributes["is_constant"] = val
1696
1705
  return val
1697
1706
 
@@ -1714,9 +1723,7 @@ class Node(WBValue):
1714
1723
 
1715
1724
 
1716
1725
  class Edge(WBValue):
1717
- """
1718
- Edge used in `Graph`
1719
- """
1726
+ """Edge used in `Graph`."""
1720
1727
 
1721
1728
  def __init__(self, from_node, to_node):
1722
1729
  self._attributes = {}
@@ -1736,7 +1743,7 @@ class Edge(WBValue):
1736
1743
 
1737
1744
  @property
1738
1745
  def name(self):
1739
- """Optional, not necessarily unique"""
1746
+ """Optional, not necessarily unique."""
1740
1747
  return self._attributes.get("name")
1741
1748
 
1742
1749
  @name.setter
wandb/docker/__init__.py CHANGED
@@ -8,7 +8,40 @@ import requests
8
8
  from dockerpycreds.utils import find_executable # type: ignore
9
9
 
10
10
  from wandb.docker import auth, www_authenticate
11
- from wandb.errors import DockerError
11
+ from wandb.errors import Error
12
+
13
+
14
+ class DockerError(Error):
15
+ """Raised when attempting to execute a docker command."""
16
+
17
+ def __init__(
18
+ self,
19
+ command_launched: List[str],
20
+ return_code: int,
21
+ stdout: Optional[bytes] = None,
22
+ stderr: Optional[bytes] = None,
23
+ ) -> None:
24
+ command_launched_str = " ".join(command_launched)
25
+ error_msg = (
26
+ f"The docker command executed was `{command_launched_str}`.\n"
27
+ f"It returned with code {return_code}\n"
28
+ )
29
+ if stdout is not None:
30
+ error_msg += f"The content of stdout is '{stdout.decode()}'\n"
31
+ else:
32
+ error_msg += (
33
+ "The content of stdout can be found above the "
34
+ "stacktrace (it wasn't captured).\n"
35
+ )
36
+ if stderr is not None:
37
+ error_msg += f"The content of stderr is '{stderr.decode()}'\n"
38
+ else:
39
+ error_msg += (
40
+ "The content of stderr can be found above the "
41
+ "stacktrace (it wasn't captured)."
42
+ )
43
+ super().__init__(error_msg)
44
+
12
45
 
13
46
  entrypoint = os.path.join(
14
47
  os.path.dirname(os.path.abspath(__file__)), "wandb-entrypoint.sh"
@@ -18,9 +51,10 @@ log = logging.getLogger(__name__)
18
51
 
19
52
 
20
53
  def shell(cmd: List[str]) -> Optional[str]:
21
- """Simple wrapper for calling docker,
54
+ """Simple wrapper for calling docker,.
22
55
 
23
- returning None on error and the output on success"""
56
+ returning None on error and the output on success
57
+ """
24
58
  try:
25
59
  return (
26
60
  subprocess.check_output(["docker"] + cmd, stderr=subprocess.STDOUT)
@@ -36,7 +70,7 @@ _buildx_installed = None
36
70
 
37
71
 
38
72
  def is_buildx_installed() -> bool:
39
- """Returns `True` if docker buildx is installed and working."""
73
+ """Return `True` if docker buildx is installed and working."""
40
74
  global _buildx_installed
41
75
  if _buildx_installed is not None:
42
76
  return _buildx_installed # type: ignore
@@ -53,12 +87,40 @@ def build(tags: List[str], file: str, context_path: str) -> str:
53
87
  build_tags = []
54
88
  for tag in tags:
55
89
  build_tags += ["-t", tag]
56
- run(
57
- ["docker"] + command + build_tags + ["-f", file, context_path],
58
- capture_stderr=False,
59
- capture_stdout=False,
90
+ args = ["docker"] + command + build_tags + ["-f", file, context_path]
91
+ stdout = run_command_live_output(
92
+ args,
60
93
  )
61
- return tags[0]
94
+ return stdout
95
+
96
+
97
+ def run_command_live_output(args: List[Any]) -> str:
98
+ with subprocess.Popen(
99
+ args,
100
+ stdout=subprocess.PIPE,
101
+ stderr=subprocess.STDOUT,
102
+ universal_newlines=True,
103
+ bufsize=1,
104
+ ) as process:
105
+ stdout = ""
106
+ while True:
107
+ chunk = os.read(process.stdout.fileno(), 4096) # type: ignore
108
+ if not chunk:
109
+ break
110
+ index = chunk.find(b"\r")
111
+ if index != -1:
112
+ print(chunk.decode(), end="")
113
+ else:
114
+ stdout += chunk.decode()
115
+ print(chunk.decode(), end="\r")
116
+
117
+ print(stdout)
118
+
119
+ return_code = process.wait()
120
+ if return_code != 0:
121
+ raise DockerError(args, return_code, stdout.encode())
122
+
123
+ return stdout
62
124
 
63
125
 
64
126
  def run(
@@ -132,7 +194,7 @@ def parse(image_name: str) -> Tuple[str, str, str]:
132
194
 
133
195
 
134
196
  def auth_token(registry: str, repo: str) -> Dict[str, str]:
135
- """Makes a request to the root of a v2 docker registry to get the auth url.
197
+ """Make a request to the root of a v2 docker registry to get the auth url.
136
198
 
137
199
  Always returns a dictionary, if there's no token key we couldn't authenticate
138
200
  """
@@ -175,7 +237,7 @@ def auth_token(registry: str, repo: str) -> Dict[str, str]:
175
237
 
176
238
 
177
239
  def image_id_from_registry(image_name: str) -> Optional[str]:
178
- """Get the docker id from a public or private registry"""
240
+ """Get the docker id from a public or private registry."""
179
241
  registry, repository, tag = parse(image_name)
180
242
  res = None
181
243
  try:
@@ -199,7 +261,7 @@ def image_id_from_registry(image_name: str) -> Optional[str]:
199
261
 
200
262
 
201
263
  def image_id(image_name: str) -> Optional[str]:
202
- """Retreve the image id from the local docker daemon or remote registry"""
264
+ """Retreve the image id from the local docker daemon or remote registry."""
203
265
  if "@sha256:" in image_name:
204
266
  return image_name
205
267
  else:
@@ -214,23 +276,23 @@ def image_id(image_name: str) -> Optional[str]:
214
276
 
215
277
 
216
278
  def get_image_uid(image_name: str) -> int:
217
- """Retrieve the image default uid through brute force"""
279
+ """Retrieve the image default uid through brute force."""
218
280
  image_uid = shell(["run", image_name, "id", "-u"])
219
281
  return int(image_uid) if image_uid else -1
220
282
 
221
283
 
222
284
  def push(image: str, tag: str) -> Optional[str]:
223
- """Push an image to a remote registry"""
285
+ """Push an image to a remote registry."""
224
286
  return shell(["push", f"{image}:{tag}"])
225
287
 
226
288
 
227
289
  def login(username: str, password: str, registry: str) -> Optional[str]:
228
- """Login to a registry"""
290
+ """Login to a registry."""
229
291
  return shell(["login", "--username", username, "--password", password, registry])
230
292
 
231
293
 
232
294
  def tag(image_name: str, tag: str) -> Optional[str]:
233
- """Tag an image"""
295
+ """Tag an image."""
234
296
  return shell(["tag", image_name, tag])
235
297
 
236
298
 
wandb/docker/auth.py CHANGED
@@ -19,8 +19,8 @@ log = logging.getLogger(__name__)
19
19
 
20
20
 
21
21
  class DockerError(Exception):
22
- """
23
- A base class from which all other exceptions inherit.
22
+ """Base class from which all other exceptions inherit.
23
+
24
24
  If you want to catch all errors that the Docker SDK might raise,
25
25
  catch this base exception.
26
26
  """
@@ -67,9 +67,10 @@ def config_path_from_environment() -> Optional[str]:
67
67
 
68
68
 
69
69
  def home_dir() -> str:
70
- """
71
- Get the user's home directory, using the same logic as the Docker Engine
72
- client - use %USERPROFILE% on Windows, $HOME/getuid on POSIX.
70
+ """Get the user's home directory.
71
+
72
+ Uses the same logic as the Docker Engine client - use %USERPROFILE% on Windows,
73
+ $HOME/getuid on POSIX.
73
74
  """
74
75
  if IS_WINDOWS_PLATFORM:
75
76
  return os.environ.get("USERPROFILE", "")
@@ -149,8 +150,8 @@ class AuthConfig(dict):
149
150
  entries: Dict[str, Dict[str, Any]],
150
151
  raise_on_error: bool = False,
151
152
  ) -> Dict[str, Dict[str, Any]]:
152
- """
153
- Parses authentication entries
153
+ """Parse authentication entries.
154
+
154
155
  Arguments:
155
156
  entries: Dict of authentication entries.
156
157
  raise_on_error: If set to true, an invalid format will raise
@@ -158,7 +159,6 @@ class AuthConfig(dict):
158
159
  Returns:
159
160
  Authentication registry.
160
161
  """
161
-
162
162
  conf = {}
163
163
  for registry, entry in entries.items():
164
164
  if not isinstance(entry, dict):
@@ -210,14 +210,15 @@ class AuthConfig(dict):
210
210
  config_dict: Optional[Dict[str, Any]],
211
211
  credstore_env: Optional[Mapping] = None,
212
212
  ) -> "AuthConfig":
213
- """
214
- Loads authentication data from a Docker configuration file in the given
215
- root directory or if config_path is passed use given path.
213
+ """Load authentication data from a Docker configuration file.
214
+
215
+ If the config_path is not passed in it looks for a configuration file in the
216
+ root directory.
217
+
216
218
  Lookup priority:
217
219
  explicit config_path parameter > DOCKER_CONFIG environment
218
- variable > ~/.docker/config.json > ~/.dockercfg
220
+ variable > ~/.docker/config.json > ~/.dockercfg.
219
221
  """
220
-
221
222
  if not config_dict:
222
223
  config_file = find_config_file(config_path)
223
224
 
@@ -274,13 +275,12 @@ class AuthConfig(dict):
274
275
  def resolve_authconfig(
275
276
  self, registry: Optional[str] = None
276
277
  ) -> Optional[Dict[str, Any]]:
277
- """
278
- Returns the authentication data from the given auth configuration for a
279
- specific registry. As with the Docker client, legacy entries in the
280
- config with full URLs are stripped down to hostnames before checking
281
- for a match. Returns None if no match was found.
282
- """
278
+ """Return the authentication data for a specific registry.
283
279
 
280
+ As with the Docker client, legacy entries in the config with full URLs are
281
+ stripped down to hostnames before checking for a match. Returns None if no match
282
+ was found.
283
+ """
284
284
  if self.creds_store or self.cred_helpers:
285
285
  store_name = self.get_credential_store(registry)
286
286
  if store_name is not None:
@@ -387,8 +387,8 @@ def decode_auth(auth: Union[str, bytes]) -> Tuple[str, str]:
387
387
  def parse_auth(
388
388
  entries: Dict, raise_on_error: bool = False
389
389
  ) -> Dict[str, Dict[str, Any]]:
390
- """
391
- Parses authentication entries
390
+ """Parse authentication entries.
391
+
392
392
  Arguments:
393
393
  entries: Dict of authentication entries.
394
394
  raise_on_error: If set to true, an invalid format will raise
@@ -396,7 +396,6 @@ def parse_auth(
396
396
  Returns:
397
397
  Authentication registry.
398
398
  """
399
-
400
399
  return AuthConfig.parse_auth(entries, raise_on_error)
401
400
 
402
401
 
wandb/env.py CHANGED
@@ -74,7 +74,6 @@ DATA_DIR = "WANDB_DATA_DIR"
74
74
  CACHE_DIR = "WANDB_CACHE_DIR"
75
75
  DISABLE_SSL = "WANDB_INSECURE_DISABLE_SSL"
76
76
  SERVICE = "WANDB_SERVICE"
77
- REQUIRE_SERVICE = "WANDB_REQUIRE_SERVICE"
78
77
  _DISABLE_SERVICE = "WANDB_DISABLE_SERVICE"
79
78
  SENTRY_DSN = "WANDB_SENTRY_DSN"
80
79
  INIT_TIMEOUT = "WANDB_INIT_TIMEOUT"