wandb 0.16.3__py3-none-any.whl → 0.16.5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. wandb/__init__.py +2 -2
  2. wandb/agents/pyagent.py +1 -1
  3. wandb/apis/importers/__init__.py +1 -4
  4. wandb/apis/importers/internals/internal.py +386 -0
  5. wandb/apis/importers/internals/protocols.py +125 -0
  6. wandb/apis/importers/internals/util.py +78 -0
  7. wandb/apis/importers/mlflow.py +125 -88
  8. wandb/apis/importers/validation.py +108 -0
  9. wandb/apis/importers/wandb.py +1604 -0
  10. wandb/apis/public/api.py +7 -10
  11. wandb/apis/public/artifacts.py +38 -0
  12. wandb/apis/public/files.py +11 -2
  13. wandb/apis/reports/v2/__init__.py +0 -19
  14. wandb/apis/reports/v2/expr_parsing.py +0 -1
  15. wandb/apis/reports/v2/interface.py +15 -18
  16. wandb/apis/reports/v2/internal.py +12 -45
  17. wandb/cli/cli.py +52 -55
  18. wandb/integration/gym/__init__.py +2 -1
  19. wandb/integration/keras/callbacks/model_checkpoint.py +1 -1
  20. wandb/integration/keras/keras.py +6 -4
  21. wandb/integration/kfp/kfp_patch.py +2 -2
  22. wandb/integration/openai/fine_tuning.py +1 -2
  23. wandb/integration/ultralytics/callback.py +0 -1
  24. wandb/proto/v3/wandb_internal_pb2.py +332 -312
  25. wandb/proto/v3/wandb_settings_pb2.py +13 -3
  26. wandb/proto/v3/wandb_telemetry_pb2.py +10 -10
  27. wandb/proto/v4/wandb_internal_pb2.py +316 -312
  28. wandb/proto/v4/wandb_settings_pb2.py +5 -3
  29. wandb/proto/v4/wandb_telemetry_pb2.py +10 -10
  30. wandb/sdk/artifacts/artifact.py +75 -31
  31. wandb/sdk/artifacts/artifact_manifest.py +5 -2
  32. wandb/sdk/artifacts/artifact_manifest_entry.py +6 -1
  33. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +8 -2
  34. wandb/sdk/artifacts/artifact_saver.py +19 -47
  35. wandb/sdk/artifacts/storage_handler.py +2 -1
  36. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +22 -9
  37. wandb/sdk/artifacts/storage_policy.py +4 -1
  38. wandb/sdk/data_types/base_types/wb_value.py +1 -1
  39. wandb/sdk/data_types/image.py +2 -2
  40. wandb/sdk/interface/interface.py +49 -13
  41. wandb/sdk/interface/interface_shared.py +17 -11
  42. wandb/sdk/internal/file_stream.py +20 -1
  43. wandb/sdk/internal/handler.py +1 -4
  44. wandb/sdk/internal/internal_api.py +3 -1
  45. wandb/sdk/internal/job_builder.py +49 -19
  46. wandb/sdk/internal/profiler.py +1 -1
  47. wandb/sdk/internal/sender.py +96 -124
  48. wandb/sdk/internal/sender_config.py +197 -0
  49. wandb/sdk/internal/settings_static.py +9 -0
  50. wandb/sdk/internal/system/system_info.py +5 -3
  51. wandb/sdk/internal/update.py +1 -1
  52. wandb/sdk/launch/_launch.py +3 -3
  53. wandb/sdk/launch/_launch_add.py +28 -29
  54. wandb/sdk/launch/_project_spec.py +148 -136
  55. wandb/sdk/launch/agent/agent.py +3 -7
  56. wandb/sdk/launch/agent/config.py +0 -27
  57. wandb/sdk/launch/builder/build.py +54 -28
  58. wandb/sdk/launch/builder/docker_builder.py +4 -15
  59. wandb/sdk/launch/builder/kaniko_builder.py +72 -45
  60. wandb/sdk/launch/create_job.py +6 -40
  61. wandb/sdk/launch/loader.py +10 -0
  62. wandb/sdk/launch/registry/anon.py +29 -0
  63. wandb/sdk/launch/registry/local_registry.py +4 -1
  64. wandb/sdk/launch/runner/kubernetes_runner.py +20 -2
  65. wandb/sdk/launch/runner/local_container.py +15 -10
  66. wandb/sdk/launch/runner/sagemaker_runner.py +1 -1
  67. wandb/sdk/launch/sweeps/scheduler.py +11 -3
  68. wandb/sdk/launch/utils.py +14 -0
  69. wandb/sdk/lib/__init__.py +2 -5
  70. wandb/sdk/lib/_settings_toposort_generated.py +4 -1
  71. wandb/sdk/lib/apikey.py +0 -5
  72. wandb/sdk/lib/config_util.py +0 -31
  73. wandb/sdk/lib/filesystem.py +11 -1
  74. wandb/sdk/lib/run_moment.py +72 -0
  75. wandb/sdk/service/service.py +7 -2
  76. wandb/sdk/service/streams.py +1 -6
  77. wandb/sdk/verify/verify.py +2 -1
  78. wandb/sdk/wandb_init.py +12 -1
  79. wandb/sdk/wandb_login.py +43 -26
  80. wandb/sdk/wandb_run.py +164 -110
  81. wandb/sdk/wandb_settings.py +58 -16
  82. wandb/testing/relay.py +5 -6
  83. wandb/util.py +50 -7
  84. {wandb-0.16.3.dist-info → wandb-0.16.5.dist-info}/METADATA +8 -1
  85. {wandb-0.16.3.dist-info → wandb-0.16.5.dist-info}/RECORD +89 -82
  86. {wandb-0.16.3.dist-info → wandb-0.16.5.dist-info}/WHEEL +1 -1
  87. wandb/apis/importers/base.py +0 -400
  88. {wandb-0.16.3.dist-info → wandb-0.16.5.dist-info}/LICENSE +0 -0
  89. {wandb-0.16.3.dist-info → wandb-0.16.5.dist-info}/entry_points.txt +0 -0
  90. {wandb-0.16.3.dist-info → wandb-0.16.5.dist-info}/top_level.txt +0 -0
