Skip to content

Commit afbae2d

Browse files
Pin encode_value rejection of Decimal / Fraction / complex / custom
The wire codec accepts only bool / int / float / str / bytes / None. Anything else hits the ``Cannot infer wire type`` branch in ``encode_value``. That rejection path was only exercised incidentally, so a future refactor that added implicit Decimal or numpy support (or accidentally accepted an object with __index__) would slip through. Add rejection tests for Decimal, Fraction, complex, plain object(), and a class defining only __index__ (which is not an int subclass). Tests intentionally do NOT include numpy — numpy is not a declared dependency, and adding optional coverage risks flaky CI signal. Integration-side tests in the dbapi package cover the corresponding DataError bubbling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 05d2bb7 commit afbae2d

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

tests/test_types.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,3 +686,47 @@ def test_encode_value_false_as_explicit_integer(self) -> None:
686686
encoded, vtype = encode_value(False, ValueType.INTEGER)
687687
assert vtype == ValueType.INTEGER
688688
assert decode_int64(encoded) == 0
689+
690+
691+
class TestEncodeValueUnsupportedTypes:
692+
"""Pin the rejection contract for Python types the wire codec does
693+
not natively understand. The codec accepts only bool / int / float /
694+
str / bytes / None; anything else must surface as ``EncodeError`` so
695+
callers see a clear driver-level error rather than a nonsense wire
696+
frame. These tests lock the current behaviour so a future refactor
697+
that adds implicit Decimal / numpy support is an intentional
698+
change — not a silent one.
699+
"""
700+
701+
def test_decimal_rejected(self) -> None:
702+
from decimal import Decimal
703+
704+
with pytest.raises(EncodeError, match="Cannot infer wire type"):
705+
encode_value(Decimal("3.14"))
706+
707+
def test_fraction_rejected(self) -> None:
708+
from fractions import Fraction
709+
710+
with pytest.raises(EncodeError, match="Cannot infer wire type"):
711+
encode_value(Fraction(1, 3))
712+
713+
def test_complex_rejected(self) -> None:
714+
with pytest.raises(EncodeError, match="Cannot infer wire type"):
715+
encode_value(complex(1, 2))
716+
717+
def test_plain_object_rejected(self) -> None:
718+
with pytest.raises(EncodeError, match="Cannot infer wire type"):
719+
encode_value(object())
720+
721+
def test_index_only_class_rejected(self) -> None:
722+
"""An object with ``__index__`` but no ``__int__`` or bool-ness
723+
is NOT treated as int by ``isinstance(value, int)``; confirm
724+
rejection so the contract stays tight.
725+
"""
726+
727+
class OnlyIndex:
728+
def __index__(self) -> int:
729+
return 42
730+
731+
with pytest.raises(EncodeError, match="Cannot infer wire type"):
732+
encode_value(OnlyIndex())

0 commit comments

Comments
 (0)