Skip to content

Commit 6b0a9e6

Browse files
committed
Removed dependency to bitstring
1 parent 2c71af4 commit 6b0a9e6

File tree

7 files changed

+37
-135
lines changed

7 files changed

+37
-135
lines changed

docs/pages/helpers.md

-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ It also provides some other utility functions, decorators, context managers and
8686
**Name** | **Description**
8787
--- | ---
8888
`range2` | alternative to `range` that supports floats
89-
`ts.BitArray` | slightly extended `BitArray` class from [`bitstring`](https://github.com/scott-griffiths/bitstring)
9089
`ts.capture` | decorator for capturing `stdout` and `stderr` of a function
9190
`ts.Capture` | context manager for capturing `stdout` and `stderr` of a code block
9291
`ts.dateparse` | date parsing function relying on `dateparser.parse`

pyproject.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ classifiers = [
3434
dependencies = [
3535
"argcomplete>=3.0.8",
3636
"asciistuff>=1.3.1",
37-
"bitstring==4.0.2",
3837
"codext>=1.15.4",
3938
"coloredlogs",
4039
"colorful",
@@ -68,7 +67,7 @@ dependencies = [
6867
"toml",
6968
"tqdm",
7069
"virtualenv>=20.26.3",
71-
"weasyprint>=60.2",
70+
"weasyprint>=64.1",
7271
"xmltodict",
7372
]
7473
dynamic = ["version"]

src/tinyscript/argreparse.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -753,13 +753,14 @@ def parse_known_args(self, args=None, namespace=None):
753753
if not hasattr(namespace, dest):
754754
setattr(namespace, dest, self._defaults[dest])
755755
# parse the arguments and exit if there are any errors
756+
a = (args, namespace) if sys.version_info.minor < 12 else (args, namespace, False)
756757
if self.exit_on_error:
757758
try:
758-
namespace, args = self._parse_known_args(args, namespace)
759+
namespace, args = self._parse_known_args(*a)
759760
except ArgumentError as err:
760761
self.error(str(err))
761762
else:
762-
namespace, args = self._parse_known_args(args, namespace)
763+
namespace, args = self._parse_known_args(*a)
763764
if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
764765
args.extend(set(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR)))
765766
try:

src/tinyscript/helpers/data/transform/common.py

+30-50
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
44
"""
55
from ..types import is_bin, is_bytes, is_hex, is_int, is_list, is_pos_int, is_str
6-
from ..utils import BitArray as Bits
76
from ...compat import b, ensure_str
87

98
for _m in ["binascii", "functools", "math"]:
@@ -91,10 +90,12 @@ def bin2hex(binary_string, nbits_in=8, nbits_out=8) -> str:
9190
def bin2int(binary_string, nbits_in=8, nbits_out=8, order="big", unsigned=True) -> int:
9291
""" Convert a binary string (eventually using a separator) to an integer, using a given number of bits and in little
9392
or big endian. """
94-
bs = binary_string
93+
bs, n_b, n_B = binary_string, nbits_in, nbits_out
9594
__validation(b=bs, o=order, u=unsigned)
96-
bs, pref = Bits(bin2bin(bs, nbits_in, nbits_out)), ["", "u"][unsigned]
97-
return getattr(bs, pref + ("intle" if order == "little" else "intbe"))
95+
bs = bin2bin(bs, n_b, n_B)
96+
if order == "little":
97+
bs = ''.join(reversed([bs[i:i+n_B] for i in range(0, len(bs), n_B)]))
98+
return int(bs, 2) - (1 << len(bs)) if not unsigned and bs[0] == "1" else int(bs, 2)
9899

99100

100101
@__ensure_bitstring
@@ -117,61 +118,44 @@ def hex2bin(hex_string, nbits_in=8, nbits_out=8) -> str:
117118
return bin2bin(padz(bs, n_b), n_b, n_B)
118119

119120

120-
def hex2int(hex_string, order="big", unsigned=True) -> int:
121+
def hex2int(hex_string, nbits_in=8, nbits_out=8, order="big", unsigned=True) -> int:
121122
""" Convert a hexadecimal string to a big integer. """
122-
h = hex_string
123-
__validation(h=h, o=order, u=unsigned)
124-
bs = Bits()
125-
bs.hex = h
126-
pref = ["", "u"][unsigned]
127-
return getattr(bs, pref + ("intle" if order == "little" else "intbe"))
123+
n_B = nbits_out
124+
return bin2int(hex2bin(hex_string, nbits_in, n_B), n_B, n_B, order, unsigned)
128125

129126

130127
def hex2str(hex_string) -> str:
131128
""" Convert a hexadecimal string to a string of 8-bits characters. """
132129
h = hex_string
133130
__validation(h=h)
134-
return ensure_str(binascii.unhexlify(b(hex_string)))
131+
return ensure_str(binascii.unhexlify(b(h)))
135132

136133

137134
# INTEGER ==> *
138135
def int2bin(integer, nbits_in=8, nbits_out=8, order="big", unsigned=True) -> str:
139136
""" Convert an integer to a binary string in little or big endian. """
140-
i = integer
141-
__validation(i=i, n_b=nbits_in, n_B=nbits_out, o=order, u=unsigned)
142-
bs = Bits()
143-
nbits = i.bit_length() + int(not unsigned)
144-
bs.hex = int(math.ceil(max(nbits, 1) / 8.0)) * 2 * "0"
145-
pref = ["", "u"][unsigned]
146-
setattr(bs, pref + ("intle" if order == "little" else "intbe"), i)
147-
bs._nbits = nbits_in
148-
bs.nbits = nbits_out
149-
return bs.bin
150-
151-
152-
def int2hex(integer, order="big", unsigned=True) -> str:
137+
i, n_b, n_B = integer, nbits_in, nbits_out
138+
__validation(i=i, n_b=n_b, n_B=nbits_out, o=order, u=unsigned)
139+
if not unsigned and i < 0:
140+
i = (1 << n_b) + i
141+
bs = format(i, f'0{n_b}b')
142+
bs = "".join(bs[i:i+n_b] for i in range(0, len(bs), n_b))
143+
bs = bs.zfill(len(bs) + (n_b - (len(bs) % n_b)) % n_b)
144+
if order == "little":
145+
bs = "".join(reversed([bs[i:i+n_b] for i in range(0, len(bs), n_b)]))
146+
return bin2bin(bs, n_b, n_B)
147+
148+
149+
def int2hex(integer, nbits_in=8, nbits_out=8, order="big", unsigned=True) -> str:
153150
""" Convert an integer to a hexadecimal string. """
154-
i = integer
155-
__validation(i=i, o=order, u=unsigned)
156-
bs = Bits()
157-
nbits = i.bit_length() + int(not unsigned)
158-
bs.hex = int(math.ceil(max(nbits, 1) / 8.0)) * 2 * "0"
159-
pref = ["", "u"][unsigned]
160-
setattr(bs, pref + ("intle" if order == "little" else "intbe"), i)
161-
return bs.hex
162-
#"".join([h[i:i+2] for i in range(0, len(h), 2)][::-1])
151+
n_B = nbits_out
152+
return bin2hex(int2bin(integer, nbits_in, n_B, order, unsigned), n_B, n_B)
163153

164154

165-
def int2str(integer, order="big", unsigned=True) -> str:
155+
def int2str(integer, nbits_in=8, nbits_out=8, order="big", unsigned=True) -> str:
166156
""" Convert a big integer to a string of 8-bits characters. """
167-
i = integer
168-
__validation(i=i, o=order, u=unsigned)
169-
bs = Bits()
170-
nbits = i.bit_length() + int(not unsigned)
171-
bs.hex = int(math.ceil(max(nbits, 1) / 8.0)) * 2 * "0"
172-
pref = ["", "u"][unsigned]
173-
setattr(bs, pref + ("intle" if order == "little" else "intbe"), i)
174-
return ensure_str(bs.bytes)
157+
n_B = nbits_out
158+
return bin2str(int2bin(integer, nbits_in, n_B, order, unsigned), n_B, n_B)
175159

176160

177161
def int2uni(integer) -> str:
@@ -202,15 +186,11 @@ def str2hex(chars_string) -> str:
202186
return ensure_str(binascii.hexlify(b(s)))
203187

204188

205-
def str2int(chars_string, order="big", unsigned=True) -> int:
189+
def str2int(chars_string, nbits_in=8, nbits_out=8, order="big", unsigned=True) -> int:
206190
""" Convert a string of 8-bits characters to a big integer or, if using blocks of nchars characters, a list of big
207191
integers. """
208-
s = chars_string
209-
__validation(s=s, o=order, u=unsigned)
210-
bs = Bits()
211-
bs.bytes = b(s)
212-
pref = ["", "u"][unsigned]
213-
return getattr(bs, pref + ("intle" if order == "little" else "intbe"))
192+
n_B = nbits_out
193+
return bin2int(str2bin(chars_string, nbits_in, n_B), n_B, n_B, order, unsigned)
214194

215195

216196
def str2lst(chars_string) -> list:

src/tinyscript/helpers/data/utils.py

+1-74
Original file line numberDiff line numberDiff line change
@@ -13,85 +13,12 @@
1313
lazy_load_module("string", alias="strmod")
1414

1515

16-
__all__ = __features__ = ["BitArray", "entropy", "entropy_bits", "pad", "unpad"]
16+
__all__ = __features__ = ["entropy", "entropy_bits", "pad", "unpad"]
1717

1818

1919
PAD = ["ansic9.23", "incremental", "iso7816-4", "pkcs5", "pkcs7", "w3c"]
2020

2121

22-
def __init_bitstring(bs):
23-
OLD_CODE, NEW_CODE = """
24-
def _getlength(self)%s:
25-
\"\"\"Return the length of the bitstring in bits.\"\"\"
26-
return self._datastore.bitlength
27-
""", """
28-
def _getlength(self)%s:
29-
\"\"\"Return the length of the bitstring in bits.\"\"\"
30-
l = self._datastore.bitlength
31-
return l + (8 - l %% 8) %% 8 if getattr(Bits, "_padding", True) else l
32-
"""
33-
try:
34-
patchy.replace(bs.Bits._getlength, OLD_CODE % " -> int", NEW_CODE % " -> int")
35-
except (SyntaxError, ValueError):
36-
patchy.replace(bs.Bits._getlength, OLD_CODE % "", NEW_CODE % "")
37-
OLD_CODE, NEW_CODE = """
38-
def _getbin(self)%s:
39-
\"\"\"Return interpretation as a binary string.\"\"\"
40-
return self._readbin(%s)
41-
""", """
42-
def _getbin(self)%s:
43-
\"\"\"Return interpretation as a binary string.\"\"\"
44-
Bits._padding = False
45-
r = self._readbin(%s)
46-
Bits._padding = True
47-
return r
48-
"""
49-
try:
50-
patchy.replace(bs.Bits._getbin, OLD_CODE % (" -> str", "0, self.len"), NEW_CODE % (" -> str", "0, self.len"))
51-
except (SyntaxError, ValueError):
52-
patchy.replace(bs.Bits._getbin, OLD_CODE % ("", "self.len, 0"), NEW_CODE % ("", "self.len, 0"))
53-
lazy_load_module("bitstring", postload=__init_bitstring)
54-
55-
56-
def __init_bitarray():
57-
class BitArray(bitstring.BitArray):
58-
__doc__ = """ Small improvement to the original bitstring.BitArray class.
59-
60-
It allows to set the number of bits per group (by default, 8, for considering bytes).
61-
62-
""" + bitstring.BitArray.__doc__
63-
64-
def __new__(cls, auto=None, length=None, offset=None, nbits=8, **kwargs):
65-
if auto:
66-
if not auto.startswith("0b"):
67-
auto = "0b" + auto
68-
c = super(BitArray, cls).__new__(cls, auto, length, offset, **kwargs)
69-
c._nbits = nbits
70-
c.original = True
71-
return c
72-
73-
@property
74-
def nbits(self):
75-
return self._nbits
76-
77-
@nbits.setter
78-
def nbits(self, n):
79-
ob = self.bin
80-
nb = ""
81-
for i in range(0, len(ob), self._nbits):
82-
group = ob[i:i+self._nbits]
83-
if i > 0 and len(group) < self._nbits:
84-
break
85-
group = pad(group, ">0", n)[-n:]
86-
if int(ob[i:i+self._nbits], 2) != int(group, 2):
87-
self.original = False
88-
nb += group
89-
self.bin = nb
90-
self._nbits = n
91-
return BitArray
92-
BitArray = lazy_object(__init_bitarray)
93-
94-
9522
def entropy(string):
9623
""" Shannon entropy computation function. """
9724
s = string

src/tinyscript/helpers/text.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def _beautify(txt, raw=False):
177177
pass
178178
md += line + "\n"
179179
# 3. links incorrectly rendered after using pandoc
180-
for link in re.findall("(<(.*?)>)", md):
180+
for link in re.findall(r"(<(.*?)>)", md):
181181
md = md.replace(link[0], "[{0}]({1}{0})".format(link[1], ["", "mailto:"][is_email(link[1])]))
182182
# import only when required to render Markdown in the terminal
183183
from rich.markdown import Markdown
@@ -201,7 +201,7 @@ def _txt_list(text, format=None, ordered=False):
201201
r = "<{}l>".format(["u", "o"][ordered])
202202
elif format in ["md", "rst", "textile"]:
203203
r = ""
204-
for line in re.split("\n[\-\*] ", text):
204+
for line in re.split(r"\n[\-\*] ", text):
205205
line = line.lstrip("*- ")
206206
if format == "html":
207207
r += "\n<li>{}</li>".format(line)

tests/test_helpers_data_utils.py

-4
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ def test_common_utility_functions(self):
1313
BIN = "01010"
1414
STR = "test"
1515
HEX = "deadbeefc0f3b1ac00"
16-
bs = BitArray("01010101")
17-
self.assertEqual(bs.nbits, 8)
18-
self.assertEqual(bs.bin, "01010101")
19-
self.assertEqual(bs.hex, "55")
2016
self.assertEqual(pad(STR, "\x00"), STR + 4 * "\x00")
2117
self.assertEqual(pad(STR, ">\x00"), 4 * "\x00" + STR)
2218
self.assertEqual(unpad(pad(STR, "\x00"), "\x00"), STR)

0 commit comments

Comments
 (0)