@@ -25,37 +25,6 @@ def dict_from_proto_list(obj_list):
25
25
  return d
26
26
 
27
27
 
28
- def update_from_proto(config_dict, config_proto):
29
- for item in config_proto.update:
30
- key_list = item.nested_key or (item.key,)
31
- assert key_list, "key or nested key must be set"
32
- target = config_dict
33
- # recurse down the dictionary structure:
34
- for prop in key_list[:-1]:
35
- if not target.get(prop):
36
- target[prop] = {}
37
- target = target[prop]
38
- # use the last element of the key to write the leaf:
39
- target[key_list[-1]] = json.loads(item.value_json)
40
- for item in config_proto.remove:
41
- key_list = item.nested_key or (item.key,)
42
- assert key_list, "key or nested key must be set"
43
- target = config_dict
44
- # recurse down the dictionary structure:
45
- for prop in key_list[:-1]:
46
- target = target[prop]
47
- # use the last element of the key to write the leaf:
48
- del target[key_list[-1]]
49
- # TODO(jhr): should we delete empty parents?
50
-
51
-
52
- def dict_add_value_dict(config_dict):
53
- d = dict()
54
- for k, v in config_dict.items():
55
- d[k] = dict(desc=None, value=v)
56
- return d
57
-
58
-
59
28
  def dict_strip_value_dict(config_dict):
60
29
  d = dict()
61
30
  for k, v in config_dict.items():
