Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a4e81e7

Browse files
authored
Merge pull request #20848 from QuLogic/pypy
FIX: PyPy wheels and tests
2 parents af1c95f + e9fbe9f commit a4e81e7

11 files changed

+66
-14
lines changed

.github/workflows/cibuildwheel.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747

4848
- name: Install cibuildwheel
4949
run: |
50-
python -m pip install cibuildwheel==1.9.0
50+
python -m pip install cibuildwheel==2.1.1
5151
5252
- name: Build minimum NumPy for aarch64
5353
if: matrix.cibw_archs == 'aarch64' && steps.numpy-cache.outputs.cache-hit != 'true'
@@ -93,7 +93,7 @@ jobs:
9393
CIBW_BUILD: "pp37-*"
9494
CIBW_BEFORE_BUILD: pip install certifi numpy==${{ env.min-numpy-version }}
9595
CIBW_ARCHS: ${{ matrix.cibw_archs }}
96-
if: runner.os != 'Windows' && matrix.cibw_archs != 'aarch64'
96+
if: matrix.cibw_archs != 'aarch64'
9797

9898
- name: Validate that LICENSE files are included in wheels
9999
run: |

lib/matplotlib/backend_bases.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,14 +1618,20 @@ def wrapper(*args, **kwargs):
16181618
if frame is None:
16191619
# when called in embedded context may hit frame is None.
16201620
break
1621+
# Work around sphinx-gallery not setting __name__.
1622+
frame_name = frame.f_globals.get('__name__', '')
16211623
if re.match(r'\A(matplotlib|mpl_toolkits)(\Z|\.(?!tests\.))',
1622-
# Work around sphinx-gallery not setting __name__.
1623-
frame.f_globals.get('__name__', '')):
1624-
if public_api.match(frame.f_code.co_name):
1625-
name = frame.f_code.co_name
1624+
frame_name):
1625+
name = frame.f_code.co_name
1626+
if public_api.match(name):
16261627
if name in ('print_figure', '_no_output_draw'):
16271628
seen_print_figure = True
16281629

1630+
elif frame_name == '_functools':
1631+
# PyPy adds an extra frame without module prefix for this
1632+
# functools wrapper, which we ignore to assume we're still in
1633+
# Matplotlib code.
1634+
continue
16291635
else:
16301636
break
16311637

lib/matplotlib/patches.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,8 @@ def _make_verts(self):
14511451

14521452

14531453
docstring.interpd.update(
1454-
FancyArrow="\n".join(inspect.getdoc(FancyArrow.__init__).splitlines()[2:]))
1454+
FancyArrow="\n".join(
1455+
(inspect.getdoc(FancyArrow.__init__) or "").splitlines()[2:]))
14551456

14561457

14571458
class CirclePolygon(RegularPolygon):

