Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-bitarray for openSUSE:Factory
checked in at 2026-06-22 17:44:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-bitarray (Old)
and /work/SRC/openSUSE:Factory/.python-bitarray.new.1956 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-bitarray"
Mon Jun 22 17:44:44 2026 rev:44 rq:1361123 version:3.8.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-bitarray/python-bitarray.changes
2026-04-04 19:08:51.148655325 +0200
+++
/work/SRC/openSUSE:Factory/.python-bitarray.new.1956/python-bitarray.changes
2026-06-22 17:45:14.478989227 +0200
@@ -1,0 +2,8 @@
+Sun Jun 21 18:18:53 UTC 2026 - Martin Hauke <[email protected]>
+
+- Update to version 3.8.2
+ * clarity/wording improvements throughout project.
+ * add 'new_allocation()' to simplify 'resize()'.
+ * drop Python 3.6 support.
+
+-------------------------------------------------------------------
Old:
----
bitarray-3.8.1.tar.gz
New:
----
bitarray-3.8.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-bitarray.spec ++++++
--- /var/tmp/diff_new_pack.XVNcb2/_old 2026-06-22 17:45:15.307018249 +0200
+++ /var/tmp/diff_new_pack.XVNcb2/_new 2026-06-22 17:45:15.307018249 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-bitarray
-Version: 3.8.1
+Version: 3.8.2
Release: 0
Summary: Efficient Arrays of Booleans
License: Python-2.0
++++++ bitarray-3.8.1.tar.gz -> bitarray-3.8.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/CHANGE_LOG
new/bitarray-3.8.2/CHANGE_LOG
--- old/bitarray-3.8.1/CHANGE_LOG 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/CHANGE_LOG 2026-06-17 17:58:51.000000000 +0200
@@ -1,3 +1,10 @@
+2026-06-17 3.8.2:
+-------------------
+ * clarity/wording improvements throughout project
+ * add `new_allocation()` to simplify `resize()`
+ * drop Python 3.6 support
+
+
2026-04-02 3.8.1:
-------------------
* fixed critial findings in C Extension Analysis Report, see #250
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/README.rst
new/bitarray-3.8.2/README.rst
--- old/bitarray-3.8.1/README.rst 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/README.rst 2026-06-17 17:58:51.000000000 +0200
@@ -57,7 +57,7 @@
$ python -c 'import bitarray; bitarray.test()'
bitarray is installed in: /Users/ilan/bitarray/bitarray
- bitarray version: 3.8.1
+ bitarray version: 3.8.2
sys.version: 3.13.5 (main, Jun 16 2025) [Clang 18.1.8]
sys.prefix: /Users/ilan/miniforge
pointer size: 64 bit
@@ -320,7 +320,7 @@
Reference
=========
-bitarray version: 3.8.1 -- `change log
<https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__
+bitarray version: 3.8.2 -- `change log
<https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__
In the following, ``item`` and ``value`` are usually a single bit -
an integer 0 or 1.
@@ -344,7 +344,7 @@
``endian``: Specifies the bit-endianness of the created bitarray object.
Allowed values are ``big`` and ``little`` (the default is ``big``).
- The bit-endianness effects the buffer representation of the bitarray.
+ The bit-endianness affects the buffer representation of the bitarray.
``buffer``: Any object which exposes a buffer. When provided,
``initializer``
cannot be present (or has to be ``None``). The imported buffer may be
@@ -439,7 +439,7 @@
``extend(iterable, /)``
- Append items from to the end of the bitarray.
+ Append items from iterable to the end of the bitarray.
If ``iterable`` is a (Unicode) string, each ``0`` and ``1`` are appended as
bits (ignoring whitespace and underscore).
@@ -470,7 +470,7 @@
``fromfile(f, n=-1, /)``
Extend bitarray with up to ``n`` bytes read from file object ``f`` (or any
- other binary stream what supports a ``.read()`` method, e.g.
``io.BytesIO``).
+ other binary stream that supports a ``.read()`` method, e.g.
``io.BytesIO``).
Each read byte will add eight bits to the bitarray. When ``n`` is omitted
or negative, reads and extends all data until EOF.
When ``n`` is non-negative but exceeds the available data, ``EOFError`` is
@@ -490,8 +490,9 @@
``invert(index=<all bits>, /)``
- Invert all bits in bitarray (in-place).
- When the optional ``index`` is given, only invert the single bit at
``index``.
+ Invert bits in-place. When ``index`` is omitted, invert all bits.
+ When ``index`` is an integer, invert the single bit at index.
+ When ``index`` is a slice, invert the selected bits.
New in version 1.5.3: optional index argument
@@ -574,7 +575,7 @@
``unpack(zero=b'\x00', one=b'\x01')`` -> bytes
Return bytes that contain one byte for each bit in the bitarray,
- using specified mapping.
+ using the specified mapping.
bitarray data descriptors:
@@ -649,7 +650,8 @@
``ba2base(n, bitarray, /, group=0, sep=' ')`` -> str
Return a string containing the base ``n`` ASCII representation of
the bitarray. Allowed values for ``n`` are 2, 4, 8, 16, 32 and 64.
- The bitarray has to be multiple of length 1, 2, 3, 4, 5 or 6 respectively.
+ The bitarray has to have a length divisible by 1, 2, 3, 4, 5 or 6
+ respectively.
For ``n=32`` the RFC 4648 Base32 alphabet is used, and for ``n=64`` the
standard base 64 alphabet is used.
When grouped, the string ``sep`` is inserted between groups
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/bitarray/_bitarray.c
new/bitarray-3.8.2/bitarray/_bitarray.c
--- old/bitarray-3.8.1/bitarray/_bitarray.c 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/bitarray/_bitarray.c 2026-06-17 17:58:51.000000000
+0200
@@ -24,6 +24,34 @@
#define bitarray_Check(obj) PyObject_TypeCheck((obj), &Bitarray_Type)
+static size_t
+new_allocation(size_t size, size_t allocated, size_t newsize)
+{
+ assert(allocated >= size);
+ assert(newsize > 0);
+
+ if (allocated >= newsize) {
+ /* current buffer is large enough to host the requested size */
+ if (newsize >= allocated / 2)
+ return allocated; /* minor downsize - keep current allocation */
+
+ return newsize; /* major downsize - shrink to exact size */
+ }
+ else {
+ /* need to grow buffer */
+ size_t new_alloc = newsize;
+ /* overallocate when previous size isn't zero and when growth
+ is moderate */
+ if (size != 0 && newsize / 2 <= allocated) {
+ /* overallocate proportional to the bitarray size and
+ add padding to make the allocated size multiple of 4 */
+ new_alloc += (newsize >> 4) + (newsize < 8 ? 3 : 7);
+ new_alloc &= ~(size_t) 3;
+ }
+ return new_alloc;
+ }
+}
+
static int
resize(bitarrayobject *self, Py_ssize_t nbits)
{
@@ -69,28 +97,13 @@
return 0;
}
- if (allocated >= newsize) {
- /* current buffer is large enough to host the requested size */
- if (newsize >= allocated / 2) {
- /* minor downsize, bypass reallocation */
- Py_SET_SIZE(self, newsize);
- self->nbits = nbits;
- return 0;
- }
- /* major downsize, resize down to exact size */
- new_allocated = newsize;
- }
- else {
- /* need to grow buffer */
- new_allocated = newsize;
- /* overallocate when previous size isn't zero and when growth
- is moderate */
- if (size != 0 && newsize / 2 <= allocated) {
- /* overallocate proportional to the bitarray size and
- add padding to make the allocated size multiple of 4 */
- new_allocated += (newsize >> 4) + (newsize < 8 ? 3 : 7);
- new_allocated &= ~(size_t) 3;
- }
+ new_allocated = new_allocation(size, allocated, newsize);
+
+ if (new_allocated == allocated) {
+ /* bypass reallocation */
+ Py_SET_SIZE(self, newsize);
+ self->nbits = nbits;
+ return 0;
}
assert(new_allocated >= newsize);
@@ -203,7 +216,7 @@
/* The following two functions operate on first n bytes in buffer.
Within this region, they shift all bits by k positions to right,
i.e. towards higher addresses.
- They operate on little-endian and bit-endian bitarrays respectively.
+ They operate on little-endian and big-endian bitarrays respectively.
As we shift right, we need to start with the highest address and loop
downwards such that lower bytes are still unaltered.
See also devel/shift_r8.c
@@ -1194,7 +1207,7 @@
PyDoc_STRVAR(extend_doc,
"extend(iterable, /)\n\
\n\
-Append items from to the end of the bitarray.\n\
+Append items from iterable to the end of the bitarray.\n\
If `iterable` is a (Unicode) string, each `0` and `1` are appended as\n\
bits (ignoring whitespace and underscore).");
@@ -1346,7 +1359,8 @@
invert_span(self, 0, self->nbits);
}
else {
- return PyErr_Format(PyExc_TypeError, "index expect, not '%s' object",
+ return PyErr_Format(PyExc_TypeError,
+ "index expected, not '%s' object",
Py_TYPE(arg)->tp_name);
}
Py_RETURN_NONE;
@@ -1355,8 +1369,9 @@
PyDoc_STRVAR(invert_doc,
"invert(index=<all bits>, /)\n\
\n\
-Invert all bits in bitarray (in-place).\n\
-When the optional `index` is given, only invert the single bit at `index`.");
+Invert bits in-place. When `index` is omitted, invert all bits.\n\
+When `index` is an integer, invert the single bit at index.\n\
+When `index` is a slice, invert the selected bits.");
static PyObject *
@@ -1557,7 +1572,7 @@
assert(Py_SIZE(self) == n + view.len);
memcpy(self->ob_item + n, (char *) view.buf, (size_t) view.len);
- /* remove pad bits staring at previous bit length (8 * n - p) */
+ /* remove pad bits starting at previous bit length (8 * n - p) */
if (delete_n(self, 8 * n - p, p) < 0)
goto error;
@@ -1654,7 +1669,7 @@
"fromfile(f, n=-1, /)\n\
\n\
Extend bitarray with up to `n` bytes read from file object `f` (or any\n\
-other binary stream what supports a `.read()` method, e.g. `io.BytesIO`).\n\
+other binary stream that supports a `.read()` method, e.g. `io.BytesIO`).\n\
Each read byte will add eight bits to the bitarray. When `n` is omitted\n\
or negative, reads and extends all data until EOF.\n\
When `n` is non-negative but exceeds the available data, `EOFError` is\n\
@@ -1673,7 +1688,7 @@
Py_ssize_t size = Py_MIN(nbytes - offset, BLOCKSIZE);
assert(size >= 0 && offset + size <= nbytes);
- /* basically: f.write(memoryview(self)[offset:offset + size] */
+ /* basically: f.write(memoryview(self)[offset:offset + size]) */
ret = PyObject_CallMethod(f, "write", "y#",
self->ob_item + offset, size);
if (ret == NULL)
@@ -1763,7 +1778,7 @@
"unpack(zero=b'\\x00', one=b'\\x01') -> bytes\n\
\n\
Return bytes that contain one byte for each bit in the bitarray,\n\
-using specified mapping.");
+using the specified mapping.");
static PyObject *
@@ -3167,7 +3182,7 @@
"complete() -> bool\n\
\n\
Return whether tree is complete. That is, whether or not all\n\
-nodes have both children (unless they are symbols nodes).");
+nodes have both children (unless they are symbol nodes).");
static PyObject *
@@ -3332,7 +3347,7 @@
PyObject *symbol;
symbol = binode_traverse(it->tree, it->self, &(it->index));
- if (symbol == NULL) /* stop iteration OR error occured */
+ if (symbol == NULL) /* stop iteration OR error occurred */
return NULL;
Py_INCREF(symbol);
return symbol;
@@ -3723,9 +3738,9 @@
}
/* As of bitarray version 2.9.0, "bitarray(nbits)" will initialize all items
- to 0 (previously, the buffer was be uninitialized).
+ to 0 (previously, the buffer was uninitialized).
However, for speed, one might want to create an uninitialized bitarray.
- In 2.9.1, we added the ability to created uninitialized bitarrays again,
+ In 2.9.1, we added the ability to create uninitialized bitarrays again,
using "bitarray(nbits, endian, Ellipsis)".
*/
static PyObject *
@@ -4003,7 +4018,7 @@
\n\
`endian`: Specifies the bit-endianness of the created bitarray object.\n\
Allowed values are `big` and `little` (the default is `big`).\n\
-The bit-endianness effects the buffer representation of the bitarray.\n\
+The bit-endianness affects the buffer representation of the bitarray.\n\
\n\
`buffer`: Any object which exposes a buffer. When provided, `initializer`\n\
cannot be present (or has to be `None`). The imported buffer may be\n\
@@ -4203,7 +4218,7 @@
PyDoc_STRVAR(sysinfo_doc,
"_sysinfo(key) -> int\n\
\n\
-Return system and compile specific information given a key.");
+Return system- and compile-specific information given a key.");
static PyMethodDef module_functions[] = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/bitarray/_util.c
new/bitarray-3.8.2/bitarray/_util.c
--- old/bitarray-3.8.1/bitarray/_util.c 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/bitarray/_util.c 2026-06-17 17:58:51.000000000 +0200
@@ -31,7 +31,7 @@
/* Return new bitarray of length 'nbits', endianness given by the PyObject
'endian' (which may be Py_None).
- Unless -1, 'c' is placed into all characters of buffer. */
+ Unless -1, 'c' is written to all bytes of the buffer. */
static bitarrayobject *
new_bitarray(Py_ssize_t nbits, PyObject *endian, int c)
{
@@ -494,7 +494,7 @@
v = zlw(b);
not_u = ~u;
not_v = ~v;
- /* for nff we need to substract the number of unused 1 bits */
+ /* for nff we need to subtract the number of unused 1 bits */
nff += popcnt_64(not_u & not_v) - (64 - rbits);
nft += popcnt_64(not_u & v);
ntf += popcnt_64(u & not_v);
@@ -552,7 +552,7 @@
if (n < 0)
return PyErr_Format(PyExc_ValueError,
- "positive int expect, got %zd", n);
+ "positive int expected, got %zd", n);
if (PyObject_GetBuffer(buffer, &view, PyBUF_SIMPLE | PyBUF_WRITABLE) < 0)
return NULL;
@@ -839,7 +839,7 @@
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* Given the length of the base m in [1..6] and a character c, return
- its index in the base 2**m alphabet , or -1 if when c is not included.
+ its index in the base 2**m alphabet, or -1 if c is not included.
Note: i >> m is true when i is not in range(0, 2**m) */
static int
digit_to_int(int m, char c)
@@ -981,7 +981,8 @@
\n\
Return a string containing the base `n` ASCII representation of\n\
the bitarray. Allowed values for `n` are 2, 4, 8, 16, 32 and 64.\n\
-The bitarray has to be multiple of length 1, 2, 3, 4, 5 or 6 respectively.\n\
+The bitarray has to have a length divisible by 1, 2, 3, 4, 5 or 6\n\
+respectively.\n\
For `n=32` the RFC 4648 Base32 alphabet is used, and for `n=64` the\n\
standard base 64 alphabet is used.\n\
When grouped, the string `sep` is inserted between groups\n\
@@ -1200,7 +1201,7 @@
* The last element rts[NSEG(self)] is always the total count.
Here: rts[NSEG(self)] = rts[4] = 12
- * The last segment may be partial. In that case, its size it given
+ * The last segment may be partial. In that case, its size is given
by nbits % 256. Here: nbits % 256 = 987 % 256 = 219
As each segment (at large) covers 256 bits (32 bytes), and each element
@@ -1284,7 +1285,7 @@
a.count(1, 8 * offset, 8 * offset + (1 << (8 * n)))
- The offset must be divisible by SEGSIZE, as this functions makes use of
+ The offset must be divisible by SEGSIZE, as this function makes use of
running totals, stored in rts[].
Here, and in the following, 'offset' is in units of bytes. */
static Py_ssize_t
@@ -1301,7 +1302,7 @@
/* Write a raw block, and return number of bytes copied.
Note that the encoded block size is the return value + 1 (the head byte).
- The header byte is in range(0x01, 0xa0).
+ The head byte is in range(0x01, 0xa0).
* range(0x01, 0x20) number of raw bytes
* range(0x20, 0xa0) number of 32-byte segments */
static int
@@ -1341,7 +1342,6 @@
sc_write_indices(char *str, bitarrayobject *a, Py_ssize_t *rts,
Py_ssize_t offset, int n, int k)
{
- const char *str_stop = str + n * k; /* stop position in buffer 'str' */
const char *buff = a->ob_item + offset;
Py_ssize_t m;
@@ -1370,12 +1370,13 @@
if (buff[i] & BITMASK(a, j)) {
write_n(str, n, 8 * i + j);
str += n;
- if (--ni == 0) {
+ if (--k == 0)
+ /* we have encountered all indices in this block */
+ return;
+
+ if (--ni == 0)
/* we have encountered all indices in this segment */
- if (str == str_stop)
- return;
goto next_segment;
- }
}
}
}
@@ -1407,7 +1408,7 @@
str[len++] = (char) (0xc0 + n); /* block type */
str[len++] = (char) k; /* index count */
}
- if (k == 0) /* no index bytes - sc_write_sparse() does not allow k = 0 */
+ if (k == 0) /* no index bytes to write */
return len;
/* write block data - k indices, n bytes per index */
@@ -1423,7 +1424,7 @@
- 32 index bytes take up as much space as a raw buffer of 32 bytes.
Hence, if the bit count of the first 32 bytes of the bitarray buffer
- is greater or equal to 32, we choose a raw block (type 0).
+ is greater than or equal to 32, we choose a raw block (type 0).
- Arguably, n index bytes always take up as much space as n raw bytes.
So what makes 32 special here? A bitarray with a 32 byte buffer has
@@ -1459,7 +1460,7 @@
header_size + (n + 1) * population
- As n >= 1, the header_size will is always 2 bytes here.
+ As n >= 1, the header_size is always 2 bytes here.
- As we only need to know which of these sizes is bigger, we can
subtract (n * population) from both sizes. Hence, the costs are:
@@ -1480,7 +1481,7 @@
assert(nbytes > 0);
count = (int) sc_count(a, rts, offset, 1);
- /* the number of index bytes exceeds the number of raw bytes */
+ /* the number of index bytes is no smaller than the number of raw bytes */
if (count >= Py_MIN(32, nbytes)) { /* type 0 - raw bytes */
int k = sc_write_raw(str + *len, a, rts, offset);
*len += 1 + k;
@@ -1515,7 +1516,7 @@
return BSI(n);
}
-/* write header and return number or bytes written to buffer 'str' */
+/* write header and return number of bytes written to buffer 'str' */
static int
sc_encode_header(char *str, bitarrayobject *a)
{
@@ -1565,7 +1566,7 @@
/* Make sure we have enough memory in output buffer for next block.
The largest block possible is a type 0 block with 128 segments.
- Its size is: 1 head bytes + 128 * 32 raw bytes.
+ Its size is: 1 head byte + 128 * 32 raw bytes.
Plus, we also may have the stop byte. */
if (allocated < len + 1 + 128 * 32 + 1) {
if (_PyBytes_Resize(&out, allocated + ALLOC_SIZE) < 0)
@@ -1597,7 +1598,7 @@
/* read header from 'iter' and set 'endian' and 'nbits', return 0 on success
- and -1 of failure (after setting exception) */
+ and -1 on failure (after setting exception) */
static int
sc_decode_header(PyObject *iter, int *endian, Py_ssize_t *nbits)
{
@@ -1759,12 +1760,12 @@
'padding' refers to the pad bits within the variable length format.
This is not the same as the pad bits of the actual bitarray.
For example, b'\x10' has padding = 1, and decodes to bitarray('000'),
- which has 5 pad bits. 'padding' can take values to up 6.
+ which has 5 pad bits. 'padding' can take values up to 6.
*/
#define LEN_PAD_BITS 3
/* initial number of bits we allocate in vl_decode(), and amount by which
- we increase our allocation by in vl_decode_core() if we run out */
+ we increase the allocation in vl_decode_core() */
#define ALLOC_BITS 1024
/* Consume 'iter' while extending bitarray 'a'.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/bitarray/bitarray.h
new/bitarray-3.8.2/bitarray/bitarray.h
--- old/bitarray-3.8.1/bitarray/bitarray.h 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/bitarray/bitarray.h 2026-06-17 17:58:51.000000000
+0200
@@ -4,7 +4,7 @@
Author: Ilan Schnell
*/
-#define BITARRAY_VERSION "3.8.1"
+#define BITARRAY_VERSION "3.8.2"
#ifdef STDC_HEADERS
# include <stddef.h>
@@ -64,7 +64,7 @@
/* number of pad bits */
#define PADBITS(self) ((8 - (self)->nbits % 8) % 8)
-/* number of bytes necessary to store given nunmber of bits */
+/* number of bytes necessary to store given number of bits */
#define BYTES(bits) (((bits) + 7) >> 3)
/* we're not using bitmask_table here, as it is actually slower */
@@ -268,7 +268,7 @@
return (4 - r) % 4;
}
-/* population count of n words starting from at uint64_t pointer w */
+/* population count of n words starting at uint64_t pointer w */
static inline Py_ssize_t
popcnt_words(uint64_t *w, Py_ssize_t n)
{
@@ -301,7 +301,7 @@
assert(*step != 1 || slicelength == 0 || *stop - *start == slicelength);
}
-/* convert Python object to C int and set value at address -
+/* convert Python object to C int at address *vi -
return 1 on success, 0 on failure (and set exception) */
static inline int
conv_pybit(PyObject *value, int *vi)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/bitarray/pythoncapi_compat.h
new/bitarray-3.8.2/bitarray/pythoncapi_compat.h
--- old/bitarray-3.8.1/bitarray/pythoncapi_compat.h 2026-04-02
17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/bitarray/pythoncapi_compat.h 2026-06-17
17:58:51.000000000 +0200
@@ -25,9 +25,6 @@
#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
# include "frameobject.h" // PyFrameObject, PyFrame_GetBack()
#endif
-#if PY_VERSION_HEX < 0x030C00A3
-# include <structmember.h> // T_SHORT, READONLY
-#endif
#ifndef _Py_CAST
@@ -1428,6 +1425,11 @@
static inline int
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
{
+ if (obj == NULL) {
+ return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer,
+ "<NULL>", 6);
+ }
+
PyObject *str = PyObject_Repr(obj);
if (str == NULL) {
return -1;
@@ -1572,6 +1574,11 @@
// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
+
+#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
+PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);
+#endif
+
static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
if (!PyUnicode_Check(str1)) {
@@ -1586,8 +1593,6 @@
}
#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
- PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);
-
return _PyUnicode_Equal(str1, str2);
#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
return _PyUnicode_EQ(str1, str2);
@@ -1610,11 +1615,14 @@
#if PY_VERSION_HEX < 0x030E00A0
+
+#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
+PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len);
+#endif
+
static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
{
#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
- PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len);
-
return _Py_HashBytes(ptr, len);
#else
Py_hash_t hash;
@@ -1919,43 +1927,46 @@
#if PY_VERSION_HEX < 0x030C00A3
-# define Py_T_SHORT T_SHORT
-# define Py_T_INT T_INT
-# define Py_T_LONG T_LONG
-# define Py_T_FLOAT T_FLOAT
-# define Py_T_DOUBLE T_DOUBLE
-# define Py_T_STRING T_STRING
-# define _Py_T_OBJECT T_OBJECT
-# define Py_T_CHAR T_CHAR
-# define Py_T_BYTE T_BYTE
-# define Py_T_UBYTE T_UBYTE
-# define Py_T_USHORT T_USHORT
-# define Py_T_UINT T_UINT
-# define Py_T_ULONG T_ULONG
-# define Py_T_STRING_INPLACE T_STRING_INPLACE
-# define Py_T_BOOL T_BOOL
-# define Py_T_OBJECT_EX T_OBJECT_EX
-# define Py_T_LONGLONG T_LONGLONG
-# define Py_T_ULONGLONG T_ULONGLONG
-# define Py_T_PYSSIZET T_PYSSIZET
+# define Py_T_SHORT 0
+# define Py_T_INT 1
+# define Py_T_LONG 2
+# define Py_T_FLOAT 3
+# define Py_T_DOUBLE 4
+# define Py_T_STRING 5
+# define _Py_T_OBJECT 6
+# define Py_T_CHAR 7
+# define Py_T_BYTE 8
+# define Py_T_UBYTE 9
+# define Py_T_USHORT 10
+# define Py_T_UINT 11
+# define Py_T_ULONG 12
+# define Py_T_STRING_INPLACE 13
+# define Py_T_BOOL 14
+# define Py_T_OBJECT_EX 16
+# define Py_T_LONGLONG 17
+# define Py_T_ULONGLONG 18
+# define Py_T_PYSSIZET 19
# if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
-# define _Py_T_NONE T_NONE
+# define _Py_T_NONE 20
# endif
-# define Py_READONLY READONLY
-# define Py_AUDIT_READ READ_RESTRICTED
-# define _Py_WRITE_RESTRICTED PY_WRITE_RESTRICTED
+# define Py_READONLY 1
+# define Py_AUDIT_READ 2
+# define _Py_WRITE_RESTRICTED 4
#endif
// gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4
#if PY_VERSION_HEX < 0x030E00A4
+
+#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION)
+PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode);
+#endif
+
static inline FILE* Py_fopen(PyObject *path, const char *mode)
{
#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION)
- PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode);
-
return _Py_fopen_obj(path, mode);
#else
FILE *f;
@@ -1992,6 +2003,8 @@
#if 0x03080000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 &&
!defined(PYPY_VERSION)
+PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
+
static inline PyObject*
PyConfig_Get(const char *name)
{
@@ -2127,8 +2140,6 @@
return Py_NewRef(value);
}
- PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
-
const PyConfig *config = _Py_GetConfig();
void *member = (char *)config + spec->offset;
switch (spec->type) {
@@ -2231,6 +2242,81 @@
}
#endif
+// gh-128926 added PyUnstable_TryIncRef() and PyUnstable_EnableTryIncRef() to
+// Python 3.14.0a5. Adapted from _Py_TryIncref() and
_PyObject_SetMaybeWeakref().
+#if PY_VERSION_HEX < 0x030E00A5
+static inline int PyUnstable_TryIncRef(PyObject *op)
+{
+#ifndef Py_GIL_DISABLED
+ if (Py_REFCNT(op) > 0) {
+ Py_INCREF(op);
+ return 1;
+ }
+ return 0;
+#else
+ // _Py_TryIncrefFast()
+ uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
+ local += 1;
+ if (local == 0) {
+ // immortal
+ return 1;
+ }
+ if (_Py_IsOwnedByCurrentThread(op)) {
+ _Py_INCREF_STAT_INC();
+ _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
+#ifdef Py_REF_DEBUG
+ _Py_INCREF_IncRefTotal();
+#endif
+ return 1;
+ }
+
+ // _Py_TryIncRefShared()
+ Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared);
+ for (;;) {
+ // If the shared refcount is zero and the object is either merged
+ // or may not have weak references, then we cannot incref it.
+ if (shared == 0 || shared == _Py_REF_MERGED) {
+ return 0;
+ }
+
+ if (_Py_atomic_compare_exchange_ssize(
+ &op->ob_ref_shared,
+ &shared,
+ shared + (1 << _Py_REF_SHARED_SHIFT))) {
+#ifdef Py_REF_DEBUG
+ _Py_INCREF_IncRefTotal();
+#endif
+ _Py_INCREF_STAT_INC();
+ return 1;
+ }
+ }
+#endif
+}
+
+static inline void PyUnstable_EnableTryIncRef(PyObject *op)
+{
+#ifdef Py_GIL_DISABLED
+ // _PyObject_SetMaybeWeakref()
+ if (_Py_IsImmortal(op)) {
+ return;
+ }
+ for (;;) {
+ Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared);
+ if ((shared & _Py_REF_SHARED_FLAG_MASK) != 0) {
+ // Nothing to do if it's in WEAKREFS, QUEUED, or MERGED states.
+ return;
+ }
+ if (_Py_atomic_compare_exchange_ssize(
+ &op->ob_ref_shared, &shared, shared | _Py_REF_MAYBE_WEAKREF)) {
+ return;
+ }
+ }
+#else
+ (void)op; // unused argument
+#endif
+}
+#endif
+
#if PY_VERSION_HEX < 0x030F0000
static inline PyObject*
@@ -2587,6 +2673,40 @@
}
#endif
+#if 0x030D0000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030F00A7 &&
!defined(PYPY_VERSION)
+// Immortal objects were implemented in Python 3.12, however there is no easy
API
+// to make objects immortal until 3.14 which has _Py_SetImmortal(). Since
+// immortal objects are primarily needed for free-threading, this API is
implemented
+// for 3.14 using _Py_SetImmortal() and uses private macros on 3.13.
+#if 0x030E0000 <= PY_VERSION_HEX
+PyAPI_FUNC(void) _Py_SetImmortal(PyObject *op);
+#endif
+
+static inline int
+PyUnstable_SetImmortal(PyObject *op)
+{
+ assert(op != NULL);
+ if (!PyUnstable_Object_IsUniquelyReferenced(op) || PyUnicode_Check(op)) {
+ return 0;
+ }
+#if 0x030E0000 <= PY_VERSION_HEX
+ _Py_SetImmortal(op);
+#else
+ // Python 3.13 doesn't export _Py_SetImmortal() function
+ if (PyObject_GC_IsTracked(op)) {
+ PyObject_GC_UnTrack(op);
+ }
+#ifdef Py_GIL_DISABLED
+ op->ob_tid = _Py_UNOWNED_TID;
+ op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL;
+ op->ob_ref_shared = 0;
+#else
+ op->ob_refcnt = _Py_IMMORTAL_REFCNT;
+#endif
+#endif
+ return 1;
+}
+#endif
#ifdef __cplusplus
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/bitarray/util.py
new/bitarray-3.8.2/bitarray/util.py
--- old/bitarray-3.8.1/bitarray/util.py 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/bitarray/util.py 2026-06-17 17:58:51.000000000 +0200
@@ -179,13 +179,13 @@
diff = a.count() - k
randrange = random.randrange
- if diff < 0: # not enough bits 1 - increase count
+ if diff < 0: # not enough 1 bits - increase count
for _ in range(-diff):
i = randrange(n)
while a[i]:
i = randrange(n)
a[i] = 1
- elif diff > 0: # too many bits 1 - decrease count
+ elif diff > 0: # too many 1 bits - decrease count
for _ in range(diff):
i = randrange(n)
while not a[i]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/devel/resize/resize.c
new/bitarray-3.8.2/devel/resize/resize.c
--- old/bitarray-3.8.1/devel/resize/resize.c 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/devel/resize/resize.c 2026-06-17 17:58:51.000000000
+0200
@@ -3,9 +3,9 @@
typedef struct {
- int size;
- int nbits;
- int allocated;
+ size_t size;
+ size_t nbits;
+ size_t allocated;
} bitarrayobject;
@@ -21,10 +21,34 @@
return s % 8000;
}
-void resize(bitarrayobject *self, int nbits)
+size_t new_allocation(size_t size, size_t allocated, size_t newsize)
{
- int size = self->size, allocated = self->allocated;
- int newsize = BYTES(nbits), new_allocated;
+ if (allocated >= newsize) {
+ /* current buffer is large enough to host the requested size */
+ if (newsize >= allocated / 2)
+ return allocated; /* minor downsize - keep current allocation */
+
+ return newsize; /* major downsize - shrink to exact size */
+ }
+ else {
+ /* need to grow buffer */
+ size_t new_alloc = newsize;
+ /* overallocate when previous size isn't zero and when growth
+ is moderate */
+ if (size != 0 && newsize / 2 <= allocated) {
+ /* overallocate proportional to the bitarray size and
+ add padding to make the allocated size multiple of 4 */
+ new_alloc += (newsize >> 4) + (newsize < 8 ? 3 : 7);
+ new_alloc &= ~(size_t) 3;
+ }
+ return new_alloc;
+ }
+}
+
+void resize(bitarrayobject *self, size_t nbits)
+{
+ size_t size = self->size, allocated = self->allocated;
+ size_t newsize = BYTES(nbits), new_allocated;
if (newsize == size) {
self->nbits = nbits;
@@ -39,20 +63,13 @@
return;
}
- if (allocated >= newsize) {
- if (newsize >= allocated / 2) {
- self->size = newsize;
- self->nbits = nbits;
- return;
- }
- new_allocated = newsize;
- }
- else {
- new_allocated = newsize;
- if (size != 0 && newsize / 2 <= allocated) {
- new_allocated += (newsize >> 4) + (newsize < 8 ? 3 : 7);
- new_allocated &= ~(int) 3;
- }
+ new_allocated = new_allocation(size, allocated, newsize);
+
+ if (new_allocated == allocated) {
+ /* bypass reallocation */
+ self->size = newsize;
+ self->nbits = nbits;
+ return;
}
/* realloc(self->ob_item) */
@@ -67,7 +84,7 @@
int i, nbits, prev_alloc = -1;
bitarrayobject x;
-#define SHOW printf("%d %d\n", x.size, x.allocated)
+#define SHOW printf("%lu %lu\n", x.size, x.allocated)
x.size = 0;
x.allocated = 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/devel/sc/notes.txt
new/bitarray-3.8.2/devel/sc/notes.txt
--- old/bitarray-3.8.1/devel/sc/notes.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/bitarray-3.8.2/devel/sc/notes.txt 2026-06-17 17:58:51.000000000
+0200
@@ -0,0 +1,21 @@
+The correspondence between bytecode and the sc format is unusually clean:
+
+instruction byte -> block head
+opcode -> block type
+instruction operands -> count and indices, or raw bytes
+machine state -> current output position / output bitarray
+halt instruction -> stop byte 0x00
+
+And like a bytecode interpreter, the decoder trusts the instruction stream
+only conditionally: it validates block heads, lengths, and index bounds as
+it executes.
+
+The encoder is then analogous to a tiny compiler or optimizer: inspect
+the source bitarray, calculate representation costs, and emit an efficient
+instruction stream for the decoder to execute.
+
+That is a nice way to teach the format because it makes
+the asymmetry intuitive:
+
+sc_encode() -> planner / compiler
+sc_decode() -> interpreter / virtual machine
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/devel/test_debug.py
new/bitarray-3.8.2/devel/test_debug.py
--- old/bitarray-3.8.1/devel/test_debug.py 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/devel/test_debug.py 2026-06-17 17:58:51.000000000
+0200
@@ -125,6 +125,8 @@
for n in range(200):
a = ones(n, self.random_endian())
b = _zlw(a)
+ self.assertEqual(len(b), 64)
+ self.assertEqual(b.endian, a.endian)
r = n % 64
self.assertEqual(b, ones(r) + zeros(64 - r))
@@ -347,8 +349,7 @@
n = randrange(1024)
a = urandom_2(n)
i = randrange(20)
- res = _cfw(a, i)
- self.assertEqual(res, a[64 * i:].count())
+ self.assertEqual(_cfw(a, i), a[64 * i:].count())
class DigitToInt_Tests(unittest.TestCase):
@@ -397,7 +398,7 @@
def test_example(self):
# see example before sc_calc_rts() in _util.c
a = zeros(987)
- a[:5] = a[512:515] = a[768:772] = 1
+ a[[0, 17, 31, 149, 255, 512, 637, 767, 768, 813, 899, 986]] = 1
self.assertEqual(a.count(), 12)
rts = _sc_rts(a)
self.assertEqual(type(rts), list)
@@ -426,8 +427,8 @@
self.assertEqual(rts[0], 0)
self.assertEqual(rts[-1], a.count())
for i in range(self.nseg(a)):
- seg_pop = a.count(1, SEGBITS * i, SEGBITS * (i + 1))
- self.assertEqual(rts[i + 1] - rts[i], seg_pop)
+ self.assertEqual(rts[i + 1] - rts[i],
+ a.count(1, SEGBITS * i, SEGBITS * (i + 1)))
class ReadN_WriteN_Tests(unittest.TestCase, Util):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/bitarray3.rst
new/bitarray-3.8.2/doc/bitarray3.rst
--- old/bitarray-3.8.1/doc/bitarray3.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/bitarray3.rst 2026-06-17 17:58:51.000000000
+0200
@@ -7,21 +7,21 @@
This is similar to how Python's ``dict.keys()``, ``.values()``
and ``.items()`` methods were revamped in the Python 2 to 3 transition.
-In the following table, ``a`` is assumed to a bitarray object.
+In the following table, ``a`` is assumed to be a bitarray object.
+----------------------+----------------------+
| before version 3 | version 3 |
+======================+======================+
| ``a.iterdecode()`` | ``a.decode()`` |
+----------------------+----------------------+
-| ``a.decode()`` | ``list(a.decode()`` |
+| ``a.decode()`` | ``list(a.decode())`` |
+----------------------+----------------------+
| ``a.itersearch()`` | ``a.search()`` |
+----------------------+----------------------+
-| ``a.search()`` | ``list(a.search()`` |
+| ``a.search()`` | ``list(a.search())`` |
+----------------------+----------------------+
-Aside from these changes which will make bitarray 3 more pythonic, there
+Aside from these changes, which will make bitarray 3 more pythonic, there
are a few other minor changes (see changelog).
It should be emphasized that in most common use cases the bitarray 3
transition will require only minor code changes, or no changes at all.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/buffer.rst
new/bitarray-3.8.2/doc/buffer.rst
--- old/bitarray-3.8.1/doc/buffer.rst 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/doc/buffer.rst 2026-06-17 17:58:51.000000000 +0200
@@ -58,7 +58,7 @@
-----------------
As of bitarray version 2.3, it is also possible to import the buffer
-from an object which exposes its buffer. Here the bytearray:
+from an object that exposes its buffer. Here a ``bytearray`` object:
.. code-block:: python
@@ -73,9 +73,9 @@
>>> a
bitarray('000011111111100000001111')
-Again, the shared buffer can be represented and modify by either object ``a``
-and ``c``. When importing a buffer into a bitarray, the length of the
-bitarray will always be multiple of 8 bits, as buffers are bases on bytes.
+Again, the shared buffer can be represented and modified by either object
+``a`` or ``c``. When importing a buffer into a bitarray, the length of the
+bitarray will always be a multiple of 8 bits, as buffers are based on bytes.
Also, we may specify the endianness of the bitarray:
.. code-block:: python
@@ -86,7 +86,7 @@
The bytearray ``c`` is now exporting its buffer twice:
to big-endian bitarray ``a``, and a little-endian bitarray ``b``.
-At this point all three object ``a``, ``b`` and ``c`` share the same buffer.
+At this point all three objects ``a``, ``b`` and ``c`` share the same buffer.
Using the ``.buffer_info()`` method, we can actually verify that the
bitarrays ``a`` and ``b`` point to the same address:
@@ -97,7 +97,7 @@
... return info[0] # using bitarray 3.7, we can also: info.address
>>> assert address(a) == address(b)
-As bitarray's expose their buffer, we can also directly create a bitarray
+As bitarrays expose their buffer, we can also directly create a bitarray
which imports the buffer from another bitarray:
.. code-block:: python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/canonical.rst
new/bitarray-3.8.2/doc/canonical.rst
--- old/bitarray-3.8.1/doc/canonical.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/canonical.rst 2026-06-17 17:58:51.000000000
+0200
@@ -26,9 +26,9 @@
>>> symbol
['a', 'b', 'r', 'c', 'd']
-The output is tuple with the following elements:
+The output is a tuple with the following elements:
-* A dictionary mapping each symbols to a ``bitarray``
+* A dictionary mapping each symbol to a ``bitarray``
* A list containing the number of symbols for each code length,
e.g. `count[3] = 1` because there is one symbol (``r``) with
code length ``3``.
@@ -65,7 +65,7 @@
bitarray('01011001110011110101100')
>>> assert ''.join(a.decode(codedict)) == msg
-And now decode using not ``codedict``, but the canonical decoding
+And now decode using the canonical decoding
tables ``count`` and ``symbol`` instead:
.. code-block:: python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/changelog.rst
new/bitarray-3.8.2/doc/changelog.rst
--- old/bitarray-3.8.1/doc/changelog.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/changelog.rst 2026-06-17 17:58:51.000000000
+0200
@@ -1,6 +1,13 @@
Change log
==========
+**3.8.2** (2026-06-17):
+
+* clarity/wording improvements throughout project
+* add ``new_allocation()`` to simplify ``resize()``
+* drop Python 3.6 support
+
+
**3.8.1** (2026-04-02):
* fixed critial findings in C Extension Analysis Report, see `#250
<https://github.com/ilanschnell/bitarray/issues/250>`__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/endianness.rst
new/bitarray-3.8.2/doc/endianness.rst
--- old/bitarray-3.8.1/doc/endianness.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/endianness.rst 2026-06-17 17:58:51.000000000
+0200
@@ -6,7 +6,7 @@
or ``.fromfile()``, as well as using ``memoryview()``, the bit-endianness
will have no effect on any computation, and one can skip this section.
-Since bitarrays allows addressing individual bits, where the machine
+Since bitarrays allow addressing individual bits, where the machine
represents 8 bits in one byte, there are two obvious choices for this
mapping: little-endian and big-endian.
@@ -70,7 +70,7 @@
Therefore, it is not possible to perform bitwise operators on bitarrays
with different endianness.
-As mentioned above, the endianness can not be changed once an object is
+As mentioned above, the endianness cannot be changed once an object is
created. However, you can create a new bitarray with different endianness:
.. code-block:: python
@@ -86,7 +86,7 @@
Utility functions
-----------------
-A number of utility functions take into the bit-endianness into account.
+A number of utility functions take the bit-endianness into account.
For example consider:
.. code-block:: python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/random_p.rst
new/bitarray-3.8.2/doc/random_p.rst
--- old/bitarray-3.8.1/doc/random_p.rst 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/doc/random_p.rst 2026-06-17 17:58:51.000000000 +0200
@@ -9,8 +9,8 @@
bitarray(random() < p for _ in range(n))
-While this expression work well for small ``n``, it is quite slow when ``n``
-is large. In the following we focus on the case of ``n`` being large.
+While this expression works well for small ``n``, it is quite slow when ``n``
+is large. In the following we focus on the case of large ``n``.
When ``p`` is small, a fast implementation of ``random_p()`` is to (a)
calculate the population of the bitarray, and then (b) set the required
@@ -19,16 +19,18 @@
need to determine the bitarray's population.
When ``p == 0.5``, we use ``random.getrandbits()`` to initialize our bitarray
-buffer. It should be noted that ``util.urandom()`` uses ``os.urandom()``,
+buffer. It should be noted that ``bitarray.util.urandom()``
+uses ``os.urandom()``,
but since ``util.random_p()`` is designed to give reproducible pseudo-random
-bitarrays, it uses ``getrandbits()``.
+bitarrays, it uses ``random.getrandbits()``.
Taking two (independent) such bitarrays and combining them
using the bitwise AND operation, gives us a random bitarray with
probability 1/4.
-Likewise, taking two bitwise OR operation gives us probability 3/4.
+Likewise, applying a bitwise OR operation to two such bitarrays gives us
+probability 3/4.
Without going into too much further detail, it is possible to combine
-more than two "getrandbits" bitarray to get probabilities ``i / 2**M``,
+more than two "getrandbits" bitarrays to get probabilities ``i / 2**M``,
where ``M`` is the maximal number of "getrandbits" bitarrays we combine,
and ``i`` is an integer.
The required sequence of AND and OR operations is calculated from
@@ -47,9 +49,8 @@
It should be noted that ``x`` is always small (once symmetry is applied in
case of AND) such that it always uses the "small p" case.
-Unlike the combinations, this gives us a bitarray
-with exact probability ``x``. Therefore, the requested probability ``p``
-is exactly obtained.
+Therefore, the bitarray has exactly probability ``x``, and hence
+the requested probability ``p`` is exact.
For more details, see ``VerificationTests`` in the
additional `random tests <../devel/test_random.py>`__.
@@ -57,7 +58,7 @@
Speedup
-------
-The speedup is largest, when the number of number of random numbers our
+The speedup is largest when the number of random numbers our
algorithm uses is smallest.
In the following, let ``k`` be the number of calls to ``getrandbits()``.
For example, when ``p=0.5`` we have ``k=1``.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/reference.rst
new/bitarray-3.8.2/doc/reference.rst
--- old/bitarray-3.8.1/doc/reference.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/reference.rst 2026-06-17 17:58:51.000000000
+0200
@@ -1,7 +1,7 @@
Reference
=========
-bitarray version: 3.8.1 -- `change log
<https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__
+bitarray version: 3.8.2 -- `change log
<https://github.com/ilanschnell/bitarray/blob/master/doc/changelog.rst>`__
In the following, ``item`` and ``value`` are usually a single bit -
an integer 0 or 1.
@@ -25,7 +25,7 @@
``endian``: Specifies the bit-endianness of the created bitarray object.
Allowed values are ``big`` and ``little`` (the default is ``big``).
- The bit-endianness effects the buffer representation of the bitarray.
+ The bit-endianness affects the buffer representation of the bitarray.
``buffer``: Any object which exposes a buffer. When provided,
``initializer``
cannot be present (or has to be ``None``). The imported buffer may be
@@ -120,7 +120,7 @@
``extend(iterable, /)``
- Append items from to the end of the bitarray.
+ Append items from iterable to the end of the bitarray.
If ``iterable`` is a (Unicode) string, each ``0`` and ``1`` are appended as
bits (ignoring whitespace and underscore).
@@ -151,7 +151,7 @@
``fromfile(f, n=-1, /)``
Extend bitarray with up to ``n`` bytes read from file object ``f`` (or any
- other binary stream what supports a ``.read()`` method, e.g.
``io.BytesIO``).
+ other binary stream that supports a ``.read()`` method, e.g.
``io.BytesIO``).
Each read byte will add eight bits to the bitarray. When ``n`` is omitted
or negative, reads and extends all data until EOF.
When ``n`` is non-negative but exceeds the available data, ``EOFError`` is
@@ -171,8 +171,9 @@
``invert(index=<all bits>, /)``
- Invert all bits in bitarray (in-place).
- When the optional ``index`` is given, only invert the single bit at
``index``.
+ Invert bits in-place. When ``index`` is omitted, invert all bits.
+ When ``index`` is an integer, invert the single bit at index.
+ When ``index`` is a slice, invert the selected bits.
New in version 1.5.3: optional index argument
@@ -255,7 +256,7 @@
``unpack(zero=b'\x00', one=b'\x01')`` -> bytes
Return bytes that contain one byte for each bit in the bitarray,
- using specified mapping.
+ using the specified mapping.
bitarray data descriptors:
@@ -330,7 +331,8 @@
``ba2base(n, bitarray, /, group=0, sep=' ')`` -> str
Return a string containing the base ``n`` ASCII representation of
the bitarray. Allowed values for ``n`` are 2, 4, 8, 16, 32 and 64.
- The bitarray has to be multiple of length 1, 2, 3, 4, 5 or 6 respectively.
+ The bitarray has to have a length divisible by 1, 2, 3, 4, 5 or 6
+ respectively.
For ``n=32`` the RFC 4648 Base32 alphabet is used, and for ``n=64`` the
standard base 64 alphabet is used.
When grouped, the string ``sep`` is inserted between groups
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/represent.rst
new/bitarray-3.8.2/doc/represent.rst
--- old/bitarray-3.8.1/doc/represent.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/represent.rst 2026-06-17 17:58:51.000000000
+0200
@@ -9,7 +9,7 @@
Binary representation
---------------------
-The most common representation of bitarrays is its native binary string
+The most common representation of bitarrays is their native binary string
representation, which is great for interactively analyzing bitarray objects:
.. code-block:: python
@@ -22,7 +22,7 @@
'11001'
However, this representation is very large compared to the bitarray object
-itself, and it not efficient for large bitarrays.
+itself, and it is not efficient for large bitarrays.
Byte representation
@@ -69,7 +69,7 @@
only valid values for the header are 0 or 16 (corresponding to a
little-endian and big-endian empty bitarray).
The functions ``serialize()`` and ``deserialize()`` are the recommended and
-fasted way to (de-) serialize bitarray objects to bytes objects (and vice
+fastest way to (de-) serialize bitarray objects to ``bytes`` objects (and vice
versa). The exact format of this representation is guaranteed to not
change in future releases.
@@ -113,7 +113,7 @@
The utility function ``ba2base()`` allows representing bitarrays by
base ``n``, with possible bases 2, 4, 8, 16, 32 and 64.
-The bitarray has to be multiple of length 1, 2, 3, 4, 5 or 6 respectively:
+The bitarray length has to be a multiple of 1, 2, 3, 4, 5 or 6 respectively:
.. code-block:: python
@@ -145,7 +145,7 @@
------------------------------
In some cases, it is useful to represent bitarrays in a binary format that
-is "self terminating" (in the same way that C strings are NUL terminated).
+is "self-terminating" (in the same way that C strings are NUL terminated).
That is, when an encoded bitarray of unknown length is encountered in a
stream of binary data, the format lets us know when the end of the encoded
bitarray is reached.
@@ -157,9 +157,9 @@
Another representation
is `compressed sparse bitarrays <./sparse_compression.rst>`__,
-whose format is also "self terminating". This, format actually uses different
-representations dependent on how sparsely the population of the bitarray (even
-sections of the bitarray) is.
+whose format is also "self-terminating". This format actually uses different
+representations depending on how sparse the bitarray (or even sections of the
+bitarray) is.
For large sparse bitarrays, the format reduces (compresses) the amount of data
very efficiently, while only requiring a very tiny overhead for non-sparsely
populated bitarrays.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/sparse_compression.rst
new/bitarray-3.8.2/doc/sparse_compression.rst
--- old/bitarray-3.8.1/doc/sparse_compression.rst 2026-04-02
17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/doc/sparse_compression.rst 2026-06-17
17:58:51.000000000 +0200
@@ -1,16 +1,17 @@
Compression of sparse bitarrays
===============================
-In a ``bitarray`` object each byte in memory represents eight bits.
+In a ``bitarray`` object, each byte in memory represents eight bits.
While this representation is very compact and efficient when dealing with
most data, there are situations when this representation is inefficient.
-One such situation are sparsely populated bitarray.
-That is, bitarray in which only a few bits are 1, but most bits are 0.
+One such situation is a sparsely populated bitarray.
+That is, a bitarray in which only a few bits are 1, but most bits are 0.
In this situation, one might consider using a data structure which stores
the indices of the 1 bits and not use the ``bitarray`` object at all.
However, having all of bitarray's functionality is very convenient.
-It may be desired to convert ``bitarray`` objects into a more compact (index
-based) format when storing objects on disk or sending them over the network.
+It may be desirable to convert ``bitarray`` objects into a more compact
+(index-based) format when storing objects on disk or sending them over the
+network.
This is the use case of the utility functions ``sc_encode()``
and ``sc_decode()``.
The lower the population count, the more efficient the compression will be:
@@ -31,8 +32,8 @@
------------
Consider a ``bitarray`` of length 256, that is 32 bytes of memory.
-If we represent this object by the indices of 1 bits as one byte each,
-the object will be represent more efficiently when the population (number
+If we represent this object by the indices of 1 bits, using one byte each,
+the object will be represented more efficiently when the population (number
of 1 bits) is less than 32. Based on the population, the
function ``sc_encode()`` chooses to represent the object as either raw bytes
or as bytes of indices of 1 bits. These are the block types 0 and 1.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/doc/variable_length.rst
new/bitarray-3.8.2/doc/variable_length.rst
--- old/bitarray-3.8.1/doc/variable_length.rst 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/doc/variable_length.rst 2026-06-17 17:58:51.000000000
+0200
@@ -2,11 +2,11 @@
===============================
In some cases, it is useful to represent bitarrays in a binary format that
-is "self terminating" (in the same way that C strings are NUL terminated).
+is "self-terminating" (in the same way that C strings are NUL terminated).
That is, when an encoded bitarray of unknown length is encountered in a
stream of binary data, the format lets us know when the end of the encoded
bitarray is reached.
-Such a "variable length format" (most memory efficient for small bitarrays)
+Such a "variable-length format" (most memory-efficient for small bitarrays)
is implemented in ``vl_encode()`` and ``vl_decode()``:
.. code-block:: python
@@ -26,9 +26,9 @@
>>> bytes(stream)
b'other stuff'
-The variable length format is similar to LEB128. A single byte can store
-bitarrays up to 4 element, every additional byte stores up to 7 more elements.
-The most significant bit of each byte indicated whether more bytes follow.
+The variable-length format is similar to LEB128. A single byte can store
+bitarrays up to 4 elements; every additional byte stores up to 7 more elements.
+The most significant bit of each byte indicates whether more bytes follow.
In addition, the first byte contains 3 bits which indicate the number of
padding bits at the end of the stream. Here is an example of
encoding ``bitarray('01010110111001110')``:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/examples/double.py
new/bitarray-3.8.2/examples/double.py
--- old/bitarray-3.8.1/examples/double.py 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/examples/double.py 2026-06-17 17:58:51.000000000
+0200
@@ -77,39 +77,66 @@
from math import pi, inf, nan, isnan
from random import getrandbits, randint
+import re
import unittest
-from bitarray.util import urandom
+from bitarray.util import urandom, gen_primes
EXAMPLES = [
- ( 0.0, "0 00000000000 " + 52 * "0"),
- ( 1.0, "0 01111111111 " + 52 * "0"),
- ( 1.5, "0 01111111111 1" + 51 * "0"),
- ( 2.0, "0 10000000000 " + 52 * "0"),
- ( 5.0, "0 10000000001 01" + 50 * "0"),
- (-5.0, "1 10000000001 01" + 50 * "0"),
+ ( 0.0, "0 00000000000 (52*0)"),
+ ( 1.0, "0 01111111111 (52*0)"),
+ ( 1.5, "0 01111111111 1(51*0)"),
+ ( 2.0, "0 10000000000 (52*0)"),
+ ( 4.0, "0 10000000001 (52*0)"),
+ ( 5.0, "0 10000000001 01(50*0)"),
+ (-5.0, "1 10000000001 01(50*0)"),
# smallest number > 1
- (1.0000000000000002, "0 01111111111 " + 51 * "0" + "1"),
+ (1.0000000000000002, "0 01111111111 (51*0)1"),
# minimal subnormal double
- (4.9406564584124654e-324, "0 00000000000 " + 51 * "0" + "1"),
+ (4.9406564584124654e-324, "0 00000000000 (51*0)1"),
# maximal subnormal double
- (2.2250738585072009e-308, "0 00000000000 " + 52 * "1"),
+ (2.2250738585072009e-308, "0 00000000000 (52*1)"),
# minimal normal double
- (2.2250738585072014e-308, "0 00000000001 " + 52 * "0"),
+ (2.2250738585072014e-308, "0 00000000001 (52*0)"),
# maximal (normal) double
- (1.7976931348623157e+308, "0 11111111110 " + 52 * "1"),
- ( inf, "0 11111111111 " + 52 * "0"),
- (-inf, "1 11111111111 " + 52 * "0"),
- ( 1/3, "0 01111111101 " + 26 * "01"),
+ (1.7976931348623157e+308, "0 11111111110 (52*1)"),
+ ( inf, "0 11111111111 (52*0)"),
+ (-inf, "1 11111111111 (52*0)"),
+ ( 1/2, "0 01111111110 (52*0)"),
+ ( 1/3, "0 01111111101 (26*01)"),
+ ( 1/4, "0 01111111101 (52*0)"),
( pi, "0 10000000000 "
"1001001000011111101101010100010001000010110100011000"),
# largest number exactly representated as integer
- (2 ** 53 - 1, "0 10000110011 " + 52 * "1"),
+ (2 ** 53 - 1, "0 10000110011 (52*1)"),
]
+def expand_str(s):
+ pat = re.compile(r"""
+ \(
+ (\d+) # multiplier
+ \* # literal *
+ ([01]+) # bit string
+ \)""", re.X)
+
+ def repl(match):
+ return int(match.group(1)) * match.group(2)
+
+ return pat.sub(repl, s)
+
+
class DoubleTests(unittest.TestCase):
+ def test_expand_str(self):
+ for s, res in [
+ ("(0*0)(0*1)", ""),
+ ("(1*1)(1*0)", "10"),
+ ("(3*1100)", "110011001100"),
+ ("(2*10) (3*1)", "1010 111"),
+ ]:
+ self.assertEqual(expand_str(s), res)
+
def test_zero(self):
d = Double()
self.assertEqual(float(d), 0.0)
@@ -119,10 +146,18 @@
def test_examples(self):
for x, s in EXAMPLES:
+ s = expand_str(s)
for d in Double(x), Double(s):
self.assertEqual(float(d), x)
self.assertEqual(str(d), s)
+ def test_numberphile(self):
+ # https://www.youtube.com/watch?v=c066hLi78B0
+ d = Double(0.41468_25098_51111_66024)
+ self.assertEqual(d.sign, 0)
+ self.assertEqual(d.exponent, -2)
+ self.assertEqual(d.fraction[::-1], gen_primes(55)[3:])
+
def test_nan(self):
s = "0 11111111111 1" + 51 * "0"
for x in nan, s:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/examples/puff/_puff.c
new/bitarray-3.8.2/examples/puff/_puff.c
--- old/bitarray-3.8.1/examples/puff/_puff.c 2026-04-02 17:13:02.000000000
+0200
+++ new/bitarray-3.8.2/examples/puff/_puff.c 2026-06-17 17:58:51.000000000
+0200
@@ -3,7 +3,7 @@
https://github.com/madler/zlib/blob/master/contrib/puff
- This is Marks's copyright notice:
+ This is Mark's copyright notice:
Copyright (C) 2002-2013 Mark Adler, all rights reserved
version 2.3, 21 Jan 2013
@@ -32,7 +32,7 @@
#define MAXBITS 15 /* maximum bits in a code */
#define MAXLCODES 286 /* maximum number of literal/length codes */
#define MAXDCODES 30 /* maximum number of distance codes */
-#define MAXCODES (MAXLCODES + MAXDCODES) /* maximum codes lengths to read */
+#define MAXCODES (MAXLCODES + MAXDCODES) /* maximum code lengths to read */
#define FIXLCODES 288 /* number of fixed literal/length codes */
@@ -228,7 +228,6 @@
return -1;
if (symbol < 256) { /* literal: symbol is the byte */
- /* write out the literal */
if (append_byte(s, symbol) < 0)
return -1;
}
@@ -266,7 +265,7 @@
/* set during module init */
static PyTypeObject *bitarray_type;
-/* create a new initialized canonical Huffman decode iterator object */
+/* create a new initialized State object */
static PyObject *
state_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
@@ -392,7 +391,7 @@
return PyErr_Format(PyExc_ValueError, \
"size of length list too large: %zd > %d", n, maxcodes)
-/* given the liter/lengths and distance lengths as one big list,
+/* given the literal/lengths and distance lengths as one big list,
decode literal/length and distance codes until an end-of-block code */
static PyObject *
state_decode_block(state_obj *self, PyObject *args)
@@ -466,7 +465,7 @@
}
/* given the code length code lengths (always 19 of them),
- decode the liter/lengths and distance lengths into one big list */
+ decode the literal/lengths and distance lengths into one big list */
static PyObject *
state_decode_lengths(state_obj *self, PyObject *args)
{
@@ -511,7 +510,7 @@
lengths[index++] = symbol;
else { /* repeat instruction */
int len = 0; /* last length to repeat, assume repeating zeros */
- int n; /* time to repeat last length */
+ int n; /* number of time to repeat last length */
if (symbol == 16) { /* repeat last length 3..6 times */
if (index == 0) {
@@ -544,9 +543,9 @@
return list_from_shorts(lengths, ncode);
}
-/* copy 'len' bytes starting at 'dist' bytes ago in self->out,
- if the count 'len' exceeds the distance 'dist, then some of the output
- data will be a copy of data that was copied earlier in the process */
+/* Copy 'len' bytes starting at 'dist' bytes ago in self->out.
+ If the count 'len' exceeds the distance 'dist, then some of the output
+ data will be a copy of data that was copied earlier in the process. */
static PyObject *
state_copy(state_obj *self, PyObject *args)
{
@@ -607,6 +606,8 @@
static void
state_dealloc(state_obj *self)
{
+ Py_DECREF(self->in);
+ Py_DECREF(self->out);
Py_TYPE(self)->tp_free((PyObject *) self);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/bitarray-3.8.1/setup.py new/bitarray-3.8.2/setup.py
--- old/bitarray-3.8.1/setup.py 2026-04-02 17:13:02.000000000 +0200
+++ new/bitarray-3.8.2/setup.py 2026-06-17 17:58:51.000000000 +0200
@@ -3,10 +3,10 @@
import platform
-if sys.version_info[:3] < (3, 6, 1):
+if sys.version_info[:3] < (3, 7):
sys.exit("""\
****************************************************************************
-* bitarray requires Python 3.6.1 or later.
+* bitarray requires Python 3.7 or later.
* The last bitarray version supporting Python 2.7 is bitarray 2.9.3.
****************************************************************************
""")
@@ -47,7 +47,6 @@
"Operating System :: OS Independent",
"Programming Language :: C",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",