Skip to content

Commit bb267e6

Browse files
committed
(improvement) serializers: address PR review feedback
- Chain original exception in _raise_bind_serialize_error (raise from exc) - Clarify docstrings for _check_float_range/_check_int32_range (OverflowError vs struct.error) - Expand _raise_bind_serialize_error docstring with specific exception types - Document __getitem__ requirement in vector serialize methods - Move io and uvint_pack imports to module scope in serializers.pyx - Fix test_plain_path_overflow_error_wrapped docstring (struct.error, not OverflowError) - Replace name-mangled __serializers with _cached_serializers
1 parent da1bc3f commit bb267e6

3 files changed

Lines changed: 153 additions & 112 deletions

File tree

cassandra/query.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -552,16 +552,16 @@ def _serializers(self):
552552
if self.column_encryption_policy:
553553
return None
554554
try:
555-
return self.__serializers
555+
return self._cached_serializers
556556
except AttributeError:
557557
pass
558558
if _HAVE_CYTHON_SERIALIZERS and self.column_metadata:
559-
self.__serializers = _cython_make_serializers(
559+
self._cached_serializers = _cython_make_serializers(
560560
[col.type for col in self.column_metadata]
561561
)
562562
else:
563-
self.__serializers = None
564-
return self.__serializers
563+
self._cached_serializers = None
564+
return self._cached_serializers
565565

566566
@classmethod
567567
def from_message(
@@ -663,13 +663,19 @@ def __str__(self):
663663

664664

665665
def _raise_bind_serialize_error(col_spec, value, exc):
666-
"""Wrap serialization errors with column context for all bind loop paths."""
666+
"""Wrap TypeError, struct.error, or OverflowError with column context.
667+
668+
Called from all three bind loop paths (CE, Cython, plain Python) to
669+
provide a uniform error message that includes the column name and
670+
expected type. Other exception types (e.g. ValueError from VectorType
671+
dimension mismatch) propagate without wrapping.
672+
"""
667673
actual_type = type(value)
668674
message = (
669675
'Received an argument of invalid type for column "%s". '
670676
"Expected: %s, Got: %s; (%s)" % (col_spec.name, col_spec.type, actual_type, exc)
671677
)
672-
raise TypeError(message)
678+
raise TypeError(message) from exc
673679

674680

675681
class BoundStatement(Statement):

cassandra/serializers.pyx

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ from libc.math cimport isinf, isnan
3434
from cpython.bytes cimport PyBytes_FromStringAndSize
3535

3636
from cassandra import cqltypes
37+
import io
38+
from cassandra.marshal import uvint_pack
3739

3840
cdef bint is_little_endian
3941
from cassandra.util import is_little_endian
@@ -60,9 +62,9 @@ cdef class Serializer:
6062
cdef inline void _check_float_range(double value) except *:
6163
"""Raise OverflowError for finite values outside float32 range.
6264
63-
This matches the behavior of struct.pack('>f', value), which raises
64-
OverflowError (via struct.error) for values that cannot be represented
65-
as a 32-bit IEEE 754 float. inf, -inf, and nan pass through unchanged.
65+
Provides equivalent validation to struct.pack('>f', value), but raises
66+
OverflowError instead of struct.error. The bind loop in query.py catches
67+
both exception types. inf, -inf, and nan pass through unchanged.
6668
"""
6769
if not isinf(value) and not isnan(value):
6870
if value > <double>FLT_MAX or value < -<double>FLT_MAX:
@@ -78,10 +80,10 @@ cdef inline void _check_float_range(double value) except *:
7880
cdef inline void _check_int32_range(object value) except *:
7981
"""Raise OverflowError for values outside the signed int32 range.
8082
81-
This matches the behavior of struct.pack('>i', value), which raises
82-
struct.error for values outside [-2147483648, 2147483647]. The check
83-
must be done on the Python int *before* the C-level <int32_t> cast,
84-
which would silently truncate.
83+
Provides equivalent validation to struct.pack('>i', value), but raises
84+
OverflowError instead of struct.error. The bind loop in query.py catches
85+
both exception types. The check must be done on the Python int *before*
86+
the C-level <int32_t> cast, which would silently truncate.
8587
"""
8688
if value > 2147483647 or value < -2147483648:
8789
raise OverflowError(
@@ -222,7 +224,11 @@ cdef class SerVectorType(Serializer):
222224
return self._serialize_generic(value, protocol_version)
223225

224226
cdef inline bytes _serialize_float(self, object values):
225-
"""Serialize a list of floats into a contiguous big-endian buffer."""
227+
"""Serialize a sequence of floats into a contiguous big-endian buffer.
228+
229+
Note: uses index-based access (values[i]) rather than iteration, so
230+
the input must support __getitem__ (e.g. list or tuple).
231+
"""
226232
cdef Py_ssize_t i
227233
cdef Py_ssize_t buf_size = self.vector_size * 4
228234
if buf_size == 0:
@@ -255,7 +261,11 @@ cdef class SerVectorType(Serializer):
255261
free(buf)
256262

257263
cdef inline bytes _serialize_double(self, object values):
258-
"""Serialize a list of doubles into a contiguous big-endian buffer."""
264+
"""Serialize a sequence of doubles into a contiguous big-endian buffer.
265+
266+
Note: uses index-based access (values[i]) rather than iteration, so
267+
the input must support __getitem__ (e.g. list or tuple).
268+
"""
259269
cdef Py_ssize_t i
260270
cdef Py_ssize_t buf_size = self.vector_size * 8
261271
if buf_size == 0:
@@ -291,7 +301,11 @@ cdef class SerVectorType(Serializer):
291301
free(buf)
292302

293303
cdef inline bytes _serialize_int32(self, object values):
294-
"""Serialize a list of int32 values into a contiguous big-endian buffer."""
304+
"""Serialize a sequence of int32 values into a contiguous big-endian buffer.
305+
306+
Note: uses index-based access (values[i]) rather than iteration, so
307+
the input must support __getitem__ (e.g. list or tuple).
308+
"""
295309
cdef Py_ssize_t i
296310
cdef Py_ssize_t buf_size = self.vector_size * 4
297311
if buf_size == 0:
@@ -325,9 +339,6 @@ cdef class SerVectorType(Serializer):
325339

326340
cdef inline bytes _serialize_generic(self, object values, int protocol_version):
327341
"""Fallback: element-by-element Python serialization for non-optimized types."""
328-
import io
329-
from cassandra.marshal import uvint_pack
330-
331342
serialized_size = self.subtype.serial_size()
332343
buf = io.BytesIO()
333344
for item in values:

0 commit comments

Comments
 (0)