@@ -227,7 +227,17 @@ def safe_open(
227
227
 
228
228
 
229
229
  def safe_copy(source_path: StrPath, target_path: StrPath) -> StrPath:
230
- """Copy a file, ensuring any changes only apply atomically once finished."""
230
+ """Copy a file atomically.
231
+
232
+ Copying is not usually atomic, and on operating systems that allow multiple
233
+ writers to the same file, the result can get corrupted. If two writers copy
234
+ to the same file, the contents can become interleaved.
235
+
236
+ We mitigate the issue somewhat by copying to a temporary file first and
237
+ then renaming. Renaming is atomic: if process 1 renames file A to X and
238
+ process 2 renames file B to X, then X will either contain the contents
239
+ of A or the contents of B, not some mixture of both.
240
+ """
231
241
  # TODO (hugh): check that there is enough free space.
232
242
  output_path = Path(target_path).resolve()
233
243
  output_path.parent.mkdir(parents=True, exist_ok=True)
@@ -0,0 +1,72 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal, Union, cast
3
+ from urllib import parse
4
+
5
+ _STEP = Literal["_step"]
6
+
7
+
8
+ @dataclass
9
+ class RunMoment:
10
+ """A moment in a run."""
11
+
12
+ run: str # run name
13
+
14
+ # currently, the _step value to fork from. in future, this will be optional
15
+ value: Union[int, float]
16
+
17
+ # only step for now, in future this will be relaxed to be any metric
18
+ metric: _STEP = "_step"
19
+
20
+ def __post_init__(self):
21
+ if self.metric != "_step":
22
+ raise ValueError(
23
+ f"Only the metric '_step' is supported, got '{self.metric}'."
24
+ )
25
+ if not isinstance(self.value, (int, float)):
26
+ raise ValueError(
27
+ f"Only int or float values are supported, got '{self.value}'."
28
+ )
29
+ if not isinstance(self.run, str):
30
+ raise ValueError(f"Only string run names are supported, got '{self.run}'.")
31
+
32
+ @classmethod
33
+ def from_uri(cls, uri: str) -> "RunMoment":
34
+ parsable = "runmoment://" + uri
35
+ parse_err = ValueError(
36
+ f"Could not parse passed run moment string '{uri}', "
37
+ f"expected format '<run>?<metric>=<numeric_value>'. "
38
+ f"Currently, only the metric '_step' is supported. "
39
+ f"Example: 'ans3bsax?_step=123'."
40
+ )
41
+
42
+ try:
43
+ parsed = parse.urlparse(parsable)
44
+ except ValueError as e:
45
+ raise parse_err from e
46
+
47
+ if parsed.scheme != "runmoment":
48
+ raise parse_err
49
+
50
+ # extract run, metric, value from parsed
51
+ if not parsed.netloc:
52
+ raise parse_err
53
+
54
+ run = parsed.netloc
55
+
56
+ if parsed.path or parsed.params or parsed.fragment:
57
+ raise parse_err
58
+
59
+ query = parse.parse_qs(parsed.query)
60
+ if len(query) != 1:
61
+ raise parse_err
62
+
63
+ metric = list(query.keys())[0]
64
+ if metric != "_step":
65
+ raise parse_err
66
+ value: str = query[metric][0]
67
+ try:
68
+ num_value = int(value) if value.isdigit() else float(value)
69
+ except ValueError as e:
70
+ raise parse_err from e
71
+
72
+ return cls(run=run, metric=cast(_STEP, metric), value=num_value)
@@ -171,6 +171,12 @@ class _Service:
171
171
  service_args.extend([core_path])
172
172
  if not error_reporting_enabled():
173
173
  service_args.append("--no-observability")
174
+ if os.environ.get("WANDB_CORE_DEBUG", False):
175
+ service_args.append("--debug")
176
+ trace_filename = os.environ.get("_WANDB_TRACE")
177
+ if trace_filename is not None:
178
+ service_args.extend(["--trace", trace_filename])
179
+
174
180
  exec_cmd_list = []
175
181
  # TODO: remove this after the wandb-core GA release
176
182
  wandb_core = get_module("wandb_core")
@@ -180,14 +186,13 @@ class _Service:
180
186
  repeat=False,
181
187
  )
182
188
  else:
183
- service_args.extend(["wandb", "service"])
189
+ service_args.extend(["wandb", "service", "--debug"])
184
190
 
185
191
  service_args += [
186
192
  "--port-filename",
187
193
  fname,
188
194
  "--pid",
189
195
  pid,
190
- "--debug",
191
196
  ]
192
197
  service_args.append("--serve-sock")
193
198
 
@@ -5,6 +5,7 @@ StreamRecord: All the external state for the internal thread (queues, etc)
5
5
  StreamAction: Lightweight record for stream ops for thread safety
6
6
  StreamMux: Container for dictionary of stream threads per runid
7
7
  """
8
+
8
9
  import functools
9
10
  import multiprocessing
10
11
  import queue
@@ -327,7 +328,6 @@ class StreamMux:
327
328
  result = internal_messages_handle.wait(timeout=-1)
328
329
  assert result
329
330
  internal_messages_response = result.response.internal_messages_response
330
- job_info_handle = stream.interface.deliver_request_job_info()
331
331
 
332
332
  # wait for them, it's ok to do this serially but this can be improved
333
333
  result = poll_exit_handle.wait(timeout=-1)
@@ -346,17 +346,12 @@ class StreamMux:
346
346
  assert result
347
347
  final_summary = result.response.get_summary_response
348
348
 
349
- result = job_info_handle.wait(timeout=-1)
350
- assert result
351
- job_info = result.response.job_info_response
352
-
353
349
  Run._footer(
354
350
  sampled_history=sampled_history,
355
351
  final_summary=final_summary,
356
352
  poll_exit_response=poll_exit_response,
357
353
  server_info_response=server_info_response,
358
354
  internal_messages_response=internal_messages_response,
359
- job_info=job_info,
360
355
  settings=stream._settings, # type: ignore
361
356
  printer=printer,
362
357
  )
@@ -8,7 +8,6 @@ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
8
8
 
9
9
  import click
10
10
  import requests
11
- from pkg_resources import parse_version
12
11
  from wandb_gql import gql
13
12
 
14
13
  import wandb
@@ -469,6 +468,8 @@ def check_wandb_version(api: Api) -> None:
469
468
  min_cli_version = server_info.get("cliVersionInfo", {}).get(
470
469
  "min_cli_version", "0.0.1"
471
470
  )
471
+ from wandb.util import parse_version
472
+
472
473
  if parse_version(wandb.__version__) < parse_version(min_cli_version):
473
474
  fail_string = "wandb version out of date, please run pip install --upgrade wandb=={}".format(
474
475
  max_cli_version
wandb/sdk/wandb_init.py CHANGED
@@ -7,6 +7,7 @@ your evaluation script, and each step would be tracked as a run in W&B.
7
7
  For more on using `wandb.init()`, including code snippets, check out our
8
8
  [guide and FAQs](https://docs.wandb.ai/guides/track/launch).
9
9
  """
10
+
10
11
  import copy
11
12
  import json
12
13
  import logging
@@ -828,7 +829,7 @@ class _WandbInit:
828
829
  and self.settings.launch_config_path
829
830
  and os.path.exists(self.settings.launch_config_path)
830
831
  ):
831
- run._save(self.settings.launch_config_path)
832
+ run.save(self.settings.launch_config_path)
832
833
  # put artifacts in run config here
833
834
  # since doing so earlier will cause an error
834
835
  # as the run is not upserted
@@ -961,6 +962,7 @@ def init(
961
962
  monitor_gym: Optional[bool] = None,
962
963
  save_code: Optional[bool] = None,
963
964
  id: Optional[str] = None,
965
+ fork_from: Optional[str] = None,
964
966
  settings: Union[Settings, Dict[str, Any], None] = None,
965
967
  ) -> Union[Run, RunDisabled, None]:
