[pypy-commit] pypy py3.5: fix test_mixedmodule.py
Author: Ronan LamyBranch: py3.5 Changeset: r91627:675b2f4d2399 Date: 2017-06-19 17:41 +0100 http://bitbucket.org/pypy/pypy/changeset/675b2f4d2399/ Log:fix test_mixedmodule.py diff --git a/pypy/interpreter/test/test_mixedmodule.py b/pypy/interpreter/test/test_mixedmodule.py --- a/pypy/interpreter/test/test_mixedmodule.py +++ b/pypy/interpreter/test/test_mixedmodule.py @@ -1,38 +1,43 @@ +import pytest + +from pypy.tool.pytest.objspace import maketestobjspace from pypy.interpreter.mixedmodule import MixedModule -import py.test +@pytest.fixture() +def space(): +# We need a fresh space for each test here +return maketestobjspace() -class TestMixedModule(object): -def test_install(self): -class Module(MixedModule): -interpleveldefs = {} -appleveldefs = {} +def test_install(space): +class Module(MixedModule): +interpleveldefs = {} +appleveldefs = {} -m = Module(self.space, self.space.wrap("test_module")) -m.install() +m = Module(space, space.wrap("test_module")) +m.install() -assert self.space.builtin_modules["test_module"] is m +assert space.builtin_modules["test_module"] is m -def test_submodule(self): -class SubModule(MixedModule): -interpleveldefs = {} -appleveldefs = {} +def test_submodule(space): +class SubModule(MixedModule): +interpleveldefs = {} +appleveldefs = {} -class Module(MixedModule): -interpleveldefs = {} -appleveldefs = {} -submodules = { -"sub": SubModule -} +class Module(MixedModule): +interpleveldefs = {} +appleveldefs = {} +submodules = { +"sub": SubModule +} -m = Module(self.space, self.space.wrap("test_module")) -m.install() +m = Module(space, space.wrap("test_module")) +m.install() -assert self.space.builtin_modules["test_module"] is m -assert isinstance(self.space.builtin_modules["test_module.sub"], SubModule) +assert space.builtin_modules["test_module"] is m +assert isinstance(space.builtin_modules["test_module.sub"], SubModule) class AppTestMixedModule(object): -pytestmark = py.test.mark.skipif("config.option.runappdirect") +pytestmark = pytest.mark.skipif("config.option.runappdirect") def setup_class(cls): space = cls.space ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy py3.5: fix test
Author: Ronan LamyBranch: py3.5 Changeset: r91628:44469c25a324 Date: 2017-06-19 19:21 +0100 http://bitbucket.org/pypy/pypy/changeset/44469c25a324/ Log:fix test diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py --- a/pypy/module/imp/test/test_app.py +++ b/pypy/module/imp/test/test_app.py @@ -115,6 +115,7 @@ mod = imp.init_builtin(name) assert mod assert mod.__spec__ +test_is_builtin.dont_track_allocations = True def test_load_module_py(self): import imp ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy default: make FrozenDict fail PySequence_Check() - fixes obscure numpy test failure
Author: Matti PicusBranch: Changeset: r91626:6d81023ea3fe Date: 2017-06-19 20:01 +0300 http://bitbucket.org/pypy/pypy/changeset/6d81023ea3fe/ Log:make FrozenDict fail PySequence_Check() - fixes obscure numpy test failure diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py --- a/pypy/module/cpyext/dictobject.py +++ b/pypy/module/cpyext/dictobject.py @@ -290,6 +290,7 @@ def make_frozendict(space): if space not in _frozendict_cache: _frozendict_cache[space] = _make_frozendict(space) +_frozendict_cache[space].flag_map_or_seq = 'M' return _frozendict_cache[space] _frozendict_cache = {} diff --git a/pypy/module/cpyext/test/test_iterator.py b/pypy/module/cpyext/test/test_iterator.py --- a/pypy/module/cpyext/test/test_iterator.py +++ b/pypy/module/cpyext/test/test_iterator.py @@ -33,6 +33,11 @@ return obj; ''' ), + ("get_dictproxy", "METH_O", +''' +return PyDictProxy_New(args); +''' +), ("check", "METH_O", ''' return PyInt_FromLong( @@ -74,6 +79,10 @@ assert operator.isMappingType(obj) # assert module.check(obj) == 2 +# make sure dictionaries return false for PySequence_Check +assert module.check({'a': 1}) == 2 +obj = module.get_dictproxy({'a': 10}) +assert module.check(obj) == 2 def test_iterable_nonmapping_object(self): module = self.import_extension('foo', [ ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: bah, I won't attempt to find the correct #ifdef magic to use on MSVC in C++ mode to know if 'char16_t' exists. The official one doesn't work, so meh.
Author: Armin RigoBranch: Changeset: r2988:40a258cefe22 Date: 2017-06-19 12:35 +0200 http://bitbucket.org/cffi/cffi/changeset/40a258cefe22/ Log:bah, I won't attempt to find the correct #ifdef magic to use on MSVC in C++ mode to know if 'char16_t' exists. The official one doesn't work, so meh. diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -2259,6 +2259,9 @@ assert ffi.typeof("int16_t") is ffi.typeof("char16_t") is ffi.typeof("long") def test_char16_char32_type(no_cpp=False): +if no_cpp is False and sys.platform == "win32": +py.test.skip("aaa why do modern MSVC compilers still define " + "a very old __cplusplus value") ffi = FFI() ffi.cdef(""" char16_t foo_2bytes(char16_t); @@ -2269,7 +2272,7 @@ typedef uint_least16_t char16_t; typedef uint_least32_t char32_t; #endif - + char16_t foo_2bytes(char16_t a) { return (char16_t)(a + 42); } char32_t foo_4bytes(char32_t a) { return (char32_t)(a + 42); } """, no_cpp=no_cpp) ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: More test fixes on Windows on Python 3
Author: Armin RigoBranch: Changeset: r2987:b4e78ef300b0 Date: 2017-06-19 12:27 +0200 http://bitbucket.org/cffi/cffi/changeset/b4e78ef300b0/ Log:More test fixes on Windows on Python 3 diff --git a/testing/cffi1/test_new_ffi_1.py b/testing/cffi1/test_new_ffi_1.py --- a/testing/cffi1/test_new_ffi_1.py +++ b/testing/cffi1/test_new_ffi_1.py @@ -418,7 +418,6 @@ # p = ffi.new("wchar_t[]", u+'\U00023456') if SIZE_OF_WCHAR == 2: -assert sys.maxunicode == 0x assert len(p) == 3 assert p[0] == u+'\ud84d' assert p[1] == u+'\udc56' diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py --- a/testing/cffi1/test_re_python.py +++ b/testing/cffi1/test_re_python.py @@ -94,6 +94,8 @@ if sys.platform == 'win32': import ctypes.util name = ctypes.util.find_msvcrt() +if name is None: +py.test.skip("dlopen(None) cannot work on Windows with Python 3") lib = ffi.dlopen(name) assert lib.strlen(b"hello") == 5 ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Probable improvement
Author: Armin RigoBranch: Changeset: r2986:54a7350ed586 Date: 2017-06-19 12:26 +0200 http://bitbucket.org/cffi/cffi/changeset/54a7350ed586/ Log:Probable improvement diff --git a/c/wchar_helper_3.h b/c/wchar_helper_3.h --- a/c/wchar_helper_3.h +++ b/c/wchar_helper_3.h @@ -143,13 +143,7 @@ cffi_char32_t *result, Py_ssize_t resultlen) { -Py_ssize_t len = PyUnicode_GET_LENGTH(unicode); -unsigned int kind = PyUnicode_KIND(unicode); -void *data = PyUnicode_DATA(unicode); -Py_ssize_t i; - -for (i = 0; i < len; i++) -result[i] = PyUnicode_READ(kind, data, i); - +if (PyUnicode_AsUCS4(unicode, (Py_UCS4 *)result, resultlen, 0) == NULL) +return -1; return 0; } ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Don't use error capture around ffi.gc() finalizer errors
Author: Armin RigoBranch: Changeset: r2984:1d3da4b31373 Date: 2017-06-19 11:58 +0200 http://bitbucket.org/cffi/cffi/changeset/1d3da4b31373/ Log:Don't use error capture around ffi.gc() finalizer errors diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1852,12 +1852,15 @@ Py_DECREF(result); } else { -PyObject *ecap, *t, *v, *tb; +PyObject *t, *v, *tb; PyErr_Fetch(, , ); -ecap = _cffi_start_error_capture(); +/* Don't use error capture here, because it is very much + * like errors at __del__(), and these ones are not captured + * either */ +/* ecap = _cffi_start_error_capture(); */ _my_PyErr_WriteUnraisable(t, v, tb, "From callback for ffi.gc ", origobj, NULL); -_cffi_stop_error_capture(ecap); +/* _cffi_stop_error_capture(ecap); */ } Py_DECREF(destructor); ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] cffi default: Write a copy of wchar_helper.h that uses CPython 3.3's new
Author: Armin RigoBranch: Changeset: r2985:5e554e5c0dfc Date: 2017-06-19 12:06 +0200 http://bitbucket.org/cffi/cffi/changeset/5e554e5c0dfc/ Log:Write a copy of wchar_helper.h that uses CPython 3.3's new unicode string API. It makes sense anyway for speed reasons, but it also avoids even more special cases for platforms with 16-bit wchar_t on CPython >= 3.3. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -286,7 +286,11 @@ # include "file_emulator.h" #endif -#include "wchar_helper.h" +#ifdef PyUnicode_KIND /* Python >= 3.3 */ +# include "wchar_helper_3.h" +#else +# include "wchar_helper.h" +#endif #include "../cffi/_cffi_errors.h" diff --git a/c/wchar_helper_3.h b/c/wchar_helper_3.h new file mode 100644 --- /dev/null +++ b/c/wchar_helper_3.h @@ -0,0 +1,155 @@ +/* + * wchar_t helpers, version CPython >= 3.3. + * + * CPython 3.3 added support for sys.maxunicode == 0x10 on all + * platforms, even ones with wchar_t limited to 2 bytes. As such, + * this code here works from the outside like wchar_helper.h in the + * case Py_UNICODE_SIZE == 4, but the implementation is very different. + */ + +typedef uint16_t cffi_char16_t; +typedef uint32_t cffi_char32_t; + + +static PyObject * +_my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size) +{ +return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, w, size); +} + +static PyObject * +_my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size) +{ +/* are there any surrogate pairs, and if so, how many? */ +Py_ssize_t i, count_surrogates = 0; +for (i = 0; i < size - 1; i++) { +if (0xD800 <= w[i] && w[i] <= 0xDBFF && +0xDC00 <= w[i+1] && w[i+1] <= 0xDFFF) +count_surrogates++; +} +if (count_surrogates == 0) { +/* no, fast path */ +return PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, w, size); +} +else +{ +PyObject *result = PyUnicode_New(size - count_surrogates, 0x10); +Py_UCS4 *data; +assert(PyUnicode_KIND(result) == PyUnicode_4BYTE_KIND); +data = PyUnicode_4BYTE_DATA(result); + +for (i = 0; i < size; i++) +{ +cffi_char32_t ch = w[i]; +if (0xD800 <= ch && ch <= 0xDBFF && i < size - 1) { +cffi_char32_t ch2 = w[i + 1]; +if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { +ch = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x1; +i++; +} +} +*data++ = ch; +} +return result; +} +} + +static int +_my_PyUnicode_AsSingleChar16(PyObject *unicode, cffi_char16_t *result, + char *err_got) +{ +cffi_char32_t ch; +if (PyUnicode_GET_LENGTH(unicode) != 1) { +sprintf(err_got, "unicode string of length %zd", +PyUnicode_GET_LENGTH(unicode)); +return -1; +} +ch = PyUnicode_READ_CHAR(unicode, 0); + +if (ch > 0x) +{ +sprintf(err_got, "larger-than-0x character"); +return -1; +} +*result = (cffi_char16_t)ch; +return 0; +} + +static int +_my_PyUnicode_AsSingleChar32(PyObject *unicode, cffi_char32_t *result, + char *err_got) +{ +if (PyUnicode_GET_LENGTH(unicode) != 1) { +sprintf(err_got, "unicode string of length %zd", +PyUnicode_GET_LENGTH(unicode)); +return -1; +} +*result = PyUnicode_READ_CHAR(unicode, 0); +return 0; +} + +static Py_ssize_t _my_PyUnicode_SizeAsChar16(PyObject *unicode) +{ +Py_ssize_t length = PyUnicode_GET_LENGTH(unicode); +Py_ssize_t result = length; +unsigned int kind = PyUnicode_KIND(unicode); + +if (kind == PyUnicode_4BYTE_KIND) +{ +Py_UCS4 *data = PyUnicode_4BYTE_DATA(unicode); +Py_ssize_t i; +for (i = 0; i < length; i++) { +if (data[i] > 0x) +result++; +} +} +return result; +} + +static Py_ssize_t _my_PyUnicode_SizeAsChar32(PyObject *unicode) +{ +return PyUnicode_GET_LENGTH(unicode); +} + +static int _my_PyUnicode_AsChar16(PyObject *unicode, + cffi_char16_t *result, + Py_ssize_t resultlen) +{ +Py_ssize_t len = PyUnicode_GET_LENGTH(unicode); +unsigned int kind = PyUnicode_KIND(unicode); +void *data = PyUnicode_DATA(unicode); +Py_ssize_t i; + +for (i = 0; i < len; i++) { +cffi_char32_t ordinal = PyUnicode_READ(kind, data, i); +if (ordinal > 0x) { +if (ordinal > 0x10) { +PyErr_Format(PyExc_ValueError, + "unicode character out of range for " + "conversion to char16_t: 0x%x", (int)ordinal); +return -1; +} +ordinal -= 0x1; +*result++ =
[pypy-commit] cffi default: Some test fixes for Python 3 on Windows
Author: Armin RigoBranch: Changeset: r2983:09cc68d4b9cf Date: 2017-06-19 10:55 +0200 http://bitbucket.org/cffi/cffi/changeset/09cc68d4b9cf/ Log:Some test fixes for Python 3 on Windows diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -61,6 +61,10 @@ path = None else: path = ctypes.util.find_library(name) +if path is None and name == 'c': +assert sys.platform == 'win32' +assert sys.version_info >= (3,) +py.test.skip("dlopen(None) cannot work on Windows with Python 3") return load_library(path, flags) def test_load_library(): diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -765,7 +765,7 @@ if sys.platform != "win32": return backend.load_library(None, flags) name = "c"# Windows: load_library(None) fails, but this works - # (backward compatibility hack only) + # on Python 2 (backward compatibility hack only) first_error = None if '.' in name or '/' in name or os.sep in name: try: @@ -775,6 +775,9 @@ import ctypes.util path = ctypes.util.find_library(name) if path is None: +if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): +raise OSError("dlopen(None) cannot work on Windows for Python 3 " + "(see http://bugs.python.org/issue23606)") msg = ("ctypes.util.find_library() did not manage " "to locate a library called %r" % (name,)) if first_error is not None: diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst --- a/doc/source/cdef.rst +++ b/doc/source/cdef.rst @@ -306,7 +306,10 @@ contain a full path or not (in which case it is searched in standard locations, as described in ``man dlopen``), with extensions or not. Alternatively, if ``libpath`` is None, it returns the standard C library -(which can be used to access the functions of glibc, on Linux). +(which can be used to access the functions of glibc, on Linux). Note +that ``libpath`` `cannot be None`__ on Windows with Python 3. + +.. __: http://bugs.python.org/issue23606 Let me state it again: this gives ABI-level access to the library, so you need to have all types declared manually exactly as they were diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -10,6 +10,10 @@ SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p) SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar) +def needs_dlopen_none(): +if sys.platform == 'win32' and sys.version_info >= (3,): +py.test.skip("dlopen(None) cannot work on Windows for Python 3") + class BackendTests: @@ -354,7 +358,6 @@ # p = ffi.new("wchar_t[]", u+'\U00023456') if SIZE_OF_WCHAR == 2: -assert sys.maxunicode == 0x assert len(p) == 3 assert p[0] == u+'\ud84d' assert p[1] == u+'\udc56' @@ -937,6 +940,7 @@ def test_enum_partial(self): ffi = FFI(backend=self.Backend()) ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };") +needs_dlopen_none() lib = ffi.dlopen(None) assert lib.B == 0 py.test.raises(VerificationMissing, getattr, lib, "A") @@ -1844,6 +1848,7 @@ #define DOT_UL 1000UL enum foo {AA, BB=DOT, CC}; """) +needs_dlopen_none() lib = ffi.dlopen(None) assert ffi.string(ffi.cast("enum foo", 100)) == "BB" assert lib.DOT_0 == 0 @@ -1873,6 +1878,7 @@ ffi = FFI() ffi.include(ffi1) ffi.cdef("enum { EE2, EE3 };") +needs_dlopen_none() lib = ffi.dlopen(None) assert lib.EE1 == 0 assert lib.EE2 == 0 diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py --- a/testing/cffi0/test_function.py +++ b/testing/cffi0/test_function.py @@ -5,6 +5,7 @@ from cffi.backend_ctypes import CTypesBackend from testing.udir import udir from testing.support import FdWriteCapture +from .backend_tests import needs_dlopen_none try: from StringIO import StringIO @@ -111,6 +112,7 @@ int fputs(const char *, void *); void *stderr; """) +needs_dlopen_none() ffi.C = ffi.dlopen(None) ffi.C.fputs # fetch before capturing, for easier debugging with FdWriteCapture() as fd: @@ -127,6 +129,7 @@ int fputs(char *, void *); void *stderr; """) +needs_dlopen_none() ffi.C = ffi.dlopen(None) ffi.C.fputs # fetch before capturing, for easier debugging with FdWriteCapture() as fd: @@ -143,6 +146,7 @@ int fprintf(void *, const char *format, ...); void *stderr; """) +needs_dlopen_none() ffi.C =
[pypy-commit] cffi default: Py3 compat
Author: Armin RigoBranch: Changeset: r2982:7495a3729d42 Date: 2017-06-19 10:12 +0200 http://bitbucket.org/cffi/cffi/changeset/7495a3729d42/ Log:Py3 compat diff --git a/cffi/_cffi_errors.h b/cffi/_cffi_errors.h --- a/cffi/_cffi_errors.h +++ b/cffi/_cffi_errors.h @@ -36,7 +36,11 @@ if (result == NULL) goto error; +#if PY_MAJOR_VERSION >= 3 +bi = PyImport_ImportModule("builtins"); +#else bi = PyImport_ImportModule("__builtin__"); +#endif if (bi == NULL) goto error; PyDict_SetItemString(result, "__builtins__", bi); ___ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit
[pypy-commit] pypy py3.5: hg merge default
Author: Armin RigoBranch: py3.5 Changeset: r91625:be1dadf96ba4 Date: 2017-06-19 09:59 +0200 http://bitbucket.org/pypy/pypy/changeset/be1dadf96ba4/ Log:hg merge default also attempt to write the Python3 version of cffi's errorbox.py on Windows, but not tested so far diff --git a/lib_pypy/cffi/_cffi_errors.h b/lib_pypy/cffi/_cffi_errors.h new file mode 100644 --- /dev/null +++ b/lib_pypy/cffi/_cffi_errors.h @@ -0,0 +1,141 @@ +#ifndef CFFI_MESSAGEBOX +# ifdef _MSC_VER +# define CFFI_MESSAGEBOX 1 +# else +# define CFFI_MESSAGEBOX 0 +# endif +#endif + + +#if CFFI_MESSAGEBOX +/* Windows only: logic to take the Python-CFFI embedding logic + initialization errors and display them in a background thread + with MessageBox. The idea is that if the whole program closes + as a result of this problem, then likely it is already a console + program and you can read the stderr output in the console too. + If it is not a console program, then it will likely show its own + dialog to complain, or generally not abruptly close, and for this + case the background thread should stay alive. +*/ +static void *volatile _cffi_bootstrap_text; + +static PyObject *_cffi_start_error_capture(void) +{ +PyObject *result = NULL; +PyObject *x, *m, *bi; + +if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, +(void *)1, NULL) != NULL) +return (PyObject *)1; + +m = PyImport_AddModule("_cffi_error_capture"); +if (m == NULL) +goto error; + +result = PyModule_GetDict(m); +if (result == NULL) +goto error; + +bi = PyImport_ImportModule("__builtin__"); +if (bi == NULL) +goto error; +PyDict_SetItemString(result, "__builtins__", bi); +Py_DECREF(bi); + +x = PyRun_String( +"import sys\n" +"class FileLike:\n" +" def write(self, x):\n" +"of.write(x)\n" +"self.buf += x\n" +"fl = FileLike()\n" +"fl.buf = ''\n" +"of = sys.stderr\n" +"sys.stderr = fl\n" +"def done():\n" +" sys.stderr = of\n" +" return fl.buf\n", /* make sure the returned value stays alive */ +Py_file_input, +result, result); +Py_XDECREF(x); + + error: +if (PyErr_Occurred()) +{ +PyErr_WriteUnraisable(Py_None); +PyErr_Clear(); +} +return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ +Sleep(666);/* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 +MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, +L"Python-CFFI error", +MB_OK | MB_ICONERROR); +#else +MessageBoxA(NULL, (char *)_cffi_bootstrap_text, +"Python-CFFI error", +MB_OK | MB_ICONERROR); +#endif +_cffi_bootstrap_text = NULL; +return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ +PyObject *s; +void *text; + +if (ecap == (PyObject *)1) +return; + +if (ecap == NULL) +goto error; + +s = PyRun_String("done()", Py_eval_input, ecap, ecap); +if (s == NULL) +goto error; + +/* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 +text = PyUnicode_AsWideCharString(s, NULL); +#else +text = PyString_AsString(s); +#endif + +_cffi_bootstrap_text = text; + +if (text != NULL) +{ +HANDLE h; +h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); +if (h != NULL) +CloseHandle(h); +} +/* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ +Py_DECREF(s); +PyErr_Clear(); +return; + + error: +_cffi_bootstrap_text = NULL; +PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif 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 @@ -109,6 +109,8 @@ /** CPython-specific section **/ #ifndef PYPY_VERSION +#include "_cffi_errors.h" + #define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] @@ -220,8 +222,16 @@ /* Print as much information as potentially useful. Debugging load-time failures with embedding is not fun */ +PyObject *ecap; PyObject *exception, *v, *tb, *f, *modules, *mod; PyErr_Fetch(, , ); +ecap = _cffi_start_error_capture(); +f =
[pypy-commit] pypy default: update to cffi/cace5cac5ccb
Author: Armin RigoBranch: Changeset: r91624:211e6e8190f1 Date: 2017-06-19 09:34 +0200 http://bitbucket.org/pypy/pypy/changeset/211e6e8190f1/ Log:update to cffi/cace5cac5ccb diff --git a/lib_pypy/cffi/_cffi_errors.h b/lib_pypy/cffi/_cffi_errors.h new file mode 100644 --- /dev/null +++ b/lib_pypy/cffi/_cffi_errors.h @@ -0,0 +1,141 @@ +#ifndef CFFI_MESSAGEBOX +# ifdef _MSC_VER +# define CFFI_MESSAGEBOX 1 +# else +# define CFFI_MESSAGEBOX 0 +# endif +#endif + + +#if CFFI_MESSAGEBOX +/* Windows only: logic to take the Python-CFFI embedding logic + initialization errors and display them in a background thread + with MessageBox. The idea is that if the whole program closes + as a result of this problem, then likely it is already a console + program and you can read the stderr output in the console too. + If it is not a console program, then it will likely show its own + dialog to complain, or generally not abruptly close, and for this + case the background thread should stay alive. +*/ +static void *volatile _cffi_bootstrap_text; + +static PyObject *_cffi_start_error_capture(void) +{ +PyObject *result = NULL; +PyObject *x, *m, *bi; + +if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, +(void *)1, NULL) != NULL) +return (PyObject *)1; + +m = PyImport_AddModule("_cffi_error_capture"); +if (m == NULL) +goto error; + +result = PyModule_GetDict(m); +if (result == NULL) +goto error; + +bi = PyImport_ImportModule("__builtin__"); +if (bi == NULL) +goto error; +PyDict_SetItemString(result, "__builtins__", bi); +Py_DECREF(bi); + +x = PyRun_String( +"import sys\n" +"class FileLike:\n" +" def write(self, x):\n" +"of.write(x)\n" +"self.buf += x\n" +"fl = FileLike()\n" +"fl.buf = ''\n" +"of = sys.stderr\n" +"sys.stderr = fl\n" +"def done():\n" +" sys.stderr = of\n" +" return fl.buf\n", /* make sure the returned value stays alive */ +Py_file_input, +result, result); +Py_XDECREF(x); + + error: +if (PyErr_Occurred()) +{ +PyErr_WriteUnraisable(Py_None); +PyErr_Clear(); +} +return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ +Sleep(666);/* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 +MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, +L"Python-CFFI error", +MB_OK | MB_ICONERROR); +#else +MessageBoxA(NULL, (char *)_cffi_bootstrap_text, +"Python-CFFI error", +MB_OK | MB_ICONERROR); +#endif +_cffi_bootstrap_text = NULL; +return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ +PyObject *s; +void *text; + +if (ecap == (PyObject *)1) +return; + +if (ecap == NULL) +goto error; + +s = PyRun_String("done()", Py_eval_input, ecap, ecap); +if (s == NULL) +goto error; + +/* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 +text = PyUnicode_AsWideCharString(s, NULL); +#else +text = PyString_AsString(s); +#endif + +_cffi_bootstrap_text = text; + +if (text != NULL) +{ +HANDLE h; +h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); +if (h != NULL) +CloseHandle(h); +} +/* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ +Py_DECREF(s); +PyErr_Clear(); +return; + + error: +_cffi_bootstrap_text = NULL; +PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif 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 @@ -109,6 +109,8 @@ /** CPython-specific section **/ #ifndef PYPY_VERSION +#include "_cffi_errors.h" + #define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] @@ -220,8 +222,16 @@ /* Print as much information as potentially useful. Debugging load-time failures with embedding is not fun */ +PyObject *ecap; PyObject *exception, *v, *tb, *f, *modules, *mod; PyErr_Fetch(, , ); +ecap = _cffi_start_error_capture(); +f = PySys_GetObject((char *)"stderr"); +if (f != NULL && f != Py_None) { +PyFile_WriteString( +