Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-bitstring for openSUSE:Factory checked in at 2022-01-15 20:05:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-bitstring (Old) and /work/SRC/openSUSE:Factory/.python-bitstring.new.1892 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-bitstring" Sat Jan 15 20:05:14 2022 rev:5 rq:946638 version:3.1.9 Changes: -------- --- /work/SRC/openSUSE:Factory/python-bitstring/python-bitstring.changes 2020-09-17 15:09:07.840954417 +0200 +++ /work/SRC/openSUSE:Factory/.python-bitstring.new.1892/python-bitstring.changes 2022-01-15 20:05:26.409770251 +0100 @@ -1,0 +2,12 @@ +Sat Jan 15 15:22:21 UTC 2022 - Dirk M??ller <dmuel...@suse.com> + +- update to 3.1.9: + * Fixed a couple of outdated results in the readme (Issue 214). + * Some more documentation tidying. + * Turned off some debug code by default. + * Fixed a couple of failing tests in different Python versions. + * Fix for consistent pos initialisation semantics for different types. + * Change to allow wheels to be uploaded to PyPI. + * More work for LSB0 mode, but still not finished or documented (sorry). + +------------------------------------------------------------------- Old: ---- bitstring-3.1.7.tar.gz New: ---- bitstring-3.1.9.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-bitstring.spec ++++++ --- /var/tmp/diff_new_pack.PPEtZz/_old 2022-01-15 20:05:26.913770644 +0100 +++ /var/tmp/diff_new_pack.PPEtZz/_new 2022-01-15 20:05:26.921770650 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-bitstring # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-bitstring -Version: 3.1.7 +Version: 3.1.9 Release: 0 Summary: Python module for the construction, analysis and modification of binary data License: MIT ++++++ bitstring-3.1.7.tar.gz -> bitstring-3.1.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/LICENSE new/bitstring-bitstring-3.1.9/LICENSE --- old/bitstring-bitstring-3.1.7/LICENSE 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/LICENSE 2021-07-20 19:37:11.000000000 +0200 @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2006-2016 Scott Griffiths (dr.scottgriffi...@gmail.com) +Copyright (c) 2006 Scott Griffiths (dr.scottgriffi...@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/README.rst new/bitstring-bitstring-3.1.9/README.rst --- old/bitstring-bitstring-3.1.7/README.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/README.rst 2021-07-20 19:37:11.000000000 +0200 @@ -14,7 +14,7 @@ bitstring is open source software, and has been released under the MIT licence. -This module works in both Python 2.7 and Python 3. +This module works in both Python 2.7 and Python 3.6+. Installation ------------ @@ -23,12 +23,6 @@ pip install bitstring -Alternatively if you have downloaded and unzipped the package then you need to run the -``setup.py`` script with the 'install' argument:: - - python setup.py install - -You may need to run this with root privileges on Unix-like systems. Documentation ------------- @@ -56,8 +50,8 @@ ('1af', '000110101111', 431) >>> a[10:3:-1].bin '1110101' - >>> 3*a + '0b100' - BitArray('0o0657056705674') + >>> '0b100' + 3*a + BitArray('0x835e35e35, 0b111') Reading data sequentially:: @@ -76,7 +70,7 @@ >>> c.find('0x48') (8,) >>> c.replace('0b001', '0xabc') - >>> c.insert('0b0000') + >>> c.insert('0b0000', pos=3) >>> del c[12:16] Unit Tests @@ -90,7 +84,7 @@ ---- The bitstring module has been released as open source under the MIT License. -Copyright (c) 2008-2020 Scott Griffiths +Copyright (c) 2006 Scott Griffiths For more information see the project's homepage on GitHub: <https://github.com/scott-griffiths/bitstring> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/bitstring.py new/bitstring-bitstring-3.1.9/bitstring.py --- old/bitstring-bitstring-3.1.7/bitstring.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/bitstring.py 2021-07-20 19:37:11.000000000 +0200 @@ -1,5 +1,5 @@ #!/usr/bin/env python -""" +r""" This package defines classes that simplify bit-wise creation, manipulation and interpretation of data. @@ -38,7 +38,7 @@ __licence__ = """ The MIT License -Copyright (c) 2006-2020 Scott Griffiths (dr.scottgriffi...@gmail.com) +Copyright (c) 2006 Scott Griffiths (dr.scottgriffi...@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -59,7 +59,7 @@ THE SOFTWARE. """ -__version__ = "3.1.7" +__version__ = "3.1.9" __author__ = "Scott Griffiths" @@ -93,6 +93,9 @@ # Maximum size of caches used for speed optimisations. CACHE_SIZE = 1000 +# Set this to True for extra assertions for debugging. +_debug = False + class Error(Exception): """Base class for errors in the bitstring module.""" @@ -228,7 +231,7 @@ if bit_offset: # first do the byte with the join. joinval = (store.getbyte(-1) & (255 ^ (255 >> bit_offset)) | - (self._rawarray[self.byteoffset] & (255 >> bit_offset))) + (self._rawarray[self.byteoffset] & (255 >> bit_offset))) store._rawarray[-1] = joinval store._rawarray.extend(self._rawarray[self.byteoffset + 1: self.byteoffset + self.bytelength]) else: @@ -312,19 +315,17 @@ shiftleft = s.offset % 8 - newoffset # First deal with everything except for the final byte for x in range(s.byteoffset, s.byteoffset + s.bytelength - 1): - newdata.append(((d[x] << shiftleft) & 0xff) +\ - (d[x + 1] >> (8 - shiftleft))) + newdata.append(((d[x] << shiftleft) & 0xff) + (d[x + 1] >> (8 - shiftleft))) bits_in_last_byte = (s.offset + s.bitlength) % 8 if not bits_in_last_byte: bits_in_last_byte = 8 if bits_in_last_byte > shiftleft: newdata.append((d[s.byteoffset + s.bytelength - 1] << shiftleft) & 0xff) - else: # newoffset > s._offset % 8 + else: # newoffset > s._offset % 8 shiftright = newoffset - s.offset % 8 newdata.append(s.getbyte(0) >> shiftright) for x in range(s.byteoffset + 1, s.byteoffset + s.bytelength): - newdata.append(((d[x - 1] << (8 - shiftright)) & 0xff) +\ - (d[x] >> shiftright)) + newdata.append(((d[x - 1] << (8 - shiftright)) & 0xff) + (d[x] >> shiftright)) bits_in_last_byte = (s.offset + s.bitlength) % 8 if not bits_in_last_byte: bits_in_last_byte = 8 @@ -504,26 +505,28 @@ # Python 2.x octals start with '0', in Python 3 it's '0o' LEADING_OCT_CHARS = len(oct(1)) - 1 + def tidy_input_string(s): """Return string made lowercase and with all whitespace removed.""" s = ''.join(s.split()).lower() return s + INIT_NAMES = ('uint', 'int', 'ue', 'se', 'sie', 'uie', 'hex', 'oct', 'bin', 'bits', 'uintbe', 'intbe', 'uintle', 'intle', 'uintne', 'intne', 'float', 'floatbe', 'floatle', 'floatne', 'bytes', 'bool', 'pad') TOKEN_RE = re.compile(r'(?P<name>' + '|'.join(INIT_NAMES) + - r')((:(?P<len>[^=]+)))?(=(?P<value>.*))?$', re.IGNORECASE) + r')(:(?P<len>[^=]+))?(=(?P<value>.*))?$', re.IGNORECASE) DEFAULT_UINT = re.compile(r'(?P<len>[^=]+)?(=(?P<value>.*))?$', re.IGNORECASE) MULTIPLICATIVE_RE = re.compile(r'(?P<factor>.*)\*(?P<token>.+)') # Hex, oct or binary literals -LITERAL_RE = re.compile(r'(?P<name>0(x|o|b))(?P<value>.+)', re.IGNORECASE) +LITERAL_RE = re.compile(r'(?P<name>0([xob]))(?P<value>.+)', re.IGNORECASE) # An endianness indicator followed by one or more struct.pack codes -STRUCT_PACK_RE = re.compile(r'(?P<endian><|>|@)?(?P<fmt>(?:\d*[bBhHlLqQfd])+)$') +STRUCT_PACK_RE = re.compile(r'(?P<endian>[<>@])?(?P<fmt>(?:\d*[bBhHlLqQfd])+)$') # A number followed by a single character struct.pack code STRUCT_SPLIT_RE = re.compile(r'\d*[bBhHlLqQfd]') @@ -550,6 +553,7 @@ '0o': 'oct', '0O': 'oct', 'bin': 'bin', '0b': 'bin', '0B': 'bin', 'bits': 'auto', 'bytes': 'bytes', 'pad': 'pad'} + def structparser(token): """Parse struct-like format string token into sub-token list.""" m = STRUCT_PACK_RE.match(token) @@ -561,7 +565,7 @@ return [token] # Split the format string into a list of 'q', '4h' etc. formatlist = re.findall(STRUCT_SPLIT_RE, m.group('fmt')) - # Now deal with mulitiplicative factors, 4h -> hhhh etc. + # Now deal with multiplicative factors, 4h -> hhhh etc. fmt = ''.join([f[-1] * int(f[:-1]) if len(f) != 1 else f for f in formatlist]) if endian == '@': @@ -578,6 +582,7 @@ tokens = [REPLACEMENTS_BE[c] for c in fmt] return tokens + def tokenparser(fmt, keys=None, token_cache={}): """Divide the format string into tokens and parse them. @@ -679,9 +684,11 @@ token_cache[token_key] = stretchy_token, return_values return stretchy_token, return_values + # Looks for first number*( BRACKET_RE = re.compile(r'(?P<factor>\d+)\*\(') + def expand_brackets(s): """Remove whitespace and expand all brackets.""" s = ''.join(s.split()) @@ -689,7 +696,7 @@ start = s.find('(') if start == -1: break - count = 1 # Number of hanging open brackets + count = 1 # Number of hanging open brackets p = start + 1 while p < len(s): if s[p] == '(': @@ -828,6 +835,10 @@ _, tokens = tokenparser(auto) except ValueError as e: raise CreationError(*e.args) + if offset is not None: + raise CreationError("offset should not be specified when using string initialisation.") + if length is not None: + raise CreationError("length should not be specified when using string initialisation.") x._datastore = ConstByteStore(bytearray(0), 0, 0) for token in tokens: x._datastore._appendstore(Bits._init_with_token(*token)._datastore) @@ -914,11 +925,11 @@ bs = Bits(bs) if bs.len <= self.len: s = self._copy() - s._append(bs) + s._addright(bs) else: s = bs._copy() s = self.__class__(s) - s._prepend(self) + s._addleft(self) return s def __radd__(self, bs): @@ -1017,19 +1028,25 @@ """ length = self.len + try: + pos = self._pos + pos_string = "" if pos == 0 else ", pos={0}".format(pos) + except AttributeError: + pos_string = "" if isinstance(self._datastore._rawarray, MmapByteArray): offsetstring = '' if self._datastore.byteoffset or self._offset: offsetstring = ", offset=%d" % (self._datastore._rawarray.byteoffset * 8 + self._offset) lengthstring = ", length=%d" % length - return "{0}(filename='{1}'{2}{3})".format(self.__class__.__name__, - self._datastore._rawarray.source.name, lengthstring, offsetstring) + return "{0}(filename='{1}'{2}{3}{4})".format(self.__class__.__name__, + self._datastore._rawarray.source.name, + lengthstring, offsetstring, pos_string) else: s = self.__str__() lengthstring = '' if s.endswith('...'): lengthstring = " # length={0}".format(length) - return "{0}('{1}'){2}".format(self.__class__.__name__, s, lengthstring) + return "{0}('{1}'{2}){3}".format(self.__class__.__name__, s, pos_string, lengthstring) def __eq__(self, bs): """Return True if two bitstrings have the same binary representation. @@ -1077,7 +1094,7 @@ raise ValueError("Cannot shift an empty bitstring.") n = min(n, self.len) s = self._slice(n, self.len) - s._append(Bits(n)) + s._addright(Bits(n)) return s def __rshift__(self, n): @@ -1093,7 +1110,7 @@ if not n: return self._copy() s = self.__class__(length=min(n, self.len)) - s._append(self[:-n]) + s._addright(self[:-n]) return s def __mul__(self, n): @@ -1247,12 +1264,17 @@ # ...whereas this is used in Python 3.x __bool__ = __nonzero__ - def _assertsanity(self): - """Check internal self consistency as a debugging aid.""" - assert self.len >= 0 - assert 0 <= self._offset, "offset={0}".format(self._offset) - assert (self.len + self._offset + 7) // 8 == self._datastore.bytelength + self._datastore.byteoffset, "len={0}, offset={1}, bytelength={2}, byteoffset={3}".format(self.len, self._offset, self._datastore.bytelength, self._datastore.byteoffset) - return True + if _debug is True: + def _assertsanity(self): + """Check internal self consistency as a debugging aid.""" + assert self.len >= 0 + assert 0 <= self._offset, "offset={0}".format(self._offset) + assert (self.len + self._offset + 7) // 8 == self._datastore.bytelength + self._datastore.byteoffset, "len={0}, offset={1}, bytelength={2}, byteoffset={3}".format(self.len, self._offset, self._datastore.bytelength, self._datastore.byteoffset) + return True + else: + @staticmethod + def _assertsanity(): + return True @classmethod def _init_with_token(cls, name, token_length, value): @@ -1438,7 +1460,7 @@ "The allowed range is [0, {2}]." raise CreationError(msg, uint, length, (1 << length) - 1) if uint < 0: - raise CreationError("uint cannot be initialsed by a negative number.") + raise CreationError("uint cannot be initialised by a negative number.") s = hex(uint)[2:] s = s.rstrip('L') if len(s) & 1: @@ -1457,7 +1479,11 @@ offset = 0 self._setbytes_unsafe(bytearray(data), length, offset) - def _readuint(self, length, start): + def _readuint_lsb0(self, length, start): + # TODO: This needs a complete rewrite - can't delegate to _readuint_msb0 + return self._readuint_msb0(length, self.len - start - length) + + def _readuint_msb0(self, length, start): """Read bits and interpret as an unsigned int.""" if not length: raise InterpretError("Cannot interpret a zero length bitstring " @@ -1831,7 +1857,7 @@ self._setbin_unsafe('1') else: self._setuie(abs(i)) - self._append(Bits([i < 0])) + self._addright(Bits([i < 0])) def _getsie(self): """Return data as signed interleaved exponential-Golomb code. @@ -2027,10 +2053,10 @@ except ValueError as e: raise CreationError(*e.args) if tokens: - b._append(Bits._init_with_token(*tokens[0])) + b._addright(Bits._init_with_token(*tokens[0])) b._datastore = offsetcopy(b._datastore, offset) for token in tokens[1:]: - b._append(Bits._init_with_token(*token)) + b._addright(Bits._init_with_token(*token)) assert b._assertsanity() assert b.len == 0 or b._offset == offset if len(cache) < CACHE_SIZE: @@ -2080,11 +2106,11 @@ # This is for the 'ue', 'se' and 'bool' tokens. They will also return the new pos. return name_to_read[name](self, pos) - def _append(self, bs): - """Append a bitstring to the current bitstring.""" + def _addright(self, bs): + """Add a bitstring to the RHS of the current bitstring.""" self._datastore._appendstore(bs._datastore) - def _prepend(self, bs): + def _addleft(self, bs): """Prepend a bitstring to the current bitstring.""" self._datastore._prependstore(bs._datastore) @@ -2101,30 +2127,34 @@ self._setbytes_unsafe(bytearray().join(n), self.length, newoffset) def _truncateleft(self, bits): - """Truncate bits from the LHS of the bitstring.""" + """Truncate bits from the start of the bitstring.""" assert 0 <= bits <= self.len if not bits: - return + return Bits() + truncated_bits = self._slice_msb0(0, bits) if bits == self.len: self._clear() - return + return truncated_bits bytepos, offset = divmod(self._offset + bits, 8) self._setbytes_unsafe(self._datastore.getbyteslice(bytepos, self._datastore.bytelength), self.len - bits, offset) assert self._assertsanity() + return truncated_bits def _truncateright(self, bits): - """Truncate bits from the RHS of the bitstring.""" + """Truncate bits from the end of the bitstring.""" assert 0 <= bits <= self.len if not bits: - return + return Bits() + truncated_bits = self._slice_lsb0(0, bits) if bits == self.len: self._clear() - return + return truncated_bits newlength_in_bytes = (self._offset + self.len - bits + 7) // 8 self._setbytes_unsafe(self._datastore.getbyteslice(0, newlength_in_bytes), self.len - bits, self._offset) assert self._assertsanity() + return truncated_bits def _insert_lsb0(self, bs, pos): """Insert bs at pos (LSB0).""" @@ -2135,16 +2165,16 @@ assert 0 <= pos <= self.len if pos > self.len // 2: # Inserting nearer end, so cut off end. - end = self._slice(pos, self.len) - self._truncateright(self.len - pos) - self._append(bs) - self._append(end) + # end = self._slice(pos, self.len) + end = self._truncateright(self.len - pos) + self._addright(bs) + self._addright(end) else: # Inserting nearer start, so cut off start. start = self._slice(0, pos) self._truncateleft(pos) - self._prepend(bs) - self._prepend(start) + self._addleft(bs) + self._addleft(start) try: self._pos = pos + bs.len except AttributeError: @@ -2210,12 +2240,12 @@ end = self._slice_msb0(pos + bits, self.len) assert self.len - pos > 0 self._truncateright(self.len - pos) - self._append(end) + self._addright(end) return # More bits after the cut point than before it. start = self._slice_msb0(0, pos) self._truncateleft(pos + bits) - self._prepend(start) + self._addleft(start) return def _reversebytes(self, start, end): @@ -2254,14 +2284,14 @@ def _ilshift(self, n): """Shift bits by n to the left in place. Return self.""" assert 0 < n <= self.len - self._append(Bits(n)) + self._addright(Bits(n)) self._truncateleft(n) return self def _irshift(self, n): """Shift bits by n to the right in place. Return self.""" assert 0 < n <= self.len - self._prepend(Bits(n)) + self._addleft(Bits(n)) self._truncateright(n) return self @@ -2274,9 +2304,9 @@ m = 1 old_len = self.len while m * 2 < n: - self._append(self) + self._addright(self) m *= 2 - self._append(self[0:(n - m) * old_len]) + self._addright(self[0:(n - m) * old_len]) return self def _inplace_logical_helper(self, bs, f): @@ -2308,7 +2338,7 @@ """Read some bits from the bitstring and return newly constructed bitstring.""" return self._slice(start, start + length) - def _validate_slice(self, start, end): + def _validate_slice_msb0(self, start, end): """Validate start and end and return them as positive bit positions.""" if start is None: start = 0 @@ -2326,6 +2356,10 @@ raise ValueError("end must not be less than start.") return start, end + def _validate_slice_lsb0(self, start, end): + start, end = self._validate_slice_msb0(start, end) + return self.len - end, self.len - start + def unpack(self, fmt, **kwargs): """Interpret the whole bitstring using fmt and return list. @@ -2478,13 +2512,7 @@ # Not found, return empty tuple return () - def _find_lsb0(self, bs, start=None, end=None, bytealigned=None): - bs = Bits(bs) - p = self.rfind(bs, start, end, bytealigned) - if p: - return (self.len - p[0] - bs.length,) - - def _find_msb0(self, bs, start=None, end=None, bytealigned=None): + def find(self, bs, start=None, end=None, bytealigned=None): """Find first occurrence of substring bs. Returns a single item tuple with the bit position if found, or an @@ -2505,6 +2533,16 @@ (6,) """ + return self._find(bs, start, end, bytealigned) + + def _find_lsb0(self, bs, start=None, end=None, bytealigned=None): + bs = Bits(bs) + start, end = self._validate_slice_lsb0(start, end) + p = self.rfind(bs, start, end, bytealigned) + if p: + return (self.len - p[0] - bs.length,) + + def _find_msb0(self, bs, start=None, end=None, bytealigned=None): bs = Bits(bs) if not bs.len: raise ValueError("Cannot find an empty bitstring.") @@ -2706,11 +2744,11 @@ s = self.__class__() i = iter(sequence) try: - s._append(Bits(next(i))) + s._addright(Bits(next(i))) while True: n = next(i) - s._append(self) - s._append(Bits(n)) + s._addright(self) + s._addright(Bits(n)) except StopIteration: pass return s @@ -2736,7 +2774,7 @@ """ # If the bitstring is file based then we don't want to read it all # in to memory. - chunksize = 1024 * 1024 # 1 MB chunks + chunksize = 1024 * 1024 # 1 MiB chunks if not self._offset: a = 0 bytelen = self._datastore.bytelength @@ -2771,7 +2809,7 @@ """ prefix = Bits(prefix) - start, end = self._validate_slice(start, end) + start, end = self._validate_slice_msb0(start, end) # the _slice deals with msb0/lsb0 if end < start + prefix.len: return False end = start + prefix.len @@ -2954,59 +2992,7 @@ """) -# Dictionary that maps token names to the function that reads them. -name_to_read = {'uint': Bits._readuint, - 'uintle': Bits._readuintle, - 'uintbe': Bits._readuintbe, - 'uintne': Bits._readuintne, - 'int': Bits._readint, - 'intle': Bits._readintle, - 'intbe': Bits._readintbe, - 'intne': Bits._readintne, - 'float': Bits._readfloat, - 'floatbe': Bits._readfloat, # floatbe is a synonym for float - 'floatle': Bits._readfloatle, - 'floatne': Bits._readfloatne, - 'hex': Bits._readhex, - 'oct': Bits._readoct, - 'bin': Bits._readbin, - 'bits': Bits._readbits, - 'bytes': Bits._readbytes, - 'ue': Bits._readue, - 'se': Bits._readse, - 'uie': Bits._readuie, - 'sie': Bits._readsie, - 'bool': Bits._readbool, - } - -# Dictionaries for mapping init keywords with init functions. -init_with_length_and_offset = {'bytes': Bits._setbytes_safe, - 'filename': Bits._setfile, - } - -init_with_length_only = {'uint': Bits._setuint, - 'int': Bits._setint, - 'float': Bits._setfloat, - 'uintbe': Bits._setuintbe, - 'intbe': Bits._setintbe, - 'floatbe': Bits._setfloat, - 'uintle': Bits._setuintle, - 'intle': Bits._setintle, - 'floatle': Bits._setfloatle, - 'uintne': Bits._setuintne, - 'intne': Bits._setintne, - 'floatne': Bits._setfloatne, - } -init_without_length_or_offset = {'bin': Bits._setbin_safe, - 'hex': Bits._sethex, - 'oct': Bits._setoct, - 'ue': Bits._setue, - 'se': Bits._setse, - 'uie': Bits._setuie, - 'sie': Bits._setsie, - 'bool': Bits._setbool, - } class BitArray(Bits): @@ -3140,7 +3126,7 @@ bs -- the bitstring to append. """ - self.append(bs) + self._append(bs) return self def __copy__(self): @@ -3176,7 +3162,6 @@ raise ValueError("Cannot set a single bit with integer {0}.".format(value)) value = Bits(value) if value.len == 1: - # TODO: this can't be optimal if value[0]: self._set(key) else: @@ -3199,7 +3184,6 @@ # value rather than initialise a new bitstring of that length. if not isinstance(value, numbers.Integral): try: - # TODO: Better way than calling constructor here? value = Bits(value) except TypeError: raise TypeError("Bitstring, integer or string expected. " @@ -3277,7 +3261,6 @@ temp.__delitem__(key) self._setbin_unsafe(''.join(temp)) return - stop = key.stop if key.start is not None: start = key.start if key.start < 0: @@ -3394,7 +3377,7 @@ lengths = [s.len for s in sections] if len(lengths) == 1: # Didn't find anything to replace. - return 0 # no replacements done + return 0 # no replacements done if new is self: # Prevent self assignment woes new = copy.copy(self) @@ -3444,7 +3427,7 @@ try: pos = self._pos except AttributeError: - raise TypeError("insert require a bit position for this type.") + raise TypeError("insert needs a bit position specified when used on a BitArray.") if pos < 0: pos += self.len if not 0 <= pos <= self.len: @@ -3467,7 +3450,7 @@ try: pos = self._pos except AttributeError: - raise TypeError("overwrite require a bit position for this type.") + raise TypeError("overwrite needs a bit position specified when used on a BitArray.") if pos < 0: pos += self.len if pos < 0 or pos + bs.len > self.len: @@ -3484,8 +3467,6 @@ bs -- The bitstring to append. """ - # The offset is a hint to make bs easily appendable. - bs = self._converttobitstring(bs, offset=(self.len + self._offset) % 8) self._append(bs) def prepend(self, bs): @@ -3494,9 +3475,17 @@ bs -- The bitstring to prepend. """ - bs = Bits(bs) self._prepend(bs) + def _append_msb0(self, bs): + # The offset is a hint to make bs easily appendable. + bs = self._converttobitstring(bs, offset=(self.len + self._offset) % 8) + self._addright(bs) + + def _append_lsb0(self, bs): + bs = Bits(bs) + self._addleft(bs) + def reverse(self, start=None, end=None): """Reverse bits in-place. @@ -3583,8 +3572,11 @@ if not self.len: raise Error("Cannot rotate an empty bitstring.") if bits < 0: - raise ValueError("Cannot rotate right by negative amount.") - start, end = self._validate_slice(start, end) + raise ValueError("Cannot rotate by negative amount.") + self._ror(bits, start, end) + + def _ror_msb0(self, bits, start=None, end=None): + start, end = self._validate_slice_msb0(start, end) # the _slice deals with msb0/lsb0 bits %= (end - start) if not bits: return @@ -3605,8 +3597,11 @@ if not self.len: raise Error("Cannot rotate an empty bitstring.") if bits < 0: - raise ValueError("Cannot rotate left by negative amount.") - start, end = self._validate_slice(start, end) + raise ValueError("Cannot rotate by negative amount.") + self._rol(bits, start, end) + + def _rol_msb0(self, bits, start=None, end=None): + start, end = self._validate_slice_msb0(start, end) bits %= (end - start) if not bits: return @@ -3811,9 +3806,9 @@ """ - __slots__ = ('_pos') + __slots__ = ('_pos',) - def __init__(self, auto=None, length=None, offset=None, **kwargs): + def __init__(self, auto=None, length=None, offset=None, pos=0, **kwargs): """Either specify an 'auto' initialiser: auto -- a string of comma separated tokens, an integer, a file object, a bytearray, a boolean iterable or another bitstring. @@ -3848,13 +3843,17 @@ offset -- bit offset to the data. These offset bits are ignored and this is intended for use when initialising using 'bytes' or 'filename'. + pos -- Initial bit position, defaults to 0. """ - self._pos = 0 + pass - def __new__(cls, auto=None, length=None, offset=None, **kwargs): + def __new__(cls, auto=None, length=None, offset=None, pos=0, **kwargs): x = super(ConstBitStream, cls).__new__(cls) x._initialise(auto, length, offset, **kwargs) + x._pos = x._datastore.bitlength + pos if pos < 0 else pos + if x._pos < 0 or x._pos > x._datastore.bitlength: + raise CreationError("Cannot set pos to {0} when length is {1}".format(pos, x._datastore.bitlength)) return x def _setbytepos(self, bytepos): @@ -3868,7 +3867,7 @@ return self._pos // 8 def _setbitpos(self, pos): - """Move to absolute postion bit in bitstream.""" + """Move to absolute position bit in bitstream.""" if pos < 0: raise ValueError("Bit position cannot be negative.") if pos > self.len: @@ -4069,9 +4068,6 @@ """) - - - class BitStream(ConstBitStream, BitArray): """A container or stream holding a mutable sequence of bits @@ -4150,7 +4146,7 @@ # As BitStream objects are mutable, we shouldn't allow them to be hashed. __hash__ = None - def __init__(self, auto=None, length=None, offset=None, **kwargs): + def __init__(self, auto=None, length=None, offset=None, pos=0, **kwargs): """Either specify an 'auto' initialiser: auto -- a string of comma separated tokens, an integer, a file object, a bytearray, a boolean iterable or another bitstring. @@ -4185,19 +4181,20 @@ offset -- bit offset to the data. These offset bits are ignored and this is intended for use when initialising using 'bytes' or 'filename'. + pos -- Initial bit position, defaults to 0. """ - self._pos = 0 # For mutable BitStreams we always read in files to memory: if not isinstance(self._datastore, (ByteStore, ConstByteStore)): self._ensureinmemory() - def __new__(cls, auto=None, length=None, offset=None, **kwargs): + def __new__(cls, auto=None, length=None, offset=None, pos=0, **kwargs): x = super(BitStream, cls).__new__(cls) - y = ConstBitStream.__new__(BitStream, auto, length, offset, **kwargs) + y = ConstBitStream.__new__(BitStream, auto, length, offset, pos, **kwargs) x._datastore = ByteStore(y._datastore._rawarray[:], y._datastore.bitlength, y._datastore.offset) + x._pos = y._pos return x def __copy__(self): @@ -4221,7 +4218,7 @@ """ bs = self._converttobitstring(bs) - self._prepend(bs) + self._addleft(bs) self._pos += bs.len @@ -4281,14 +4278,14 @@ length = kwargs[length] # Also if we just have a dictionary name then we want to use it if name in kwargs and length is None and value is None: - s.append(kwargs[name]) + s._append(kwargs[name]) continue if length is not None: length = int(length) if value is None and name != 'pad': # Take the next value from the ones provided value = next(value_iter) - s._append(BitStream._init_with_token(name, length, value)) + s._addright(BitStream._init_with_token(name, length, value)) except StopIteration: raise CreationError("Not enough parameters present to pack according to the " "format. {0} values are needed.", len(tokens)) @@ -4299,44 +4296,123 @@ return s raise CreationError("Too many parameters present to pack according to the format.") + # Whether to label the Least Significant Bit as bit 0. Default is False. Experimental feature. _lsb0 = False -def _switch_lsb0_methods(): - if _lsb0: +# Dictionary that maps token names to the function that reads them. Is set in next function. +name_to_read = {} + + +def _switch_lsb0_methods(lsb0): + global _lsb0 + _lsb0 = lsb0 + if lsb0: ConstByteStore.getbit = ConstByteStore._getbit_lsb0 - Bits.find = Bits._find_lsb0 + Bits._find = Bits._find_lsb0 Bits._slice = Bits._slice_lsb0 BitArray._overwrite = BitArray._overwrite_lsb0 BitArray._insert = BitArray._insert_lsb0 BitArray._delete = BitArray._delete_lsb0 + BitArray._ror = BitArray._rol_msb0 + BitArray._rol = BitArray._ror_msb0 ByteStore.setbit = ByteStore._setbit_lsb0 ByteStore.unsetbit = ByteStore._unsetbit_lsb0 ByteStore.invertbit = ByteStore._invertbit_lsb0 + BitArray._append = BitArray._append_lsb0 + BitArray._prepend = BitArray._append_msb0 # An LSB0 prepend is an MSB0 append + Bits._readuint = Bits._readuint_lsb0 + Bits._truncatestart = Bits._truncateright + Bits._truncateend = Bits._truncateleft + Bits._validate_slice = Bits._validate_slice_lsb0 else: ConstByteStore.getbit = ConstByteStore._getbit_msb0 - Bits.find = Bits._find_msb0 + Bits._find = Bits._find_msb0 Bits._slice = Bits._slice_msb0 BitArray._overwrite = BitArray._overwrite_msb0 BitArray._insert = BitArray._insert_msb0 BitArray._delete = BitArray._delete_msb0 + BitArray._ror = BitArray._ror_msb0 + BitArray._rol = BitArray._rol_msb0 ByteStore.setbit = ByteStore._setbit_msb0 ByteStore.unsetbit = ByteStore._unsetbit_msb0 ByteStore.invertbit = ByteStore._invertbit_msb0 + BitArray._append = BitArray._append_msb0 + BitArray._prepend = BitArray._append_lsb0 + Bits._readuint = Bits._readuint_msb0 + Bits._truncatestart = Bits._truncateleft + Bits._truncateend = Bits._truncateright + Bits._validate_slice = Bits._validate_slice_msb0 + + global name_to_read + name_to_read = {'uint': Bits._readuint, + 'uintle': Bits._readuintle, + 'uintbe': Bits._readuintbe, + 'uintne': Bits._readuintne, + 'int': Bits._readint, + 'intle': Bits._readintle, + 'intbe': Bits._readintbe, + 'intne': Bits._readintne, + 'float': Bits._readfloat, + 'floatbe': Bits._readfloat, # floatbe is a synonym for float + 'floatle': Bits._readfloatle, + 'floatne': Bits._readfloatne, + 'hex': Bits._readhex, + 'oct': Bits._readoct, + 'bin': Bits._readbin, + 'bits': Bits._readbits, + 'bytes': Bits._readbytes, + 'ue': Bits._readue, + 'se': Bits._readse, + 'uie': Bits._readuie, + 'sie': Bits._readsie, + 'bool': Bits._readbool, + } + def set_lsb0(v=True): """Experimental method changing the bit numbering so that the least significant bit is bit 0""" - global _lsb0 - _lsb0 = bool(v) - _switch_lsb0_methods() + _switch_lsb0_methods(v) + def set_msb0(v=True): """Experimental method to reset the bit numbering so that the most significant bit is bit 0""" - global _lsb0 - _lsb0 = not bool(v) - _switch_lsb0_methods() + set_lsb0(not v) + + +# Initialise the default behaviour +set_msb0() + + +# Dictionaries for mapping init keywords with init functions. +init_with_length_and_offset = {'bytes': Bits._setbytes_safe, + 'filename': Bits._setfile, + } + +init_with_length_only = {'uint': Bits._setuint, + 'int': Bits._setint, + 'float': Bits._setfloat, + 'uintbe': Bits._setuintbe, + 'intbe': Bits._setintbe, + 'floatbe': Bits._setfloat, + 'uintle': Bits._setuintle, + 'intle': Bits._setintle, + 'floatle': Bits._setfloatle, + 'uintne': Bits._setuintne, + 'intne': Bits._setintne, + 'floatne': Bits._setfloatne, + } + +init_without_length_or_offset = {'bin': Bits._setbin_safe, + 'hex': Bits._sethex, + 'oct': Bits._setoct, + 'ue': Bits._setue, + 'se': Bits._setse, + 'uie': Bits._setuie, + 'sie': Bits._setsie, + 'bool': Bits._setbool, + } -_switch_lsb0_methods() # Aliases for backward compatibility ConstBitArray = Bits @@ -4346,32 +4422,33 @@ 'Bits', 'BitString', 'pack', 'Error', 'ReadError', 'InterpretError', 'ByteAlignError', 'CreationError', 'bytealigned', 'set_lsb0', 'set_msb0'] -if __name__ == '__main__': - """Create and interpret a bitstring from command-line parameters. - - Command-line parameters are concatenated and a bitstring created - from them. If the final parameter is either an interpretation string - or ends with a '.' followed by an interpretation string then that - interpretation of the bitstring will be used when printing it. - - Typical usage might be invoking the Python module from a console - as a one-off calculation: - - $ python -m bitstring int:16=-400 - 0xfe70 - $ python -m bitstring float:32=0.2 bin - 00111110010011001100110011001101 - $ python -m bitstring 0xff 3*0b01,0b11 uint - 65367 - $ python -m bitstring hex=01, uint:12=352.hex - 01160 - - This feature is experimental and is subject to change or removal. - """ +def main(): # check if final parameter is an interpretation string fp = sys.argv[-1] - if fp in name_to_read.keys(): + if fp == '--help' or len(sys.argv) == 1: + print("""Create and interpret a bitstring from command-line parameters. + +Command-line parameters are concatenated and a bitstring created +from them. If the final parameter is either an interpretation string +or ends with a '.' followed by an interpretation string then that +interpretation of the bitstring will be used when printing it. + +Typical usage might be invoking the Python module from a console +as a one-off calculation: + +$ python -m bitstring int:16=-400 +0xfe70 +$ python -m bitstring float:32=0.2 bin +00111110010011001100110011001101 +$ python -m bitstring 0xff 3*0b01,0b11 uint +65367 +$ python -m bitstring hex=01, uint:12=352.hex +01160 + +This feature is experimental and is subject to change or removal. + """) + elif fp in name_to_read.keys(): # concatenate all other parameters and interpret using the final one b1 = Bits(','.join(sys.argv[1: -1])) print(b1._readtoken(fp, 0, b1.__len__())[0]) @@ -4386,3 +4463,7 @@ # No interpretation - just use default print b1 = Bits(','.join(sys.argv[1:])) print(b1) + + +if __name__ == '__main__': + main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/bitstream.rst new/bitstring-bitstring-3.1.9/doc/bitstream.rst --- old/bitstring-bitstring-3.1.7/doc/bitstream.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/bitstream.rst 2021-07-20 19:37:11.000000000 +0200 @@ -3,9 +3,9 @@ The BitStream class ------------------- -.. class:: BitStream([auto, length, offset, **kwargs]) +.. class:: BitStream([auto, length, offset, pos, **kwargs]) - Both the :class:`BitArray` and the :class:`ConstBitStream` classes are base classes for :class:`BitStream` and so all of their methods are also available for :class:`BitStream` objects. The initialiser is also the same as for :class:`Bits` and so won't be repeated here. + Both the :class:`BitArray` and the :class:`ConstBitStream` classes are base classes for :class:`BitStream` and so all of their methods are also available for :class:`BitStream` objects. The initialiser is the same as for :class:`ConstBitStream`. A :class:`BitStream` is a mutable container of bits with methods and properties that allow it to be parsed as a stream of bits. There are no additional methods or properties in this class - see its base classes (:class:`Bits`, :class:`BitArray` and :class:`ConstBitStream`) for details. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/constbitstream.rst new/bitstring-bitstring-3.1.9/doc/constbitstream.rst --- old/bitstring-bitstring-3.1.7/doc/constbitstream.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/constbitstream.rst 2021-07-20 19:37:11.000000000 +0200 @@ -3,9 +3,9 @@ The ConstBitStream class ------------------------ -.. class:: ConstBitStream([auto, length, offset, **kwargs]) +.. class:: ConstBitStream([auto, length, offset, pos, **kwargs]) - The :class:`Bits` class is the base class for :class:`ConstBitStream` and so all of its methods are also available for :class:`ConstBitStream` objects. The initialiser is also the same as for :class:`Bits` and so won't be repeated here. + The :class:`Bits` class is the base class for :class:`ConstBitStream` and so all of its methods are also available for :class:`ConstBitStream` objects. The initialiser is the same as for :class:`Bits` except that an initial bit position :attr:`pos` can be given (defaults to 0). A :class:`ConstBitStream` is a :class:`Bits` with added methods and properties that allow it to be parsed as a stream of bits. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/creation.rst new/bitstring-bitstring-3.1.9/doc/creation.rst --- old/bitstring-bitstring-3.1.7/doc/creation.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/creation.rst 2021-07-20 19:37:11.000000000 +0200 @@ -5,7 +5,7 @@ Creation ======== -You can create bitstrings in a variety of ways. Internally they are stored as byte arrays, which means that no space is wasted, and a bitstring containing 10MB of binary data will only take up 10MB of memory. +You can create bitstrings in a variety of ways. Internally they are stored as byte arrays, which means that no space is wasted, and a bitstring containing 10MiB of binary data will only take up 10MiB of memory. The bitstring classes --------------------- @@ -27,7 +27,7 @@ * If you need to change the contents of the bitstring then you must use :class:`BitArray` or :class:`BitStream`. Truncating, replacing, inserting, appending etc. are not available for the const classes. * If you need to use a bitstring as the key in a dictionary or as a member of a ``set`` then you must use :class:`Bits` or a :class:`ConstBitStream`. As :class:`BitArray` and :class:`BitStream` objects are mutable they do not support hashing and so cannot be used in these ways. -* If you are creating directly from a file then a :class:`BitArray` or :class:`BitStream` will read the file into memory whereas a :class:`Bits` or :class:`ConstBitStream` will not, so using the const classes allows extremely large files to be examined. +* If you are creating directly from a file then a :class:`BitArray` or :class:`BitStream` will read the whole file into memory whereas a :class:`Bits` or :class:`ConstBitStream` will not, so using the const classes allows extremely large files to be examined. * If you don't need the extra functionality of a particular class then the simpler ones might be faster and more memory efficient. The fastest and most memory efficient class is :class:`Bits`. The :class:`Bits` class is the base class of the other three class. This means that ``isinstance(s, Bits)`` will be true if ``s`` is an instance of any of the four classes. @@ -38,7 +38,7 @@ When initialising a bitstring you need to specify at most one initialiser. These will be explained in full below, but briefly they are: * ``auto`` : Either a specially formatted string, a list or tuple, a file object, integer, bytearray, array, bytes or another bitstring. -* ``bytes`` : A ``bytes`` object (a ``str`` in Python 2), for example read from a binary file. +* ``bytes`` : A ``bytes`` object (a ``str`` in Python 2.7), for example read from a binary file. * ``hex``, ``oct``, ``bin``: Hexadecimal, octal or binary strings. * ``int``, ``uint``: Signed or unsigned bit-wise big-endian binary integers. * ``intle``, ``uintle``: Signed or unsigned byte-wise little-endian binary integers. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/examples.rst new/bitstring-bitstring-3.1.9/doc/examples.rst --- old/bitstring-bitstring-3.1.7/doc/examples.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/examples.rst 2021-07-20 19:37:11.000000000 +0200 @@ -74,21 +74,4 @@ >>> print(sps.constraint_flags) [0, 0, 0, 1] -Sieve of Eratosthenes ---------------------- - -This classic (though inefficient) method of calculating prime numbers uses a bitstring to store whether each bit position represents a prime number. This takes much less memory than an ordinary array. :: - - - def prime_sieve(top=1000000): - b = BitArray(top) # bitstring of '0' bits - for i in xrange(2, top): - if not b[i]: - yield i - # i is prime, so set all its multiples to '1'. - b.set(True, xrange(i*i, top, i)) - - - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/index.rst new/bitstring-bitstring-3.1.9/doc/index.rst --- old/bitstring-bitstring-3.1.7/doc/index.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/index.rst 2021-07-20 19:37:11.000000000 +0200 @@ -7,7 +7,7 @@ Features -------- -* Supports Python 2.7 and Python 3. +* Supports Python 2.7 and Python 3.6 and later. * Rich API - chances are that whatever you want to do there's a simple and elegant way of doing it. * Bit level slicing, joining, searching, replacing and more. * Create bitstrings from hex, octal, binary, files, formatted strings, bytes, integers and floats of different endiannesses. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/interpretation.rst new/bitstring-bitstring-3.1.9/doc/interpretation.rst --- old/bitstring-bitstring-3.1.7/doc/interpretation.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/interpretation.rst 2021-07-20 19:37:11.000000000 +0200 @@ -8,7 +8,7 @@ Several Python properties are used to create interpretations for the bitstring. These properties call private functions which will calculate and return the appropriate interpretation. These don???t change the bitstring in any way and it remains just a collection of bits. If you use the property again then the calculation will be repeated. -Note that these properties can potentially be very expensive in terms of both computation and memory requirements. For example if you have initialised a bitstring from a 10 GB file object and ask for its binary string representation then that string will be around 80 GB in size! +Note that these properties can potentially be very expensive in terms of both computation and memory requirements. For example if you have initialised a bitstring from a 10 GiB file object and ask for its binary string representation then that string will be around 80 GiB in size! For the properties described below we will use these:: @@ -99,7 +99,7 @@ bytes ^^^^^ -A common need is to retrieve the raw bytes from a bitstring for further processing or for writing to a file. For this use the :attr:`~Bits.bytes` interpretation, which returns a ``bytes`` object (which is equivalent to an ordinary ``str`` in Python 2.6/2.7). +A common need is to retrieve the raw bytes from a bitstring for further processing or for writing to a file. For this use the :attr:`~Bits.bytes` interpretation, which returns a ``bytes`` object (which is equivalent to an ordinary ``str`` in Python 2.7). If the length of the bitstring isn't a multiple of eight then a :exc:`ValueError` will be raised. This is because there isn't an unequivocal representation as ``bytes``. You may prefer to use the method :meth:`~Bits.tobytes` as this will be pad with between one and seven zero bits up to a byte boundary if necessary. :: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/introduction.rst new/bitstring-bitstring-3.1.9/doc/introduction.rst --- old/bitstring-bitstring-3.1.7/doc/introduction.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/introduction.rst 2021-07-20 19:37:11.000000000 +0200 @@ -6,7 +6,7 @@ While it is not difficult to manipulate binary data in Python, for example using the :mod:`struct` and :mod:`array` modules, it can be quite fiddly and time consuming even for quite small tasks, especially if you are not dealing only with whole-byte data. -The bitstring module provides four classes, :class:`BitStream`, :class:`BitArray`, :class:`ConstBitStream` and :class:`Bits`, instances of which can be constructed from integers, floats, hex, octal, binary, strings or files, but they all just represent a string of binary digits. I shall use the general term 'bitstring' when referring generically to any of the classes, and use the class names for parts that apply to only one or another. +The bitstring module provides four classes, :class:`BitStream`, :class:`BitArray`, :class:`ConstBitStream` and :class:`Bits`, instances of which can be constructed from integers, floats, hex, octal, binary, strings or files, but they all just represent a string of binary digits. I shall use the term 'bitstring' when referring generically to any of the classes, and use the class names for parts that apply to only one or another. :class:`BitArray` objects can be sliced, joined, reversed, inserted into, overwritten, packed, unpacked etc. with simple functions or slice notation. :class:`BitStream` objects can also be read from, searched in, and navigated in, similar to a file or stream. @@ -75,11 +75,11 @@ python setup.py install -You might need to add a 'sudo' to the start of that command, depending on your system. This will copy the source files to your Python installation's ``site-packages`` directory. +You might need to add a 'sudo' to the start of that command, depending on your system, if you're not using a virtualenv. This will copy the source files to your Python installation's ``site-packages`` directory. The module comes with comprehensive unit tests. To run them yourself use your favourite unit test running method, mine is:: python -m unittest discover -which when run in the `test` folder should run all the tests (almost 500) and say OK. If tests fail then either your version of Python isn't supported (you need Python 2.7 or 3.x) or something unexpected has happened - in which case please tell me about it. +which when run in the `test` folder should run all the tests (over 500) and say OK. If tests fail then either your version of Python isn't supported (you need Python 2.7 or 3.6+) or something unexpected has happened - in which case please tell me about it. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/misc.rst new/bitstring-bitstring-3.1.9/doc/misc.rst --- old/bitstring-bitstring-3.1.7/doc/misc.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/misc.rst 2021-07-20 19:37:11.000000000 +0200 @@ -39,7 +39,7 @@ Returns the byte data contained in the bitstring as a ``bytes`` object (equivalent to a ``str`` if you're using Python 2.7). This differs from using the plain :attr:`~Bits.bytes` property in that if the bitstring isn't a whole number of bytes long then it will be made so by appending up to seven zero bits. :: >>> BitArray('0b1').tobytes() - '\x80' + b'\x80' ``tofile`` ^^^^^^^^^^ @@ -82,7 +82,7 @@ This implements the :func:`len` function and returns the length of the bitstring in bits. -It's recommended that you use the :attr:`~Bits.len` property instead of the function as a limitation of Python means that the function will raise an :exc:`OverflowError` if the bitstring has more than ``sys.maxsize`` elements (that's typically 256MB of data with 32-bit Python). +It's recommended that you use the :attr:`~Bits.len` property instead of the function if you're using a 32-bit Python installation as the len function will raise an :exc:`OverflowError` if the bitstring has more than ``sys.maxsize`` elements (that's typically 256MiB of data with 32-bit Python). There's not much more to say really, except to emphasise that it is always in bits and never bytes. :: @@ -110,7 +110,7 @@ ``__eq__ / __ne__`` ^^^^^^^^^^^^^^^^^^^ -The equality of two bitstring objects is determined by their binary representations being equal. If you have a different criterion you wish to use then code it explicitly, for example ``a.int == b.int`` could be true even if ``a == b`` wasn't (as they could be different lengths). :: +The equality of two bitstring objects is determined by their binary representations being equal. If you have a different criterion you wish to use then code it explicitly, for example ``a.int == b.int`` could be true even if ``a == b`` wasn't (as they could be different lengths). :: >>> BitArray('0b0010') == '0x2' True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/reading.rst new/bitstring-bitstring-3.1.9/doc/reading.rst --- old/bitstring-bitstring-3.1.7/doc/reading.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/reading.rst 2021-07-20 19:37:11.000000000 +0200 @@ -11,7 +11,7 @@ The :class:`BitStream` and :class:`ConstBitStream` classes contain number of methods for reading the bitstring as if it were a file or stream. Depending on how it was constructed the bitstream might actually be contained in a file rather than stored in memory, but these methods work for either case. -In order to behave like a file or stream, every bitstream has a property :attr:`~ConstBitStream.pos` which is the current position from which reads occur. :attr:`~ConstBitStream.pos` can range from zero (its value on construction) to the length of the bitstream, a position from which all reads will fail as it is past the last bit. Note that the :attr:`~ConstBitStream.pos` property isn't considered a part of the bitstream's identity; this allows it to vary for immutable :class:`ConstBitStream` objects and means that it doesn't affect equality or hash values. +In order to behave like a file or stream, every bitstream has a property :attr:`~ConstBitStream.pos` which is the current position from which reads occur. :attr:`~ConstBitStream.pos` can range from zero (its default value on construction) to the length of the bitstream, a position from which all reads will fail as it is past the last bit. Note that the :attr:`~ConstBitStream.pos` property isn't considered a part of the bitstream's identity; this allows it to vary for immutable :class:`ConstBitStream` objects and means that it doesn't affect equality or hash values. The property :attr:`~ConstBitStream.bytepos` is also available, and is useful if you are only dealing with byte data and don't want to always have to divide the bit position by eight. Note that if you try to use :attr:`~ConstBitStream.bytepos` and the bitstring isn't byte aligned (i.e. :attr:`~ConstBitStream.pos` isn't a multiple of 8) then a :exc:`ByteAlignError` exception will be raised. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/doc/walkthrough.rst new/bitstring-bitstring-3.1.9/doc/walkthrough.rst --- old/bitstring-bitstring-3.1.7/doc/walkthrough.rst 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/doc/walkthrough.rst 2021-07-20 19:37:11.000000000 +0200 @@ -16,7 +16,7 @@ Prerequisites ------------- -* Python 2.7 or 3.x. +* Python 2.7 or 3.6 or later. * An installed bitstring module. * A rudimentary knowledge of binary concepts. * A little free time. @@ -61,12 +61,12 @@ >>> b.int -2 >>> a.bytes - '\xff\x01' + b'\xff\x01' There are a few things to note here: * To get the different interpretations of the binary data we use properties such as :attr:`~Bits.bin`, :attr:`~Bits.hex`, :attr:`~Bits.oct`, :attr:`~Bits.int` and :attr:`~Bits.bytes`. You can probably guess what these all mean, but you don't need to know quite yet. The properties are calculated when you ask for them rather than being stored as part of the object itself. -* The :attr:`~Bits.bytes` property returns a ``bytes`` object. This is slightly different in Python 2.7 to Python 3 - in Python 3 you would get ``b'\xff\x01'`` returned instead. +* The :attr:`~Bits.bytes` property returns a ``bytes`` object. This is slightly different in Python 2.7 to Python 3 - in Python 2.7 you would get ``'\xff\x01'`` returned instead. Great - let's try some more:: @@ -265,10 +265,10 @@ # create a BitArray with a million zero bits. # The bits will be set to indicate that the bit position isn't prime. has_factors = BitArray(1000000) - for i in xrange(2, 1000000): + for i in range(2, 1000000): if not has_factors[i]: print(i) # Set all multiples of our prime to 1. - has_factors.set(True, xrange(i*2, 1000000, i)) + has_factors.set(True, range(i*2, 1000000, i)) I'll leave optimising the algorithm as an exercise for the reader, but it illustrates both bit checking and setting. One reason you might want to use a bitstring for this purpose (instead of a plain list for example) is that the million bits only take up a million bits in memory, whereas for a list of integers it would be much more. Try asking for a billion elements in a list - unless you've got some really nice hardware it will fail, whereas a billion element bitstring only takes 125MB. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/release_notes.txt new/bitstring-bitstring-3.1.9/release_notes.txt --- old/bitstring-bitstring-3.1.7/release_notes.txt 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/release_notes.txt 2021-07-20 19:37:11.000000000 +0200 @@ -3,6 +3,20 @@ -------------------------------- --------------------------------------- +July 20th 2021: version 3.1.9 released +--------------------------------------- +(version 3.1.8 was pulled due to serious issues) +Another maintenance release. + +* Fixed a couple of outdated results in the readme (Issue 214). +* Some more documentation tidying. +* Turned off some debug code by default. +* Fixed a couple of failing tests in different Python versions. +* Fix for consistent pos initialisation semantics for different types. +* Change to allow wheels to be uploaded to PyPI. +* More work for LSB0 mode, but still not finished or documented (sorry). + +--------------------------------------- May 5th 2020: version 3.1.7 released --------------------------------------- This is a maintenance release with a few bug fixes plus an experimental diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/setup.py new/bitstring-bitstring-3.1.9/setup.py --- old/bitstring-bitstring-3.1.7/setup.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/setup.py 2021-07-20 19:37:11.000000000 +0200 @@ -1,5 +1,6 @@ #!/usr/bin/env python +import setuptools from distutils.core import setup import sys @@ -10,7 +11,7 @@ raise Exception('This version of bitstring needs Python 2.7 or later.') setup(name='bitstring', - version='3.1.7', + version='3.1.9', description='Simple construction, analysis and modification of binary data.', author='Scott Griffiths', author_email='dr.scottgriffi...@gmail.com', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/test/test_bitarray.py new/bitstring-bitstring-3.1.9/test/test_bitarray.py --- old/bitstring-bitstring-3.1.7/test/test_bitarray.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/test/test_bitarray.py 2021-07-20 19:37:11.000000000 +0200 @@ -390,9 +390,9 @@ def testAppendingBits(self): a = BitArray('0b111') a.append('0b000') - self.assertEqual(a.bin, '111000') + self.assertEqual(a.bin, '000111') a += '0xabc' - self.assertEqual(a, '0b111000, 0xabc') + self.assertEqual(a, '0xabc, 0b000111') def testSettingSlice(self): a = BitArray('0x012345678') @@ -434,14 +434,13 @@ self.assertEqual(l, ['0x2222', '0x11ff', '0xff11', '0xff00']) def testFind(self): - pass - # a = BitArray('0b10101010, 0xabcd, 0b10101010, 0x0') - # p, = a.find('0b10101010', bytealigned=False) - # self.assertEqual(p, 4) - # p, = a.find('0b10101010', start=4, bytealigned=False) - # self.assertEqual(p, 4) - # p, = a.find('0b10101010', start=5, bytealigned=False) - # self.assertEqual(p, 28) + a = BitArray('0b10101010, 0xabcd, 0b10101010, 0x0') + p, = a.find('0b10101010', bytealigned=False) + self.assertEqual(p, 4) + p, = a.find('0b10101010', start=4, bytealigned=False) + self.assertEqual(p, 4) + p, = a.find('0b10101010', start=5, bytealigned=False) + self.assertEqual(p, 22) def testRfind(self): pass @@ -450,16 +449,25 @@ pass def testSplit(self): - pass + a = BitArray('0x4700004711472222') + l = list(a.split('0x47', bytealigned=True)) + self.assertEqual(l, ['', '0x472222', '0x4711', '0x470000']) def testByteSwap(self): - pass + a = BitArray('0xff00ff00ff00') + n = a.byteswap(2, end=32, repeat=True) + self.assertEqual(n, 2) + self.assertEqual(a, '0xff0000ff00ff') def testInsert(self): - pass + a = BitArray('0x0123456') + a.insert('0xf', 4) + self.assertEqual(a, '0x012345f6') def testOverwrite(self): - pass + a = BitArray('0x00000000') + a.overwrite('0xdead', 4) + self.assertEqual(a, '0x000dead0') def testReplace(self): pass @@ -468,10 +476,28 @@ pass def testRor(self): - pass + a = BitArray('0b111000') + a.ror(1) + self.assertEqual(a, '0b011100') + a = BitArray('0b111000') + a.ror(1, start=2, end=6) + self.assertEqual(a, '0b011100') def testRol(self): pass def testSet(self): - pass + a = BitArray(100) + a.set(1, [0, 2, 4]) + self.assertTrue(a[0]) + self.assertTrue(a.startswith('0b000010101')) + a = BitArray('0b111') + a.set(False, 0) + self.assertEqual(a, '0b110') + + +class Repr(unittest.TestCase): + + def testStandardRepr(self): + a = BitArray('0o12345') + self.assertEqual(repr(a), "BitArray('0b001010011100101')") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/test/test_bits.py new/bitstring-bitstring-3.1.9/test/test_bits.py --- old/bitstring-bitstring-3.1.7/test/test_bits.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/test/test_bits.py 2021-07-20 19:37:11.000000000 +0200 @@ -47,11 +47,10 @@ Bits(hex='0Xx0') with self.assertRaises(bitstring.CreationError): Bits(hex='-2e') - # These really should fail, but it's awkward and not a big deal... - # with self.assertRaises(bitstring.CreationError): - # Bits('0x2', length=2) - # with self.assertRaises(bitstring.CreationError): - # Bits('0x3', offset=1) + with self.assertRaises(bitstring.CreationError): + Bits('0x2', length=2) + with self.assertRaises(bitstring.CreationError): + Bits('0x3', offset=1) def testCreationFromBin(self): s = Bits(bin='1010000011111111') @@ -581,3 +580,19 @@ a = Bits('0x1234abcd') self.assertTrue(a.endswith('0x123')) self.assertFalse(a.endswith('0xabcd')) + + +class Lsb0Interpretations(unittest.TestCase): + + @classmethod + def setUpClass(cls): + bitstring.set_lsb0(True) + + @classmethod + def tearDownClass(cls): + bitstring.set_lsb0(False) + + def testUint(self): + a = Bits('0x01') + self.assertEqual(a, '0b00000001') + self.assertEqual(a.uint, 1) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/test/test_bitstream.py new/bitstring-bitstring-3.1.9/test/test_bitstream.py --- old/bitstring-bitstring-3.1.7/test/test_bitstream.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/test/test_bitstream.py 2021-07-20 19:37:11.000000000 +0200 @@ -1930,7 +1930,9 @@ a = BitStream('0b1') self.assertEqual(repr(a), "BitStream('0b1')") a += '0b11' - self.assertEqual(repr(a), "BitStream('0b111')") + a.pos = 2 + self.assertEqual(repr(a), "BitStream('0b111', pos=2)") + a.pos = 0 a += '0b1' self.assertEqual(repr(a), "BitStream('0xf')") a *= max @@ -2829,10 +2831,10 @@ c = BitStream(a) self.assertEqual(a, c) a = ConstBitStream('0b1') - a._append(a) + a._addright(a) self.assertEqual(a, '0b11') self.assertEqual(type(a), ConstBitStream) - a._prepend(a) + a._addleft(a) self.assertEqual(a, '0b1111') self.assertEqual(type(a), ConstBitStream) @@ -3991,7 +3993,11 @@ bitstring.set_msb0() def testSimpleBitPositions(self): - pass + s = BitStream('0x0000ff') + self.assertEqual(s.pos, 0) + v = s.read('uint:8') + self.assertEqual(v, 255) + self.assertEqual(s.pos, 8) def testBitPosAfterFind(self): pass @@ -4009,4 +4015,21 @@ pass def testBitPosAfterReplace(self): - pass \ No newline at end of file + pass + + def testReadList(self): + a = BitStream('0x0123456789abcdef') + + vals = a.readlist('uint:4, uint:4, uint:24, uint:12, uint:12, uint:8') + self.assertEqual(vals, [15, 14, 0x89abcd, 0x567, 0x234, 1]) + +class testRepr(unittest.TestCase): + + def testWithoutPos(self): + a = BitStream('0x12345', pos=0) + self.assertEqual(repr(a), "BitStream('0x12345')") + + def testWithPos(self): + a = BitStream('0b00111', pos=-1) + self.assertEqual(a.pos, 4) + self.assertEqual(repr(a), "BitStream('0b00111', pos=4)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/test/test_bitstring.py new/bitstring-bitstring-3.1.9/test/test_bitstring.py --- old/bitstring-bitstring-3.1.7/test/test_bitstring.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/test/test_bitstring.py 2021-07-20 19:37:11.000000000 +0200 @@ -12,7 +12,7 @@ class ModuleData(unittest.TestCase): def testVersion(self): - self.assertEqual(bitstring.__version__, '3.1.7') + self.assertEqual(bitstring.__version__, '3.1.9') def testAll(self): exported = ['ConstBitArray', 'ConstBitStream', 'BitStream', 'BitArray', @@ -95,13 +95,13 @@ class LSB0(unittest.TestCase): def testGettingAndSetting(self): self.assertEqual(bitstring._lsb0, False) - bitstring.set_lsb0(True) + bitstring.set_lsb0() self.assertEqual(bitstring._lsb0, True) bitstring.set_lsb0(False) self.assertEqual(bitstring._lsb0, False) bitstring.set_msb0(False) self.assertEqual(bitstring._lsb0, True) - bitstring.set_msb0(True) + bitstring.set_msb0() self.assertEqual(bitstring._lsb0, False) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bitstring-bitstring-3.1.7/test/test_constbitstream.py new/bitstring-bitstring-3.1.9/test/test_constbitstream.py --- old/bitstring-bitstring-3.1.7/test/test_constbitstream.py 2020-05-05 22:05:19.000000000 +0200 +++ new/bitstring-bitstring-3.1.9/test/test_constbitstream.py 2021-07-20 19:37:11.000000000 +0200 @@ -162,4 +162,39 @@ with self.assertRaises(bitstring.CreationError): s = CBS(f, length=9*8 + 1) with self.assertRaises(bitstring.CreationError): - s = CBS(f, length=9*8, offset=1) \ No newline at end of file + s = CBS(f, length=9*8, offset=1) + + +class CreationWithPos(unittest.TestCase): + + def testDefaultCreation(self): + s = CBS('0xabc') + self.assertEqual(s.pos, 0) + + def testPositivePos(self): + s = CBS('0xabc', pos=0) + self.assertEqual(s.pos, 0) + s = CBS('0xabc', pos=1) + self.assertEqual(s.pos, 1) + s = CBS('0xabc', pos=12) + self.assertEqual(s.pos, 12) + with self.assertRaises(bitstring.CreationError): + s = CBS('0xabc', pos=13) + + def testNegativePos(self): + s = CBS('0xabc', pos=-1) + self.assertEqual(s.pos, 11) + s = CBS('0xabc', pos=-12) + self.assertEqual(s.pos, 0) + with self.assertRaises(bitstring.CreationError): + s = CBS('0xabc', pos=-13) + + def testStringRepresentation(self): + s = CBS('0b110', pos=2) + self.assertEqual(s.__repr__(), "ConstBitStream('0b110', pos=2)") + + def testStringRepresentationFromFile(self): + s = CBS(filename='test.m1v', pos=2001) + self.assertEqual(s.__repr__(), "ConstBitStream(filename='test.m1v', length=1002400, pos=2001)") + s.pos = 0 + self.assertEqual(s.__repr__(), "ConstBitStream(filename='test.m1v', length=1002400)") \ No newline at end of file