swbt-python 0.5.0__py3-none-any.whl → 0.5.2__py3-none-any.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.
swbt/diagnostics.py CHANGED
@@ -67,21 +67,16 @@ class GamepadStatus:
67
67
 
68
68
 
69
69
  class DiagnosticsRecorder:
70
- """Record a small in-memory diagnostics event history."""
70
+ """Record bounded diagnostics aggregates and optional JSON Lines traces."""
71
71
 
72
72
  def __init__(self, trace_writer: TextIO | None = None) -> None:
73
73
  """Create an empty recorder."""
74
- self._events: list[DiagnosticsEvent] = []
75
74
  self._report_counters: dict[int, int] = {}
76
75
  self._last_subcommand_id: int | None = None
77
76
  self._raw_rumble: bytes | None = None
77
+ self._last_error: DiagnosticsEvent | None = None
78
78
  self._trace_writer = trace_writer
79
79
 
80
- @property
81
- def events(self) -> tuple[DiagnosticsEvent, ...]:
82
- """Return recorded events in order."""
83
- return tuple(self._events)
84
-
85
80
  @property
86
81
  def report_counters(self) -> dict[int, int]:
87
82
  """Return sent report counters keyed by report ID."""
@@ -100,10 +95,7 @@ class DiagnosticsRecorder:
100
95
  @property
101
96
  def last_error(self) -> DiagnosticsEvent | None:
102
97
  """Return the latest error event."""
103
- for event in reversed(self._events):
104
- if event.event == "error":
105
- return event
106
- return None
98
+ return self._last_error
107
99
 
108
100
  def record_event(self, event: str, **fields: object) -> DiagnosticsEvent:
109
101
  """Record a diagnostics event with schema fields."""
@@ -155,21 +147,6 @@ class DiagnosticsRecorder:
155
147
  **fields,
156
148
  )
157
149
 
158
- def record_state_transition(
159
- self,
160
- *,
161
- previous: str,
162
- next_state: str,
163
- reason: str,
164
- ) -> DiagnosticsEvent:
165
- """Record one lifecycle state transition."""
166
- return self.record_event(
167
- "state_transition",
168
- previous=previous,
169
- next=next_state,
170
- reason=reason,
171
- )
172
-
173
150
  def record_error(self, error: BaseException, *, recoverable: bool) -> DiagnosticsEvent:
174
151
  """Record an exception as an error event."""
175
152
  event = DiagnosticsEvent(
@@ -178,11 +155,11 @@ class DiagnosticsRecorder:
178
155
  message=str(error),
179
156
  recoverable=recoverable,
180
157
  )
158
+ self._last_error = event
181
159
  self._append(event)
182
160
  return event
183
161
 
184
162
  def _append(self, event: DiagnosticsEvent) -> None:
185
- self._events.append(event)
186
163
  if self._trace_writer is None:
187
164
  return
188
165
  payload: dict[str, object] = {"event": event.event}
swbt/gamepad/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  from swbt.gamepad.connection import ConnectionResult, ConnectionStatus
4
4
  from swbt.gamepad.constants import DISCONNECT_REQUEST_TIMEOUT_SECONDS
5
- from swbt.gamepad.core import (
5
+ from swbt.gamepad.controllers import (
6
6
  DirectJoyConL,
7
7
  DirectJoyConR,
8
8
  DirectProController,
swbt/gamepad/_config.py CHANGED
@@ -1,82 +1,14 @@
1
- """Configuration models for gamepad construction and runtime setup."""
1
+ """Normalized configuration for gamepad construction and runtime setup."""
2
2
 
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
 
5
5
  from swbt.errors import InvalidInputError
6
6
  from swbt.protocol.profiles.base import ControllerColors, ControllerProfile
7
- from swbt.protocol.profiles.pro_controller import default_controller_profile
8
7
 
9
8
 
10
- @dataclass(frozen=True)
11
- class _SwitchGamepadConfig:
12
- """Configuration used to construct a concrete gamepad.
13
-
14
- Attributes:
15
- adapter: Bumble adapter moniker, such as ``"usb:0"``.
16
- profile_path: Path to a swbt-owned pairing profile.
17
- profile: Fixed controller identity and protocol profile.
18
- report_period_us: Periodic input report interval in microseconds.
19
- device_name: HID device name advertised to the host.
20
- controller_colors: Fixed controller body, button, and grip colors for SPI profile data.
21
- """
22
-
23
- adapter: str | None = None
24
- profile_path: str | None = None
25
- profile: ControllerProfile = field(default_factory=default_controller_profile)
26
- report_period_us: int | None = None
27
- device_name: str | None = None
28
- controller_colors: ControllerColors | None = None
29
-
30
- def __post_init__(self) -> None:
31
- """Validate resource configuration."""
32
- if not isinstance(self.profile, ControllerProfile):
33
- msg = "profile must be a ControllerProfile"
34
- raise InvalidInputError(msg)
35
- if self.report_period_us is None:
36
- object.__setattr__(
37
- self,
38
- "report_period_us",
39
- self.profile.default_report_period_us,
40
- )
41
- elif self.report_period_us <= 0:
42
- msg = "report_period_us must be positive"
43
- raise InvalidInputError(msg)
44
- if self.device_name is None:
45
- object.__setattr__(self, "device_name", self.profile.device_name)
46
- if self.controller_colors is not None and not isinstance(
47
- self.controller_colors, ControllerColors
48
- ):
49
- msg = "controller_colors must be a ControllerColors"
50
- raise InvalidInputError(msg)
51
-
52
-
53
- @dataclass(frozen=True)
54
- class _ControllerSpec:
55
- """Internal controller identity selected by a concrete controller class."""
56
-
57
- profile: ControllerProfile
58
-
59
- def build_config(
60
- self,
61
- *,
62
- adapter: str | None,
63
- report_period_us: int | None,
64
- controller_colors: ControllerColors | None,
65
- profile_path: str | None = None,
66
- ) -> _SwitchGamepadConfig:
67
- """Create internal construction config from public constructor options."""
68
- return _SwitchGamepadConfig(
69
- adapter=adapter,
70
- profile_path=profile_path,
71
- profile=self.profile,
72
- report_period_us=report_period_us,
73
- controller_colors=controller_colors,
74
- )
75
-
76
-
77
- @dataclass(frozen=True)
78
- class _RuntimeConfig:
79
- """Normalized internal configuration for ControllerRuntime."""
9
+ @dataclass(frozen=True, init=False)
10
+ class _GamepadConfig:
11
+ """Normalized internal configuration shared by a controller and its runtime."""
80
12
 
81
13
  adapter: str | None
82
14
  profile_path: str | None
@@ -85,17 +17,37 @@ class _RuntimeConfig:
85
17
  device_name: str
86
18
  controller_colors: ControllerColors | None
87
19
 
88
- @classmethod
89
- def from_public_config(cls, config: _SwitchGamepadConfig) -> "_RuntimeConfig":
90
- """Create normalized runtime configuration from public construction config."""
91
- if config.report_period_us is None or config.device_name is None:
92
- msg = "_SwitchGamepadConfig was not normalized"
20
+ def __init__(
21
+ self,
22
+ *,
23
+ profile: ControllerProfile,
24
+ adapter: str | None = None,
25
+ profile_path: str | None = None,
26
+ report_period_us: int | None = None,
27
+ device_name: str | None = None,
28
+ controller_colors: ControllerColors | None = None,
29
+ ) -> None:
30
+ """Validate and normalize controller construction values."""
31
+ if not isinstance(profile, ControllerProfile):
32
+ msg = "profile must be a ControllerProfile"
33
+ raise InvalidInputError(msg)
34
+ normalized_report_period = (
35
+ profile.default_report_period_us if report_period_us is None else report_period_us
36
+ )
37
+ if normalized_report_period <= 0:
38
+ msg = "report_period_us must be positive"
93
39
  raise InvalidInputError(msg)
94
- return cls(
95
- adapter=config.adapter,
96
- profile_path=config.profile_path,
97
- profile=config.profile,
98
- report_period_us=config.report_period_us,
99
- device_name=config.device_name,
100
- controller_colors=config.controller_colors,
40
+ if controller_colors is not None and not isinstance(controller_colors, ControllerColors):
41
+ msg = "controller_colors must be a ControllerColors"
42
+ raise InvalidInputError(msg)
43
+
44
+ object.__setattr__(self, "adapter", adapter)
45
+ object.__setattr__(self, "profile_path", profile_path)
46
+ object.__setattr__(self, "profile", profile)
47
+ object.__setattr__(self, "report_period_us", normalized_report_period)
48
+ object.__setattr__(
49
+ self,
50
+ "device_name",
51
+ profile.device_name if device_name is None else device_name,
101
52
  )
53
+ object.__setattr__(self, "controller_colors", controller_colors)
@@ -1,30 +1,11 @@
1
- """Connection workflow for SwitchGamepad."""
1
+ """Public connection result types."""
2
2
 
3
- import asyncio
4
- from collections.abc import Awaitable, Callable
5
3
  from dataclasses import dataclass
6
4
  from typing import Literal
7
5
 
8
- from swbt.diagnostics import DiagnosticsRecorder
9
- from swbt.errors import (
10
- ClosedError,
11
- ConnectionFailedError,
12
- ConnectionTimeoutError,
13
- InvalidKeyStoreError,
14
- )
15
- from swbt.transport.base import HidDeviceTransport
16
-
17
6
  ConnectionRoute = Literal["active_reconnect", "pairing"]
18
7
  ConnectionStatus = Literal["connected", "no_bond", "timeout", "failed"]
19
8
 
20
- EnsureOpen = Callable[[], Awaitable[None]]
21
- TransportProvider = Callable[[], HidDeviceTransport | None]
22
- StateSetter = Callable[[str], None]
23
- EventClearer = Callable[[], None]
24
- WaitForConnected = Callable[[float | None], Awaitable[None]]
25
- CloseNeutral = Callable[[], Awaitable[None]]
26
- PairWithTimeout = Callable[[float | None], Awaitable[None]]
27
-
28
9
 
29
10
  @dataclass(frozen=True)
30
11
  class ConnectionResult:
@@ -33,196 +14,11 @@ class ConnectionResult:
33
14
  Args:
34
15
  route: Connection path that produced the result.
35
16
  status: Outcome of the connection attempt.
36
- peer_address: Address of the bonded peer used for reconnect, when one was selected.
37
- peer_count: Number of bonded peers observed while selecting a reconnect target.
38
-
39
- Attributes:
40
- route: Connection path that produced the result.
41
- status: Outcome of the connection attempt.
42
- peer_address: Address of the bonded peer used for reconnect, when one was selected.
43
- peer_count: Number of bonded peers observed while selecting a reconnect target.
17
+ peer_address: Address used for active reconnect, when one was selected.
18
+ peer_count: Number of current peers observed while selecting a reconnect target.
44
19
  """
45
20
 
46
21
  route: ConnectionRoute
47
22
  status: ConnectionStatus
48
23
  peer_address: str | None = None
49
24
  peer_count: int | None = None
50
-
51
-
52
- @dataclass
53
- class ConnectionWorkflow:
54
- """Run active reconnect and pairing fallback workflows."""
55
-
56
- clear_connected: EventClearer
57
- close_neutral: CloseNeutral
58
- diagnostics: DiagnosticsRecorder
59
- ensure_open: EnsureOpen
60
- get_transport: TransportProvider
61
- profile_path: str | None
62
- pair: PairWithTimeout
63
- set_connection_state: StateSetter
64
- transport_was_injected: bool
65
- wait_for_connected: WaitForConnected
66
-
67
- async def try_reconnect(
68
- self,
69
- timeout: float | None = None, # noqa: ASYNC109
70
- ) -> ConnectionResult:
71
- """Try active reconnect with exactly one bonded peer."""
72
- await self.ensure_open()
73
- transport = self._transport()
74
- if self.profile_path is None and not self.transport_was_injected:
75
- self.diagnostics.record_event(
76
- "reconnect_profile_unavailable",
77
- reason="profile_path_none",
78
- route="active_reconnect",
79
- )
80
- peers = await transport.list_bonded_peers()
81
- if len(peers) > 1:
82
- self.diagnostics.record_event(
83
- "invalid_key_store",
84
- peer_count=len(peers),
85
- reason="multiple_current_peers",
86
- )
87
- msg = "key store contains multiple current peers"
88
- raise InvalidKeyStoreError(msg)
89
- selection = _bonded_peer_selection(len(peers))
90
- self.diagnostics.record_event(
91
- "bonded_peers_discovered",
92
- peer_count=len(peers),
93
- selection=selection,
94
- )
95
- if not peers:
96
- self.diagnostics.record_event(
97
- "active_reconnect_result",
98
- peer_count=0,
99
- route="active_reconnect",
100
- status="no_bond",
101
- )
102
- return ConnectionResult(
103
- route="active_reconnect",
104
- status="no_bond",
105
- peer_count=0,
106
- )
107
- peer = peers[0]
108
- self.set_connection_state("reconnecting")
109
- self.clear_connected()
110
- self.diagnostics.record_event(
111
- "active_reconnect_attempt",
112
- peer_address=peer.address,
113
- route="active_reconnect",
114
- )
115
- try:
116
- await transport.connect_bonded_peer(
117
- peer.address,
118
- connect_timeout=timeout,
119
- )
120
- await self.wait_for_connected(timeout)
121
- except TimeoutError:
122
- self.diagnostics.record_event(
123
- "active_reconnect_result",
124
- failure_reason="connection_timeout",
125
- peer_address=peer.address,
126
- route="active_reconnect",
127
- status="timeout",
128
- )
129
- await self.close_neutral()
130
- return ConnectionResult(
131
- route="active_reconnect",
132
- status="timeout",
133
- peer_address=peer.address,
134
- peer_count=1,
135
- )
136
- except asyncio.CancelledError as error:
137
- if _current_task_is_cancelling():
138
- raise
139
- return await self._record_transport_error(error, peer_address=peer.address)
140
- except Exception as error: # noqa: BLE001
141
- return await self._record_transport_error(error, peer_address=peer.address)
142
-
143
- self.diagnostics.record_event(
144
- "active_reconnect_result",
145
- peer_address=peer.address,
146
- route="active_reconnect",
147
- status="connected",
148
- )
149
- return ConnectionResult(
150
- route="active_reconnect",
151
- status="connected",
152
- peer_address=peer.address,
153
- peer_count=1,
154
- )
155
-
156
- async def try_connect(
157
- self,
158
- *,
159
- timeout: float | None = None, # noqa: ASYNC109
160
- allow_pairing: bool = False,
161
- ) -> ConnectionResult:
162
- """Try bonded reconnect first, then optional pairing fallback."""
163
- reconnect_result = await self.try_reconnect(timeout=timeout)
164
- if reconnect_result.status != "no_bond" or not allow_pairing:
165
- return reconnect_result
166
- self.diagnostics.record_event(
167
- "connect_pairing_fallback",
168
- reason="no_bond",
169
- route="pairing",
170
- )
171
- try:
172
- await self.pair(timeout)
173
- except ConnectionTimeoutError:
174
- return ConnectionResult(route="pairing", status="timeout")
175
- return ConnectionResult(route="pairing", status="connected")
176
-
177
- def _transport(self) -> HidDeviceTransport:
178
- transport = self.get_transport()
179
- if transport is None:
180
- msg = "gamepad is not open"
181
- raise ClosedError(msg)
182
- return transport
183
-
184
- async def _record_transport_error(
185
- self,
186
- error: BaseException,
187
- *,
188
- peer_address: str,
189
- ) -> ConnectionResult:
190
- self.diagnostics.record_event(
191
- "active_reconnect_result",
192
- error_type=type(error).__name__,
193
- failure_reason="transport_error",
194
- message=str(error),
195
- peer_address=peer_address,
196
- route="active_reconnect",
197
- status="failed",
198
- )
199
- self.diagnostics.record_error(error, recoverable=True)
200
- await self.close_neutral()
201
- return ConnectionResult(
202
- route="active_reconnect",
203
- status="failed",
204
- peer_address=peer_address,
205
- peer_count=1,
206
- )
207
-
208
-
209
- def raise_if_connection_failed(result: ConnectionResult) -> None:
210
- """Raise the public connection error for a non-connected result."""
211
- if result.status == "connected":
212
- return
213
- if result.status == "timeout":
214
- msg = "connection timed out"
215
- raise ConnectionTimeoutError(msg)
216
- msg = f"connection failed: {result.status}"
217
- raise ConnectionFailedError(msg)
218
-
219
-
220
- def _bonded_peer_selection(peer_count: int) -> str:
221
- if peer_count == 0:
222
- return "none"
223
- return "selected"
224
-
225
-
226
- def _current_task_is_cancelling() -> bool:
227
- task = asyncio.current_task()
228
- return task is not None and task.cancelling() > 0
@@ -0,0 +1,211 @@
1
+ """Public concrete gamepad controllers."""
2
+
3
+ from swbt.diagnostics import DiagnosticsConfig
4
+ from swbt.gamepad.interface import DirectSwitchGamepad, PeriodicSwitchGamepad
5
+ from swbt.protocol.profiles.base import ControllerColors
6
+ from swbt.protocol.profiles.joycon import JoyConLeftProfile, JoyConRightProfile
7
+ from swbt.protocol.profiles.pro_controller import default_controller_profile
8
+
9
+
10
+ class ProController(PeriodicSwitchGamepad):
11
+ """Runtime-backed Pro Controller-compatible gamepad."""
12
+
13
+ _profile = default_controller_profile()
14
+
15
+ def __init__(
16
+ self,
17
+ *,
18
+ adapter: str | None = None,
19
+ profile_path: str | None = None,
20
+ report_period_us: int | None = None,
21
+ controller_colors: ControllerColors | None = None,
22
+ diagnostics: DiagnosticsConfig | None = None,
23
+ ) -> None:
24
+ """Create a Pro Controller-compatible gamepad.
25
+
26
+ Args:
27
+ adapter: Bumble adapter moniker used for the Bluetooth backend.
28
+ profile_path: Optional swbt-owned pairing profile path.
29
+ report_period_us: Optional periodic input report interval in microseconds.
30
+ controller_colors: Optional fixed controller body, button, and grip colors.
31
+ diagnostics: Optional diagnostics configuration for trace output.
32
+
33
+ Raises:
34
+ InvalidInputError: adapter is omitted or report_period_us is not positive.
35
+ """
36
+ self._initialize_runtime(
37
+ adapter=adapter,
38
+ profile_path=profile_path,
39
+ report_period_us=report_period_us,
40
+ controller_colors=controller_colors,
41
+ diagnostics=diagnostics,
42
+ )
43
+
44
+
45
+ class JoyConL(PeriodicSwitchGamepad):
46
+ """Runtime-backed Joy-Con L-compatible gamepad."""
47
+
48
+ _profile = JoyConLeftProfile()
49
+
50
+ def __init__(
51
+ self,
52
+ *,
53
+ adapter: str | None = None,
54
+ profile_path: str | None = None,
55
+ report_period_us: int | None = None,
56
+ controller_colors: ControllerColors | None = None,
57
+ diagnostics: DiagnosticsConfig | None = None,
58
+ ) -> None:
59
+ """Create a left Joy-Con-compatible gamepad.
60
+
61
+ Args:
62
+ adapter: Bumble adapter moniker used for the Bluetooth backend.
63
+ profile_path: Optional swbt-owned pairing profile path.
64
+ report_period_us: Optional periodic input report interval in microseconds.
65
+ controller_colors: Optional fixed controller body, button, and grip colors.
66
+ diagnostics: Optional diagnostics configuration for trace output.
67
+
68
+ Raises:
69
+ InvalidInputError: ``adapter`` is omitted or ``report_period_us`` is not positive.
70
+ """
71
+ self._initialize_runtime(
72
+ adapter=adapter,
73
+ profile_path=profile_path,
74
+ report_period_us=report_period_us,
75
+ controller_colors=controller_colors,
76
+ diagnostics=diagnostics,
77
+ )
78
+
79
+
80
+ class JoyConR(PeriodicSwitchGamepad):
81
+ """Runtime-backed Joy-Con R-compatible gamepad."""
82
+
83
+ _profile = JoyConRightProfile()
84
+
85
+ def __init__(
86
+ self,
87
+ *,
88
+ adapter: str | None = None,
89
+ profile_path: str | None = None,
90
+ report_period_us: int | None = None,
91
+ controller_colors: ControllerColors | None = None,
92
+ diagnostics: DiagnosticsConfig | None = None,
93
+ ) -> None:
94
+ """Create a right Joy-Con-compatible gamepad.
95
+
96
+ Args:
97
+ adapter: Bumble adapter moniker used for the Bluetooth backend.
98
+ profile_path: Optional swbt-owned pairing profile path.
99
+ report_period_us: Optional periodic input report interval in microseconds.
100
+ controller_colors: Optional fixed controller body, button, and grip colors.
101
+ diagnostics: Optional diagnostics configuration for trace output.
102
+
103
+ Raises:
104
+ InvalidInputError: ``adapter`` is omitted or ``report_period_us`` is not positive.
105
+ """
106
+ self._initialize_runtime(
107
+ adapter=adapter,
108
+ profile_path=profile_path,
109
+ report_period_us=report_period_us,
110
+ controller_colors=controller_colors,
111
+ diagnostics=diagnostics,
112
+ )
113
+
114
+
115
+ class DirectProController(DirectSwitchGamepad):
116
+ """Direct-reporting Pro Controller-compatible gamepad."""
117
+
118
+ _profile = default_controller_profile()
119
+
120
+ def __init__(
121
+ self,
122
+ *,
123
+ adapter: str | None = None,
124
+ profile_path: str | None = None,
125
+ controller_colors: ControllerColors | None = None,
126
+ diagnostics: DiagnosticsConfig | None = None,
127
+ ) -> None:
128
+ """Create a direct-reporting Pro Controller-compatible gamepad.
129
+
130
+ Args:
131
+ adapter: Bumble adapter moniker used for the Bluetooth backend.
132
+ profile_path: Optional swbt-owned pairing profile path.
133
+ controller_colors: Optional fixed controller body, button, and grip colors.
134
+ diagnostics: Optional diagnostics configuration for trace output.
135
+
136
+ Raises:
137
+ InvalidInputError: ``adapter`` is omitted.
138
+ """
139
+ self._initialize_runtime(
140
+ adapter=adapter,
141
+ profile_path=profile_path,
142
+ report_period_us=None,
143
+ controller_colors=controller_colors,
144
+ diagnostics=diagnostics,
145
+ )
146
+
147
+
148
+ class DirectJoyConL(DirectSwitchGamepad):
149
+ """Direct-reporting Joy-Con L-compatible gamepad."""
150
+
151
+ _profile = JoyConLeftProfile()
152
+
153
+ def __init__(
154
+ self,
155
+ *,
156
+ adapter: str | None = None,
157
+ profile_path: str | None = None,
158
+ controller_colors: ControllerColors | None = None,
159
+ diagnostics: DiagnosticsConfig | None = None,
160
+ ) -> None:
161
+ """Create a direct-reporting Joy-Con L-compatible gamepad.
162
+
163
+ Args:
164
+ adapter: Bumble adapter moniker used for the Bluetooth backend.
165
+ profile_path: Optional swbt-owned pairing profile path.
166
+ controller_colors: Optional fixed controller body, button, and grip colors.
167
+ diagnostics: Optional diagnostics configuration for trace output.
168
+
169
+ Raises:
170
+ InvalidInputError: ``adapter`` is omitted.
171
+ """
172
+ self._initialize_runtime(
173
+ adapter=adapter,
174
+ profile_path=profile_path,
175
+ report_period_us=None,
176
+ controller_colors=controller_colors,
177
+ diagnostics=diagnostics,
178
+ )
179
+
180
+
181
+ class DirectJoyConR(DirectSwitchGamepad):
182
+ """Direct-reporting Joy-Con R-compatible gamepad."""
183
+
184
+ _profile = JoyConRightProfile()
185
+
186
+ def __init__(
187
+ self,
188
+ *,
189
+ adapter: str | None = None,
190
+ profile_path: str | None = None,
191
+ controller_colors: ControllerColors | None = None,
192
+ diagnostics: DiagnosticsConfig | None = None,
193
+ ) -> None:
194
+ """Create a direct-reporting Joy-Con R-compatible gamepad.
195
+
196
+ Args:
197
+ adapter: Bumble adapter moniker used for the Bluetooth backend.
198
+ profile_path: Optional swbt-owned pairing profile path.
199
+ controller_colors: Optional fixed controller body, button, and grip colors.
200
+ diagnostics: Optional diagnostics configuration for trace output.
201
+
202
+ Raises:
203
+ InvalidInputError: ``adapter`` is omitted.
204
+ """
205
+ self._initialize_runtime(
206
+ adapter=adapter,
207
+ profile_path=profile_path,
208
+ report_period_us=None,
209
+ controller_colors=controller_colors,
210
+ diagnostics=diagnostics,
211
+ )