Skip to content

Commit 5aae44b

Browse files
authored
Merge pull request #501 from zxzxwu/exception
Reorganize exceptions
2 parents e3ea167 + f8a2d4f commit 5aae44b

26 files changed

+260
-159
lines changed

bumble/at.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@
1414

1515
from typing import List, Union
1616

17+
from bumble import core
18+
19+
20+
class AtParsingError(core.InvalidPacketError):
21+
"""Error raised when parsing AT commands fails."""
22+
1723

1824
def tokenize_parameters(buffer: bytes) -> List[bytes]:
1925
"""Split input parameters into tokens.
2026
Removes space characters outside of double quote blocks:
2127
T-rec-V-25 - 5.2.1 Command line general format: "Space characters (IA5 2/0)
2228
are ignored [..], unless they are embedded in numeric or string constants"
23-
Raises ValueError in case of invalid input string."""
29+
Raises AtParsingError in case of invalid input string."""
2430

2531
tokens = []
2632
in_quotes = False
@@ -43,11 +49,11 @@ def tokenize_parameters(buffer: bytes) -> List[bytes]:
4349
token = bytearray()
4450
elif char == b'(':
4551
if len(token) > 0:
46-
raise ValueError("open_paren following regular character")
52+
raise AtParsingError("open_paren following regular character")
4753
tokens.append(char)
4854
elif char == b'"':
4955
if len(token) > 0:
50-
raise ValueError("quote following regular character")
56+
raise AtParsingError("quote following regular character")
5157
in_quotes = True
5258
token.extend(char)
5359
else:
@@ -59,7 +65,7 @@ def tokenize_parameters(buffer: bytes) -> List[bytes]:
5965

6066
def parse_parameters(buffer: bytes) -> List[Union[bytes, list]]:
6167
"""Parse the parameters using the comma and parenthesis separators.
62-
Raises ValueError in case of invalid input string."""
68+
Raises AtParsingError in case of invalid input string."""
6369

6470
tokens = tokenize_parameters(buffer)
6571
accumulator: List[list] = [[]]
@@ -73,13 +79,13 @@ def parse_parameters(buffer: bytes) -> List[Union[bytes, list]]:
7379
accumulator.append([])
7480
elif token == b')':
7581
if len(accumulator) < 2:
76-
raise ValueError("close_paren without matching open_paren")
82+
raise AtParsingError("close_paren without matching open_paren")
7783
accumulator[-1].append(current)
7884
current = accumulator.pop()
7985
else:
8086
current = token
8187

8288
accumulator[-1].append(current)
8389
if len(accumulator) > 1:
84-
raise ValueError("missing close_paren")
90+
raise AtParsingError("missing close_paren")
8591
return accumulator[0]

bumble/avc.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import struct
2121
from typing import Dict, Type, Union, Tuple
2222

23+
from bumble import core
2324
from bumble.utils import OpenIntEnum
2425

2526

@@ -88,7 +89,9 @@ def subclass(subclass):
8889
short_name = subclass.__name__.replace("ResponseFrame", "")
8990
category_class = ResponseFrame
9091
else:
91-
raise ValueError(f"invalid subclass name {subclass.__name__}")
92+
raise core.InvalidArgumentError(
93+
f"invalid subclass name {subclass.__name__}"
94+
)
9295

