bitstring 4.2.0b1__tar.gz → 4.2.0b2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bitstring-4.2.0b1/bitstring.egg-info → bitstring-4.2.0b2}/PKG-INFO +15 -14
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/README.md +14 -13
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/__init__.py +60 -11
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/array_.py +77 -44
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/bits.py +205 -197
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/bitstore.py +35 -28
- bitstring-4.2.0b2/bitstring/bitstore_helpers.py +260 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/bitstream.py +19 -2
- bitstring-4.2.0b2/bitstring/bitstring_options.py +94 -0
- bitstring-4.2.0b2/bitstring/dtypes.py +397 -0
- bitstring-4.2.0b2/bitstring/fp8.py +97 -0
- bitstring-4.2.0b2/bitstring/luts.py +248 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/methods.py +2 -5
- bitstring-4.2.0b2/bitstring/mxfp.py +200 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/utils.py +20 -24
- {bitstring-4.2.0b1 → bitstring-4.2.0b2/bitstring.egg-info}/PKG-INFO +15 -14
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring.egg-info/SOURCES.txt +5 -1
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/pyproject.toml +1 -1
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/release_notes.txt +36 -9
- bitstring-4.2.0b2/tests/test_array.py +929 -0
- bitstring-4.2.0b2/tests/test_bitarray.py +979 -0
- bitstring-4.2.0b2/tests/test_bits.py +981 -0
- bitstring-4.2.0b2/tests/test_bitstore.py +94 -0
- bitstring-4.2.0b2/tests/test_bitstream.py +4172 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/tests/test_bitstring.py +73 -74
- bitstring-4.2.0b2/tests/test_constbitstream.py +265 -0
- bitstring-4.2.0b2/tests/test_dtypes.py +134 -0
- bitstring-4.2.0b2/tests/test_fp8.py +295 -0
- bitstring-4.2.0b2/tests/test_mxfp.py +441 -0
- bitstring-4.2.0b2/tests/test_scaled_dtypes.py +13 -0
- bitstring-4.2.0b1/bitstring/bitstore_helpers.py +0 -252
- bitstring-4.2.0b1/bitstring/bitstring_options.py +0 -89
- bitstring-4.2.0b1/bitstring/dtypes.py +0 -244
- bitstring-4.2.0b1/bitstring/fp8.py +0 -93
- bitstring-4.2.0b1/tests/test_array.py +0 -915
- bitstring-4.2.0b1/tests/test_bitarray.py +0 -979
- bitstring-4.2.0b1/tests/test_bits.py +0 -974
- bitstring-4.2.0b1/tests/test_bitstore.py +0 -94
- bitstring-4.2.0b1/tests/test_bitstream.py +0 -4174
- bitstring-4.2.0b1/tests/test_constbitstream.py +0 -247
- bitstring-4.2.0b1/tests/test_dtypes.py +0 -86
- bitstring-4.2.0b1/tests/test_fp8.py +0 -220
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/LICENSE +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/MANIFEST.in +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/__main__.py +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/bitarray_.py +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/exceptions.py +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring/py.typed +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring.egg-info/dependency_links.txt +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring.egg-info/requires.txt +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/bitstring.egg-info/top_level.txt +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/setup.cfg +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/tests/__init__.py +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/tests/smalltestfile +0 -0
- {bitstring-4.2.0b1 → bitstring-4.2.0b2}/tests/test.m1v +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bitstring
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.0b2
|
|
4
4
|
Summary: Simple construction, analysis and modification of binary data.
|
|
5
5
|
Author-email: Scott Griffiths <dr.scottgriffiths@gmail.com>
|
|
6
6
|
Project-URL: homepage, https://github.com/scott-griffiths/bitstring
|
|
@@ -37,17 +37,25 @@ It has been actively maintained since 2006.
|
|
|
37
37
|
[](https://app.codacy.com/gh/scott-griffiths/bitstring/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
38
38
|
[](https://libraries.io/pypi/bitstring)
|
|
39
39
|
|
|
40
|
-
[](https://
|
|
40
|
+
[](https://www.pepy.tech/projects/bitstring)
|
|
41
41
|
[](https://pypistats.org/packages/bitstring)
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
News
|
|
45
45
|
----
|
|
46
|
-
**
|
|
46
|
+
**March 2024**: bitstring 4.2.0b2 released. This is the final beta release before 4.2.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
Install the beta with `pip install bitstring==4.2.0b2`, or use `pip install bitstring` for the latest stable version.
|
|
49
|
+
|
|
50
|
+
New in 4.2:
|
|
51
|
+
|
|
52
|
+
* Dropped support for Python 3.7. Minimum version is now 3.8.
|
|
53
|
+
* A new `Dtype` class can be optionally used to specify types.
|
|
54
|
+
* The `bitstring.options` object is now the preferred method for changing module options.
|
|
55
|
+
* New `fromstring` method as another way to create bitstrings from formatted strings.
|
|
56
|
+
* More types can now be pretty printed.
|
|
57
|
+
* A range of 8-bit, 6-bit and even 4-bit float formats added (beta):
|
|
58
|
+
* Performance improvements.
|
|
51
59
|
|
|
52
60
|
See the [release notes](https://github.com/scott-griffiths/bitstring/blob/main/release_notes.txt) for details. Please let me know if you encounter any problems.
|
|
53
61
|
|
|
@@ -137,13 +145,6 @@ Examples
|
|
|
137
145
|
Array('uint7', [45, 100, 15, 1])
|
|
138
146
|
|
|
139
147
|
|
|
140
|
-
Unit Tests
|
|
141
|
-
----------
|
|
142
|
-
|
|
143
|
-
The 700+ unit tests should all pass. They can be run from the root of the project with
|
|
144
|
-
|
|
145
|
-
python -m unittest
|
|
146
|
-
|
|
147
148
|
|
|
148
149
|
Credits
|
|
149
150
|
-------
|
|
@@ -153,4 +154,4 @@ Maintained and expanded ever since as it became unexpectedly popular.
|
|
|
153
154
|
Thanks to all those who have contributed ideas and code (and bug reports) over the years.
|
|
154
155
|
|
|
155
156
|
|
|
156
|
-
<sub>Copyright (c) 2006 -
|
|
157
|
+
<sub>Copyright (c) 2006 - 2024 Scott Griffiths</sub>
|
|
@@ -13,17 +13,25 @@ It has been actively maintained since 2006.
|
|
|
13
13
|
[](https://app.codacy.com/gh/scott-griffiths/bitstring/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
14
14
|
[](https://libraries.io/pypi/bitstring)
|
|
15
15
|
|
|
16
|
-
[](https://
|
|
16
|
+
[](https://www.pepy.tech/projects/bitstring)
|
|
17
17
|
[](https://pypistats.org/packages/bitstring)
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
News
|
|
21
21
|
----
|
|
22
|
-
**
|
|
22
|
+
**March 2024**: bitstring 4.2.0b2 released. This is the final beta release before 4.2.
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
Install the beta with `pip install bitstring==4.2.0b2`, or use `pip install bitstring` for the latest stable version.
|
|
25
|
+
|
|
26
|
+
New in 4.2:
|
|
27
|
+
|
|
28
|
+
* Dropped support for Python 3.7. Minimum version is now 3.8.
|
|
29
|
+
* A new `Dtype` class can be optionally used to specify types.
|
|
30
|
+
* The `bitstring.options` object is now the preferred method for changing module options.
|
|
31
|
+
* New `fromstring` method as another way to create bitstrings from formatted strings.
|
|
32
|
+
* More types can now be pretty printed.
|
|
33
|
+
* A range of 8-bit, 6-bit and even 4-bit float formats added (beta):
|
|
34
|
+
* Performance improvements.
|
|
27
35
|
|
|
28
36
|
See the [release notes](https://github.com/scott-griffiths/bitstring/blob/main/release_notes.txt) for details. Please let me know if you encounter any problems.
|
|
29
37
|
|
|
@@ -113,13 +121,6 @@ Examples
|
|
|
113
121
|
Array('uint7', [45, 100, 15, 1])
|
|
114
122
|
|
|
115
123
|
|
|
116
|
-
Unit Tests
|
|
117
|
-
----------
|
|
118
|
-
|
|
119
|
-
The 700+ unit tests should all pass. They can be run from the root of the project with
|
|
120
|
-
|
|
121
|
-
python -m unittest
|
|
122
|
-
|
|
123
124
|
|
|
124
125
|
Credits
|
|
125
126
|
-------
|
|
@@ -129,4 +130,4 @@ Maintained and expanded ever since as it became unexpectedly popular.
|
|
|
129
130
|
Thanks to all those who have contributed ideas and code (and bug reports) over the years.
|
|
130
131
|
|
|
131
132
|
|
|
132
|
-
<sub>Copyright (c) 2006 -
|
|
133
|
+
<sub>Copyright (c) 2006 - 2024 Scott Griffiths</sub>
|
|
@@ -10,15 +10,15 @@ BitArray -- A mutable container for binary data.
|
|
|
10
10
|
ConstBitStream -- An immutable container with streaming methods.
|
|
11
11
|
BitStream -- A mutable container with streaming methods.
|
|
12
12
|
Array -- An efficient list-like container where each item has a fixed-length binary format.
|
|
13
|
+
Dtype -- Encapsulate the data types used in the other classes.
|
|
13
14
|
|
|
14
15
|
Functions:
|
|
15
16
|
|
|
16
17
|
pack -- Create a BitStream from a format string.
|
|
17
18
|
|
|
18
19
|
Data:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
lsb0 -- If True, the least significant bit (the final bit) is indexed as bit zero.
|
|
20
|
+
|
|
21
|
+
options -- Module-wide options.
|
|
22
22
|
|
|
23
23
|
Exceptions:
|
|
24
24
|
|
|
@@ -55,7 +55,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
55
55
|
THE SOFTWARE.
|
|
56
56
|
"""
|
|
57
57
|
|
|
58
|
-
__version__ = "4.2.
|
|
58
|
+
__version__ = "4.2.0b2"
|
|
59
59
|
|
|
60
60
|
__author__ = "Scott Griffiths"
|
|
61
61
|
|
|
@@ -71,6 +71,12 @@ from .exceptions import Error, ReadError, InterpretError, ByteAlignError, Creati
|
|
|
71
71
|
from .dtypes import DtypeDefinition, dtype_register, Dtype
|
|
72
72
|
import types
|
|
73
73
|
from typing import List, Tuple, Literal
|
|
74
|
+
from .mxfp import decompress_luts as mxfp_decompress_luts
|
|
75
|
+
from .fp8 import decompress_luts as binary8_decompress_luts
|
|
76
|
+
|
|
77
|
+
# Decompress the LUTs for the exotic floating point formats
|
|
78
|
+
mxfp_decompress_luts()
|
|
79
|
+
binary8_decompress_luts()
|
|
74
80
|
|
|
75
81
|
# The Options class returns a singleton.
|
|
76
82
|
options = Options()
|
|
@@ -136,13 +142,40 @@ def float_bits2chars(bitlength: Literal[16, 32, 64]):
|
|
|
136
142
|
else:
|
|
137
143
|
return 24 # Empirical value
|
|
138
144
|
|
|
139
|
-
def
|
|
145
|
+
def p3binary_bits2chars(bitlength: Literal[8]):
|
|
140
146
|
return 19 # Empirical value
|
|
141
147
|
|
|
142
|
-
def
|
|
148
|
+
def p4binary_bits2chars(bitlength: Literal[8]):
|
|
143
149
|
# Found by looking at all the possible values
|
|
144
150
|
return 13 # Empirical value
|
|
145
151
|
|
|
152
|
+
def e4m3mxfp_bits2chars(bitlength: Literal[8]):
|
|
153
|
+
return 13
|
|
154
|
+
|
|
155
|
+
def e5m2mxfp_bits2chars(bitlength: Literal[8]):
|
|
156
|
+
return 19
|
|
157
|
+
|
|
158
|
+
def e3m2mxfp_bits2chars(bitlength: Literal[6]):
|
|
159
|
+
# Not sure what the best value is here. It's 7 without considering the scale that could be applied.
|
|
160
|
+
return 7
|
|
161
|
+
|
|
162
|
+
def e2m3mxfp_bits2chars(bitlength: Literal[6]):
|
|
163
|
+
# Not sure what the best value is here.
|
|
164
|
+
return 7
|
|
165
|
+
|
|
166
|
+
def e2m1mxfp_bits2chars(bitlength: Literal[4]):
|
|
167
|
+
# Not sure what the best value is here.
|
|
168
|
+
return 7
|
|
169
|
+
|
|
170
|
+
def e8m0mxfp_bits2chars(bitlength: Literal[8]):
|
|
171
|
+
# Can range same as float32
|
|
172
|
+
return 23
|
|
173
|
+
|
|
174
|
+
def mxint_bits2chars(bitlength: Literal[8]):
|
|
175
|
+
# Not sure what the best value is here.
|
|
176
|
+
return 10
|
|
177
|
+
|
|
178
|
+
|
|
146
179
|
def bfloat_bits2chars(bitlength: Literal[16]):
|
|
147
180
|
# Found by looking at all the possible values
|
|
148
181
|
return 23 # Empirical value
|
|
@@ -175,13 +208,9 @@ dtype_definitions = [
|
|
|
175
208
|
allowed_lengths=(0, 4, 8, ...), description="a hexadecimal string"),
|
|
176
209
|
DtypeDefinition('bin', Bits._setbin_safe, Bits._getbin, str, False, bin_bits2chars,
|
|
177
210
|
description="a binary string"),
|
|
178
|
-
DtypeDefinition('oct',Bits._setoct, Bits._getoct, str, False, oct_bits2chars,
|
|
211
|
+
DtypeDefinition('oct', Bits._setoct, Bits._getoct, str, False, oct_bits2chars,
|
|
179
212
|
allowed_lengths=(0, 3, 6, ...), description="an octal string"),
|
|
180
213
|
# Float types
|
|
181
|
-
DtypeDefinition('e5m2float', Bits._sete5m2float, Bits._gete5m2float, float, True, e5m2float_bits2chars,
|
|
182
|
-
allowed_lengths=(8,), description="an 8 bit float with e5m2float format"),
|
|
183
|
-
DtypeDefinition('e4m3float', Bits._sete4m3float, Bits._gete4m3float, float, True, e4m3float_bits2chars,
|
|
184
|
-
allowed_lengths=(8,), description="an 8 bit float with e4m3float format"),
|
|
185
214
|
DtypeDefinition('float', Bits._setfloatbe, Bits._getfloatbe, float, True, float_bits2chars,
|
|
186
215
|
allowed_lengths=(16, 32, 64), description="a big-endian floating point number"),
|
|
187
216
|
DtypeDefinition('floatle', Bits._setfloatle, Bits._getfloatle, float, True, float_bits2chars,
|
|
@@ -209,6 +238,26 @@ dtype_definitions = [
|
|
|
209
238
|
# Special case pad type
|
|
210
239
|
DtypeDefinition('pad', Bits._setpad, Bits._getpad, None, False, None,
|
|
211
240
|
description="a skipped section of padding"),
|
|
241
|
+
|
|
242
|
+
# MXFP and IEEE 8-bit float types
|
|
243
|
+
DtypeDefinition('p3binary', Bits._setp3binary, Bits._getp3binary, float, True, p3binary_bits2chars,
|
|
244
|
+
allowed_lengths=(8,), description="an 8 bit float with binary8p3 format"),
|
|
245
|
+
DtypeDefinition('p4binary', Bits._setp4binary, Bits._getp4binary, float, True, p4binary_bits2chars,
|
|
246
|
+
allowed_lengths=(8,), description="an 8 bit float with binary8p4 format"),
|
|
247
|
+
DtypeDefinition('e4m3mxfp', Bits._sete4m3mxfp, Bits._gete4m3mxfp, float, True, e4m3mxfp_bits2chars,
|
|
248
|
+
allowed_lengths=(8,), description="an 8 bit float with MXFP E4M3 format"),
|
|
249
|
+
DtypeDefinition('e5m2mxfp', Bits._sete5m2mxfp, Bits._gete5m2mxfp, float, True, e5m2mxfp_bits2chars,
|
|
250
|
+
allowed_lengths=(8,), description="an 8 bit float with MXFP E5M2 format"),
|
|
251
|
+
DtypeDefinition('e3m2mxfp', Bits._sete3m2mxfp, Bits._gete3m2mxfp, float, True, e3m2mxfp_bits2chars,
|
|
252
|
+
allowed_lengths=(6,), description="a 6 bit float with MXFP E3M2 format"),
|
|
253
|
+
DtypeDefinition('e2m3mxfp', Bits._sete2m3mxfp, Bits._gete2m3mxfp, float, True, e2m3mxfp_bits2chars,
|
|
254
|
+
allowed_lengths=(6,), description="a 6 bit float with MXFP E2M3 format"),
|
|
255
|
+
DtypeDefinition('e2m1mxfp', Bits._sete2m1mxfp, Bits._gete2m1mxfp, float, True, e2m1mxfp_bits2chars,
|
|
256
|
+
allowed_lengths=(4,), description="a 4 bit float with MXFP E2M1 format"),
|
|
257
|
+
DtypeDefinition('e8m0mxfp', Bits._sete8m0mxfp, Bits._gete8m0mxfp, float, False, e8m0mxfp_bits2chars,
|
|
258
|
+
allowed_lengths=(8,), description="an 8 bit float with MXFP E8M0 format"),
|
|
259
|
+
DtypeDefinition('mxint', Bits._setmxint, Bits._getmxint, float, True, mxint_bits2chars,
|
|
260
|
+
allowed_lengths=(8,), description="an 8 bit float with MXFP INT8 format"),
|
|
212
261
|
]
|
|
213
262
|
|
|
214
263
|
|
|
@@ -70,6 +70,11 @@ class Array:
|
|
|
70
70
|
def __init__(self, dtype: Union[str, Dtype], initializer: Optional[Union[int, Array, array.array, Iterable, Bits, bytes, bytearray, memoryview, BinaryIO]] = None,
|
|
71
71
|
trailing_bits: Optional[BitsType] = None) -> None:
|
|
72
72
|
self.data = BitArray()
|
|
73
|
+
if isinstance(dtype, Dtype) and dtype.scale == 'auto':
|
|
74
|
+
if isinstance(initializer, (int, Bits, bytes, bytearray, memoryview, BinaryIO)):
|
|
75
|
+
raise TypeError("An Array with an 'auto' scale factor can only be created from an iterable of values.")
|
|
76
|
+
auto_scale = self._calculate_auto_scale(initializer, dtype.name, dtype.length)
|
|
77
|
+
dtype = Dtype(dtype.name, dtype.length, scale=auto_scale)
|
|
73
78
|
try:
|
|
74
79
|
self._set_dtype(dtype)
|
|
75
80
|
except ValueError as e:
|
|
@@ -87,6 +92,43 @@ class Array:
|
|
|
87
92
|
if trailing_bits is not None:
|
|
88
93
|
self.data += BitArray._create_from_bitstype(trailing_bits)
|
|
89
94
|
|
|
95
|
+
_largest_values = None
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _calculate_auto_scale(initializer, name: str, length: Optional[int]) -> float:
|
|
98
|
+
# Now need to find the largest power of 2 representable with this format.
|
|
99
|
+
if Array._largest_values is None:
|
|
100
|
+
Array._largest_values = {
|
|
101
|
+
'mxint8': Bits('0b01111111').mxint8, # 1.0 + 63.0/64.0,
|
|
102
|
+
'e2m1mxfp4': Bits('0b0111').e2m1mxfp4, # 6.0
|
|
103
|
+
'e2m3mxfp6': Bits('0b011111').e2m3mxfp6, # 7.5
|
|
104
|
+
'e3m2mxfp6': Bits('0b011111').e3m2mxfp6, # 28.0
|
|
105
|
+
'e4m3mxfp8': Bits('0b01111110').e4m3mxfp8, # 448.0
|
|
106
|
+
'e5m2mxfp8': Bits('0b01111011').e5m2mxfp8, # 57344.0
|
|
107
|
+
'p4binary8': Bits('0b01111110').p4binary8, # 224.0
|
|
108
|
+
'p3binary8': Bits('0b01111110').p3binary8, # 49152.0
|
|
109
|
+
'float16': Bits('0x7bff').float16, # 65504.0
|
|
110
|
+
# The bfloat range is so large the scaling algorithm doesn't work well, so I'm disallowing it.
|
|
111
|
+
# 'bfloat16': Bits('0x7f7f').bfloat16, # 3.38953139e38,
|
|
112
|
+
}
|
|
113
|
+
if f'{name}{length}' in Array._largest_values.keys():
|
|
114
|
+
float_values = Array('float64', initializer).tolist()
|
|
115
|
+
max_float_value = max(abs(x) for x in float_values)
|
|
116
|
+
if max_float_value == 0:
|
|
117
|
+
# This special case isn't covered in the standard. I'm choosing to return no scale.
|
|
118
|
+
return 1.0
|
|
119
|
+
log2 = int(math.log2(max_float_value))
|
|
120
|
+
lp2 = int(math.log2(Array._largest_values[f'{name}{length}']))
|
|
121
|
+
lg_scale = log2 - lp2
|
|
122
|
+
# Saturate at values representable in E8M0 format.
|
|
123
|
+
if lg_scale > 127:
|
|
124
|
+
lg_scale = 127
|
|
125
|
+
elif lg_scale < -127:
|
|
126
|
+
lg_scale = -127
|
|
127
|
+
return 2 ** lg_scale
|
|
128
|
+
else:
|
|
129
|
+
raise ValueError(f"Can't calculate auto scale for format '{name}{length}'. "
|
|
130
|
+
f"This feature is only available for these formats: {list(Array._largest_values.keys())}.")
|
|
131
|
+
|
|
90
132
|
@property
|
|
91
133
|
def itemsize(self) -> int:
|
|
92
134
|
return self._dtype.length
|
|
@@ -96,19 +138,6 @@ class Array:
|
|
|
96
138
|
trailing_bit_length = len(self.data) % self._dtype.bitlength
|
|
97
139
|
return BitArray() if trailing_bit_length == 0 else self.data[-trailing_bit_length:]
|
|
98
140
|
|
|
99
|
-
# Converting array.array typecodes to our equivalents.
|
|
100
|
-
_array_typecodes: dict[str, str] = {'b': 'int8',
|
|
101
|
-
'B': 'uint8',
|
|
102
|
-
'h': 'intne16',
|
|
103
|
-
'H': 'uintne16',
|
|
104
|
-
'l': 'intne32',
|
|
105
|
-
'L': 'uintne32',
|
|
106
|
-
'q': 'intne64',
|
|
107
|
-
'Q': 'uintne64',
|
|
108
|
-
'e': 'floatne16',
|
|
109
|
-
'f': 'floatne32',
|
|
110
|
-
'd': 'floatne64'}
|
|
111
|
-
|
|
112
141
|
@property
|
|
113
142
|
def dtype(self) -> Dtype:
|
|
114
143
|
return self._dtype
|
|
@@ -120,7 +149,6 @@ class Array:
|
|
|
120
149
|
def _set_dtype(self, new_dtype: Union[str, Dtype]) -> None:
|
|
121
150
|
if isinstance(new_dtype, Dtype):
|
|
122
151
|
self._dtype = new_dtype
|
|
123
|
-
self._fmt = str(self._dtype)
|
|
124
152
|
else:
|
|
125
153
|
try:
|
|
126
154
|
dtype = Dtype(new_dtype)
|
|
@@ -133,14 +161,14 @@ class Array:
|
|
|
133
161
|
if dtype.length is None:
|
|
134
162
|
raise ValueError(f"A fixed length format is needed for an Array, received '{new_dtype}'.")
|
|
135
163
|
self._dtype = dtype
|
|
136
|
-
|
|
164
|
+
if self._dtype.scale == 'auto':
|
|
165
|
+
raise ValueError("A Dtype with an 'auto' scale factor can only be used when creating a new Array.")
|
|
137
166
|
|
|
138
167
|
def _create_element(self, value: ElementType) -> Bits:
|
|
139
168
|
"""Create Bits from value according to the token_name and token_length"""
|
|
140
|
-
b =
|
|
141
|
-
self._dtype.set_fn(b, value)
|
|
169
|
+
b = self._dtype.build(value)
|
|
142
170
|
if len(b) != self._dtype.length:
|
|
143
|
-
raise ValueError(f"The value {value!r} has the wrong length for the format '{self.
|
|
171
|
+
raise ValueError(f"The value {value!r} has the wrong length for the format '{self._dtype}'.")
|
|
144
172
|
return b
|
|
145
173
|
|
|
146
174
|
def __len__(self) -> int:
|
|
@@ -161,11 +189,11 @@ class Array:
|
|
|
161
189
|
d = BitArray()
|
|
162
190
|
for s in range(start * self._dtype.length, stop * self._dtype.length, step * self._dtype.length):
|
|
163
191
|
d.append(self.data[s: s + self._dtype.length])
|
|
164
|
-
a =
|
|
192
|
+
a = self.__class__(self._dtype)
|
|
165
193
|
a.data = d
|
|
166
194
|
return a
|
|
167
195
|
else:
|
|
168
|
-
a =
|
|
196
|
+
a = self.__class__(self._dtype)
|
|
169
197
|
a.data = self.data[start * self._dtype.length: stop * self._dtype.length]
|
|
170
198
|
return a
|
|
171
199
|
else:
|
|
@@ -234,15 +262,15 @@ class Array:
|
|
|
234
262
|
trailing_bit_length = len(self.data) % self._dtype.length
|
|
235
263
|
final_str = "" if trailing_bit_length == 0 else ", trailing_bits=" + repr(
|
|
236
264
|
self.data[-trailing_bit_length:])
|
|
237
|
-
return f"Array('{self.
|
|
265
|
+
return f"Array('{self._dtype}', {list_str}{final_str})"
|
|
238
266
|
|
|
239
267
|
def astype(self, dtype: Union[str, Dtype]) -> Array:
|
|
240
268
|
"""Return Array with elements of new dtype, initialised from current Array."""
|
|
241
|
-
new_array =
|
|
269
|
+
new_array = self.__class__(dtype, self.tolist())
|
|
242
270
|
return new_array
|
|
243
271
|
|
|
244
272
|
def tolist(self) -> List[ElementType]:
|
|
245
|
-
return
|
|
273
|
+
return [self._dtype.read_fn(self.data, start=start)
|
|
246
274
|
for start in range(0, len(self.data) - self._dtype.length + 1, self._dtype.length)]
|
|
247
275
|
|
|
248
276
|
def append(self, x: ElementType) -> None:
|
|
@@ -250,13 +278,13 @@ class Array:
|
|
|
250
278
|
raise ValueError("Cannot append to Array as its length is not a multiple of the format length.")
|
|
251
279
|
self.data += self._create_element(x)
|
|
252
280
|
|
|
253
|
-
def extend(self, iterable: Union[Array, array.array, Iterable]) -> None:
|
|
281
|
+
def extend(self, iterable: Union[Array, array.array, Iterable[Any]]) -> None:
|
|
254
282
|
if len(self.data) % self._dtype.length != 0:
|
|
255
283
|
raise ValueError(f"Cannot extend Array as its data length ({len(self.data)} bits) is not a multiple of the format length ({self._dtype.length} bits).")
|
|
256
284
|
if isinstance(iterable, Array):
|
|
257
285
|
if self._dtype.name != iterable._dtype.name or self._dtype.length != iterable._dtype.length:
|
|
258
286
|
raise TypeError(
|
|
259
|
-
f"Cannot extend an Array with format '{self.
|
|
287
|
+
f"Cannot extend an Array with format '{self._dtype}' from an Array of format '{iterable._dtype}'.")
|
|
260
288
|
# No need to iterate over the elements, we can just append the data
|
|
261
289
|
self.data.append(iterable.data)
|
|
262
290
|
elif isinstance(iterable, array.array):
|
|
@@ -264,10 +292,10 @@ class Array:
|
|
|
264
292
|
name_value = utils.parse_single_struct_token('=' + iterable.typecode)
|
|
265
293
|
if name_value is None:
|
|
266
294
|
raise ValueError(f"Cannot extend from array with typecode {iterable.typecode}.")
|
|
267
|
-
other_dtype = dtype_register.get_dtype(*name_value)
|
|
295
|
+
other_dtype = dtype_register.get_dtype(*name_value, scale=None)
|
|
268
296
|
if self._dtype.name != other_dtype.name or self._dtype.length != other_dtype.length:
|
|
269
297
|
raise ValueError(
|
|
270
|
-
f"Cannot extend an Array with format '{self.
|
|
298
|
+
f"Cannot extend an Array with format '{self._dtype}' from an array with typecode '{iterable.typecode}'.")
|
|
271
299
|
self.data += iterable.tobytes()
|
|
272
300
|
else:
|
|
273
301
|
if isinstance(iterable, str):
|
|
@@ -302,7 +330,7 @@ class Array:
|
|
|
302
330
|
"""
|
|
303
331
|
if self._dtype.length % 8 != 0:
|
|
304
332
|
raise ValueError(
|
|
305
|
-
f"byteswap can only be used for whole-byte elements. The '{self.
|
|
333
|
+
f"byteswap can only be used for whole-byte elements. The '{self._dtype}' format is {self._dtype.length} bits long.")
|
|
306
334
|
self.data.byteswap(self.itemsize // 8)
|
|
307
335
|
|
|
308
336
|
def count(self, value: ElementType) -> int:
|
|
@@ -368,7 +396,7 @@ class Array:
|
|
|
368
396
|
stream -- A TextIO object with a write() method. Defaults to sys.stdout.
|
|
369
397
|
|
|
370
398
|
"""
|
|
371
|
-
colour = Colour(options.
|
|
399
|
+
colour = Colour(not options.no_color)
|
|
372
400
|
sep = ' '
|
|
373
401
|
dtype2 = None
|
|
374
402
|
tidy_fmt = None
|
|
@@ -381,7 +409,6 @@ class Array:
|
|
|
381
409
|
if len(token_list) not in [1, 2]:
|
|
382
410
|
raise ValueError(f"Only one or two tokens can be used in an Array.pp() format - '{fmt}' has {len(token_list)} tokens.")
|
|
383
411
|
dtype1 = Dtype(*utils.parse_name_length_token(token_list[0]))
|
|
384
|
-
parameter_str = f"fmt='{fmt}'"
|
|
385
412
|
if len(token_list) == 2:
|
|
386
413
|
dtype2 = Dtype(*utils.parse_name_length_token(token_list[1]))
|
|
387
414
|
|
|
@@ -405,7 +432,7 @@ class Array:
|
|
|
405
432
|
data = self.data if trailing_bit_length == 0 else self.data[0: -trailing_bit_length]
|
|
406
433
|
length = len(self.data) // token_length
|
|
407
434
|
len_str = colour.green + str(length) + colour.off
|
|
408
|
-
stream.write(f"<
|
|
435
|
+
stream.write(f"<{self.__class__.__name__} {tidy_fmt}, length={len_str}, itemsize={token_length} bits, total data size={(len(self.data) + 7) // 8} bytes> [\n")
|
|
409
436
|
data._pp(dtype1, dtype2, token_length, width, sep, format_sep, show_offset, stream, False, token_length)
|
|
410
437
|
stream.write("]")
|
|
411
438
|
if trailing_bit_length != 0:
|
|
@@ -443,13 +470,13 @@ class Array:
|
|
|
443
470
|
start += self._dtype.length
|
|
444
471
|
|
|
445
472
|
def __copy__(self) -> Array:
|
|
446
|
-
a_copy =
|
|
473
|
+
a_copy = self.__class__(self._dtype)
|
|
447
474
|
a_copy.data = copy.copy(self.data)
|
|
448
475
|
return a_copy
|
|
449
476
|
|
|
450
477
|
def _apply_op_to_all_elements(self, op, value: Union[int, float, None], is_comparison: bool = False) -> Array:
|
|
451
478
|
"""Apply op with value to each element of the Array and return a new Array"""
|
|
452
|
-
new_array =
|
|
479
|
+
new_array = self.__class__('bool' if is_comparison else self._dtype)
|
|
453
480
|
new_data = BitArray()
|
|
454
481
|
failures = index = 0
|
|
455
482
|
msg = ''
|
|
@@ -505,7 +532,7 @@ class Array:
|
|
|
505
532
|
"""Apply op with value to each element of the Array as an unsigned integer in place."""
|
|
506
533
|
value = BitArray._create_from_bitstype(value)
|
|
507
534
|
if len(value) != self._dtype.length:
|
|
508
|
-
raise ValueError(f"Bitwise op needs a bitstring of length {self._dtype.length} to match format {self.
|
|
535
|
+
raise ValueError(f"Bitwise op needs a bitstring of length {self._dtype.length} to match format {self._dtype}.")
|
|
509
536
|
for start in range(0, len(self) * self._dtype.length, self._dtype.length):
|
|
510
537
|
self.data[start: start + self._dtype.length] = op(self.data[start: start + self._dtype.length], value)
|
|
511
538
|
return self
|
|
@@ -520,7 +547,7 @@ class Array:
|
|
|
520
547
|
new_type = dtype_register.get_dtype('bool', 1)
|
|
521
548
|
else:
|
|
522
549
|
new_type = self._promotetype(self._dtype, other._dtype)
|
|
523
|
-
new_array =
|
|
550
|
+
new_array = self.__class__(new_type)
|
|
524
551
|
new_data = BitArray()
|
|
525
552
|
failures = index = 0
|
|
526
553
|
msg = ''
|
|
@@ -553,7 +580,7 @@ class Array:
|
|
|
553
580
|
|
|
554
581
|
"""
|
|
555
582
|
def is_float(x): return x.return_type is float
|
|
556
|
-
def is_int(x): return x.return_type is int
|
|
583
|
+
def is_int(x): return x.return_type is int or x.return_type is bool
|
|
557
584
|
if is_float(type1) + is_int(type1) + is_float(type2) + is_int(type2) != 2:
|
|
558
585
|
raise ValueError(f"Only integer and floating point types can be combined - not '{type1}' and '{type2}'.")
|
|
559
586
|
# If same type choose the widest
|
|
@@ -722,15 +749,21 @@ class Array:
|
|
|
722
749
|
return self._apply_op_between_arrays(operator.le, other, is_comparison=True)
|
|
723
750
|
return self._apply_op_to_all_elements(operator.le, other, is_comparison=True)
|
|
724
751
|
|
|
725
|
-
def
|
|
726
|
-
if isinstance(other,
|
|
727
|
-
return self.
|
|
728
|
-
|
|
752
|
+
def _eq_ne(self, op, other: Any) -> Array:
|
|
753
|
+
if isinstance(other, (int, float, str, Bits)):
|
|
754
|
+
return self._apply_op_to_all_elements(op, other, is_comparison=True)
|
|
755
|
+
try:
|
|
756
|
+
other = self.__class__(self.dtype, other)
|
|
757
|
+
except:
|
|
758
|
+
return NotImplemented
|
|
759
|
+
finally:
|
|
760
|
+
return self._apply_op_between_arrays(op, other, is_comparison=True)
|
|
729
761
|
|
|
730
|
-
def
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
762
|
+
def __eq__(self, other: Any) -> Array:
|
|
763
|
+
return self._eq_ne(operator.eq, other)
|
|
764
|
+
|
|
765
|
+
def __ne__(self, other: Any) -> Array:
|
|
766
|
+
return self._eq_ne(operator.ne, other)
|
|
734
767
|
|
|
735
768
|
# Unary operators
|
|
736
769
|
|