wandb 0.18.1__py3-none-win32.whl → 0.18.2__py3-none-win32.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. wandb/__init__.py +3 -3
  2. wandb/__init__.pyi +67 -12
  3. wandb/apis/internal.py +3 -0
  4. wandb/apis/public/api.py +128 -2
  5. wandb/apis/public/artifacts.py +11 -7
  6. wandb/apis/public/jobs.py +8 -0
  7. wandb/apis/public/runs.py +16 -5
  8. wandb/bin/wandb-core +0 -0
  9. wandb/cli/cli.py +0 -3
  10. wandb/errors/__init__.py +11 -40
  11. wandb/errors/errors.py +37 -0
  12. wandb/errors/warnings.py +2 -0
  13. wandb/integration/tensorboard/log.py +1 -1
  14. wandb/old/core.py +2 -80
  15. wandb/plot/bar.py +7 -4
  16. wandb/plot/confusion_matrix.py +5 -4
  17. wandb/plot/histogram.py +7 -4
  18. wandb/plot/line.py +7 -4
  19. wandb/proto/v3/wandb_settings_pb2.py +2 -2
  20. wandb/proto/v4/wandb_settings_pb2.py +2 -2
  21. wandb/proto/v5/wandb_settings_pb2.py +2 -2
  22. wandb/sdk/artifacts/_validators.py +48 -3
  23. wandb/sdk/artifacts/artifact.py +157 -183
  24. wandb/sdk/artifacts/artifact_file_cache.py +13 -11
  25. wandb/sdk/artifacts/artifact_instance_cache.py +4 -2
  26. wandb/sdk/artifacts/artifact_manifest.py +13 -11
  27. wandb/sdk/artifacts/artifact_manifest_entry.py +24 -22
  28. wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +9 -7
  29. wandb/sdk/artifacts/artifact_saver.py +27 -25
  30. wandb/sdk/artifacts/exceptions.py +26 -25
  31. wandb/sdk/artifacts/storage_handler.py +11 -9
  32. wandb/sdk/artifacts/storage_handlers/azure_handler.py +16 -14
  33. wandb/sdk/artifacts/storage_handlers/gcs_handler.py +15 -13
  34. wandb/sdk/artifacts/storage_handlers/http_handler.py +15 -14
  35. wandb/sdk/artifacts/storage_handlers/local_file_handler.py +10 -8
  36. wandb/sdk/artifacts/storage_handlers/multi_handler.py +14 -12
  37. wandb/sdk/artifacts/storage_handlers/s3_handler.py +19 -19
  38. wandb/sdk/artifacts/storage_handlers/tracking_handler.py +10 -8
  39. wandb/sdk/artifacts/storage_handlers/wb_artifact_handler.py +12 -10
  40. wandb/sdk/artifacts/storage_handlers/wb_local_artifact_handler.py +9 -7
  41. wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +31 -29
  42. wandb/sdk/artifacts/storage_policy.py +20 -20
  43. wandb/sdk/backend/backend.py +8 -26
  44. wandb/sdk/data_types/base_types/wb_value.py +1 -3
  45. wandb/sdk/data_types/video.py +2 -2
  46. wandb/sdk/interface/interface.py +0 -24
  47. wandb/sdk/interface/interface_shared.py +0 -12
  48. wandb/sdk/internal/handler.py +0 -10
  49. wandb/sdk/internal/internal_api.py +71 -0
  50. wandb/sdk/internal/sender.py +0 -43
  51. wandb/sdk/internal/tb_watcher.py +1 -1
  52. wandb/sdk/lib/_settings_toposort_generated.py +1 -0
  53. wandb/sdk/lib/hashutil.py +34 -12
  54. wandb/sdk/lib/service_connection.py +216 -0
  55. wandb/sdk/lib/service_token.py +94 -0
  56. wandb/sdk/lib/sock_client.py +7 -3
  57. wandb/sdk/service/server.py +2 -5
  58. wandb/sdk/service/service.py +0 -22
  59. wandb/sdk/wandb_init.py +32 -22
  60. wandb/sdk/wandb_run.py +12 -7
  61. wandb/sdk/wandb_settings.py +2 -0
  62. wandb/sdk/wandb_setup.py +25 -16
  63. wandb/sdk/wandb_sync.py +9 -3
  64. wandb/sdk/wandb_watch.py +31 -15
  65. wandb/util.py +8 -1
  66. {wandb-0.18.1.dist-info → wandb-0.18.2.dist-info}/METADATA +2 -1
  67. {wandb-0.18.1.dist-info → wandb-0.18.2.dist-info}/RECORD +71 -71
  68. wandb/sdk/internal/update.py +0 -113
  69. wandb/sdk/service/service_base.py +0 -50
  70. wandb/sdk/service/service_sock.py +0 -70
  71. wandb/sdk/wandb_manager.py +0 -232
  72. /wandb/{sdk/lib → plot}/viz.py +0 -0
  73. {wandb-0.18.1.dist-info → wandb-0.18.2.dist-info}/WHEEL +0 -0
  74. {wandb-0.18.1.dist-info → wandb-0.18.2.dist-info}/entry_points.txt +0 -0
  75. {wandb-0.18.1.dist-info → wandb-0.18.2.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/lib/hashutil.py CHANGED
@@ -1,19 +1,22 @@
1
+ from __future__ import annotations
2
+
1
3
  import base64
2
4
  import hashlib
3
5
  import mmap
4
- import os
5
6
  import sys
6
- from pathlib import Path
7
- from typing import NewType, Union
7
+ from typing import TYPE_CHECKING, NewType
8
8
 
9
9
  from wandb.sdk.lib.paths import StrPath
10
10
 
11
+ if TYPE_CHECKING:
12
+ import _hashlib # type: ignore[import-not-found]
13
+
11
14
  ETag = NewType("ETag", str)
12
15
  HexMD5 = NewType("HexMD5", str)
13
16
  B64MD5 = NewType("B64MD5", str)
14
17
 
15
18
 
16
- def _md5(data: bytes = b"") -> "hashlib._Hash":
19
+ def _md5(data: bytes = b"") -> _hashlib.HASH:
17
20
  """Allow FIPS-compliant md5 hash when supported."""
18
21
  if sys.version_info >= (3, 9):
19
22
  return hashlib.md5(data, usedforsecurity=False)
@@ -25,7 +28,7 @@ def md5_string(string: str) -> B64MD5:
25
28
  return _b64_from_hasher(_md5(string.encode("utf-8")))
26
29
 
27
30
 
28
- def _b64_from_hasher(hasher: "hashlib._Hash") -> B64MD5:
31
+ def _b64_from_hasher(hasher: _hashlib.HASH) -> B64MD5:
29
32
  return B64MD5(base64.b64encode(hasher.digest()).decode("ascii"))
30
33
 
31
34
 
@@ -33,7 +36,7 @@ def b64_to_hex_id(string: B64MD5) -> HexMD5:
33
36
  return HexMD5(base64.standard_b64decode(string).hex())
34
37
 
35
38
 
36
- def hex_to_b64_id(encoded_string: Union[str, bytes]) -> B64MD5:
39
+ def hex_to_b64_id(encoded_string: str | bytes) -> B64MD5:
37
40
  if isinstance(encoded_string, bytes):
38
41
  encoded_string = encoded_string.decode("utf-8")
39
42
  as_str = bytes.fromhex(encoded_string)
@@ -48,15 +51,34 @@ def md5_file_hex(*paths: StrPath) -> HexMD5:
48
51
  return HexMD5(_md5_file_hasher(*paths).hexdigest())
49
52
 
50
53
 
51
- def _md5_file_hasher(*paths: StrPath) -> "hashlib._Hash":
54
+ _KB: int = 1_024
55
+ _CHUNKSIZE: int = 128 * _KB
56
+ """Chunk size (in bytes) for iteratively reading from file, if needed."""
57
+
58
+
59
+ def _md5_file_hasher(*paths: StrPath) -> _hashlib.HASH:
52
60
  md5_hash = _md5()
53
61
 
54
- for path in sorted(Path(p) for p in paths):
55
- with path.open("rb") as f:
56
- if os.stat(f.fileno()).st_size <= 1024 * 1024:
57
- md5_hash.update(f.read())
58
- else:
62
+ # Note: We use str paths (instead of pathlib.Path objs) for minor perf improvements.
63
+ for path in sorted(map(str, paths)):
64
+ with open(path, "rb") as f:
65
+ try:
59
66
  with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as mview:
60
67
  md5_hash.update(mview)
68
+ except OSError:
69
+ # This occurs if the mmap-ed file is on a different/mounted filesystem,
70
+ # so we'll fall back on a less performant implementation.
71
+
72
+ # Note: At the time of implementation, the walrus operator `:=`
73
+ # is avoided to maintain support for users on python 3.7.
74
+ # Consider revisiting once 3.7 support is no longer needed.
75
+ chunk = f.read(_CHUNKSIZE)
76
+ while chunk:
77
+ md5_hash.update(chunk)
78
+ chunk = f.read(_CHUNKSIZE)
79
+ except ValueError:
80
+ # This occurs when mmap-ing an empty file, which can be skipped.
81
+ # See: https://github.com/python/cpython/blob/986a4e1b6fcae7fe7a1d0a26aea446107dd58dd2/Modules/mmapmodule.c#L1589
82
+ pass
61
83
 
62
84
  return md5_hash
@@ -0,0 +1,216 @@
1
+ from __future__ import annotations
2
+
3
+ import atexit
4
+ import os
5
+ from typing import Callable
6
+
7
+ from wandb.proto import wandb_internal_pb2 as pb
8
+ from wandb.proto import wandb_server_pb2 as spb
9
+ from wandb.proto import wandb_settings_pb2
10
+ from wandb.sdk import wandb_settings
11
+ from wandb.sdk.interface.interface import InterfaceBase
12
+ from wandb.sdk.interface.interface_sock import InterfaceSock
13
+ from wandb.sdk.lib import service_token
14
+ from wandb.sdk.lib.exit_hooks import ExitHooks
15
+ from wandb.sdk.lib.mailbox import Mailbox
16
+ from wandb.sdk.lib.sock_client import SockClient, SockClientTimeoutError
17
+ from wandb.sdk.service import service
18
+
19
+
20
+ class WandbServiceNotOwnedError(Exception):
21
+ """Raised when the current process does not own the service process."""
22
+
23
+
24
+ class WandbServiceConnectionError(Exception):
25
+ """Raised on failure to connect to the service process."""
26
+
27
+
28
+ class WandbAttachFailedError(Exception):
29
+ """Raised if attaching to a run fails."""
30
+
31
+
32
+ def connect_to_service(
33
+ settings: wandb_settings.Settings,
34
+ ) -> ServiceConnection:
35
+ """Connects to the service process, starting one up if necessary."""
36
+ conn = _try_connect_to_existing_service()
37
+ if conn:
38
+ return conn
39
+
40
+ return _start_and_connect_service(settings)
41
+
42
+
43
+ def _try_connect_to_existing_service() -> ServiceConnection | None:
44
+ """Attemps to connect to an existing service process."""
45
+ token = service_token.get_service_token()
46
+ if not token:
47
+ return None
48
+
49
+ # Only localhost sockets are supported below.
50
+ assert token.host == "localhost"
51
+ client = SockClient()
52
+
53
+ try:
54
+ # TODO: This may block indefinitely if the service is unhealthy.
55
+ client.connect(token.port)
56
+
57
+ except Exception as e:
58
+ raise WandbServiceConnectionError(
59
+ "Failed to connect to internal service."
60
+ ) from e
61
+
62
+ return ServiceConnection(client=client, proc=None)
63
+
64
+
65
+ def _start_and_connect_service(
66
+ settings: wandb_settings.Settings,
67
+ ) -> ServiceConnection:
68
+ """Starts a service process and returns a connection to it.
69
+
70
+ An atexit hook is registered to tear down the service process and wait for
71
+ it to complete. The hook does not run in processes started using the
72
+ multiprocessing module.
73
+ """
74
+ proc = service._Service(settings)
75
+ proc.start()
76
+
77
+ port = proc.sock_port
78
+ assert port
79
+ client = SockClient()
80
+ client.connect(port)
81
+
82
+ service_token.set_service_token(
83
+ parent_pid=os.getpid(),
84
+ transport="tcp",
85
+ host="localhost",
86
+ port=port,
87
+ )
88
+
89
+ hooks = ExitHooks()
90
+ hooks.hook()
91
+
92
+ def teardown_atexit():
93
+ conn.teardown(hooks.exit_code)
94
+
95
+ conn = ServiceConnection(
96
+ client=client,
97
+ proc=proc,
98
+ cleanup=lambda: atexit.unregister(teardown_atexit),
99
+ )
100
+
101
+ atexit.register(teardown_atexit)
102
+
103
+ return conn
104
+
105
+
106
+ class ServiceConnection:
107
+ """A connection to the W&B internal service process."""
108
+
109
+ def __init__(
110
+ self,
111
+ client: SockClient,
112
+ proc: service._Service | None,
113
+ cleanup: Callable[[], None] | None = None,
114
+ ):
115
+ """Returns a new ServiceConnection.
116
+
117
+ Args:
118
+ client: A socket that's connected to the service.
119
+ proc: The service process if we own it, or None otherwise.
120
+ cleanup: A callback to run on teardown before doing anything.
121
+ """
122
+ self._client = client
123
+ self._proc = proc
124
+ self._torn_down = False
125
+ self._cleanup = cleanup
126
+
127
+ def make_interface(self, mailbox: Mailbox) -> InterfaceBase:
128
+ """Returns an interface for communicating with the service."""
129
+ return InterfaceSock(self._client, mailbox)
130
+
131
+ def send_record(self, record: pb.Record) -> None:
132
+ """Sends data to the service."""
133
+ self._client.send_record_publish(record)
134
+
135
+ def inform_init(
136
+ self,
137
+ settings: wandb_settings_pb2.Settings,
138
+ run_id: str,
139
+ ) -> None:
140
+ """Sends an init request to the service."""
141
+ request = spb.ServerInformInitRequest()
142
+ request.settings.CopyFrom(settings)
143
+ request._info.stream_id = run_id
144
+ self._client.send(inform_init=request)
145
+
146
+ def inform_finish(self, run_id: str) -> None:
147
+ """Sends an finish request to the service."""
148
+ request = spb.ServerInformFinishRequest()
149
+ request._info.stream_id = run_id
150
+ self._client.send(inform_finish=request)
151
+
152
+ def inform_attach(
153
+ self,
154
+ attach_id: str,
155
+ ) -> wandb_settings_pb2.Settings:
156
+ """Sends an attach request to the service.
157
+
158
+ Raises a WandbAttachFailedError if attaching is not possible.
159
+ """
160
+ request = spb.ServerInformAttachRequest()
161
+ request._info.stream_id = attach_id
162
+
163
+ try:
164
+ response = self._client.send_and_recv(inform_attach=request)
165
+ return response.inform_attach_response.settings
166
+ except SockClientTimeoutError:
167
+ raise WandbAttachFailedError(
168
+ "Could not attach because the run does not belong to"
169
+ " the current service process, or because the service"
170
+ " process is busy (unlikely)."
171
+ )
172
+
173
+ def inform_start(
174
+ self,
175
+ settings: wandb_settings_pb2.Settings,
176
+ run_id: str,
177
+ ) -> None:
178
+ """Sends a start request to the service."""
179
+ request = spb.ServerInformStartRequest()
180
+ request.settings.CopyFrom(settings)
181
+ request._info.stream_id = run_id
182
+ self._client.send(inform_start=request)
183
+
184
+ def teardown(self, exit_code: int) -> int:
185
+ """Shuts down the service process and returns its exit code.
186
+
187
+ This may only be called once.
188
+
189
+ Returns:
190
+ The exit code of the service process.
191
+
192
+ Raises:
193
+ WandbServiceNotOwnedError: If the current process did not start
194
+ the service process.
195
+ """
196
+ if not self._proc:
197
+ raise WandbServiceNotOwnedError(
198
+ "Cannot tear down service started by different process",
199
+ )
200
+
201
+ assert not self._torn_down
202
+ self._torn_down = True
203
+
204
+ if self._cleanup:
205
+ self._cleanup()
206
+
207
+ # Clear the service token to prevent new connections from being made.
208
+ service_token.clear_service_token()
209
+
210
+ self._client.send(
211
+ inform_teardown=spb.ServerInformTeardownRequest(
212
+ exit_code=exit_code,
213
+ )
214
+ )
215
+
216
+ return self._proc.join()
@@ -0,0 +1,94 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import os
5
+
6
+ from wandb import env
7
+
8
+ _CURRENT_VERSION = "2"
9
+ _SUPPORTED_TRANSPORTS = "tcp"
10
+
11
+
12
+ def get_service_token() -> ServiceToken | None:
13
+ """Reads the token from environment variables.
14
+
15
+ Returns:
16
+ The token if the correct environment variable is set, or None.
17
+
18
+ Raises:
19
+ ValueError: If the environment variable is set but cannot be
20
+ parsed.
21
+ """
22
+ token = os.environ.get(env.SERVICE)
23
+ if not token:
24
+ return None
25
+
26
+ parts = token.split("-")
27
+ if len(parts) != 5:
28
+ raise ValueError(f"Invalid token: {token}")
29
+
30
+ version, pid_str, transport, host, port_str = parts
31
+
32
+ if version != _CURRENT_VERSION:
33
+ raise ValueError(
34
+ f"Expected version {_CURRENT_VERSION},"
35
+ f" but got {version} (token={token})"
36
+ )
37
+ if transport not in _SUPPORTED_TRANSPORTS:
38
+ raise ValueError(
39
+ f"Unsupported transport: {transport} (token={token})",
40
+ )
41
+
42
+ try:
43
+ return ServiceToken(
44
+ version=version,
45
+ pid=int(pid_str),
46
+ transport=transport,
47
+ host=host,
48
+ port=int(port_str),
49
+ )
50
+ except ValueError as e:
51
+ raise ValueError(f"Invalid token: {token}") from e
52
+
53
+
54
+ def set_service_token(parent_pid: int, transport: str, host: str, port: int) -> None:
55
+ """Stores a service token in an environment variable.
56
+
57
+ Args:
58
+ parent_pid: The process ID of the process that started the service.
59
+ transport: The transport used to communicate with the service.
60
+ host: The host part of the internet address on which the service
61
+ is listening (e.g. localhost).
62
+ port: The port the service is listening on.
63
+
64
+ Raises:
65
+ ValueError: If given an unsupported transport.
66
+ """
67
+ if transport not in _SUPPORTED_TRANSPORTS:
68
+ raise ValueError(f"Unsupported transport: {transport}")
69
+
70
+ os.environ[env.SERVICE] = "-".join(
71
+ (
72
+ _CURRENT_VERSION,
73
+ str(parent_pid),
74
+ transport,
75
+ host,
76
+ str(port),
77
+ )
78
+ )
79
+
80
+
81
+ def clear_service_token() -> None:
82
+ """Clears the environment variable storing the service token."""
83
+ os.environ.pop(env.SERVICE, None)
84
+
85
+
86
+ @dataclasses.dataclass(frozen=True)
87
+ class ServiceToken:
88
+ """An identifier for a running service process."""
89
+
90
+ version: str
91
+ pid: int
92
+ transport: str
93
+ host: str
94
+ port: int
@@ -14,9 +14,11 @@ if TYPE_CHECKING:
14
14
 
15
15
 
16
16
  class SockClientClosedError(Exception):
17
- """Socket has been closed."""
17
+ """Raised on operations on a closed socket."""
18
18
 
19
- pass
19
+
20
+ class SockClientTimeoutError(Exception):
21
+ """Raised if the server didn't respond before the timeout."""
20
22
 
21
23
 
22
24
  class SockBuffer:
@@ -182,8 +184,10 @@ class SockClient:
182
184
  # it should be relatively stable.
183
185
  # This pass would be solved as part of the fix in https://wandb.atlassian.net/browse/WB-8709
184
186
  response = self.read_server_response(timeout=1)
187
+
185
188
  if response is None:
186
- raise Exception("No response")
189
+ raise SockClientTimeoutError("No response after 1 second.")
190
+
187
191
  return response
188
192
 
189
193
  def send(
@@ -20,7 +20,6 @@ class WandbServer:
20
20
  _pid: Optional[int]
21
21
  _sock_port: Optional[int]
22
22
  _debug: bool
23
- _serve_sock: bool
24
23
  _sock_server: Optional[SocketServer]
25
24
  _startup_debug_enabled: bool
26
25
 
@@ -31,14 +30,12 @@ class WandbServer:
31
30
  address: Optional[str] = None,
32
31
  pid: Optional[int] = None,
33
32
  debug: bool = True,
34
- serve_sock: bool = False,
35
33
  ) -> None:
36
34
  self._sock_port = sock_port
37
35
  self._port_fname = port_fname
38
36
  self._address = address
39
37
  self._pid = pid
40
38
  self._debug = debug
41
- self._serve_sock = serve_sock
42
39
  self._sock_server = None
43
40
  self._startup_debug_enabled = _startup_debug.is_enabled()
44
41
 
@@ -97,7 +94,7 @@ class WandbServer:
97
94
  pid = str(self._pid or 0)
98
95
  transport = "s" if sock_port else "g"
99
96
  port = sock_port or 0
100
- # this format is similar to wandb_manager token, but it's purely informative now
97
+ # this format is similar to the service token, but it's purely informative now
101
98
  # (consider unifying this in the future)
102
99
  service_id = f"{service_ver}-{pid}-{transport}-{port}"
103
100
  proc_title = f"wandb-service({service_id})"
@@ -109,7 +106,7 @@ class WandbServer:
109
106
  self._setup_tracelog()
110
107
  mux = StreamMux()
111
108
  self._startup_debug_print("before_network")
112
- sock_port = self._start_sock(mux=mux) if self._serve_sock else None
109
+ sock_port = self._start_sock(mux=mux)
113
110
  self._startup_debug_print("after_network")
114
111
  self._inform_used_ports(sock_port=sock_port)
115
112
  self._startup_debug_print("after_inform")
@@ -21,8 +21,6 @@ from wandb.sdk.lib.wburls import wburls
21
21
  from wandb.util import get_core_path, get_module
22
22
 
23
23
  from . import _startup_debug, port_file
24
- from .service_base import ServiceInterface
25
- from .service_sock import ServiceSockInterface
26
24
 
27
25
  if TYPE_CHECKING:
28
26
  from wandb.sdk.wandb_settings import Settings
@@ -31,25 +29,18 @@ if TYPE_CHECKING:
31
29
  class ServiceStartProcessError(Error):
32
30
  """Raised when a known error occurs when launching wandb service."""
33
31
 
34
- pass
35
-
36
32
 
37
33
  class ServiceStartTimeoutError(Error):
38
34
  """Raised when service start times out."""
39
35
 
40
- pass
41
-
42
36
 
43
37
  class ServiceStartPortError(Error):
44
38
  """Raised when service start fails to find a port."""
45
39
 
46
- pass
47
-
48
40
 
49
41
  class _Service:
50
42
  _settings: "Settings"
51
43
  _sock_port: Optional[int]
52
- _service_interface: ServiceInterface
53
44
  _internal_proc: Optional[subprocess.Popen]
54
45
  _startup_debug_enabled: bool
55
46
 
@@ -65,10 +56,6 @@ class _Service:
65
56
 
66
57
  _sentry.configure_scope(tags=dict(settings), process_context="service")
67
58
 
68
- # current code only supports socket server implementation, in the
69
- # future we might be able to support both
70
- self._service_interface = ServiceSockInterface()
71
-
72
59
  def _startup_debug_print(self, message: str) -> None:
73
60
  if not self._startup_debug_enabled:
74
61
  return
@@ -175,10 +162,6 @@ class _Service:
175
162
  if core_debug(default="False"):
176
163
  service_args.append("--debug")
177
164
 
178
- trace_filename = os.environ.get("_WANDB_TRACE")
179
- if trace_filename is not None:
180
- service_args.extend(["--trace", trace_filename])
181
-
182
165
  exec_cmd_list = []
183
166
  termlog(
184
167
  "Using wandb-core as the SDK backend."
@@ -194,7 +177,6 @@ class _Service:
194
177
  "--pid",
195
178
  pid,
196
179
  ]
197
- service_args.append("--serve-sock")
198
180
 
199
181
  if os.environ.get("WANDB_SERVICE_PROFILE") == "memray":
200
182
  _ = get_module(
@@ -253,10 +235,6 @@ class _Service:
253
235
  def sock_port(self) -> Optional[int]:
254
236
  return self._sock_port
255
237
 
256
- @property
257
- def service_interface(self) -> ServiceInterface:
258
- return self._service_interface
259
-
260
238
  def join(self) -> int:
261
239
  ret = 0
262
240
  if self._internal_proc:
wandb/sdk/wandb_init.py CHANGED
@@ -655,9 +655,9 @@ class _WandbInit:
655
655
  f"Successfully finished last run (ID:{latest_run._run_id}). Initializing new run:<br/>"
656
656
  )
657
657
  elif isinstance(wandb.run, Run):
658
- manager = self._wl._get_manager()
658
+ service = self._wl.service
659
659
  # We shouldn't return a stale global run if we are in a new pid
660
- if not manager or os.getpid() == wandb.run._init_pid:
660
+ if not service or os.getpid() == wandb.run._init_pid:
661
661
  logger.info("wandb.init() called when a run is still active")
662
662
  with telemetry.context() as tel:
663
663
  tel.feature.init_return_run = True
@@ -665,15 +665,20 @@ class _WandbInit:
665
665
 
666
666
  logger.info("starting backend")
667
667
 
668
- manager = self._wl._get_manager()
669
- if manager:
670
- logger.info("setting up manager")
671
- manager._inform_init(
672
- settings=self.settings.to_proto(), run_id=self.settings.run_id
668
+ service = self._wl.service
669
+ if service:
670
+ logger.info("sending inform_init request")
671
+ service.inform_init(
672
+ settings=self.settings.to_proto(),
673
+ run_id=self.settings.run_id,
673
674
  )
674
675
 
675
676
  mailbox = Mailbox()
676
- backend = Backend(settings=self.settings, manager=manager, mailbox=mailbox)
677
+ backend = Backend(
678
+ settings=self.settings,
679
+ service=service,
680
+ mailbox=mailbox,
681
+ )
677
682
  backend.ensure_launched()
678
683
  logger.info("backend started and connected")
679
684
  # Make sure we are logged in
@@ -739,7 +744,7 @@ class _WandbInit:
739
744
  if os.environ.get(wandb.env._DISABLE_SERVICE):
740
745
  tel.feature.service_disabled = True
741
746
 
742
- if manager:
747
+ if service:
743
748
  tel.feature.service = True
744
749
  if self.settings._flow_control_disabled:
745
750
  tel.feature.flow_control_disabled = True
@@ -830,7 +835,7 @@ class _WandbInit:
830
835
 
831
836
  if error is not None:
832
837
  logger.error(f"encountered error: {error}")
833
- if not manager:
838
+ if not service:
834
839
  # Shutdown the backend and get rid of the logger
835
840
  # we don't need to do console cleanup at this point
836
841
  backend.cleanup()
@@ -857,9 +862,10 @@ class _WandbInit:
857
862
  logger.info("starting run threads in backend")
858
863
  # initiate run (stats and metadata probing)
859
864
 
860
- if manager:
861
- manager._inform_start(
862
- settings=self.settings.to_proto(), run_id=self.settings.run_id
865
+ if service:
866
+ service.inform_start(
867
+ settings=self.settings.to_proto(),
868
+ run_id=self.settings.run_id,
863
869
  )
864
870
 
865
871
  assert backend.interface
@@ -934,33 +940,37 @@ def _attach(
934
940
  if logger is None:
935
941
  raise UsageError("logger is not initialized")
936
942
 
937
- manager = _wl._get_manager()
938
- response = manager._inform_attach(attach_id=attach_id) if manager else None
939
- if response is None:
940
- raise UsageError(f"Unable to attach to run {attach_id}")
943
+ service = _wl.service
944
+ if not service:
945
+ raise UsageError(f"Unable to attach to run {attach_id} (no service process)")
946
+
947
+ try:
948
+ attach_settings = service.inform_attach(attach_id=attach_id)
949
+ except Exception as e:
950
+ raise UsageError(f"Unable to attach to run {attach_id}") from e
941
951
 
942
952
  settings: Settings = copy.copy(_wl._settings)
943
953
 
944
954
  settings.update(
945
955
  {
946
956
  "run_id": attach_id,
947
- "_start_time": response._start_time.value,
948
- "_start_datetime": response._start_datetime.value,
949
- "_offline": response._offline.value,
957
+ "_start_time": attach_settings._start_time.value,
958
+ "_start_datetime": attach_settings._start_datetime.value,
959
+ "_offline": attach_settings._offline.value,
950
960
  },
951
961
  source=Source.INIT,
952
962
  )
953
963
 
954
964
  # TODO: consolidate this codepath with wandb.init()
955
965
  mailbox = Mailbox()
956
- backend = Backend(settings=settings, manager=manager, mailbox=mailbox)
966
+ backend = Backend(settings=settings, service=service, mailbox=mailbox)
957
967
  backend.ensure_launched()
958
968
  logger.info("attach backend started and connected")
959
969
 
960
970
  if run is None:
961
971
  run = Run(settings=settings)
962
972
  else:
963
- run._init()
973
+ run._init(settings=settings)
964
974
  run._set_library(_wl)
965
975
  run._set_backend(backend)
966
976
  backend._hack_set_run(run)