Skip to content

Commit 3b07395

Browse files
authored
Fix Cython3 compatibility (#97)
* Extend tox environments to test new/old Cythons * Compatibility changes for Cython 3 - Change __check_compatibility to _check_compatability, as Cython3 mangles names starting with __ in inherited classes like Python - Explicitly declare noexcept in relevant type signatures so that we don't need the legacy_implicit_noexcept directive. - This should still be compatible with Cython <3 * Run all default tox environments in CI * Build wheels for test_wheel using python -m build
1 parent 7e46a67 commit 3b07395

File tree

4 files changed

+39
-22
lines changed

4 files changed

+39
-22
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ jobs:
2828
env:
2929
HYPOTHESIS_PROFILE: ci
3030
run: |
31-
tox -e test
31+
tox

pyroaring/abstract_bitmap.pxi

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ cdef class AbstractBitMap:
8282
BitMap([1, 27, 123456789])
8383
"""
8484

85-
cdef from_ptr(self, croaring.roaring_bitmap_t *ptr):
85+
cdef from_ptr(self, croaring.roaring_bitmap_t *ptr) noexcept:
8686
"""
8787
Return an instance of AbstractBitMap (or one of its subclasses) initialized with the given pointer.
8888
@@ -115,7 +115,7 @@ cdef class AbstractBitMap:
115115
if self._c_bitmap is not NULL:
116116
croaring.roaring_bitmap_free(self._c_bitmap)
117117

118-
def __check_compatibility(self, AbstractBitMap other):
118+
def _check_compatibility(self, AbstractBitMap other):
119119
if self.copy_on_write != other.copy_on_write:
120120
raise ValueError('Cannot have interactions between bitmaps with and without copy_on_write.\n')
121121

@@ -129,7 +129,7 @@ cdef class AbstractBitMap:
129129
return croaring.roaring_bitmap_get_cardinality(self._c_bitmap)
130130

131131
def __richcmp__(self, other, int op):
132-
self.__check_compatibility(other)
132+
self._check_compatibility(other)
133133
if op == 0: # <
134134
return croaring.roaring_bitmap_is_strict_subset((<AbstractBitMap?>self)._c_bitmap, (<AbstractBitMap?>other)._c_bitmap)
135135
elif op == 1: # <=
@@ -414,7 +414,7 @@ cdef class AbstractBitMap:
414414
return bitmaps[0] | bitmaps[1]
415415
else:
416416
for bm in bitmaps:
417-
bitmaps[0].__check_compatibility(bm)
417+
bitmaps[0]._check_compatibility(bm)
418418
buff.push_back(bm._c_bitmap)
419419
result = croaring.roaring_bitmap_or_many(size, &buff[0])
420420
return (<AbstractBitMap>bitmaps[0].__class__()).from_ptr(result) # FIXME to change when from_ptr is a classmethod
@@ -438,21 +438,24 @@ cdef class AbstractBitMap:
438438
result &= bm
439439
return bitmaps[0].__class__(result)
440440

441-
cdef binary_op(self, AbstractBitMap other, (croaring.roaring_bitmap_t*)func(const croaring.roaring_bitmap_t*, const croaring.roaring_bitmap_t*)):
442-
self.__check_compatibility(other)
441+
cdef binary_op(self, AbstractBitMap other, (croaring.roaring_bitmap_t*)func(const croaring.roaring_bitmap_t*, const croaring.roaring_bitmap_t*) noexcept) noexcept:
443442
cdef croaring.roaring_bitmap_t *r = func(self._c_bitmap, other._c_bitmap)
444443
return self.from_ptr(r)
445444

446445
def __or__(self, other):
446+
self._check_compatibility(other)
447447
return (<AbstractBitMap>self).binary_op(<AbstractBitMap?>other, croaring.roaring_bitmap_or)
448448

449449
def __and__(self, other):
450+
self._check_compatibility(other)
450451
return (<AbstractBitMap>self).binary_op(<AbstractBitMap?>other, croaring.roaring_bitmap_and)
451452

452453
def __xor__(self, other):
454+
self._check_compatibility(other)
453455
return (<AbstractBitMap>self).binary_op(<AbstractBitMap?>other, croaring.roaring_bitmap_xor)
454456

455457
def __sub__(self, other):
458+
self._check_compatibility(other)
456459
return (<AbstractBitMap>self).binary_op(<AbstractBitMap?>other, croaring.roaring_bitmap_andnot)
457460

458461
def union_cardinality(self, AbstractBitMap other):
@@ -464,7 +467,7 @@ cdef class AbstractBitMap:
464467
>>> BitMap([3, 12]).union_cardinality(AbstractBitMap([3, 5, 8]))
465468
4
466469
"""
467-
self.__check_compatibility(other)
470+
self._check_compatibility(other)
468471
return croaring.roaring_bitmap_or_cardinality(self._c_bitmap, other._c_bitmap)
469472

470473
def intersection_cardinality(self, AbstractBitMap other):
@@ -476,7 +479,7 @@ cdef class AbstractBitMap:
476479
>>> BitMap([3, 12]).intersection_cardinality(BitMap([3, 5, 8]))
477480
1
478481
"""
479-
self.__check_compatibility(other)
482+
self._check_compatibility(other)
480483
return croaring.roaring_bitmap_and_cardinality(self._c_bitmap, other._c_bitmap)
481484

482485
def difference_cardinality(self, AbstractBitMap other):
@@ -488,7 +491,7 @@ cdef class AbstractBitMap:
488491
>>> BitMap([3, 12]).difference_cardinality(BitMap([3, 5, 8]))
489492
1
490493
"""
491-
self.__check_compatibility(other)
494+
self._check_compatibility(other)
492495
return croaring.roaring_bitmap_andnot_cardinality(self._c_bitmap, other._c_bitmap)
493496

494497
def symmetric_difference_cardinality(self, AbstractBitMap other):
@@ -500,7 +503,7 @@ cdef class AbstractBitMap:
500503
>>> BitMap([3, 12]).symmetric_difference_cardinality(BitMap([3, 5, 8]))
501504
3
502505
"""
503-
self.__check_compatibility(other)
506+
self._check_compatibility(other)
504507
return croaring.roaring_bitmap_xor_cardinality(self._c_bitmap, other._c_bitmap)
505508

506509
def intersect(self, AbstractBitMap other):
@@ -514,7 +517,7 @@ cdef class AbstractBitMap:
514517
>>> BitMap([3, 12]).intersect(BitMap([5, 18]))
515518
False
516519
"""
517-
self.__check_compatibility(other)
520+
self._check_compatibility(other)
518521
return croaring.roaring_bitmap_intersect(self._c_bitmap, other._c_bitmap)
519522

520523
def jaccard_index(self, AbstractBitMap other):
@@ -527,7 +530,7 @@ cdef class AbstractBitMap:
527530
>>> BitMap([3, 10, 12]).jaccard_index(BitMap([3, 18]))
528531
0.25
529532
"""
530-
self.__check_compatibility(other)
533+
self._check_compatibility(other)
531534
return croaring.roaring_bitmap_jaccard_index(self._c_bitmap, other._c_bitmap)
532535

533536
def get_statistics(self):

pyroaring/bitmap.pxi

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,21 +106,24 @@ cdef class BitMap(AbstractBitMap):
106106
if not test:
107107
raise KeyError(value)
108108

109-
cdef binary_iop(self, AbstractBitMap other, (void)func(croaring.roaring_bitmap_t*, const croaring.roaring_bitmap_t*)):
110-
self.__check_compatibility(other)
109+
cdef binary_iop(self, AbstractBitMap other, (void)func(croaring.roaring_bitmap_t*, const croaring.roaring_bitmap_t*) noexcept) noexcept:
111110
func(self._c_bitmap, other._c_bitmap)
112111
return self
113112

114113
def __ior__(self, other):
114+
self._check_compatibility(other)
115115
return (<BitMap>self).binary_iop(<AbstractBitMap?>other, croaring.roaring_bitmap_or_inplace)
116116

117117
def __iand__(self, other):
118+
self._check_compatibility(other)
118119
return (<BitMap>self).binary_iop(<AbstractBitMap?>other, croaring.roaring_bitmap_and_inplace)
119120

120121
def __ixor__(self, other):
122+
self._check_compatibility(other)
121123
return (<BitMap>self).binary_iop(<AbstractBitMap?>other, croaring.roaring_bitmap_xor_inplace)
122124

123125
def __isub__(self, other):
126+
self._check_compatibility(other)
124127
return (<BitMap>self).binary_iop(<AbstractBitMap?>other, croaring.roaring_bitmap_andnot_inplace)
125128

126129
def intersection_update(self, *all_values): # FIXME could be more efficient

tox.ini

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
[tox]
22
envlist =
3-
test
3+
cython_pre3
4+
cython3
45
test_wheel
56

67

7-
[testenv:test]
8+
[testenv:cython_pre3]
89
deps =
910
hypothesis
11+
cython<3.0.0
12+
passenv =
13+
HYPOTHESIS_PROFILE
14+
commands =
15+
python test.py
16+
python cydoctest.py
17+
18+
19+
[testenv:cython3]
20+
deps =
21+
hypothesis
22+
cython>=3.0.2
1023
passenv =
1124
HYPOTHESIS_PROFILE
1225
commands =
@@ -18,6 +31,7 @@ commands =
1831
deps =
1932
hypothesis
2033
wheel
34+
build
2135
twine
2236
skip_sdist = true
2337
skip_install = true
@@ -28,12 +42,9 @@ allowlist_externals =
2842
mkdir
2943
commands =
3044
# Clear our prebuilt wheels so we have a fresh directory
31-
- mkdir wheel
32-
- rm wheel/*
33-
# Build the wheel into the cleaned directory
34-
pip wheel . -w wheel
45+
python -m build
3546
# Install from the wheel in that directory
36-
pip install --only-binary ":all:" --find-links=wheel pyroaring
47+
pip install --only-binary ":all:" --find-links=dist --no-index pyroaring
3748
python test.py
3849
python cydoctest.py
3950

0 commit comments

Comments
 (0)