lib/matplotlib/scale.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,11 @@ def _get_scale_docs():
620620
"""
621621
docs = []
622622
for name, scale_class in _scale_mapping.items():
623+
docstring = inspect.getdoc(scale_class.__init__) or ""
623624
docs.extend([
624625
f" {name!r}",
625626
"",
626-
textwrap.indent(inspect.getdoc(scale_class.__init__), " " * 8),
627+
textwrap.indent(docstring, " " * 8),
627628
""
628629
])
629630
return "\n".join(docs)

lib/matplotlib/tests/test_animation.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import gc
21
import os
32
from pathlib import Path
3+
import platform
44
import subprocess
55
import sys
66
import weakref
@@ -87,10 +87,15 @@ def test_null_movie_writer(anim):
8787

8888
@pytest.mark.parametrize('anim', [dict(klass=dict)], indirect=['anim'])
8989
def test_animation_delete(anim):
90+
if platform.python_implementation() == 'PyPy':
91+
# Something in the test setup fixture lingers around into the test and
92+
# breaks pytest.warns on PyPy. This garbage collection fixes it.
93+
# https://foss.heptapod.net/pypy/pypy/-/issues/3536
94+
np.testing.break_cycles()
9095
anim = animation.FuncAnimation(**anim)
9196
with pytest.warns(Warning, match='Animation was deleted'):
9297
del anim
93-
gc.collect()
98+
np.testing.break_cycles()
9499

95100

96101
def test_movie_writer_dpi_default():
@@ -201,6 +206,11 @@ def test_save_animation_smoketest(tmpdir, writer, frame_format, output, anim):
201206
])
202207
@pytest.mark.parametrize('anim', [dict(klass=dict)], indirect=['anim'])
203208
def test_animation_repr_html(writer, html, want, anim):
209+
if platform.python_implementation() == 'PyPy':
210+
# Something in the test setup fixture lingers around into the test and
211+
# breaks pytest.warns on PyPy. This garbage collection fixes it.
212+
# https://foss.heptapod.net/pypy/pypy/-/issues/3536
213+
np.testing.break_cycles()
204214
if (writer == 'imagemagick' and html == 'html5'
205215
# ImageMagick delegates to ffmpeg for this format.
206216
and not animation.FFMpegWriter.isAvailable()):
@@ -214,7 +224,8 @@ def test_animation_repr_html(writer, html, want, anim):
214224
if want is None:
215225
assert html is None
216226
with pytest.warns(UserWarning):
217-
del anim # Animtion was never run, so will warn on cleanup.
227+
del anim # Animation was never run, so will warn on cleanup.
228+
np.testing.break_cycles()
218229
else:
219230
assert want in html
220231

@@ -324,6 +335,7 @@ def frames_generator():
324335
writer = NullMovieWriter()
325336
anim.save('unused.null', writer=writer)
326337
assert len(frames_generated) == 5
338+
np.testing.break_cycles()
327339
for f in frames_generated:
328340
# If cache_frame_data is True, then the weakref should be alive;
329341
# if cache_frame_data is False, then the weakref should be dead (None).

lib/matplotlib/tests/test_backend_tk.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import functools
22
import inspect
33
import os
4+
import platform
45
import re
56
import subprocess
67
import sys
@@ -111,6 +112,9 @@ def legitimate_quit():
111112
print("success")
112113

113114

115+
@pytest.mark.skipif(platform.python_implementation() != 'CPython',
116+
reason='PyPy does not support Tkinter threading: '
117+
'https://foss.heptapod.net/pypy/pypy/-/issues/1929')
114118
@pytest.mark.backend('TkAgg', skip_on_importerror=True)
115119
@pytest.mark.flaky(reruns=3)
116120
@_isolated_tk_test(success_count=1)

lib/matplotlib/tests/test_backends_interactive.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import inspect
44
import json
55
import os
6+
import platform
67
import signal
78
import subprocess
89
import sys
@@ -220,6 +221,12 @@ def _test_thread_impl():
220221
elif param.values[0].get("QT_API") == "PySide2":
221222
param.marks.append(
222223
pytest.mark.xfail(raises=subprocess.CalledProcessError))
224+
elif backend == "tkagg" and platform.python_implementation() != 'CPython':
225+
param.marks.append(
226+
pytest.mark.xfail(
227+
reason='PyPy does not support Tkinter threading: '
228+
'https://foss.heptapod.net/pypy/pypy/-/issues/1929',
229+
strict=True))
223230

224231

225232
@pytest.mark.parametrize("env", _thread_safe_backends)

lib/matplotlib/tests/test_cbook.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,13 @@ def count(self):
198198
return count1
199199

200200
def is_empty(self):
201+
np.testing.break_cycles()
201202
assert self.callbacks._func_cid_map == {}
202203
assert self.callbacks.callbacks == {}
203204
assert self.callbacks._pickled_cids == set()
204205

205206
def is_not_empty(self):
207+
np.testing.break_cycles()
206208
assert self.callbacks._func_cid_map != {}
207209
assert self.callbacks.callbacks != {}
208210

lib/matplotlib/tests/test_quiver.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import platform
2+
import sys
3+
14
import numpy as np
25
import pytest
3-
import sys
6+
47
from matplotlib import pyplot as plt
58
from matplotlib.testing.decorators import image_comparison
69

@@ -15,6 +18,8 @@ def draw_quiver(ax, **kw):
1518
return Q
1619

1720

21+
@pytest.mark.skipif(platform.python_implementation() != 'CPython',
22+
reason='Requires CPython')
1823
def test_quiver_memory_leak():
1924
fig, ax = plt.subplots()
2025

@@ -27,6 +32,8 @@ def test_quiver_memory_leak():
2732
assert sys.getrefcount(ttX) == 2
2833

2934

35+
@pytest.mark.skipif(platform.python_implementation() != 'CPython',
36+
reason='Requires CPython')
3037
def test_quiver_key_memory_leak():
3138
fig, ax = plt.subplots()
3239

lib/matplotlib/tests/test_style.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from contextlib import contextmanager
2-
import gc
32
from pathlib import Path
43
from tempfile import TemporaryDirectory
54
import sys
65

6+
import numpy as np
77
import pytest
88

99
import matplotlib as mpl
@@ -165,7 +165,7 @@ def test_xkcd_no_cm():
165165
assert mpl.rcParams["path.sketch"] is None
166166
plt.xkcd()
167167
assert mpl.rcParams["path.sketch"] == (1, 100, 2)
168-
gc.collect()
168+
np.testing.break_cycles()
169169
assert mpl.rcParams["path.sketch"] == (1, 100, 2)
170170

171171

src/_c_internal_utils.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@ mpl_GetCurrentProcessExplicitAppUserModelID(PyObject* module)
6868
wchar_t* appid = NULL;
6969
HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
7070
if (FAILED(hr)) {
71+
#if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x07030600
72+
/* Remove when we require PyPy 7.3.6 */
73+
PyErr_SetFromWindowsErr(hr);
74+
return NULL;
75+
#else
7176
return PyErr_SetFromWindowsErr(hr);
77+
#endif
7278
}
7379
PyObject* py_appid = PyUnicode_FromWideChar(appid, -1);
7480
CoTaskMemFree(appid);
@@ -89,7 +95,13 @@ mpl_SetCurrentProcessExplicitAppUserModelID(PyObject* module, PyObject* arg)
8995
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
9096
PyMem_Free(appid);
9197
if (FAILED(hr)) {
98+
#if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x07030600
99+
/* Remove when we require PyPy 7.3.6 */
100+
PyErr_SetFromWindowsErr(hr);
101+
return NULL;
102+
#else
92103
return PyErr_SetFromWindowsErr(hr);
104+
#endif
93105
}
94106
Py_RETURN_NONE;
95107
#else

0 commit comments

Comments
 (0)