99CACHE_SIZE = 256
1010
1111
12- class Dtype :
12+ def scaled_get_fn (get_fn , s : Union [int , float ]):
13+ def wrapper (* args , scale = s , ** kwargs ):
14+ return get_fn (* args , ** kwargs ) * scale
15+ return wrapper
16+
17+
18+ def scaled_set_fn (set_fn , s : Union [int , float ]):
19+ def wrapper (bs , value , * args , scale = s , ** kwargs ):
20+ return set_fn (bs , value / scale , * args , ** kwargs )
21+ return wrapper
22+
23+
24+ def scaled_read_fn (read_fn , s : Union [int , float ]):
25+ def wrapper (* args , scale = s , ** kwargs ):
26+ return read_fn (* args , ** kwargs ) * scale
27+ return wrapper
1328
14- __slots__ = ('read_fn' , 'name' , 'set_fn' , 'get_fn' , 'return_type' , 'is_signed' , 'set_fn_needs_length' , 'variable_length' , 'bitlength' , 'bits_per_item' , 'length' )
15-
16- name : str
17- read_fn : Callable
18- set_fn : Callable
19- get_fn : Callable
20- return_type : Any
21- is_signed : bool
22- set_fn_needs_length : bool
23- variable_length : bool
24- bitlength : Optional [int ]
25- bits_per_item : int
26- length : Optional [int ]
27-
28- def __new__ (cls , token : Union [str , Dtype , None ] = None , / , length : Optional [int ] = None ) -> Dtype :
29+
30+ class Dtype :
31+ _name : str
32+ _read_fn : Callable
33+ _set_fn : Callable
34+ _get_fn : Callable
35+ _return_type : Any
36+ _is_signed : bool
37+ _set_fn_needs_length : bool
38+ _variable_length : bool
39+ _bitlength : Optional [int ]
40+ _bits_per_item : int
41+ _length : Optional [int ]
42+ _scale : Union [None , float , int ]
43+
44+
45+ def __new__ (cls , token : Union [str , Dtype , None ] = None , / , length : Optional [int ] = None , scale : Union [None , float , int ] = None ) -> Dtype :
2946 if isinstance (token , cls ):
3047 return token
3148 if token is not None :
3249 if length is None :
33- return cls ._new_from_token (token )
50+ x = cls ._new_from_token (token , scale )
51+ return x
3452 else :
35- return dtype_register .get_dtype (token , length )
53+ x = dtype_register .get_dtype (token , length , scale )
54+ return x
3655 return super ().__new__ (cls )
3756
57+ @property
58+ def scale (self ) -> int :
59+ return self ._scale
60+
61+ @property
62+ def name (self ) -> str :
63+ return self ._name
64+
65+ @property
66+ def length (self ) -> int :
67+ return self ._length
68+
69+ @property
70+ def bitlength (self ) -> int :
71+ return self ._bitlength
72+
73+ @property
74+ def bits_per_item (self ) -> int :
75+ return self ._bits_per_item
76+
77+ @property
78+ def variable_length (self ) -> bool :
79+ return self ._variable_length
80+
81+ @property
82+ def return_type (self ) -> Any :
83+ return self ._return_type
84+
85+ @property
86+ def is_signed (self ) -> bool :
87+ return self ._is_signed
88+
89+ @property
90+ def set_fn (self ) -> Optional [Callable ]:
91+ return self ._set_fn
92+
93+ @property
94+ def get_fn (self ) -> Callable :
95+ return self ._get_fn
96+
97+ @property
98+ def read_fn (self ) -> Callable :
99+ return self ._read_fn
100+
101+ def _set_scale (self , value : Union [None , float , int ]) -> None :
102+ self ._scale = value
103+ if self ._scale is None :
104+ return
105+ if not hasattr (self , 'unscaled_get_fn' ):
106+ self .unscaled_get_fn = self ._get_fn
107+ self .unscaled_set_fn = self ._set_fn
108+ self .unscaled_read_fn = self ._read_fn
109+ self ._get_fn = scaled_get_fn (self .unscaled_get_fn , self ._scale )
110+ self ._set_fn = scaled_set_fn (self .unscaled_set_fn , self ._scale )
111+ self ._read_fn = scaled_read_fn (self .unscaled_read_fn , self ._scale )
112+
38113 @classmethod
39114 @functools .lru_cache (CACHE_SIZE )
40- def _new_from_token (cls , token : str ) -> Dtype :
115+ def _new_from_token (cls , token : str , scale : Union [ None , float , int ] = None ) -> Dtype :
41116 token = '' .join (token .split ())
42- return dtype_register .get_dtype (* utils .parse_name_length_token (token ))
117+ return dtype_register .get_dtype (* utils .parse_name_length_token (token ), scale = scale )
43118
44119 def __hash__ (self ) -> int :
45- return hash ((self .name , self .length ))
120+ return hash ((self ._name , self ._length ))
46121
47122 @classmethod
48123 @functools .lru_cache (CACHE_SIZE )
49- def _create (cls , definition : DtypeDefinition , length : Optional [int ]) -> Dtype :
124+ def _create (cls , definition : DtypeDefinition , length : Optional [int ], scale : Union [ None , float , int ] ) -> Dtype :
50125 x = cls .__new__ (cls )
51- x .name = definition .name
52- x .bitlength = x .length = length
53- x .bits_per_item = definition .multiplier
54- if x .bitlength is not None :
55- x .bitlength *= x .bits_per_item
56- x .set_fn_needs_length = definition .set_fn_needs_length
57- x .variable_length = definition .variable_length
58- if x .variable_length or len (dtype_register .names [x .name ].allowed_lengths ) == 1 :
59- x .read_fn = definition .read_fn
126+ x ._name = definition .name
127+ x ._bitlength = x ._length = length
128+ x ._bits_per_item = definition .multiplier
129+ if x ._bitlength is not None :
130+ x ._bitlength *= x ._bits_per_item
131+ x ._set_fn_needs_length = definition .set_fn_needs_length
132+ x ._variable_length = definition .variable_length
133+ if x ._variable_length or len (dtype_register .names [x ._name ].allowed_lengths ) == 1 :
134+ x ._read_fn = definition .read_fn
60135 else :
61- x .read_fn = functools .partial (definition .read_fn , length = x .bitlength )
136+ x ._read_fn = functools .partial (definition .read_fn , length = x ._bitlength )
62137 if definition .set_fn is None :
63- x .set_fn = None
138+ x ._set_fn = None
64139 else :
65- if x .set_fn_needs_length :
66- x .set_fn = functools .partial (definition .set_fn , length = x .bitlength )
140+ if x ._set_fn_needs_length :
141+ x ._set_fn = functools .partial (definition .set_fn , length = x ._bitlength )
67142 else :
68- x .set_fn = definition .set_fn
69- x .get_fn = definition .get_fn
70- x .return_type = definition .return_type
71- x .is_signed = definition .is_signed
143+ x ._set_fn = definition .set_fn
144+ x ._get_fn = definition .get_fn
145+ x ._return_type = definition .return_type
146+ x ._is_signed = definition .is_signed
147+ x ._set_scale (scale )
72148 return x
73149
74150 def build (self , value : Any , / ) -> bitstring .Bits :
75151 """Create a bitstring from a value."""
76152 b = bitstring .Bits ()
77- self .set_fn (b , value )
153+ self ._set_fn (b , value )
78154 return b
79155
80156 def parse (self , b : BitsType , / ) -> Any :
81157 """Parse a bitstring into a value."""
82158 b = bitstring .Bits ._create_from_bitstype (b )
83- return self .get_fn (bitstring .Bits (b ))
159+ return self ._get_fn (bitstring .Bits (b ))
84160
85161 def __str__ (self ) -> str :
86- hide_length = self .variable_length or len (dtype_register .names [self .name ].allowed_lengths ) == 1 or self .length is None
87- length_str = '' if hide_length else str (self .length )
88- return f"{ self .name } { length_str } "
162+ if self ._scale is not None :
163+ return self .__repr__ ()
164+ hide_length = self ._variable_length or len (dtype_register .names [self ._name ].allowed_lengths ) == 1 or self ._length is None
165+ length_str = '' if hide_length else str (self ._length )
166+ return f"{ self ._name } { length_str } "
89167
90168 def __repr__ (self ) -> str :
91- hide_length = self .variable_length or len (dtype_register .names [self .name ].allowed_lengths ) == 1 or self .length is None
92- length_str = '' if hide_length else ', ' + str (self .length )
93- return f"{ self .__class__ .__name__ } ('{ self .name } '{ length_str } )"
169+ hide_length = self ._variable_length or len (dtype_register .names [self ._name ].allowed_lengths ) == 1 or self ._length is None
170+ length_str = '' if hide_length else ', ' + str (self ._length )
171+ scale_str = '' if self ._scale is None else f', scale={ self ._scale } '
172+ return f"{ self .__class__ .__name__ } ('{ self ._name } '{ length_str } { scale_str } )"
94173
95174 def __eq__ (self , other : Any ) -> bool :
96175 if isinstance (other , Dtype ):
97- return self .name == other .name and self .length == other .length
176+ return self ._name == other ._name and self ._length == other ._length
98177 return False
99178
100179
@@ -186,7 +265,7 @@ def read_fn(bs, start):
186265 self .read_fn = read_fn
187266 self .bitlength2chars_fn = bitlength2chars_fn
188267
189- def get_dtype (self , length : Optional [int ] = None ) -> Dtype :
268+ def get_dtype (self , length : Optional [int ] = None , scale : Union [ None , float , int ] = None ) -> Dtype :
190269 if self .allowed_lengths :
191270 if length is None :
192271 if len (self .allowed_lengths ) == 1 :
@@ -198,11 +277,11 @@ def get_dtype(self, length: Optional[int] = None) -> Dtype:
198277 else :
199278 raise ValueError (f"A length of { length } was supplied for the '{ self .name } ' dtype which is not one of its possible lengths (must be one of { self .allowed_lengths } )." )
200279 if length is None :
201- d = Dtype ._create (self , None )
280+ d = Dtype ._create (self , None , scale )
202281 return d
203282 if self .variable_length :
204283 raise ValueError (f"A length ({ length } ) shouldn't be supplied for the variable length dtype '{ self .name } '." )
205- d = Dtype ._create (self , length )
284+ d = Dtype ._create (self , length , scale )
206285 return d
207286
208287 def __repr__ (self ) -> str :
@@ -240,13 +319,13 @@ def add_dtype_alias(cls, name: str, alias: str):
240319 setattr (bitstring .bitarray_ .BitArray , alias , property (fget = definition .get_fn , fset = definition .set_fn , doc = f"An alias for '{ name } '. Read and write." ))
241320
242321 @classmethod
243- def get_dtype (cls , name : str , length : Optional [int ]) -> Dtype :
322+ def get_dtype (cls , name : str , length : Optional [int ], scale : Union [ None , float , int ] = None ) -> Dtype :
244323 try :
245324 definition = cls .names [name ]
246325 except KeyError :
247326 raise ValueError (f"Unknown Dtype name '{ name } '." )
248327 else :
249- return definition .get_dtype (length )
328+ return definition .get_dtype (length , scale )
250329
251330 @classmethod
252331 def __getitem__ (cls , name : str ) -> DtypeDefinition :
0 commit comments