Skip to content

Commit 263de3f

Browse files
committed
Stop raising generic RuntimeError on unexpected conditions
Instead, use InternalClientError (or its subclasses) consistently.
1 parent bf07199 commit 263de3f

File tree

7 files changed

+56
-40
lines changed

7 files changed

+56
-40
lines changed

asyncpg/exceptions/_base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,11 @@ def __init__(self, msg, *, detail=None, hint=None):
222222

223223

224224
class InternalClientError(Exception):
225-
pass
225+
"""All unexpected errors not classified otherwise."""
226+
227+
228+
class ProtocolError(InternalClientError):
229+
"""Unexpected condition in the handling of PostgreSQL protocol input."""
226230

227231

228232
class OutdatedSchemaCacheError(InternalClientError):

asyncpg/protocol/buffer.pyx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
from cpython cimport Py_buffer
99
from libc.string cimport memcpy
1010

11+
from asyncpg import exceptions
1112

12-
class BufferError(Exception):
13+
14+
class BufferError(exceptions.InternalClientError):
1315
pass
1416

17+
1518
@cython.no_gc_clear
1619
@cython.final
1720
@cython.freelist(_MEMORY_FREELIST_SIZE)
@@ -49,7 +52,7 @@ cdef class WriteBuffer:
4952
self._size = 0
5053

5154
if self._view_count:
52-
raise RuntimeError(
55+
raise BufferError(
5356
'Deallocating buffer with attached memoryviews')
5457

5558
def __getbuffer__(self, Py_buffer *buffer, int flags):
@@ -292,7 +295,7 @@ cdef class ReadBuffer:
292295

293296
if ASYNCPG_DEBUG:
294297
if self._len0 < 1:
295-
raise RuntimeError(
298+
raise BufferError(
296299
'debug: second buffer of ReadBuffer is empty')
297300

298301
cdef inline const char* _try_read_bytes(self, ssize_t nbytes):
@@ -381,7 +384,7 @@ cdef class ReadBuffer:
381384

382385
if ASYNCPG_DEBUG:
383386
if not self._buf0:
384-
raise RuntimeError(
387+
raise BufferError(
385388
'debug: first buffer of ReadBuffer is empty')
386389

387390
self._ensure_first_buf()

asyncpg/protocol/codecs/array.pyx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from collections.abc import Iterable as IterableABC, Sized as SizedABC
99

10+
from asyncpg import exceptions
11+
1012

1113
DEF ARRAY_MAXDIM = 6 # defined in postgresql/src/includes/c.h
1214

@@ -285,7 +287,7 @@ cdef inline array_decode(ConnectionSettings settings, FastReadBuffer buf,
285287
return result
286288

287289
if ndims > ARRAY_MAXDIM:
288-
raise RuntimeError(
290+
raise exceptions.ProtocolError(
289291
'number of array dimensions ({}) exceed the maximum expected ({})'.
290292
format(ndims, ARRAY_MAXDIM))
291293

@@ -337,7 +339,8 @@ cdef _nested_array_decode(ConnectionSettings settings,
337339

338340
if ASYNCPG_DEBUG:
339341
if ndims <= 0:
340-
raise RuntimeError('unexpected ndims value: {}'.format(ndims))
342+
raise exceptions.ProtocolError(
343+
'unexpected ndims value: {}'.format(ndims))
341344

342345
for i in range(ndims):
343346
array_len *= dims[i]
@@ -409,7 +412,7 @@ cdef textarray_decode(ConnectionSettings settings, FastReadBuffer buf,
409412
return _textarray_decode(
410413
settings, array_text, decoder, decoder_arg, typdelim)
411414
except ValueError as e:
412-
raise ValueError(
415+
raise exceptions.ProtocolError(
413416
'malformed array literal {!r}: {}'.format(s, e.args[0]))
414417
finally:
415418
PyMem_Free(array_text)
@@ -845,7 +848,8 @@ cdef arraytext_decode(ConnectionSettings settings, FastReadBuffer buf):
845848
cdef anyarray_decode(ConnectionSettings settings, FastReadBuffer buf):
846849
# Instances of anyarray (or any other polymorphic pseudotype) are
847850
# never supposed to be returned from actual queries.
848-
raise RuntimeError('unexpected instance of \'anyarray\' type')
851+
raise exceptions.ProtocolError(
852+
'unexpected instance of \'anyarray\' type')
849853

850854

851855
cdef init_array_codecs():

asyncpg/protocol/codecs/base.pyx

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
66

77

8-
from asyncpg.exceptions import OutdatedSchemaCacheError
8+
from asyncpg import exceptions
99

1010

1111
cdef void* binary_codec_map[(MAXSUPPORTEDOID + 1) * 2]
@@ -62,14 +62,14 @@ cdef class Codec:
6262
self.decoder = <codec_decode_func>&self.decode_array_text
6363
elif type == CODEC_RANGE:
6464
if format != PG_FORMAT_BINARY:
65-
raise RuntimeError(
65+
raise NotImplementedError(
6666
'cannot encode type "{}"."{}": text encoding of '
6767
'range types is not supported'.format(schema, name))
6868
self.encoder = <codec_encode_func>&self.encode_range
6969
self.decoder = <codec_decode_func>&self.decode_range
7070
elif type == CODEC_COMPOSITE:
7171
if format != PG_FORMAT_BINARY:
72-
raise RuntimeError(
72+
raise NotImplementedError(
7373
'cannot encode type "{}"."{}": text encoding of '
7474
'composite types is not supported'.format(schema, name))
7575
self.encoder = <codec_encode_func>&self.encode_composite
@@ -78,7 +78,8 @@ cdef class Codec:
7878
self.encoder = <codec_encode_func>&self.encode_in_python
7979
self.decoder = <codec_decode_func>&self.decode_in_python
8080
else:
81-
raise RuntimeError('unexpected codec type: {}'.format(type))
81+
raise exceptions.InternalClientError(
82+
'unexpected codec type: {}'.format(type))
8283

8384
cdef Codec copy(self):
8485
cdef Codec codec
@@ -150,12 +151,12 @@ cdef class Codec:
150151
elif self.format == PG_FORMAT_TEXT:
151152
text_encode(settings, buf, data)
152153
else:
153-
raise RuntimeError(
154+
raise exceptions.InternalClientError(
154155
'unexpected data format: {}'.format(self.format))
155156
elif self.xformat == PG_XFORMAT_TUPLE:
156157
self.c_encoder(settings, buf, data)
157158
else:
158-
raise RuntimeError(
159+
raise exceptions.InternalClientError(
159160
'unexpected exchange format: {}'.format(self.xformat))
160161

161162
cdef encode(self, ConnectionSettings settings, WriteBuffer buf,
@@ -193,7 +194,7 @@ cdef class Codec:
193194

194195
elem_count = <ssize_t><uint32_t>hton.unpack_int32(buf.read(4))
195196
if elem_count != len(self.element_type_oids):
196-
raise OutdatedSchemaCacheError(
197+
raise exceptions.OutdatedSchemaCacheError(
197198
'unexpected number of attributes of composite type: '
198199
'{}, expected {}'
199200
.format(
@@ -209,7 +210,7 @@ cdef class Codec:
209210
received_elem_typ = <uint32_t>hton.unpack_int32(buf.read(4))
210211

211212
if received_elem_typ != elem_typ:
212-
raise OutdatedSchemaCacheError(
213+
raise exceptions.OutdatedSchemaCacheError(
213214
'unexpected data type of composite type attribute {}: '
214215
'{!r}, expected {!r}'
215216
.format(
@@ -243,12 +244,12 @@ cdef class Codec:
243244
elif self.format == PG_FORMAT_TEXT:
244245
data = text_decode(settings, buf)
245246
else:
246-
raise RuntimeError(
247+
raise exceptions.InternalClientError(
247248
'unexpected data format: {}'.format(self.format))
248249
elif self.xformat == PG_XFORMAT_TUPLE:
249250
data = self.c_decoder(settings, buf)
250251
else:
251-
raise RuntimeError(
252+
raise exceptions.InternalClientError(
252253
'unexpected exchange format: {}'.format(self.xformat))
253254

254255
return self.py_decoder(data)
@@ -455,7 +456,7 @@ cdef class DataCodecConfig:
455456

456457
elif ti['kind'] == b'c':
457458
if not comp_type_attrs:
458-
raise RuntimeError(
459+
raise exceptions.InternalClientError(
459460
'type record missing field types for '
460461
'composite {}'.format(oid))
461462

@@ -469,7 +470,7 @@ cdef class DataCodecConfig:
469470
elem_codec = self.get_codec(typoid, PG_FORMAT_TEXT)
470471
has_text_elements = True
471472
if elem_codec is None:
472-
raise RuntimeError(
473+
raise exceptions.InternalClientError(
473474
'no codec for composite attribute type {}'.format(
474475
typoid))
475476
comp_elem_codecs.append(elem_codec)
@@ -490,7 +491,7 @@ cdef class DataCodecConfig:
490491
# Domain type
491492

492493
if not base_type:
493-
raise RuntimeError(
494+
raise exceptions.InternalClientError(
494495
'type record missing base type for domain {}'.format(
495496
oid))
496497

@@ -506,7 +507,7 @@ cdef class DataCodecConfig:
506507
# Range type
507508

508509
if not range_subtype_oid:
509-
raise RuntimeError(
510+
raise exceptions.InternalClientError(
510511
'type record missing base type for range {}'.format(
511512
oid))
512513

@@ -542,7 +543,7 @@ cdef class DataCodecConfig:
542543
if xformat == PG_XFORMAT_TUPLE:
543544
core_codec = get_any_core_codec(oid, format, xformat)
544545
if core_codec is None:
545-
raise ValueError(
546+
raise exceptions.InterfaceError(
546547
"{} type does not support 'tuple' exchange format".format(
547548
typename))
548549
c_encoder = core_codec.c_encoder
@@ -593,7 +594,8 @@ cdef class DataCodecConfig:
593594
self._custom_type_codecs[typeoid] = codec
594595
break
595596
else:
596-
raise ValueError('unknown alias target: {}'.format(alias_to))
597+
raise exceptions.InterfaceError(
598+
'invalid builtin codec reference: {}'.format(alias_to))
597599

598600
def set_builtin_type_codec(self, typeoid, typename, typeschema, typekind,
599601
alias_to, format=PG_FORMAT_ANY):
@@ -707,7 +709,7 @@ cdef register_core_codec(uint32_t oid,
707709
ClientExchangeFormat xformat=PG_XFORMAT_OBJECT):
708710

709711
if oid > MAXSUPPORTEDOID:
710-
raise RuntimeError(
712+
raise exceptions.InternalClientError(
711713
'cannot register core codec for OID {}: it is greater '
712714
'than MAXSUPPORTEDOID ({})'.format(oid, MAXSUPPORTEDOID))
713715

@@ -729,7 +731,8 @@ cdef register_core_codec(uint32_t oid,
729731
elif format == PG_FORMAT_TEXT:
730732
text_codec_map[oid * xformat] = <void*>codec
731733
else:
732-
raise RuntimeError('invalid data format: {}'.format(format))
734+
raise exceptions.InternalClientError(
735+
'invalid data format: {}'.format(format))
733736

734737

735738
cdef register_extra_codec(str name,

asyncpg/protocol/codecs/record.pyx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
66

77

8+
from asyncpg import exceptions
9+
10+
811
cdef inline record_encode_frame(ConnectionSettings settings, WriteBuffer buf,
912
WriteBuffer elem_data, int32_t elem_count):
1013
buf.write_int32(4 + elem_data.len())
@@ -36,7 +39,7 @@ cdef anonymous_record_decode(ConnectionSettings settings, FastReadBuffer buf):
3639
else:
3740
elem_codec = settings.get_data_codec(elem_typ)
3841
if elem_codec is None or not elem_codec.has_decoder():
39-
raise RuntimeError(
42+
raise exceptions.InternalClientError(
4043
'no decoder for composite type element in '
4144
'position {} of type OID {}'.format(i, elem_typ))
4245
elem = elem_codec.decode(settings,

asyncpg/protocol/coreproto.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ cdef class CoreProtocol:
113113
# Sync point, self to push the result
114114
if self.result_type != RESULT_FAILED:
115115
self.result_type = RESULT_FAILED
116-
self.result = RuntimeError(
116+
self.result = apg_exc.InternalClientError(
117117
'unknown error in protocol implementation')
118118

119119
self._push_result()

asyncpg/protocol/prepared_stmt.pyx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ cdef class PreparedStatementState:
3030
for oid in self.parameters_desc:
3131
codec = self.settings.get_data_codec(oid)
3232
if codec is None:
33-
raise RuntimeError
33+
raise exceptions.InternalClientError(
34+
'missing codec information for OID {}'.format(oid))
3435
result.append(apg_types.Type(
3536
oid, codec.name, codec.kind, codec.schema))
3637

@@ -49,7 +50,8 @@ cdef class PreparedStatementState:
4950

5051
codec = self.settings.get_data_codec(oid)
5152
if codec is None:
52-
raise RuntimeError
53+
raise exceptions.InternalClientError(
54+
'missing codec information for OID {}'.format(oid))
5355

5456
name = name.decode(self.settings._encoding)
5557

@@ -199,7 +201,8 @@ cdef class PreparedStatementState:
199201
oid = row[3]
200202
codec = self.settings.get_data_codec(oid)
201203
if codec is None or not codec.has_decoder():
202-
raise RuntimeError('no decoder for OID {}'.format(oid))
204+
raise exceptions.InternalClientError(
205+
'no decoder for OID {}'.format(oid))
203206
if not codec.is_binary():
204207
self.have_text_cols = True
205208

@@ -223,7 +226,8 @@ cdef class PreparedStatementState:
223226
p_oid = self.parameters_desc[i]
224227
codec = self.settings.get_data_codec(p_oid)
225228
if codec is None or not codec.has_encoder():
226-
raise RuntimeError('no encoder for OID {}'.format(p_oid))
229+
raise exceptions.InternalClientError(
230+
'no encoder for OID {}'.format(p_oid))
227231
if codec.type not in {}:
228232
self.have_text_args = True
229233

@@ -257,16 +261,11 @@ cdef class PreparedStatementState:
257261
fnum = hton.unpack_int16(rbuf.read(2))
258262

259263
if fnum != self.cols_num:
260-
raise RuntimeError(
261-
'number of columns in result ({}) is '
264+
raise exceptions.ProtocolError(
265+
'the number of columns in the result row ({}) is '
262266
'different from what was described ({})'.format(
263267
fnum, self.cols_num))
264268

265-
if rows_codecs is None or len(rows_codecs) < fnum:
266-
if fnum > 0:
267-
# It's OK to have no rows_codecs for empty records
268-
raise RuntimeError('invalid rows_codecs')
269-
270269
dec_row = record.ApgRecord_New(self.cols_desc, fnum)
271270
for i in range(fnum):
272271
flen = hton.unpack_int32(rbuf.read(4))

0 commit comments

Comments
 (0)