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/apis/public.py CHANGED
@@ -47,11 +47,16 @@ from wandb import __version__, env, util
47
47
  from wandb.apis.internal import Api as InternalApi
48
48
  from wandb.apis.normalize import normalize_exceptions
49
49
  from wandb.data_types import WBValue
50
- from wandb.errors import CommError, LaunchError
50
+ from wandb.errors import CommError
51
51
  from wandb.errors.term import termlog
52
52
  from wandb.sdk.data_types._dtypes import InvalidType, Type, TypeRegistry
53
53
  from wandb.sdk.interface import artifacts
54
- from wandb.sdk.launch.utils import LAUNCH_DEFAULT_PROJECT, _fetch_git_repo, apply_patch
54
+ from wandb.sdk.launch.utils import (
55
+ LAUNCH_DEFAULT_PROJECT,
56
+ LaunchError,
57
+ _fetch_git_repo,
58
+ apply_patch,
59
+ )
55
60
  from wandb.sdk.lib import filesystem, ipython, retry, runid
56
61
  from wandb.sdk.lib.hashutil import b64_to_hex_id, hex_to_b64_id, md5_file_b64
57
62
 
@@ -269,8 +274,7 @@ class RetryingClient:
269
274
 
270
275
 
271
276
  class Api:
272
- """
273
- Used for querying the wandb server.
277
+ """Used for querying the wandb server.
274
278
 
275
279
  Examples:
276
280
  Most common way to initialize
@@ -433,7 +437,7 @@ class Api:
433
437
  self._client = RetryingClient(self._base_client)
434
438
 
435
439
  def create_run(self, **kwargs):
436
- """Create a new run"""
440
+ """Create a new run."""
437
441
  if kwargs.get("entity") is None:
438
442
  kwargs["entity"] = self.default_entity
439
443
  return Run.create(self, **kwargs)
@@ -459,8 +463,7 @@ class Api:
459
463
  self.client.execute(self.CREATE_PROJECT, {"entityName": entity, "name": name})
460
464
 
461
465
  def load_report(self, path: str) -> "wandb.apis.reports.Report":
462
- """
463
- Get report at a given path.
466
+ """Get report at a given path.
464
467
 
465
468
  Arguments:
466
469
  path: (str) Path to the target report in the form `entity/project/reports/reportId`.
@@ -476,7 +479,7 @@ class Api:
476
479
  return wandb.apis.reports.Report.from_url(path)
477
480
 
478
481
  def create_user(self, email, admin=False):
479
- """Creates a new user
482
+ """Create a new user.
480
483
 
481
484
  Arguments:
482
485
  email: (str) The name of the team
@@ -488,8 +491,8 @@ class Api:
488
491
  return User.create(self, email, admin)
489
492
 
490
493
  def sync_tensorboard(self, root_dir, run_id=None, project=None, entity=None):
491
- """Sync a local directory containing tfevent files to wandb"""
492
- from wandb.sync import SyncManager # noqa: F401 TODO: circular import madness
494
+ """Sync a local directory containing tfevent files to wandb."""
495
+ from wandb.sync import SyncManager # TODO: circular import madness
493
496
 
494
497
  run_id = run_id or runid.generate_id()
495
498
  project = project or self.settings.get("project") or "uncategorized"
@@ -550,15 +553,16 @@ class Api:
550
553
  return self._viewer
551
554
 
552
555
  def flush(self):
553
- """
556
+ """Flush the local cache.
557
+
554
558
  The api object keeps a local cache of runs, so if the state of the run may
555
- change while executing your script you must clear the local cache with `api.flush()`
556
- to get the latest values associated with the run.
559
+ change while executing your script you must clear the local cache with
560
+ `api.flush()` to get the latest values associated with the run.
557
561
  """
558
562
  self._runs = {}
559
563
 
560
564
  def from_path(self, path):
561
- """Return a run, sweep, project or report from a path
565
+ """Return a run, sweep, project or report from a path.
562
566
 
563
567
  Examples:
564
568
  ```
@@ -614,7 +618,7 @@ class Api:
614
618
  )
615
619
 
616
620
  def _parse_project_path(self, path):
617
- """Returns project and entity for project specified by path"""
621
+ """Return project and entity for project specified by path."""
618
622
  project = self.settings["project"]
619
623
  entity = self.settings["entity"] or self.default_entity
620
624
  if path is None:
@@ -625,13 +629,14 @@ class Api:
625
629
  return parts
626
630
 
627
631
  def _parse_path(self, path):
628
- """Parses paths in the following formats:
632
+ """Parse url, filepath, or docker paths.
629
633
 
630
- url: entity/project/runs/id
631
- path: entity/project/id
632
- docker: entity/project:id
634
+ Allows paths in the following formats:
635
+ - url: entity/project/runs/id
636
+ - path: entity/project/id
637
+ - docker: entity/project:id
633
638
 
634
- entity is optional and will fall back to the current logged-in user.
639
+ Entity is optional and will fall back to the current logged-in user.
635
640
  """
636
641
  project = self.settings["project"]
637
642
  entity = self.settings["entity"] or self.default_entity
@@ -656,7 +661,7 @@ class Api:
656
661
  return entity, project, id
657
662
 
658
663
  def _parse_artifact_path(self, path):
659
- """Returns project, entity and artifact name for project specified by path"""
664
+ """Return project, entity and artifact name for project specified by path."""
660
665
  project = self.settings["project"]
