Author: Alexander Schremmer <alex AT alexanderweb DOT de> Branch: math-improvements Changeset: r95783:b17fec9f72db Date: 2019-02-04 11:13 +0100 http://bitbucket.org/pypy/pypy/changeset/b17fec9f72db/
Log: Merge default into math-improvements. diff too long, truncating to 2000 out of 13722 lines diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -30,7 +30,7 @@ DEALINGS IN THE SOFTWARE. -PyPy Copyright holders 2003-2018 +PyPy Copyright holders 2003-2019 -------------------------------- Except when otherwise stated (look for LICENSE files or information at @@ -40,16 +40,16 @@ Armin Rigo Maciej Fijalkowski Carl Friedrich Bolz-Tereick + Antonio Cuni Amaury Forgeot d'Arc - Antonio Cuni Matti Picus Samuele Pedroni Ronan Lamy Alex Gaynor Philip Jenvey + Richard Plangger Brian Kearns - Richard Plangger - Michael Hudson + Michael Hudson-Doyle Manuel Jacob David Schneider Holger Krekel @@ -59,8 +59,8 @@ Anders Chrigstrom Wim Lavrijsen Eric van Riet Paap + Remi Meier Richard Emslie - Remi Meier Alexander Schremmer Dan Villiom Podlaski Christiansen Lukas Diekmann @@ -70,10 +70,10 @@ Niklaus Haldimann Camillo Bruni Laura Creighton - Romain Guillebert Toon Verwaest Leonardo Santagada Seo Sanghyeon + Romain Guillebert Ronny Pfannschmidt Justin Peel Raffael Tfirst @@ -114,12 +114,12 @@ Squeaky Edd Barrett Timo Paulssen + Laurence Tratt Marius Gedminas Nicolas Truessel Alexandre Fayolle Simon Burton Martin Matusiak - Laurence Tratt Wenzhu Man Konstantin Lopuhin John Witulski @@ -134,8 +134,9 @@ Jean-Philippe St. Pierre Guido van Rossum Pavel Vinogradov + Stefan Beyer + William Leslie Paweł Piotr Przeradowski - William Leslie marky1991 Ilya Osadchiy Tobias Oberstein @@ -144,10 +145,10 @@ Taavi Burns Adrian Kuhn tav + Stian Andreassen Georg Brandl Joannah Nanjekye Bert Freudenberg - Stian Andreassen Wanja Saatkamp Mike Blume Gerald Klix @@ -163,6 +164,7 @@ Vasily Kuznetsov Preston Timmons David Ripton + Pieter Zieschang Dusty Phillips Lukas Renggli Guenter Jantzen @@ -176,6 +178,7 @@ Andrew Durdin Ben Young Michael Schneider + Yusuke Tsutsumi Nicholas Riley Jason Chu Igor Trindade Oliveira @@ -187,7 +190,6 @@ Mariano Anaya anatoly techtonik Karl Bartel - Stefan Beyer Gabriel Lavoie Jared Grubb Alecsandru Patrascu @@ -198,7 +200,6 @@ Victor Stinner Andrews Medina Aaron Iles - p_ziesch...@yahoo.de Toby Watson Daniel Patrick Stuart Williams @@ -210,6 +211,7 @@ Mikael Schönenberg Stanislaw Halik Mihnea Saracin + Matt Jackson Berkin Ilbeyi Gasper Zejn Faye Zhao @@ -217,12 +219,14 @@ Anders Qvist Corbin Simpson Chirag Jadwani + Pauli Virtanen Jonathan David Riehl Beatrice During Alex Perry Robert Zaremba Alan McIntyre Alexander Sedov + David C Ellis Vaibhav Sood Reuben Cummings Attila Gobi @@ -242,7 +246,6 @@ Arjun Naik Aaron Gallagher Alexis Daboville - Pieter Zieschang Karl Ramm Lukas Vacek Omer Katz @@ -270,12 +273,15 @@ Catalin Gabriel Manciu Jacob Oscarson Ryan Gonzalez + Antoine Dupre Kristjan Valur Jonsson Lucio Torre Richard Lancaster Dan Buch Lene Wagner Tomo Cocoa + Miro Hrončok + Anthony Sottile David Lievens Neil Blakey-Milner Henrik Vendelbo @@ -290,10 +296,12 @@ Bobby Impollonia Roberto De Ioris Jeong YunWon + andrewjlawrence Christopher Armstrong Aaron Tubbs Vasantha Ganesh K Jason Michalski + Radu Ciorba Markus Holtermann Andrew Thompson Yusei Tahara @@ -301,28 +309,26 @@ Fabio Niephaus Akira Li Gustavo Niemeyer - Rafał Gałczyński + Nate Bragg Lucas Stadler roberto@goyle + Carl Bordum Hansen Matt Bogosian Yury V. Zaytsev florinpapa Anders Sigfridsson - Matt Jackson Nikolay Zinov rafalgalczyn...@gmail.com Joshua Gilbert Anna Katrina Dominguez Kim Jin Su Amber Brown - Miro Hrončok - Anthony Sottile - Nate Bragg + Andrew Stepanov + Rafał Gałczyński Ben Darnell Juan Francisco Cantero Hurtado Godefroid Chappelle Julian Berman - Michael Hudson-Doyle Stephan Busemann Dan Colish timo @@ -332,6 +338,7 @@ halgari Jim Baker Chris Lambacher + John Aldis coolbutusel...@gmail.com Mike Bayer Rodrigo Araújo @@ -340,6 +347,7 @@ OlivierBlanvillain Jonas Pfannschmidt Zearin + Johan Forsberg Andrey Churin Dan Crosta reub...@gmail.com @@ -349,8 +357,9 @@ Steve Papanik Eli Stevens Boglarka Vezer - gabrielg + gabri...@ec2-54-146-239-158.compute-1.amazonaws.com PavloKapyshin + Hervé Beraud Tomer Chachamu Christopher Groskopf Asmo Soinio @@ -364,7 +373,6 @@ Michael Chermside Anna Ravencroft remarkablerocket - Pauli Virtanen Petre Vijiac Berker Peksag Christian Muirhead @@ -384,12 +392,13 @@ Zooko Wilcox-O Hearn James Lan jiaaro + Evgenii Gorinov Markus Unterwaditzer Kristoffer Kleine Graham Markall Dan Loewenherz werat - Andrew Stepanov + Filip Salomonsson Niclas Olofsson Chris Pressey Tobias Diaz diff --git a/extra_tests/cffi_tests/cffi0/test_ffi_backend.py b/extra_tests/cffi_tests/cffi0/test_ffi_backend.py --- a/extra_tests/cffi_tests/cffi0/test_ffi_backend.py +++ b/extra_tests/cffi_tests/cffi0/test_ffi_backend.py @@ -325,8 +325,31 @@ a = array.array('H', [10000, 20000, 30000]) c = ffi.from_buffer(a) assert ffi.typeof(c) is ffi.typeof("char[]") + assert len(c) == 6 ffi.cast("unsigned short *", c)[1] += 500 assert list(a) == [10000, 20500, 30000] + assert c == ffi.from_buffer("char[]", a, True) + assert c == ffi.from_buffer(a, require_writable=True) + # + c = ffi.from_buffer("unsigned short[]", a) + assert len(c) == 3 + assert c[1] == 20500 + # + p = ffi.from_buffer(b"abcd") + assert p[2] == b"c" + # + assert p == ffi.from_buffer(b"abcd", require_writable=False) + py.test.raises((TypeError, BufferError), ffi.from_buffer, + "char[]", b"abcd", True) + py.test.raises((TypeError, BufferError), ffi.from_buffer, b"abcd", + require_writable=True) + + def test_release(self): + ffi = FFI() + p = ffi.new("int[]", 123) + ffi.release(p) + # here, reading p[0] might give garbage or segfault... + ffi.release(p) # no effect def test_memmove(self): ffi = FFI() diff --git a/extra_tests/cffi_tests/cffi0/test_function.py b/extra_tests/cffi_tests/cffi0/test_function.py --- a/extra_tests/cffi_tests/cffi0/test_function.py +++ b/extra_tests/cffi_tests/cffi0/test_function.py @@ -46,14 +46,15 @@ assert x != math.sin(1.23) # rounding effects assert abs(x - math.sin(1.23)) < 1E-6 - def test_lround_no_return_value(self): + def test_getenv_no_return_value(self): # check that 'void'-returning functions work too ffi = FFI(backend=self.Backend()) ffi.cdef(""" - void lround(double x); + void getenv(char *); """) - m = ffi.dlopen(lib_m) - x = m.lround(1.23) + needs_dlopen_none() + m = ffi.dlopen(None) + x = m.getenv(b"FOO") assert x is None def test_dlopen_filename(self): diff --git a/extra_tests/cffi_tests/cffi1/test_ffi_obj.py b/extra_tests/cffi_tests/cffi1/test_ffi_obj.py --- a/extra_tests/cffi_tests/cffi1/test_ffi_obj.py +++ b/extra_tests/cffi_tests/cffi1/test_ffi_obj.py @@ -239,11 +239,33 @@ def test_ffi_from_buffer(): import array ffi = _cffi1_backend.FFI() - a = array.array('H', [10000, 20000, 30000]) + a = array.array('H', [10000, 20000, 30000, 40000]) c = ffi.from_buffer(a) assert ffi.typeof(c) is ffi.typeof("char[]") + assert len(c) == 8 ffi.cast("unsigned short *", c)[1] += 500 - assert list(a) == [10000, 20500, 30000] + assert list(a) == [10000, 20500, 30000, 40000] + py.test.raises(TypeError, ffi.from_buffer, a, True) + assert c == ffi.from_buffer("char[]", a, True) + assert c == ffi.from_buffer(a, require_writable=True) + # + c = ffi.from_buffer("unsigned short[]", a) + assert len(c) == 4 + assert c[1] == 20500 + # + c = ffi.from_buffer("unsigned short[2][2]", a) + assert len(c) == 2 + assert len(c[0]) == 2 + assert c[0][1] == 20500 + # + p = ffi.from_buffer(b"abcd") + assert p[2] == b"c" + # + assert p == ffi.from_buffer(b"abcd", require_writable=False) + py.test.raises((TypeError, BufferError), ffi.from_buffer, + "char[]", b"abcd", True) + py.test.raises((TypeError, BufferError), ffi.from_buffer, b"abcd", + require_writable=True) def test_memmove(): ffi = _cffi1_backend.FFI() diff --git a/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py b/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py --- a/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py +++ b/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py @@ -1457,6 +1457,35 @@ import gc; gc.collect(); gc.collect(); gc.collect() assert seen == [3] + def test_release(self): + p = ffi.new("int[]", 123) + ffi.release(p) + # here, reading p[0] might give garbage or segfault... + ffi.release(p) # no effect + + def test_release_new_allocator(self): + seen = [] + def myalloc(size): + seen.append(size) + return ffi.new("char[]", b"X" * size) + def myfree(raw): + seen.append(raw) + alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree) + p = alloc2("int[]", 15) + assert seen == [15 * 4] + ffi.release(p) + assert seen == [15 * 4, p] + ffi.release(p) # no effect + assert seen == [15 * 4, p] + # + del seen[:] + p = alloc2("struct ab *") + assert seen == [2 * 4] + ffi.release(p) + assert seen == [2 * 4, p] + ffi.release(p) # no effect + assert seen == [2 * 4, p] + def test_CData_CType(self): assert isinstance(ffi.cast("int", 0), ffi.CData) assert isinstance(ffi.new("int *"), ffi.CData) @@ -1647,14 +1676,6 @@ py.test.raises(TypeError, len, q.a) py.test.raises(TypeError, list, q.a) - def test_from_buffer(self): - import array - a = array.array('H', [10000, 20000, 30000]) - c = ffi.from_buffer(a) - assert ffi.typeof(c) is ffi.typeof("char[]") - ffi.cast("unsigned short *", c)[1] += 500 - assert list(a) == [10000, 20500, 30000] - def test_all_primitives(self): assert set(PRIMITIVE_TO_INDEX) == set([ "char", diff --git a/extra_tests/cffi_tests/cffi1/test_pkgconfig.py b/extra_tests/cffi_tests/cffi1/test_pkgconfig.py new file mode 100644 --- /dev/null +++ b/extra_tests/cffi_tests/cffi1/test_pkgconfig.py @@ -0,0 +1,95 @@ +# Generated by pypy/tool/import_cffi.py +import sys +import subprocess +import py +import cffi.pkgconfig as pkgconfig +from cffi import PkgConfigError + + +def mock_call(libname, flag): + assert libname=="foobarbaz" + flags = { + "--cflags": "-I/usr/include/python3.6m -DABCD -DCFFI_TEST=1 -O42\n", + "--libs": "-L/usr/lib64 -lpython3.6 -shared\n", + } + return flags[flag] + + +def test_merge_flags(): + d1 = {"ham": [1, 2, 3], "spam" : ["a", "b", "c"], "foo" : []} + d2 = {"spam" : ["spam", "spam", "spam"], "bar" : ["b", "a", "z"]} + + pkgconfig.merge_flags(d1, d2) + assert d1 == { + "ham": [1, 2, 3], + "spam" : ["a", "b", "c", "spam", "spam", "spam"], + "bar" : ["b", "a", "z"], + "foo" : []} + + +def test_pkgconfig(): + assert pkgconfig.flags_from_pkgconfig([]) == {} + + saved = pkgconfig.call + try: + pkgconfig.call = mock_call + flags = pkgconfig.flags_from_pkgconfig(["foobarbaz"]) + finally: + pkgconfig.call = saved + assert flags == { + 'include_dirs': ['/usr/include/python3.6m'], + 'library_dirs': ['/usr/lib64'], + 'libraries': ['python3.6'], + 'define_macros': [('ABCD', None), ('CFFI_TEST', '1')], + 'extra_compile_args': ['-O42'], + 'extra_link_args': ['-shared'] + } + +class mock_subprocess: + PIPE = Ellipsis + class Popen: + def __init__(self, cmd, stdout, stderr): + if mock_subprocess.RESULT is None: + raise OSError("oops can't run") + assert cmd == ['pkg-config', '--print-errors', '--cflags', 'libfoo'] + def communicate(self): + bout, berr, rc = mock_subprocess.RESULT + self.returncode = rc + return bout, berr + +def test_call(): + saved = pkgconfig.subprocess + try: + pkgconfig.subprocess = mock_subprocess + + mock_subprocess.RESULT = None + e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags") + assert str(e.value) == "cannot run pkg-config: oops can't run" + + mock_subprocess.RESULT = b"", "Foo error!\n", 1 + e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags") + assert str(e.value) == "Foo error!" + + mock_subprocess.RESULT = b"abc\\def\n", "", 0 + e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags") + assert str(e.value).startswith("pkg-config --cflags libfoo returned an " + "unsupported backslash-escaped output:") + + mock_subprocess.RESULT = b"abc def\n", "", 0 + result = pkgconfig.call("libfoo", "--cflags") + assert result == "abc def\n" + + mock_subprocess.RESULT = b"abc def\n", "", 0 + result = pkgconfig.call("libfoo", "--cflags") + assert result == "abc def\n" + + if sys.version_info >= (3,): + mock_subprocess.RESULT = b"\xff\n", "", 0 + e = py.test.raises(PkgConfigError, pkgconfig.call, + "libfoo", "--cflags", encoding="utf-8") + assert str(e.value) == ( + "pkg-config --cflags libfoo returned bytes that cannot be " + "decoded with encoding 'utf-8':\nb'\\xff\\n'") + + finally: + pkgconfig.subprocess = saved diff --git a/extra_tests/cffi_tests/cffi1/test_recompiler.py b/extra_tests/cffi_tests/cffi1/test_recompiler.py --- a/extra_tests/cffi_tests/cffi1/test_recompiler.py +++ b/extra_tests/cffi_tests/cffi1/test_recompiler.py @@ -5,7 +5,7 @@ from cffi import recompiler from extra_tests.cffi_tests.udir import udir from extra_tests.cffi_tests.support import u, long -from extra_tests.cffi_tests.support import FdWriteCapture, StdErrCapture +from extra_tests.cffi_tests.support import FdWriteCapture, StdErrCapture, _verify try: import importlib @@ -36,7 +36,7 @@ # add '-Werror' to the existing 'extra_compile_args' flags kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) + ['-Werror']) - return recompiler._verify(ffi, module_name, source, *args, **kwds) + return _verify(ffi, module_name, source, *args, **kwds) def test_set_source_no_slashes(): ffi = FFI() @@ -1539,15 +1539,18 @@ assert (pt.x, pt.y) == (99*500*999, -99*500*999) def test_extern_python_1(): + import warnings ffi = FFI() - ffi.cdef(""" + with warnings.catch_warnings(record=True) as log: + ffi.cdef(""" extern "Python" { int bar(int, int); void baz(int, int); int bok(void); void boz(void); } - """) + """) + assert len(log) == 0, "got a warning: %r" % (log,) lib = verify(ffi, 'test_extern_python_1', """ static void baz(int, int); /* forward */ """) diff --git a/extra_tests/cffi_tests/cffi1/test_verify1.py b/extra_tests/cffi_tests/cffi1/test_verify1.py --- a/extra_tests/cffi_tests/cffi1/test_verify1.py +++ b/extra_tests/cffi_tests/cffi1/test_verify1.py @@ -4,6 +4,7 @@ from cffi import CDefError from cffi import recompiler from extra_tests.cffi_tests.support import * +from extra_tests.cffi_tests.support import _verify import _cffi_backend lib_m = ['m'] @@ -38,9 +39,8 @@ except AttributeError: pass self.set_source(module_name, preamble) - return recompiler._verify(self, module_name, preamble, *args, - extra_compile_args=self._extra_compile_args, - **kwds) + return _verify(self, module_name, preamble, *args, + extra_compile_args=self._extra_compile_args, **kwds) class FFI_warnings_not_error(FFI): _extra_compile_args = [] diff --git a/extra_tests/cffi_tests/support.py b/extra_tests/cffi_tests/support.py --- a/extra_tests/cffi_tests/support.py +++ b/extra_tests/cffi_tests/support.py @@ -62,3 +62,28 @@ def getvalue(self): return self._value + +def _verify(ffi, module_name, preamble, *args, **kwds): + import imp + from cffi.recompiler import recompile + from .udir import udir + assert module_name not in sys.modules, "module name conflict: %r" % ( + module_name,) + kwds.setdefault('tmpdir', str(udir)) + outputfilename = recompile(ffi, module_name, preamble, *args, **kwds) + module = imp.load_dynamic(module_name, outputfilename) + # + # hack hack hack: copy all *bound methods* from module.ffi back to the + # ffi instance. Then calls like ffi.new() will invoke module.ffi.new(). + for name in dir(module.ffi): + if not name.startswith('_'): + attr = getattr(module.ffi, name) + if attr is not getattr(ffi, name, object()): + setattr(ffi, name, attr) + def typeof_disabled(*args, **kwds): + raise NotImplementedError + ffi._typeof = typeof_disabled + for name in dir(ffi): + if not name.startswith('_') and not hasattr(module.ffi, name): + setattr(ffi, name, NotImplemented) + return module.lib diff --git a/pypy/module/test_lib_pypy/ctypes_tests/__init__.py b/extra_tests/ctypes_tests/__init__.py rename from pypy/module/test_lib_pypy/ctypes_tests/__init__.py rename to extra_tests/ctypes_tests/__init__.py diff --git a/pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c b/extra_tests/ctypes_tests/_ctypes_test.c rename from pypy/module/test_lib_pypy/ctypes_tests/_ctypes_test.c rename to extra_tests/ctypes_tests/_ctypes_test.c diff --git a/pypy/module/test_lib_pypy/ctypes_tests/conftest.py b/extra_tests/ctypes_tests/conftest.py rename from pypy/module/test_lib_pypy/ctypes_tests/conftest.py rename to extra_tests/ctypes_tests/conftest.py --- a/pypy/module/test_lib_pypy/ctypes_tests/conftest.py +++ b/extra_tests/ctypes_tests/conftest.py @@ -3,10 +3,6 @@ import sys import os -def pytest_ignore_collect(path): - if '__pypy__' not in sys.builtin_module_names: - return True - # XXX: copied from pypy/tool/cpyext/extbuild.py if os.name != 'nt': so_ext = 'so' @@ -85,8 +81,7 @@ return outputfilename # end copy -def compile_so_file(): - udir = pytest.ensuretemp('_ctypes_test') +def compile_so_file(udir): cfile = py.path.local(__file__).dirpath().join("_ctypes_test.c") if sys.platform == 'win32': @@ -96,8 +91,12 @@ return c_compile([cfile], str(udir / '_ctypes_test'), libraries=libraries) -# we need to run after the "tmpdir" plugin which installs pytest.ensuretemp -@pytest.mark.trylast -def pytest_configure(config): - global sofile - sofile = compile_so_file() +@pytest.fixture(scope='session') +def sofile(tmpdir_factory): + udir = tmpdir_factory.mktemp('_ctypes_test') + return str(compile_so_file(udir)) + +@pytest.fixture +def dll(sofile): + from ctypes import CDLL + return CDLL(str(sofile)) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/support.py b/extra_tests/ctypes_tests/support.py rename from pypy/module/test_lib_pypy/ctypes_tests/support.py rename to extra_tests/ctypes_tests/support.py diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_anon.py b/extra_tests/ctypes_tests/test_anon.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_anon.py rename to extra_tests/ctypes_tests/test_anon.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_anon.py +++ b/extra_tests/ctypes_tests/test_anon.py @@ -1,86 +1,55 @@ import pytest from ctypes import * -from .support import BaseCTypesTestChecker -class TestAnon(BaseCTypesTestChecker): +@pytest.mark.pypy_only +def test_nested(): + class ANON_S(Structure): + _fields_ = [("a", c_int)] - def test_anon(self): - class ANON(Union): - _fields_ = [("a", c_int), - ("b", c_int)] + class ANON_U(Union): + _fields_ = [("_", ANON_S), + ("b", c_int)] + _anonymous_ = ["_"] - class Y(Structure): - _fields_ = [("x", c_int), - ("_", ANON), - ("y", c_int)] - _anonymous_ = ["_"] + class Y(Structure): + _fields_ = [("x", c_int), + ("_", ANON_U), + ("y", c_int)] + _anonymous_ = ["_"] - assert Y.a.offset == sizeof(c_int) - assert Y.b.offset == sizeof(c_int) + assert Y.x.offset == 0 + assert Y.a.offset == sizeof(c_int) + assert Y.b.offset == sizeof(c_int) + assert Y._.offset == sizeof(c_int) + assert Y.y.offset == sizeof(c_int) * 2 - assert ANON.a.offset == 0 - assert ANON.b.offset == 0 + assert Y._names_ == ['x', 'a', 'b', 'y'] - def test_anon_nonseq(self): - # TypeError: _anonymous_ must be a sequence - with pytest.raises(TypeError): - type(Structure)( - "Name", (Structure,), {"_fields_": [], "_anonymous_": 42}) +def test_anonymous_fields_on_instance(): + # this is about the *instance-level* access of anonymous fields, + # which you'd guess is the most common, but used not to work + # (issue #2230) - def test_anon_nonmember(self): - # AttributeError: type object 'Name' has no attribute 'x' - with pytest.raises(AttributeError): - type(Structure)( - "Name", (Structure,), {"_fields_": [], "_anonymous_": ["x"]}) + class B(Structure): + _fields_ = [("x", c_int), ("y", c_int), ("z", c_int)] + class A(Structure): + _anonymous_ = ["b"] + _fields_ = [("b", B)] - def test_nested(self): - class ANON_S(Structure): - _fields_ = [("a", c_int)] + a = A() + a.x = 5 + assert a.x == 5 + assert a.b.x == 5 + a.b.x += 1 + assert a.x == 6 - class ANON_U(Union): - _fields_ = [("_", ANON_S), - ("b", c_int)] - _anonymous_ = ["_"] + class C(Structure): + _anonymous_ = ["a"] + _fields_ = [("v", c_int), ("a", A)] - class Y(Structure): - _fields_ = [("x", c_int), - ("_", ANON_U), - ("y", c_int)] - _anonymous_ = ["_"] - - assert Y.x.offset == 0 - assert Y.a.offset == sizeof(c_int) - assert Y.b.offset == sizeof(c_int) - assert Y._.offset == sizeof(c_int) - assert Y.y.offset == sizeof(c_int) * 2 - - assert Y._names_ == ['x', 'a', 'b', 'y'] - - def test_anonymous_fields_on_instance(self): - # this is about the *instance-level* access of anonymous fields, - # which you'd guess is the most common, but used not to work - # (issue #2230) - - class B(Structure): - _fields_ = [("x", c_int), ("y", c_int), ("z", c_int)] - class A(Structure): - _anonymous_ = ["b"] - _fields_ = [("b", B)] - - a = A() - a.x = 5 - assert a.x == 5 - assert a.b.x == 5 - a.b.x += 1 - assert a.x == 6 - - class C(Structure): - _anonymous_ = ["a"] - _fields_ = [("v", c_int), ("a", A)] - - c = C() - c.v = 3 - c.y = -8 - assert c.v == 3 - assert c.y == c.a.y == c.a.b.y == -8 - assert not hasattr(c, 'b') + c = C() + c.v = 3 + c.y = -8 + assert c.v == 3 + assert c.y == c.a.y == c.a.b.y == -8 + assert not hasattr(c, 'b') diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_array.py b/extra_tests/ctypes_tests/test_array.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_array.py rename to extra_tests/ctypes_tests/test_array.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_array.py +++ b/extra_tests/ctypes_tests/test_array.py @@ -1,177 +1,64 @@ import pytest from ctypes import * -from .support import BaseCTypesTestChecker -formats = "bBhHiIlLqQfd" +def test_slice(): + values = list(range(5)) + numarray = c_int * 5 -formats = c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, \ - c_long, c_ulonglong, c_float, c_double + na = numarray(*(c_int(x) for x in values)) -class TestArray(BaseCTypesTestChecker): - def test_simple(self): - # create classes holding simple numeric types, and check - # various properties. + assert list(na[0:0]) == [] + assert list(na[:]) == values + assert list(na[:10]) == values - init = range(15, 25) +def test_init_again(): + sz = (c_char * 3)() + addr1 = addressof(sz) + sz.__init__(*b"foo") + addr2 = addressof(sz) + assert addr1 == addr2 - for fmt in formats: - alen = len(init) - int_array = ARRAY(fmt, alen) +def test_array_of_structures(): + class X(Structure): + _fields_ = [('x', c_int), ('y', c_int)] - ia = int_array(*init) - # length of instance ok? - assert len(ia) == alen + Y = X * 2 + y = Y() + x = X() + x.y = 3 + y[1] = x + assert y[1].y == 3 - # slot values ok? - values = [ia[i] for i in range(len(init))] - assert values == init +def test_output_simple(): + A = c_char * 10 + TP = POINTER(A) + x = TP(A()) + assert x[0] != b'' - # change the items - from operator import setitem - new_values = range(42, 42+alen) - [setitem(ia, n, new_values[n]) for n in range(alen)] - values = [ia[i] for i in range(len(init))] - assert values == new_values + A = c_wchar * 10 + TP = POINTER(A) + x = TP(A()) + assert x[0] != b'' - # are the items initialized to 0? - ia = int_array() - values = [ia[i] for i in range(len(init))] - assert values == [0] * len(init) +def test_output_simple_array(): + A = c_char * 10 + AA = A * 10 + aa = AA() + assert aa[0] != b'' - # Too many in itializers should be caught - with pytest.raises(IndexError): - int_array(*range(alen*2)) +def test_output_complex_test(): + class Car(Structure): + _fields_ = [("brand", c_char * 10), + ("speed", c_float), + ("owner", c_char * 10)] - CharArray = ARRAY(c_char, 3) + assert isinstance(Car(b"abcdefghi", 42.0, b"12345").brand, bytes) + assert Car(b"abcdefghi", 42.0, b"12345").brand == b"abcdefghi" + assert Car(b"abcdefghio", 42.0, b"12345").brand == b"abcdefghio" + with pytest.raises(ValueError): + Car(b"abcdefghiop", 42.0, b"12345") - ca = CharArray("a", "b", "c") - - # Should this work? It doesn't: - # CharArray("abc") - with pytest.raises(TypeError): - CharArray("abc") - - assert ca[0] == "a" - assert ca[1] == "b" - assert ca[2] == "c" - assert ca[-3] == "a" - assert ca[-2] == "b" - assert ca[-1] == "c" - - assert len(ca) == 3 - - # slicing is now supported, but not extended slicing (3-argument)! - from operator import getslice, delitem - with pytest.raises(TypeError): - getslice(ca, 0, 1, -1) - - # cannot delete items - with pytest.raises(TypeError): - delitem(ca, 0) - - def test_numeric_arrays(self): - - alen = 5 - - numarray = ARRAY(c_int, alen) - - na = numarray() - values = [na[i] for i in range(alen)] - assert values == [0] * alen - - na = numarray(*[c_int()] * alen) - values = [na[i] for i in range(alen)] - assert values == [0]*alen - - na = numarray(1, 2, 3, 4, 5) - values = [i for i in na] - assert values == [1, 2, 3, 4, 5] - - na = numarray(*map(c_int, (1, 2, 3, 4, 5))) - values = [i for i in na] - assert values == [1, 2, 3, 4, 5] - - def test_slice(self): - values = range(5) - numarray = c_int * 5 - - na = numarray(*(c_int(x) for x in values)) - - assert list(na[0:0]) == [] - assert list(na[:]) == values - assert list(na[:10]) == values - - def test_classcache(self): - assert not ARRAY(c_int, 3) is ARRAY(c_int, 4) - assert ARRAY(c_int, 3) is ARRAY(c_int, 3) - - def test_from_address(self): - # Failed with 0.9.8, reported by JUrner - p = create_string_buffer("foo") - sz = (c_char * 3).from_address(addressof(p)) - assert sz[:] == "foo" - assert sz.value == "foo" - - def test_init_again(self): - sz = (c_char * 3)() - addr1 = addressof(sz) - sz.__init__(*"foo") - addr2 = addressof(sz) - assert addr1 == addr2 - - try: - create_unicode_buffer - except NameError: - pass - else: - def test_from_addressW(self): - p = create_unicode_buffer("foo") - sz = (c_wchar * 3).from_address(addressof(p)) - assert sz[:] == "foo" - assert sz.value == "foo" - -class TestSophisticatedThings(BaseCTypesTestChecker): - def test_array_of_structures(self): - class X(Structure): - _fields_ = [('x', c_int), ('y', c_int)] - - Y = X * 2 - y = Y() - x = X() - x.y = 3 - y[1] = x - assert y[1].y == 3 - - def test_output_simple(self): - A = c_char * 10 - TP = POINTER(A) - x = TP(A()) - assert x[0] != '' - - A = c_wchar * 10 - TP = POINTER(A) - x = TP(A()) - assert x[0] != '' - - def test_output_simple_array(self): - A = c_char * 10 - AA = A * 10 - aa = AA() - assert aa[0] != '' - - def test_output_complex_test(self): - class Car(Structure): - _fields_ = [("brand", c_char * 10), - ("speed", c_float), - ("owner", c_char * 10)] - - assert isinstance(Car("abcdefghi", 42.0, "12345").brand, bytes) - assert Car("abcdefghi", 42.0, "12345").brand == "abcdefghi" - assert Car("abcdefghio", 42.0, "12345").brand == "abcdefghio" - with pytest.raises(ValueError): - Car("abcdefghiop", 42.0, "12345") - - A = Car._fields_[2][1] - TP = POINTER(A) - x = TP(A()) - assert x[0] != '' + A = Car._fields_[2][1] + TP = POINTER(A) + x = TP(A()) + assert x[0] != b'' diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_base.py b/extra_tests/ctypes_tests/test_base.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_base.py rename to extra_tests/ctypes_tests/test_base.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_base.py +++ b/extra_tests/ctypes_tests/test_base.py @@ -1,26 +1,24 @@ -from .support import WhiteBoxTests - +import pytest from ctypes import * -# WhiteBoxTests +pytestmark = pytest.mark.pypy_only -class TestCTypesBase(WhiteBoxTests): - def test_pointer(self): - p = pointer(pointer(c_int(2))) - x = p[0] - assert x._base is p +def test_pointer(): + p = pointer(pointer(c_int(2))) + x = p[0] + assert x._base is p - def test_structure(self): - class X(Structure): - _fields_ = [('x', POINTER(c_int)), - ('y', POINTER(c_int))] +def test_structure(): + class X(Structure): + _fields_ = [('x', POINTER(c_int)), + ('y', POINTER(c_int))] - x = X() - assert x.y._base is x - assert x.y._index == 1 + x = X() + assert x.y._base is x + assert x.y._index == 1 - def test_array(self): - X = POINTER(c_int) * 24 - x = X() - assert x[16]._base is x - assert x[16]._index == 16 +def test_array(): + X = POINTER(c_int) * 24 + x = X() + assert x[16]._base is x + assert x[16]._index == 16 diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_bitfields.py b/extra_tests/ctypes_tests/test_bitfields.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_bitfields.py rename to extra_tests/ctypes_tests/test_bitfields.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_bitfields.py +++ b/extra_tests/ctypes_tests/test_bitfields.py @@ -1,249 +1,19 @@ import pytest from ctypes import * -from .support import BaseCTypesTestChecker -import os -import ctypes -signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong) -unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong) -int_types = unsigned_int_types + signed_int_types +def test_set_fields_attr(): + class A(Structure): + pass + A._fields_ = [("a", c_byte), ("b", c_ubyte)] +def test_set_fields_attr_bitfields(): + class A(Structure): + pass + A._fields_ = [("a", POINTER(A)), ("b", c_ubyte, 4)] -def setup_module(mod): - import conftest - _ctypes_test = str(conftest.sofile) - func = CDLL(_ctypes_test).unpack_bitfields - func.argtypes = POINTER(BITS), c_char - mod.func = func - - -class BITS(Structure): - _fields_ = [("A", c_int, 1), - ("B", c_int, 2), - ("C", c_int, 3), - ("D", c_int, 4), - ("E", c_int, 5), - ("F", c_int, 6), - ("G", c_int, 7), - ("H", c_int, 8), - ("I", c_int, 9), - - ("M", c_short, 1), - ("N", c_short, 2), - ("O", c_short, 3), - ("P", c_short, 4), - ("Q", c_short, 5), - ("R", c_short, 6), - ("S", c_short, 7)] - - -class TestC: - def test_ints(self): - for i in range(512): - for name in "ABCDEFGHI": - b = BITS() - setattr(b, name, i) - assert (name, i, getattr(b, name)) == (name, i, func(byref(b), name)) - - def test_shorts(self): - for i in range(256): - for name in "MNOPQRS": - b = BITS() - setattr(b, name, i) - assert (name, i, getattr(b, name)) == (name, i, func(byref(b), name)) - - -class TestBitField: - def test_longlong(self): - class X(Structure): - _fields_ = [("a", c_longlong, 1), - ("b", c_longlong, 62), - ("c", c_longlong, 1)] - - assert sizeof(X) == sizeof(c_longlong) - x = X() - x.a, x.b, x.c = -1, 7, -1 - assert (x.a, x.b, x.c) == (-1, 7, -1) - - x = X() - x.a, x.b, x.c = -1, -7, -1 - assert (x.a, x.b, x.c) == (-1, -7, -1) - - def test_ulonglong(self): - class X(Structure): - _fields_ = [("a", c_ulonglong, 1), - ("b", c_ulonglong, 62), - ("c", c_ulonglong, 1)] - - assert sizeof(X) == sizeof(c_longlong) - x = X() - assert (x.a, x.b, x.c) == (0, 0, 0) - x.a, x.b, x.c = 7, 2305843009213693953, 7 - assert (x.a, x.b, x.c) == (1, 2305843009213693953, 1) - - def test_signed(self): - for c_typ in signed_int_types: - class X(Structure): - _fields_ = [("dummy", c_typ), - ("a", c_typ, 3), - ("b", c_typ, 3), - ("c", c_typ, 1)] - assert sizeof(X) == sizeof(c_typ)*2 - - x = X() - assert (c_typ, x.a, x.b, x.c) == (c_typ, 0, 0, 0) - x.a = -1 - assert (c_typ, x.a, x.b, x.c) == (c_typ, -1, 0, 0) - x.a, x.b = 0, -1 - assert (c_typ, x.a, x.b, x.c) == (c_typ, 0, -1, 0) - - def test_unsigned(self): - for c_typ in unsigned_int_types: - class X(Structure): - _fields_ = [("a", c_typ, 3), - ("b", c_typ, 3), - ("c", c_typ, 1)] - assert sizeof(X) == sizeof(c_typ) - - x = X() - assert (c_typ, x.a, x.b, x.c) == (c_typ, 0, 0, 0) - x.a = -1 - assert (c_typ, x.a, x.b, x.c) == (c_typ, 7, 0, 0) - x.a, x.b = 0, -1 - assert (c_typ, x.a, x.b, x.c) == (c_typ, 0, 7, 0) - - def fail_fields(self, *fields): - return self.get_except(type(Structure), "X", (), - {"_fields_": fields}) - - def test_nonint_types(self): - # bit fields are not allowed on non-integer types. - result = self.fail_fields(("a", c_char_p, 1)) - assert result == (TypeError, 'bit fields not allowed for type c_char_p') - - result = self.fail_fields(("a", c_void_p, 1)) - assert result == (TypeError, 'bit fields not allowed for type c_void_p') - - if c_int != c_long: - result = self.fail_fields(("a", POINTER(c_int), 1)) - assert result == (TypeError, 'bit fields not allowed for type LP_c_int') - - result = self.fail_fields(("a", c_char, 1)) - assert result == (TypeError, 'bit fields not allowed for type c_char') - - try: - c_wchar - except NameError: - pass - else: - result = self.fail_fields(("a", c_wchar, 1)) - assert result == (TypeError, 'bit fields not allowed for type c_wchar') - - class Dummy(Structure): - _fields_ = [] - - result = self.fail_fields(("a", Dummy, 1)) - assert result == (TypeError, 'bit fields not allowed for type Dummy') - - def test_single_bitfield_size(self): - for c_typ in int_types: - result = self.fail_fields(("a", c_typ, -1)) - assert result == (ValueError, 'number of bits invalid for bit field') - - result = self.fail_fields(("a", c_typ, 0)) - assert result == (ValueError, 'number of bits invalid for bit field') - - class X(Structure): - _fields_ = [("a", c_typ, 1)] - assert sizeof(X) == sizeof(c_typ) - - class X(Structure): - _fields_ = [("a", c_typ, sizeof(c_typ)*8)] - assert sizeof(X) == sizeof(c_typ) - - result = self.fail_fields(("a", c_typ, sizeof(c_typ)*8 + 1)) - assert result == (ValueError, 'number of bits invalid for bit field') - - def test_multi_bitfields_size(self): - class X(Structure): - _fields_ = [("a", c_short, 1), - ("b", c_short, 14), - ("c", c_short, 1)] - assert sizeof(X) == sizeof(c_short) - - class X(Structure): - _fields_ = [("a", c_short, 1), - ("a1", c_short), - ("b", c_short, 14), - ("c", c_short, 1)] - assert sizeof(X) == sizeof(c_short)*3 - assert X.a.offset == 0 - assert X.a1.offset == sizeof(c_short) - assert X.b.offset == sizeof(c_short)*2 - assert X.c.offset == sizeof(c_short)*2 - - class X(Structure): - _fields_ = [("a", c_short, 3), - ("b", c_short, 14), - ("c", c_short, 14)] - assert sizeof(X) == sizeof(c_short)*3 - assert X.a.offset == sizeof(c_short)*0 - assert X.b.offset == sizeof(c_short)*1 - assert X.c.offset == sizeof(c_short)*2 - - def get_except(self, func, *args, **kw): - try: - func(*args, **kw) - except Exception as detail: - import traceback - traceback.print_exc() - return detail.__class__, str(detail) - - def test_mixed_1(self): - class X(Structure): - _fields_ = [("a", c_byte, 4), - ("b", c_int, 4)] - if os.name in ("nt", "ce"): - assert sizeof(X) == sizeof(c_int)*2 - else: - assert sizeof(X) == sizeof(c_int) - - def test_mixed_2(self): - class X(Structure): - _fields_ = [("a", c_byte, 4), - ("b", c_int, 32)] - assert sizeof(X) == sizeof(c_int)*2 - - def test_mixed_3(self): - class X(Structure): - _fields_ = [("a", c_byte, 4), - ("b", c_ubyte, 4)] - assert sizeof(X) == sizeof(c_byte) - - def test_anon_bitfields(self): - # anonymous bit-fields gave a strange error message - class X(Structure): - _fields_ = [("a", c_byte, 4), - ("b", c_ubyte, 4)] - class Y(Structure): - _anonymous_ = ["_"] - _fields_ = [("_", X)] - - def test_set_fields_attr(self): - class A(Structure): - pass - A._fields_ = [("a", c_byte), - ("b", c_ubyte)] - - def test_set_fields_attr_bitfields(self): - class A(Structure): - pass - A._fields_ = [("a", POINTER(A)), - ("b", c_ubyte, 4)] - - def test_set_fields_cycle_fails(self): - class A(Structure): - pass - with pytest.raises(AttributeError): - A._fields_ = [("a", A)] +def test_set_fields_cycle_fails(): + class A(Structure): + pass + with pytest.raises(AttributeError): + A._fields_ = [("a", A)] diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py b/extra_tests/ctypes_tests/test_buffers.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py rename to extra_tests/ctypes_tests/test_buffers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_buffers.py +++ b/extra_tests/ctypes_tests/test_buffers.py @@ -1,76 +1,38 @@ from ctypes import * -from .support import BaseCTypesTestChecker -class TestStringBuffer(BaseCTypesTestChecker): +def test_buffer(): + b = create_string_buffer(32) + assert len(b) == 32 + assert sizeof(b) == 32 * sizeof(c_char) + assert type(b[0]) is str - def test_buffer(self): - b = create_string_buffer(32) - assert len(b) == 32 - assert sizeof(b) == 32 * sizeof(c_char) - assert type(b[0]) is str + b = create_string_buffer(33L) + assert len(b) == 33 + assert sizeof(b) == 33 * sizeof(c_char) + assert type(b[0]) is str - b = create_string_buffer(33L) - assert len(b) == 33 - assert sizeof(b) == 33 * sizeof(c_char) - assert type(b[0]) is str + b = create_string_buffer(b"abc") + assert len(b) == 4 # trailing nul char + assert sizeof(b) == 4 * sizeof(c_char) + assert type(b[0]) is str + assert b[0] == b"a" + assert b[:] == b"abc\0" - b = create_string_buffer("abc") - assert len(b) == 4 # trailing nul char - assert sizeof(b) == 4 * sizeof(c_char) - assert type(b[0]) is str - assert b[0] == "a" - assert b[:] == "abc\0" +def test_from_buffer(): + b1 = bytearray(b"abcde") + b = (c_char * 5).from_buffer(b1) + assert b[2] == b"c" + # + b1 = bytearray(b"abcd") + b = c_int.from_buffer(b1) + assert b.value in (1684234849, # little endian + 1633837924) # big endian - def test_string_conversion(self): - b = create_string_buffer(u"abc") - assert len(b) == 4 # trailing nul char - assert sizeof(b) == 4 * sizeof(c_char) - assert type(b[0]) is str - assert b[0] == "a" - assert b[:] == "abc\0" - - def test_from_buffer(self): - b1 = bytearray("abcde") - b = (c_char * 5).from_buffer(b1) - assert b[2] == "c" - # - b1 = bytearray("abcd") - b = c_int.from_buffer(b1) - assert b.value in (1684234849, # little endian - 1633837924) # big endian - - def test_from_buffer_keepalive(self): - # Issue #2878 - b1 = bytearray("ab") - array = (c_uint16 * 32)() - array[6] = c_uint16.from_buffer(b1) - # this is also what we get on CPython. I don't think it makes - # sense because the array contains just a copy of the number. - assert array._objects == {'6': b1} - - try: - c_wchar - except NameError: - pass - else: - def test_unicode_buffer(self): - b = create_unicode_buffer(32) - assert len(b) == 32 - assert sizeof(b) == 32 * sizeof(c_wchar) - assert type(b[0]) is unicode - - b = create_unicode_buffer(u"abc") - assert len(b) == 4 # trailing nul char - assert sizeof(b) == 4 * sizeof(c_wchar) - assert type(b[0]) is unicode - assert b[0] == u"a" - assert b[:] == "abc\0" - - def test_unicode_conversion(self): - b = create_unicode_buffer("abc") - assert len(b) == 4 # trailing nul char - assert sizeof(b) == 4 * sizeof(c_wchar) - assert type(b[0]) is unicode - assert b[0] == u"a" - assert b[:] == "abc\0" - +def test_from_buffer_keepalive(): + # Issue #2878 + b1 = bytearray(b"ab") + array = (c_uint16 * 32)() + array[6] = c_uint16.from_buffer(b1) + # this is also what we get on CPython. I don't think it makes + # sense because the array contains just a copy of the number. + assert array._objects == {'6': b1} diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callback_traceback.py b/extra_tests/ctypes_tests/test_callback_traceback.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_callback_traceback.py rename to extra_tests/ctypes_tests/test_callback_traceback.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callback_traceback.py +++ b/extra_tests/ctypes_tests/test_callback_traceback.py @@ -1,80 +1,35 @@ # derived from test_random_things.py -import py +import pytest + from ctypes import * -import sys -def callback_func(arg): - 42 / arg - raise ValueError(arg) +_rawffi = pytest.importorskip('_rawffi') -class TestCallbackTraceback: - # When an exception is raised in a ctypes callback function, the C - # code prints a traceback. +# +# This test makes sure the exception types *and* the exception +# value is printed correctly. + +@pytest.mark.skipif("sys.flags.inspect") +def test_SystemExit(monkeypatch, capsys): + """ + When an exception is raised in a ctypes callback function, the C + code prints a traceback. When SystemExit is raised, the interpreter + normally exits immediately. + """ + def callback_func(arg): + raise SystemExit(42) + def custom_exit(value): + raise Exception("<<<exit(%r)>>>" % (value,)) + monkeypatch.setattr(_rawffi, 'exit', custom_exit) + cb = CFUNCTYPE(c_int, c_int)(callback_func) + cb2 = cast(cast(cb, c_void_p), CFUNCTYPE(c_int, c_int)) + out, err = capsys.readouterr() + assert not err + cb2(0) + out, err = capsys.readouterr() + assert err.splitlines()[-1] == "Exception: <<<exit(42)>>>" # - # This test makes sure the exception types *and* the exception - # value is printed correctly. - # - # Changed in 0.9.3: No longer is '(in callback)' prepended to the - # error message - instead a additional frame for the C code is - # created, then a full traceback printed. When SystemExit is - # raised in a callback function, the interpreter exits. - - def capture_stderr(self, func, *args, **kw): - # helper - call function 'func', and return the captured stderr - import StringIO - old_stderr = sys.stderr - logger = sys.stderr = StringIO.StringIO() - try: - func(*args, **kw) - finally: - sys.stderr = old_stderr - return logger.getvalue() - - def test_ValueError(self): - cb = CFUNCTYPE(c_int, c_int)(callback_func) - out = self.capture_stderr(cb, 42) - assert out.splitlines()[-1] == ( - "ValueError: 42") - - def test_IntegerDivisionError(self): - cb = CFUNCTYPE(c_int, c_int)(callback_func) - out = self.capture_stderr(cb, 0) - assert out.splitlines()[-1][:19] == ( - "ZeroDivisionError: ") - - def test_FloatDivisionError(self): - cb = CFUNCTYPE(c_int, c_double)(callback_func) - out = self.capture_stderr(cb, 0.0) - assert out.splitlines()[-1][:19] == ( - "ZeroDivisionError: ") - - def test_TypeErrorDivisionError(self): - cb = CFUNCTYPE(c_int, c_char_p)(callback_func) - out = self.capture_stderr(cb, "spam") - assert out.splitlines()[-1].startswith( - "TypeError: " - "unsupported operand type(s) for") - - def test_SystemExit(self): - import _rawffi - if sys.flags.inspect: - skip("requires sys.flags.inspect == 0") - def callback_func(arg): - raise SystemExit(42) - def custom_exit(value): - raise Exception("<<<exit(%r)>>>" % (value,)) - original_exit = _rawffi.exit - try: - _rawffi.exit = custom_exit - # - cb = CFUNCTYPE(c_int, c_int)(callback_func) - cb2 = cast(cast(cb, c_void_p), CFUNCTYPE(c_int, c_int)) - out = self.capture_stderr(cb2, 0) - assert out.splitlines()[-1] == "Exception: <<<exit(42)>>>" - # - cb = CFUNCTYPE(c_int, c_int)(callback_func) - out = self.capture_stderr(cb, 0) - assert out.splitlines()[-1] == "Exception: <<<exit(42)>>>" - # - finally: - _rawffi.exit = original_exit + cb = CFUNCTYPE(c_int, c_int)(callback_func) + cb(0) + out, err = capsys.readouterr() + assert err.splitlines()[-1] == "Exception: <<<exit(42)>>>" diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/extra_tests/ctypes_tests/test_callbacks.py rename from pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py rename to extra_tests/ctypes_tests/test_callbacks.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py +++ b/extra_tests/ctypes_tests/test_callbacks.py @@ -1,283 +1,194 @@ +import pytest + +import math from ctypes import * -import pytest from .support import BaseCTypesTestChecker -class TestCallbacks(BaseCTypesTestChecker): - functype = CFUNCTYPE - -## def tearDown(self): -## import gc -## gc.collect() - - def callback(self, *args): - self.got_args = args - return args[-1] - - def check_type(self, typ, arg): - unwrapped_types = { - c_float: (float,), - c_double: (float,), - c_char: (str,), - c_char_p: (str,), - c_uint: (int, long), - c_ulong: (int, long), - } - - PROTO = self.functype.im_func(typ, typ) - cfunc = PROTO(self.callback) - result = cfunc(arg) - if typ == c_float: - assert abs(result - arg) < 0.000001 - else: - assert self.got_args == (arg,) - assert result == arg - - result2 = cfunc(typ(arg)) - assert type(result2) in unwrapped_types.get(typ, (int, long)) - - PROTO = self.functype.im_func(typ, c_byte, typ) - result = PROTO(self.callback)(-3, arg) - if typ == c_float: - assert abs(result - arg) < 0.000001 - else: - assert self.got_args == (-3, arg) - assert result == arg - - ################ - - def test_byte(self): - self.check_type(c_byte, 42) - self.check_type(c_byte, -42) - - def test_ubyte(self): - self.check_type(c_ubyte, 42) - - def test_short(self): - self.check_type(c_short, 42) - self.check_type(c_short, -42) - - def test_ushort(self): - self.check_type(c_ushort, 42) - - def test_int(self): - self.check_type(c_int, 42) - self.check_type(c_int, -42) - - def test_uint(self): - self.check_type(c_uint, 42) - - def test_long(self): - self.check_type(c_long, 42) - self.check_type(c_long, -42) - - def test_ulong(self): - self.check_type(c_ulong, 42) - - def test_longlong(self): - self.check_type(c_longlong, 42) - self.check_type(c_longlong, -42) - - def test_ulonglong(self): - self.check_type(c_ulonglong, 42) - - def test_float(self): - # only almost equal: double -> float -> double - import math - self.check_type(c_float, math.e) - self.check_type(c_float, -math.e) - - def test_double(self): - self.check_type(c_double, 3.14) - self.check_type(c_double, -3.14) - - def test_char(self): - self.check_type(c_char, "x") - self.check_type(c_char, "a") - - # disabled: would now (correctly) raise a RuntimeWarning about - # a memory leak. A callback function cannot return a non-integral - # C type without causing a memory leak. -## def test_char_p(self): -## self.check_type(c_char_p, "abc") -## self.check_type(c_char_p, "def") - - - @pytest.mark.xfail( - reason="we are less strict about callback return type sanity") - def test_unsupported_restype_1(self): - # Only "fundamental" result types are supported for callback - # functions, the type must have a non-NULL stgdict->setfunc. - # POINTER(c_double), for example, is not supported. - - prototype = self.functype.im_func(POINTER(c_double)) - # The type is checked when the prototype is called - with pytest.raises(TypeError): - prototype(lambda: None) - +functypes = [CFUNCTYPE] try: - WINFUNCTYPE + functypes.append(WINFUNCTYPE) except NameError: pass -else: - class TestStdcallCallbacks(TestCallbacks): - functype = WINFUNCTYPE -################################################################ -class TestSampleCallbacks(BaseCTypesTestChecker): +def callback(*args): + callback.got_args = args + return args[-1] - def test_integrate(self): - # Derived from some then non-working code, posted by David Foster - import conftest - _ctypes_test = str(conftest.sofile) - dll = CDLL(_ctypes_test) +unwrapped_types = { + c_float: (float,), + c_double: (float,), + c_char: (str,), + c_char_p: (str,), + c_uint: (int, long), + c_ulong: (int, long), + } - # The function prototype called by 'integrate': double func(double); - CALLBACK = CFUNCTYPE(c_double, c_double) +@pytest.mark.parametrize("typ, arg", [ + (c_byte, 42), + (c_byte, -42), + (c_ubyte, 42), + (c_short, 42), + (c_short, -42), + (c_ushort, 42), + (c_int, 42), + (c_int, -42), + (c_uint, 42), + (c_long, 42), + (c_long, -42), + (c_ulong, 42), + (c_longlong, 42), + (c_longlong, -42), + (c_ulonglong, 42), + (c_float, math.e), # only almost equal: double -> float -> double + (c_float, -math.e), + (c_double, 3.14), + (c_double, -3.14), + (c_char, b"x"), + (c_char, b"a"), +]) +@pytest.mark.parametrize('functype', functypes) +def test_types(typ, arg, functype): + PROTO = functype(typ, typ) + cfunc = PROTO(callback) + result = cfunc(arg) + if typ == c_float: + assert abs(result - arg) < 0.000001 + else: + assert callback.got_args == (arg,) + assert result == arg - # The integrate function itself, exposed from the _ctypes_test dll - integrate = dll.integrate - integrate.argtypes = (c_double, c_double, CALLBACK, c_long) - integrate.restype = c_double + result2 = cfunc(typ(arg)) + assert type(result2) in unwrapped_types.get(typ, (int, long)) - def func(x): - print 'calculating x**2 of',x - return x**2 + PROTO = functype(typ, c_byte, typ) + result = PROTO(callback)(-3, arg) + if typ == c_float: + assert abs(result - arg) < 0.000001 + else: + assert callback.got_args == (-3, arg) + assert result == arg - result = integrate(0.0, 1.0, CALLBACK(func), 10) - diff = abs(result - 1./3.) +@pytest.mark.parametrize('functype', functypes) +def test_unsupported_restype_1(functype): + # Only "fundamental" result types are supported for callback + # functions, the type must have a non-NULL stgdict->setfunc. + # POINTER(c_double), for example, is not supported. - assert diff < 0.01, "%s not less than 0.01" % diff + prototype = functype(POINTER(c_double)) + # The type is checked when the prototype is called + with pytest.raises(TypeError): + prototype(lambda: None) -################################################################ -class TestMoreCallbacks(BaseCTypesTestChecker): +def test_callback_with_struct_argument(): + class RECT(Structure): + _fields_ = [("left", c_int), ("top", c_int), + ("right", c_int), ("bottom", c_int)] - def test_callback_with_struct_argument(self): - class RECT(Structure): - _fields_ = [("left", c_int), ("top", c_int), - ("right", c_int), ("bottom", c_int)] + proto = CFUNCTYPE(c_int, RECT) - proto = CFUNCTYPE(c_int, RECT) - def callback(point): - point.left *= -1 - return point.left+point.top+point.right+point.bottom + def callback(point): + point.left *= -1 + return point.left + point.top + point.right + point.bottom - cbp = proto(callback) + cbp = proto(callback) + rect = RECT(-1000, 100, 10, 1) + res = cbp(rect) + assert res == 1111 + assert rect.left == -1000 # must not have been changed! - rect = RECT(-1000,100,10,1) +def test_callback_from_c_with_struct_argument(dll): + class RECT(Structure): + _fields_ = [("left", c_long), ("top", c_long), + ("right", c_long), ("bottom", c_long)] - res = cbp(rect) + proto = CFUNCTYPE(c_int, RECT) - assert res == 1111 - assert rect.left == -1000 # must not have been changed! + def callback(point): + return point.left + point.top + point.right + point.bottom - def test_callback_from_c_with_struct_argument(self): - import conftest - _ctypes_test = str(conftest.sofile) - dll = CDLL(_ctypes_test) + cbp = proto(callback) + rect = RECT(1000, 100, 10, 1) - class RECT(Structure): - _fields_ = [("left", c_long), ("top", c_long), - ("right", c_long), ("bottom", c_long)] + call_callback_with_rect = dll.call_callback_with_rect + call_callback_with_rect.restype = c_int + call_callback_with_rect.argtypes = [proto, RECT] + res = call_callback_with_rect(cbp, rect) + assert res == 1111 - proto = CFUNCTYPE(c_int, RECT) - def callback(point): - return point.left+point.top+point.right+point.bottom +def test_callback_unsupported_return_struct(): + class RECT(Structure): + _fields_ = [("left", c_int), ("top", c_int), + ("right", c_int), ("bottom", c_int)] - cbp = proto(callback) - rect = RECT(1000,100,10,1) + proto = CFUNCTYPE(RECT, c_int) + with pytest.raises(TypeError): + proto(lambda r: 0) - call_callback_with_rect = dll.call_callback_with_rect - call_callback_with_rect.restype = c_int - call_callback_with_rect.argtypes = [proto, RECT] - res = call_callback_with_rect(cbp, rect) - assert res == 1111 - def test_callback_unsupported_return_struct(self): - class RECT(Structure): - _fields_ = [("left", c_int), ("top", c_int), - ("right", c_int), ("bottom", c_int)] +def test_qsort(dll): + PI = POINTER(c_int) + A = c_int*5 + a = A() + for i in range(5): + a[i] = 5-i - proto = CFUNCTYPE(RECT, c_int) - with pytest.raises(TypeError): - proto(lambda r: 0) + assert a[0] == 5 # sanity + def comp(a, b): + a = a.contents.value + b = b.contents.value + return cmp(a,b) + qs = dll.my_qsort + qs.restype = None + CMP = CFUNCTYPE(c_int, PI, PI) + qs.argtypes = (PI, c_size_t, c_size_t, CMP) - def test_qsort(self): - import conftest - _ctypes_test = str(conftest.sofile) - dll = CDLL(_ctypes_test) + qs(cast(a, PI), 5, sizeof(c_int), CMP(comp)) - PI = POINTER(c_int) - A = c_int*5 - a = A() - for i in range(5): - a[i] = 5-i + res = list(a) - assert a[0] == 5 # sanity + assert res == [1,2,3,4,5] - def comp(a, b): - a = a.contents.value - b = b.contents.value - return cmp(a,b) - qs = dll.my_qsort - qs.restype = None - CMP = CFUNCTYPE(c_int, PI, PI) - qs.argtypes = (PI, c_size_t, c_size_t, CMP) +def test_pyobject_as_opaque(dll): + def callback(arg): + return arg() - qs(cast(a, PI), 5, sizeof(c_int), CMP(comp)) + CTP = CFUNCTYPE(c_int, py_object) + cfunc = dll._testfunc_callback_opaque + cfunc.argtypes = [CTP, py_object] + cfunc.restype = c_int + res = cfunc(CTP(callback), lambda : 3) + assert res == 3 - res = list(a) +def test_callback_void(capsys, dll): + def callback(): + pass - assert res == [1,2,3,4,5] + CTP = CFUNCTYPE(None) + cfunc = dll._testfunc_callback_void + cfunc.argtypes = [CTP] + cfunc.restype = int + cfunc(CTP(callback)) + out, err = capsys.readouterr() + assert (out, err) == ("", "") - def test_pyobject_as_opaque(self): - import conftest - _ctypes_test = str(conftest.sofile) - dll = CDLL(_ctypes_test) - def callback(arg): - return arg() +def test_callback_pyobject(): + def callback(obj): + return obj - CTP = CFUNCTYPE(c_int, py_object) - cfunc = dll._testfunc_callback_opaque - cfunc.argtypes = [CTP, py_object] - cfunc.restype = c_int - res = cfunc(CTP(callback), lambda : 3) - assert res == 3 + FUNC = CFUNCTYPE(py_object, py_object) + cfunc = FUNC(callback) + param = c_int(42) + assert cfunc(param) is param - def test_callback_void(self, capsys): - import conftest - _ctypes_test = str(conftest.sofile) - dll = CDLL(_ctypes_test) - - def callback(): - pass - - CTP = CFUNCTYPE(None) - cfunc = dll._testfunc_callback_void - cfunc.argtypes = [CTP] - cfunc.restype = int - cfunc(CTP(callback)) - out, err = capsys.readouterr() - assert (out, err) == ("", "") - - _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit