wandb 0.20.2rc20250616__py3-none-win32.whl → 0.21.0__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 (72) hide show
  1. wandb/__init__.py +1 -1
  2. wandb/__init__.pyi +24 -23
  3. wandb/apis/internal.py +3 -0
  4. wandb/apis/paginator.py +17 -4
  5. wandb/apis/public/api.py +83 -2
  6. wandb/apis/public/artifacts.py +10 -8
  7. wandb/apis/public/files.py +5 -5
  8. wandb/apis/public/projects.py +44 -3
  9. wandb/apis/public/reports.py +64 -8
  10. wandb/apis/public/runs.py +16 -23
  11. wandb/automations/__init__.py +10 -10
  12. wandb/automations/_filters/run_metrics.py +0 -2
  13. wandb/automations/_utils.py +0 -2
  14. wandb/automations/actions.py +0 -2
  15. wandb/automations/automations.py +0 -2
  16. wandb/automations/events.py +0 -2
  17. wandb/bin/gpu_stats.exe +0 -0
  18. wandb/bin/wandb-core +0 -0
  19. wandb/integration/catboost/catboost.py +6 -2
  20. wandb/integration/kfp/kfp_patch.py +3 -1
  21. wandb/integration/sb3/sb3.py +3 -3
  22. wandb/integration/ultralytics/callback.py +6 -2
  23. wandb/plot/__init__.py +2 -0
  24. wandb/plot/bar.py +30 -29
  25. wandb/plot/confusion_matrix.py +75 -71
  26. wandb/plot/histogram.py +26 -25
  27. wandb/plot/line.py +33 -32
  28. wandb/plot/line_series.py +100 -103
  29. wandb/plot/pr_curve.py +33 -32
  30. wandb/plot/roc_curve.py +38 -38
  31. wandb/plot/scatter.py +27 -27
  32. wandb/proto/v3/wandb_internal_pb2.py +366 -385
  33. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  34. wandb/proto/v4/wandb_internal_pb2.py +352 -356
  35. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  36. wandb/proto/v5/wandb_internal_pb2.py +352 -356
  37. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  38. wandb/proto/v6/wandb_internal_pb2.py +352 -356
  39. wandb/proto/v6/wandb_settings_pb2.py +2 -2
  40. wandb/sdk/artifacts/_generated/__init__.py +12 -1
  41. wandb/sdk/artifacts/_generated/input_types.py +20 -2
  42. wandb/sdk/artifacts/_generated/link_artifact.py +21 -0
  43. wandb/sdk/artifacts/_generated/operations.py +9 -0
  44. wandb/sdk/artifacts/_validators.py +40 -2
  45. wandb/sdk/artifacts/artifact.py +163 -21
  46. wandb/sdk/data_types/base_types/media.py +9 -7
  47. wandb/sdk/data_types/base_types/wb_value.py +6 -6
  48. wandb/sdk/data_types/saved_model.py +3 -3
  49. wandb/sdk/data_types/table.py +41 -41
  50. wandb/sdk/data_types/trace_tree.py +12 -12
  51. wandb/sdk/interface/interface.py +8 -19
  52. wandb/sdk/interface/interface_shared.py +7 -16
  53. wandb/sdk/internal/datastore.py +18 -18
  54. wandb/sdk/internal/handler.py +3 -5
  55. wandb/sdk/internal/internal_api.py +54 -0
  56. wandb/sdk/internal/sender.py +23 -3
  57. wandb/sdk/internal/sender_config.py +9 -0
  58. wandb/sdk/launch/_project_spec.py +3 -3
  59. wandb/sdk/launch/agent/agent.py +3 -3
  60. wandb/sdk/launch/agent/job_status_tracker.py +3 -1
  61. wandb/sdk/launch/utils.py +3 -3
  62. wandb/sdk/lib/console_capture.py +66 -19
  63. wandb/sdk/wandb_init.py +1 -2
  64. wandb/sdk/wandb_require.py +0 -1
  65. wandb/sdk/wandb_run.py +23 -113
  66. wandb/sdk/wandb_settings.py +234 -72
  67. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/METADATA +1 -1
  68. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/RECORD +71 -71
  69. wandb/sdk/wandb_metadata.py +0 -623
  70. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/WHEEL +0 -0
  71. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/entry_points.txt +0 -0
  72. {wandb-0.20.2rc20250616.dist-info → wandb-0.21.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,623 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from contextlib import contextmanager
4
- from datetime import datetime, timezone
5
-
6
- # For backward compatibility with pydantic v1
7
- from typing import Any, Callable, Dict, List, Optional
8
-
9
- from google.protobuf.timestamp_pb2 import Timestamp
10
- from pydantic import BaseModel, ConfigDict, Field
11
- from typing_extensions import Self
12
-
13
- from wandb import termwarn
14
- from wandb._pydantic import IS_PYDANTIC_V2
15
- from wandb.proto import wandb_internal_pb2
16
-
17
- if IS_PYDANTIC_V2:
18
- from pydantic import model_validator
19
-
20
-
21
- class DiskInfo(BaseModel, validate_assignment=True):
22
- total: Optional[int] = None
23
- used: Optional[int] = None
24
-
25
- def to_proto(self) -> wandb_internal_pb2.DiskInfo:
26
- return wandb_internal_pb2.DiskInfo(
27
- total=self.total or 0,
28
- used=self.used or 0,
29
- )
30
-
31
- @classmethod
32
- def from_proto(cls, proto: wandb_internal_pb2.DiskInfo) -> DiskInfo:
33
- return cls(total=proto.total, used=proto.used)
34
-
35
-
36
- class MemoryInfo(BaseModel, validate_assignment=True):
37
- total: Optional[int] = None
38
-
39
- def to_proto(self) -> wandb_internal_pb2.MemoryInfo:
40
- return wandb_internal_pb2.MemoryInfo(total=self.total or 0)
41
-
42
- @classmethod
43
- def from_proto(cls, proto: wandb_internal_pb2.MemoryInfo) -> MemoryInfo:
44
- return cls(total=proto.total)
45
-
46
-
47
- class CpuInfo(BaseModel, validate_assignment=True):
48
- count: Optional[int] = None
49
- count_logical: Optional[int] = None
50
-
51
- def to_proto(self) -> wandb_internal_pb2.CpuInfo:
52
- return wandb_internal_pb2.CpuInfo(
53
- count=self.count or 0,
54
- count_logical=self.count_logical or 0,
55
- )
56
-
57
- @classmethod
58
- def from_proto(cls, proto: wandb_internal_pb2.CpuInfo) -> CpuInfo:
59
- return cls(count=proto.count, count_logical=proto.count_logical)
60
-
61
-
62
- class AppleInfo(BaseModel, validate_assignment=True):
63
- name: Optional[str] = None
64
- ecpu_cores: Optional[int] = None
65
- pcpu_cores: Optional[int] = None
66
- gpu_cores: Optional[int] = None
67
- memory_gb: Optional[int] = None
68
- swap_total_bytes: Optional[int] = None
69
- ram_total_bytes: Optional[int] = None
70
-
71
- def to_proto(self) -> wandb_internal_pb2.AppleInfo:
72
- return wandb_internal_pb2.AppleInfo(
73
- name=self.name or "",
74
- ecpu_cores=self.ecpu_cores or 0,
75
- pcpu_cores=self.pcpu_cores or 0,
76
- gpu_cores=self.gpu_cores or 0,
77
- memory_gb=self.memory_gb or 0,
78
- swap_total_bytes=self.swap_total_bytes or 0,
79
- ram_total_bytes=self.ram_total_bytes or 0,
80
- )
81
-
82
- @classmethod
83
- def from_proto(cls, proto: wandb_internal_pb2.AppleInfo) -> AppleInfo:
84
- return cls(
85
- name=proto.name,
86
- ecpu_cores=proto.ecpu_cores,
87
- pcpu_cores=proto.pcpu_cores,
88
- gpu_cores=proto.gpu_cores,
89
- memory_gb=proto.memory_gb,
90
- swap_total_bytes=proto.swap_total_bytes,
91
- ram_total_bytes=proto.ram_total_bytes,
92
- )
93
-
94
-
95
- class GpuNvidiaInfo(BaseModel, validate_assignment=True):
96
- name: Optional[str] = None
97
- memory_total: Optional[int] = None
98
- cuda_cores: Optional[int] = None
99
- architecture: Optional[str] = None
100
- uuid: Optional[str] = None
101
-
102
- def to_proto(self) -> wandb_internal_pb2.GpuNvidiaInfo:
103
- return wandb_internal_pb2.GpuNvidiaInfo(
104
- name=self.name or "",
105
- memory_total=self.memory_total or 0,
106
- cuda_cores=self.cuda_cores or 0,
107
- architecture=self.architecture or "",
108
- uuid=self.uuid or "",
109
- )
110
-
111
- @classmethod
112
- def from_proto(cls, proto: wandb_internal_pb2.GpuNvidiaInfo) -> GpuNvidiaInfo:
113
- return cls(
114
- name=proto.name,
115
- memory_total=proto.memory_total,
116
- cuda_cores=proto.cuda_cores,
117
- architecture=proto.architecture,
118
- uuid=proto.uuid,
119
- )
120
-
121
-
122
- class GpuAmdInfo(BaseModel, validate_assignment=True):
123
- id: Optional[str] = None
124
- unique_id: Optional[str] = None
125
- vbios_version: Optional[str] = None
126
- performance_level: Optional[str] = None
127
- gpu_overdrive: Optional[str] = None
128
- gpu_memory_overdrive: Optional[str] = None
129
- max_power: Optional[str] = None
130
- series: Optional[str] = None
131
- model: Optional[str] = None
132
- vendor: Optional[str] = None
133
- sku: Optional[str] = None
134
- sclk_range: Optional[str] = None
135
- mclk_range: Optional[str] = None
136
-
137
- def to_proto(self) -> wandb_internal_pb2.GpuAmdInfo:
138
- return wandb_internal_pb2.GpuAmdInfo(
139
- id=self.id or "",
140
- unique_id=self.unique_id or "",
141
- vbios_version=self.vbios_version or "",
142
- performance_level=self.performance_level or "",
143
- gpu_overdrive=self.gpu_overdrive or "",
144
- gpu_memory_overdrive=self.gpu_memory_overdrive or "",
145
- max_power=self.max_power or "",
146
- series=self.series or "",
147
- model=self.model or "",
148
- vendor=self.vendor or "",
149
- sku=self.sku or "",
150
- sclk_range=self.sclk_range or "",
151
- mclk_range=self.mclk_range or "",
152
- )
153
-
154
- @classmethod
155
- def from_proto(cls, proto: wandb_internal_pb2.GpuAmdInfo) -> GpuAmdInfo:
156
- return cls(
157
- id=proto.id,
158
- unique_id=proto.unique_id,
159
- vbios_version=proto.vbios_version,
160
- performance_level=proto.performance_level,
161
- gpu_overdrive=proto.gpu_overdrive,
162
- gpu_memory_overdrive=proto.gpu_memory_overdrive,
163
- max_power=proto.max_power,
164
- series=proto.series,
165
- model=proto.model,
166
- vendor=proto.vendor,
167
- sku=proto.sku,
168
- sclk_range=proto.sclk_range,
169
- mclk_range=proto.mclk_range,
170
- )
171
-
172
-
173
- class TrainiumInfo(BaseModel, validate_assignment=True):
174
- name: Optional[str] = None
175
- vendor: Optional[str] = None
176
- neuron_device_count: Optional[int] = None
177
- neuroncore_per_device_count: Optional[int] = None
178
-
179
- def to_proto(self) -> wandb_internal_pb2.TrainiumInfo:
180
- return wandb_internal_pb2.TrainiumInfo(
181
- name=self.name or "",
182
- vendor=self.vendor or "",
183
- neuron_device_count=self.neuron_device_count or 0,
184
- neuroncore_per_device_count=self.neuroncore_per_device_count or 0,
185
- )
186
-
187
- @classmethod
188
- def from_proto(cls, proto: wandb_internal_pb2.TrainiumInfo) -> TrainiumInfo:
189
- return cls(
190
- name=proto.name,
191
- vendor=proto.vendor,
192
- neuron_device_count=proto.neuron_device_count,
193
- neuroncore_per_device_count=proto.neuroncore_per_device_count,
194
- )
195
-
196
-
197
- class TPUInfo(BaseModel, validate_assignment=True):
198
- name: Optional[str] = None
199
- hbm_gib: Optional[int] = None
200
- devices_per_chip: Optional[int] = None
201
- count: Optional[int] = None
202
-
203
- def to_proto(self) -> wandb_internal_pb2.TPUInfo:
204
- return wandb_internal_pb2.TPUInfo(
205
- name=self.name or "",
206
- hbm_gib=self.hbm_gib or 0,
207
- devices_per_chip=self.devices_per_chip or 0,
208
- count=self.count or 0,
209
- )
210
-
211
- @classmethod
212
- def from_proto(cls, proto: wandb_internal_pb2.TPUInfo) -> TPUInfo:
213
- return cls(
214
- name=proto.name,
215
- hbm_gib=proto.hbm_gib,
216
- devices_per_chip=proto.devices_per_chip,
217
- count=proto.count,
218
- )
219
-
220
-
221
- class GitRepoRecord(BaseModel, validate_assignment=True):
222
- remote_url: Optional[str] = Field(None, alias="remote")
223
- commit: Optional[str] = None
224
-
225
- def to_proto(self) -> wandb_internal_pb2.GitRepoRecord:
226
- return wandb_internal_pb2.GitRepoRecord(
227
- remote_url=self.remote_url or "",
228
- commit=self.commit or "",
229
- )
230
-
231
- @classmethod
232
- def from_proto(cls, proto: wandb_internal_pb2.GitRepoRecord) -> GitRepoRecord:
233
- return cls(remote=proto.remote_url, commit=proto.commit)
234
-
235
-
236
- class Metadata(BaseModel, validate_assignment=True):
237
- """Metadata about the run environment.
238
-
239
- NOTE: Definitions must be kept in sync with wandb_internal.proto::MetadataRequest.
240
-
241
- Examples:
242
- Update Run metadata:
243
-
244
- ```python
245
- with wandb.init(settings=settings) as run:
246
- run._metadata.gpu_nvidia = [
247
- {
248
- "name": "Tesla T4",
249
- "memory_total": "16106127360",
250
- "cuda_cores": 2560,
251
- "architecture": "Turing",
252
- },
253
- ...,
254
- ]
255
-
256
- run._metadata.gpu_type = "Tesla T4"
257
- run._metadata.gpu_count = 42
258
-
259
- run._metadata.tpu = {
260
- "name": "v6e",
261
- "hbm_gib": 32,
262
- "devices_per_chip": 1,
263
- "count": 1337,
264
- }
265
- ```
266
- """
267
-
268
- model_config = ConfigDict(
269
- extra="ignore", # ignore extra fields
270
- validate_default=True, # validate default values
271
- use_attribute_docstrings=True, # for field descriptions
272
- revalidate_instances="always",
273
- )
274
-
275
- os: Optional[str] = None
276
- """Operating system."""
277
-
278
- python: Optional[str] = None
279
- """Python version."""
280
-
281
- heartbeat_at: Optional[datetime] = Field(default=None, alias="heartbeatAt")
282
- """Timestamp of last heartbeat."""
283
-
284
- started_at: Optional[datetime] = Field(default=None, alias="startedAt")
285
- """Timestamp of run start."""
286
-
287
- docker: Optional[str] = None
288
- """Docker image."""
289
-
290
- cuda: Optional[str] = None
291
- """CUDA version."""
292
-
293
- args: List[str] = Field(default_factory=list)
294
- """Command-line arguments."""
295
-
296
- state: Optional[str] = None
297
- """Run state."""
298
-
299
- program: Optional[str] = None
300
- """Program name."""
301
-
302
- code_path: Optional[str] = Field(default=None, alias="codePath")
303
- """Path to code."""
304
-
305
- git: Optional[GitRepoRecord] = None
306
- """Git repository information."""
307
-
308
- email: Optional[str] = None
309
- """Email address."""
310
-
311
- root: Optional[str] = None
312
- """Root directory."""
313
-
314
- host: Optional[str] = None
315
- """Host name."""
316
-
317
- username: Optional[str] = None
318
- """Username."""
319
-
320
- executable: Optional[str] = None
321
- """Python executable path."""
322
-
323
- code_path_local: Optional[str] = Field(default=None, alias="codePathLocal")
324
- """Local code path."""
325
-
326
- colab: Optional[str] = None
327
- """Colab URL."""
328
-
329
- cpu_count: Optional[int] = Field(default=None, alias="cpuCount")
330
- """CPU count."""
331
-
332
- cpu_count_logical: Optional[int] = Field(default=None, alias="cpuCountLogical")
333
- """Logical CPU count."""
334
-
335
- gpu_type: Optional[str] = Field(default=None, alias="gpuType")
336
- """GPU type."""
337
-
338
- gpu_count: Optional[int] = Field(default=None, alias="gpuCount")
339
- """GPU count."""
340
-
341
- disk: Dict[str, DiskInfo] = Field(default_factory=dict)
342
- """Disk information."""
343
-
344
- memory: Optional[MemoryInfo] = None
345
- """Memory information."""
346
-
347
- cpu: Optional[CpuInfo] = None
348
- """CPU information."""
349
-
350
- apple: Optional[AppleInfo] = None
351
- """Apple silicon information."""
352
-
353
- gpu_nvidia: List[GpuNvidiaInfo] = Field(default_factory=list, alias="gpuNvidia")
354
- """NVIDIA GPU information."""
355
-
356
- gpu_amd: List[GpuAmdInfo] = Field(default_factory=list, alias="gpuAmd")
357
- """AMD GPU information."""
358
-
359
- slurm: Dict[str, str] = Field(default_factory=dict)
360
- """Slurm environment information."""
361
-
362
- cuda_version: Optional[str] = Field(default=None, alias="cudaVersion")
363
- """CUDA version."""
364
-
365
- trainium: Optional[TrainiumInfo] = None
366
- """Trainium information."""
367
-
368
- tpu: Optional[TPUInfo] = None
369
- """TPU information."""
370
-
371
- def __init__(self, **data):
372
- super().__init__(**data)
373
-
374
- if not IS_PYDANTIC_V2:
375
- termwarn(
376
- "Metadata is read-only when using pydantic v1.",
377
- repeat=False,
378
- )
379
- return
380
-
381
- # Callback for post-update. This is used in the Run object to trigger
382
- # a metadata update after the object is modified.
383
- self._post_update_callback: Optional[Callable] = None # type: ignore
384
-
385
- def _set_callback(self, callback: Callable) -> None:
386
- if not IS_PYDANTIC_V2:
387
- return
388
- self._post_update_callback = callback
389
-
390
- @contextmanager
391
- def disable_callback(self):
392
- """Temporarily disable callback."""
393
- if not IS_PYDANTIC_V2:
394
- yield
395
- else:
396
- original_callback = self._post_update_callback
397
- self._post_update_callback = None
398
- try:
399
- yield
400
- finally:
401
- self._post_update_callback = original_callback
402
-
403
- if IS_PYDANTIC_V2:
404
-
405
- @model_validator(mode="after")
406
- def _callback(self) -> Self:
407
- if getattr(self, "_post_update_callback", None) is not None:
408
- self._post_update_callback(self.to_proto()) # type: ignore
409
-
410
- return self
411
-
412
- @classmethod
413
- def _datetime_to_timestamp(cls, dt: datetime | None) -> Timestamp | None:
414
- """Convert a datetime to a protobuf Timestamp."""
415
- if dt is None:
416
- return None
417
- ts = Timestamp()
418
- # Convert to UTC if the datetime has a timezone
419
- if dt.tzinfo is not None:
420
- dt = dt.astimezone(timezone.utc)
421
- # Convert to seconds and nanos
422
- ts.seconds = int(dt.timestamp())
423
- ts.nanos = dt.microsecond * 1000
424
- return ts
425
-
426
- @classmethod
427
- def _timestamp_to_datetime(cls, ts: Timestamp | None) -> datetime | None:
428
- """Convert a protobuf Timestamp to a datetime."""
429
- if ts is None:
430
- return None
431
- # Create UTC datetime from seconds and add microseconds
432
- dt = datetime.fromtimestamp(ts.seconds, tz=timezone.utc)
433
- return dt.replace(microsecond=ts.nanos // 1000)
434
-
435
- def to_proto(self) -> wandb_internal_pb2.MetadataRequest: # noqa: C901
436
- """Convert the metadata to a protobuf message."""
437
- proto = wandb_internal_pb2.MetadataRequest()
438
-
439
- # A flag to indicate that the metadata has been modified by the user.
440
- # Updates to the metadata object originating from the user take precedence
441
- # over automatic updates.
442
- proto._user_modified = True
443
-
444
- # Handle all scalar fields
445
- if self.os is not None:
446
- proto.os = self.os
447
- if self.python is not None:
448
- proto.python = self.python
449
- if self.docker is not None:
450
- proto.docker = self.docker
451
- if self.cuda is not None:
452
- proto.cuda = self.cuda
453
- if self.state is not None:
454
- proto.state = self.state
455
- if self.program is not None:
456
- proto.program = self.program
457
- if self.code_path is not None:
458
- proto.code_path = self.code_path
459
- if self.email is not None:
460
- proto.email = self.email
461
- if self.root is not None:
462
- proto.root = self.root
463
- if self.host is not None:
464
- proto.host = self.host
465
- if self.username is not None:
466
- proto.username = self.username
467
- if self.executable is not None:
468
- proto.executable = self.executable
469
- if self.code_path_local is not None:
470
- proto.code_path_local = self.code_path_local
471
- if self.colab is not None:
472
- proto.colab = self.colab
473
- if self.cpu_count is not None:
474
- proto.cpu_count = self.cpu_count
475
- if self.cpu_count_logical is not None:
476
- proto.cpu_count_logical = self.cpu_count_logical
477
- if self.gpu_type is not None:
478
- proto.gpu_type = self.gpu_type
479
- if self.gpu_count is not None:
480
- proto.gpu_count = self.gpu_count
481
- if self.cuda_version is not None:
482
- proto.cuda_version = self.cuda_version
483
-
484
- # Handle timestamp fields
485
- if self.heartbeat_at is not None:
486
- proto.heartbeat_at.CopyFrom(self._datetime_to_timestamp(self.heartbeat_at))
487
- if self.started_at is not None:
488
- proto.started_at.CopyFrom(self._datetime_to_timestamp(self.started_at))
489
-
490
- # Handle nested message fields
491
- if self.git is not None:
492
- proto.git.CopyFrom(self.git.to_proto())
493
- if self.memory is not None:
494
- proto.memory.CopyFrom(self.memory.to_proto())
495
- if self.cpu is not None:
496
- proto.cpu.CopyFrom(self.cpu.to_proto())
497
- if self.apple is not None:
498
- proto.apple.CopyFrom(self.apple.to_proto())
499
- if self.trainium is not None:
500
- proto.trainium.CopyFrom(self.trainium.to_proto())
501
- if self.tpu is not None:
502
- proto.tpu.CopyFrom(self.tpu.to_proto())
503
-
504
- # Handle repeated fields
505
- if self.args:
506
- proto.args.extend(self.args)
507
- if self.gpu_nvidia:
508
- proto.gpu_nvidia.extend(gpu.to_proto() for gpu in self.gpu_nvidia)
509
- if self.gpu_amd:
510
- proto.gpu_amd.extend(gpu.to_proto() for gpu in self.gpu_amd)
511
-
512
- # Handle map fields
513
- if self.disk:
514
- for k, v in self.disk.items():
515
- proto.disk[k].CopyFrom(v.to_proto())
516
- if self.slurm:
517
- proto.slurm.update(self.slurm)
518
-
519
- return proto
520
-
521
- def update_from_proto( # noqa: C901
522
- self,
523
- proto: wandb_internal_pb2.MetadataRequest,
524
- skip_existing: bool = False,
525
- ):
526
- """Update the metadata from a protobuf message.
527
-
528
- Args:
529
- proto (wandb_internal_pb2.MetadataRequest): The protobuf message.
530
- skip_existing (bool, optional): Skip updating fields that are already set.
531
- """
532
- data: Dict[str, Any] = {}
533
-
534
- # Handle all scalar fields.
535
- if proto.os:
536
- data["os"] = proto.os
537
- if proto.python:
538
- data["python"] = proto.python
539
- if proto.docker:
540
- data["docker"] = proto.docker
541
- if proto.cuda:
542
- data["cuda"] = proto.cuda
543
- if proto.state:
544
- data["state"] = proto.state
545
- if proto.program:
546
- data["program"] = proto.program
547
- if proto.code_path:
548
- data["code_path"] = proto.code_path
549
- if proto.email:
550
- data["email"] = proto.email
551
- if proto.root:
552
- data["root"] = proto.root
553
- if proto.host:
554
- data["host"] = proto.host
555
- if proto.username:
556
- data["username"] = proto.username
557
- if proto.executable:
558
- data["executable"] = proto.executable
559
- if proto.code_path_local:
560
- data["code_path_local"] = proto.code_path_local
561
- if proto.colab:
562
- data["colab"] = proto.colab
563
- if proto.cpu_count:
564
- data["cpu_count"] = proto.cpu_count
565
- if proto.cpu_count_logical:
566
- data["cpu_count_logical"] = proto.cpu_count_logical
567
- if proto.gpu_type:
568
- data["gpu_type"] = proto.gpu_type
569
- if proto.gpu_count:
570
- data["gpu_count"] = proto.gpu_count
571
- if proto.cuda_version:
572
- data["cuda_version"] = proto.cuda_version
573
-
574
- # Handle timestamp fields (these are messages, so use HasField)
575
- if proto.HasField("heartbeat_at"):
576
- data["heartbeat_at"] = self._timestamp_to_datetime(proto.heartbeat_at)
577
- if proto.HasField("started_at"):
578
- data["started_at"] = self._timestamp_to_datetime(proto.started_at)
579
-
580
- # Handle nested message fields (these have presence)
581
- if proto.HasField("git"):
582
- data["git"] = GitRepoRecord.from_proto(proto.git)
583
- if proto.HasField("memory"):
584
- data["memory"] = MemoryInfo.from_proto(proto.memory)
585
- if proto.HasField("cpu"):
586
- data["cpu"] = CpuInfo.from_proto(proto.cpu)
587
- if proto.HasField("apple"):
588
- data["apple"] = AppleInfo.from_proto(proto.apple)
589
- if proto.HasField("trainium"):
590
- data["trainium"] = TrainiumInfo.from_proto(proto.trainium)
591
- if proto.HasField("tpu"):
592
- data["tpu"] = TPUInfo.from_proto(proto.tpu)
593
-
594
- # Handle repeated fields
595
- if len(proto.args) > 0:
596
- data["args"] = list(proto.args)
597
- else:
598
- data["args"] = []
599
- if len(proto.gpu_nvidia) > 0:
600
- data["gpu_nvidia"] = [
601
- GpuNvidiaInfo.from_proto(gpu) for gpu in proto.gpu_nvidia
602
- ]
603
- else:
604
- data["gpu_nvidia"] = []
605
- if len(proto.gpu_amd) > 0:
606
- data["gpu_amd"] = [GpuAmdInfo.from_proto(gpu) for gpu in proto.gpu_amd]
607
- else:
608
- data["gpu_amd"] = []
609
-
610
- # Handle map fields
611
- if len(proto.disk) > 0:
612
- data["disk"] = {k: DiskInfo.from_proto(v) for k, v in proto.disk.items()}
613
- else:
614
- data["disk"] = {}
615
- if len(proto.slurm) > 0:
616
- data["slurm"] = dict(proto.slurm)
617
- else:
618
- data["slurm"] = {}
619
-
620
- for k, v in data.items():
621
- if skip_existing and getattr(self, k) is not None:
622
- continue
623
- setattr(self, k, v)