swbt-python 0.5.3__py3-none-any.whl → 0.6.0__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/gamepad/interface.py CHANGED
@@ -121,11 +121,11 @@ class SwitchGamepad(ABC):
121
121
  await self._runtime.open()
122
122
 
123
123
  async def pair(self, timeout: float | None = None) -> None: # noqa: ASYNC109
124
- """Start pairing advertising and wait until the controller is ready for input.
124
+ """Start pairing and wait until the controller can accept normal input.
125
125
 
126
126
  Args:
127
- timeout: Maximum seconds for link connection and protocol initialization.
128
- ``None`` waits without a deadline.
127
+ timeout: Maximum seconds for link connection, protocol initialization,
128
+ and normal-input readiness. ``None`` waits without a deadline.
129
129
 
130
130
  Raises:
131
131
  ConnectionTimeoutError: The timeout elapsed before a connection completed.
@@ -134,15 +134,15 @@ class SwitchGamepad(ABC):
134
134
  await self._runtime.pair(timeout=timeout)
135
135
 
136
136
  async def reconnect(self, timeout: float | None = None) -> None: # noqa: ASYNC109
137
- """Reconnect with exactly one bonded peer and raise on failure.
137
+ """Reconnect with one bonded peer and wait until normal input can begin.
138
138
 
139
139
  Args:
140
- timeout: Maximum seconds for the active reconnect attempt. ``None`` uses
141
- the transport default.
140
+ timeout: Maximum seconds for the active reconnect attempt and
141
+ normal-input readiness. ``None`` uses the transport default.
142
142
 
143
143
  Raises:
144
144
  ConnectionFailedError: No single bonded peer was available or reconnect failed.
145
- ConnectionTimeoutError: The active reconnect attempt timed out.
145
+ ConnectionTimeoutError: The reconnect or normal-input readiness timed out.
146
146
  InvalidKeyStoreError: The key store cannot identify one current peer.
147
147
  """
148
148
  await self._runtime.reconnect(timeout=timeout)
@@ -154,11 +154,12 @@ class SwitchGamepad(ABC):
154
154
  """Try active reconnect with exactly one bonded peer.
155
155
 
156
156
  Args:
157
- timeout: Maximum seconds for the active reconnect attempt. ``None`` uses
158
- the transport default.
157
+ timeout: Maximum seconds for the active reconnect attempt and
158
+ normal-input readiness. ``None`` uses the transport default.
159
159
 
160
160
  Returns:
161
- Reconnect route, status, selected peer, and peer count.
161
+ Reconnect route, status, selected peer, and peer count. ``connected``
162
+ means that normal input can begin.
162
163
 
163
164
  Raises:
164
165
  InvalidKeyStoreError: The key store cannot identify one current peer.
@@ -171,7 +172,7 @@ class SwitchGamepad(ABC):
171
172
  timeout: float | None = None, # noqa: ASYNC109
172
173
  allow_pairing: bool = False,
173
174
  ) -> None:
174
- """Connect using bonded reconnect first, then optional pairing fallback.
175
+ """Connect by bonded reconnect or pairing and wait for normal-input readiness.
175
176
 
176
177
  Args:
177
178
  timeout: Maximum seconds for each connection attempt. ``None`` uses the
@@ -199,7 +200,8 @@ class SwitchGamepad(ABC):
199
200
  allow_pairing: If ``True``, run pairing when no bonded peer is available.
200
201
 
201
202
  Returns:
202
- Route and status chosen by reconnect or pairing fallback.
203
+ Route and status chosen by reconnect or pairing fallback. ``connected``
204
+ means that normal input can begin.
203
205
 
204
206
  Raises:
205
207
  InvalidKeyStoreError: The key store cannot identify one current peer.
@@ -375,7 +377,8 @@ class PeriodicSwitchGamepad(SwitchGamepad):
375
377
  diagnostics: Optional diagnostics configuration for trace output.
376
378
 
377
379
  Returns:
