Skip to content

Commit 8d13e29

Browse files
author
Scott Griffiths
committed
A few more tweaks to dtypes.
1 parent 973a764 commit 8d13e29

File tree

2 files changed

+24
-26
lines changed

2 files changed

+24
-26
lines changed

bitstring/array_.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,19 +551,21 @@ def _promotetype(cls, type1: Dtype, type2: Dtype) -> Dtype:
551551
6. In a tie the first type wins against the second type.
552552
553553
"""
554-
if type1.is_float + type1.is_integer + type2.is_float + type2.is_integer != 2:
554+
def is_float(x): return x.return_type is float
555+
def is_int(x): return x.return_type is int
556+
if is_float(type1) + is_int(type1) + is_float(type2) + is_int(type2) != 2:
555557
raise ValueError(f"Only integer and floating point types can be combined - not '{type1}' and '{type2}'.")
556558
# If same type choose the widest
557559
if type1.name == type2.name:
558560
return type1 if type1.length > type2.length else type2
559561
# We choose floats above integers, irrespective of the widths
560-
if type1.is_float and type2.is_integer:
562+
if is_float(type1) and is_int(type2):
561563
return type1
562-
if type1.is_integer and type2.is_float:
564+
if is_int(type1) and is_float(type2):
563565
return type2
564-
if type1.is_float and type2.is_float:
566+
if is_float(type1) and is_float(type2):
565567
return type2 if type2.length > type1.length else type1
566-
assert type1.is_integer and type2.is_integer
568+
assert is_int(type1) and is_int(type2)
567569
if type1.is_signed and not type2.is_signed:
568570
return type1
569571
if type2.is_signed and not type1.is_signed:

bitstring/dtypes.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,6 @@ def _new_from_token(cls, token: str, length: Optional[int] = None) -> Dtype:
3434
def __hash__(self) -> int:
3535
return 0 # TODO: Optimise :)
3636

37-
@property
38-
def is_integer(self) -> bool:
39-
return self.return_type == int
40-
41-
@property
42-
def is_float(self) -> bool:
43-
return self.return_type == float
44-
4537
@classmethod
4638
@functools.lru_cache(CACHE_SIZE)
4739
def create(cls, definition: DtypeDefinition, length: Optional[int]) -> Dtype:
@@ -52,7 +44,7 @@ def create(cls, definition: DtypeDefinition, length: Optional[int]) -> Dtype:
5244
if x.bitlength is not None:
5345
x.bitlength *= x.bits_per_item
5446
x.is_unknown_length = definition.is_unknown_length
55-
if x.is_unknown_length:
47+
if x.is_unknown_length or len(dtype_register.names[x.name].fixed_length) == 1:
5648
x.read_fn = definition.read_fn
5749
else:
5850
x.read_fn = functools.partial(definition.read_fn, length=x.bitlength)
@@ -88,7 +80,9 @@ def __init__(self, name: str, set_fn, get_fn, return_type: Any = Any, is_signed:
8880

8981
# Consistency checks
9082
if is_unknown_length and fixed_length is not None:
91-
raise ValueError("Can't set is_unknown_length and give a value for length.")
83+
raise ValueError("Can't set is_unknown_length and give a value for fixed_length.")
84+
if int(multiplier) != multiplier or multiplier <= 0:
85+
raise ValueError("multiplier must be an positive integer")
9286

9387
self.name = name
9488
self.description = description
@@ -106,17 +100,9 @@ def __init__(self, name: str, set_fn, get_fn, return_type: Any = Any, is_signed:
106100
self.set_fn = set_fn
107101
self.get_fn = get_fn # Interpret everything
108102

109-
if not self.is_unknown_length:
110-
# TODO: Move the length logic out of the function
111-
def read_fn(bs, start, length):
112-
if length is None:
113-
assert len(self.fixed_length) == 1
114-
return self.get_fn(bs[start:start + self.fixed_length[0]])
115-
else:
116-
return self.get_fn(bs[start:start + length])
117-
self.read_fn = read_fn
118-
else:
119-
# For unknown lengths we get a reading function instead of a getter, so switch them around...
103+
# Create a reading function from the get_fn.
104+
if self.is_unknown_length:
105+
# For unknown lengths the get_fn is really a reading function, so switch them around and create a new get_fn
120106
self.read_fn = get_fn
121107
def new_get_fn(bs):
122108
try:
@@ -127,6 +113,14 @@ def new_get_fn(bs):
127113
raise ValueError # TODO
128114
return value
129115
self.get_fn = new_get_fn
116+
else:
117+
if len(self.fixed_length) == 1:
118+
def read_fn(bs, start):
119+
return self.get_fn(bs[start:start + self.fixed_length[0]])
120+
else:
121+
def read_fn(bs, start, length):
122+
return self.get_fn(bs[start:start + length])
123+
self.read_fn = read_fn
130124

131125
self.bitlength2chars_fn = bitlength2chars_fn
132126

@@ -173,6 +167,7 @@ def add_dtype(cls, definition: DtypeDefinition):
173167
cls._modified_flag = True
174168
if definition.get_fn is not None:
175169
setattr(Bits, definition.name, property(fget=definition.get_fn, doc=f"The bitstring as {definition.description}. Read only."))
170+
if definition.set_fn is not None:
176171
setattr(BitArray, definition.name, property(fget=definition.get_fn, fset=definition.set_fn, doc=f"The bitstring as {definition.description}. Read and write."))
177172

178173
@classmethod
@@ -182,6 +177,7 @@ def add_dtype_alias(cls, name: str, alias: str):
182177
cls._modified_flag = True
183178
if definition.get_fn is not None:
184179
setattr(Bits, alias, property(fget=definition.get_fn, doc=f"An alias for '{name}'. Read only."))
180+
if definition.set_fn is not None:
185181
setattr(BitArray, alias, property(fget=definition.get_fn, fset=definition.set_fn, doc=f"An alias for '{name}'. Read and write."))
186182

187183
@classmethod

0 commit comments

Comments
 (0)