9396
uppercase_indexes = [
9497
i for i in range(len(short_name)) if short_name[i].isupper()
@@ -106,7 +109,7 @@ def subclass(subclass):
106109
@staticmethod
107110
def from_bytes(data: bytes) -> Frame:
108111
if data[0] >> 4 != 0:
109-
raise ValueError("first 4 bits must be 0s")
112+
raise core.InvalidPacketError("first 4 bits must be 0s")
110113

111114
ctype_or_response = data[0] & 0xF
112115
subunit_type = Frame.SubunitType(data[1] >> 3)
@@ -122,7 +125,7 @@ def from_bytes(data: bytes) -> Frame:
122125
# Extended to the next byte
123126
extension = data[2]
124127
if extension == 0:
125-
raise ValueError("extended subunit ID value reserved")
128+
raise core.InvalidPacketError("extended subunit ID value reserved")
126129
if extension == 0xFF:
127130
subunit_id = 5 + 254 + data[3]
128131
opcode_offset = 4
@@ -131,7 +134,7 @@ def from_bytes(data: bytes) -> Frame:
131134
opcode_offset = 3
132135

133136
elif subunit_id == 6:
134-
raise ValueError("reserved subunit ID")
137+
raise core.InvalidPacketError("reserved subunit ID")
135138

136139
opcode = Frame.OperationCode(data[opcode_offset])
137140
operands = data[opcode_offset + 1 :]
@@ -448,7 +451,7 @@ def __init__(
448451
operation_data: bytes,
449452
) -> None:
450453
if len(operation_data) > 255:
451-
raise ValueError("operation data must be <= 255 bytes")
454+
raise core.InvalidArgumentError("operation data must be <= 255 bytes")
452455
self.state_flag = state_flag
453456
self.operation_id = operation_id
454457
self.operation_data = operation_data

bumble/avctp.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from bumble.colors import color
2525
from bumble import avc
26+
from bumble import core
2627
from bumble import l2cap
2728

2829
# -----------------------------------------------------------------------------
@@ -275,7 +276,7 @@ def unregister_command_handler(
275276
self, pid: int, handler: Protocol.CommandHandler
276277
) -> None:
277278
if pid not in self.command_handlers or self.command_handlers[pid] != handler:
278-
raise ValueError("command handler not registered")
279+
raise core.InvalidArgumentError("command handler not registered")
279280
del self.command_handlers[pid]
280281

281282
def register_response_handler(
@@ -287,5 +288,5 @@ def unregister_response_handler(
287288
self, pid: int, handler: Protocol.ResponseHandler
288289
) -> None:
289290
if pid not in self.response_handlers or self.response_handlers[pid] != handler:
290-
raise ValueError("response handler not registered")
291+
raise core.InvalidArgumentError("response handler not registered")
291292
del self.response_handlers[pid]

bumble/avdtp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
BT_ADVANCED_AUDIO_DISTRIBUTION_SERVICE,
4444
InvalidStateError,
4545
ProtocolError,
46+
InvalidArgumentError,
4647
name_or_number,
4748
)
4849
from .a2dp import (
@@ -700,7 +701,7 @@ def subclass(subclass):
700701
signal_identifier_str = name[:-7]
701702
message_type = Message.MessageType.RESPONSE_REJECT
702703
else:
703-
raise ValueError('invalid class name')
704+
raise InvalidArgumentError('invalid class name')
704705

705706
subclass.message_type = message_type
706707

bumble/avrcp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
)
5656
from bumble.utils import AsyncRunner, OpenIntEnum
5757
from bumble.core import (
58+
InvalidArgumentError,
5859
ProtocolError,
5960
BT_L2CAP_PROTOCOL_ID,
6061
BT_AVCTP_PROTOCOL_ID,
@@ -1411,7 +1412,7 @@ def notify_playback_status_changed(self, status: PlayStatus) -> None:
14111412
def notify_track_changed(self, identifier: bytes) -> None:
14121413
"""Notify the connected peer of a Track change."""
14131414
if len(identifier) != 8:
1414-
raise ValueError("identifier must be 8 bytes")
1415+
raise InvalidArgumentError("identifier must be 8 bytes")
14151416
self.notify_event(TrackChangedEvent(identifier))
14161417

14171418
def notify_playback_position_changed(self, position: int) -> None:

bumble/codecs.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from __future__ import annotations
1919
from dataclasses import dataclass
2020

21+
from bumble import core
22+
2123

2224
# -----------------------------------------------------------------------------
2325
class BitReader:
@@ -40,7 +42,7 @@ def read(self, bits: int) -> int:
4042
""" "Read up to 32 bits."""
4143

4244
if bits > 32:
43-
raise ValueError('maximum read size is 32')
45+
raise core.InvalidArgumentError('maximum read size is 32')
4446

4547
if self.bits_cached >= bits:
4648
# We have enough bits.
@@ -53,7 +55,7 @@ def read(self, bits: int) -> int:
5355
feed_size = len(feed_bytes)
5456
feed_int = int.from_bytes(feed_bytes, byteorder='big')
5557
if 8 * feed_size + self.bits_cached < bits:
56-
raise ValueError('trying to read past the data')
58+
raise core.InvalidArgumentError('trying to read past the data')
5759
self.byte_position += feed_size
5860

5961
# Combine the new cache and the old cache
@@ -68,7 +70,7 @@ def read(self, bits: int) -> int:
6870

6971
def read_bytes(self, count: int):
7072
if self.bit_position + 8 * count > 8 * len(self.data):
71-
raise ValueError('not enough data')
73+
raise core.InvalidArgumentError('not enough data')
7274

7375
if self.bit_position % 8:
7476
# Not byte aligned
@@ -113,7 +115,7 @@ def latm_value(reader: BitReader) -> int:
113115

114116
@staticmethod
115117
def program_config_element(reader: BitReader):
116-
raise ValueError('program_config_element not supported')
118+
raise core.InvalidPacketError('program_config_element not supported')
117119

118120
@dataclass
119121
class GASpecificConfig:
@@ -140,7 +142,7 @@ def __init__(
140142
aac_spectral_data_resilience_flags = reader.read(1)
141143
extension_flag_3 = reader.read(1)
142144
if extension_flag_3 == 1:
143-
raise ValueError('extensionFlag3 == 1 not supported')
145+
raise core.InvalidPacketError('extensionFlag3 == 1 not supported')
144146

145147
@staticmethod
146148
def audio_object_type(reader: BitReader):
@@ -216,7 +218,7 @@ def __init__(self, reader: BitReader) -> None:
216218
reader, self.channel_configuration, self.audio_object_type
217219
)
218220
else:
219-
raise ValueError(
221+
raise core.InvalidPacketError(
220222
f'audioObjectType {self.audio_object_type} not supported'
221223
)
222224

@@ -260,18 +262,18 @@ def __init__(self, reader: BitReader) -> None:
260262
else:
261263
audio_mux_version_a = 0
262264
if audio_mux_version_a != 0:
263-
raise ValueError('audioMuxVersionA != 0 not supported')
265+
raise core.InvalidPacketError('audioMuxVersionA != 0 not supported')
264266
if audio_mux_version == 1:
265267
tara_buffer_fullness = AacAudioRtpPacket.latm_value(reader)
266268
stream_cnt = 0
267269
all_streams_same_time_framing = reader.read(1)
268270
num_sub_frames = reader.read(6)
269271
num_program = reader.read(4)
270272
if num_program != 0:
271-
raise ValueError('num_program != 0 not supported')
273+
raise core.InvalidPacketError('num_program != 0 not supported')
272274
num_layer = reader.read(3)
273275
if num_layer != 0:
274-
raise ValueError('num_layer != 0 not supported')
276+
raise core.InvalidPacketError('num_layer != 0 not supported')
275277
if audio_mux_version == 0:
276278
self.audio_specific_config = AacAudioRtpPacket.AudioSpecificConfig(
277279
reader
@@ -284,7 +286,7 @@ def __init__(self, reader: BitReader) -> None:
284286
)
285287
audio_specific_config_len = reader.bit_position - marker
286288
if asc_len < audio_specific_config_len:
287-
raise ValueError('audio_specific_config_len > asc_len')
289+
raise core.InvalidPacketError('audio_specific_config_len > asc_len')
288290
asc_len -= audio_specific_config_len
289291
reader.skip(asc_len)
290292
frame_length_type = reader.read(3)
@@ -293,7 +295,9 @@ def __init__(self, reader: BitReader) -> None:
293295
elif frame_length_type == 1:
294296
frame_length = reader.read(9)
295297
else:
296-
raise ValueError(f'frame_length_type {frame_length_type} not supported')
298+
raise core.InvalidPacketError(
299+
f'frame_length_type {frame_length_type} not supported'
300+
)
297301

298302
self.other_data_present = reader.read(1)
299303
if self.other_data_present:
@@ -318,12 +322,12 @@ class AudioMuxElement:
318322

319323
def __init__(self, reader: BitReader, mux_config_present: int):
320324
if mux_config_present == 0:
321-
raise ValueError('muxConfigPresent == 0 not supported')
325+
raise core.InvalidPacketError('muxConfigPresent == 0 not supported')
322326

323327
# AudioMuxElement - ISO/EIC 14496-3 Table 1.41
324328
use_same_stream_mux = reader.read(1)
325329
if use_same_stream_mux:
326-
raise ValueError('useSameStreamMux == 1 not supported')
330+
raise core.InvalidPacketError('useSameStreamMux == 1 not supported')
327331
self.stream_mux_config = AacAudioRtpPacket.StreamMuxConfig(reader)
328332

329333
# We only support:

bumble/colors.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
from typing import List, Optional, Union
1717

1818

19+
class ColorError(ValueError):
20+
"""Error raised when a color spec is invalid."""
21+
22+
1923
# ANSI color names. There is also a "default"
2024
COLORS = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white')
2125

@@ -52,7 +56,7 @@ def _color_code(spec: ColorSpec, base: int) -> str:
5256
elif isinstance(spec, int) and 0 <= spec <= 255:
5357
return _join(base + 8, 5, spec)
5458
else:
55-
raise ValueError('Invalid color spec "%s"' % spec)
59+
raise ColorError('Invalid color spec "%s"' % spec)
5660

5761

5862
def color(
@@ -72,7 +76,7 @@ def color(
7276
if style_part in STYLES:
7377
codes.append(STYLES.index(style_part))
7478
else:
75-
raise ValueError('Invalid style "%s"' % style_part)
79+
raise ColorError('Invalid style "%s"' % style_part)
7680

7781
if codes:
7882
return '\x1b[{0}m{1}\x1b[0m'.format(_join(*codes), s)

0 commit comments

Comments
 (0)