378
- The protocol-ready periodic controller. The caller owns its lifetime.
380
+ A periodic controller ready to accept normal input. The caller owns
381
+ its lifetime.
379
382
 
380
383
  Raises:
381
384
  ValueError: ``local_address`` is invalid.
@@ -440,7 +443,8 @@ class DirectSwitchGamepad(SwitchGamepad):
440
443
  diagnostics: Optional diagnostics configuration for trace output.
441
444
 
442
445
  Returns:
443
- The protocol-ready direct controller. The caller owns its lifetime.
446
+ A direct controller ready to accept normal input. The caller owns
447
+ its lifetime.
444
448
 
445
449
  Raises:
446
450
  ValueError: ``local_address`` is invalid.
swbt/gamepad/runtime.py CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  import asyncio
4
4
  from collections.abc import Awaitable, Callable
5
+ from contextlib import suppress
5
6
  from dataclasses import replace
7
+ from time import monotonic
6
8
  from typing import Literal
7
9
 
8
10
  import swbt.gamepad as gamepad_module
@@ -48,6 +50,8 @@ class ControllerRuntime:
48
50
  diagnostics: DiagnosticsConfig | None = None,
49
51
  reporting_mode: Literal["periodic", "direct"] = "periodic",
50
52
  transport: HidDeviceTransport | None = None,
53
+ _report_sender_monotonic_time: Callable[[], float] = monotonic,
54
+ _report_sender_sleep: Callable[[float], Awaitable[None]] = asyncio.sleep,
51
55
  ) -> None:
52
56
  """Create a fully initialized gamepad runtime.
53
57
 
@@ -57,6 +61,8 @@ class ControllerRuntime:
57
61
  reporting_mode: Owner of normal input report scheduling.
58
62
  transport: Optional HID transport instance. When supplied, no Bumble
59
63
  transport is created by the constructor.
64
+ _report_sender_monotonic_time: Internal holdoff clock override for tests.
65
+ _report_sender_sleep: Internal holdoff sleep override for tests.
60
66
 
61
67
  Raises:
62
68
  InvalidInputError: ``adapter`` is omitted for the default transport.
@@ -68,6 +74,8 @@ class ControllerRuntime:
68
74
  self._reporting_mode = reporting_mode
69
75
  self._transport = transport
70
76
  self._transport_was_injected = transport is not None
77
+ self._report_sender_monotonic_time = _report_sender_monotonic_time
78
+ self._report_sender_sleep = _report_sender_sleep
71
79
  self._pairing_profile: PairingProfile | None = None
72
80
  self._state_store = InputStateStore()
73
81
  self._diagnostics = DiagnosticsRecorder(
@@ -94,6 +102,7 @@ class ControllerRuntime:
94
102
  self._report_loop: ReportLoop | None = None
95
103
  self._report_sender: ReportSender | None = None
96
104
  self._protocol_handshake: ProtocolHandshake | None = None
105
+ self._input_readiness_task: asyncio.Task[None] | None = None
97
106
  self._input_operation_lock = asyncio.Lock()
98
107
  self._lifecycle_lock = asyncio.Lock()
99
108
  self._connected_event = asyncio.Event()
@@ -139,6 +148,8 @@ class ControllerRuntime:
139
148
  ),
140
149
  session=self._protocol_session,
141
150
  diagnostics=self._diagnostics,
151
+ monotonic_time=self._report_sender_monotonic_time,
152
+ _sleep=self._report_sender_sleep,
142
153
  )
143
154
  self._report_sender = report_sender
144
155
  self._connection_state = "opened"
@@ -161,14 +172,14 @@ class ControllerRuntime:
161
172
  self._configured_device_info_bluetooth_address = None
162
173
 
163
174
  async def pair(self, timeout: float | None = None) -> None: # noqa: ASYNC109
164
- """Start pairing advertising and wait until the controller is ready for input.
175
+ """Start pairing and wait until the controller can accept normal input.
165
176
 
166
177
  Args:
167
- timeout: Maximum seconds for link connection and protocol initialization.
168
- ``None`` waits without a deadline.
178
+ timeout: Maximum seconds for link connection, protocol initialization,
179
+ and normal-input readiness. ``None`` waits without a deadline.
169
180
 
170
181
  Raises:
171
- ConnectionTimeoutError: The deadline elapsed before protocol readiness.
182
+ ConnectionTimeoutError: The deadline elapsed before normal-input readiness.
172
183
  ConnectionFailedError: Protocol initialization or the link failed.
173
184
  ClosedError: The transport was unavailable after opening.
174
185
  """
