wandb 0.15.9__py3-none-any.whl → 0.15.11__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. wandb/__init__.py +5 -1
  2. wandb/apis/public.py +137 -17
  3. wandb/apis/reports/_panels.py +1 -1
  4. wandb/apis/reports/blocks.py +1 -0
  5. wandb/apis/reports/report.py +27 -5
  6. wandb/cli/cli.py +52 -41
  7. wandb/docker/__init__.py +17 -0
  8. wandb/docker/auth.py +1 -1
  9. wandb/env.py +24 -4
  10. wandb/filesync/step_checksum.py +3 -3
  11. wandb/integration/openai/openai.py +3 -0
  12. wandb/integration/ultralytics/__init__.py +9 -0
  13. wandb/integration/ultralytics/bbox_utils.py +196 -0
  14. wandb/integration/ultralytics/callback.py +458 -0
  15. wandb/integration/ultralytics/classification_utils.py +66 -0
  16. wandb/integration/ultralytics/mask_utils.py +141 -0
  17. wandb/integration/ultralytics/pose_utils.py +92 -0
  18. wandb/integration/xgboost/xgboost.py +3 -3
  19. wandb/integration/yolov8/__init__.py +0 -7
  20. wandb/integration/yolov8/yolov8.py +22 -3
  21. wandb/old/settings.py +7 -0
  22. wandb/plot/line_series.py +0 -1
  23. wandb/proto/v3/wandb_internal_pb2.py +353 -300
  24. wandb/proto/v3/wandb_server_pb2.py +37 -41
  25. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  26. wandb/proto/v3/wandb_telemetry_pb2.py +16 -16
  27. wandb/proto/v4/wandb_internal_pb2.py +272 -260
  28. wandb/proto/v4/wandb_server_pb2.py +37 -40
  29. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  30. wandb/proto/v4/wandb_telemetry_pb2.py +16 -16
  31. wandb/proto/wandb_internal_codegen.py +7 -31
  32. wandb/sdk/artifacts/artifact.py +321 -189
  33. wandb/sdk/artifacts/artifact_cache.py +14 -0
  34. wandb/sdk/artifacts/artifact_manifest.py +5 -4
  35. wandb/sdk/artifacts/artifact_manifest_entry.py +37 -9
  36. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +1 -9
  37. wandb/sdk/artifacts/artifact_saver.py +13 -50
  38. wandb/sdk/artifacts/artifact_ttl.py +6 -0
  39. wandb/sdk/artifacts/artifacts_cache.py +119 -93
  40. wandb/sdk/artifacts/staging.py +25 -0
  41. wandb/sdk/artifacts/storage_handlers/s3_handler.py +12 -7
  42. wandb/sdk/artifacts/storage_handlers/wb_local_artifact_handler.py +2 -3
  43. wandb/sdk/artifacts/storage_policies/__init__.py +4 -0
  44. wandb/sdk/artifacts/storage_policies/register.py +1 -0
  45. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +4 -3
  46. wandb/sdk/artifacts/storage_policy.py +4 -2
  47. wandb/sdk/backend/backend.py +0 -16
  48. wandb/sdk/data_types/image.py +3 -1
  49. wandb/sdk/integration_utils/auto_logging.py +38 -13
  50. wandb/sdk/interface/interface.py +16 -135
  51. wandb/sdk/interface/interface_shared.py +9 -147
  52. wandb/sdk/interface/interface_sock.py +0 -26
  53. wandb/sdk/internal/file_pusher.py +20 -3
  54. wandb/sdk/internal/file_stream.py +3 -1
  55. wandb/sdk/internal/handler.py +53 -70
  56. wandb/sdk/internal/internal_api.py +220 -130
  57. wandb/sdk/internal/job_builder.py +41 -37
  58. wandb/sdk/internal/sender.py +7 -25
  59. wandb/sdk/internal/system/assets/disk.py +144 -11
  60. wandb/sdk/internal/system/system_info.py +6 -2
  61. wandb/sdk/launch/__init__.py +5 -0
  62. wandb/sdk/launch/{launch.py → _launch.py} +53 -54
  63. wandb/sdk/launch/{launch_add.py → _launch_add.py} +34 -31
  64. wandb/sdk/launch/_project_spec.py +13 -2
  65. wandb/sdk/launch/agent/agent.py +103 -59
  66. wandb/sdk/launch/agent/run_queue_item_file_saver.py +6 -4
  67. wandb/sdk/launch/builder/build.py +19 -1
  68. wandb/sdk/launch/builder/docker_builder.py +5 -1
  69. wandb/sdk/launch/builder/kaniko_builder.py +5 -1
  70. wandb/sdk/launch/create_job.py +20 -5
  71. wandb/sdk/launch/loader.py +14 -5
  72. wandb/sdk/launch/runner/abstract.py +0 -2
  73. wandb/sdk/launch/runner/kubernetes_monitor.py +329 -0
  74. wandb/sdk/launch/runner/kubernetes_runner.py +66 -209
  75. wandb/sdk/launch/runner/local_container.py +5 -2
  76. wandb/sdk/launch/runner/local_process.py +4 -1
  77. wandb/sdk/launch/sweeps/scheduler.py +43 -25
  78. wandb/sdk/launch/sweeps/utils.py +5 -3
  79. wandb/sdk/launch/utils.py +3 -1
  80. wandb/sdk/lib/_settings_toposort_generate.py +3 -9
  81. wandb/sdk/lib/_settings_toposort_generated.py +27 -3
  82. wandb/sdk/lib/_wburls_generated.py +1 -0
  83. wandb/sdk/lib/filenames.py +27 -6
  84. wandb/sdk/lib/filesystem.py +181 -7
  85. wandb/sdk/lib/fsm.py +5 -3
  86. wandb/sdk/lib/gql_request.py +3 -0
  87. wandb/sdk/lib/ipython.py +7 -0
  88. wandb/sdk/lib/wburls.py +1 -0
  89. wandb/sdk/service/port_file.py +2 -15
  90. wandb/sdk/service/server.py +7 -55
  91. wandb/sdk/service/service.py +56 -26
  92. wandb/sdk/service/service_base.py +1 -1
  93. wandb/sdk/service/streams.py +11 -5
  94. wandb/sdk/verify/verify.py +2 -2
  95. wandb/sdk/wandb_init.py +8 -2
  96. wandb/sdk/wandb_manager.py +4 -14
  97. wandb/sdk/wandb_run.py +143 -53
  98. wandb/sdk/wandb_settings.py +148 -35
  99. wandb/testing/relay.py +85 -38
  100. wandb/util.py +87 -4
  101. wandb/wandb_torch.py +24 -38
  102. {wandb-0.15.9.dist-info → wandb-0.15.11.dist-info}/METADATA +48 -23
  103. {wandb-0.15.9.dist-info → wandb-0.15.11.dist-info}/RECORD +107 -103
  104. {wandb-0.15.9.dist-info → wandb-0.15.11.dist-info}/WHEEL +1 -1
  105. wandb/proto/v3/wandb_server_pb2_grpc.py +0 -1422
  106. wandb/proto/v4/wandb_server_pb2_grpc.py +0 -1422
  107. wandb/proto/wandb_server_pb2_grpc.py +0 -8
  108. wandb/sdk/artifacts/storage_policies/s3_bucket_policy.py +0 -61
  109. wandb/sdk/interface/interface_grpc.py +0 -460
  110. wandb/sdk/service/server_grpc.py +0 -444
  111. wandb/sdk/service/service_grpc.py +0 -73
  112. {wandb-0.15.9.dist-info → wandb-0.15.11.dist-info}/LICENSE +0 -0
  113. {wandb-0.15.9.dist-info → wandb-0.15.11.dist-info}/entry_points.txt +0 -0
  114. {wandb-0.15.9.dist-info → wandb-0.15.11.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,16 @@
1
1
  import inspect
2
2
  import sys
3
- from typing import Any, Dict, List, Optional, Set, Tuple
3
+ from typing import Any, Dict, List, Set, Tuple
4
4
 
5
5
  from wandb.errors import UsageError
6
6
  from wandb.sdk.wandb_settings import Settings
7
7
 
8
8
  if sys.version_info >= (3, 8):
9
- from typing import get_args, get_origin, get_type_hints
9
+ from typing import get_type_hints
10
10
  elif sys.version_info >= (3, 7):
11
- from typing_extensions import get_args, get_origin, get_type_hints
11
+ from typing_extensions import get_type_hints
12
12
  else:
13
13
 
14
- def get_args(obj: Any) -> Optional[Any]:
15
- return obj.__args__ if hasattr(obj, "__args__") else None
16
-
17
- def get_origin(obj: Any) -> Optional[Any]:
18
- return obj.__origin__ if hasattr(obj, "__origin__") else None
19
-
20
14
  def get_type_hints(obj: Any) -> Dict[str, Any]:
21
15
  return dict(obj.__annotations__) if hasattr(obj, "__annotations__") else dict()
22
16
 
@@ -22,12 +22,24 @@ _Setting = Literal[
22
22
  "_disable_setproctitle",
23
23
  "_disable_stats",
24
24
  "_disable_viewer",
25
+ "_disable_machine_info",
25
26
  "_except_exit",
26
27
  "_executable",
27
28
  "_extra_http_headers",
29
+ "_file_stream_retry_max",
30
+ "_file_stream_retry_wait_min_seconds",
31
+ "_file_stream_retry_wait_max_seconds",
28
32
  "_file_stream_timeout_seconds",
33
+ "_file_uploader_retry_max",
34
+ "_file_uploader_retry_wait_min_seconds",
35
+ "_file_uploader_retry_wait_max_seconds",
36
+ "_file_uploader_timeout_seconds",
29
37
  "_flow_control_custom",
30
38
  "_flow_control_disabled",
39
+ "_graphql_retry_max",
40
+ "_graphql_retry_wait_min_seconds",
41
+ "_graphql_retry_wait_max_seconds",
42
+ "_graphql_timeout_seconds",
31
43
  "_internal_check_process",
32
44
  "_internal_queue_timeout",
33
45
  "_ipython",
@@ -46,6 +58,7 @@ _Setting = Literal[
46
58
  "_sync",
47
59
  "_os",
48
60
  "_platform",
61
+ "_proxies",
49
62
  "_python",
50
63
  "_runqueue_item_id",
51
64
  "_require_nexus",
@@ -61,6 +74,7 @@ _Setting = Literal[
61
74
  "_stats_neuron_monitor_config_path",
62
75
  "_stats_open_metrics_endpoints",
63
76
  "_stats_open_metrics_filters",
77
+ "_stats_disk_paths",
64
78
  "_tmp_code_dir",
65
79
  "_tracelog",
66
80
  "_unsaved_keys",
@@ -71,6 +85,7 @@ _Setting = Literal[
71
85
  "azure_account_url_to_access_key",
72
86
  "base_url",
73
87
  "code_dir",
88
+ "colab_url",
74
89
  "config_paths",
75
90
  "console",
76
91
  "deployment",
@@ -108,6 +123,7 @@ _Setting = Literal[
108
123
  "notebook_name",
109
124
  "problem",
110
125
  "program",
126
+ "program_abspath",
111
127
  "program_relpath",
112
128
  "project",
113
129
  "project_url",
@@ -174,6 +190,12 @@ SETTINGS_TOPOLOGICALLY_SORTED: Final[Tuple[_Setting, ...]] = (
174
190
  "start_method",
175
191
  "_aws_lambda",
176
192
  "_colab",
193
+ "_disable_machine_info",
194
+ "_disable_meta",
195
+ "_disable_stats",
196
+ "_network_buffer",
197
+ "_flow_control_disabled",
198
+ "_flow_control_custom",
177
199
  "_ipython",
178
200
  "_jupyter",
179
201
  "_kaggle",
@@ -181,9 +203,6 @@ SETTINGS_TOPOLOGICALLY_SORTED: Final[Tuple[_Setting, ...]] = (
181
203
  "_notebook",
182
204
  "disabled",
183
205
  "_offline",
184
- "_network_buffer",
185
- "_flow_control_disabled",
186
- "_flow_control_custom",
187
206
  "_stats_neuron_monitor_config_path",
188
207
  "run_mode",
189
208
  "_start_datetime",
@@ -193,14 +212,19 @@ SETTINGS_TOPOLOGICALLY_SORTED: Final[Tuple[_Setting, ...]] = (
193
212
  "tmp_dir",
194
213
  "_tmp_code_dir",
195
214
  "_windows",
215
+ "colab_url",
196
216
  "is_local",
197
217
  "deployment",
218
+ "disable_code",
219
+ "disable_git",
220
+ "disable_job_creation",
198
221
  "files_dir",
199
222
  "log_dir",
200
223
  "log_internal",
201
224
  "log_symlink_internal",
202
225
  "log_symlink_user",
203
226
  "log_user",
227
+ "program",
204
228
  "project_url",
205
229
  "resume_fname",
206
230
  "run_url",
@@ -17,4 +17,5 @@ URLS = Literal[
17
17
  "multiprocess",
18
18
  "wandb_init",
19
19
  "wandb_server",
20
+ "wandb_define_metric",
20
21
  ]
@@ -1,6 +1,5 @@
1
- #
2
1
  import os
3
- from typing import Callable, Generator
2
+ from typing import Callable, Generator, Union
4
3
 
5
4
  WANDB_DIRS = ("wandb", ".wandb")
6
5
 
@@ -29,15 +28,37 @@ def is_wandb_file(name: str) -> bool:
29
28
 
30
29
 
31
30
  def filtered_dir(
32
- root: str, include_fn: Callable[[str], bool], exclude_fn: Callable[[str], bool]
31
+ root: str,
32
+ include_fn: Union[Callable[[str, str], bool], Callable[[str], bool]],
33
+ exclude_fn: Union[Callable[[str, str], bool], Callable[[str], bool]],
33
34
  ) -> Generator[str, None, None]:
34
35
  """Simple generator to walk a directory."""
36
+ import inspect
37
+
38
+ # compatibility with old API, which didn't pass root
39
+ def _include_fn(path: str, root: str) -> bool:
40
+ return (
41
+ include_fn(path, root) # type: ignore
42
+ if len(inspect.signature(include_fn).parameters) == 2
43
+ else include_fn(path) # type: ignore
44
+ )
45
+
46
+ def _exclude_fn(path: str, root: str) -> bool:
47
+ return (
48
+ exclude_fn(path, root) # type: ignore
49
+ if len(inspect.signature(exclude_fn).parameters) == 2
50
+ else exclude_fn(path) # type: ignore
51
+ )
52
+
35
53
  for dirpath, _, files in os.walk(root):
36
54
  for fname in files:
37
55
  file_path = os.path.join(dirpath, fname)
38
- if include_fn(file_path) and not exclude_fn(file_path):
56
+ if _include_fn(file_path, root) and not _exclude_fn(file_path, root):
39
57
  yield file_path
40
58
 
41
59
 
42
- def exclude_wandb_fn(path: str) -> bool:
43
- return any(os.sep + wandb_dir + os.sep in path for wandb_dir in WANDB_DIRS)
60
+ def exclude_wandb_fn(path: str, root: str) -> bool:
61
+ return any(
62
+ os.path.relpath(path, root).startswith(wandb_dir + os.sep)
63
+ for wandb_dir in WANDB_DIRS
64
+ )
@@ -1,4 +1,6 @@
1
1
  import contextlib
2
+ import ctypes
3
+ import errno
2
4
  import logging
3
5
  import os
4
6
  import platform
@@ -8,7 +10,7 @@ import stat
8
10
  import tempfile
9
11
  import threading
10
12
  from pathlib import Path
11
- from typing import IO, Any, BinaryIO, Generator
13
+ from typing import IO, Any, BinaryIO, Generator, Optional
12
14
 
13
15
  from wandb.sdk.lib.paths import StrPath
14
16
 
@@ -17,6 +19,10 @@ logger = logging.getLogger(__name__)
17
19
  WRITE_PERMISSIONS = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH | stat.S_IWRITE
18
20
 
19
21
 
22
+ # https://en.wikipedia.org/wiki/Filename#Comparison_of_filename_limitations
23
+ PROBLEMATIC_PATH_CHARS = "".join(chr(i) for i in range(0, 32)) + ':"*<>?|'
24
+
25
+
20
26
  def mkdir_exists_ok(dir_name: StrPath) -> None:
21
27
  """Create `dir_name` and any parent directories if they don't exist.
22
28
 
@@ -32,6 +38,53 @@ def mkdir_exists_ok(dir_name: StrPath) -> None:
32
38
  raise PermissionError(f"{dir_name!s} is not writable") from e
33
39
 
34
40
 
41
+ def path_fallbacks(path: StrPath) -> Generator[str, None, None]:
42
+ """Yield variations of `path` that may exist on the filesystem.
43
+
44
+ Return a sequence of paths that should be checked in order for existence or
45
+ create-ability. Essentially, keep replacing "suspect" characters until we run out.
46
+ """
47
+ path = str(path)
48
+ root, tail = os.path.splitdrive(path)
49
+ yield os.path.join(root, tail)
50
+ for char in PROBLEMATIC_PATH_CHARS:
51
+ if char in tail:
52
+ tail = tail.replace(char, "-")
53
+ yield os.path.join(root, tail)
54
+
55
+
56
+ def mkdir_allow_fallback(dir_name: StrPath) -> StrPath:
57
+ """Create `dir_name`, removing invalid path characters if necessary.
58
+
59
+ Returns:
60
+ The path to the created directory, which may not be the original path.
61
+ """
62
+ for new_name in path_fallbacks(dir_name):
63
+ try:
64
+ os.makedirs(new_name, exist_ok=True)
65
+ if Path(new_name) != Path(dir_name):
66
+ logger.warning(f"Creating '{new_name}' instead of '{dir_name}'")
67
+ return Path(new_name) if isinstance(dir_name, Path) else new_name
68
+ except (ValueError, NotADirectoryError):
69
+ pass
70
+ except OSError as e:
71
+ if e.errno != 22:
72
+ raise
73
+
74
+ raise OSError(f"Unable to create directory '{dir_name}'")
75
+
76
+
77
+ def files_in(path: StrPath) -> Generator[os.DirEntry, None, None]:
78
+ """Yield a directory entry for each file under a given path (recursive)."""
79
+ if not os.path.isdir(path):
80
+ return
81
+ for entry in os.scandir(path):
82
+ if entry.is_dir():
83
+ yield from files_in(entry.path)
84
+ else:
85
+ yield entry
86
+
87
+
35
88
  class WriteSerializingFile:
36
89
  """Wrapper for a file object that serializes writes."""
37
90
 
@@ -99,11 +152,7 @@ def copy_or_overwrite_changed(source_path: StrPath, target_path: StrPath) -> Str
99
152
  """
100
153
  return_type = type(target_path)
101
154
 
102
- if platform.system() == "Windows":
103
- head, tail = os.path.splitdrive(str(target_path))
104
- if ":" in tail:
105
- logger.warning("Replacing ':' in %s with '-'", tail)
106
- target_path = os.path.join(head, tail.replace(":", "-"))
155
+ target_path = system_preferred_path(target_path, warn=True)
107
156
 
108
157
  need_copy = (
109
158
  not os.path.isfile(target_path)
@@ -112,7 +161,8 @@ def copy_or_overwrite_changed(source_path: StrPath, target_path: StrPath) -> Str
112
161
 
113
162
  permissions_plus_write = os.stat(source_path).st_mode | WRITE_PERMISSIONS
114
163
  if need_copy:
115
- mkdir_exists_ok(os.path.dirname(target_path))
164
+ dir_name, file_name = os.path.split(target_path)
165
+ target_path = os.path.join(mkdir_allow_fallback(dir_name), file_name)
116
166
  try:
117
167
  # Use copy2 to preserve file metadata (including modified time).
118
168
  shutil.copy2(source_path, target_path)
@@ -190,3 +240,127 @@ def safe_copy(source_path: StrPath, target_path: StrPath) -> StrPath:
190
240
  shutil.copy2(source_path, tmp_path)
191
241
  tmp_path.replace(output_path)
192
242
  return target_path
243
+
244
+
245
+ def _reflink_linux(existing_path: Path, new_path: Path) -> None:
246
+ """Create a reflink to `existing_path` at `new_path` on Linux."""
247
+ import fcntl
248
+
249
+ FICLONE = 0x40049409 # magic number from <linux/fs.h> # noqa: N806
250
+ with open(existing_path, "rb") as t_f, open(new_path, "wb+") as l_f:
251
+ fcntl.ioctl(l_f.fileno(), FICLONE, t_f.fileno())
252
+
253
+
254
+ def _reflink_macos(existing_path: Path, new_path: Path) -> None:
255
+ try:
256
+ clib = ctypes.CDLL("libc.dylib", use_errno=True)
257
+ except (FileNotFoundError, OSError) as e:
258
+ if ctypes.get_errno() != errno.ENOENT and not isinstance(e, FileNotFoundError):
259
+ raise
260
+ # Before macOS 11 (<Nov 2020) clib was in libSystem.dylib, so we can try there.
261
+ clib = ctypes.CDLL("/usr/lib/libSystem.dylib", use_errno=True)
262
+
263
+ try:
264
+ clonefile = clib.clonefile
265
+ except AttributeError:
266
+ raise OSError(errno.ENOTSUP, "'clonefile' is not available on this system")
267
+
268
+ clonefile.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int)
269
+ clonefile.restype = ctypes.c_int
270
+
271
+ if clonefile(os.fsencode(existing_path), os.fsencode(new_path), ctypes.c_int(0)):
272
+ # Anything other than 0 is an error.
273
+ err = ctypes.get_errno()
274
+ raise OSError(err, os.strerror(err), existing_path)
275
+
276
+
277
+ def reflink(existing_path: StrPath, new_path: StrPath, overwrite: bool = False) -> None:
278
+ """Create a reflink to `existing_path` at `new_path`.
279
+
280
+ A reflink (reflective link) is a copy-on-write reference to a file. Once linked, the
281
+ file and link are both "real" files (not symbolic or hard links) and each can be
282
+ modified independently without affecting the other; however, they share the same
283
+ underlying data blocks on disk so until one is modified they are "zero-cost" copies.
284
+
285
+ Reflinks have all the functionality of copies, so we should use them wherever they
286
+ are supported if we would otherwise copy a file. (This is not particularly radical--
287
+ GNU `cp` defaults to `reflink=auto`, using it whenever available) However, support
288
+ for them is limited to a small number of filesystems. They should work on:
289
+ - Linux with a Btrfs or XFS filesystem (NOT ext4)
290
+ - macOS 10.13 or later with an APFS filesystem (called clone files)
291
+
292
+ Reflinks are also supported on Solaris and Windows with ReFSv2, but we haven't
293
+ implemented support for them.
294
+
295
+ Like hard links, a reflink can only be created on the same filesystem as the target.
296
+ """
297
+ if platform.system() == "Linux":
298
+ link_fn = _reflink_linux
299
+ elif platform.system() == "Darwin":
300
+ link_fn = _reflink_macos
301
+ else:
302
+ raise OSError(
303
+ errno.ENOTSUP, f"reflinks are not supported on {platform.system()}"
304
+ )
305
+
306
+ new_path = Path(new_path).resolve()
307
+ existing_path = Path(existing_path).resolve()
308
+ if new_path.exists():
309
+ if not overwrite:
310
+ raise FileExistsError(f"{new_path} already exists")
311
+ logger.warning(f"Overwriting existing file {new_path}.")
312
+ new_path.unlink()
313
+
314
+ # Create any missing parent directories.
315
+ new_path.parent.mkdir(parents=True, exist_ok=True)
316
+
317
+ try:
318
+ link_fn(existing_path, new_path)
319
+ except OSError as e:
320
+ base_msg = f"failed to create reflink from {existing_path} to {new_path}."
321
+ if e.errno in (errno.EPERM, errno.EACCES):
322
+ raise PermissionError(f"Insufficient permissions; {base_msg}") from e
323
+ if e.errno == errno.ENOENT:
324
+ raise FileNotFoundError(f"File not found; {base_msg}") from e
325
+ if e.errno == errno.EXDEV:
326
+ raise ValueError(f"Cannot link across filesystems; {base_msg}") from e
327
+ if e.errno == errno.EISDIR:
328
+ raise IsADirectoryError(f"Cannot reflink a directory; {base_msg}") from e
329
+ if e.errno in (errno.EOPNOTSUPP, errno.ENOTSUP):
330
+ raise OSError(
331
+ errno.ENOTSUP,
332
+ f"Filesystem does not support reflinks; {base_msg}",
333
+ ) from e
334
+ if e.errno == errno.EINVAL:
335
+ raise ValueError(f"Cannot link file ranges; {base_msg}") from e
336
+ raise
337
+
338
+
339
+ def check_exists(path: StrPath) -> Optional[StrPath]:
340
+ """Look for variations of `path` and return the first found.
341
+
342
+ This exists to support former behavior around system-dependent paths; we used to use
343
+ ':' in Artifact paths unless we were on Windows, but this has issues when e.g. a
344
+ Linux machine is accessing an NTFS filesystem; we might need to look for the
345
+ alternate path. This checks all the possible directories we would consider creating.
346
+ """
347
+ for dest in path_fallbacks(path):
348
+ if os.path.exists(dest):
349
+ return Path(dest) if isinstance(path, Path) else dest
350
+ return None
351
+
352
+
353
+ def system_preferred_path(path: StrPath, warn: bool = False) -> StrPath:
354
+ """Replace ':' with '-' in paths on Windows.
355
+
356
+ Args:
357
+ path: The path to convert.
358
+ warn: Whether to warn if ':' is replaced.
359
+ """
360
+ if platform.system() != "Windows":
361
+ return path
362
+ head, tail = os.path.splitdrive(path)
363
+ if warn and ":" in tail:
364
+ logger.warning(f"Replacing ':' in {tail} with '-'")
365
+ new_path = head + tail.replace(":", "-")
366
+ return Path(new_path) if isinstance(path, Path) else new_path
wandb/sdk/lib/fsm.py CHANGED
@@ -9,19 +9,21 @@ Usage:
9
9
  def on_output(self, inputs) -> None:
10
10
  pass
11
11
 
12
+
12
13
  class B:
13
14
  def on_output(self, inputs) -> None:
14
15
  pass
15
16
 
17
+
16
18
  def to_b(inputs) -> bool:
17
19
  return True
18
20
 
21
+
19
22
  def to_a(inputs) -> bool:
20
23
  return True
21
24
 
22
- f = Fsm(states=[A(), B()],
23
- table={A: [(to_b, B)],
24
- B: [(to_a, A)]})
25
+
26
+ f = Fsm(states=[A(), B()], table={A: [(to_b, B)], B: [(to_a, A)]})
25
27
  f.run({"input1": 1, "input2": 2})
26
28
  ```
27
29
  """
@@ -20,6 +20,7 @@ class GraphQLSession(HTTPTransport):
20
20
  auth: Optional[Union[Tuple[str, str], Callable]] = None,
21
21
  use_json: bool = False,
22
22
  timeout: Optional[Union[int, float]] = None,
23
+ proxies: Optional[Dict[str, str]] = None,
23
24
  **kwargs: Any,
24
25
  ) -> None:
25
26
  """Setup a session for sending GraphQL queries and mutations.
@@ -32,6 +33,8 @@ class GraphQLSession(HTTPTransport):
32
33
  """
33
34
  super().__init__(url, **kwargs)
34
35
  self.session = requests.Session()
36
+ if proxies:
37
+ self.session.proxies.update(proxies)
35
38
  self.session.auth = auth
36
39
  self.default_timeout = timeout
37
40
  self.use_json = use_json
wandb/sdk/lib/ipython.py CHANGED
@@ -28,6 +28,9 @@ def toggle_button(what="run"):
28
28
 
29
29
 
30
30
  def _get_python_type() -> PythonType:
31
+ if "IPython" not in sys.modules:
32
+ return "python"
33
+
31
34
  try:
32
35
  from IPython import get_ipython # type: ignore
33
36
 
@@ -42,6 +45,10 @@ def _get_python_type() -> PythonType:
42
45
  (get_ipython().config.get("IPKernelApp", {}) or {})
43
46
  .get("connection_file", "")
44
47
  .lower()
48
+ ) or (
49
+ (get_ipython().config.get("ColabKernelApp", {}) or {})
50
+ .get("connection_file", "")
51
+ .lower()
45
52
  )
46
53
 
47
54
  if (
wandb/sdk/lib/wburls.py CHANGED
@@ -33,6 +33,7 @@ class WBURLs:
33
33
  multiprocess="http://wandb.me/init-multiprocess",
34
34
  wandb_init="https://wandb.me/wandb-init",
35
35
  wandb_server="https://wandb.me/wandb-server",
36
+ wandb_define_metric="https://wandb.me/define-metric",
36
37
  )
37
38
 
38
39
  def get(self, s: "URLS") -> str:
@@ -6,18 +6,13 @@ from typing import Optional
6
6
 
7
7
 
8
8
  class PortFile:
9
- _grpc_port: Optional[int]
10
9
  _sock_port: Optional[int]
11
10
  _valid: bool
12
11
 
13
- GRPC_TOKEN = "grpc="
14
12
  SOCK_TOKEN = "sock="
15
13
  EOF_TOKEN = "EOF"
16
14
 
17
- def __init__(
18
- self, grpc_port: Optional[int] = None, sock_port: Optional[int] = None
19
- ) -> None:
20
- self._grpc_port = grpc_port
15
+ def __init__(self, sock_port: Optional[int] = None) -> None:
21
16
  self._sock_port = sock_port
22
17
  self._valid = False
23
18
 
@@ -28,8 +23,6 @@ class PortFile:
28
23
  tmp_filename = f.name
29
24
  with f:
30
25
  data = []
31
- if self._grpc_port:
32
- data.append(f"{self.GRPC_TOKEN}{self._grpc_port}")
33
26
  if self._sock_port:
34
27
  data.append(f"{self.SOCK_TOKEN}{self._sock_port}")
35
28
  data.append(self.EOF_TOKEN)
@@ -47,16 +40,10 @@ class PortFile:
47
40
  if lines[-1] != self.EOF_TOKEN:
48
41
  return
49
42
  for ln in lines:
50
- if ln.startswith(self.GRPC_TOKEN):
51
- self._grpc_port = int(ln[len(self.GRPC_TOKEN) :])
52
- elif ln.startswith(self.SOCK_TOKEN):
43
+ if ln.startswith(self.SOCK_TOKEN):
53
44
  self._sock_port = int(ln[len(self.SOCK_TOKEN) :])
54
45
  self._valid = True
55
46
 
56
- @property
57
- def grpc_port(self) -> Optional[int]:
58
- return self._grpc_port
59
-
60
47
  @property
61
48
  def sock_port(self) -> Optional[int]:
62
49
  return self._sock_port
@@ -1,12 +1,11 @@
1
1
  """wandb server.
2
2
 
3
- Start up grpc or socket transport servers.
3
+ Start up socket transport servers.
4
4
  """
5
5
 
6
6
  import logging
7
7
  import os
8
8
  import sys
9
- from concurrent import futures
10
9
  from typing import Optional
11
10
 
12
11
  import wandb
@@ -19,83 +18,39 @@ from .streams import StreamMux
19
18
 
20
19
  class WandbServer:
21
20
  _pid: Optional[int]
22
- _grpc_port: Optional[int]
23
21
  _sock_port: Optional[int]
24
22
  _debug: bool
25
- _serve_grpc: bool
26
23
  _serve_sock: bool
27
24
  _sock_server: Optional[SocketServer]
28
25
  _startup_debug_enabled: bool
29
26
 
30
27
  def __init__(
31
28
  self,
32
- grpc_port: Optional[int] = None,
33
29
  sock_port: Optional[int] = None,
34
30
  port_fname: Optional[str] = None,
35
31
  address: Optional[str] = None,
36
32
  pid: Optional[int] = None,
37
33
  debug: bool = True,
38
- serve_grpc: bool = False,
39
34
  serve_sock: bool = False,
40
35
  ) -> None:
41
- self._grpc_port = grpc_port
42
36
  self._sock_port = sock_port
43
37
  self._port_fname = port_fname
44
38
  self._address = address
45
39
  self._pid = pid
46
40
  self._debug = debug
47
- self._serve_grpc = serve_grpc
48
41
  self._serve_sock = serve_sock
49
42
  self._sock_server = None
50
43
  self._startup_debug_enabled = _startup_debug.is_enabled()
51
44
 
52
- if grpc_port:
53
- _ = wandb.util.get_module(
54
- "grpc",
55
- required="grpc port requires the grpcio library, run pip install wandb[grpc]",
56
- )
57
-
58
45
  if debug:
59
46
  logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
60
47
 
61
- def _inform_used_ports(
62
- self, grpc_port: Optional[int], sock_port: Optional[int]
63
- ) -> None:
48
+ def _inform_used_ports(self, sock_port: Optional[int]) -> None:
64
49
  if not self._port_fname:
65
50
  return
66
- pf = port_file.PortFile(grpc_port=grpc_port, sock_port=sock_port)
51
+ pf = port_file.PortFile(sock_port=sock_port)
67
52
  pf.write(self._port_fname)
68
53
 
69
- def _start_grpc(self, mux: StreamMux) -> int:
70
- import grpc
71
-
72
- from wandb.proto import wandb_server_pb2_grpc as spb_grpc
73
-
74
- from .server_grpc import WandbServicer
75
-
76
- address: str = self._address or "127.0.0.1"
77
- port: int = self._grpc_port or 0
78
- pid: int = self._pid or 0
79
- server = grpc.server(
80
- futures.ThreadPoolExecutor(max_workers=10, thread_name_prefix="GrpcPoolThr")
81
- )
82
- servicer = WandbServicer(server=server, mux=mux)
83
- try:
84
- spb_grpc.add_InternalServiceServicer_to_server(servicer, server)
85
- port = server.add_insecure_port(f"{address}:{port}")
86
- mux.set_port(port)
87
- mux.set_pid(pid)
88
- server.start()
89
- except KeyboardInterrupt:
90
- mux.cleanup()
91
- server.stop(0)
92
- raise
93
- except Exception:
94
- mux.cleanup()
95
- server.stop(0)
96
- raise
97
- return port
98
-
99
54
  def _start_sock(self, mux: StreamMux) -> int:
100
55
  address: str = self._address or "127.0.0.1"
101
56
  port: int = self._sock_port or 0
@@ -129,9 +84,7 @@ class WandbServer:
129
84
  return
130
85
  _startup_debug.print_message(message)
131
86
 
132
- def _setup_proctitle(
133
- self, grpc_port: Optional[int], sock_port: Optional[int]
134
- ) -> None:
87
+ def _setup_proctitle(self, sock_port: Optional[int]) -> None:
135
88
  # TODO: similar to _setup_tracelog, the internal_process should have
136
89
  # a better way to have access to settings.
137
90
  disable_setproctitle = os.environ.get("WANDB__DISABLE_SETPROCTITLE")
@@ -143,7 +96,7 @@ class WandbServer:
143
96
  service_ver = 2
144
97
  pid = str(self._pid or 0)
145
98
  transport = "s" if sock_port else "g"
146
- port = grpc_port or sock_port or 0
99
+ port = sock_port or 0
147
100
  # this format is similar to wandb_manager token, but it's purely informative now
148
101
  # (consider unifying this in the future)
149
102
  service_id = f"{service_ver}-{pid}-{transport}-{port}"
@@ -156,12 +109,11 @@ class WandbServer:
156
109
  self._setup_tracelog()
157
110
  mux = StreamMux()
158
111
  self._startup_debug_print("before_network")
159
- grpc_port = self._start_grpc(mux=mux) if self._serve_grpc else None
160
112
  sock_port = self._start_sock(mux=mux) if self._serve_sock else None
161
113
  self._startup_debug_print("after_network")
162
- self._inform_used_ports(grpc_port=grpc_port, sock_port=sock_port)
114
+ self._inform_used_ports(sock_port=sock_port)
163
115
  self._startup_debug_print("after_inform")
164
- self._setup_proctitle(grpc_port=grpc_port, sock_port=sock_port)
116
+ self._setup_proctitle(sock_port=sock_port)
165
117
  self._startup_debug_print("before_loop")
166
118
  mux.loop()
167
119
  self._stop_servers()