Skip to content

Commit bb68dbe

Browse files
authored
Merge pull request #2095 from minrk/314
test on CPython 3.14-pre
2 parents 27abf26 + 61ad88d commit bb68dbe

File tree

2 files changed

+44
-46
lines changed

2 files changed

+44
-46
lines changed

.github/workflows/test.yml

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,12 @@ concurrency:
2525

2626
env:
2727
FORCE_COLOR: "1"
28-
# only affects Windows, but easiest to set here for now
29-
SETUPTOOLS_ENABLE_FEATURES: "legacy-editable"
3028

3129
jobs:
3230
test:
3331
runs-on: ${{ matrix.os }}
3432
timeout-minutes: 20
35-
continue-on-error: ${{ matrix.zmq == 'head' }}
33+
continue-on-error: ${{ matrix.zmq == 'head' || matrix.python == '3.14' }}
3634

3735
env:
3836
MACOSX_DEPLOYMENT_TARGET: "13.7"
@@ -44,10 +42,6 @@ jobs:
4442
- os: macos-13
4543
python: "3.8"
4644

47-
- os: macos-14
48-
python: "3.12"
49-
zmq: bundled
50-
5145
- os: macos-14
5246
python: "3.13"
5347
zmq: bundled
@@ -70,7 +64,6 @@ jobs:
7064

7165
- os: ubuntu-22.04
7266
python: "3.9"
73-
tornado: head
7467

7568
- os: ubuntu-22.04
7669
python: "3.10"
@@ -81,6 +74,7 @@ jobs:
8174

8275
- os: ubuntu-24.04
8376
python: "3.12"
77+
tornado: head
8478

8579
- os: ubuntu-24.04
8680
python: "3.13"
@@ -93,6 +87,13 @@ jobs:
9387
python: "3.13"
9488
free_threading: free_threading
9589

90+
- os: ubuntu-24.04
91+
python: "3.14"
92+
93+
- os: ubuntu-24.04
94+
python: "3.14"
95+
free_threading: free_threading
96+
9697
- os: windows-2022
9798
python: "3.8"
9899
arch: x86
@@ -110,43 +111,26 @@ jobs:
110111

111112
- name: setup python
112113
uses: actions/setup-python@v5
113-
if: ${{ !matrix.free_threading }}
114114
with:
115115
python-version: ${{ matrix.python }}
116116
architecture: ${{ matrix.arch || 'x64' }}
117117
# allows us to use '3.12' and get '-dev' while we wait
118118
allow-prereleases: true
119+
freethreaded: ${{ matrix.free_threading == 'free_threading' }}
120+
check-latest: ${{ matrix.python == '3.14' }}
119121
cache: pip
120122

121-
- name: setup python (free threading)
122-
if: ${{ matrix.free_threading }}
123-
uses: mamba-org/setup-micromamba@v2
124-
with:
125-
environment-name: nogil
126-
condarc: |
127-
channels:
128-
- ad-testing/label/py313_nogil
129-
- defaults
130-
create-args: >-
131-
python=${{ matrix.python-version }}
132-
pip
133-
134-
- name: activate python (free threading)
123+
- name: setup free threading
135124
if: ${{ matrix.free_threading }}
136-
# light activate, just add env to path
137-
# run this in micromamba-shell
138-
# so we don't have to for the rest
139125
run: |
140-
echo $PATH
141-
echo "PATH=$PATH" >> "$GITHUB_ENV"
142126
echo "PYTHON_GIL=0" >> "$GITHUB_ENV"
143127
# need prerelease Cython until 3.1 is out
144128
echo "PIP_PRE=1" >> "$GITHUB_ENV"
145129
echo "PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" >> "$GITHUB_ENV"
146-
shell: micromamba-shell {0}
130+
echo "EXTRA_PIP=--no-binary coverage" >> "$GITHUB_ENV"
147131
148132
- name: setup coverage
149-
if: startsWith(matrix.python, 'pypy') || startsWith(matrix.python, '3.12')
133+
if: startsWith(matrix.python, 'pypy') || startsWith(matrix.python, '3.14')
150134
run: |
151135
grep -v plugins .coveragerc > .coveragerc-save
152136
mv .coveragerc-save .coveragerc
@@ -159,7 +143,7 @@ jobs:
159143
- name: install dependencies
160144
run: |
161145
pip install --upgrade pip wheel
162-
pip install -r test-requirements.txt
146+
pip install ${EXTRA_PIP:-} -r test-requirements.txt
163147
164148
- name: remove tornado
165149
if: matrix.tornado == 'none'

tests/test_message.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import copy
66
import gc
7-
import sys
87

98
try:
109
from sys import getrefcount
@@ -18,6 +17,7 @@
1817
import pytest
1918

2019
import zmq
20+
from zmq.utils.garbage import gc as zmq_gc
2121
from zmq_test_utils import PYPY, BaseZMQTestCase, SkipTest, skip_cpython_cffi, skip_pypy
2222

2323
# some useful constants:
@@ -30,40 +30,52 @@
3030
view_rc = grc(x) - rc0
3131

3232

33-
def await_gc(obj, rc):
34-
"""wait for refcount on an object to drop to an expected value
33+
def await_gc(gc_key):
34+
"""wait for zmq garbage collection
3535
3636
Necessary because of the zero-copy gc thread,
3737
which can take some time to receive its DECREF message.
3838
"""
39-
# count refs for this function
40-
if sys.version_info < (3, 11):
41-
my_refs = 2
42-
else:
43-
my_refs = 1
44-
for i in range(50):
45-
# rc + 2 because of the refs in this function
46-
if grc(obj) <= rc + my_refs:
39+
deadline = time.monotonic() + 3
40+
gc.collect()
41+
while time.monotonic() < deadline:
42+
if gc_key in zmq_gc.refs:
43+
time.sleep(0.05)
44+
else:
45+
gc.collect()
4746
return
48-
time.sleep(0.05)
47+
raise TimeoutError("gc not collected")
4948

5049

5150
class TestFrame(BaseZMQTestCase):
51+
def setUp(self):
52+
super().setUp()
53+
# make sure we are starting clean
54+
assert not zmq_gc.refs
55+
5256
def tearDown(self):
5357
super().tearDown()
5458
for i in range(3):
5559
gc.collect()
5660

61+
deadline = time.monotonic() + 3
62+
while zmq_gc.refs and time.monotonic() < deadline:
63+
time.sleep(0.05)
64+
65+
# make sure we left no refs
66+
assert not zmq_gc.refs
67+
5768
@skip_pypy
5869
def test_above_30(self):
5970
"""Message above 30 bytes are never copied by 0MQ."""
6071
for i in range(5, 16): # 32, 64,..., 65536
6172
s = (2**i) * x
6273
rc = grc(s)
6374
m = zmq.Frame(s, copy=False)
75+
_gc_ref = next(iter(zmq_gc.refs))
6476
assert grc(s) == rc + 2
6577
del m
66-
await_gc(s, rc)
78+
await_gc(_gc_ref)
6779
assert grc(s) == rc
6880
del s
6981

@@ -116,6 +128,7 @@ def test_lifecycle1(self):
116128
s = (2**i) * x
117129
rc = rc_0 = grc(s)
118130
m = zmq.Frame(s, copy=False)
131+
_gc_ref = next(iter(zmq_gc.refs))
119132
rc += 2
120133
assert grc(s) == rc
121134
m2 = copy.copy(m)
@@ -137,7 +150,7 @@ def test_lifecycle1(self):
137150
assert grc(s) == rc
138151
del m
139152
rc -= 2
140-
await_gc(s, rc)
153+
await_gc(_gc_ref)
141154
assert grc(s) == rc
142155
assert rc == rc_0
143156
del s
@@ -149,6 +162,7 @@ def test_lifecycle2(self):
149162
s = (2**i) * x
150163
rc = rc_0 = grc(s)
151164
m = zmq.Frame(s, copy=False)
165+
_gc_ref = next(iter(zmq_gc.refs))
152166
rc += 2
153167
assert grc(s) == rc
154168
m2 = copy.copy(m)
@@ -169,7 +183,7 @@ def test_lifecycle2(self):
169183
assert grc(s) == rc
170184
del m2
171185
rc -= 2
172-
await_gc(s, rc)
186+
await_gc(_gc_ref)
173187
assert grc(s) == rc
174188
assert rc == rc_0
175189
del s

0 commit comments

Comments
 (0)