@@ -186,7 +197,7 @@ class ControllerRuntime:
186
197
  raise ClosedError(msg)
187
198
  await self._transport.start_advertising()
188
199
  self._configure_device_info_bluetooth_address(self._transport)
189
- await self._wait_for_protocol_ready(None)
200
+ await self._wait_for_input_ready(None)
190
201
 
191
202
  try:
192
203
  if timeout is None:
@@ -194,6 +205,9 @@ class ControllerRuntime:
194
205
  else:
195
206
  async with asyncio.timeout(timeout):
196
207
  await advertise_and_wait()
208
+ except asyncio.CancelledError:
209
+ await self._stop_input_readiness_wait()
210
+ raise
197
211
  except TimeoutError as error:
198
212
  msg = "connection timed out"
199
213
  connection_error = ConnectionTimeoutError(msg)
@@ -204,7 +218,7 @@ class ControllerRuntime:
204
218
  ),
205
219
  player_lights=_format_optional_byte(self._protocol_session.state.player_lights),
206
220
  report_mode=_format_optional_byte(self._protocol_session.state.report_mode),
207
- stage="protocol_initialization",
221
+ stage=self._connection_readiness_stage(),
208
222
  state=self._connection_state,
209
223
  timeout=timeout,
210
224
  )
@@ -216,15 +230,15 @@ class ControllerRuntime:
216
230
  raise
217
231
 
218
232
  async def reconnect(self, timeout: float | None = None) -> None: # noqa: ASYNC109
219
- """Reconnect with exactly one bonded peer and raise on failure.
233
+ """Reconnect with one bonded peer and wait until normal input can begin.
220
234
 
221
235
  Args:
222
- timeout: Maximum seconds for the active reconnect attempt. ``None`` uses
223
- the transport default.
236
+ timeout: Maximum seconds for the active reconnect attempt and
237
+ normal-input readiness. ``None`` uses the transport default.
224
238
 
225
239
  Raises:
226
240
  ConnectionFailedError: No single bonded peer was available or reconnect failed.
227
- ConnectionTimeoutError: The active reconnect attempt timed out.
241
+ ConnectionTimeoutError: The reconnect or normal-input readiness timed out.
228
242
  """
229
243
  result = await self.try_reconnect(timeout=timeout)
230
244
  self._raise_if_connection_failed(result)
@@ -236,8 +250,8 @@ class ControllerRuntime:
236
250
  """Try active reconnect with exactly one bonded peer.
237
251
 
238
252
  Args:
239
- timeout: Maximum seconds for the active reconnect attempt. ``None`` uses
240
- the transport default.
253
+ timeout: Maximum seconds for the active reconnect attempt and
254
+ normal-input readiness. ``None`` uses the transport default.
241
255
 
242
256
  Returns:
243
257
  ConnectionResult: Reconnect route, status, selected peer, and peer count.
@@ -308,6 +322,7 @@ class ControllerRuntime:
308
322
  )
309
323
  except asyncio.CancelledError as error:
310
324
  if _current_task_is_cancelling():
325
+ await self._stop_input_readiness_wait()
311
326
  raise
312
327
  return await self._record_active_reconnect_transport_error(
313
328
  error,
@@ -406,6 +421,7 @@ class ControllerRuntime:
406
421
  except Exception as error: # noqa: BLE001
407
422
  self._diagnostics.record_error(error, recoverable=True)
408
423
  await self._stop_protocol_handshake()
424
+ await self._stop_input_readiness_wait()
409
425
  if self._report_loop is not None:
410
426
  await self._report_loop.stop()
411
427
  self._disconnect_event.clear()
@@ -820,7 +836,7 @@ class ControllerRuntime:
820
836
 
821
837
  async def _wait_for_reconnect_connected(self, *, max_wait: float | None) -> None:
822
838
  try:
823
- await self._wait_for_protocol_ready(max_wait)
839
+ await self._wait_for_input_ready(max_wait)
824
840
  except TimeoutError as error:
825
841
  self._diagnostics.record_event(
826
842
  "connection_timeout",
@@ -830,13 +846,13 @@ class ControllerRuntime:
830
846
  player_lights=_format_optional_byte(self._protocol_session.state.player_lights),
831
847
  report_mode=_format_optional_byte(self._protocol_session.state.report_mode),
832
848
  route="active_reconnect",
833
- stage="protocol_initialization",
849
+ stage=self._connection_readiness_stage(),
834
850
  state=self._connection_state,
835
851
  timeout=max_wait,
836
852
  )
837
853
  raise TimeoutError from error
838
854
 
839
- async def _wait_for_protocol_ready(self, max_wait: float | None) -> None:
855
+ async def _wait_for_input_ready(self, max_wait: float | None) -> None:
840
856
  if max_wait is None:
841
857
  await self._connection_attempt_event.wait()
842
858
  else:
@@ -844,9 +860,14 @@ class ControllerRuntime:
844
860
  await self._connection_attempt_event.wait()
845
861
  if self._connected_event.is_set():
846
862
  return
847
- msg = "protocol initialization failed"
863
+ msg = "connection initialization failed"
848
864
  raise ConnectionFailedError(msg) from self._connection_attempt_error
849
865
 
866
+ def _connection_readiness_stage(self) -> str:
867
+ if self._protocol_session.state.protocol_ready:
868
+ return "input_readiness"
869
+ return "protocol_initialization"
870
+
850
871
  def _record_disconnect_request_result(self, result: DisconnectRequestResult) -> None:
851
872
  fields: dict[str, object] = {"status": result.status}
852
873
  if result.channels:
@@ -917,6 +938,15 @@ class ControllerRuntime:
917
938
  if handshake is not None:
918
939
  await handshake.stop()
919
940
 
941
+ async def _stop_input_readiness_wait(self) -> None:
942
+ task = self._input_readiness_task
943
+ self._input_readiness_task = None
944
+ if task is None or task is asyncio.current_task():
945
+ return
946
+ task.cancel()
947
+ with suppress(asyncio.CancelledError):
948
+ await task
949
+
920
950
  def _start_periodic_report_loop(self) -> None:
921
951
  if self._transport is None or self._report_loop is not None:
922
952
  return
@@ -950,12 +980,7 @@ class ControllerRuntime:
950
980
  return
951
981
  if self._connected_event.is_set():
952
982
  return
953
- self._connection_state = "connected"
954
- self._connected_event.set()
955
- self._connection_attempt_event.set()
956
983
  self._protocol_handshake = None
957
- if self._reporting_mode == "periodic":
958
- self._start_periodic_report_loop()
959
984
  session_state = self._protocol_session.state
960
985
  self._diagnostics.record_event(
961
986
  "protocol_ready",
@@ -965,6 +990,50 @@ class ControllerRuntime:
965
990
  route=self._connection_route,
966
991
  observed_subcommands=_format_subcommands(session_state.observed_subcommands),
967
992
  )
993
+ if self._reporting_mode == "direct":
994
+ self._publish_input_ready()
995
+ return
996
+ if self._input_readiness_task is not None:
997
+ return
998
+ self._input_readiness_task = asyncio.create_task(
999
+ self._complete_periodic_input_readiness(),
1000
+ name="swbt-input-readiness",
1001
+ )
1002
+
1003
+ async def _complete_periodic_input_readiness(self) -> None:
1004
+ task = asyncio.current_task()
1005
+ sender = self._require_report_sender()
1006
+ try:
1007
+ await sender.wait_until_automatic_input_ready()
1008
+ if (
1009
+ self._close_in_progress
1010
+ or self._connection_attempt_event.is_set()
1011
+ or self._report_sender is not sender
1012
+ ):
1013
+ return
1014
+ self._start_periodic_report_loop()
1015
+ self._publish_input_ready()
1016
+ except asyncio.CancelledError:
1017
+ raise
1018
+ except Exception as error: # noqa: BLE001
1019
+ if not self._close_in_progress:
1020
+ self._record_protocol_initialization_failure(error)
1021
+ finally:
1022
+ if self._input_readiness_task is task:
1023
+ self._input_readiness_task = None
1024
+
1025
+ def _publish_input_ready(self) -> None:
1026
+ if self._connected_event.is_set() or self._connection_attempt_event.is_set():
1027
+ return
1028
+ self._connection_state = "connected"
1029
+ self._connected_event.set()
1030
+ self._connection_attempt_event.set()
1031
+ self._diagnostics.record_event(
1032
+ "input_ready",
1033
+ profile_kind=self._controller_profile.kind.value,
1034
+ reporting_mode=self._reporting_mode,
1035
+ route=self._connection_route,
1036
+ )
968
1037
 
969
1038
  async def _fail_protocol_initialization(self, error: Exception) -> None:
970
1039
  if self._protocol_handshake is not None:
@@ -987,7 +1056,7 @@ class ControllerRuntime:
987
1056
  profile_kind=self._controller_profile.kind.value,
988
1057
  report_mode=_format_optional_byte(self._protocol_session.state.report_mode),
989
1058
  route=self._connection_route,
990
- stage="protocol_initialization",
1059
+ stage=self._connection_readiness_stage(),
991
1060
  )