661
666
  entity = self.settings["entity"] or self.default_entity
662
667
  if path is None:
@@ -671,8 +676,7 @@ class Api:
671
676
  return parts
672
677
 
673
678
  def projects(self, entity=None, per_page=200):
674
- """
675
- Get projects for a given entity.
679
+ """Get projects for a given entity.
676
680
 
677
681
  Arguments:
678
682
  entity: (str) Name of the entity requested. If None, will fall back to
@@ -731,7 +735,7 @@ class Api:
731
735
  return self._reports[key]
732
736
 
733
737
  def create_team(self, team, admin_username=None):
734
- """Creates a new team
738
+ """Create a new team.
735
739
 
736
740
  Arguments:
737
741
  team: (str) The name of the team
@@ -746,7 +750,7 @@ class Api:
746
750
  return Team(self.client, team)
747
751
 
748
752
  def user(self, username_or_email):
749
- """Return a user from a username or email address
753
+ """Return a user from a username or email address.
750
754
 
751
755
  Note: This function only works for Local Admins, if you are trying to get your own user object, please use `api.viewer`.
752
756
 
@@ -768,7 +772,7 @@ class Api:
768
772
  return User(self._client, res["users"]["edges"][0]["node"])
769
773
 
770
774
  def users(self, username_or_email):
771
- """Return all users from a partial username or email address query
775
+ """Return all users from a partial username or email address query.
772
776
 
773
777
  Note: This function only works for Local Admins, if you are trying to get your own user object, please use `api.viewer`.
774
778
 
@@ -789,8 +793,7 @@ class Api:
789
793
  per_page: int = 50,
790
794
  include_sweeps: bool = True,
791
795
  ):
792
- """
793
- Return a set of runs from a project that match the filters provided.
796
+ """Return a set of runs from a project that match the filters provided.
794
797
 
795
798
  You can filter by `config.*`, `summary_metrics.*`, `tags`, `state`, `entity`, `createdAt`, etc.
796
799
 
@@ -862,8 +865,7 @@ class Api:
862
865
 
863
866
  @normalize_exceptions
864
867
  def run(self, path=""):
865
- """
866
- Returns a single run by parsing path in the form entity/project/run_id.
868
+ """Return a single run by parsing path in the form entity/project/run_id.
867
869
 
868
870
  Arguments:
869
871
  path: (str) path to run in the form `entity/project/run_id`.
@@ -887,8 +889,9 @@ class Api:
887
889
  container_job=False,
888
890
  project_queue=None,
889
891
  ):
890
- """
891
- Returns a single queued run by parsing the path in the form entity/project/queue_id/run_queue_item_id
892
+ """Return a single queued run based on the path.
893
+
894
+ Parses paths of the form entity/project/queue_id/run_queue_item_id.
892
895
  """
893
896
  return QueuedRun(
894
897
  self.client,
@@ -902,8 +905,7 @@ class Api:
902
905
 
903
906
  @normalize_exceptions
904
907
  def sweep(self, path=""):
905
- """
906
- Returns a sweep by parsing path in the form `entity/project/sweep_id`.
908
+ """Return a sweep by parsing path in the form `entity/project/sweep_id`.
907
909
 
908
910
  Arguments:
909
911
  path: (str, optional) path to sweep in the form entity/project/sweep_id. If `api.entity`
@@ -936,8 +938,7 @@ class Api:
936
938
 
937
939
  @normalize_exceptions
938
940
  def artifact(self, name, type=None):
939
- """
940
- Returns a single artifact by parsing path in the form `entity/project/run_id`.
941
+ """Return a single artifact by parsing path in the form `entity/project/run_id`.
941
942
 
942
943
  Arguments:
943
944
  name: (str) An artifact name. May be prefixed with entity/project. Valid names
@@ -946,6 +947,7 @@ class Api:
946
947
  name:alias
947
948
  digest
948
949
  type: (str, optional) The type of artifact to fetch.
950
+
949
951
  Returns:
950
952
  A `Artifact` object.
951
953
  """
@@ -975,7 +977,7 @@ class Attrs:
975
977
  return camel[0].lower() + camel[1:]
976
978
 
977
979
  def display(self, height=420, hidden=False) -> bool:
978
- """Display this object in jupyter"""
980
+ """Display this object in jupyter."""
979
981
  html = self.to_html(height, hidden)
980
982
  if html is None:
981
983
  wandb.termwarn("This object does not support `.display()`")
@@ -1125,14 +1127,14 @@ class User(Attrs):
1125
1127
 
1126
1128
  @property
1127
1129
  def user_api(self):
1128
- """An instance of the api using credentials from the user"""
1130
+ """An instance of the api using credentials from the user."""
1129
1131
  if self._user_api is None and len(self.api_keys) > 0:
1130
1132
  self._user_api = wandb.Api(api_key=self.api_keys[0])
1131
1133
  return self._user_api
1132
1134
 
1133
1135
  @classmethod
1134
1136
  def create(cls, api, email, admin=False):
1135
- """Creates a new user
1137
+ """Create a new user.
1136
1138
 
1137
1139
  Arguments:
1138
1140
  api: (`Api`) The api instance to use
@@ -1161,7 +1163,7 @@ class User(Attrs):
1161
1163
  return [k["node"]["name"] for k in self._attrs["teams"]["edges"]]
1162
1164
 
1163
1165
  def delete_api_key(self, api_key):
1164
- """Delete a users api key
1166
+ """Delete a user's api key.
1165
1167
 
1166
1168
  Returns:
1167
1169
  Boolean indicating success
@@ -1180,7 +1182,7 @@ class User(Attrs):
1180
1182
  return True
1181
1183
 
1182
1184
  def generate_api_key(self, description=None):
1183
- """Generates a new api key
1185
+ """Generate a new api key.
1184
1186
 
1185
1187
  Returns:
1186
1188
  The new api key, or None on failure
@@ -1225,7 +1227,7 @@ class Member(Attrs):
1225
1227
  self.team = team
1226
1228
 
1227
1229
  def delete(self):
1228
- """Remove a member from a team
1230
+ """Remove a member from a team.
1229
1231
 
1230
1232
  Returns:
1231
1233
  Boolean indicating success
@@ -1327,7 +1329,7 @@ class Team(Attrs):
1327
1329
 
1328
1330
  @classmethod
1329
1331
  def create(cls, api, team, admin_username=None):
1330
- """Creates a new team
1332
+ """Create a new team.
1331
1333
 
1332
1334
  Arguments:
1333
1335
  api: (`Api`) The api instance to use
@@ -1347,7 +1349,7 @@ class Team(Attrs):
1347
1349
  return Team(api.client, team)
1348
1350
 
1349
1351
  def invite(self, username_or_email, admin=False):
1350
- """Invites a user to a team
1352
+ """Invite a user to a team.
1351
1353
 
1352
1354
  Arguments:
1353
1355
  username_or_email: (str) The username or email address of the user you want to invite
@@ -1368,7 +1370,7 @@ class Team(Attrs):
1368
1370
  return True
1369
1371
 
1370
1372
  def create_service_account(self, description):
1371
- """Creates a service account for the team
1373
+ """Create a service account for the team.
1372
1374
 
1373
1375
  Arguments:
1374
1376
  description: (str) A description for this service account
@@ -1401,9 +1403,7 @@ class Team(Attrs):
1401
1403
 
1402
1404
 
1403
1405
  class Projects(Paginator):
1404
- """
1405
- An iterable collection of `Project` objects.
1406
- """
1406
+ """An iterable collection of `Project` objects."""
1407
1407
 
1408
1408
  QUERY = gql(
1409
1409
  """
@@ -1480,7 +1480,7 @@ class Project(Attrs):
1480
1480
  return self.client.app_url + "/".join(self.path + ["workspace"])
1481
1481
 
1482
1482
  def to_html(self, height=420, hidden=False):
1483
- """Generate HTML containing an iframe displaying this project"""
1483
+ """Generate HTML containing an iframe displaying this project."""
1484
1484
  url = self.url + "?jupyter=true"
1485
1485
  style = f"border:none;width:100%;height:{height}px;"
1486
1486
  prefix = ""
@@ -1549,7 +1549,8 @@ class Project(Attrs):
1549
1549
 
1550
1550
  class Runs(Paginator):
1551
1551
  """An iterable collection of runs associated with a project and optional filter.
1552
- This is generally used indirectly via the `Api`.runs method
1552
+
1553
+ This is generally used indirectly via the `Api`.runs method.
1553
1554
  """
1554
1555
 
1555
1556
  QUERY = gql(
@@ -1661,8 +1662,7 @@ class Runs(Paginator):
1661
1662
 
1662
1663
 
1663
1664
  class Run(Attrs):
1664
- """
1665
- A single run associated with an entity and project.
1665
+ """A single run associated with an entity and project.
1666
1666
 
1667
1667
  Attributes:
1668
1668
  tags ([str]): a list of tags associated with the run
@@ -1694,8 +1694,10 @@ class Run(Attrs):
1694
1694
  attrs: Optional[Mapping] = None,
1695
1695
  include_sweeps: bool = True,
1696
1696
  ):
1697
- """
1698
- Run is always initialized by calling api.runs() where api is an instance of wandb.Api
1697
+ """Initialize a Run object.
1698
+
1699
+ Run is always initialized by calling api.runs() where api is an instance of
1700
+ wandb.Api.
1699
1701
  """
1700
1702
  _attrs = attrs or {}
1701
1703
  super().__init__(dict(_attrs))
@@ -1758,7 +1760,7 @@ class Run(Attrs):
1758
1760
 
1759
1761
  @classmethod
1760
1762
  def create(cls, api, run_id=None, project=None, entity=None):
1761
- """Create a run for the given project"""
1763
+ """Create a run for the given project."""
1762
1764
  run_id = run_id or runid.generate_id()
1763
1765
  project = project or api.settings.get("project") or "uncategorized"
1764
1766
  mutation = gql(
@@ -1883,9 +1885,7 @@ class Run(Attrs):
1883
1885
 
1884
1886
  @normalize_exceptions
1885
1887
  def update(self):
1886
- """
1887
- Persists changes to the run object to the wandb backend.
1888
- """
1888
+ """Persist changes to the run object to the wandb backend."""
1889
1889
  mutation = gql(
1890
1890
  """
1891
1891
  mutation UpsertBucket($id: String!, $description: String, $display_name: String, $notes: String, $tags: [String!], $config: JSONString!, $groupName: String) {
@@ -1913,9 +1913,7 @@ class Run(Attrs):
1913
1913
 
1914
1914
  @normalize_exceptions
1915
1915
  def delete(self, delete_artifacts=False):
1916
- """
1917
- Deletes the given run from the wandb backend.
1918
- """
1916
+ """Delete the given run from the wandb backend."""
1919
1917
  mutation = gql(
1920
1918
  """
1921
1919
  mutation DeleteRun(
@@ -1958,7 +1956,7 @@ class Run(Attrs):
1958
1956
  return json.dumps(config)
1959
1957
 
1960
1958
  def _exec(self, query, **kwargs):
1961
- """Execute a query against the cloud backend"""
1959
+ """Execute a query against the cloud backend."""
1962
1960
  variables = {"entity": self.entity, "project": self.project, "name": self.id}
1963
1961
  variables.update(kwargs)
1964
1962
  return self.client.execute(query, variable_values=variables)
@@ -1997,10 +1995,11 @@ class Run(Attrs):
1997
1995
 
1998
1996
  @normalize_exceptions
1999
1997
  def files(self, names=None, per_page=50):
2000
- """
1998
+ """Return a file path for each file named.
1999
+
2001
2000
  Arguments:
2002
2001
  names (list): names of the requested files, if empty returns all files
2003
- per_page (int): number of results per page
2002
+ per_page (int): number of results per page.
2004
2003
 
2005
2004
  Returns:
2006
2005
  A `Files` object, which is an iterator over `File` objects.
@@ -2009,7 +2008,8 @@ class Run(Attrs):
2009
2008
 
2010
2009
  @normalize_exceptions
2011
2010
  def file(self, name):
2012
- """
2011
+ """Return the path of a file with a given name in the artifact.
2012
+
2013
2013
  Arguments:
2014
2014
  name (str): name of requested file.
2015
2015
 
@@ -2020,12 +2020,13 @@ class Run(Attrs):
2020
2020
 
2021
2021
  @normalize_exceptions
2022
2022
  def upload_file(self, path, root="."):
2023
- """
2023
+ """Upload a file.
2024
+
2024
2025
  Arguments:
2025
2026
  path (str): name of file to upload.
2026
2027
  root (str): the root path to save the file relative to. i.e.
2027
2028
  If you want to have the file saved in the run as "my_dir/file.txt"
2028
- and you're currently in "my_dir" you would set root to "../"
2029
+ and you're currently in "my_dir" you would set root to "../".
2029
2030
 
2030
2031
  Returns:
2031
2032
  A `File` matching the name argument.
@@ -2045,20 +2046,21 @@ class Run(Attrs):
2045
2046
  def history(
2046
2047
  self, samples=500, keys=None, x_axis="_step", pandas=True, stream="default"
2047
2048
  ):
2048
- """
2049
- Returns sampled history metrics for a run. This is simpler and faster if you are ok with
2050
- the history records being sampled.
2049
+ """Return sampled history metrics for a run.
2050
+
2051
+ This is simpler and faster if you are ok with the history records being sampled.
2051
2052
 
2052
2053
  Arguments:
2053
- samples (int, optional): The number of samples to return
2054
- pandas (bool, optional): Return a pandas dataframe
2055
- keys (list, optional): Only return metrics for specific keys
2056
- x_axis (str, optional): Use this metric as the xAxis defaults to _step
2057
- stream (str, optional): "default" for metrics, "system" for machine metrics
2054
+ samples : (int, optional) The number of samples to return
2055
+ pandas : (bool, optional) Return a pandas dataframe
2056
+ keys : (list, optional) Only return metrics for specific keys
2057
+ x_axis : (str, optional) Use this metric as the xAxis defaults to _step
2058
+ stream : (str, optional) "default" for metrics, "system" for machine metrics
2058
2059
 
2059
2060
  Returns:
2060
- If pandas=True returns a `pandas.DataFrame` of history metrics.
2061
- If pandas=False returns a list of dicts of history metrics.
2061
+ pandas.DataFrame: If pandas=True returns a `pandas.DataFrame` of history
2062
+ metrics.
2063
+ list of dicts: If pandas=False returns a list of dicts of history metrics.
2062
2064
  """
2063
2065
  if keys is not None and not isinstance(keys, list):
2064
2066
  wandb.termerror("keys must be specified in a list")
@@ -2084,8 +2086,7 @@ class Run(Attrs):
2084
2086
 
2085
2087
  @normalize_exceptions
2086
2088
  def scan_history(self, keys=None, page_size=1000, min_step=None, max_step=None):
2087
- """
2088
- Returns an iterable collection of all history records for a run.
2089
+ """Returns an iterable collection of all history records for a run.
2089
2090
 
2090
2091
  Example:
2091
2092
  Export all the loss values for an example run
@@ -2158,6 +2159,7 @@ class Run(Attrs):
2158
2159
  to easily differentiate artifacts used in a
2159
2160
  run, when using the beta wandb launch
2160
2161
  feature's artifact swapping functionality.
2162
+
2161
2163
  Returns:
2162
2164
  A `Artifact` object.
2163
2165
  """
@@ -2258,7 +2260,7 @@ class Run(Attrs):
2258
2260
  return history_keys["lastStep"] if "lastStep" in history_keys else -1
2259
2261
 
2260
2262
  def to_html(self, height=420, hidden=False):
2261
- """Generate HTML containing an iframe displaying this run"""
2263
+ """Generate HTML containing an iframe displaying this run."""
2262
2264
  url = self.url + "?jupyter=true"
2263
2265
  style = f"border:none;width:100%;height:{height}px;"
2264
2266
  prefix = ""
@@ -2275,9 +2277,7 @@ class Run(Attrs):
2275
2277
 
2276
2278
 
2277
2279
  class QueuedRun:
2278
- """
2279
- A single queued run associated with an entity and project. Call `run = wait_until_running()` or `run = wait_until_finished()` methods to access the run
2280
- """
2280
+ """A single queued run associated with an entity and project. Call `run = wait_until_running()` or `run = wait_until_finished()` methods to access the run."""
2281
2281
 
2282
2282
  def __init__(
2283
2283
  self,
@@ -2402,9 +2402,7 @@ class QueuedRun:
2402
2402
 
2403
2403
  @normalize_exceptions
2404
2404
  def delete(self, delete_artifacts=False):
2405
- """
2406
- Deletes the given queued run from the wandb backend.
2407
- """
2405
+ """Delete the given queued run from the wandb backend."""
2408
2406
  query = gql(
2409
2407
  """
2410
2408
  query fetchRunQueuesFromProject($entityName: String!, $projectName: String!, $runQueueName: String!) {
@@ -2582,7 +2580,7 @@ class Sweep(Attrs):
2582
2580
  )
2583
2581
 
2584
2582
  def best_run(self, order=None):
2585
- "Returns the best run sorted by the metric defined in config or the order passed in"
2583
+ """Return the best run sorted by the metric defined in config or the order passed in."""
2586
2584
  if order is None:
2587
2585
  order = self.order
2588
2586
  else:
@@ -2608,7 +2606,7 @@ class Sweep(Attrs):
2608
2606
 
2609
2607
  @property
2610
2608
  def expected_run_count(self) -> Optional[int]:
2611
- "Returns the number of expected runs in the sweep or None for infinite runs."
2609
+ """Return the number of expected runs in the sweep or None for infinite runs."""
2612
2610
  return self._attrs.get("runCountExpected")
2613
2611
 
2614
2612
  @property
@@ -2640,7 +2638,7 @@ class Sweep(Attrs):
2640
2638
  query=None,
2641
2639
  **kwargs,
2642
2640
  ):
2643
- """Execute a query against the cloud backend"""
2641
+ """Execute a query against the cloud backend."""
2644
2642
  if query is None:
2645
2643
  query = cls.QUERY
2646
2644
 
@@ -2681,7 +2679,7 @@ class Sweep(Attrs):
2681
2679
  return sweep
2682
2680
 
2683
2681
  def to_html(self, height=420, hidden=False):
2684
- """Generate HTML containing an iframe displaying this sweep"""
2682
+ """Generate HTML containing an iframe displaying this sweep."""
2685
2683
  url = self.url + "?jupyter=true"
2686
2684
  style = f"border:none;width:100%;height:{height}px;"
2687
2685
  prefix = ""
@@ -2940,7 +2938,7 @@ class Reports(Paginator):
2940
2938
 
2941
2939
 
2942
2940
  class QueryGenerator:
2943
- """QueryGenerator is a helper object to write filters for runs"""
2941
+ """QueryGenerator is a helper object to write filters for runs."""
2944
2942
 
2945
2943
  INDIVIDUAL_OP_TO_MONGO = {
2946
2944
  "!=": "$ne",
@@ -3195,15 +3193,15 @@ class PythonMongoishQueryGenerator:
3195
3193
 
3196
3194
  def _replace_numeric_dots(self, s):
3197
3195
  numeric_dots = []
3198
- for i, (l, m, r) in enumerate(zip(s, s[1:], s[2:]), 1):
3199
- if m == ".":
3196
+ for i, (left, mid, right) in enumerate(zip(s, s[1:], s[2:]), 1):
3197
+ if mid == ".":
3200
3198
  if (
3201
- l.isdigit()
3202
- and r.isdigit() # 1.2
3203
- or l.isdigit()
3204
- and r == " " # 1.
3205
- or l == " "
3206
- and r.isdigit() # .2
3199
+ left.isdigit()
3200
+ and right.isdigit() # 1.2
3201
+ or left.isdigit()
3202
+ and right == " " # 1.
3203
+ or left == " "
3204
+ and right.isdigit() # .2
3207
3205
  ):
3208
3206
  numeric_dots.append(i)
3209
3207
  # Edge: Catch number ending in dot at end of string
@@ -3459,7 +3457,7 @@ class BetaReport(Attrs):
3459
3457
  )
3460
3458
 
3461
3459
  def to_html(self, height=1024, hidden=False):
3462
- """Generate HTML containing an iframe displaying this report"""
3460
+ """Generate HTML containing an iframe displaying this report."""
3463
3461
  url = self.url + "?jupyter=true"
3464
3462
  style = f"border:none;width:100%;height:{height}px;"
3465
3463
  prefix = ""
@@ -3997,7 +3995,7 @@ class ArtifactType:
3997
3995
 
3998
3996
  @normalize_exceptions
3999
3997
  def collections(self, per_page=50):
4000
- """Artifact collections"""
3998
+ """Artifact collections."""
4001
3999
  return ProjectArtifactCollections(
4002
4000
  self.client, self.entity, self.project, self.type
4003
4001
  )
@@ -4037,7 +4035,7 @@ class ArtifactCollection:
4037
4035
 
4038
4036
  @normalize_exceptions
4039
4037
  def versions(self, per_page=50):
4040
- """Artifact versions"""
4038
+ """Artifact versions."""
4041
4039
  return ArtifactVersions(
4042
4040
  self.client,
4043
4041
  self.entity,
@@ -4049,7 +4047,7 @@ class ArtifactCollection:
4049
4047
 
4050
4048
  @property
4051
4049
  def aliases(self):
4052
- """Artifact Collection Aliases"""
4050
+ """Artifact Collection Aliases."""
4053
4051
  return self._aliases
4054
4052
 
4055
4053
  def load(self):
@@ -4137,37 +4135,27 @@ class _DownloadedArtifactEntry(artifacts.ArtifactManifestEntry):
4137
4135
  return self._parent_artifact
4138
4136
 
4139
4137
  def copy(self, cache_path, target_path):
4140
- # can't have colons in Windows
4141
- if platform.system() == "Windows":
4142
- head, tail = os.path.splitdrive(target_path)
4143
- target_path = head + tail.replace(":", "-")
4144
-
4145
- need_copy = (
4146
- not os.path.isfile(target_path)
4147
- or os.stat(cache_path).st_mtime != os.stat(target_path).st_mtime
4148
- )
4149
- if need_copy:
4150
- filesystem.mkdir_exists_ok(os.path.dirname(target_path))
4151
- # We use copy2, which preserves file metadata including modified
4152
- # time (which we use above to check whether we should do the copy).
4153
- shutil.copy2(cache_path, target_path)
4154
- return target_path
4138
+ raise NotImplementedError()
4155
4139
 
4156
4140
  def download(self, root=None):
4157
4141
  root = root or self._parent_artifact._default_root()
4142
+ dest_path = os.path.join(root, self.name)
4143
+
4158
4144
  self._parent_artifact._add_download_root(root)
4159
4145
  manifest = self._parent_artifact._load_manifest()
4146
+
4147
+ # Skip checking the cache (and possibly downloading) if the file already exists
4148
+ # and has the digest we're expecting.
4149
+ entry = manifest.entries[self.name]
4150
+ if os.path.exists(dest_path) and entry.digest == md5_file_b64(dest_path):
4151
+ return dest_path
4152
+
4160
4153
  if self.ref is not None:
4161
- cache_path = manifest.storage_policy.load_reference(
4162
- manifest.entries[self.name],
4163
- local=True,
4164
- )
4154
+ cache_path = manifest.storage_policy.load_reference(entry, local=True)
4165
4155
  else:
4166
- cache_path = manifest.storage_policy.load_file(
4167
- self._parent_artifact, manifest.entries[self.name]
4168
- )
4156
+ cache_path = manifest.storage_policy.load_file(self._parent_artifact, entry)
4169
4157
 
4170
- return self.copy(cache_path, os.path.join(root, self.name))
4158
+ return filesystem.copy_or_overwrite_changed(cache_path, dest_path)
4171
4159
 
4172
4160
  def ref_target(self):
4173
4161
  manifest = self._parent_artifact._load_manifest()
@@ -4224,8 +4212,7 @@ class _ArtifactDownloadLogger:
4224
4212
 
4225
4213
 
4226
4214
  class Artifact(artifacts.Artifact):
4227
- """
4228
- A wandb Artifact.
4215
+ """A wandb Artifact.
4229
4216
 
4230
4217
  An artifact that has been logged, including all its attributes, links to the runs
4231
4218
  that use it, and a link to the run that logged it.
@@ -4350,7 +4337,7 @@ class Artifact(artifacts.Artifact):
4350
4337
  with requests.get(index_file_url) as req:
4351
4338
  req.raise_for_status()
4352
4339
  artifact._manifest = artifacts.ArtifactManifest.from_manifest_json(
4353
- artifact, json.loads(util.ensure_text(req.content))
4340
+ json.loads(util.ensure_text(req.content))
4354
4341
  )
4355
4342
 
4356
4343
  artifact._load_dependent_manifests()
@@ -4366,6 +4353,19 @@ class Artifact(artifacts.Artifact):
4366
4353
  self._attrs = attrs
4367
4354
  if self._attrs is None:
4368
4355
  self._load()
4356
+
4357
+ # The entity and project above are taken from the passed-in artifact version path
4358
+ # so if the user is pulling an artifact version from an artifact portfolio, the entity/project
4359
+ # of that portfolio may be different than the birth entity/project of the artifact version.
4360
+ self._birth_project = (
4361
+ self._attrs.get("artifactType", {}).get("project", {}).get("name")
4362
+ )
4363
+ self._birth_entity = (
4364
+ self._attrs.get("artifactType", {})
4365
+ .get("project", {})
4366
+ .get("entity", {})
4367
+ .get("name")
4368
+ )
4369
4369
  self._metadata = json.loads(self._attrs.get("metadata") or "{}")
4370
4370
  self._description = self._attrs.get("description", None)
4371
4371
  self._sequence_name = self._attrs["artifactSequence"]["name"]
@@ -4395,19 +4395,17 @@ class Artifact(artifacts.Artifact):
4395
4395
 
4396
4396
  @property
4397
4397
  def source_version(self):
4398
- """
4399
- Returns:
4400
- (str) The artifact's version index under its parent artifact collection. This will return
4401
- a string with the format "v{number}".
4398
+ """The artifact's version index under its parent artifact collection.
4399
+
4400
+ A string with the format "v{number}".
4402
4401
  """
4403
4402
  return f"v{self._sequence_version_index}"
4404
4403
 
4405
4404
  @property
4406
4405
  def version(self):
4407
- """
4408
- Returns:
4409
- (str): The artifact's version index under the given artifact collection. This will return
4410
- a string with the format "v{number}".
4406
+ """The artifact's version index under the given artifact collection.
4407
+
4408
+ A string with the format "v{number}".
4411
4409
  """
4412
4410
  for a in self._attrs["aliases"]:
4413
4411
  if a[
@@ -4452,18 +4450,12 @@ class Artifact(artifacts.Artifact):
4452
4450
 
4453
4451
  @property
4454
4452
  def created_at(self):
4455
- """
4456
- Returns:
4457
- (datetime): The time at which the artifact was created.
4458
- """
4453
+ """The time at which the artifact was created."""
4459
4454
  return self._attrs["createdAt"]
4460
4455
 
4461
4456
  @property
4462
4457
  def updated_at(self):
4463
- """
4464
- Returns:
4465
- (datetime): The time at which the artifact was last updated.
4466
- """
4458
+ """The time at which the artifact was last updated."""
4467
4459
  return self._attrs["updatedAt"] or self._attrs["createdAt"]
4468
4460
 
4469
4461
  @property
@@ -4490,8 +4482,7 @@ class Artifact(artifacts.Artifact):
4490
4482
 
4491
4483
  @property
4492
4484
  def aliases(self):
4493
- """
4494
- The aliases associated with this artifact.
4485
+ """The aliases associated with this artifact.
4495
4486
 
4496
4487
  Returns:
4497
4488
  List[str]: The aliases associated with this artifact.
@@ -4510,7 +4501,7 @@ class Artifact(artifacts.Artifact):
4510
4501
 
4511
4502
  @staticmethod
4512
4503
  def expected_type(client, name, entity_name, project_name):
4513
- """Returns the expected type for a given artifact name and project"""
4504
+ """Returns the expected type for a given artifact name and project."""
4514
4505
  query = gql(
4515
4506
  """
4516
4507
  query ArtifactType(
@@ -4604,8 +4595,7 @@ class Artifact(artifacts.Artifact):
4604
4595
 
4605
4596
  @normalize_exceptions
4606
4597
  def delete(self, delete_aliases=False):
4607
- """
4608
- Delete an artifact and its files.
4598
+ """Delete an artifact and its files.
4609
4599
 
4610
4600
  Examples:
4611
4601
  Delete all the "model" artifacts a run has logged:
@@ -4660,17 +4650,15 @@ class Artifact(artifacts.Artifact):
4660
4650
  raise ValueError("Cannot add files to an artifact once it has been saved")
4661
4651
 
4662
4652
  def _add_download_root(self, dir_path):
4663
- """Adds `dir_path` as one of the known directories which this
4664
- artifact treated as a root"""
4653
+ """Make `dir_path` a root directory for this artifact."""
4665
4654
  self._download_roots.add(os.path.abspath(dir_path))
4666
4655
 
4667
4656
  def _is_download_root(self, dir_path):
4668
- """Determines if `dir_path` is a directory which this artifact as
4669
- treated as a root for downloading"""
4657
+ """Determine if `dir_path` is a root directory for this artifact."""
4670
4658
  return dir_path in self._download_roots
4671
4659
 
4672
4660
  def _local_path_to_name(self, file_path):
4673
- """Converts a local file path to a path entry in the artifact"""
4661
+ """Convert a local file path to a path entry in the artifact."""
4674
4662
  abs_file_path = os.path.abspath(file_path)
4675
4663
  abs_file_parts = abs_file_path.split(os.sep)
4676
4664
  for i in range(len(abs_file_parts) + 1):
@@ -4679,10 +4667,11 @@ class Artifact(artifacts.Artifact):
4679
4667
  return None
4680
4668
 
4681
4669
  def _get_obj_entry(self, name):
4682
- """
4683
- When objects are added with `.add(obj, name)`, the name is typically
4684
- changed to include the suffix of the object type when serializing to JSON. So we need
4685
- to be able to resolve a name, without tasking the user with appending .THING.json.
4670
+ """Return an object entry by name, handling any type suffixes.
4671
+
4672
+ When objects are added with `.add(obj, name)`, the name is typically changed to
4673
+ include the suffix of the object type when serializing to JSON. So we need to be
4674
+ able to resolve a name, without tasking the user with appending .THING.json.
4686
4675
  This method returns an entry if it exists by a suffixed name.
4687
4676
 
4688
4677
  Args:
@@ -4831,7 +4820,7 @@ class Artifact(artifacts.Artifact):
4831
4820
  print("Warning: skipped verification of %s refs" % ref_count)
4832
4821
 
4833
4822
  def file(self, root=None):
4834
- """Download a single file artifact to dir specified by the root
4823
+ """Download a single file artifact to dir specified by the root.
4835
4824
 
4836
4825
  Arguments:
4837
4826
  root: (str, optional) The root directory in which to place the file. Defaults to './artifacts/self.name/'.
@@ -4839,7 +4828,6 @@ class Artifact(artifacts.Artifact):
4839
4828
  Returns:
4840
4829
  (str): The full path of the downloaded file.
4841
4830
  """
4842
-
4843
4831
  if root is None:
4844
4832
  root = os.path.join(".", "artifacts", self.name)
4845
4833
 
@@ -4878,9 +4866,7 @@ class Artifact(artifacts.Artifact):
4878
4866
 
4879
4867
  @normalize_exceptions
4880
4868
  def save(self):
4881
- """
4882
- Persists artifact changes to the wandb backend.
4883
- """
4869
+ """Persists artifact changes to the wandb backend."""
4884
4870
  mutation = gql(
4885
4871
  """
4886
4872
  mutation updateArtifact(
@@ -4948,11 +4934,10 @@ class Artifact(artifacts.Artifact):
4948
4934
 
4949
4935
  @normalize_exceptions
4950
4936
  def _save_alias_changes(self):
4951
- """
4952
- Convenience function called by artifact.save() to persist alias changes
4953
- on this artifact to the wandb backend.
4954
- """
4937
+ """Persist alias changes on this artifact to the wandb backend.
4955
4938
 
4939
+ Called by artifact.save().
4940
+ """
4956
4941
  aliases_to_add = set(self._aliases) - set(self._frozen_aliases)
4957
4942
  aliases_to_remove = set(self._frozen_aliases) - set(self._aliases)
4958
4943
 
@@ -5152,7 +5137,7 @@ class Artifact(artifacts.Artifact):
5152
5137
  with requests.get(index_file_url) as req:
5153
5138
  req.raise_for_status()
5154
5139
  self._manifest = artifacts.ArtifactManifest.from_manifest_json(
5155
- self, json.loads(util.ensure_text(req.content))
5140
+ json.loads(util.ensure_text(req.content))
5156
5141
  )
5157
5142
 
5158
5143
  self._load_dependent_manifests()
@@ -5160,7 +5145,7 @@ class Artifact(artifacts.Artifact):
5160
5145
  return self._manifest
5161
5146
 
5162
5147
  def _load_dependent_manifests(self):
5163
- """Helper function to interrogate entries and ensure we have loaded their manifests"""
5148
+ """Interrogate entries and ensure we have loaded their manifests."""
5164
5149
  # Make sure dependencies are avail
5165
5150
  for entry_key in self._manifest.entries:
5166
5151
  entry = self._manifest.entries[entry_key]
@@ -5172,19 +5157,19 @@ class Artifact(artifacts.Artifact):
5172
5157
 
5173
5158
  @staticmethod
5174
5159
  def _manifest_entry_is_artifact_reference(entry):
5175
- """Helper function determines if an ArtifactManifestEntry in manifest is an artifact reference"""
5160
+ """Determine if an ArtifactManifestEntry is an artifact reference."""
5176
5161
  return (
5177
5162
  entry.ref is not None
5178
5163
  and urllib.parse.urlparse(entry.ref).scheme == "wandb-artifact"
5179
5164
  )
5180
5165
 
5181
5166
  def _get_ref_artifact_from_entry(self, entry):
5182
- """Helper function returns the referenced artifact from an entry"""
5167
+ """Helper function returns the referenced artifact from an entry."""
5183
5168
  artifact_id = util.host_from_path(entry.ref)
5184
5169
  return Artifact.from_id(hex_to_b64_id(artifact_id), self.client)
5185
5170
 
5186
5171
  def used_by(self):
5187
- """Retrieves the runs which use this artifact directly
5172
+ """Retrieve the runs which use this artifact directly.
5188
5173
 
5189
5174
  Returns:
5190
5175
  [Run]: a list of Run objects which use this artifact
@@ -5231,7 +5216,7 @@ class Artifact(artifacts.Artifact):
5231
5216
  return runs
5232
5217
 
5233
5218
  def logged_by(self):
5234
- """Retrieves the run which logged this artifact
5219
+ """Retrieve the run which logged this artifact.
5235
5220
 
5236
5221
  Returns:
5237
5222
  Run: Run object which logged this artifact
@@ -5277,7 +5262,8 @@ class Artifact(artifacts.Artifact):
5277
5262
 
5278
5263
  class ArtifactVersions(Paginator):
5279
5264
  """An iterable collection of artifact versions associated with a project and optional filter.
5280
- This is generally used indirectly via the `Api`.artifact_versions method
5265
+
5266
+ This is generally used indirectly via the `Api`.artifact_versions method.
5281
5267
  """
5282
5268
 
5283
5269
  def __init__(
@@ -5419,8 +5405,8 @@ class ArtifactFiles(Paginator):
5419
5405
  ):
5420
5406
  self.artifact = artifact
5421
5407
  variables = {
5422
- "entityName": artifact.entity,
5423
- "projectName": artifact.project,
5408
+ "entityName": artifact._birth_entity,
5409
+ "projectName": artifact._birth_project,
5424
5410
  "artifactTypeName": artifact.type,
5425
5411
  "artifactName": artifact.name,
5426
5412
  "fileNames": names,
@@ -5473,7 +5459,6 @@ class ArtifactFiles(Paginator):
5473
5459
 
5474
5460
 
5475
5461
  class Job:
5476
-
5477
5462
  _name: str
5478
5463
  _input_types: Type
5479
5464
  _output_types: Type
@@ -5577,7 +5562,6 @@ class Job:
5577
5562
  queue=None,
5578
5563
  resource="local-container",
5579
5564
  resource_args=None,
5580
- cuda=False,
5581
5565
  project_queue=None,
5582
5566
  ):
5583
5567
  from wandb.sdk.launch import launch_add
@@ -5604,6 +5588,5 @@ class Job:
5604
5588
  resource=resource,
5605
5589
  project_queue=project_queue,
5606
5590
  resource_args=resource_args,
5607
- cuda=cuda,
5608
5591
  )
5609
5592
  return queued_run