966
968
  r"""Start a new run to track and log to W&B.
@@ -1122,6 +1124,10 @@ def init(
1122
1124
  for saving hyperparameters to compare across runs. The ID cannot
1123
1125
  contain the following special characters: `/\#?%:`.
1124
1126
  See [our guide to resuming runs](https://docs.wandb.com/guides/runs/resuming).
1127
+ fork_from: (str, optional) A string with the format <run_id>?_step=<step> describing
1128
+ a moment in a previous run to fork a new run from. Creates a new run that picks up
1129
+ logging history from the specified run at the specified moment. The target run must
1130
+ be in the current project.
1125
1131
 
1126
1132
  Examples:
1127
1133
  ### Set where the run is logged
@@ -1167,6 +1173,11 @@ def init(
1167
1173
  error_seen = None
1168
1174
  except_exit = None
1169
1175
  run: Optional[Union[Run, RunDisabled]] = None
1176
+
1177
+ # convert fork_from into a version that can be passed to settings
1178
+ if fork_from is not None and resume is not None:
1179
+ raise ValueError("Cannot specify both `fork_from` and `resume`")
1180
+
1170
1181
  try:
1171
1182
  wi = _WandbInit()
1172
1183
  wi.setup(kwargs)
wandb/sdk/wandb_login.py CHANGED
@@ -22,7 +22,7 @@ from wandb.old.settings import Settings as OldSettings
22
22
  from ..apis import InternalApi
23
23
  from .internal.internal_api import Api
24
24
  from .lib import apikey
25
- from .wandb_settings import Settings, Source
25
+ from .wandb_settings import Settings
26
26
 
27
27
 
28
28
  def _handle_host_wandb_setting(host: Optional[str], cloud: bool = False) -> None:
@@ -80,11 +80,17 @@ def login(
80
80
  _handle_host_wandb_setting(host)
81
81
  if wandb.setup()._settings._noop:
82
82
  return True
83
- kwargs = dict(locals())
84
- _verify = kwargs.pop("verify", False)
85
- configured = _login(**kwargs)
86
83
 
87
- if _verify:
84
+ configured = _login(
85
+ anonymous=anonymous,
86
+ key=key,
87
+ relogin=relogin,
88
+ host=host,
89
+ force=force,
90
+ timeout=timeout,
91
+ )
92
+
93
+ if verify:
88
94
  from . import wandb_setup
89
95
 
90
96
  singleton = wandb_setup._WandbSetup._instance
@@ -115,22 +121,32 @@ class _WandbLogin:
115
121
  self._key = None
116
122
  self._relogin = None
117
123
 
118
- def setup(self, kwargs):
119
- self.kwargs = kwargs
124
+ def setup(
125
+ self,
126
+ *,
127
+ anonymous: Optional[Literal["must", "allow", "never"]] = None,
128
+ key: Optional[str] = None,
129
+ relogin: Optional[bool] = None,
130
+ host: Optional[str] = None,
131
+ force: Optional[bool] = None,
132
+ timeout: Optional[int] = None,
133
+ ):
134
+ self._relogin = relogin
120
135
 
121
136
  # built up login settings
122
137
  login_settings: Settings = wandb.Settings()
123
- settings_param = kwargs.pop("_settings", None)
124
- # note that this case does not come up anywhere except for the tests
125
- if settings_param is not None:
126
- if isinstance(settings_param, Settings):
127
- login_settings._apply_settings(settings_param)
128
- elif isinstance(settings_param, dict):
129
- login_settings.update(settings_param, source=Source.LOGIN)
130
- _logger = wandb.setup()._get_logger()
131
- # Do not save relogin into settings as we just want to relogin once
132
- self._relogin = kwargs.pop("relogin", None)
133
- login_settings._apply_login(kwargs, _logger=_logger)
138
+ logger = wandb.setup()._get_logger()
139
+
140
+ login_settings._apply_login(
141
+ {
142
+ "anonymous": anonymous,
143
+ "key": key,
144
+ "host": host,
145
+ "force": force,
146
+ "timeout": timeout,
147
+ },
148
+ _logger=logger,
149
+ )
134
150
 
135
151
  # make sure they are applied globally
136
152
  self._wl = wandb.setup(settings=login_settings)
@@ -259,6 +275,7 @@ class _WandbLogin:
259
275
 
260
276
 
261
277
  def _login(
278
+ *,
262
279
  anonymous: Optional[Literal["must", "allow", "never"]] = None,
263
280
  key: Optional[str] = None,
264
281
  relogin: Optional[bool] = None,
@@ -270,9 +287,6 @@ def _login(
270
287
  _disable_warning: Optional[bool] = None,
271
288
  _entity: Optional[str] = None,
272
289
  ):
273
- kwargs = dict(locals())
274
- _disable_warning = kwargs.pop("_disable_warning", None)
275
-
276
290
  if wandb.run is not None:
277
291
  if not _disable_warning:
278
292
  wandb.termwarn("Calling wandb.login() after wandb.init() has no effect.")
@@ -280,20 +294,24 @@ def _login(
280
294
 
281
295
  wlogin = _WandbLogin()
282
296
 
283
- _backend = kwargs.pop("_backend", None)
284
297
  if _backend:
285
298
  wlogin.set_backend(_backend)
286
299
 
287
- _silent = kwargs.pop("_silent", None)
288
300
  if _silent:
289
301
  wlogin.set_silent(_silent)
290
302
 
291
- _entity = kwargs.pop("_entity", None)
292
303
  if _entity:
293
304
  wlogin.set_entity(_entity)
294
305
 
295
306
  # configure login object
296
- wlogin.setup(kwargs)
307
+ wlogin.setup(
308
+ anonymous=anonymous,
309
+ key=key,
310
+ relogin=relogin,
311
+ host=host,
312
+ force=force,
313
+ timeout=timeout,
314
+ )
297
315
 
298
316
  if wlogin._settings._offline:
299
317
  return False
@@ -306,7 +324,6 @@ def _login(
306
324
  # perform a login
307
325
  logged_in = wlogin.login()
308
326
 
309
- key = kwargs.get("key")
310
327
  if key:
311
328
  wlogin.configure_api_key(key)
312
329