992
1061
  self._diagnostics.record_error(error, recoverable=False)
993
1062
 
@@ -999,7 +1068,7 @@ class ControllerRuntime:
999
1068
  and not self._connection_attempt_event.is_set()
1000
1069
  and not self._close_in_progress
1001
1070
  ):
1002
- msg = "disconnected before protocol initialization completed"
1071
+ msg = "disconnected before connection initialization completed"
1003
1072
  handshake_failure = ConnectionFailedError(msg)
1004
1073
  if self._protocol_handshake is not None:
1005
1074
  self._protocol_handshake.fail(handshake_failure)
@@ -1014,6 +1083,7 @@ class ControllerRuntime:
1014
1083
  self._protocol_handshake = None
1015
1084
  else:
1016
1085
  await self._stop_protocol_handshake()
1086
+ await self._stop_input_readiness_wait()
1017
1087
  if self._report_loop is not None:
1018
1088
  await self._report_loop.stop()
1019
1089
  self._report_loop = None
swbt/report_loop.py CHANGED
@@ -34,6 +34,7 @@ class ReportSender:
34
34
  diagnostics: DiagnosticsRecorder | None = None,
35
35
  clock_ns: Callable[[], int] = monotonic_ns,
36
36
  monotonic_time: Callable[[], float] = monotonic,
37
+ _sleep: Callable[[float], Awaitable[None]] = asyncio.sleep,
37
38
  ) -> None:
38
39
  """Create a session-scoped serialized report sender."""
39
40
  self._transport = transport
@@ -42,6 +43,7 @@ class ReportSender:
42
43
  self._diagnostics = diagnostics
43
44
  self._clock_ns = clock_ns
44
45
  self._monotonic_time = monotonic_time
46
+ self._sleep = _sleep
45
47
  self._timer = 0
46
48
  self._send_lock = asyncio.Lock()
47
49
  self._automatic_input_holdoff_until = 0.0
@@ -80,6 +82,15 @@ class ReportSender:
80
82
  await self._send_input_locked(state, reason=reason)
81
83
  return True
82
84
 
85
+ async def wait_until_automatic_input_ready(self) -> None:
86
+ """Wait until automatic input is no longer held off by an accepted reply."""
87
+ while True:
88
+ async with self._send_lock:
89
+ remaining = self._automatic_input_holdoff_until - self._monotonic_time()
90
+ if remaining <= 0:
91
+ return
92
+ await self._sleep(remaining)
93
+
83
94
  async def send_subcommand_reply(self, build_report: ReplyBuilder) -> bytes:
84
95
  """Build and send a subcommand reply under the shared send lock."""
85
96
  async with self._send_lock:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swbt-python
3
- Version: 0.5.3
3
+ Version: 0.6.0
4
4
  Summary: Python library for presenting an NX-compatible virtual Bluetooth HID input device.
5
5
  Keywords: bluetooth,bluetooth-hid,controller,gamepad,hid,nx
6
6
  Author: niart120
@@ -14,14 +14,14 @@ Classifier: Operating System :: MacOS
14
14
  Classifier: Operating System :: Microsoft :: Windows
15
15
  Classifier: Operating System :: POSIX :: Linux
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.12
18
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
19
  Classifier: Topic :: Software Development :: Libraries
20
20
  Classifier: Typing :: Typed
21
21
  Requires-Dist: bumble==0.0.233
22
22
  Maintainer: niart120
23
23
  Maintainer-email: niart120 <38847256+niart120@users.noreply.github.com>
24
- Requires-Python: >=3.12
24
+ Requires-Python: >=3.13
25
25
  Description-Content-Type: text/markdown
26
26
 
27
27
  # swbt-python
@@ -32,7 +32,7 @@ NX 向けの仮想 Bluetooth HID 入力デバイスを Python から扱うため
32
32
 
33
33
  ## 必要なもの
34
34
 
35
- - Python 3.12 以降
35
+ - Python 3.13 以降
36
36
  - uv
37
37
  - Bumble が利用可能な専用 USB Bluetooth ドングル
38
38
 
@@ -7,10 +7,10 @@ swbt/gamepad/_config.py,sha256=VjYrR4erPhEohjZ1Pw5ElxryNEa8dRfsKhz2EsjpEUs,2050
7
7
  swbt/gamepad/connection.py,sha256=8EUeKYvdV_n1OIq11MFAVNhKmIbJHUoijaK6xUx6Y4g,753
8
8
  swbt/gamepad/constants.py,sha256=gDesRFvVxZ3SMSiP4qzd42em_Dt9M5hIu3-2exgKEus,84
9
9
  swbt/gamepad/controllers.py,sha256=G6EMi82F_36wSi2pm5QMFLJSZSakRogVcDeygqJJ8gI,7487
10
- swbt/gamepad/interface.py,sha256=quHOOj5nWzBz_W3qYMBEWglo-3zR_I9zxNqlA7HznGI,17525
10
+ swbt/gamepad/interface.py,sha256=HWABzdzrVPAumTZPOrUjiku-mKvAPIhqTE-pvqAIgSU,17793
11
11
  swbt/gamepad/output.py,sha256=NeOp-NwYshEkuelge_POwk_i7orqOQc4SXm9t9Njs1s,5361
12
12
  swbt/gamepad/protocol_handshake.py,sha256=9vAdE0PIpSpWk9oXhStOTq0XxDlE8DejE1SLBh21rx4,6217
13
- swbt/gamepad/runtime.py,sha256=7QrhoqyHx5jy9cjnlNUlJ4xxnQp5_vxfE2SVGZ1Dvtk,44102
13
+ swbt/gamepad/runtime.py,sha256=HVuhQxPtpVpcyxVo2RnWOM5Vkmn2kc9NjhJ9PPWwG4o,47170
14
14
  swbt/gamepad/transport_factory.py,sha256=0eiC-HqtNG0CJuHR8TlSPWtpInW03A4ojnBccqpryN0,921
15
15
  swbt/imu.py,sha256=sT1_MsYECQlQ-pSfayD8gojD9l3w9zEtOI3xP1IovQM,4237
16
16
  swbt/input.py,sha256=7gv75lzrcmoV8Sijz7f1pvsheRrmUi_TCIMW3DjUVjw,22275
@@ -30,7 +30,7 @@ swbt/protocol/session.py,sha256=SVkF0jaJPbnKCAWswRQsrdoCxZwjHPEMz4lktVBcXc4,4811
30
30
  swbt/protocol/spi.py,sha256=buKyNYYOHOSYbpVh3Wa2968FL4VIO_43QcSXNowNfJs,2594
31
31
  swbt/protocol/subcommand.py,sha256=NRtp9-lB8IBimC0kO8oyJnel_qSSPx65XlmGWTARB0E,8662
32
32
  swbt/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
33
- swbt/report_loop.py,sha256=jEnwlxdWQgPwbIXvJfyhgMaJdrGYLNYzlZNotOMKiKw,7853
33
+ swbt/report_loop.py,sha256=zGaKStCsupzkmSTF8YZOL9H2DbH1Nf15yHtI3POJiTY,8350
34
34
  swbt/state_store.py,sha256=jE1TeNpqynbVpxFp0Xt3m1Dfl1LUKR-uqV4f14qntuM,1402
35
35
  swbt/transport/__init__.py,sha256=b_Vqsg0k_g7XclN9XHQrcJxqCwGIklxG5NqzISal4_I,68
36
36
  swbt/transport/_adapter_identity.py,sha256=xOECQBlGAZJoyKrfxrIPt88kXoksHWmWzzVo1-x5XmA,6621
@@ -46,8 +46,8 @@ swbt/transport/_pairing_profile.py,sha256=95tISeYHnllHfFpNs0oBsaYb5uAffXfi9eFkjb
46
46
  swbt/transport/base.py,sha256=eI0hs1wTwJf2ppzqda4ok-tUXF1hE9dwpb0p-lpvwmo,5163
47
47
  swbt/transport/bumble.py,sha256=VufUEo4aUeVebSFvZPJaVe_G7nNz5fKQMCbjgqmBbRs,33414
48
48
  swbt/transport/fake.py,sha256=4O5zlsg1TO61Ai54FGCn_xM8TEA9yi938Fso-XHdh1w,12891
49
- swbt_python-0.5.3.dist-info/licenses/LICENSE,sha256=FzzUoYjuIh5DzpeaujIbDUTylYnyzcHRVU-_ZMyowyk,1065
50
- swbt_python-0.5.3.dist-info/WHEEL,sha256=uOqnPWqgFlbov4NeTCercq7cBQ2UN7xh5fiW55lOnAg,81
51
- swbt_python-0.5.3.dist-info/entry_points.txt,sha256=YYQc7VgoSy74iZ6s8Qr6iJpnvFoDpp8G4-v0KJH5TGo,48
52
- swbt_python-0.5.3.dist-info/METADATA,sha256=W59IobyxaCz0_nIchUTIqNv24T9XjR9d7CuarGeItW0,5902
53
- swbt_python-0.5.3.dist-info/RECORD,,
49
+ swbt_python-0.6.0.dist-info/licenses/LICENSE,sha256=FzzUoYjuIh5DzpeaujIbDUTylYnyzcHRVU-_ZMyowyk,1065
50
+ swbt_python-0.6.0.dist-info/WHEEL,sha256=uOqnPWqgFlbov4NeTCercq7cBQ2UN7xh5fiW55lOnAg,81
51
+ swbt_python-0.6.0.dist-info/entry_points.txt,sha256=YYQc7VgoSy74iZ6s8Qr6iJpnvFoDpp8G4-v0KJH5TGo,48
52
+ swbt_python-0.6.0.dist-info/METADATA,sha256=uYO6HjCv9WQ4YTzUKV4gIn-L4LvMOeVWAzEh37GL6RA,5902
53
+ swbt_python-0.6.0.dist-info/RECORD,,