Author: Ronan Lamy <[email protected]> Branch: union-side-effects Changeset: r86872:be656798450c Date: 2016-09-04 19:34 +0100 http://bitbucket.org/pypy/pypy/changeset/be656798450c/
Log: hg merge default 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.8.0 +Version: 1.8.1 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.8.0" -__version_info__ = (1, 8, 0) +__version__ = "1.8.1" +__version_info__ = (1, 8, 1) # 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/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -1,4 +1,20 @@ #define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. +*/ +#ifndef _CFFI_USE_EMBEDDING +# include <pyconfig.h> +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) +# define Py_LIMITED_API +# endif +#endif + #include <Python.h> #ifdef __cplusplus extern "C" { 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.8.0" + "\ncompiled with cffi version: 1.8.1" "\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 @@ -652,7 +652,7 @@ recompile(self, module_name, source, c_file=filename, call_c_compiler=False, **kwds) - def compile(self, tmpdir='.', verbose=0, target=None): + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): """The 'target' argument gives the final file name of the compiled DLL. Use '*' to force distutils' choice, suitable for regular CPython C API modules. Use a file name ending in '.*' @@ -669,7 +669,7 @@ module_name, source, source_extension, kwds = self._assigned_source return recompile(self, module_name, source, tmpdir=tmpdir, target=target, source_extension=source_extension, - compiler_verbose=verbose, **kwds) + compiler_verbose=verbose, debug=debug, **kwds) def init_once(self, func, tag): # Read _init_once_cache[tag], which is either (False, lock) if 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 @@ -997,29 +997,43 @@ assert onerror is None # XXX not implemented return BType(source, error) + _weakref_cache_ref = None + def gcp(self, cdata, destructor): - BType = self.typeof(cdata) + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(self()) + return self._hash + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref if destructor is None: - if not (hasattr(BType, '_gcp_type') and - BType._gcp_type is BType): + try: + del weak_cache[MyRef(cdata)] + except KeyError: raise TypeError("Can remove destructor only on a object " "previously returned by ffi.gc()") - cdata._destructor = None return None - try: - gcp_type = BType._gcp_type - except AttributeError: - class CTypesDataGcp(BType): - __slots__ = ['_orig', '_destructor'] - def __del__(self): - if self._destructor is not None: - self._destructor(self._orig) - gcp_type = BType._gcp_type = CTypesDataGcp - new_cdata = self.cast(gcp_type, cdata) - new_cdata._orig = cdata - new_cdata._destructor = destructor + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) return new_cdata typeof = type 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 @@ -21,12 +21,12 @@ allsources.append(os.path.normpath(src)) return Extension(name=modname, sources=allsources, **kwds) -def compile(tmpdir, ext, compiler_verbose=0): +def compile(tmpdir, ext, compiler_verbose=0, debug=None): """Compile a C extension module using distutils.""" saved_environ = os.environ.copy() try: - outputfilename = _build(tmpdir, ext, compiler_verbose) + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) outputfilename = os.path.abspath(outputfilename) finally: # workaround for a distutils bugs where some env vars can @@ -36,7 +36,7 @@ os.environ[key] = value return outputfilename -def _build(tmpdir, ext, compiler_verbose=0): +def _build(tmpdir, ext, compiler_verbose=0, debug=None): # XXX compact but horrible :-( from distutils.core import Distribution import distutils.errors, distutils.log @@ -44,6 +44,9 @@ dist = Distribution({'ext_modules': [ext]}) dist.parse_config_files() options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) options['force'] = ('ffiplatform', True) options['build_lib'] = ('ffiplatform', tmpdir) options['build_temp'] = ('ffiplatform', tmpdir) 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 @@ -275,8 +275,8 @@ def write_c_source_to_f(self, f, preamble): self._f = f prnt = self._prnt - if self.ffi._embedding is None: - prnt('#define Py_LIMITED_API') + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') # # first the '#include' (actually done by inlining the file's content) lines = self._rel_readlines('_cffi_include.h') @@ -1431,7 +1431,7 @@ def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, c_file=None, source_extension='.c', extradir=None, - compiler_verbose=1, target=None, **kwds): + compiler_verbose=1, target=None, debug=None, **kwds): if not isinstance(module_name, str): module_name = module_name.encode('ascii') if ffi._windows_unicode: @@ -1467,7 +1467,8 @@ if target != '*': _patch_for_target(patchlist, target) os.chdir(tmpdir) - outputfilename = ffiplatform.compile('.', ext, compiler_verbose) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) finally: os.chdir(cwd) _unpatch_meths(patchlist) diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -69,16 +69,36 @@ else: _add_c_module(dist, ffi, module_name, source, source_extension, kwds) +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + """ + if 'py_limited_api' not in kwds: + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): from distutils.core import Extension - from distutils.command.build_ext import build_ext + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext from distutils.dir_util import mkpath from distutils import log from cffi import recompiler allsources = ['$PLACEHOLDER'] allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) ext = Extension(name=module_name, sources=allsources, **kwds) def make_mod(tmpdir, pre_run=None): 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.8.0" +VERSION = "1.8.1" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: 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.8.0", ("This test_c.py file is for testing a version" +assert __version__ == "1.8.1", ("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,): diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,8 +29,8 @@ #define PY_VERSION "2.7.10" /* PyPy version as a string */ -#define PYPY_VERSION "5.4.1-alpha0" -#define PYPY_VERSION_NUM 0x05040100 +#define PYPY_VERSION "5.5.0-alpha0" +#define PYPY_VERSION_NUM 0x05050000 /* Defined to mean a PyPy where cpyext holds more regular references to PyObjects, e.g. staying alive as long as the internal PyPy object diff --git a/pypy/module/cpyext/test/test_version.py b/pypy/module/cpyext/test/test_version.py --- a/pypy/module/cpyext/test/test_version.py +++ b/pypy/module/cpyext/test/test_version.py @@ -32,9 +32,11 @@ assert module.py_minor_version == sys.version_info.minor assert module.py_micro_version == sys.version_info.micro - @pytest.mark.skipif('__pypy__' not in sys.builtin_module_names, reason='pypy only test') + #@pytest.mark.skipif('__pypy__' not in sys.builtin_module_names, reason='pypy only test') def test_pypy_versions(self): import sys + if '__pypy__' not in sys.builtin_module_names: + py.test.skip("pypy only test") init = """ if (Py_IsInitialized()) { PyObject *m = Py_InitModule("foo", NULL); diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -10,7 +10,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (5, 4, 1, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (5, 5, 0, "alpha", 0) #XXX # sync patchlevel.h import pypy diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py @@ -1479,6 +1479,7 @@ assert p1[0] == 123 seen.append(1) q = ffi.gc(p, destructor) + assert ffi.typeof(q) is ffi.typeof(p) import gc; gc.collect() assert seen == [] del q diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py @@ -149,3 +149,28 @@ p = snip_setuptools_verify2.C.getpwuid(0) assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root" ''') + + def test_set_py_limited_api(self): + from cffi.setuptools_ext import _set_py_limited_api + try: + import setuptools + except ImportError as e: + py.test.skip(str(e)) + orig_version = setuptools.__version__ + try: + setuptools.__version__ = '26.0.0' + from setuptools import Extension + + kwds = _set_py_limited_api(Extension, {}) + assert kwds['py_limited_api'] == True + + setuptools.__version__ = '25.0' + kwds = _set_py_limited_api(Extension, {}) + assert not kwds + + setuptools.__version__ = 'development' + kwds = _set_py_limited_api(Extension, {}) + assert kwds['py_limited_api'] == True + + finally: + setuptools.__version__ = orig_version 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 @@ -1975,9 +1975,9 @@ def test_function_returns_partial_struct(): ffi = FFI() - ffi.cdef("struct a { int a; ...; }; struct a f1(int);") + ffi.cdef("struct aaa { int a; ...; }; struct aaa f1(int);") lib = verify(ffi, "test_function_returns_partial_struct", """ - struct a { int b, a, c; }; - static struct a f1(int x) { struct a s = {0}; s.a = x; return s; } + struct aaa { int b, a, c; }; + static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; } """) assert lib.f1(52).a == 52 diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -97,6 +97,21 @@ OPENSSL_VERSION_NUMBER = cconfig["OPENSSL_VERSION_NUMBER"] HAVE_TLSv1_2 = OPENSSL_VERSION_NUMBER >= 0x10001000 +if OPENSSL_VERSION_NUMBER >= 0x10100000: + eci.pre_include_bits = () + eci.post_include_bits = () + raise Exception("""OpenSSL version >= 1.1 not supported yet. + + This program requires OpenSSL version 1.0.x, and may also + work with LibreSSL or OpenSSL 0.9.x. OpenSSL 1.1 is quite + some work to update to; contributions are welcome. Sorry, + you need to install an older version of OpenSSL for now. + Make sure this older version is the one picked up by this + program when it runs the compiler. + + This is the configuration used: %r""" % (eci,)) + + class CConfig: _compilation_info_ = eci diff --git a/rpython/rlib/runicode.py b/rpython/rlib/runicode.py --- a/rpython/rlib/runicode.py +++ b/rpython/rlib/runicode.py @@ -1,5 +1,5 @@ import sys -from rpython.rlib.objectmodel import specialize, we_are_translated +from rpython.rlib.objectmodel import specialize, we_are_translated, enforceargs from rpython.rlib.rstring import StringBuilder, UnicodeBuilder from rpython.rlib.rarithmetic import r_uint, intmask, widen from rpython.rlib.unicodedata import unicodedb @@ -145,19 +145,21 @@ _invalid_byte_3_of_4 = _invalid_cont_byte _invalid_byte_4_of_4 = _invalid_cont_byte [email protected](2) +@enforceargs(allow_surrogates=bool) def _invalid_byte_2_of_3(ordch1, ordch2, allow_surrogates): return (ordch2>>6 != 0x2 or # 0b10 (ordch1 == 0xe0 and ordch2 < 0xa0) # surrogates shouldn't be valid UTF-8! - or (not allow_surrogates and ordch1 == 0xed and ordch2 > 0x9f)) + or (ordch1 == 0xed and ordch2 > 0x9f and not allow_surrogates)) def _invalid_byte_2_of_4(ordch1, ordch2): return (ordch2>>6 != 0x2 or # 0b10 (ordch1 == 0xf0 and ordch2 < 0x90) or (ordch1 == 0xf4 and ordch2 > 0x8f)) [email protected](5) +# note: this specialize() is here for rtyper/rstr.py, which calls this +# function too but with its own fixed errorhandler [email protected]_or_var(4) def str_decode_utf_8_impl(s, size, errors, final, errorhandler, allow_surrogates, result): if size == 0: @@ -330,6 +332,9 @@ return unicode_encode_utf_8_impl(s, size, errors, errorhandler, allow_surrogates=allow_surrogates) +# note: this specialize() is here for rtyper/rstr.py, which calls this +# function too but with its own fixed errorhandler [email protected]_or_var(3) def unicode_encode_utf_8_impl(s, size, errors, errorhandler, allow_surrogates=False): assert(size >= 0) diff --git a/rpython/rlib/test/test_runicode.py b/rpython/rlib/test/test_runicode.py --- a/rpython/rlib/test/test_runicode.py +++ b/rpython/rlib/test/test_runicode.py @@ -55,7 +55,7 @@ s = s.encode(encoding) except LookupError as e: py.test.skip(e) - result, consumed = decoder(s, len(s), True) + result, consumed = decoder(s, len(s), 'strict', final=True) assert consumed == len(s) self.typeequals(trueresult, result) @@ -69,7 +69,7 @@ s = s.decode(encoding) except LookupError as e: py.test.skip(e) - result = encoder(s, len(s), True) + result = encoder(s, len(s), 'strict') self.typeequals(trueresult, result) def checkencodeerror(self, s, encoding, start, stop): @@ -823,9 +823,15 @@ def f(x): s1 = "".join(["\xd7\x90\xd6\x96\xeb\x96\x95\xf0\x90\x91\x93"] * x) - u, consumed = runicode.str_decode_utf_8(s1, len(s1), True) - s2 = runicode.unicode_encode_utf_8(u, len(u), True) - return s1 == s2 + u, consumed = runicode.str_decode_utf_8(s1, len(s1), 'strict', + allow_surrogates=True) + s2 = runicode.unicode_encode_utf_8(u, len(u), 'strict', + allow_surrogates=True) + u3, consumed3 = runicode.str_decode_utf_8(s1, len(s1), 'strict', + allow_surrogates=False) + s3 = runicode.unicode_encode_utf_8(u3, len(u3), 'strict', + allow_surrogates=False) + return s1 == s2 == s3 res = interpret(f, [2]) assert res diff --git a/rpython/rtyper/rint.py b/rpython/rtyper/rint.py --- a/rpython/rtyper/rint.py +++ b/rpython/rtyper/rint.py @@ -540,7 +540,7 @@ def ll_ullong_py_mod_zer(x, y): if y == 0: raise ZeroDivisionError - return llop.ullong_mod(UnsignedLongLong, x, y) + return ll_ullong_py_mod(x, y) @jit.dont_look_inside def ll_lllong_py_mod(x, y): diff --git a/rpython/rtyper/rstr.py b/rpython/rtyper/rstr.py --- a/rpython/rtyper/rstr.py +++ b/rpython/rtyper/rstr.py @@ -30,12 +30,13 @@ assert value is not None result = UnicodeBuilder(len(value)) self.rstr_decode_utf_8( - value, len(value), 'strict', final=False, + value, len(value), 'strict', final=True, errorhandler=self.ll_raise_unicode_exception_decode, allow_surrogates=False, result=result) return self.ll.llunicode(result.build()) - def ll_raise_unicode_exception_decode(self, errors, encoding, msg, s, + @staticmethod + def ll_raise_unicode_exception_decode(errors, encoding, msg, s, startingpos, endingpos): raise UnicodeDecodeError(encoding, s, startingpos, endingpos, msg) @@ -411,7 +412,8 @@ allow_surrogates=False) return self.ll.llstr(bytes) - def ll_raise_unicode_exception_encode(self, errors, encoding, msg, u, + @staticmethod + def ll_raise_unicode_exception_encode(errors, encoding, msg, u, startingpos, endingpos): raise UnicodeEncodeError(encoding, u, startingpos, endingpos, msg) diff --git a/rpython/rtyper/test/test_runicode.py b/rpython/rtyper/test/test_runicode.py --- a/rpython/rtyper/test/test_runicode.py +++ b/rpython/rtyper/test/test_runicode.py @@ -162,6 +162,18 @@ assert self.ll_to_string(self.interpret(f, [0])) == f(0) + def test_unicode_decode_final(self): + strings = ['\xc3', ''] + def f(n): + try: + strings[n].decode('utf-8') + except UnicodeDecodeError: + return True + return False + + assert f(0) + assert self.interpret(f, [0]) + def test_utf_8_decoding_annotation(self): from rpython.rlib.runicode import str_decode_utf_8 def errorhandler(errors, encoding, msg, s, _______________________________________________ pypy-commit mailing list [email protected] https://mail.python.org/mailman/listinfo/pypy-commit
