wandb 0.19.4rc1__py3-none-win32.whl → 0.19.6rc4__py3-none-win32.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 (47) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +1 -8
  3. wandb/_iterutils.py +46 -0
  4. wandb/apis/internal.py +4 -0
  5. wandb/apis/normalize.py +13 -5
  6. wandb/bin/gpu_stats.exe +0 -0
  7. wandb/bin/wandb-core +0 -0
  8. wandb/cli/cli.py +9 -2
  9. wandb/proto/v3/wandb_internal_pb2.py +36 -36
  10. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  11. wandb/proto/v4/wandb_internal_pb2.py +36 -36
  12. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  13. wandb/proto/v5/wandb_internal_pb2.py +36 -36
  14. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  15. wandb/sdk/artifacts/artifact.py +120 -8
  16. wandb/sdk/artifacts/storage_handlers/local_file_handler.py +12 -5
  17. wandb/sdk/artifacts/storage_handlers/wb_local_artifact_handler.py +1 -1
  18. wandb/sdk/backend/backend.py +7 -11
  19. wandb/sdk/data_types/base_types/wb_value.py +10 -10
  20. wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +2 -2
  21. wandb/sdk/data_types/helper_types/image_mask.py +2 -2
  22. wandb/sdk/data_types/image.py +0 -3
  23. wandb/sdk/data_types/saved_model.py +1 -1
  24. wandb/sdk/data_types/utils.py +2 -6
  25. wandb/sdk/interface/interface.py +26 -12
  26. wandb/sdk/interface/interface_sock.py +7 -11
  27. wandb/sdk/internal/internal_api.py +9 -1
  28. wandb/sdk/internal/sender.py +2 -2
  29. wandb/sdk/internal/system/assets/cpu.py +1 -1
  30. wandb/sdk/lib/apikey.py +7 -19
  31. wandb/sdk/lib/mailbox.py +0 -14
  32. wandb/sdk/lib/retry.py +6 -3
  33. wandb/sdk/lib/run_moment.py +19 -7
  34. wandb/sdk/lib/server.py +20 -0
  35. wandb/sdk/lib/service_connection.py +2 -2
  36. wandb/sdk/wandb_init.py +71 -46
  37. wandb/sdk/wandb_login.py +86 -110
  38. wandb/sdk/wandb_metadata.py +60 -31
  39. wandb/sdk/wandb_run.py +32 -45
  40. wandb/sdk/wandb_settings.py +465 -143
  41. wandb/sdk/wandb_setup.py +10 -22
  42. wandb/util.py +44 -12
  43. {wandb-0.19.4rc1.dist-info → wandb-0.19.6rc4.dist-info}/METADATA +1 -1
  44. {wandb-0.19.4rc1.dist-info → wandb-0.19.6rc4.dist-info}/RECORD +47 -46
  45. {wandb-0.19.4rc1.dist-info → wandb-0.19.6rc4.dist-info}/WHEEL +0 -0
  46. {wandb-0.19.4rc1.dist-info → wandb-0.19.6rc4.dist-info}/entry_points.txt +0 -0
  47. {wandb-0.19.4rc1.dist-info → wandb-0.19.6rc4.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_init.py CHANGED
@@ -20,7 +20,7 @@ import platform
20
20
  import sys
21
21
  import tempfile
22
22
  import time
23
- from typing import TYPE_CHECKING, Any, Literal, Sequence
23
+ from typing import Any, Literal, Sequence
24
24
 
25
25
  if sys.version_info >= (3, 11):
26
26
  from typing import Self
@@ -40,16 +40,13 @@ from wandb.util import _is_artifact_representation
40
40
 
41
41
  from . import wandb_login, wandb_setup
42
42
  from .backend.backend import Backend
43
- from .lib import SummaryDisabled, filesystem, module, printer, telemetry
43
+ from .lib import SummaryDisabled, filesystem, module, paths, printer, telemetry
44
44
  from .lib.deprecate import Deprecated, deprecate
45
45
  from .lib.mailbox import Mailbox, MailboxProgress
46
46
  from .wandb_helper import parse_config
47
47
  from .wandb_run import Run, TeardownHook, TeardownStage
48
48
  from .wandb_settings import Settings
49
49
 
50
- if TYPE_CHECKING:
51
- from wandb.proto import wandb_internal_pb2 as pb
52
-
53
50
 
54
51
  def _huggingface_version() -> str | None:
55
52
  if "transformers" in sys.modules:
@@ -180,7 +177,6 @@ class _WandbInit:
180
177
  force=run_settings.force,
181
178
  _disable_warning=True,
182
179
  _silent=run_settings.quiet or run_settings.silent,
183
- _entity=run_settings.entity,
184
180
  )
185
181
 
186
182
  def warn_env_vars_change_after_setup(self) -> None:
@@ -454,6 +450,23 @@ class _WandbInit:
454
450
  artifacts=result.artifacts,
455
451
  )
456
452
 
453
+ wandb_internal = result.base_no_artifacts.setdefault("_wandb", dict())
454
+
455
+ if settings.save_code and settings.program_relpath:
456
+ wandb_internal["code_path"] = paths.LogicalPath(
457
+ os.path.join("code", settings.program_relpath)
458
+ )
459
+ if settings.fork_from is not None:
460
+ wandb_internal["branch_point"] = {
461
+ "run_id": settings.fork_from.run,
462
+ "step": settings.fork_from.value,
463
+ }
464
+ if settings.resume_from is not None:
465
+ wandb_internal["branch_point"] = {
466
+ "run_id": settings.resume_from.run,
467
+ "step": settings.resume_from.value,
468
+ }
469
+
457
470
  return result
458
471
 
459
472
  def teardown(self) -> None:
@@ -864,7 +877,7 @@ class _WandbInit:
864
877
  tel.feature.core = True
865
878
  if settings._shared:
866
879
  wandb.termwarn(
867
- "The `_shared` feature is experimental and may change. "
880
+ "The `shared` mode feature is experimental and may change. "
868
881
  "Please contact support@wandb.com for guidance and to report any issues."
869
882
  )
870
883
  tel.feature.shared_mode = True
@@ -891,7 +904,6 @@ class _WandbInit:
891
904
  run._set_backend(backend)
892
905
  run._set_teardown_hooks(self._teardown_hooks)
893
906
 
894
- backend._hack_set_run(run)
895
907
  assert backend.interface
896
908
  mailbox.enable_keepalive()
897
909
  backend.interface.publish_header()
@@ -902,8 +914,6 @@ class _WandbInit:
902
914
  if not (settings.disable_git or settings.x_disable_machine_info):
903
915
  run._populate_git_info()
904
916
 
905
- run_result: pb.RunUpdateResult | None = None
906
-
907
917
  if settings._offline and settings.resume:
908
918
  wandb.termwarn(
909
919
  "`resume` will be ignored since W&B syncing is set to `offline`. "
@@ -911,6 +921,16 @@ class _WandbInit:
911
921
  )
912
922
  error: wandb.Error | None = None
913
923
 
924
+ # In shared mode, generate a unique label if not provided.
925
+ # The label is used to distinguish between system metrics and console logs
926
+ # from different writers to the same run.
927
+ if settings._shared and not settings.x_label:
928
+ # TODO: If executed in a known distributed environment (e.g. Ray or SLURM),
929
+ # use the env vars to generate a label (e.g. SLURM_JOB_ID or RANK)
930
+ prefix = settings.host or ""
931
+ label = runid.generate_id()
932
+ settings.x_label = f"{prefix}-{label}" if prefix else label
933
+
914
934
  timeout = settings.init_timeout
915
935
 
916
936
  self._logger.info(
@@ -923,47 +943,53 @@ class _WandbInit:
923
943
  on_progress=self._on_progress_init,
924
944
  cancel=True,
925
945
  )
926
- if result:
927
- run_result = result.run_result
928
-
929
- if run_result is None:
930
- error_message = (
931
- f"Run initialization has timed out after {timeout} sec. "
932
- "Please try increasing the timeout with the `init_timeout` setting: "
933
- "`wandb.init(settings=wandb.Settings(init_timeout=120))`."
934
- )
935
- # We're not certain whether the error we encountered is due to an issue
936
- # with the server (a "CommError") or if it's a problem within the SDK (an "Error").
937
- # This means that the error could be a result of the server being unresponsive,
938
- # or it could be because we were unable to communicate with the wandb service.
939
- error = CommError(error_message)
940
- run_init_handle._cancel()
941
- elif run_result.HasField("error"):
942
- error = ProtobufErrorHandler.to_exception(run_result.error)
943
-
944
- if error is not None:
945
- self._logger.error(f"encountered error: {error}")
946
+
947
+ # Raise an error if deliver_run failed.
948
+ #
949
+ # This is wrapped in a try-except to perform additional cleanup logic
950
+ # when x_disable_service is True.
951
+ #
952
+ # TODO: Remove try-except once x_disable_service is removed.
953
+ try:
954
+ if not result or not result.run_result:
955
+ run_init_handle._cancel()
956
+
957
+ # This may either be an issue with the W&B server (a CommError)
958
+ # or a bug in the SDK (an Error). We cannot distinguish between
959
+ # the two causes here.
960
+ raise CommError(
961
+ f"Run initialization has timed out after {timeout} sec."
962
+ " Please try increasing the timeout with the `init_timeout`"
963
+ " setting: `wandb.init(settings=wandb.Settings(init_timeout=120))`."
964
+ )
965
+
966
+ if error := ProtobufErrorHandler.to_exception(result.run_result.error):
967
+ raise error
968
+
969
+ if not result.run_result.HasField("run"):
970
+ raise Error("Assertion failed: run_result is missing the run field")
971
+
972
+ except Exception:
946
973
  if not service:
947
- # Shutdown the backend and get rid of the logger
948
- # we don't need to do console cleanup at this point
974
+ # Kill the background thread or process.
949
975
  backend.cleanup()
950
- self.teardown()
951
- raise error
952
-
953
- assert run_result is not None # for mypy
954
976
 
955
- if not run_result.HasField("run"):
956
- raise Error(
957
- "It appears that something have gone wrong during the program "
958
- "execution as an unexpected missing field was encountered. "
959
- "(run_result is missing the 'run' field)"
960
- )
977
+ # Do some Jupyter and logger cleanup.
978
+ #
979
+ # NOTE: This shouldn't be necessary. The logger is global,
980
+ # so on any error outside of this try-catch, we fail to
981
+ # clean it up, causing the next run to write some of its
982
+ # initial logs to this run's log file. The Jupyter
983
+ # monkeypatching should probably happen at the library level
984
+ # (in wandb.setup()) rather than per-run.
985
+ self.teardown()
986
+ raise
961
987
 
962
- if run_result.run.resumed:
988
+ if result.run_result.run.resumed:
963
989
  self._logger.info("run resumed")
964
990
  with telemetry.context(run=run) as tel:
965
- tel.feature.resumed = run_result.run.resumed
966
- run._set_run_obj(run_result.run)
991
+ tel.feature.resumed = result.run_result.run.resumed
992
+ run._set_run_obj(result.run_result.run)
967
993
 
968
994
  self._logger.info("starting run threads in backend")
969
995
  # initiate run (stats and metadata probing)
@@ -1069,7 +1095,6 @@ def _attach(
1069
1095
  run._init(settings=settings)
1070
1096
  run._set_library(_wl)
1071
1097
  run._set_backend(backend)
1072
- backend._hack_set_run(run)
1073
1098
  assert backend.interface
1074
1099
 
1075
1100
  mailbox.enable_keepalive()
wandb/sdk/wandb_login.py CHANGED
@@ -8,6 +8,7 @@ import os
8
8
  from typing import Literal, Optional, Tuple
9
9
 
10
10
  import click
11
+ from requests.exceptions import ConnectionError
11
12
 
12
13
  import wandb
13
14
  from wandb.errors import AuthenticationError, UsageError
@@ -16,7 +17,6 @@ from wandb.old.settings import Settings as OldSettings
16
17
  from ..apis import InternalApi
17
18
  from .internal.internal_api import Api
18
19
  from .lib import apikey
19
- from .wandb_settings import Settings
20
20
 
21
21
 
22
22
  def _handle_host_wandb_setting(host: Optional[str], cloud: bool = False) -> None:
@@ -73,30 +73,16 @@ def login(
73
73
  UsageError - if api_key cannot be configured and no tty
74
74
  """
75
75
  _handle_host_wandb_setting(host)
76
- if wandb.setup()._settings._noop:
77
- return True
78
-
79
- configured = _login(
76
+ return _login(
80
77
  anonymous=anonymous,
81
78
  key=key,
82
79
  relogin=relogin,
83
80
  host=host,
84
81
  force=force,
85
82
  timeout=timeout,
83
+ verify=verify,
86
84
  )
87
85
 
88
- if verify:
89
- from . import wandb_setup
90
-
91
- singleton = wandb_setup.singleton()
92
- assert singleton is not None
93
- viewer = singleton._server._viewer
94
- if not viewer:
95
- raise AuthenticationError(
96
- "API key verification failed. Make sure your API key is valid."
97
- )
98
- return True if configured else False
99
-
100
86
 
101
87
  class ApiKeyStatus(enum.Enum):
102
88
  VALID = 1
@@ -106,26 +92,15 @@ class ApiKeyStatus(enum.Enum):
106
92
 
107
93
 
108
94
  class _WandbLogin:
109
- def __init__(self):
110
- self._settings: Optional[Settings] = None
111
- self._backend = None
112
- self._silent: Optional[bool] = None
113
- self._entity: Optional[str] = None
114
- self._wl = None
115
- self._key = None
116
- self._relogin = None
117
-
118
- def setup(
95
+ def __init__(
119
96
  self,
120
- *,
121
- anonymous: Optional[Literal["allow", "must", "never"]] = None,
97
+ anonymous: Optional[Literal["must", "allow", "never"]] = None,
98
+ force: Optional[bool] = None,
99
+ host: Optional[str] = None,
122
100
  key: Optional[str] = None,
123
101
  relogin: Optional[bool] = None,
124
- host: Optional[str] = None,
125
- force: Optional[bool] = None,
126
102
  timeout: Optional[int] = None,
127
- ) -> None:
128
- """Updates login-related settings on the global setup object."""
103
+ ):
129
104
  self._relogin = relogin
130
105
 
131
106
  login_settings = {
@@ -135,61 +110,47 @@ class _WandbLogin:
135
110
  "force": force,
136
111
  "login_timeout": timeout,
137
112
  }
113
+ self.is_anonymous = anonymous == "must"
138
114
 
139
- # make sure they are applied globally
140
- self._wl = wandb.setup(
141
- settings=wandb.Settings(
142
- **{k: v for k, v in login_settings.items() if v is not None}
143
- )
144
- )
145
- self._settings = self._wl.settings
115
+ self._wandb_setup = wandb.setup()
116
+ self._wandb_setup.settings.update_from_dict(login_settings)
117
+ self._settings = self._wandb_setup.settings
118
+
119
+ def _update_global_anonymous_setting(self) -> None:
120
+ api = InternalApi()
121
+ if self.is_anonymous:
122
+ api.set_setting("anonymous", "must", globally=True, persist=True)
123
+ else:
124
+ api.clear_setting("anonymous", globally=True, persist=True)
146
125
 
147
126
  def is_apikey_configured(self) -> bool:
148
127
  """Returns whether an API key is set or can be inferred."""
149
128
  return apikey.api_key(settings=self._settings) is not None
150
129
 
151
- def should_use_identity_token(self):
152
- return self._settings.identity_token_file is not None
153
-
154
- def set_backend(self, backend):
155
- self._backend = backend
156
-
157
- def set_silent(self, silent: bool) -> None:
158
- self._silent = silent
159
-
160
- def set_entity(self, entity: str) -> None:
161
- self._entity = entity
162
-
163
- def login(self) -> bool:
164
- """Returns whether the user is logged in (i.e. an API key exists).
165
-
166
- If the user is logged in, this also prints an informational message.
167
- """
168
- apikey_configured = self.is_apikey_configured()
169
- if self._settings.relogin or self._relogin:
170
- apikey_configured = False
171
- if not apikey_configured:
172
- return False
173
-
174
- if not self._silent:
175
- self._print_logged_in_message()
176
-
177
- return apikey_configured
178
-
179
130
  def _print_logged_in_message(self) -> None:
180
131
  """Prints a message telling the user they are logged in."""
181
- username = self._wl._get_username()
132
+ username = self._wandb_setup._get_username()
182
133
 
183
134
  if username:
135
+ host_str = (
136
+ f" to {click.style(self._settings.base_url, fg='green')}"
137
+ if self._settings.base_url
138
+ else ""
139
+ )
140
+
184
141
  # check to see if we got an entity from the setup call or from the user
185
- entity = self._entity or self._wl._get_entity()
142
+ entity = self._settings.entity or self._wandb_setup._get_entity()
186
143
 
187
144
  entity_str = ""
188
145
  # check if entity exist, valid (is part of a certain team) and different from the username
189
- if entity and entity in self._wl._get_teams() and entity != username:
146
+ if (
147
+ entity
148
+ and entity in self._wandb_setup._get_teams()
149
+ and entity != username
150
+ ):
190
151
  entity_str = f" ({click.style(entity, fg='yellow')})"
191
152
 
192
- login_state_str = f"Currently logged in as: {click.style(username, fg='yellow')}{entity_str}"
153
+ login_state_str = f"Currently logged in as: {click.style(username, fg='yellow')}{entity_str}{host_str}"
193
154
  else:
194
155
  login_state_str = "W&B API key is configured"
195
156
 
@@ -210,9 +171,8 @@ class _WandbLogin:
210
171
  "WANDB_API_KEY environment variable, or running "
211
172
  "`wandb login` from the command line."
212
173
  )
213
- apikey.write_key(self._settings, key)
214
- self.update_session(key)
215
- self._key = key
174
+ if key:
175
+ apikey.write_key(self._settings, key)
216
176
 
217
177
  def update_session(
218
178
  self,
@@ -230,11 +190,11 @@ class _WandbLogin:
230
190
  login_settings = dict(mode="disabled")
231
191
  elif key:
232
192
  login_settings = dict(api_key=key)
233
- self._wl._settings.update_from_dict(login_settings)
193
+ self._wandb_setup.settings.update_from_dict(login_settings)
234
194
  # Whenever the key changes, make sure to pull in user settings
235
195
  # from server.
236
- if not self._wl.settings._offline:
237
- self._wl._update_user_settings()
196
+ if not self._wandb_setup.settings._offline:
197
+ self._wandb_setup._update_user_settings()
238
198
 
239
199
  def _prompt_api_key(self) -> Tuple[Optional[str], ApiKeyStatus]:
240
200
  api = Api(self._settings)
@@ -259,7 +219,7 @@ class _WandbLogin:
259
219
  return None, ApiKeyStatus.OFFLINE
260
220
  return key, ApiKeyStatus.VALID
261
221
 
262
- def prompt_api_key(self) -> None:
222
+ def prompt_api_key(self) -> Tuple[Optional[str], ApiKeyStatus]:
263
223
  """Updates the global API key by prompting the user."""
264
224
  key, status = self._prompt_api_key()
265
225
  if status == ApiKeyStatus.NOTTY:
@@ -270,8 +230,24 @@ class _WandbLogin:
270
230
  )
271
231
  raise UsageError("api_key not configured (no-tty). call " + directive)
272
232
 
273
- self.update_session(key, status=status)
274
- self._key = key
233
+ return key, status
234
+
235
+ def _verify_login(self, key: str) -> None:
236
+ api = InternalApi(api_key=key)
237
+
238
+ try:
239
+ is_api_key_valid = api.validate_api_key()
240
+
241
+ if not is_api_key_valid:
242
+ raise AuthenticationError(
243
+ "API key verification failed. Make sure your API key is valid."
244
+ )
245
+ except ConnectionError:
246
+ raise AuthenticationError(
247
+ "Unable to connect to server to verify API token."
248
+ )
249
+ except Exception:
250
+ raise AuthenticationError("An error occurred while verifying the API key.")
275
251
 
276
252
 
277
253
  def _login(
@@ -282,38 +258,29 @@ def _login(
282
258
  host: Optional[str] = None,
283
259
  force: Optional[bool] = None,
284
260
  timeout: Optional[int] = None,
285
- _backend=None,
261
+ verify: bool = False,
286
262
  _silent: Optional[bool] = None,
287
263
  _disable_warning: Optional[bool] = None,
288
- _entity: Optional[str] = None,
289
- ):
264
+ ) -> bool:
290
265
  if wandb.run is not None:
291
266
  if not _disable_warning:
292
267
  wandb.termwarn("Calling wandb.login() after wandb.init() has no effect.")
293
268
  return True
294
269
 
295
- wlogin = _WandbLogin()
296
-
297
- if _backend:
298
- wlogin.set_backend(_backend)
299
-
300
- if _silent:
301
- wlogin.set_silent(_silent)
302
-
303
- if _entity:
304
- wlogin.set_entity(_entity)
305
-
306
- # configure login object
307
- wlogin.setup(
270
+ wlogin = _WandbLogin(
308
271
  anonymous=anonymous,
272
+ force=force,
273
+ host=host,
309
274
  key=key,
310
275
  relogin=relogin,
311
- host=host,
312
- force=force,
313
276
  timeout=timeout,
314
277
  )
315
278
 
316
- if wlogin._settings._offline:
279
+ if wlogin._settings._noop:
280
+ return True
281
+
282
+ if wlogin._settings._offline and not wlogin._settings.x_cli_only_mode:
283
+ wandb.termwarn("Unable to verify login in offline mode.")
317
284
  return False
318
285
  elif wandb.util._is_kaggle() and not wandb.util._has_internet():
319
286
  wandb.termerror(
@@ -321,19 +288,28 @@ def _login(
321
288
  )
322
289
  return False
323
290
 
324
- if wlogin.should_use_identity_token():
291
+ if wlogin._settings.identity_token_file:
325
292
  return True
326
293
 
327
- # perform a login
328
- logged_in = wlogin.login()
294
+ key_is_pre_configured = False
295
+ key_status = None
296
+ if key is None:
297
+ # Check if key is already set in the settings, or configured in the users .netrc file.
298
+ key = apikey.api_key(settings=wlogin._settings)
299
+ if key and not relogin:
300
+ key_is_pre_configured = True
301
+ else:
302
+ key, key_status = wlogin.prompt_api_key()
303
+
304
+ if verify:
305
+ wlogin._verify_login(key)
329
306
 
330
- if key:
307
+ if not key_is_pre_configured:
331
308
  wlogin.configure_api_key(key)
309
+ wlogin.update_session(key, status=key_status)
310
+ wlogin._update_global_anonymous_setting()
332
311
 
333
- if logged_in:
334
- return logged_in
335
-
336
- if not key:
337
- wlogin.prompt_api_key()
312
+ if key and not _silent:
313
+ wlogin._print_logged_in_message()
338
314
 
339
- return wlogin._key or False
315
+ return key is not None
@@ -95,6 +95,7 @@ class GpuNvidiaInfo(BaseModel, validate_assignment=True):
95
95
  memory_total: int | None = None
96
96
  cuda_cores: int | None = None
97
97
  architecture: str | None = None
98
+ uuid: str | None = None
98
99
 
99
100
  def to_proto(self) -> wandb_internal_pb2.GpuNvidiaInfo:
100
101
  return wandb_internal_pb2.GpuNvidiaInfo(
@@ -102,6 +103,7 @@ class GpuNvidiaInfo(BaseModel, validate_assignment=True):
102
103
  memory_total=self.memory_total or 0,
103
104
  cuda_cores=self.cuda_cores or 0,
104
105
  architecture=self.architecture or "",
106
+ uuid=self.uuid or "",
105
107
  )
106
108
 
107
109
  @classmethod
@@ -111,6 +113,7 @@ class GpuNvidiaInfo(BaseModel, validate_assignment=True):
111
113
  memory_total=proto.memory_total,
112
114
  cuda_cores=proto.cuda_cores,
113
115
  architecture=proto.architecture,
116
+ uuid=proto.uuid,
114
117
  )
115
118
 
116
119
 
@@ -234,37 +237,63 @@ class Metadata(BaseModel, validate_assignment=True):
234
237
  NOTE: Definitions must be kept in sync with wandb_internal.proto::MetadataRequest.
235
238
 
236
239
  Attributes:
237
- os (str, optional): Operating system.
238
- python (str, optional): Python version.
239
- heartbeat_at (datetime, optional): Timestamp of last heartbeat.
240
- started_at (datetime, optional): Timestamp of run start.
241
- docker (str, optional): Docker image.
242
- cuda (str, optional): CUDA version.
243
- args (List[str]): Command-line arguments.
244
- state (str, optional): Run state.
245
- program (str, optional): Program name.
246
- code_path (str, optional): Path to code.
247
- git (GitRepoRecord, optional): Git repository information.
248
- email (str, optional): Email address.
249
- root (str, optional): Root directory.
250
- host (str, optional): Host name.
251
- username (str, optional): Username.
252
- executable (str, optional): Python executable path.
253
- code_path_local (str, optional): Local code path.
254
- colab (str, optional): Colab URL.
255
- cpu_count (int, optional): CPU count.
256
- cpu_count_logical (int, optional): Logical CPU count.
257
- gpu_type (str, optional): GPU type.
258
- disk (Dict[str, DiskInfo]): Disk information.
259
- memory (MemoryInfo, optional): Memory information.
260
- cpu (CpuInfo, optional): CPU information.
261
- apple (AppleInfo, optional): Apple silicon information.
262
- gpu_nvidia (List[GpuNvidiaInfo]): NVIDIA GPU information.
263
- gpu_amd (List[GpuAmdInfo]): AMD GPU information.
264
- slurm (Dict[str, str]): Slurm environment information.
265
- cuda_version (str, optional): CUDA version.
266
- trainium (TrainiumInfo, optional): Trainium information.
267
- tpu (TPUInfo, optional): TPU information.
240
+ os: Operating system.
241
+ python: Python version.
242
+ heartbeat_at: Timestamp of last heartbeat.
243
+ started_at: Timestamp of run start.
244
+ docker: Docker image.
245
+ cuda: CUDA version.
246
+ args: Command-line arguments.
247
+ state: Run state.
248
+ program: Program name.
249
+ code_path: Path to code.
250
+ git: Git repository information.
251
+ email: Email address.
252
+ root: Root directory.
253
+ host: Host name.
254
+ username: Username.
255
+ executable: Python executable path.
256
+ code_path_local: Local code path.
257
+ colab: Colab URL.
258
+ cpu_count: CPU count.
259
+ cpu_count_logical: Logical CPU count.
260
+ gpu_type: GPU type.
261
+ disk: Disk information.
262
+ memory: Memory information.
263
+ cpu: CPU information.
264
+ apple: Apple silicon information.
265
+ gpu_nvidia: NVIDIA GPU information.
266
+ gpu_amd: AMD GPU information.
267
+ slurm: Slurm environment information.
268
+ cuda_version: CUDA version.
269
+ trainium: Trainium information.
270
+ tpu: TPU information.
271
+
272
+ Examples:
273
+ Update Run metadata:
274
+
275
+ ```python
276
+ with wandb.init(settings=settings) as run:
277
+ run._metadata.gpu_nvidia = [
278
+ {
279
+ "name": "Tesla T4",
280
+ "memory_total": "16106127360",
281
+ "cuda_cores": 2560,
282
+ "architecture": "Turing",
283
+ },
284
+ ...,
285
+ ]
286
+
287
+ run._metadata.gpu_type = "Tesla T4"
288
+ run._metadata.gpu_count = 42
289
+
290
+ run._metadata.tpu = {
291
+ "name": "v6e",
292
+ "hbm_gib": 32,
293
+ "devices_per_chip": 1,
294
+ "count": 1337,
295
+ }
296
+ ```
268
297
  """
269
298
 
270
299
  # TODO: Pydantic configuration.