Author: mattip <matti.pi...@gmail.com> Branch: ufuncapi Changeset: r75362:a0cbd2bf13da Date: 2015-01-15 21:55 +0200 http://bitbucket.org/pypy/pypy/changeset/a0cbd2bf13da/
Log: merge default into branch diff too long, truncating to 2000 out of 6448 lines diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -28,7 +28,7 @@ DEALINGS IN THE SOFTWARE. -PyPy Copyright holders 2003-2014 +PyPy Copyright holders 2003-2015 ----------------------------------- Except when otherwise stated (look for LICENSE files or information at diff --git a/lib-python/2.7/distutils/unixccompiler.py b/lib-python/2.7/distutils/unixccompiler.py --- a/lib-python/2.7/distutils/unixccompiler.py +++ b/lib-python/2.7/distutils/unixccompiler.py @@ -58,7 +58,7 @@ executables = {'preprocessor' : None, 'compiler' : ["cc"], 'compiler_so' : ["cc"], - 'compiler_cxx' : ["cc"], + 'compiler_cxx' : ["c++"], # pypy: changed, 'cc' is bogus 'linker_so' : ["cc", "-shared"], 'linker_exe' : ["cc"], 'archiver' : ["ar", "-cr"], diff --git a/lib-python/2.7/subprocess.py b/lib-python/2.7/subprocess.py --- a/lib-python/2.7/subprocess.py +++ b/lib-python/2.7/subprocess.py @@ -1589,7 +1589,7 @@ 'copyfile' in caller.f_globals): dest_dir = sys.pypy_resolvedirof(target_executable) src_dir = sys.pypy_resolvedirof(sys.executable) - for libname in ['libpypy-c.so']: + for libname in ['libpypy-c.so', 'libpypy-c.dylib']: dest_library = os.path.join(dest_dir, libname) src_library = os.path.join(src_dir, libname) if os.path.exists(src_library): diff --git a/lib_pypy/_functools.py b/lib_pypy/_functools.py --- a/lib_pypy/_functools.py +++ b/lib_pypy/_functools.py @@ -9,7 +9,10 @@ of the given arguments and keywords. """ - def __init__(self, func, *args, **keywords): + def __init__(self, *args, **keywords): + if not args: + raise TypeError('__init__() takes at least 2 arguments (1 given)') + func, args = args[0], args[1:] if not callable(func): raise TypeError("the first argument must be callable") self._func = func 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 @@ -6,3 +6,8 @@ __version__ = "0.8.6" __version_info__ = (0, 8, 6) + +# 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__ +# if nothing is clearly incompatible. +__version_verifier_modules__ = "0.8.6" 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 @@ -69,6 +69,7 @@ self._function_caches = [] self._libraries = [] self._cdefsources = [] + self._windows_unicode = None if hasattr(backend, 'set_ffi'): backend.set_ffi(self) for name in backend.__dict__: @@ -77,6 +78,7 @@ # with self._lock: self.BVoidP = self._get_cached_btype(model.voidp_type) + self.BCharA = self._get_cached_btype(model.char_array_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): @@ -189,13 +191,16 @@ cdecl = self._typeof(cdecl) return self._backend.alignof(cdecl) - def offsetof(self, cdecl, fieldname): + def offsetof(self, cdecl, *fields_or_indexes): """Return the offset of the named field inside the given - structure, which must be given as a C type name. + structure or array, which must be given as a C type name. + You can give several field names in case of nested structures. + You can also give numeric values which correspond to array + items, in case of an array type. """ if isinstance(cdecl, basestring): cdecl = self._typeof(cdecl) - return self._backend.typeoffsetof(cdecl, fieldname)[1] + return self._typeoffsetof(cdecl, *fields_or_indexes)[1] def new(self, cdecl, init=None): """Allocate an instance according to the specified C type and @@ -264,6 +269,16 @@ """ return self._backend.buffer(cdata, size) + def from_buffer(self, python_buffer): + """Return a <cdata 'char[]'> that points to the data of the + given Python object, which must support the buffer interface. + Note that this is not meant to be used on the built-in types str, + unicode, or bytearray (you can build 'char[]' arrays explicitly) + but only on objects containing large quantities of raw data + in some other format, like 'array.array' or numpy arrays. + """ + return self._backend.from_buffer(self.BCharA, python_buffer) + def callback(self, cdecl, python_callable=None, error=None): """Return a callback object or a decorator making such a callback object. 'cdecl' must name a C function pointer type. @@ -335,9 +350,23 @@ which requires binary compatibility in the signatures. """ from .verifier import Verifier, _caller_dir_pycache + # + # If set_unicode(True) was called, insert the UNICODE and + # _UNICODE macro declarations + if self._windows_unicode: + self._apply_windows_unicode(kwargs) + # + # Set the tmpdir here, and not in Verifier.__init__: it picks + # up the caller's directory, which we want to be the caller of + # ffi.verify(), as opposed to the caller of Veritier(). tmpdir = tmpdir or _caller_dir_pycache() + # + # Make a Verifier() and use it to load the library. self.verifier = Verifier(self, source, tmpdir, **kwargs) lib = self.verifier.load_library() + # + # Save the loaded library for keep-alive purposes, even + # if the caller doesn't keep it alive itself (it should). self._libraries.append(lib) return lib @@ -356,15 +385,29 @@ with self._lock: return model.pointer_cache(self, ctype) - def addressof(self, cdata, field=None): + def addressof(self, cdata, *fields_or_indexes): """Return the address of a <cdata 'struct-or-union'>. - If 'field' is specified, return the address of this field. + If 'fields_or_indexes' are given, returns the address of that + field or array item in the structure or array, recursively in + case of nested structures. """ ctype = self._backend.typeof(cdata) - ctype, offset = self._backend.typeoffsetof(ctype, field) + if fields_or_indexes: + ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) + else: + if ctype.kind == "pointer": + raise TypeError("addressof(pointer)") + offset = 0 ctypeptr = self._pointer_to(ctype) return self._backend.rawaddressof(ctypeptr, cdata, offset) + def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): + ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) + for field1 in fields_or_indexes: + ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) + offset += offset1 + return ctype, offset + def include(self, ffi_to_include): """Includes the typedefs, structs, unions and enums defined in another FFI instance. Usage is similar to a #include in C, @@ -387,6 +430,44 @@ def from_handle(self, x): return self._backend.from_handle(x) + def set_unicode(self, enabled_flag): + """Windows: if 'enabled_flag' is True, enable the UNICODE and + _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR + to be (pointers to) wchar_t. If 'enabled_flag' is False, + declare these types to be (pointers to) plain 8-bit characters. + This is mostly for backward compatibility; you usually want True. + """ + if self._windows_unicode is not None: + raise ValueError("set_unicode() can only be called once") + enabled_flag = bool(enabled_flag) + if enabled_flag: + self.cdef("typedef wchar_t TBYTE;" + "typedef wchar_t TCHAR;" + "typedef const wchar_t *LPCTSTR;" + "typedef const wchar_t *PCTSTR;" + "typedef wchar_t *LPTSTR;" + "typedef wchar_t *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + else: + self.cdef("typedef char TBYTE;" + "typedef char TCHAR;" + "typedef const char *LPCTSTR;" + "typedef const char *PCTSTR;" + "typedef char *LPTSTR;" + "typedef char *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + self._windows_unicode = enabled_flag + + def _apply_windows_unicode(self, kwds): + defmacros = kwds.get('define_macros', ()) + if not isinstance(defmacros, (list, tuple)): + raise TypeError("'define_macros' must be a list or tuple") + defmacros = list(defmacros) + [('UNICODE', '1'), + ('_UNICODE', '1')] + kwds['define_macros'] = defmacros + def _load_backend_lib(backend, name, flags): if name is None: diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -169,6 +169,7 @@ class CTypesGenericPtr(CTypesData): __slots__ = ['_address', '_as_ctype_ptr'] _automatic_casts = False + kind = "pointer" @classmethod def _newp(cls, init): @@ -370,10 +371,12 @@ (CTypesPrimitive, type(source).__name__)) return source # + kind1 = kind class CTypesPrimitive(CTypesGenericPrimitive): __slots__ = ['_value'] _ctype = ctype _reftypename = '%s &' % name + kind = kind1 def __init__(self, value): self._value = value @@ -703,12 +706,13 @@ class struct_or_union(base_ctypes_class): pass struct_or_union.__name__ = '%s_%s' % (kind, name) + kind1 = kind # class CTypesStructOrUnion(CTypesBaseStructOrUnion): __slots__ = ['_blob'] _ctype = struct_or_union _reftypename = '%s &' % (name,) - _kind = kind + _kind = kind = kind1 # CTypesStructOrUnion._fix_class() return CTypesStructOrUnion @@ -994,27 +998,42 @@ def getcname(self, BType, replace_with): return BType._get_c_name(replace_with) - def typeoffsetof(self, BType, fieldname): - if fieldname is not None and issubclass(BType, CTypesGenericPtr): - BType = BType._BItem - if not issubclass(BType, CTypesBaseStructOrUnion): - raise TypeError("expected a struct or union ctype") - if fieldname is None: - return (BType, 0) - else: + def typeoffsetof(self, BType, fieldname, num=0): + if isinstance(fieldname, str): + if num == 0 and issubclass(BType, CTypesGenericPtr): + BType = BType._BItem + if not issubclass(BType, CTypesBaseStructOrUnion): + raise TypeError("expected a struct or union ctype") BField = BType._bfield_types[fieldname] if BField is Ellipsis: raise TypeError("not supported for bitfields") return (BField, BType._offsetof(fieldname)) + elif isinstance(fieldname, (int, long)): + if issubclass(BType, CTypesGenericArray): + BType = BType._CTPtr + if not issubclass(BType, CTypesGenericPtr): + raise TypeError("expected an array or ptr ctype") + BItem = BType._BItem + offset = BItem._get_size() * fieldname + if offset > sys.maxsize: + raise OverflowError + return (BItem, offset) + else: + raise TypeError(type(fieldname)) - def rawaddressof(self, BTypePtr, cdata, offset): + def rawaddressof(self, BTypePtr, cdata, offset=None): if isinstance(cdata, CTypesBaseStructOrUnion): ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) elif isinstance(cdata, CTypesGenericPtr): + if offset is None or not issubclass(type(cdata)._BItem, + CTypesBaseStructOrUnion): + raise TypeError("unexpected cdata type") + ptr = type(cdata)._to_ctypes(cdata) + elif isinstance(cdata, CTypesGenericArray): ptr = type(cdata)._to_ctypes(cdata) else: raise TypeError("expected a <cdata 'struct-or-union'>") - if offset != 0: + if offset: ptr = ctypes.cast( ctypes.c_void_p( ctypes.cast(ptr, ctypes.c_void_p).value + offset), diff --git a/lib_pypy/cffi/commontypes.py b/lib_pypy/cffi/commontypes.py --- a/lib_pypy/cffi/commontypes.py +++ b/lib_pypy/cffi/commontypes.py @@ -29,6 +29,9 @@ result = model.PointerType(resolve_common_type(result[:-2])) elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES: result = model.PrimitiveType(result) + elif result == 'set-unicode-needed': + raise api.FFIError("The Windows type %r is only available after " + "you call ffi.set_unicode()" % (commontype,)) else: if commontype == result: raise api.FFIError("Unsupported type: %r. Please file a bug " @@ -86,8 +89,6 @@ "ULONGLONG": "unsigned long long", "WCHAR": "wchar_t", "SHORT": "short", - "TBYTE": "WCHAR", - "TCHAR": "WCHAR", "UCHAR": "unsigned char", "UINT": "unsigned int", "UINT8": "unsigned char", @@ -157,14 +158,12 @@ "LPCVOID": model.const_voidp_type, "LPCWSTR": "const WCHAR *", - "LPCTSTR": "LPCWSTR", "LPDWORD": "DWORD *", "LPHANDLE": "HANDLE *", "LPINT": "int *", "LPLONG": "long *", "LPSTR": "CHAR *", "LPWSTR": "WCHAR *", - "LPTSTR": "LPWSTR", "LPVOID": model.voidp_type, "LPWORD": "WORD *", "LRESULT": "LONG_PTR", @@ -173,7 +172,6 @@ "PBYTE": "BYTE *", "PCHAR": "CHAR *", "PCSTR": "const CHAR *", - "PCTSTR": "LPCWSTR", "PCWSTR": "const WCHAR *", "PDWORD": "DWORD *", "PDWORDLONG": "DWORDLONG *", @@ -200,9 +198,6 @@ "PSIZE_T": "SIZE_T *", "PSSIZE_T": "SSIZE_T *", "PSTR": "CHAR *", - "PTBYTE": "TBYTE *", - "PTCHAR": "TCHAR *", - "PTSTR": "LPWSTR", "PUCHAR": "UCHAR *", "PUHALF_PTR": "UHALF_PTR *", "PUINT": "UINT *", @@ -240,6 +235,15 @@ "USN": "LONGLONG", "VOID": model.void_type, "WPARAM": "UINT_PTR", + + "TBYTE": "set-unicode-needed", + "TCHAR": "set-unicode-needed", + "LPCTSTR": "set-unicode-needed", + "PCTSTR": "set-unicode-needed", + "LPTSTR": "set-unicode-needed", + "PTSTR": "set-unicode-needed", + "PTBYTE": "set-unicode-needed", + "PTCHAR": "set-unicode-needed", }) return result diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -1,4 +1,3 @@ - from . import api, model from .commontypes import COMMON_TYPES, resolve_common_type try: @@ -209,6 +208,8 @@ def _add_constants(self, key, val): if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations raise api.FFIError( "multiple declarations of constant: %s" % (key,)) self._int_constants[key] = val @@ -228,12 +229,18 @@ pyvalue = int(int_str, 0) self._add_constants(key, pyvalue) + self._declare('macro ' + key, pyvalue) elif value == '...': self._declare('macro ' + key, value) else: - raise api.CDefError('only supports the syntax "#define ' - '%s ..." (literally) or "#define ' - '%s 0x1FF" for now' % (key, key)) + raise api.CDefError( + 'only supports one of the following syntax:\n' + ' #define %s ... (literally dot-dot-dot)\n' + ' #define %s NUMBER (with NUMBER an integer' + ' constant, decimal/hex/octal)\n' + 'got:\n' + ' #define %s %s' + % (key, key, key, value)) def _parse_decl(self, decl): node = decl.type @@ -460,6 +467,8 @@ elif kind == 'union': tp = model.UnionType(explicit_name, None, None, None) elif kind == 'enum': + if explicit_name == '__dotdotdot__': + raise CDefError("Enums cannot be declared with ...") tp = self._build_enum_type(explicit_name, type.values) else: raise AssertionError("kind = %r" % (kind,)) @@ -532,9 +541,24 @@ def _parse_constant(self, exprnode, partial_length_ok=False): # for now, limited to expressions that are an immediate number - # or negative number + # or positive/negative number if isinstance(exprnode, pycparser.c_ast.Constant): - return int(exprnode.value, 0) + s = exprnode.value + if s.startswith('0'): + if s.startswith('0x') or s.startswith('0X'): + return int(s, 16) + return int(s, 8) + elif '1' <= s[0] <= '9': + return int(s, 10) + elif s[0] == "'" and s[-1] == "'" and ( + len(s) == 3 or (len(s) == 4 and s[1] == "\\")): + return ord(s[-2]) + else: + raise api.CDefError("invalid constant %r" % (s,)) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '+'): + return self._parse_constant(exprnode.expr) # if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and exprnode.op == '-'): diff --git a/lib_pypy/cffi/ffiplatform.py b/lib_pypy/cffi/ffiplatform.py --- a/lib_pypy/cffi/ffiplatform.py +++ b/lib_pypy/cffi/ffiplatform.py @@ -11,6 +11,9 @@ """ +LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', + 'extra_objects', 'depends'] + def get_extension(srcfilename, modname, sources=(), **kwds): from distutils.core import Extension allsources = [srcfilename] diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -235,6 +235,8 @@ BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) +char_array_type = ArrayType(PrimitiveType('char'), None) + class StructOrUnionOrEnum(BaseTypeByIdentity): _attrs_ = ('name',) @@ -478,7 +480,7 @@ try: res = getattr(ffi._backend, funcname)(*args) except NotImplementedError as e: - raise NotImplementedError("%r: %s" % (srctype, e)) + raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) # note that setdefault() on WeakValueDictionary is not atomic # and contains a rare bug (http://bugs.python.org/issue19542); # we have to use a lock and do it ourselves diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -65,7 +65,7 @@ # The following two 'chained_list_constants' items contains # the head of these two chained lists, as a string that gives the # call to do, if any. - self._chained_list_constants = ['0', '0'] + self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] # prnt = self._prnt # first paste some standard set of lines that are mostly '#define' @@ -138,15 +138,22 @@ prnt() prnt('#endif') - def load_library(self): + def load_library(self, flags=None): # XXX review all usages of 'self' here! # import it as a new extension module + if hasattr(sys, "getdlopenflags"): + previous_flags = sys.getdlopenflags() try: + if hasattr(sys, "setdlopenflags") and flags is not None: + sys.setdlopenflags(flags) module = imp.load_dynamic(self.verifier.get_module_name(), self.verifier.modulefilename) except ImportError as e: error = "importing %r: %s" % (self.verifier.modulefilename, e) raise ffiplatform.VerificationError(error) + finally: + if hasattr(sys, "setdlopenflags"): + sys.setdlopenflags(previous_flags) # # call loading_cpy_struct() to get the struct layout inferred by # the C compiler @@ -228,7 +235,8 @@ converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name else: - converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),) + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) errvalue = '-1' # elif isinstance(tp, model.PointerType): @@ -267,8 +275,8 @@ self._prnt(' if (datasize != 0) {') self._prnt(' if (datasize < 0)') self._prnt(' %s;' % errcode) - self._prnt(' %s = alloca(datasize);' % (tovar,)) - self._prnt(' memset((void *)%s, 0, datasize);' % (tovar,)) + self._prnt(' %s = alloca((size_t)datasize);' % (tovar,)) + self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,)) self._prnt(' if (_cffi_convert_array_from_object(' '(char *)%s, _cffi_type(%d), %s) < 0)' % ( tovar, self._gettypenum(tp), fromvar)) @@ -336,7 +344,7 @@ prnt = self._prnt numargs = len(tp.args) if numargs == 0: - argname = 'no_arg' + argname = 'noarg' elif numargs == 1: argname = 'arg0' else: @@ -386,6 +394,9 @@ prnt(' Py_END_ALLOW_THREADS') prnt() # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') if result_code: prnt(' return %s;' % self._convert_expr_from_c(tp.result, 'result', 'result type')) @@ -452,6 +463,7 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) and ftype.is_integer_type()) or fbitsize >= 0: @@ -482,6 +494,8 @@ prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) prnt(' -1') prnt(' };') + prnt(' (void)self; /* unused */') + prnt(' (void)noarg; /* unused */') prnt(' return _cffi_get_struct_layout(nums);') prnt(' /* the next line is not executed, but compiled */') prnt(' %s(0);' % (checkfuncname,)) @@ -578,7 +592,8 @@ # constants, likely declared with '#define' def _generate_cpy_const(self, is_int, name, tp=None, category='const', - vartp=None, delayed=True, size_too=False): + vartp=None, delayed=True, size_too=False, + check_value=None): prnt = self._prnt funcname = '_cffi_%s_%s' % (category, name) prnt('static int %s(PyObject *lib)' % funcname) @@ -590,6 +605,9 @@ else: assert category == 'const' # + if check_value is not None: + self._check_int_constant_value(name, check_value) + # if not is_int: if category == 'var': realexpr = '&' + name @@ -637,6 +655,27 @@ # ---------- # enums + def _check_int_constant_value(self, name, value, err_prefix=''): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % + name) + prnt(' PyErr_Format(_cffi_VerificationError,') + prnt(' "%s%s has the real value %s, not %s",') + prnt(' "%s", "%s", buf, "%d");' % ( + err_prefix, name, value)) + prnt(' return -1;') + prnt(' }') + def _enum_funcname(self, prefix, name): # "$enum_$1" => "___D_enum____D_1" name = name.replace('$', '___D_') @@ -653,25 +692,8 @@ prnt('static int %s(PyObject *lib)' % funcname) prnt('{') for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - if enumvalue < 0: - prnt(' if ((%s) >= 0 || (long)(%s) != %dL) {' % ( - enumerator, enumerator, enumvalue)) - else: - prnt(' if ((%s) < 0 || (unsigned long)(%s) != %dUL) {' % ( - enumerator, enumerator, enumvalue)) - prnt(' char buf[64];') - prnt(' if ((%s) < 0)' % enumerator) - prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % enumerator) - prnt(' else') - prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % - enumerator) - prnt(' PyErr_Format(_cffi_VerificationError,') - prnt(' "enum %s: %s has the real value %s, ' - 'not %s",') - prnt(' "%s", "%s", buf, "%d");' % ( - name, enumerator, enumvalue)) - prnt(' return -1;') - prnt(' }') + self._check_int_constant_value(enumerator, enumvalue, + "enum %s: " % name) prnt(' return %s;' % self._chained_list_constants[True]) self._chained_list_constants[True] = funcname + '(lib)' prnt('}') @@ -695,8 +717,11 @@ # macros: for now only for integers def _generate_cpy_macro_decl(self, tp, name): - assert tp == '...' - self._generate_cpy_const(True, name) + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) _generate_cpy_macro_collecttype = _generate_nothing _generate_cpy_macro_method = _generate_nothing @@ -783,6 +808,24 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; # else # include <stdint.h> # endif @@ -828,12 +871,15 @@ PyLong_FromLongLong((long long)(x))) #define _cffi_from_c_int(x, type) \ - (((type)-1) > 0 ? /* unsigned */ \ - (sizeof(type) < sizeof(long) ? PyInt_FromLong(x) : \ - sizeof(type) == sizeof(long) ? PyLong_FromUnsignedLong(x) : \ - PyLong_FromUnsignedLongLong(x)) \ - : (sizeof(type) <= sizeof(long) ? PyInt_FromLong(x) : \ - PyLong_FromLongLong(x))) + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) #define _cffi_to_c_int(o, type) \ (sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ @@ -844,7 +890,7 @@ : (type)_cffi_to_c_i32(o)) : \ sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ : (type)_cffi_to_c_i64(o)) : \ - (Py_FatalError("unsupported size for type " #type), 0)) + (Py_FatalError("unsupported size for type " #type), (type)0)) #define _cffi_to_c_i8 \ ((int(*)(PyObject *))_cffi_exports[1]) @@ -907,6 +953,7 @@ { PyObject *library; int was_alive = (_cffi_types != NULL); + (void)self; /* unused */ if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, &library)) return NULL; diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -58,12 +58,12 @@ modname = self.verifier.get_module_name() prnt("void %s%s(void) { }\n" % (prefix, modname)) - def load_library(self): + def load_library(self, flags=0): # import it with the CFFI backend backend = self.ffi._backend # needs to make a path that contains '/', on Posix filename = os.path.join(os.curdir, self.verifier.modulefilename) - module = backend.load_library(filename) + module = backend.load_library(filename, flags) # # call loading_gen_struct() to get the struct layout inferred by # the C compiler @@ -235,6 +235,7 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) and ftype.is_integer_type()) or fbitsize >= 0: @@ -354,11 +355,20 @@ # ---------- # constants, likely declared with '#define' - def _generate_gen_const(self, is_int, name, tp=None, category='const'): + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): prnt = self._prnt funcname = '_cffi_%s_%s' % (category, name) self.export_symbols.append(funcname) - if is_int: + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: assert category == 'const' prnt('int %s(long long *out_value)' % funcname) prnt('{') @@ -367,6 +377,7 @@ prnt('}') else: assert tp is not None + assert check_value is None prnt(tp.get_c_name(' %s(void)' % funcname, name),) prnt('{') if category == 'var': @@ -383,9 +394,13 @@ _loading_gen_constant = _loaded_noop - def _load_constant(self, is_int, tp, name, module): + def _load_constant(self, is_int, tp, name, module, check_value=None): funcname = '_cffi_const_%s' % name - if is_int: + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: BType = self.ffi._typeof_locked("long long*")[0] BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] function = module.load_function(BFunc, funcname) @@ -396,6 +411,7 @@ BLongLong = self.ffi._typeof_locked("long long")[0] value += (1 << (8*self.ffi.sizeof(BLongLong))) else: + assert check_value is None BFunc = self.ffi._typeof_locked(tp.get_c_name('(*)(void)', name))[0] function = module.load_function(BFunc, funcname) value = function() @@ -410,6 +426,36 @@ # ---------- # enums + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise ffiplatform.VerificationError(error) + def _enum_funcname(self, prefix, name): # "$enum_$1" => "___D_enum____D_1" name = name.replace('$', '___D_') @@ -427,24 +473,7 @@ prnt('int %s(char *out_error)' % funcname) prnt('{') for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - if enumvalue < 0: - prnt(' if ((%s) >= 0 || (long)(%s) != %dL) {' % ( - enumerator, enumerator, enumvalue)) - else: - prnt(' if ((%s) < 0 || (unsigned long)(%s) != %dUL) {' % ( - enumerator, enumerator, enumvalue)) - prnt(' char buf[64];') - prnt(' if ((%s) < 0)' % enumerator) - prnt(' sprintf(buf, "%%ld", (long)(%s));' % enumerator) - prnt(' else') - prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % - enumerator) - prnt(' sprintf(out_error,' - ' "%s has the real value %s, not %s",') - prnt(' "%s", buf, "%d");' % ( - enumerator[:100], enumvalue)) - prnt(' return -1;') - prnt(' }') + self._check_int_constant_value(enumerator, enumvalue) prnt(' return 0;') prnt('}') prnt() @@ -456,16 +485,8 @@ tp.enumvalues = tuple(enumvalues) tp.partial_resolved = True else: - BType = self.ffi._typeof_locked("char[]")[0] - BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] funcname = self._enum_funcname(prefix, name) - function = module.load_function(BFunc, funcname) - p = self.ffi.new(BType, 256) - if function(p) < 0: - error = self.ffi.string(p) - if sys.version_info >= (3,): - error = str(error, 'utf-8') - raise ffiplatform.VerificationError(error) + self._load_known_int_constant(module, funcname) def _loaded_gen_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): @@ -476,13 +497,21 @@ # macros: for now only for integers def _generate_gen_macro_decl(self, tp, name): - assert tp == '...' - self._generate_gen_const(True, name) + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) _loading_gen_macro = _loaded_noop def _loaded_gen_macro(self, tp, name, module, library): - value = self._load_constant(True, tp, name, module) + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) setattr(library, name, value) type(library)._cffi_dir.append(name) @@ -565,6 +594,24 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; # else # include <stdint.h> # endif diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -1,12 +1,23 @@ -import sys, os, binascii, imp, shutil -from . import __version__ +import sys, os, binascii, shutil +from . import __version_verifier_modules__ from . import ffiplatform +if sys.version_info >= (3, 3): + import importlib.machinery + def _extension_suffixes(): + return importlib.machinery.EXTENSION_SUFFIXES[:] +else: + import imp + def _extension_suffixes(): + return [suffix for suffix, _, type in imp.get_suffixes() + if type == imp.C_EXTENSION] + class Verifier(object): def __init__(self, ffi, preamble, tmpdir=None, modulename=None, - ext_package=None, tag='', force_generic_engine=False, **kwds): + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, relative_to=None, **kwds): self.ffi = ffi self.preamble = preamble if not modulename: @@ -14,14 +25,15 @@ vengine_class = _locate_engine_class(ffi, force_generic_engine) self._vengine = vengine_class(self) self._vengine.patch_extension_kwds(kwds) - self.kwds = kwds + self.flags = flags + self.kwds = self.make_relative_to(kwds, relative_to) # if modulename: if tag: raise TypeError("can't specify both 'modulename' and 'tag'") else: - key = '\x00'.join([sys.version[:3], __version__, preamble, - flattened_kwds] + + key = '\x00'.join([sys.version[:3], __version_verifier_modules__, + preamble, flattened_kwds] + ffi._cdefsources) if sys.version_info >= (3,): key = key.encode('utf-8') @@ -33,7 +45,7 @@ k1, k2) suffix = _get_so_suffixes()[0] self.tmpdir = tmpdir or _caller_dir_pycache() - self.sourcefilename = os.path.join(self.tmpdir, modulename + '.c') + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) self.ext_package = ext_package self._has_source = False @@ -97,6 +109,20 @@ def generates_python_module(self): return self._vengine._gen_python_module + def make_relative_to(self, kwds, relative_to): + if relative_to and os.path.dirname(relative_to): + dirname = os.path.dirname(relative_to) + kwds = kwds.copy() + for key in ffiplatform.LIST_OF_FILE_NAMES: + if key in kwds: + lst = kwds[key] + if not isinstance(lst, (list, tuple)): + raise TypeError("keyword '%s' should be a list or tuple" + % (key,)) + lst = [os.path.join(dirname, fn) for fn in lst] + kwds[key] = lst + return kwds + # ---------- def _locate_module(self): @@ -148,7 +174,10 @@ def _load_library(self): assert self._has_module - return self._vengine.load_library() + if self.flags is not None: + return self._vengine.load_library(self.flags) + else: + return self._vengine.load_library() # ____________________________________________________________ @@ -181,6 +210,9 @@ def _caller_dir_pycache(): if _TMPDIR: return _TMPDIR + result = os.environ.get('CFFI_TMPDIR') + if result: + return result filename = sys._getframe(2).f_code.co_filename return os.path.abspath(os.path.join(os.path.dirname(filename), '__pycache__')) @@ -222,11 +254,7 @@ pass def _get_so_suffixes(): - suffixes = [] - for suffix, mode, type in imp.get_suffixes(): - if type == imp.C_EXTENSION: - suffixes.append(suffix) - + suffixes = _extension_suffixes() if not suffixes: # bah, no C_EXTENSION available. Occurs on pypy without cpyext if sys.platform == 'win32': diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -30,12 +30,10 @@ Initialize threads. Only need to be called if there are any threads involved -.. function:: long pypy_setup_home(char* home, int verbose); +.. function:: int pypy_setup_home(char* home, int verbose); This function searches the PyPy standard library starting from the given - "PyPy home directory". It is not strictly necessary to execute it before - running Python code, but without it you will not be able to import any - non-builtin module from the standard library. The arguments are: + "PyPy home directory". The arguments are: * ``home``: NULL terminated path to an executable inside the pypy directory (can be a .so name, can be made up) @@ -84,25 +82,36 @@ const char source[] = "print 'hello from pypy'"; - int main() + int main(void) { - int res; + int res; - rpython_startup_code(); - // pypy_setup_home() is not needed in this trivial example - res = pypy_execute_source((char*)source); - if (res) { - printf("Error calling pypy_execute_source!\n"); - } - return res; + rpython_startup_code(); + res = pypy_setup_home("/opt/pypy/bin/libpypy-c.so", 1); + if (res) { + printf("Error setting pypy home!\n"); + return 1; + } + + res = pypy_execute_source((char*)source); + if (res) { + printf("Error calling pypy_execute_source!\n"); + } + return res; } -If we save it as ``x.c`` now, compile it and run it with:: +If we save it as ``x.c`` now, compile it and run it (on linux) with:: fijal@hermann:/opt/pypy$ gcc -o x x.c -lpypy-c -L. fijal@hermann:/opt/pypy$ LD_LIBRARY_PATH=. ./x hello from pypy +on OSX it is necessary to set the rpath of the binary if one wants to link to it:: + + gcc -o x x.c -lpypy-c -L. -Wl,-rpath -Wl,@executable_path + ./x + hello from pypy + Worked! .. note:: If the compilation fails because of missing PyPy.h header file, diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst --- a/pypy/doc/install.rst +++ b/pypy/doc/install.rst @@ -38,14 +38,13 @@ and not move the binary there, else PyPy would not be able to find its library. -If you want to install 3rd party libraries, the most convenient way is to -install distribute_ and pip_: +If you want to install 3rd party libraries, the most convenient way is +to install pip_ (unless you want to install virtualenv as explained +below; then you can directly use pip inside virtualenvs): .. code-block:: console - $ curl -O http://python-distribute.org/distribute_setup.py - $ curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.1/bin/pypy distribute_setup.py + $ curl -O https://bootstrap.pypa.io/get-pip.py $ ./pypy-2.1/bin/pypy get-pip.py $ ./pypy-2.1/bin/pip install pygments # for example @@ -69,7 +68,6 @@ Note that bin/python is now a symlink to bin/pypy. -.. _distribute: http://www.python-distribute.org/ .. _pip: http://pypi.python.org/pypi/pip diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -101,7 +101,7 @@ if space.is_none(w_path): if verbose: debug("Failed to find library based on pypy_find_stdlib") - return 1 + return rffi.cast(rffi.INT, 1) space.startup() space.call_function(w_pathsetter, w_path) # import site @@ -109,13 +109,13 @@ import_ = space.getattr(space.getbuiltinmodule('__builtin__'), space.wrap('__import__')) space.call_function(import_, space.wrap('site')) - return 0 + return rffi.cast(rffi.INT, 0) except OperationError, e: if verbose: debug("OperationError:") debug(" operror-type: " + e.w_type.getname(space)) debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) - return -1 + return rffi.cast(rffi.INT, -1) @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') def pypy_execute_source(ll_source): @@ -234,8 +234,7 @@ enable_translationmodules(config) config.translation.suggest(check_str_without_nul=True) - if sys.platform.startswith('linux'): - config.translation.suggest(shared=True) + config.translation.suggest(shared=True) if config.translation.thread: config.objspace.usemodules.thread = True diff --git a/pypy/module/__builtin__/app_io.py b/pypy/module/__builtin__/app_io.py --- a/pypy/module/__builtin__/app_io.py +++ b/pypy/module/__builtin__/app_io.py @@ -86,9 +86,11 @@ def print_(*args, **kwargs): """The new-style print function from py3k.""" - fp = kwargs.pop("file", sys.stdout) + fp = kwargs.pop("file", None) if fp is None: - return + fp = sys.stdout + if fp is None: + return def write(data): if not isinstance(data, basestring): data = str(data) diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py --- a/pypy/module/__builtin__/test/test_builtin.py +++ b/pypy/module/__builtin__/test/test_builtin.py @@ -651,9 +651,12 @@ out = sys.stdout = StringIO.StringIO() try: pr("Hello,", "person!") + pr("2nd line", file=None) + sys.stdout = None + pr("nowhere") finally: sys.stdout = save - assert out.getvalue() == "Hello, person!\n" + assert out.getvalue() == "Hello, person!\n2nd line\n" out = StringIO.StringIO() pr("Hello,", "person!", file=out) assert out.getvalue() == "Hello, person!\n" @@ -668,7 +671,6 @@ result = out.getvalue() assert isinstance(result, unicode) assert result == u"Hello, person!\n" - pr("Hello", file=None) # This works. out = StringIO.StringIO() pr(None, file=out) assert out.getvalue() == "None\n" 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 @@ -34,6 +34,7 @@ 'newp_handle': 'handle.newp_handle', 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', + 'from_buffer': 'func.from_buffer', 'string': 'func.string', 'buffer': 'cbuffer.buffer', diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -45,8 +45,9 @@ # cif_descr = self.getfunctype().cif_descr if not cif_descr: - raise OperationError(space.w_NotImplementedError, - space.wrap("callbacks with '...'")) + raise oefmt(space.w_NotImplementedError, + "%s: callback with unsupported argument or " + "return type or with '...'", self.getfunctype().name) res = clibffi.c_ffi_prep_closure(self.get_closure(), cif_descr.cif, invoke_callback, rffi.cast(rffi.VOIDP, self.unique_id)) @@ -98,7 +99,7 @@ def print_error(self, operr, extra_line): space = self.space - operr.write_unraisable(space, "callback ", self.w_callable, + operr.write_unraisable(space, "cffi callback ", self.w_callable, with_traceback=True, extra_line=extra_line) def write_error_return_value(self, ll_res): 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 @@ -440,6 +440,25 @@ return "handle to %s" % (self.space.str_w(w_repr),) +class W_CDataFromBuffer(W_CData): + _attrs_ = ['buf', 'length', 'w_keepalive'] + _immutable_fields_ = ['buf', 'length', 'w_keepalive'] + + def __init__(self, space, cdata, ctype, buf, w_object): + W_CData.__init__(self, space, cdata, ctype) + self.buf = buf + self.length = buf.getlength() + self.w_keepalive = w_object + + def get_array_length(self): + return self.length + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "buffer len %d from '%s' object" % ( + self.length, self.space.type(self.w_keepalive).name) + + W_CData.typedef = TypeDef( '_cffi_backend.CData', __module__ = '_cffi_backend', 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 @@ -107,6 +107,9 @@ return self.space.w_None return W_CTypePtrOrArray._fget(self, attrchar) + def typeoffsetof_index(self, index): + return self.ctptr.typeoffsetof_index(index) + class W_CDataIter(W_Root): _immutable_fields_ = ['ctitem', 'cdata', '_stop'] # but not '_next' diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py --- a/pypy/module/_cffi_backend/ctypefunc.py +++ b/pypy/module/_cffi_backend/ctypefunc.py @@ -27,6 +27,8 @@ _immutable_fields_ = ['fargs[*]', 'ellipsis', 'cif_descr'] kind = "function" + cif_descr = lltype.nullptr(CIF_DESCRIPTION) + def __init__(self, space, fargs, fresult, ellipsis): extra = self._compute_extra_text(fargs, fresult, ellipsis) size = rffi.sizeof(rffi.VOIDP) @@ -41,7 +43,17 @@ # at all. The cif is computed on every call from the actual # types passed in. For all other functions, the cif_descr # is computed here. - CifDescrBuilder(fargs, fresult).rawallocate(self) + builder = CifDescrBuilder(fargs, fresult) + try: + builder.rawallocate(self) + except OperationError, e: + if not e.match(space, space.w_NotImplementedError): + raise + # else, eat the NotImplementedError. We will get the + # exception if we see an actual call + if self.cif_descr: # should not be True, but you never know + lltype.free(self.cif_descr, flavor='raw') + self.cif_descr = lltype.nullptr(CIF_DESCRIPTION) def new_ctypefunc_completing_argtypes(self, args_w): space = self.space @@ -57,10 +69,12 @@ "argument %d passed in the variadic part needs to " "be a cdata object (got %T)", i + 1, w_obj) fvarargs[i] = ct + # xxx call instantiate() directly. It's a bit of a hack. ctypefunc = instantiate(W_CTypeFunc) ctypefunc.space = space ctypefunc.fargs = fvarargs ctypefunc.ctitem = self.ctitem + #ctypefunc.cif_descr = NULL --- already provided as the default CifDescrBuilder(fvarargs, self.ctitem).rawallocate(ctypefunc) return ctypefunc @@ -178,8 +192,6 @@ # ____________________________________________________________ -W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION) # default value - BIG_ENDIAN = sys.byteorder == 'big' USE_C_LIBFFI_MSVC = getattr(clibffi, 'USE_C_LIBFFI_MSVC', False) @@ -295,18 +307,18 @@ nflat = 0 for i, cf in enumerate(ctype.fields_list): if cf.is_bitfield(): - raise OperationError(space.w_NotImplementedError, - space.wrap("cannot pass as argument or return value " - "a struct with bit fields")) + raise oefmt(space.w_NotImplementedError, + "ctype '%s' not supported as argument or return value" + " (it is a struct with bit fields)", ctype.name) flat = 1 ct = cf.ctype while isinstance(ct, ctypearray.W_CTypeArray): flat *= ct.length ct = ct.ctitem if flat <= 0: - raise OperationError(space.w_NotImplementedError, - space.wrap("cannot pass as argument or return value " - "a struct with a zero-length array")) + raise oefmt(space.w_NotImplementedError, + "ctype '%s' not supported as argument or return value" + " (it is a struct with a zero-length array)", ctype.name) nflat += flat if USE_C_LIBFFI_MSVC and is_result_type: 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 @@ -142,12 +142,14 @@ raise oefmt(space.w_ValueError, "ctype '%s' is of unknown alignment", self.name) - def typeoffsetof(self, fieldname): + def typeoffsetof_field(self, fieldname, following): space = self.space - if fieldname is None: - msg = "expected a struct or union ctype" - else: - msg = "expected a struct or union ctype, or a pointer to one" + msg = "with a field name argument, expected a struct or union ctype" + raise OperationError(space.w_TypeError, space.wrap(msg)) + + def typeoffsetof_index(self, index): + space = self.space + msg = "with an integer argument, expected an array or pointer ctype" raise OperationError(space.w_TypeError, space.wrap(msg)) def rawaddressof(self, cdata, offset): diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -308,24 +308,36 @@ def getcfield(self, attr): return self.ctitem.getcfield(attr) - def typeoffsetof(self, fieldname): - if fieldname is None: - return W_CTypePtrBase.typeoffsetof(self, fieldname) - else: - return self.ctitem.typeoffsetof(fieldname) + def typeoffsetof_field(self, fieldname, following): + if following == 0: + return self.ctitem.typeoffsetof_field(fieldname, -1) + return W_CTypePtrBase.typeoffsetof_field(self, fieldname, following) + + def typeoffsetof_index(self, index): + space = self.space + ctitem = self.ctitem + if ctitem.size < 0: + raise OperationError(space.w_TypeError, + space.wrap("pointer to opaque")) + try: + offset = ovfcheck(index * ctitem.size) + except OverflowError: + raise OperationError(space.w_OverflowError, + space.wrap("array offset would overflow a ssize_t")) + return ctitem, offset def rawaddressof(self, cdata, offset): from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion space = self.space ctype2 = cdata.ctype if (isinstance(ctype2, W_CTypeStructOrUnion) or - (isinstance(ctype2, W_CTypePtrOrArray) and - isinstance(ctype2.ctitem, W_CTypeStructOrUnion))): + isinstance(ctype2, W_CTypePtrOrArray)): ptrdata = rffi.ptradd(cdata._cdata, offset) return cdataobj.W_CData(space, ptrdata, self) else: raise OperationError(space.w_TypeError, - space.wrap("expected a 'cdata struct-or-union' object")) + space.wrap("expected a cdata struct/union/array/pointer" + " object")) def _fget(self, attrchar): if attrchar == 'i': # item diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -65,9 +65,7 @@ keepalive_until_here(ob) return ob - def typeoffsetof(self, fieldname): - if fieldname is None: - return (self, 0) + def typeoffsetof_field(self, fieldname, following): self.check_complete() space = self.space try: 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 @@ -48,13 +48,28 @@ align = w_ctype.alignof() return space.wrap(align) -@unwrap_spec(w_ctype=ctypeobj.W_CType, fieldname="str_or_None") -def typeoffsetof(space, w_ctype, fieldname): - ctype, offset = w_ctype.typeoffsetof(fieldname) +@unwrap_spec(w_ctype=ctypeobj.W_CType, following=int) +def typeoffsetof(space, w_ctype, w_field_or_index, following=0): + try: + fieldname = space.str_w(w_field_or_index) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + try: + index = space.int_w(w_field_or_index) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + raise OperationError(space.w_TypeError, + space.wrap("field name or array index expected")) + ctype, offset = w_ctype.typeoffsetof_index(index) + else: + ctype, offset = w_ctype.typeoffsetof_field(fieldname, following) + # return space.newtuple([space.wrap(ctype), space.wrap(offset)]) @unwrap_spec(w_ctype=ctypeobj.W_CType, w_cdata=cdataobj.W_CData, offset=int) -def rawaddressof(space, w_ctype, w_cdata, offset=0): +def rawaddressof(space, w_ctype, w_cdata, offset): return w_ctype.rawaddressof(w_cdata, offset) # ____________________________________________________________ @@ -76,3 +91,32 @@ def _get_types(space): return space.newtuple([space.gettypefor(cdataobj.W_CData), space.gettypefor(ctypeobj.W_CType)]) + +# ____________________________________________________________ + +@unwrap_spec(w_ctype=ctypeobj.W_CType) +def from_buffer(space, w_ctype, w_x): + from pypy.module._cffi_backend import ctypearray, ctypeprim + # + if (not isinstance(w_ctype, ctypearray.W_CTypeArray) or + not isinstance(w_ctype.ctptr.ctitem, ctypeprim.W_CTypePrimitiveChar)): + raise oefmt(space.w_TypeError, + "needs 'char[]', got '%s'", w_ctype.name) + # + # xxx do we really need to implement the same mess as in CPython 2.7 + # w.r.t. buffers and memoryviews?? + try: + buf = space.readbuf_w(w_x) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + buf = space.buffer_w(w_x, space.BUF_SIMPLE) + try: + _cdata = buf.get_raw_address() + except ValueError: + raise oefmt(space.w_TypeError, + "from_buffer() got a '%T' object, which supports the " + "buffer interface but cannot be rendered as a plain " + "raw address on PyPy", w_x) + # + return cdataobj.W_CDataFromBuffer(space, _cdata, w_ctype, buf, w_x) 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 @@ -1030,11 +1030,12 @@ BInt = new_primitive_type("int") BArray0 = new_array_type(new_pointer_type(BInt), 0) BStruct = new_struct_type("struct foo") + BStructP = new_pointer_type(BStruct) complete_struct_or_union(BStruct, [('a', BArray0)]) - py.test.raises(NotImplementedError, new_function_type, - (BStruct,), BInt, False) - py.test.raises(NotImplementedError, new_function_type, - (BInt,), BStruct, False) + BFunc = new_function_type((BStruct,), BInt, False) + py.test.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123)) + BFunc2 = new_function_type((BInt,), BStruct, False) + py.test.raises(NotImplementedError, cast(BFunc2, 123), 123) def test_call_function_9(): BInt = new_primitive_type("int") @@ -1174,7 +1175,7 @@ assert sys.stderr.getvalue() == '' assert f(10000) == -42 assert matches(sys.stderr.getvalue(), """\ -From callback <function$Zcb1 at 0x$>: +From cffi callback <function$Zcb1 at 0x$>: Traceback (most recent call last): File "$", line $, in Zcb1 $ @@ -1186,7 +1187,7 @@ bigvalue = 20000 assert f(bigvalue) == -42 assert matches(sys.stderr.getvalue(), """\ -From callback <function$Zcb1 at 0x$>: +From cffi callback <function$Zcb1 at 0x$>: Trying to convert the result back to C: OverflowError: integer 60000 does not fit 'short' """) @@ -1805,7 +1806,8 @@ new_function_type((), new_pointer_type(BFunc)) BUnion = new_union_type("union foo_u") complete_struct_or_union(BUnion, []) - py.test.raises(NotImplementedError, new_function_type, (), BUnion) + BFunc = new_function_type((), BUnion) + py.test.raises(NotImplementedError, cast(BFunc, 123)) py.test.raises(TypeError, new_function_type, (), BArray) def test_struct_return_in_func(): @@ -2525,13 +2527,32 @@ ('a2', BChar, -1), ('a3', BChar, -1)]) py.test.raises(TypeError, typeoffsetof, BStructPtr, None) - assert typeoffsetof(BStruct, None) == (BStruct, 0) + py.test.raises(TypeError, typeoffsetof, BStruct, None) assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0) assert typeoffsetof(BStruct, 'a1') == (BChar, 0) assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1) assert typeoffsetof(BStruct, 'a3') == (BChar, 2) + assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1) + assert typeoffsetof(BStruct, u+'a3') == (BChar, 2) + py.test.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1) py.test.raises(KeyError, typeoffsetof, BStructPtr, 'a4') py.test.raises(KeyError, typeoffsetof, BStruct, 'a5') + py.test.raises(TypeError, typeoffsetof, BStruct, 42) + py.test.raises(TypeError, typeoffsetof, BChar, 'a1') + +def test_typeoffsetof_array(): + BInt = new_primitive_type("int") + BIntP = new_pointer_type(BInt) + BArray = new_array_type(BIntP, None) + py.test.raises(TypeError, typeoffsetof, BArray, None) + py.test.raises(TypeError, typeoffsetof, BArray, 'a1') + assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int()) + assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int()) + assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int()) + MAX = sys.maxsize // size_of_int() + assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int()) + assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int()) + py.test.raises(OverflowError, typeoffsetof, BArray, MAX + 1) def test_typeoffsetof_no_bitfield(): BInt = new_primitive_type("int") @@ -2551,17 +2572,26 @@ assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>" s = p[0] assert repr(s) == "<cdata 'struct foo' owning 3 bytes>" - a = rawaddressof(BStructPtr, s) + a = rawaddressof(BStructPtr, s, 0) assert repr(a).startswith("<cdata 'struct foo *' 0x") - py.test.raises(TypeError, rawaddressof, BStruct, s) - b = rawaddressof(BCharP, s) + py.test.raises(TypeError, rawaddressof, BStruct, s, 0) + b = rawaddressof(BCharP, s, 0) assert b == cast(BCharP, p) - c = rawaddressof(BStructPtr, a) + c = rawaddressof(BStructPtr, a, 0) assert c == a - py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?')) + py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0) # d = rawaddressof(BCharP, s, 1) assert d == cast(BCharP, p) + 1 + # + e = cast(BCharP, 109238) + f = rawaddressof(BCharP, e, 42) + assert f == e + 42 + # + BCharA = new_array_type(BCharP, None) + e = newp(BCharA, 50) + f = rawaddressof(BCharP, e, 42) + assert f == e + 42 def test_newp_signed_unsigned_char(): BCharArray = new_array_type( @@ -3195,6 +3225,20 @@ ('a2', BChar, 5)], None, -1, -1, SF_PACKED) +def test_from_buffer(): + import array + a = array.array('H', [10000, 20000, 30000]) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BCharA = new_array_type(BCharP, None) + c = from_buffer(BCharA, a) + assert typeof(c) is BCharA + assert len(c) == 6 + assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>" + p = new_pointer_type(new_primitive_type("unsigned short")) + cast(p, c)[1] += 500 + assert list(a) == [10000, 20500, 30000] + def test_version(): # this test is here mostly for PyPy assert __version__ == "0.8.6" diff --git a/pypy/module/_cffi_backend/test/test_c.py b/pypy/module/_cffi_backend/test/test_c.py --- a/pypy/module/_cffi_backend/test/test_c.py +++ b/pypy/module/_cffi_backend/test/test_c.py @@ -30,7 +30,7 @@ class AppTestC(object): """Populated below, hack hack hack.""" - spaceconfig = dict(usemodules=('_cffi_backend', 'cStringIO')) + spaceconfig = dict(usemodules=('_cffi_backend', 'cStringIO', 'array')) def setup_class(cls): testfuncs_w = [] diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py --- a/pypy/module/_io/interp_bufferedio.py +++ b/pypy/module/_io/interp_bufferedio.py @@ -565,7 +565,7 @@ # Flush the write buffer if necessary if self.writable: - self._writer_flush_unlocked(space) + self._flush_and_rewind_unlocked(space) self._reader_reset_buf() # Read whole blocks, and don't buffer them diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -362,3 +362,32 @@ f.read(1) f.seek(-1, 1) f.write(b'') + + def test_issue1902_2(self): + import _io + with _io.open(self.tmpfile, 'w+b', 4096) as f: + f.write(b'\xff' * 13569) + f.flush() + f.seek(0, 0) + + f.read(1) + f.seek(-1, 1) + f.write(b'\xff') + f.seek(1, 0) + f.read(4123) + f.seek(-4123, 1) + + def test_issue1902_3(self): + import _io + buffer_size = 4096 + with _io.open(self.tmpfile, 'w+b', buffer_size) as f: + f.write(b'\xff' * buffer_size * 3) + f.flush() + f.seek(0, 0) + + f.read(1) + f.seek(-1, 1) + f.write(b'\xff') + f.seek(1, 0) + f.read(buffer_size * 2) + assert f.tell() == 1 + buffer_size * 2 diff --git a/pypy/module/micronumpy/descriptor.py b/pypy/module/micronumpy/descriptor.py --- a/pypy/module/micronumpy/descriptor.py +++ b/pypy/module/micronumpy/descriptor.py @@ -394,7 +394,7 @@ alignment = space.int_w(space.getitem(w_data, space.wrap(6))) if (w_names == space.w_None) != (w_fields == space.w_None): - raise oefmt(space.w_ValueError, "inconsistent fields and names") + raise oefmt(space.w_ValueError, "inconsistent fields and names in Numpy dtype unpickling") self.byteorder = endian self.shape = [] diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -1234,7 +1234,8 @@ d = np.dtype(('<f8', 2)) exc = raises(ValueError, "d.__setstate__((3, '|', None, ('f0', 'f1'), None, 16, 1, 0))") - assert exc.value[0] == 'inconsistent fields and names' + inconsistent = 'inconsistent fields and names in Numpy dtype unpickling' + assert exc.value[0] == inconsistent assert d.fields is None assert d.shape == (2,) assert d.subdtype is not None @@ -1242,7 +1243,7 @@ d = np.dtype(('<f8', 2)) exc = raises(ValueError, "d.__setstate__((3, '|', None, None, {'f0': (np.dtype('float64'), 0), 'f1': (np.dtype('float64'), 8)}, 16, 1, 0))") - assert exc.value[0] == 'inconsistent fields and names' + assert exc.value[0] == inconsistent assert d.fields is None assert d.shape == (2,) assert d.subdtype is not None @@ -1283,7 +1284,11 @@ from cPickle import loads, dumps d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '|', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '|', None, + ('x', 'y', 'z', 'value'), + {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), + 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12), + }, 20, 1, 0)) new_d = loads(dumps(d)) diff --git a/pypy/module/micronumpy/tool/numready/main.py b/pypy/module/micronumpy/tool/numready/main.py --- a/pypy/module/micronumpy/tool/numready/main.py +++ b/pypy/module/micronumpy/tool/numready/main.py @@ -71,6 +71,10 @@ lines = subprocess.check_output(args).splitlines() items = SearchableSet() for line in lines: + # since calling a function in "search.py" may have printed side effects, + # make sure the line begins with '[UT] : ' + if not (line[:1] in KINDS.values() and line[1:4] == ' : '): + continue kind, name = line.split(" : ", 1) subitems = [] if kind == KINDS["TYPE"] and name in SPECIAL_NAMES and attr is None: @@ -97,7 +101,15 @@ "nditer"] def main(argv): - cpy_items = find_numpy_items("/usr/bin/python") + if 'help' in argv[1]: + print '\nusage: python', os.path.dirname(__file__), '<path-to-pypy> [<outfile.html>] [<path-to-cpython-with-numpy>]' + print ' path-to-cpython-with-numpy defaults to "/usr/bin/python"\n' + return + if len(argv) < 4: + cpython = '/usr/bin/python' + else: + cpython = argv[3] + cpy_items = find_numpy_items(cpython) pypy_items = find_numpy_items(argv[1]) ver = get_version_str(argv[1]) all_items = [] diff --git a/pypy/module/micronumpy/tool/numready/search.py b/pypy/module/micronumpy/tool/numready/search.py --- a/pypy/module/micronumpy/tool/numready/search.py +++ b/pypy/module/micronumpy/tool/numready/search.py @@ -23,6 +23,15 @@ if attr is None and name.startswith("_"): continue subobj = getattr(obj, name) + if subobj is None: + continue + if isinstance(subobj, types.FunctionType): + try: + subobj() + except NotImplementedError: + continue + except: + pass if isinstance(subobj, types.TypeType): kind = KINDS["TYPE"] else: diff --git a/pypy/module/termios/__init__.py b/pypy/module/termios/__init__.py --- a/pypy/module/termios/__init__.py +++ b/pypy/module/termios/__init__.py @@ -1,5 +1,7 @@ from pypy.interpreter.mixedmodule import MixedModule +from rpython.rlib import rtermios + class Module(MixedModule): "This module provides an interface to the Posix calls for tty I/O control.\n\ For a complete description of these calls, see the Posix or Unix manual\n\ @@ -23,10 +25,6 @@ 'error' : 'space.fromcache(interp_termios.Cache).w_error', } -# XXX this is extremaly not-portable, but how to prevent this? - -import termios -for i in dir(termios): - val = getattr(termios, i) - if i.isupper() and type(val) is int: - Module.interpleveldefs[i] = "space.wrap(%s)" % val + for name in rtermios.all_constants: + value = getattr(rtermios, name) + interpleveldefs[name] = "space.wrap(%s)" % value diff --git a/pypy/module/termios/interp_termios.py b/pypy/module/termios/interp_termios.py --- a/pypy/module/termios/interp_termios.py +++ b/pypy/module/termios/interp_termios.py @@ -6,7 +6,6 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.error import wrap_oserror, OperationError from rpython.rlib import rtermios -import termios class Cache: def __init__(self, space): @@ -52,9 +51,9 @@ l_w = [space.wrap(i) for i in [iflag, oflag, cflag, lflag, ispeed, ospeed]] # last one need to be chosen carefully cc_w = [space.wrap(i) for i in cc] - if lflag & termios.ICANON: - cc_w[termios.VMIN] = space.wrap(ord(cc[termios.VMIN][0])) - cc_w[termios.VTIME] = space.wrap(ord(cc[termios.VTIME][0])) + if lflag & rtermios.ICANON: + cc_w[rtermios.VMIN] = space.wrap(ord(cc[rtermios.VMIN][0])) + cc_w[rtermios.VTIME] = space.wrap(ord(cc[rtermios.VTIME][0])) w_cc = space.newlist(cc_w) l_w.append(w_cc) return space.newlist(l_w) @@ -63,14 +62,14 @@ def tcsendbreak(space, w_fd, duration): fd = space.c_filedescriptor_w(w_fd) try: - termios.tcsendbreak(fd, duration) + rtermios.tcsendbreak(fd, duration) except OSError, e: raise convert_error(space, e) def tcdrain(space, w_fd): fd = space.c_filedescriptor_w(w_fd) try: - termios.tcdrain(fd) + rtermios.tcdrain(fd) except OSError, e: raise convert_error(space, e) @@ -78,7 +77,7 @@ def tcflush(space, w_fd, queue): fd = space.c_filedescriptor_w(w_fd) try: - termios.tcflush(fd, queue) + rtermios.tcflush(fd, queue) except OSError, e: raise convert_error(space, e) @@ -86,6 +85,6 @@ def tcflow(space, w_fd, action): fd = space.c_filedescriptor_w(w_fd) try: - termios.tcflow(fd, action) + rtermios.tcflow(fd, action) except OSError, e: raise convert_error(space, e) diff --git a/pypy/module/termios/test/test_termios.py b/pypy/module/termios/test/test_termios.py --- a/pypy/module/termios/test/test_termios.py +++ b/pypy/module/termios/test/test_termios.py @@ -136,7 +136,7 @@ val = getattr(termios, name) if name.isupper() and type(val) is int: d[name] = val - assert d == self.orig_module_dict + assert sorted(d.items()) == sorted(self.orig_module_dict.items()) def test_error(self): import termios, errno, os diff --git a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py @@ -2,7 +2,7 @@ import py import platform import sys, ctypes -from cffi import FFI, CDefError +from cffi import FFI, CDefError, FFIError from pypy.module.test_lib_pypy.cffi_tests.support import * SIZE_OF_INT = ctypes.sizeof(ctypes.c_int) @@ -917,6 +917,16 @@ assert int(invalid_value) == 2 assert ffi.string(invalid_value) == "2" + def test_enum_char_hex_oct(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef(r"enum foo{A='!', B='\'', C=0x10, D=010, E=- 0x10, F=-010};") + assert ffi.string(ffi.cast("enum foo", ord('!'))) == "A" + assert ffi.string(ffi.cast("enum foo", ord("'"))) == "B" + assert ffi.string(ffi.cast("enum foo", 16)) == "C" + assert ffi.string(ffi.cast("enum foo", 8)) == "D" + assert ffi.string(ffi.cast("enum foo", -16)) == "E" + assert ffi.string(ffi.cast("enum foo", -8)) == "F" + def test_array_of_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a, b; };") @@ -950,6 +960,25 @@ assert ffi.offsetof("struct foo", "b") == 4 assert ffi.offsetof("struct foo", "c") == 8 + def test_offsetof_nested(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("struct foo { int a, b, c; };" + "struct bar { struct foo d, e; };") + assert ffi.offsetof("struct bar", "e") == 12 + py.test.raises(KeyError, ffi.offsetof, "struct bar", "e.a") + assert ffi.offsetof("struct bar", "e", "a") == 12 + assert ffi.offsetof("struct bar", "e", "b") == 16 + assert ffi.offsetof("struct bar", "e", "c") == 20 + + def test_offsetof_array(self): + ffi = FFI(backend=self.Backend()) + assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int") + assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int") + ffi.cdef("struct bar { int a, b; int c[99]; };") + assert ffi.offsetof("struct bar", "c") == 2 * ffi.sizeof("int") + assert ffi.offsetof("struct bar", "c", 0) == 2 * ffi.sizeof("int") + assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int") + def test_alignof(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { char a; short b; char c; };") @@ -1482,8 +1511,10 @@ p = ffi.new("struct foo_s *") a = ffi.addressof(p[0]) assert repr(a).startswith("<cdata 'struct foo_s *' 0x") + assert a == p py.test.raises(TypeError, ffi.addressof, p) py.test.raises((AttributeError, TypeError), ffi.addressof, 5) + py.test.raises(TypeError, ffi.addressof, ffi.cast("int", 5)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit