asyncpg_BitString = dialect.dbapi.asyncpg.BitString
def to_bind(value):
- print(f'processing bound value \'{value}\'')
+ print(f"processing bound value '{value}'")
if isinstance(value, str):
value = BitString(value)
r = asyncpg_BitString.from_int(int(value), len(value))
- print(f'returning {r}')
+ print(f"returning {r}")
return r
return value
def result_processor(self, dialect, coltype):
def to_result(value):
if value is not None:
- print(f'result {value} length {len(value)}')
- value = BitString.from_int(
- value.to_int(),
- length=len(value)
- )
+ print(f"result {value} length {len(value)}")
+ value = BitString.from_int(value.to_int(), length=len(value))
return value
return to_result
-# dialects/postgresql/types.py
+# dialects/postgresql/bitstring.py
# Copyright (C) 2013-2025 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
from __future__ import annotations
import functools
+import itertools
import math
-from typing import SupportsIndex, cast
+from typing import Any
+from typing import cast
from typing import Literal
+from typing import SupportsIndex
@functools.total_ordering
b = BitString('101')
"""
- def __new__(cls, _value: str, _check=True):
+ def __new__(cls, _value: str, _check: bool = True) -> BitString:
if not isinstance(_value, BitString) and (
_check and _value and any(c not in "01" for c in _value)
):
- print(f'value: {_value}')
raise ValueError("BitString must only contain '0' and '1' chars")
return super().__new__(cls, _value)
@classmethod
- def from_int(cls, value: int, length: int):
+ def from_int(cls, value: int, length: int) -> BitString:
"""
Returns a BitString consisting of the bits in the little-endian
representation of the given python int ``value``. A ``ValueError``
will be padded on the left by ``'0'`` to bits to produce a
"""
if value < 0:
- raise ValueError("value must be a postive integer")
+ raise ValueError("value must be non-negative")
+ if length < 0:
+ raise ValueError("length must be non-negative")
- if length >= 0:
- if length > 0:
- template_str = f'{{0:0{length}b}}' if length > 0 else ''
- r = template_str.format(value)
- else:
- # f'{0:00b}'.format(0) == '0'
- r = ''
-
- if len(r) > length:
- raise ValueError(
- f"Cannot encode {value} as a BitString of length {length}"
- )
- else:
- r = '{0:b}'.format(value)
+ template_str = f"{{0:0{length}b}}" if length > 0 else ""
+ r = template_str.format(value)
+
+ if (length == 0 and value > 0) or len(r) > length:
+ raise ValueError(
+ f"Cannot encode {value} as a BitString of length {length}"
+ )
return cls(r)
@classmethod
- def from_bytes(cls, value: bytes, length: int = -1):
+ def from_bytes(cls, value: bytes, length: int = -1) -> BitString:
"""
Returns a ``BitString`` consisting of the bits in the given ``value``
bytes.
cannot be represented in a string of this length, then a ``ValueError``
will be raised.
"""
- str_v: str = "".join(f"{c:08b}" for c in value)
+ str_v: str = "".join(f"{int(c):08b}" for c in value)
if length >= 0:
- str_v = str_v.lstrip('0')
+ str_v = str_v.lstrip("0")
- if len(str_v) >= length:
+ if len(str_v) > length:
raise ValueError(
- f"Cannot encode {value} as a BitString of length {length}"
+ f"Cannot encode {value!r} as a BitString of "
+ f"length {length}"
)
str_v = str_v.zfill(length)
return cls(str_v)
- def get_bit(self, index) -> Literal["0", "1"]:
+ def get_bit(self, index: int) -> Literal["0", "1"]:
"""
Returns the value of the flag at the given index
return cast(Literal["0", "1"], super().__getitem__(index))
@property
- def bit_length(self):
+ def bit_length(self) -> int:
return len(self)
@property
- def octet_length(self):
+ def octet_length(self) -> int:
return math.ceil(len(self) / 8)
- def has_bit(self, index) -> bool:
+ def has_bit(self, index: int) -> bool:
return self.get_bit(index) == "1"
def set_bit(
return self
return BitString(
- "".join([self[:index], value, self[index + 1:]]), False
+ "".join([self[:index], value, self[index + 1 :]]), False
)
- # These methods probably should return str and not override the fillchar
- # def ljust(self, width, fillchar=None) -> BitString:
- # """
- # Returns the BitString left justified in a string of length width.
- # Padding is done using the provided fillchar (default is '0').
-
- # If the width is shorter than the length, then the original BitString
- # is returned.
- # """
- # if width < len(self):
- # return self
-
- # fillchar = fillchar or "0"
- # if str(fillchar) not in "01":
- # raise ValueError("fillchar must be either '0' or '1'")
-
- # return BitString(super().ljust(width, fillchar or "0"))
-
- # def rjust(self, width, fillchar=None) -> BitString:
- # if width < len(self):
- # return self
-
- # fillchar = fillchar or "0"
- # if str(fillchar) not in "01":
- # raise ValueError("fillchar must be either '0' or '1'")
-
- # return BitString(super().rjust(width, fillchar))
-
- def lstrip(self, char=None) -> BitString:
+ def lstrip(self, char: str | None = None) -> BitString:
"""
Returns a copy of the BitString with leading characters removed.
If omitted or None, 'chars' defaults '0'
e.g.
- BitString('00010101000').lstrip() === BitString('00010101')
- BitString('11110101111').lstrip('1') === BitString('1111010')
+ BitString('00010101000').lstrip() === BitString('00010101')
+ BitString('11110101111').lstrip('1') === BitString('1111010')
"""
if char is None:
char = "0"
return BitString(super().lstrip(char), False)
- def rstrip(self, char=None) -> BitString:
+ def rstrip(self, char: str | None = "0") -> BitString:
"""
Returns a copy of the BitString with trailing characters removed.
- If omitted or None, 'chars' trailing '0'
+ If omitted or None, 'char' defaults to "0"
e.g.
- BitString('00010101000').rstrip() === BitString('10101000')
- BitString('11110101111').rstrip('1') === BitString('10101111')
+ BitString('00010101000').rstrip() === BitString('10101000')
+ BitString('11110101111').rstrip('1') === BitString('10101111')
"""
if char is None:
char = "0"
return BitString(super().rstrip(char), False)
- def strip(self, char=None) -> BitString:
+ def strip(self, char: str | None = "0") -> BitString:
"""
Returns a copy of the BitString with both leading and trailing
characters removed.
- If ommitted or None, char defaults to '0'
+ If ommitted or None, char defaults to "0"
e.g.
- BitString('00010101000').rstrip() === BitString('10101')
- BitString('11110101111').rstrip('1') === BitString('1010')
+ BitString('00010101000').rstrip() === BitString('10101')
+ BitString('11110101111').rstrip('1') === BitString('1010')
"""
if char is None:
char = "0"
return BitString(super().strip(char))
- def partition(self, sep: str = "0") -> tuple[BitString, str, BitString]:
- """
- Split the string after the first appearance of sep
- (which defaults to '0') and return a 3-tuple containing
- the portion of the string before the separator.
-
- """
- prefix, _, suffix = super().partition(sep)
- return (BitString(prefix, False), sep, BitString(suffix, False))
-
def removeprefix(self, prefix: str, /) -> BitString:
return BitString(super().removeprefix(prefix), False)
def removesuffix(self, suffix: str, /) -> BitString:
return BitString(super().removesuffix(suffix), False)
- def replace(self, old, new, count: SupportsIndex = -1) -> BitString:
+ def replace(
+ self,
+ old: str,
+ new: str,
+ count: SupportsIndex = -1,
+ ) -> BitString:
new = BitString(new)
return BitString(super().replace(old, new, count=count), False)
- def split( # type: ignore
- self,
- sep=None,
- maxsplit: SupportsIndex = -1,
- ) -> list[BitString]:
+ def split(
+ self,
+ sep: str | None = None,
+ maxsplit: SupportsIndex = -1,
+ ) -> list[str]:
return [BitString(word) for word in super().split(sep, maxsplit)]
- def zfill(self, width) -> BitString:
+ def zfill(self, width: SupportsIndex) -> BitString:
return BitString(super().zfill(width), False)
- def __repr__(self):
+ def __repr__(self) -> str:
return f'BitString("{self.__str__()}")'
- def __int__(self):
+ def __int__(self) -> int:
return int(self, 2) if self else 0
- def __bytes__(self):
+ def to_bytes(self, length: int = -1) -> bytes:
s = str(self)
- bs = []
+ bs: list[int] = []
while s:
- bs.append(int(s[-8:], 2))
+ bs.insert(0, int(s[-8:], 2))
s = s[:-8]
+ if length >= 0:
+ bs = list(itertools.dropwhile(lambda c: c == 0, bs))
+ if len(bs) > length:
+ raise ValueError(
+ f"Cannot fit a BitString of length {len(self)} into a "
+ f"bytes instance of length {length}"
+ )
+ # "zfill" the result with 0 bytes
+ bs = [0] * (length - len(bs)) + bs
return bytes(bs)
- def __lt__(self, o):
+ def __bytes__(self) -> bytes:
+ return self.to_bytes()
+
+ def __lt__(self, o: object) -> bool:
if isinstance(o, BitString):
return super().__lt__(o)
return NotImplemented
- def __eq__(self, o):
+ def __eq__(self, o: object) -> bool:
return isinstance(o, BitString) and super().__eq__(o)
- def __hash__(self):
+ def __hash__(self) -> int:
return hash(BitString) ^ super().__hash__()
- def __getitem__(self, key):
+ def __getitem__(self, key: SupportsIndex | slice[Any, Any, Any]) -> str:
return BitString(super().__getitem__(key), False)
- def __add__(self, o):
+ def __add__(self, o: str) -> BitString:
"""Return self + o"""
if not isinstance(o, str):
- raise TypeError((
- "Can only concatenate str "
- "(not '{0}') to BitString"
- ).format(type(o)))
- return BitString(''.join([self, o]))
+ raise TypeError(
+ ("Can only concatenate str (not '{0}') to BitString").format(
+ type(o)
+ )
+ )
+ return BitString("".join([self, o]))
- def __radd__(self, o):
+ def __radd__(self, o: str) -> BitString:
if not isinstance(o, str):
- raise TypeError((
- "Can only concatenate str (not '{0}') to BitString"
- ).format(type(o)))
- return BitString(''.join([o, self]))
+ raise TypeError(
+ (f"Can only concatenate str (not '{0}') to BitString").format(
+ type(o)
+ )
+ )
+ return BitString("".join([o, self]))
- def __lshift__(self, amount: int):
+ def __lshift__(self, amount: int) -> BitString:
"""
Shifts each the bitstring to the left by the given amount.
String length is preserved.
i.e. BitString('000101') << 1 == BitString('001010')
"""
return BitString(
- "".join([self, *("0" for _ in range(amount))])[-len(self):], False
+ "".join([self, *("0" for _ in range(amount))])[-len(self) :], False
)
- def __rshift__(self, amount: int):
+ def __rshift__(self, amount: int) -> BitString:
"""
Shifts each bit in the bitstring to the right by the given amount.
String length is preserved.
"""
return BitString(self[:-amount], False).zfill(width=len(self))
- def __invert__(self):
+ def __invert__(self) -> BitString:
"""
Inverts (~) each bit in the bitstring
"""
return BitString("".join("1" if x == "0" else "0" for x in self))
- def __and__(self, o):
+ def __and__(self, o: str) -> BitString:
"""
Performs a bitwise and (``&``) with the given operand.
A ``ValueError`` is raised if the operand is not the same length.
False,
)
- def __or__(self, o):
+ def __or__(self, o: str) -> BitString:
"""
Performs a bitwise or (``|``) with the given operand.
A ``ValueError`` is raised if the operand is not the same length.
False,
)
- def __xor__(self, o):
+ def __xor__(self, o: str) -> BitString:
"""
Performs a bitwise xor (``^``) with the given operand.
A ``ValueError`` is raised if the operand is not the same length.
from typing import TYPE_CHECKING
from uuid import UUID as _python_UUID
+from .bitstring import BitString
from ...sql import sqltypes
from ...sql import type_api
from ...sql.type_api import TypeEngine
-from .bitstring import BitString
-
if TYPE_CHECKING:
from ...engine.interfaces import Dialect
+ from ...sql.operators import ColumnOperators
from ...sql.operators import OperatorType
+ from ...sql.type_api import _BindProcessorType
from ...sql.type_api import _LiteralProcessorType
+ from ...sql.type_api import _ResultProcessorType
_DECIMAL_TYPES = (1231, 1700)
_FLOAT_TYPES = (700, 701, 1021, 1022)
self.length = length or 1
self.varying = varying
- def bind_processor(self, dialect):
- def bound_value(value):
+ def bind_processor(
+ self, dialect: Dialect
+ ) -> _BindProcessorType[BitString]:
+ def bound_value(value: Any) -> Any:
if isinstance(value, BitString):
return str(value)
return value
+
return bound_value
- def result_processor(self, dialect, coltype):
- def from_result_value(value):
+ def result_processor(
+ self, dialect: Dialect, coltype: object
+ ) -> _ResultProcessorType[BitString]:
+ def from_result_value(value: Any) -> Any:
if value is not None:
value = BitString(value)
return value
+
return from_result_value
- def coerce_compared_value(self, op, value) -> TypeEngine[Any]:
+ def coerce_compared_value(
+ self, op: OperatorType | None, value: Any
+ ) -> TypeEngine[Any]:
if isinstance(value, str):
return self
return super().coerce_compared_value(op, value)
@property
- def python_type(self):
+ def python_type(self) -> type[Any]:
return BitString
class comparator_factory(TypeEngine.Comparator[BitString]):
- def __lshift__(self, other: Any):
+ def __lshift__(self, other: Any) -> ColumnOperators:
return self.bitwise_lshift(other)
- def __rshift__(self, other: Any):
+ def __rshift__(self, other: Any) -> ColumnOperators:
return self.bitwise_rshift(other)
- def __and__(self, other: Any):
+ def __and__(self, other: Any) -> ColumnOperators:
return self.bitwise_and(other)
- def __or__(self, other: Any):
+ def __or__(self, other: Any) -> ColumnOperators:
return self.bitwise_or(other)
- def __invert__(self):
+ # __xor__ is not defined on sql.operators.ColumnOperators.
+ # Use `bitwise_xor` directly instead.
+ # def __xor__(self, other: Any) -> ColumnOperators:
+ # return self.bitwise_xor(other)
+
+ def __invert__(self) -> ColumnOperators:
return self.bitwise_not()
+
PGBit = BIT
-from sqlalchemy.testing import fixtures
-
+from sqlalchemy import testing
from sqlalchemy.dialects.postgresql import BitString
+from sqlalchemy.testing import fixtures
+from sqlalchemy.testing.assertions import assert_raises
from sqlalchemy.testing.assertions import eq_
from sqlalchemy.testing.assertions import is_false
from sqlalchemy.testing.assertions import is_true
-from sqlalchemy.testing.assertions import assert_raises
class BitStringTests(fixtures.TestBase):
+ __only_on__ = "postgresql"
- def test_ctor(self):
+ def test_str_conversion(self):
x = BitString("1110111")
eq_(str(x), "1110111")
- eq_(int(x), 119)
eq_(BitString("111"), BitString("111"))
is_false(BitString("111") == "111")
eq_(BitString("011")[1], BitString("1"))
- def test_int_conversion(self):
- assert_raises(ValueError, lambda: BitString.from_int(127, length=6))
-
- eq_(BitString.from_int(127, length=8), BitString("01111111"))
- eq_(int(BitString.from_int(127, length=8)), 127)
-
- eq_(BitString.from_int(119, length=10), BitString("0001110111"))
- eq_(int(BitString.from_int(119, length=10)), 119)
-
- def test_bytes_conversion(self):
- eq_(BitString.from_bytes(b"\x01"), BitString("0000001"))
- eq_(BitString.from_bytes(b"\x01", 4), BitString("00000001"))
-
- eq_(BitString.from_bytes(b"\xaf\x04"), BitString("101011110010"))
- eq_(
- BitString.from_bytes(b"\xaf\x04", 12),
- BitString("0000101011110010"),
- )
- assert_raises(
- ValueError, lambda: BitString.from_bytes(b"\xaf\x04", 4), 1
- )
+ assert_raises(ValueError, lambda: BitString("1246"))
+
+ @testing.combinations(
+ (0, 0, BitString("")),
+ (0, 1, BitString("0")),
+ (1, 1, BitString("1")),
+ (1, 0, ValueError),
+ (1, -1, ValueError),
+ (2, 1, ValueError),
+ (-1, 4, ValueError),
+ (1, 4, BitString("0001")),
+ (1, 10, BitString("0000000001")),
+ (127, 8, BitString("01111111")),
+ (127, 10, BitString("0001111111")),
+ (1404, 8, ValueError),
+ (1404, 12, BitString("010101111100")),
+ argnames="source, bitlen, result_or_error",
+ )
+ def test_int_conversion(self, source, bitlen, result_or_error):
+ if isinstance(result_or_error, type):
+ assert_raises(
+ result_or_error, lambda: BitString.from_int(source, bitlen)
+ )
+ return
+
+ result = result_or_error
+
+ bits = BitString.from_int(source, bitlen)
+ eq_(bits, result)
+ eq_(int(bits), source)
+
+ @testing.combinations(
+ (b"", -1, BitString("")),
+ (b"", 4, BitString("0000")),
+ (b"\x00", 1, BitString("0")),
+ (b"\x01", 1, BitString("1")),
+ (b"\x01", 4, BitString("0001")),
+ (b"\x01", 10, BitString("0000000001")),
+ (b"\x01", -1, BitString("00000001")),
+ (b"\xff", 10, BitString("0011111111")),
+ (b"\xaf\x04", 8, ValueError),
+ (b"\xaf\x04", 16, BitString("1010111100000100")),
+ (b"\xaf\x04", 20, BitString("00001010111100000100")),
+ argnames="source, bitlen, result_or_error",
+ )
+ def test_bytes_conversion(self, source, bitlen, result_or_error):
+ if isinstance(result_or_error, type):
+ assert_raises(
+ result_or_error,
+ lambda: BitString.from_bytes(source, length=bitlen),
+ )
+ return
+ result = result_or_error
+
+ bits = BitString.from_bytes(source, bitlen)
+ eq_(bits, result)
+
+ # Expecting a roundtrip conversion in this case is nonsensical
+ if source == b"" and bitlen > 0:
+ return
+ eq_(bits.to_bytes(len(source)), source)
def test_get_set_bit(self):
eq_(BitString("1010").get_bit(2), "1")
def test_string_methods(self):
- # Which of these methods should be overridden to produce BitStrings?
- eq_(BitString("111").center(8), " 111 ")
-
- eq_(BitString("0101").ljust(8), "0101 ")
- eq_(BitString("0110").rjust(8), " 0110")
-
eq_(BitString("01100").lstrip(), BitString("1100"))
eq_(BitString("01100").rstrip(), BitString("011"))
eq_(BitString("01100").strip(), BitString("11"))
eq_(BitString("0110").split("11"), [BitString("0"), BitString("0")])
eq_(BitString("111").zfill(8), BitString("00000111"))
- def test_str_ops(self):
+ def test_string_operators(self):
is_true("1" in BitString("001"))
is_true("0" in BitString("110"))
is_false("1" in BitString("000"))
eq_(BitString("010") + "001", BitString("010001"))
eq_("001" + BitString("010"), BitString("001010"))
- def test_bitwise_ops(self):
+ def test_bitwise_operators(self):
eq_(~BitString("0101"), BitString("1010"))
eq_(BitString("010") & BitString("011"), BitString("010"))
eq_(BitString("010") | BitString("011"), BitString("011"))
from sqlalchemy.dialects.postgresql import array_agg
from sqlalchemy.dialects.postgresql import asyncpg
from sqlalchemy.dialects.postgresql import base
-from sqlalchemy.dialects.postgresql import BitString
from sqlalchemy.dialects.postgresql import BIT
+from sqlalchemy.dialects.postgresql import BitString
from sqlalchemy.dialects.postgresql import BYTEA
from sqlalchemy.dialects.postgresql import CITEXT
from sqlalchemy.dialects.postgresql import DATEMULTIRANGE
assert t.c.bitstring_varying.type.length is None
assert t.c.bitstring_varying_6.type.varying is True
- assert t.c.bitstring_varying_6.type.length == 6
+ assert t.c.bitstring_varying_6.type.length == 6
assert t.c.bitstring_4.type.varying is False
assert t.c.bitstring_4.type.length == 4
-
@testing.combinations(
(postgresql.INET, "127.0.0.1"),
(postgresql.CIDR, "192.168.100.128/25"),
"bits",
metadata,
Column("name", String),
- Column("value", column_type)
+ Column("value", column_type),
)
t.create(connection)
connection.execute(t.insert(), {"name": "test", "value": value})
- print('value type affinity', t.c.value.type._type_affinity)
+ print("value type affinity", t.c.value.type._type_affinity)
eq_(
connection.scalar(select(t.c.name).where(t.c.value == value)),
"test",
)
- result_value = connection.scalar(select(t.c.value).where(t.c.name == "test"))
+ result_value = connection.scalar(
+ select(t.c.value).where(t.c.name == "test")
+ )
assert isinstance(result_value, BitString)
assert str(result_value) == str(value)
class BitTests(fixtures.TestBase):
+ __dialect__ = "postgresql"
+ __only_on__ = "postgresql"
+
def test_concatenation(self, connection):
coltype = BIT(varying=True)
q = select(
- literal(BitString('1111'), coltype).concat(BitString('0000'))
+ literal(BitString("1111"), coltype).concat(BitString("0000"))
)
r = connection.execute(q).first()
- eq_(r[0], BitString('11110000'))
+ eq_(r[0], BitString("11110000"))
- @testing.skip("compiler bug")
+ @testing.skip_if("postgresql", "sql compiler bug")
def test_invert_operator(self, connection):
coltype = BIT(4)
- q = select(
- literal(BitString('0010'), coltype).bitwise_not()
- )
+ q = select(literal(BitString("0010"), coltype).bitwise_not())
r = connection.execute(q).first()
# Observing r[0] == '1101' here.
+ #
# See: sql.compiler.Compiler._label_select_column
# The unary operator does not "wrap a column expression"
# and it isn't a from clause of the select,
# the compiler doesn't actually add the column to the select's
# result_columns and thus the type's result_processor never gets
# called.
- eq_(r[0], BitString('1101'))
+ eq_(r[0], BitString("1101"))
def test_and_operator(self, connection):
coltype = BIT(6)
q1 = select(
- literal(BitString('001010'), coltype)
- & literal(BitString('010111'), coltype)
+ literal(BitString("001010"), coltype)
+ & literal(BitString("010111"), coltype)
)
r1 = connection.execute(q1).first()
- eq_(r1[0], BitString('000010'))
+ eq_(r1[0], BitString("000010"))
q2 = select(
- literal(BitString('010101'), coltype) & BitString('001011')
+ literal(BitString("010101"), coltype) & BitString("001011")
)
r2 = connection.execute(q2).first()
- eq_(r2[0], BitString('000001'))
+ eq_(r2[0], BitString("000001"))
def test_or_operator(self, connection):
coltype = BIT(6)
q1 = select(
- literal(BitString('001010'), coltype)
- & literal(BitString('010111'), coltype)
+ literal(BitString("001010"), coltype)
+ | literal(BitString("010111"), coltype)
)
r1 = connection.execute(q1).first()
- eq_(r1[0], BitString('011111'))
+ eq_(r1[0], BitString("011111"))
q2 = select(
- literal(BitString('010101')) & BitString('001001')
+ literal(BitString("010101"), coltype) | BitString("001011")
)
r2 = connection.execute(q2).first()
- eq_(r2[0], BitString('011101'))
+ eq_(r2[0], BitString("011111"))
def test_xor_operator(self, connection):
coltype = BIT(6)
q1 = select(
- literal(BitString('001010'), coltype)
- & literal(BitString('010111'), coltype)
+ literal(BitString("001010"), coltype).bitwise_xor(
+ literal(BitString("010111"), coltype)
+ )
)
r1 = connection.execute(q1).first()
- eq_(r1[0], BitString('001101'))
+ eq_(r1[0], BitString("011101"))
q2 = select(
- literal(BitString('010101'), coltype) & BitString('001011')
+ literal(BitString("010101"), coltype).bitwise_xor(
+ BitString("001011")
+ )
)
r2 = connection.execute(q2).first()
- eq_(r2[0], BitString('011110'))
+ eq_(r2[0], BitString("011110"))
def test_lshift_operator(self, connection):
coltype = BIT(6)
q = select(
- literal(BitString('001010'), coltype),
- literal(BitString('001010'), coltype) << 1,
+ literal(BitString("001010"), coltype),
+ literal(BitString("001010"), coltype) << 1,
)
r = connection.execute(q).first()
- eq_(tuple(r), (BitString('001010'), BitString('010100')))
+ eq_(tuple(r), (BitString("001010"), BitString("010100")))
def test_rshift_operator(self, connection):
coltype = BIT(6)
q = select(
- literal(BitString('001010'), coltype),
- literal(BitString('001010'), coltype) >> 1
+ literal(BitString("001010"), coltype),
+ literal(BitString("001010"), coltype) >> 1,
)
r = connection.execute(q).first()
- eq_(tuple(r), (BitString('001010'), BitString('000101')))
+ eq_(tuple(r), (BitString("001010"), BitString("000101")))
class RangeMiscTests(fixtures.TestBase):