Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r83725:df440f20d566 Date: 2016-04-17 17:51 -0700 http://bitbucket.org/pypy/pypy/changeset/df440f20d566/
Log: merge default diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -111,23 +111,24 @@ Simon Burton Martin Matusiak Konstantin Lopuhin + Stefano Rivera Wenzhu Man John Witulski Laurence Tratt Ivan Sichmann Freitas Greg Price Dario Bertini - Stefano Rivera Mark Pearse Simon Cross + Edd Barrett Andreas Stührk - Edd Barrett Jean-Philippe St. Pierre Guido van Rossum Pavel Vinogradov + Spenser Bauman Jeremy Thurgood Paweł Piotr Przeradowski - Spenser Bauman + Tobias Pape Paul deGrandis Ilya Osadchiy marky1991 @@ -139,7 +140,7 @@ Georg Brandl Bert Freudenberg Stian Andreassen - Tobias Pape + Mark Young Wanja Saatkamp Gerald Klix Mike Blume @@ -170,9 +171,9 @@ Yichao Yu Rocco Moretti Gintautas Miliauskas + Devin Jeanpierre Michael Twomey Lucian Branescu Mihaila - Devin Jeanpierre Gabriel Lavoie Olivier Dormond Jared Grubb @@ -183,6 +184,7 @@ Victor Stinner Andrews Medina anatoly techtonik + Sergey Matyunin Stuart Williams Jasper Schulz Christian Hudon @@ -217,7 +219,6 @@ Arjun Naik Valentina Mukhamedzhanova Stefano Parmesan - Mark Young Alexis Daboville Jens-Uwe Mager Carl Meyer @@ -225,7 +226,9 @@ Pieter Zieschang Gabriel Lukas Vacek + Kunal Grover Andrew Dalke + Florin Papa Sylvain Thenault Jakub Stasiak Nathan Taylor @@ -240,7 +243,6 @@ Kristjan Valur Jonsson David Lievens Neil Blakey-Milner - Sergey Matyunin Lutz Paelike Lucio Torre Lars Wassermann @@ -252,9 +254,11 @@ Artur Lisiecki Sergey Kishchenko Ignas Mikalajunas + Alecsandru Patrascu Christoph Gerum Martin Blais Lene Wagner + Catalin Gabriel Manciu Tomo Cocoa Kim Jin Su Toni Mattis @@ -291,6 +295,7 @@ Akira Li Gustavo Niemeyer Stephan Busemann + florinpapa Rafał Gałczyński Matt Bogosian Christian Muirhead @@ -305,6 +310,7 @@ Boglarka Vezer Chris Pressey Buck Golemon + Diana Popa Konrad Delong Dinu Gherman Chris Lambacher diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.5.2 +Version: 1.6.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.5.2" -__version_info__ = (1, 5, 2) +__version__ = "1.6.0" +__version_info__ = (1, 6, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.5.2" + "\ncompiled with cffi version: 1.6.0" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py --- a/lib_pypy/cffi/api.py +++ b/lib_pypy/cffi/api.py @@ -299,6 +299,23 @@ """ return self._backend.string(cdata, maxlen) + def unpack(self, cdata, length): + """Unpack an array of C data of the given length, + returning a Python string/unicode/list. + + If 'cdata' is a pointer to 'char', returns a byte string. + It does not stop at the first null. This is equivalent to: + ffi.buffer(cdata, length)[:] + + If 'cdata' is a pointer to 'wchar_t', returns a unicode string. + 'length' is measured in wchar_t's; it is not the size in bytes. + + If 'cdata' is a pointer to anything else, returns a list of + 'length' items. This is a faster equivalent to: + [cdata[i] for i in range(length)] + """ + return self._backend.unpack(cdata, length) + def buffer(self, cdata, size=-1): """Return a read-write buffer object that references the raw C data pointed to by the given 'cdata'. The 'cdata' must be a pointer or @@ -721,6 +738,26 @@ raise ValueError("ffi.def_extern() is only available on API-mode FFI " "objects") + def list_types(self): + """Returns the user type names known to this FFI instance. + This returns a tuple containing three lists of names: + (typedef_names, names_of_structs, names_of_unions) + """ + typedefs = [] + structs = [] + unions = [] + for key in self._parser._declarations: + if key.startswith('typedef '): + typedefs.append(key[8:]) + elif key.startswith('struct '): + structs.append(key[7:]) + elif key.startswith('union '): + unions.append(key[6:]) + typedefs.sort() + structs.sort() + unions.sort() + return (typedefs, structs, unions) + def _load_backend_lib(backend, name, flags): if name is None: diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py --- a/lib_pypy/cffi/recompiler.py +++ b/lib_pypy/cffi/recompiler.py @@ -1231,7 +1231,7 @@ if c == '\n': return '\\n' return '\\%03o' % ord(c) lines = [] - for line in s.splitlines(True): + for line in s.splitlines(True) or ['']: lines.append('"%s"' % ''.join([_char_repr(c) for c in line])) return ' \\\n'.join(lines) @@ -1319,7 +1319,9 @@ s = s.encode('ascii') super(NativeIO, self).write(s) -def _make_c_or_py_source(ffi, module_name, preamble, target_file): +def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): + if verbose: + print("generating %s" % (target_file,)) recompiler = Recompiler(ffi, module_name, target_is_python=(preamble is None)) recompiler.collect_type_table() @@ -1331,6 +1333,8 @@ with open(target_file, 'r') as f1: if f1.read(len(output) + 1) != output: raise IOError + if verbose: + print("(already up-to-date)") return False # already up-to-date except IOError: tmp_file = '%s.~%d' % (target_file, os.getpid()) @@ -1343,12 +1347,14 @@ os.rename(tmp_file, target_file) return True -def make_c_source(ffi, module_name, preamble, target_c_file): +def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): assert preamble is not None - return _make_c_or_py_source(ffi, module_name, preamble, target_c_file) + return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, + verbose) -def make_py_source(ffi, module_name, target_py_file): - return _make_c_or_py_source(ffi, module_name, None, target_py_file) +def make_py_source(ffi, module_name, target_py_file, verbose=False): + return _make_c_or_py_source(ffi, module_name, None, target_py_file, + verbose) def _modname_to_file(outputdir, modname, extension): parts = modname.split('.') @@ -1438,7 +1444,8 @@ target = '*' # ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) - updated = make_c_source(ffi, module_name, preamble, c_file) + updated = make_c_source(ffi, module_name, preamble, c_file, + verbose=compiler_verbose) if call_c_compiler: patchlist = [] cwd = os.getcwd() @@ -1458,7 +1465,8 @@ else: if c_file is None: c_file, _ = _modname_to_file(tmpdir, module_name, '.py') - updated = make_py_source(ffi, module_name, c_file) + updated = make_py_source(ffi, module_name, c_file, + verbose=compiler_verbose) if call_c_compiler: return c_file else: @@ -1484,4 +1492,7 @@ 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/doc/contributor.rst b/pypy/doc/contributor.rst --- a/pypy/doc/contributor.rst +++ b/pypy/doc/contributor.rst @@ -81,13 +81,13 @@ Simon Burton Martin Matusiak Konstantin Lopuhin + Stefano Rivera Wenzhu Man John Witulski Laurence Tratt Ivan Sichmann Freitas Greg Price Dario Bertini - Stefano Rivera Mark Pearse Simon Cross Andreas Stührk @@ -95,9 +95,10 @@ Jean-Philippe St. Pierre Guido van Rossum Pavel Vinogradov + Spenser Bauman Jeremy Thurgood Paweł Piotr Przeradowski - Spenser Bauman + Tobias Pape Paul deGrandis Ilya Osadchiy marky1991 @@ -109,7 +110,7 @@ Georg Brandl Bert Freudenberg Stian Andreassen - Tobias Pape + Mark Young Wanja Saatkamp Gerald Klix Mike Blume @@ -140,9 +141,9 @@ Yichao Yu Rocco Moretti Gintautas Miliauskas + Devin Jeanpierre Michael Twomey Lucian Branescu Mihaila - Devin Jeanpierre Gabriel Lavoie Olivier Dormond Jared Grubb @@ -153,6 +154,7 @@ Victor Stinner Andrews Medina anatoly techtonik + Sergey Matyunin Stuart Williams Jasper Schulz Christian Hudon @@ -187,7 +189,6 @@ Arjun Naik Valentina Mukhamedzhanova Stefano Parmesan - Mark Young Alexis Daboville Jens-Uwe Mager Carl Meyer @@ -195,7 +196,9 @@ Pieter Zieschang Gabriel Lukas Vacek + Kunal Grover Andrew Dalke + Florin Papa Sylvain Thenault Jakub Stasiak Nathan Taylor @@ -210,7 +213,6 @@ Kristjan Valur Jonsson David Lievens Neil Blakey-Milner - Sergey Matyunin Lutz Paelike Lucio Torre Lars Wassermann @@ -222,9 +224,11 @@ Artur Lisiecki Sergey Kishchenko Ignas Mikalajunas + Alecsandru Patrascu Christoph Gerum Martin Blais Lene Wagner + Catalin Gabriel Manciu Tomo Cocoa Kim Jin Su Toni Mattis @@ -261,6 +265,7 @@ Akira Li Gustavo Niemeyer Stephan Busemann + florinpapa Rafał Gałczyński Matt Bogosian Christian Muirhead @@ -275,6 +280,7 @@ Boglarka Vezer Chris Pressey Buck Golemon + Diana Popa Konrad Delong Dinu Gherman Chris Lambacher diff --git a/pypy/doc/release-5.1.0.rst b/pypy/doc/release-5.1.0.rst --- a/pypy/doc/release-5.1.0.rst +++ b/pypy/doc/release-5.1.0.rst @@ -78,8 +78,6 @@ * Try harder to not emit NEON instructions on ARM processors without NEON support - * Support glibc < 2.16 on ARM - * Improve the rpython posix module system interaction function calls * Detect a missing class function implementation instead of calling a random @@ -92,6 +90,8 @@ * Fix JIT issue with unpack() on a Trace which contains half-written operations + * Fix sandbox startup (a regression in 5.0) + * Issues reported with our previous release were resolved_ after reports from users on our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at #pypy diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -5,3 +5,12 @@ .. this is a revision shortly after release-5.1 .. startrev: 2180e1eaf6f6 +.. branch: rposix-for-3 + +Reuse rposix definition of TIMESPEC in rposix_stat, add wrapper for fstatat(). +This updates the underlying rpython functions with the ones needed for the +py3k branch + +.. branch: numpy_broadcast + +Add broadcast to micronumpy diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1051,6 +1051,9 @@ def newlist_int(self, list_i): return self.newlist([self.wrap(i) for i in list_i]) + def newlist_float(self, list_f): + return self.newlist([self.wrap(f) for f in list_f]) + def newlist_hint(self, sizehint): from pypy.objspace.std.listobject import make_empty_list_with_size return make_empty_list_with_size(self, sizehint) diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi, entrypoint from rpython.rtyper.lltypesystem import rffi -VERSION = "1.5.2" +VERSION = "1.6.0" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: @@ -48,7 +48,7 @@ 'from_buffer': 'func.from_buffer', 'string': 'func.string', - 'rawstring': 'func.rawstring', + 'unpack': 'func.unpack', 'buffer': 'cbuffer.buffer', 'memmove': 'func.memmove', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -323,14 +323,18 @@ from pypy.module._cffi_backend import ctypearray ctype = self.ctype if isinstance(ctype, ctypearray.W_CTypeArray): - return ctype.ctitem.unpack_list_of_int_items(self) + length = self.get_array_length() + with self as ptr: + return ctype.ctitem.unpack_list_of_int_items(ptr, length) return None def unpackiterable_float(self, space): from pypy.module._cffi_backend import ctypearray ctype = self.ctype if isinstance(ctype, ctypearray.W_CTypeArray): - return ctype.ctitem.unpack_list_of_float_items(self) + length = self.get_array_length() + with self as ptr: + return ctype.ctitem.unpack_list_of_float_items(ptr, length) return None @specialize.argtype(1) @@ -367,6 +371,25 @@ with self as ptr: return W_CDataGCP(self.space, ptr, self.ctype, self, w_destructor) + def unpack(self, length): + from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray + space = self.space + if not self.ctype.is_nonfunc_pointer_or_array: + raise oefmt(space.w_TypeError, + "expected a pointer or array, got '%s'", + self.ctype.name) + if length < 0: + raise oefmt(space.w_ValueError, "'length' cannot be negative") + ctype = self.ctype + assert isinstance(ctype, W_CTypePtrOrArray) + with self as ptr: + if not ptr: + raise oefmt(space.w_RuntimeError, + "cannot use unpack() on %s", + space.str_w(self.repr())) + w_result = ctype.ctitem.unpack_ptr(ctype, ptr, length) + return w_result + class W_CDataMem(W_CData): """This is used only by the results of cffi.cast('int', x) diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py --- a/pypy/module/_cffi_backend/ctypearray.py +++ b/pypy/module/_cffi_backend/ctypearray.py @@ -109,21 +109,6 @@ def typeoffsetof_index(self, index): return self.ctptr.typeoffsetof_index(index) - def rawstring(self, w_cdata): - if isinstance(self.ctitem, ctypeprim.W_CTypePrimitive): - space = self.space - length = w_cdata.get_array_length() - if self.ctitem.size == rffi.sizeof(lltype.Char): - with w_cdata as ptr: - s = rffi.charpsize2str(ptr, length) - return space.wrapbytes(s) - elif self.is_unichar_ptr_or_array(): - with w_cdata as ptr: - cdata = rffi.cast(rffi.CWCHARP, ptr) - u = rffi.wcharpsize2unicode(cdata, length) - return space.wrap(u) - return W_CTypePtrOrArray.rawstring(self, w_cdata) - class W_CDataIter(W_Root): _immutable_fields_ = ['ctitem', 'cdata', '_stop'] # but not '_next' diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py --- a/pypy/module/_cffi_backend/ctypeobj.py +++ b/pypy/module/_cffi_backend/ctypeobj.py @@ -49,10 +49,10 @@ def is_unichar_ptr_or_array(self): return False - def unpack_list_of_int_items(self, cdata): + def unpack_list_of_int_items(self, ptr, length): return None - def unpack_list_of_float_items(self, cdata): + def unpack_list_of_float_items(self, ptr, length): return None def pack_list_of_items(self, cdata, w_ob): @@ -127,11 +127,20 @@ raise oefmt(space.w_TypeError, "string(): unexpected cdata '%s' argument", self.name) - def rawstring(self, cdataobj): + def unpack_ptr(self, w_ctypeptr, ptr, length): + # generic implementation, when the type of items is not known to + # be one for which a fast-case exists space = self.space - raise oefmt(space.w_TypeError, - "expected a 'char[]' or 'uint8_t[]' or 'int8_t[]' " - "or 'wchar_t[]', got '%s'", self.name) + itemsize = self.size + if itemsize < 0: + raise oefmt(space.w_ValueError, + "'%s' points to items of unknown size", + w_ctypeptr.name) + result_w = [None] * length + for i in range(length): + result_w[i] = self.convert_to_object(ptr) + ptr = rffi.ptradd(ptr, itemsize) + return space.newlist(result_w) def add(self, cdata, i): space = self.space diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -87,6 +87,13 @@ return self.space.wrapbytes(s) return W_CType.string(self, cdataobj, maxlen) + def unpack_ptr(self, w_ctypeptr, ptr, length): + result = self.unpack_list_of_int_items(ptr, length) + if result is not None: + return self.space.newlist_int(result) + return W_CType.unpack_ptr(self, w_ctypeptr, ptr, length) + + class W_CTypePrimitiveCharOrUniChar(W_CTypePrimitive): _attrs_ = [] is_primitive_integer = True @@ -125,6 +132,10 @@ value = self._convert_to_char(w_ob) cdata[0] = value + def unpack_ptr(self, w_ctypeptr, ptr, length): + s = rffi.charpsize2str(ptr, length) + return self.space.wrapbytes(s) + # XXX explicitly use an integer type instead of lltype.UniChar here, # because for now the latter is defined as unsigned by RPython (even @@ -171,6 +182,10 @@ value = self._convert_to_unichar(w_ob) rffi.cast(rffi.CWCHARP, cdata)[0] = value + def unpack_ptr(self, w_ctypeptr, ptr, length): + u = rffi.wcharpsize2unicode(rffi.cast(rffi.CWCHARP, ptr), length) + return self.space.wrap(u) + class W_CTypePrimitiveSigned(W_CTypePrimitive): _attrs_ = ['value_fits_long', 'value_smaller_than_long'] @@ -221,19 +236,16 @@ def write_raw_integer_data(self, w_cdata, value): w_cdata.write_raw_signed_data(value) - def unpack_list_of_int_items(self, w_cdata): + def unpack_list_of_int_items(self, ptr, length): if self.size == rffi.sizeof(rffi.LONG): from rpython.rlib.rrawarray import populate_list_from_raw_array res = [] - length = w_cdata.get_array_length() - with w_cdata as ptr: - buf = rffi.cast(rffi.LONGP, ptr) - populate_list_from_raw_array(res, buf, length) + buf = rffi.cast(rffi.LONGP, ptr) + populate_list_from_raw_array(res, buf, length) return res elif self.value_smaller_than_long: - res = [0] * w_cdata.get_array_length() - with w_cdata as ptr: - misc.unpack_list_from_raw_array(res, ptr, self.size) + res = [0] * length + misc.unpack_list_from_raw_array(res, ptr, self.size) return res return None @@ -313,11 +325,10 @@ def write_raw_integer_data(self, w_cdata, value): w_cdata.write_raw_unsigned_data(value) - def unpack_list_of_int_items(self, w_cdata): + def unpack_list_of_int_items(self, ptr, length): if self.value_fits_long: - res = [0] * w_cdata.get_array_length() - with w_cdata as ptr: - misc.unpack_unsigned_list_from_raw_array(res, ptr, self.size) + res = [0] * length + misc.unpack_unsigned_list_from_raw_array(res, ptr, self.size) return res return None @@ -391,19 +402,16 @@ value = space.float_w(space.float(w_ob)) misc.write_raw_float_data(cdata, value, self.size) - def unpack_list_of_float_items(self, w_cdata): + def unpack_list_of_float_items(self, ptr, length): if self.size == rffi.sizeof(rffi.DOUBLE): from rpython.rlib.rrawarray import populate_list_from_raw_array res = [] - length = w_cdata.get_array_length() - with w_cdata as ptr: - buf = rffi.cast(rffi.DOUBLEP, ptr) - populate_list_from_raw_array(res, buf, length) + buf = rffi.cast(rffi.DOUBLEP, ptr) + populate_list_from_raw_array(res, buf, length) return res elif self.size == rffi.sizeof(rffi.FLOAT): - res = [0.0] * w_cdata.get_array_length() - with w_cdata as ptr: - misc.unpack_cfloat_list_from_raw_array(res, ptr) + res = [0.0] * length + misc.unpack_cfloat_list_from_raw_array(res, ptr) return res return None @@ -421,6 +429,12 @@ return True return W_CTypePrimitive.pack_list_of_items(self, cdata, w_ob) + def unpack_ptr(self, w_ctypeptr, ptr, length): + result = self.unpack_list_of_float_items(ptr, length) + if result is not None: + return self.space.newlist_float(result) + return W_CType.unpack_ptr(self, w_ctypeptr, ptr, length) + class W_CTypePrimitiveLongDouble(W_CTypePrimitiveFloat): _attrs_ = [] diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -542,19 +542,23 @@ return w_cdata.ctype.string(w_cdata, maxlen) - @unwrap_spec(w_cdata=W_CData) - def descr_rawstring(self, w_cdata): - """\ -Convert a cdata that is an array of 'char' or 'wchar_t' to -a byte or unicode string. Unlike ffi.string(), it does not stop -at the first null. + @unwrap_spec(w_cdata=W_CData, length=int) + def descr_unpack(self, w_cdata, length): + """Unpack an array of C data of the given length, +returning a Python string/unicode/list. -Note that if you have a pointer and an explicit length, you -can use 'p[0:length]' to make an array view. This is similar to -the construct 'list(p[0:length])', which returns a list of chars/ -unichars/ints/floats.""" +If 'cdata' is a pointer to 'char', returns a byte string. +It does not stop at the first null. This is equivalent to: +ffi.buffer(cdata, length)[:] + +If 'cdata' is a pointer to 'wchar_t', returns a unicode string. +'length' is measured in wchar_t's; it is not the size in bytes. + +If 'cdata' is a pointer to anything else, returns a list of +'length' items. This is a faster equivalent to: +[cdata[i] for i in range(length)]""" # - return w_cdata.ctype.rawstring(w_cdata) + return w_cdata.unpack(length) def descr_sizeof(self, w_arg): @@ -626,6 +630,38 @@ return w_result + def descr_list_types(self): + """\ +Returns the user type names known to this FFI instance. +This returns a tuple containing three lists of names: +(typedef_names, names_of_structs, names_of_unions)""" + # + space = self.space + ctx = self.ctxobj.ctx + + lst1_w = [] + for i in range(rffi.getintfield(ctx, 'c_num_typenames')): + s = rffi.charp2str(ctx.c_typenames[i].c_name) + lst1_w.append(space.wrap(s)) + + lst2_w = [] + lst3_w = [] + for i in range(rffi.getintfield(ctx, 'c_num_struct_unions')): + su = ctx.c_struct_unions[i] + if su.c_name[0] == '$': + continue + s = rffi.charp2str(su.c_name) + if rffi.getintfield(su, 'c_flags') & cffi_opcode.F_UNION: + lst_w = lst3_w + else: + lst_w = lst2_w + lst_w.append(space.wrap(s)) + + return space.newtuple([space.newlist(lst1_w), + space.newlist(lst2_w), + space.newlist(lst3_w)]) + + def descr_init_once(self, w_func, w_tag): """\ init_once(function, tag): run function() once. More precisely, @@ -746,13 +782,14 @@ getctype = interp2app(W_FFIObject.descr_getctype), init_once = interp2app(W_FFIObject.descr_init_once), integer_const = interp2app(W_FFIObject.descr_integer_const), + list_types = interp2app(W_FFIObject.descr_list_types), memmove = interp2app(W_FFIObject.descr_memmove), new = interp2app(W_FFIObject.descr_new), new_allocator = interp2app(W_FFIObject.descr_new_allocator), new_handle = interp2app(W_FFIObject.descr_new_handle), offsetof = interp2app(W_FFIObject.descr_offsetof), - rawstring = interp2app(W_FFIObject.descr_rawstring), sizeof = interp2app(W_FFIObject.descr_sizeof), string = interp2app(W_FFIObject.descr_string), typeof = interp2app(W_FFIObject.descr_typeof), + unpack = interp2app(W_FFIObject.descr_unpack), **_extras) diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py --- a/pypy/module/_cffi_backend/func.py +++ b/pypy/module/_cffi_backend/func.py @@ -78,9 +78,9 @@ # ____________________________________________________________ -@unwrap_spec(w_cdata=cdataobj.W_CData) -def rawstring(space, w_cdata): - return w_cdata.ctype.rawstring(w_cdata) +@unwrap_spec(w_cdata=cdataobj.W_CData, length=int) +def unpack(space, w_cdata, length): + return w_cdata.unpack(length) # ____________________________________________________________ diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.5.2", ("This test_c.py file is for testing a version" +assert __version__ == "1.6.0", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") if sys.version_info < (3,): @@ -3515,21 +3515,71 @@ _get_common_types(d) assert d['bool'] == '_Bool' -def test_rawstring(): +def test_unpack(): BChar = new_primitive_type("char") BArray = new_array_type(new_pointer_type(BChar), 10) # char[10] - p = newp(BArray, "abc\x00def") - assert rawstring(p) == "abc\x00def\x00\x00\x00" - assert rawstring(p[1:6]) == "bc\x00de" + p = newp(BArray, b"abc\x00def") + p0 = p + assert unpack(p, 10) == b"abc\x00def\x00\x00\x00" + assert unpack(p+1, 5) == b"bc\x00de" BWChar = new_primitive_type("wchar_t") BArray = new_array_type(new_pointer_type(BWChar), 10) # wchar_t[10] p = newp(BArray, u"abc\x00def") - assert rawstring(p) == u"abc\x00def\x00\x00\x00" - assert rawstring(p[1:6]) == u"bc\x00de" - BChar = new_primitive_type("uint8_t") - BArray = new_array_type(new_pointer_type(BChar), 10) # uint8_t[10] - p = newp(BArray, [65 + i for i in range(10)]) - assert rawstring(p) == "ABCDEFGHIJ" + assert unpack(p, 10) == u"abc\x00def\x00\x00\x00" + + for typename, samples in [ + ("uint8_t", [0, 2**8-1]), + ("uint16_t", [0, 2**16-1]), + ("uint32_t", [0, 2**32-1]), + ("uint64_t", [0, 2**64-1]), + ("int8_t", [-2**7, 2**7-1]), + ("int16_t", [-2**15, 2**15-1]), + ("int32_t", [-2**31, 2**31-1]), + ("int64_t", [-2**63, 2**63-1]), + ("_Bool", [0, 1]), + ("float", [0.0, 10.5]), + ("double", [12.34, 56.78]), + ]: + BItem = new_primitive_type(typename) + BArray = new_array_type(new_pointer_type(BItem), 10) + p = newp(BArray, samples) + result = unpack(p, len(samples)) + assert result == samples + for i in range(len(samples)): + assert result[i] == p[i] and type(result[i]) is type(p[i]) # - py.test.raises(TypeError, rawstring, "foobar") - py.test.raises(TypeError, rawstring, p + 1) + BInt = new_primitive_type("int") + py.test.raises(TypeError, unpack, p) + py.test.raises(TypeError, unpack, b"foobar", 6) + py.test.raises(TypeError, unpack, cast(BInt, 42), 1) + # + BPtr = new_pointer_type(BInt) + random_ptr = cast(BPtr, -424344) + other_ptr = cast(BPtr, 54321) + BArray = new_array_type(new_pointer_type(BPtr), None) + lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2) + assert lst == [random_ptr, other_ptr] + # + BFunc = new_function_type((BInt, BInt), BInt, False) + BFuncPtr = new_pointer_type(BFunc) + lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2) + assert len(lst) == 2 + assert not lst[0] and not lst[1] + assert typeof(lst[0]) is BFunc + # + BStruct = new_struct_type("foo") + BStructPtr = new_pointer_type(BStruct) + e = py.test.raises(ValueError, unpack, cast(BStructPtr, 42), 5) + assert str(e.value) == "'foo *' points to items of unknown size" + complete_struct_or_union(BStruct, [('a1', BInt, -1), + ('a2', BInt, -1)]) + array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]]) + lst = unpack(array_of_structs, 2) + assert typeof(lst[0]) is BStruct + assert lst[0].a1 == 4 and lst[1].a2 == 7 + # + py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0) + py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10) + # + py.test.raises(ValueError, unpack, p0, -1) + py.test.raises(ValueError, unpack, p, -1) diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py --- a/pypy/module/_cffi_backend/test/test_ffi_obj.py +++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py @@ -477,15 +477,10 @@ raises(ValueError, ffi.init_once, do_init, "tag") assert seen == [1] * (i + 1) - def test_rawstring(self): + def test_unpack(self): import _cffi_backend as _cffi1_backend ffi = _cffi1_backend.FFI() - p = ffi.new("char[]", "abc\x00def") - assert ffi.rawstring(p) == "abc\x00def\x00" - assert ffi.rawstring(p[1:6]) == "bc\x00de" - p = ffi.new("wchar_t[]", u"abc\x00def") - assert ffi.rawstring(p) == u"abc\x00def\x00" - assert ffi.rawstring(p[1:6]) == u"bc\x00de" - # - raises(TypeError, ffi.rawstring, "foobar") - raises(TypeError, ffi.rawstring, p + 1) + p = ffi.new("char[]", b"abc\x00def") + assert ffi.unpack(p+1, 7) == b"bc\x00def\x00" + p = ffi.new("int[]", [-123456789]) + assert ffi.unpack(p, 1) == [-123456789] diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py --- a/pypy/module/_cffi_backend/test/test_recompiler.py +++ b/pypy/module/_cffi_backend/test/test_recompiler.py @@ -1626,3 +1626,150 @@ # a case where 'onerror' is not callable raises(TypeError, ffi.def_extern(name='bar', onerror=42), lambda x: x) + + def test_extern_python_stdcall(self): + ffi, lib = self.prepare(""" + extern "Python" int __stdcall foo(int); + extern "Python" int WINAPI bar(int); + int (__stdcall * mycb1)(int); + int indirect_call(int); + """, 'test_extern_python_stdcall', """ + #ifndef _MSC_VER + # define __stdcall + #endif + static int (__stdcall * mycb1)(int); + static int indirect_call(int x) { + return mycb1(x); + } + """) + # + @ffi.def_extern() + def foo(x): + return x + 42 + @ffi.def_extern() + def bar(x): + return x + 43 + assert lib.foo(100) == 142 + assert lib.bar(100) == 143 + lib.mycb1 = lib.foo + assert lib.mycb1(200) == 242 + assert lib.indirect_call(300) == 342 + + def test_introspect_function(self): + ffi, lib = self.prepare(""" + float f1(double); + """, 'test_introspect_function', """ + float f1(double x) { return x; } + """) + assert dir(lib) == ['f1'] + FUNC = ffi.typeof(lib.f1) + assert FUNC.kind == 'function' + assert FUNC.args[0].cname == 'double' + assert FUNC.result.cname == 'float' + assert ffi.typeof(ffi.addressof(lib, 'f1')) is FUNC + + def test_introspect_global_var(self): + ffi, lib = self.prepare(""" + float g1; + """, 'test_introspect_global_var', """ + float g1; + """) + assert dir(lib) == ['g1'] + FLOATPTR = ffi.typeof(ffi.addressof(lib, 'g1')) + assert FLOATPTR.kind == 'pointer' + assert FLOATPTR.item.cname == 'float' + + def test_introspect_global_var_array(self): + ffi, lib = self.prepare(""" + float g1[100]; + """, 'test_introspect_global_var_array', """ + float g1[100]; + """) + assert dir(lib) == ['g1'] + FLOATARRAYPTR = ffi.typeof(ffi.addressof(lib, 'g1')) + assert FLOATARRAYPTR.kind == 'pointer' + assert FLOATARRAYPTR.item.kind == 'array' + assert FLOATARRAYPTR.item.length == 100 + assert ffi.typeof(lib.g1) is FLOATARRAYPTR.item + + def test_introspect_integer_const(self): + ffi, lib = self.prepare("#define FOO 42", + 'test_introspect_integer_const', """ + #define FOO 42 + """) + assert dir(lib) == ['FOO'] + assert lib.FOO == ffi.integer_const('FOO') == 42 + + def test_introspect_typedef(self): + ffi, lib = self.prepare("typedef int foo_t;", + 'test_introspect_typedef', """ + typedef int foo_t; + """) + assert ffi.list_types() == (['foo_t'], [], []) + assert ffi.typeof('foo_t').kind == 'primitive' + assert ffi.typeof('foo_t').cname == 'int' + + def test_introspect_typedef_multiple(self): + ffi, lib = self.prepare(""" + typedef signed char a_t, c_t, g_t, b_t; + """, 'test_introspect_typedef_multiple', """ + typedef signed char a_t, c_t, g_t, b_t; + """) + assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'g_t'], [], []) + + def test_introspect_struct(self): + ffi, lib = self.prepare(""" + struct foo_s { int a; }; + """, 'test_introspect_struct', """ + struct foo_s { int a; }; + """) + assert ffi.list_types() == ([], ['foo_s'], []) + assert ffi.typeof('struct foo_s').kind == 'struct' + assert ffi.typeof('struct foo_s').cname == 'struct foo_s' + + def test_introspect_union(self): + ffi, lib = self.prepare(""" + union foo_s { int a; }; + """, 'test_introspect_union', """ + union foo_s { int a; }; + """) + assert ffi.list_types() == ([], [], ['foo_s']) + assert ffi.typeof('union foo_s').kind == 'union' + assert ffi.typeof('union foo_s').cname == 'union foo_s' + + def test_introspect_struct_and_typedef(self): + ffi, lib = self.prepare(""" + typedef struct { int a; } foo_t; + """, 'test_introspect_struct_and_typedef', """ + typedef struct { int a; } foo_t; + """) + assert ffi.list_types() == (['foo_t'], [], []) + assert ffi.typeof('foo_t').kind == 'struct' + assert ffi.typeof('foo_t').cname == 'foo_t' + + def test_introspect_included_type(self): + SOURCE = """ + typedef signed char schar_t; + struct sint_t { int x; }; + """ + ffi1, lib1 = self.prepare(SOURCE, + "test_introspect_included_type_parent", SOURCE) + ffi2, lib2 = self.prepare("", + "test_introspect_included_type", SOURCE, + includes=[ffi1]) + assert ffi1.list_types() == ffi2.list_types() == ( + ['schar_t'], ['sint_t'], []) + + def test_introspect_order(self): + ffi, lib = self.prepare(""" + union aaa { int a; }; typedef struct ccc { int a; } b; + union g { int a; }; typedef struct cc { int a; } bbb; + union aa { int a; }; typedef struct a { int a; } bb; + """, "test_introspect_order", """ + union aaa { int a; }; typedef struct ccc { int a; } b; + union g { int a; }; typedef struct cc { int a; } bbb; + union aa { int a; }; typedef struct a { int a; } bb; + """) + assert ffi.list_types() == (['b', 'bb', 'bbb'], + ['a', 'cc', 'ccc'], + ['aa', 'aaa', 'g']) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -32,6 +32,7 @@ 'set_string_function': 'appbridge.set_string_function', 'typeinfo': 'descriptor.get_dtype_cache(space).w_typeinfo', 'nditer': 'nditer.W_NDIter', + 'broadcast': 'broadcast.W_Broadcast', 'set_docstring': 'support.descr_set_docstring', 'VisibleDeprecationWarning': 'support.W_VisibleDeprecationWarning', diff --git a/pypy/module/micronumpy/broadcast.py b/pypy/module/micronumpy/broadcast.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/broadcast.py @@ -0,0 +1,110 @@ +import pypy.module.micronumpy.constants as NPY +from nditer import ConcreteIter, parse_op_flag, parse_op_arg +from pypy.interpreter.error import OperationError, oefmt +from pypy.interpreter.gateway import interp2app +from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.module.micronumpy import support +from pypy.module.micronumpy.base import W_NDimArray, convert_to_array, W_NumpyObject +from rpython.rlib import jit +from strides import calculate_broadcast_strides, shape_agreement_multiple + +def descr_new_broadcast(space, w_subtype, __args__): + return W_Broadcast(space, __args__.arguments_w) + +class W_Broadcast(W_NumpyObject): + """ + Implementation of numpy.broadcast. + This class is a simplified version of nditer.W_NDIter with fixed iteration for broadcasted arrays. + """ + + def __init__(self, space, args): + num_args = len(args) + if not (2 <= num_args <= NPY.MAXARGS): + raise oefmt(space.w_ValueError, + "Need at least two and fewer than (%d) array objects.", NPY.MAXARGS) + + self.seq = [convert_to_array(space, w_elem) + for w_elem in args] + + self.op_flags = parse_op_arg(space, 'op_flags', space.w_None, + len(self.seq), parse_op_flag) + + self.shape = shape_agreement_multiple(space, self.seq, shape=None) + self.order = NPY.CORDER + + self.iters = [] + self.index = 0 + + try: + self.size = support.product_check(self.shape) + except OverflowError as e: + raise oefmt(space.w_ValueError, "broadcast dimensions too large.") + for i in range(len(self.seq)): + it = self.get_iter(space, i) + it.contiguous = False + self.iters.append((it, it.reset())) + + self.done = False + pass + + def get_iter(self, space, i): + arr = self.seq[i] + imp = arr.implementation + if arr.is_scalar(): + return ConcreteIter(imp, 1, [], [], [], self.op_flags[i], self) + shape = self.shape + + backward = imp.order != self.order + + r = calculate_broadcast_strides(imp.strides, imp.backstrides, imp.shape, + shape, backward) + + iter_shape = shape + if len(shape) != len(r[0]): + # shape can be shorter when using an external loop, just return a view + iter_shape = imp.shape + return ConcreteIter(imp, imp.get_size(), iter_shape, r[0], r[1], + self.op_flags[i], self) + + def descr_iter(self, space): + return space.wrap(self) + + def descr_get_shape(self, space): + return space.newtuple([space.wrap(i) for i in self.shape]) + + def descr_get_size(self, space): + return space.wrap(self.size) + + def descr_get_index(self, space): + return space.wrap(self.index) + + def descr_get_numiter(self, space): + return space.wrap(len(self.iters)) + + @jit.unroll_safe + def descr_next(self, space): + if self.index >= self.size: + self.done = True + raise OperationError(space.w_StopIteration, space.w_None) + self.index += 1 + res = [] + for i, (it, st) in enumerate(self.iters): + res.append(self._get_item(it, st)) + self.iters[i] = (it, it.next(st)) + if len(res) < 2: + return res[0] + return space.newtuple(res) + + def _get_item(self, it, st): + return W_NDimArray(it.getoperand(st)) + + +W_Broadcast.typedef = TypeDef("numpy.broadcast", + __new__=interp2app(descr_new_broadcast), + __iter__=interp2app(W_Broadcast.descr_iter), + next=interp2app(W_Broadcast.descr_next), + shape=GetSetProperty(W_Broadcast.descr_get_shape), + size=GetSetProperty(W_Broadcast.descr_get_size), + index=GetSetProperty(W_Broadcast.descr_get_index), + numiter=GetSetProperty(W_Broadcast.descr_get_numiter), + ) diff --git a/pypy/module/micronumpy/constants.py b/pypy/module/micronumpy/constants.py --- a/pypy/module/micronumpy/constants.py +++ b/pypy/module/micronumpy/constants.py @@ -77,6 +77,8 @@ WRAP = 1 RAISE = 2 +MAXARGS = 32 + # These can be requested in constructor functions and tested for ARRAY_C_CONTIGUOUS = 0x0001 ARRAY_F_CONTIGUOUS = 0x0002 diff --git a/pypy/module/micronumpy/test/test_broadcast.py b/pypy/module/micronumpy/test/test_broadcast.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_broadcast.py @@ -0,0 +1,97 @@ +# -*- encoding: utf-8 -*- + +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + + +class AppTestArrayBroadcast(BaseNumpyAppTest): + def test_broadcast_for_row_and_column(self): + import numpy as np + x = np.array([[1], [2], [3]]) + y = np.array([4, 5]) + b = list(np.broadcast(x, y)) + assert b == [(1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)] + + def test_broadcast_properties(self): + import numpy as np + x = np.array([[1], [2], [3]]) + y = np.array([4, 5]) + b = np.broadcast(x, y) + + assert b.shape == (3, 2) + assert b.size == 6 + assert b.index == 0 + + b.next() + b.next() + + assert b.shape == (3, 2) + assert b.size == 6 + assert b.index == 2 + + def test_broadcast_from_doctest(self): + """ + Test from numpy.broadcast doctest. + """ + import numpy as np + x = np.array([[1], [2], [3]]) + y = np.array([4, 5, 6]) + reference = np.array([[5., 6., 7.], + [6., 7., 8.], + [7., 8., 9.]]) + + b = np.broadcast(x, y) + out = np.empty(b.shape) + out.flat = [u + v for (u, v) in b] + + assert (reference == out).all() + assert out.dtype == reference.dtype + assert b.shape == reference.shape + + def test_broadcast_linear(self): + import numpy as np + x = np.array([1, 2, 3]) + y = np.array([4, 5, 6]) + b = list(np.broadcast(x, y)) + assert b == [(1, 4), (2, 5), (3, 6)] + assert b[0][0].dtype == x.dtype + + def test_broadcast_failures(self): + import numpy as np + import sys + x = np.array([1, 2, 3]) + y = np.array([4, 5]) + raises(ValueError, np.broadcast, x, y) + a = np.empty(2**16,dtype='int8') + a = a.reshape(-1, 1, 1, 1) + b = a.reshape(1, -1, 1, 1) + c = a.reshape(1, 1, -1, 1) + d = a.reshape(1, 1, 1, -1) + exc = raises(ValueError, np.broadcast, a, b, c, d) + assert exc.value[0] == ('broadcast dimensions too large.') + + def test_broadcast_3_args(self): + import numpy as np + x = np.array([[[1]], [[2]], [[3]]]) + y = np.array([[[40], [50]]]) + z = np.array([[[700, 800]]]) + + b = list(np.broadcast(x, y, z)) + + assert b == [(1, 40, 700), (1, 40, 800), (1, 50, 700), (1, 50, 800), + (2, 40, 700), (2, 40, 800), (2, 50, 700), (2, 50, 800), + (3, 40, 700), (3, 40, 800), (3, 50, 700), (3, 50, 800)] + + def test_number_of_arguments(self): + """ + Test from numpy unit tests. + """ + import numpy as np + arr = np.empty((5,)) + for j in range(35): + arrs = [arr] * j + if j < 2 or j > 32: + exc = raises(ValueError, np.broadcast, *arrs) + assert exc.value[0] == ('Need at least two and fewer than (32) array objects.') + else: + mit = np.broadcast(*arrs) + assert mit.numiter == j diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ffi_backend.py @@ -424,3 +424,59 @@ def test_ffi_def_extern(self): ffi = FFI() py.test.raises(ValueError, ffi.def_extern) + + def test_introspect_typedef(self): + ffi = FFI() + ffi.cdef("typedef int foo_t;") + assert ffi.list_types() == (['foo_t'], [], []) + assert ffi.typeof('foo_t').kind == 'primitive' + assert ffi.typeof('foo_t').cname == 'int' + # + ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;") + assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'foo_t', 'g_t'], + [], []) + + def test_introspect_struct(self): + ffi = FFI() + ffi.cdef("struct foo_s { int a; };") + assert ffi.list_types() == ([], ['foo_s'], []) + assert ffi.typeof('struct foo_s').kind == 'struct' + assert ffi.typeof('struct foo_s').cname == 'struct foo_s' + + def test_introspect_union(self): + ffi = FFI() + ffi.cdef("union foo_s { int a; };") + assert ffi.list_types() == ([], [], ['foo_s']) + assert ffi.typeof('union foo_s').kind == 'union' + assert ffi.typeof('union foo_s').cname == 'union foo_s' + + def test_introspect_struct_and_typedef(self): + ffi = FFI() + ffi.cdef("typedef struct { int a; } foo_t;") + assert ffi.list_types() == (['foo_t'], [], []) + assert ffi.typeof('foo_t').kind == 'struct' + assert ffi.typeof('foo_t').cname == 'foo_t' + + def test_introspect_included_type(self): + ffi1 = FFI() + ffi2 = FFI() + ffi1.cdef("typedef signed char schar_t; struct sint_t { int x; };") + ffi2.include(ffi1) + assert ffi1.list_types() == ffi2.list_types() == ( + ['schar_t'], ['sint_t'], []) + + def test_introspect_order(self): + ffi = FFI() + ffi.cdef("union aaa { int a; }; typedef struct ccc { int a; } b;") + ffi.cdef("union g { int a; }; typedef struct cc { int a; } bbb;") + ffi.cdef("union aa { int a; }; typedef struct a { int a; } bb;") + assert ffi.list_types() == (['b', 'bb', 'bbb'], + ['a', 'cc', 'ccc'], + ['aa', 'aaa', 'g']) + + def test_unpack(self): + ffi = FFI() + p = ffi.new("char[]", b"abc\x00def") + assert ffi.unpack(p+1, 7) == b"bc\x00def\x00" + p = ffi.new("int[]", [-123456789]) + assert ffi.unpack(p, 1) == [-123456789] diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py @@ -496,3 +496,10 @@ assert i < 20 time.sleep(0.51) assert seen == ['init!', 'oops'] * 3 + +def test_unpack(): + ffi = _cffi1_backend.FFI() + p = ffi.new("char[]", b"abc\x00def") + assert ffi.unpack(p+1, 7) == b"bc\x00def\x00" + p = ffi.new("int[]", [-123456789]) + assert ffi.unpack(p, 1) == [-123456789] diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -1744,3 +1744,125 @@ lib.mycb1 = lib.foo assert lib.mycb1(200) == 242 assert lib.indirect_call(300) == 342 + +def test_introspect_function(): + ffi = FFI() + ffi.cdef("float f1(double);") + lib = verify(ffi, 'test_introspect_function', """ + float f1(double x) { return x; } + """) + assert dir(lib) == ['f1'] + FUNC = ffi.typeof(lib.f1) + assert FUNC.kind == 'function' + assert FUNC.args[0].cname == 'double' + assert FUNC.result.cname == 'float' + assert ffi.typeof(ffi.addressof(lib, 'f1')) is FUNC + +def test_introspect_global_var(): + ffi = FFI() + ffi.cdef("float g1;") + lib = verify(ffi, 'test_introspect_global_var', """ + float g1; + """) + assert dir(lib) == ['g1'] + FLOATPTR = ffi.typeof(ffi.addressof(lib, 'g1')) + assert FLOATPTR.kind == 'pointer' + assert FLOATPTR.item.cname == 'float' + +def test_introspect_global_var_array(): + ffi = FFI() + ffi.cdef("float g1[100];") + lib = verify(ffi, 'test_introspect_global_var_array', """ + float g1[100]; + """) + assert dir(lib) == ['g1'] + FLOATARRAYPTR = ffi.typeof(ffi.addressof(lib, 'g1')) + assert FLOATARRAYPTR.kind == 'pointer' + assert FLOATARRAYPTR.item.kind == 'array' + assert FLOATARRAYPTR.item.length == 100 + assert ffi.typeof(lib.g1) is FLOATARRAYPTR.item + +def test_introspect_integer_const(): + ffi = FFI() + ffi.cdef("#define FOO 42") + lib = verify(ffi, 'test_introspect_integer_const', """ + #define FOO 42 + """) + assert dir(lib) == ['FOO'] + assert lib.FOO == ffi.integer_const('FOO') == 42 + +def test_introspect_typedef(): + ffi = FFI() + ffi.cdef("typedef int foo_t;") + lib = verify(ffi, 'test_introspect_typedef', """ + typedef int foo_t; + """) + assert ffi.list_types() == (['foo_t'], [], []) + assert ffi.typeof('foo_t').kind == 'primitive' + assert ffi.typeof('foo_t').cname == 'int' + +def test_introspect_typedef_multiple(): + ffi = FFI() + ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;") + lib = verify(ffi, 'test_introspect_typedef_multiple', """ + typedef signed char a_t, c_t, g_t, b_t; + """) + assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'g_t'], [], []) + +def test_introspect_struct(): + ffi = FFI() + ffi.cdef("struct foo_s { int a; };") + lib = verify(ffi, 'test_introspect_struct', """ + struct foo_s { int a; }; + """) + assert ffi.list_types() == ([], ['foo_s'], []) + assert ffi.typeof('struct foo_s').kind == 'struct' + assert ffi.typeof('struct foo_s').cname == 'struct foo_s' + +def test_introspect_union(): + ffi = FFI() + ffi.cdef("union foo_s { int a; };") + lib = verify(ffi, 'test_introspect_union', """ + union foo_s { int a; }; + """) + assert ffi.list_types() == ([], [], ['foo_s']) + assert ffi.typeof('union foo_s').kind == 'union' + assert ffi.typeof('union foo_s').cname == 'union foo_s' + +def test_introspect_struct_and_typedef(): + ffi = FFI() + ffi.cdef("typedef struct { int a; } foo_t;") + lib = verify(ffi, 'test_introspect_struct_and_typedef', """ + typedef struct { int a; } foo_t; + """) + assert ffi.list_types() == (['foo_t'], [], []) + assert ffi.typeof('foo_t').kind == 'struct' + assert ffi.typeof('foo_t').cname == 'foo_t' + +def test_introspect_included_type(): + SOURCE = """ + typedef signed char schar_t; + struct sint_t { int x; }; + """ + ffi1 = FFI() + ffi1.cdef(SOURCE) + ffi2 = FFI() + ffi2.include(ffi1) + verify(ffi1, "test_introspect_included_type_parent", SOURCE) + verify(ffi2, "test_introspect_included_type", SOURCE) + assert ffi1.list_types() == ffi2.list_types() == ( + ['schar_t'], ['sint_t'], []) + +def test_introspect_order(): + ffi = FFI() + ffi.cdef("union aaa { int a; }; typedef struct ccc { int a; } b;") + ffi.cdef("union g { int a; }; typedef struct cc { int a; } bbb;") + ffi.cdef("union aa { int a; }; typedef struct a { int a; } bb;") + verify(ffi, "test_introspect_order", """ + union aaa { int a; }; typedef struct ccc { int a; } b; + union g { int a; }; typedef struct cc { int a; } bbb; + union aa { int a; }; typedef struct a { int a; } bb; + """) + assert ffi.list_types() == (['b', 'bb', 'bbb'], + ['a', 'cc', 'ccc'], + ['aa', 'aaa', 'g']) diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py @@ -695,25 +695,14 @@ assert ffi.string(ffi.cast('enum ee', 11)) == "EE2" assert ffi.string(ffi.cast('enum ee', -10)) == "EE3" # - # try again - ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };") - assert ffi.string(ffi.cast('enum ee', 11)) == "EE2" - # assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3': -10} assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'} def test_full_enum(): ffi = FFI() ffi.cdef("enum ee { EE1, EE2, EE3 };") - ffi.verify("enum ee { EE1, EE2, EE3 };") - py.test.raises(VerificationError, ffi.verify, "enum ee { EE1, EE2 };") - # disabled: for now, we always accept and fix transparently constant values - #e = py.test.raises(VerificationError, ffi.verify, - # "enum ee { EE1, EE3, EE2 };") - #assert str(e.value) == 'enum ee: EE2 has the real value 2, not 1' - # extra items cannot be seen and have no bad consequence anyway - lib = ffi.verify("enum ee { EE1, EE2, EE3, EE4 };") - assert lib.EE3 == 2 + lib = ffi.verify("enum ee { EE1, EE2, EE3 };") + assert [lib.EE1, lib.EE2, lib.EE3] == [0, 1, 2] def test_enum_usage(): ffi = FFI() diff --git a/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py b/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py --- a/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py +++ b/pypy/module/test_lib_pypy/cffi_tests/embedding/test_basic.py @@ -143,7 +143,7 @@ env_extra[envname] = libpath for key, value in sorted(env_extra.items()): if os.environ.get(key) != value: - print '* setting env var %r to %r' % (key, value) + print('* setting env var %r to %r' % (key, value)) os.environ[key] = value def execute(self, name): @@ -165,6 +165,9 @@ class TestBasic(EmbeddingTests): + def test_empty(self): + empty_cffi = self.prepare_module('empty') + def test_basic(self): add1_cffi = self.prepare_module('add1') self.compile('add1-test', [add1_cffi]) diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -205,6 +205,12 @@ storage = strategy.erase(list_i) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + @staticmethod + def newlist_float(space, list_f): + strategy = space.fromcache(FloatListStrategy) + storage = strategy.erase(list_f) + return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def __repr__(self): """ representation for debugging purposes """ return "%s(%s, %s)" % (self.__class__.__name__, self.strategy, diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -310,6 +310,9 @@ def newlist_int(self, list_i): return W_ListObject.newlist_int(self, list_i) + def newlist_float(self, list_f): + return W_ListObject.newlist_float(self, list_f) + def newdict(self, module=False, instance=False, kwargs=False, strdict=False): return W_DictMultiObject.allocate_and_init_instance( diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -4510,7 +4510,10 @@ continue w = t[2].split() if len(w) == 0: - continue + if '<UNDEFINED>' in line: + w = ['UNDEFINED'] + else: + continue words.append(w[0] + ';') print '[[%s]]' % (w[0],) text = ' '.join(words) diff --git a/rpython/rlib/rposix_stat.py b/rpython/rlib/rposix_stat.py --- a/rpython/rlib/rposix_stat.py +++ b/rpython/rlib/rposix_stat.py @@ -36,10 +36,9 @@ # - ALL_STAT_FIELDS contains Float fields if the system can retrieve # sub-second timestamps. # - TIMESPEC is defined when the "struct stat" contains st_atim field. - -try: +if sys.platform.startswith('linux') or sys.platform.startswith('openbsd'): from rpython.rlib.rposix import TIMESPEC -except ImportError: +else: TIMESPEC = None _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit