Author: Armin Rigo <ar...@tunes.org> Branch: py3k Changeset: r86605:471b3d7456a2 Date: 2016-08-27 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/471b3d7456a2/
Log: hg merge default diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -58,16 +58,16 @@ # General information about the project. project = u'PyPy' -copyright = u'2015, The PyPy Project' +copyright = u'2016, The PyPy Project' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '4.0' +version = '5.4' # The full version, including alpha/beta/rc tags. -release = '4.0.0' +release = '5.4.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst --- a/pypy/doc/index-of-release-notes.rst +++ b/pypy/doc/index-of-release-notes.rst @@ -6,6 +6,7 @@ .. toctree:: + release-pypy2.7-v5.4.0.rst release-pypy2.7-v5.3.1.rst release-pypy2.7-v5.3.0.rst release-5.1.1.rst diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst --- a/pypy/doc/index-of-whatsnew.rst +++ b/pypy/doc/index-of-whatsnew.rst @@ -7,6 +7,7 @@ .. toctree:: whatsnew-head.rst + whatsnew-pypy2-5.4.0.rst whatsnew-pypy2-5.3.1.rst whatsnew-pypy2-5.3.0.rst whatsnew-5.1.0.rst diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -57,7 +57,7 @@ -------------- Our cpyext C-API compatiblity layer can now run upstream NumPy unmodified. -Release PyPy2.7-v5.3 still fails about 200 of the ~6000 test in the NumPy +Release PyPy2.7-v5.4 still fails about 60 of the ~6000 test in the NumPy test suite. We could use help analyzing the failures and fixing them either as patches to upstream NumPy, or as fixes to PyPy. diff --git a/pypy/doc/release-pypy2.7-v5.4.0.rst b/pypy/doc/release-pypy2.7-v5.4.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-pypy2.7-v5.4.0.rst @@ -0,0 +1,219 @@ +============ +PyPy2.7 v5.4 +============ + +We have released PyPy2.7 v5.4, a little under two months after PyPy2.7 v5.3. +This new PyPy2.7 release includes further improvements to our C-API compatability layer (cpyext), enabling us to pass over 99% of the upstream +numpy `test suite`_. We updated built-in cffi_ support to version 1.8, +which now supports the "limited API" mode for c-extensions on +CPython >=3.2. + +We improved tooling for the PyPy JIT_, and expanded VMProf +support to OpenBSD and Dragon Fly BSD + +As always, this release fixed many issues and bugs raised by the +growing community of PyPy users. + +XXXXX MORE ??? + +You can download the PyPy2.7 v5.4 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project. + +We would also like to thank our contributors and +encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ +with making RPython's JIT even better. + +.. _`test suite`: https://bitbucket.org/pypy/pypy/wiki/Adventures%20in%20cpyext%20compatibility +.. _cffi: https://cffi.readthedocs.org +.. _JIT: https://morepypy.blogspot.com.au/2016/08/pypy-tooling-upgrade-jitviewer-and.html +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other `dynamic languages`_ to see what RPython +can do for them. + +This release supports: + + * **x86** machines on most common operating systems + (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD) + + * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + +.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://pypyjs.org + +Other Highlights (since 5.3 released in June 2016) +========================================================= + +* New features: + + * Add `sys.{get,set}dlopenflags` + + * Improve CPython compatibility of 'is' for small and empty strings + + * Support for rgc.FinalizerQueue in the Boehm garbage collector + + * (RPython) support spawnv() if it is called in C `_spawnv` on windows + + * Fill in more slots when creating a PyTypeObject from a W_TypeObject, + like `__hex__`, `__sub__`, `__pow__` + + * Copy CPython's logic more closely for `isinstance()` and + `issubclass()` as well as `type.__instancecheck__()` and + `type.__subclasscheck__()` + + * Expose the name of CDLL objects + + * Rewrite the win32 dependencies of `subprocess` to use cffi + instead of ctypes + + * Improve the `JIT logging`_ facitilities + + * (RPython) make int * string work + + * Allocate all RPython strings with one extra byte, normally + unused. This now allows `ffi.from_buffer(string)` in CFFI with + no copy + + * Adds a new commandline option `-X track-resources` that will + produce a `ResourceWarning` when the GC closes a file or socket. + The traceback for the place where the file or socket was allocated + is given as well, which aids finding places where `close()` is + missing + + * Add missing `PyObject_Realloc`, `PySequence_GetSlice` + + * `type.__dict__` now returns a `dict_proxy` object, like on CPython. + Previously it returned what looked like a regular dict object (but + it was already read-only) + + * (RPython) add `rposix.{get,set}_inheritable()`, needed by Python 3.5 + + * (RPython) add `rposix_scandir` portably, needed for Python 3.5 + + * Support for memoryview attributes (format, itemsize, ...) which also + adds support for `PyMemoryView_FromObject` + +* Bug Fixes + + * Reject `mkdir()` in read-only sandbox filesystems + + * Add include guards to pymem.h to enable c++ compilation + + * Fix build breakage on OpenBSD and FreeBSD + + * Support OpenBSD, Dragon Fly BSD in VMProf + + * Fix for `bytearray('').replace('a', 'ab')` for empty strings + + * Sync internal state before calling `PyFile_AsFile()` + + * Allow writing to a char* from `PyString_AsString()` until it is + forced, also refactor `PyStringObject` to look like CPython's + and allow subclassing `PyString_Type` and `PyUnicode_Type` + + * Rpython rffi's socket(2) wrapper did not preserve errno + + * Refactor `PyTupleObject` to look like CPython's and allow + subclassing `PyTuple_Type` + + * Allow c-level assignment to a function pointer in a C-API + user-defined type after calling PyTypeReady by retrieving + a pointer to the function via offsets + rather than storing the function pointer itself + + * Use `madvise(MADV_FREE)`, or if that doesn't exist + `MADV_DONTNEED` on freed arenas to release memory back to the + OS for resource monitoring + + * Fix overflow detection in conversion of float to 64-bit integer + in timeout argument to various thread/threading primitives + + * Fix win32 outputting `\r\r\n` in some cases + + * Make `hash(-1)` return -2, as CPython does, and fix all the + ancilary places this matters + + * Issues reported with our previous release were resolved_ after + reports from users on our issue tracker at + https://bitbucket.org/pypy/pypy/issues or on IRC at #pypy + + * Fix `PyNumber_Check()` to behave more like CPython + + * (VMProf) Try hard to not miss any Python-level frame in the + captured stacks, even if there is metainterp or blackhole interp + involved. Also fix the stacklet (greenlet) support + + * Fix a critical JIT bug where `raw_malloc` -equivalent functions + lost the additional flags + + * Fix the mapdict cache for subclasses of builtin types that + provide a dict + +* Performance improvements: + + * Add a before_call()-like equivalent before a few operations like + `malloc_nursery`, to move values from registers into other registers + instead of to the stack. + + * More tightly pack the stack when calling with `release gil` + + * Support `int_floordiv()`, `int_mod()` in the JIT more efficiently + and add `rarithmetic.int_c_div()`, `rarithmetic.int_c_mod()` as + explicit interfaces. Clarify that `int_floordiv()` does python-style + rounding, unlike `llop.int_floordiv()`. + + * Use `ll_assert` (more often) in incminimark + + * (Testing) Simplify handling of interp-level tests and make it + more forward-compatible. Don't use interp-level RPython + machinery to test building app-level extensions in cpyext + + * Constant-fold `ffi.offsetof("structname", "fieldname")` in cffi + backend + + * Avoid a case in the JIT, where successive guard failures in + the same Python function end up as successive levels of + RPython functions, eventually exhausting the stack, while at + app-level the traceback is very short + + * Check for NULL returns from calls to the raw-malloc and raise, + rather than a guard + + * Improve `socket.recvfrom()` so that it copies less if possible + + * When generating C code, inline `goto` to blocks with only one + predecessor, generating less lines of code + + * When running the final backend-optimization phase before emitting + C code, constant-fold calls to we_are_jitted to return False. This + makes the generated C code a few percent smaller + + * Refactor the `uid_t/gid_t` handling in `rlib.rposix` and in + `interp_posix.py`, based on the clean-up of CPython 2.7.x + +.. _`JIT logging`: https://morepypy.blogspot.com/2016/08/pypy-tooling-upgrade-jitviewer-and.html +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-5.4.0.html + +Please update, and continue to help us make PyPy better. + +Cheers diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -1,157 +1,8 @@ -========================= -What's new in PyPy2.7 5.3+ -========================= +========================== +What's new in PyPy2.7 5.4+ +========================== -.. this is a revision shortly after release-pypy2.7-v5.3 -.. startrev: 873218a739f1 +.. this is a revision shortly after release-pypy2.7-v5.4 +.. startrev: 4176c6f63109 -.. 418b05f95db5 -Improve CPython compatibility for ``is``. Now code like ``if x is ():`` -works the same way as it does on CPython. See http://pypy.readthedocs.io/en/latest/cpython_differences.html#object-identity-of-primitive-values-is-and-id . -.. pull request #455 -Add sys.{get,set}dlopenflags, for cpyext extensions. - -.. branch: fix-gen-dfa - -Resolves an issue with the generator script to build the dfa for Python syntax. - -.. branch: z196-support - -Fixes a critical issue in the register allocator and extends support on s390x. -PyPy runs and translates on the s390x revisions z10 (released February 2008, experimental) -and z196 (released August 2010) in addition to zEC12 and z13. -To target e.g. z196 on a zEC12 machine supply CFLAGS="-march=z196" to your shell environment. - -.. branch: s390x-5.3-catchup - -Implement the backend related changes for s390x. - -.. branch: incminimark-ll_assert -.. branch: vmprof-openbsd - -.. branch: testing-cleanup - -Simplify handling of interp-level tests and make it more forward- -compatible. - -.. branch: pyfile-tell -Sync w_file with the c-level FILE* before returning FILE* in PyFile_AsFile - -.. branch: rw-PyString_AS_STRING -Allow rw access to the char* returned from PyString_AS_STRING, also refactor -PyStringObject to look like cpython's and allow subclassing PyString_Type and -PyUnicode_Type - -.. branch: save_socket_errno - -Bug fix: if ``socket.socket()`` failed, the ``socket.error`` did not show -the errno of the failing system call, but instead some random previous -errno. - -.. branch: PyTuple_Type-subclass - -Refactor PyTupleObject to look like cpython's and allow subclassing -PyTuple_Type - -.. branch: call-via-pyobj - -Use offsets from PyTypeObject to find actual c function to call rather than -fixed functions, allows function override after PyType_Ready is called - -.. branch: issue2335 - -Avoid exhausting the stack in the JIT due to successive guard -failures in the same Python function ending up as successive levels of -RPython functions, while at app-level the traceback is very short - -.. branch: use-madv-free - -Try harder to memory to the OS. See e.g. issue #2336. Note that it does -not show up as a reduction of the VIRT column in ``top``, and the RES -column might also not show the reduction, particularly on Linux >= 4.5 or -on OS/X: it uses MADV_FREE, which only marks the pages as returnable to -the OS if the memory is low. - -.. branch: cpyext-slotdefs2 - -Fill in more slots when creating a PyTypeObject from a W_TypeObject -More slots are still TBD, like tp_print and richcmp - -.. branch: json-surrogates - -Align json module decode with the cpython's impl, fixes issue 2345 - -.. branch: issue2343 - -Copy CPython's logic more closely for handling of ``__instancecheck__()`` -and ``__subclasscheck__()``. Fixes issue 2343. - -.. branch: msvcrt-cffi - -Rewrite the Win32 dependencies of 'subprocess' to use cffi instead -of ctypes. This avoids importing ctypes in many small programs and -scripts, which in turn avoids enabling threads (because ctypes -creates callbacks at import time, and callbacks need threads). - -.. branch: new-jit-log - -The new logging facility that integrates with and adds features to vmprof.com. - -.. branch: jitlog-32bit - -Resolve issues to use the new logging facility on a 32bit system - -.. branch: ep2016sprint - -Trying harder to make hash(-1) return -2, like it does on CPython - -.. branch: jitlog-exact-source-lines - -Log exact line positions in debug merge points. - -.. branch: null_byte_after_str - -Allocate all RPython strings with one extra byte, normally unused. -It is used to hold a final zero in case we need some ``char *`` -representation of the string, together with checks like ``not -can_move()`` or object pinning. Main new thing that this allows: -``ffi.from_buffer(string)`` in CFFI. Additionally, and most -importantly, CFFI calls that take directly a string as argument don't -copy the string any more---this is like CFFI on CPython. - -.. branch: resource_warning - -Add a new command line option -X track-resources which will produce -ResourceWarnings when the GC closes unclosed files and sockets. - -.. branch: cpyext-realloc - -Implement PyObject_Realloc - -.. branch: inline-blocks - -Improve a little bit the readability of the generated C code - -.. branch: improve-vmprof-testing - -Improved vmprof support: now tries hard to not miss any Python-level -frame in the captured stacks, even if there is the metainterp or -blackhole interp involved. Also fix the stacklet (greenlet) support. - -.. branch: py2-mappingproxy - -``type.__dict__`` now returns a ``dict_proxy`` object, like on CPython. -Previously it returned what looked like a regular dict object (but it -was already read-only). - - -.. branch: const-fold-we-are-jitted - -Reduce the size of the generated C code by constant-folding ``we_are_jitted`` -in non-jitcode. - -.. branch: memoryview-attributes - -Support for memoryview attributes (format, itemsize, ...). -Extends the cpyext emulation layer. diff --git a/pypy/doc/whatsnew-pypy2-5.4.0.rst b/pypy/doc/whatsnew-pypy2-5.4.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/whatsnew-pypy2-5.4.0.rst @@ -0,0 +1,165 @@ +========================= +What's new in PyPy2.7 5.4 +========================= + +.. this is a revision shortly after release-pypy2.7-v5.3 +.. startrev: 873218a739f1 + +.. 418b05f95db5 +Improve CPython compatibility for ``is``. Now code like ``if x is ():`` +works the same way as it does on CPython. See http://pypy.readthedocs.io/en/latest/cpython_differences.html#object-identity-of-primitive-values-is-and-id . + +.. pull request #455 +Add sys.{get,set}dlopenflags, for cpyext extensions. + +.. branch: fix-gen-dfa + +Resolves an issue with the generator script to build the dfa for Python syntax. + +.. branch: z196-support + +Fixes a critical issue in the register allocator and extends support on s390x. +PyPy runs and translates on the s390x revisions z10 (released February 2008, experimental) +and z196 (released August 2010) in addition to zEC12 and z13. +To target e.g. z196 on a zEC12 machine supply CFLAGS="-march=z196" to your shell environment. + +.. branch: s390x-5.3-catchup + +Implement the backend related changes for s390x. + +.. branch: incminimark-ll_assert +.. branch: vmprof-openbsd + +.. branch: testing-cleanup + +Simplify handling of interp-level tests and make it more forward- +compatible. + +.. branch: pyfile-tell +Sync w_file with the c-level FILE* before returning FILE* in PyFile_AsFile + +.. branch: rw-PyString_AS_STRING +Allow rw access to the char* returned from PyString_AS_STRING, also refactor +PyStringObject to look like cpython's and allow subclassing PyString_Type and +PyUnicode_Type + +.. branch: save_socket_errno + +Bug fix: if ``socket.socket()`` failed, the ``socket.error`` did not show +the errno of the failing system call, but instead some random previous +errno. + +.. branch: PyTuple_Type-subclass + +Refactor PyTupleObject to look like cpython's and allow subclassing +PyTuple_Type + +.. branch: call-via-pyobj + +Use offsets from PyTypeObject to find actual c function to call rather than +fixed functions, allows function override after PyType_Ready is called + +.. branch: issue2335 + +Avoid exhausting the stack in the JIT due to successive guard +failures in the same Python function ending up as successive levels of +RPython functions, while at app-level the traceback is very short + +.. branch: use-madv-free + +Try harder to memory to the OS. See e.g. issue #2336. Note that it does +not show up as a reduction of the VIRT column in ``top``, and the RES +column might also not show the reduction, particularly on Linux >= 4.5 or +on OS/X: it uses MADV_FREE, which only marks the pages as returnable to +the OS if the memory is low. + +.. branch: cpyext-slotdefs2 + +Fill in more slots when creating a PyTypeObject from a W_TypeObject +More slots are still TBD, like tp_print and richcmp + +.. branch: json-surrogates + +Align json module decode with the cpython's impl, fixes issue 2345 + +.. branch: issue2343 + +Copy CPython's logic more closely for handling of ``__instancecheck__()`` +and ``__subclasscheck__()``. Fixes issue 2343. + +.. branch: msvcrt-cffi + +Rewrite the Win32 dependencies of 'subprocess' to use cffi instead +of ctypes. This avoids importing ctypes in many small programs and +scripts, which in turn avoids enabling threads (because ctypes +creates callbacks at import time, and callbacks need threads). + +.. branch: new-jit-log + +The new logging facility that integrates with and adds features to vmprof.com. + +.. branch: jitlog-32bit + +Resolve issues to use the new logging facility on a 32bit system + +.. branch: ep2016sprint + +Trying harder to make hash(-1) return -2, like it does on CPython + +.. branch: jitlog-exact-source-lines + +Log exact line positions in debug merge points. + +.. branch: null_byte_after_str + +Allocate all RPython strings with one extra byte, normally unused. +It is used to hold a final zero in case we need some ``char *`` +representation of the string, together with checks like ``not +can_move()`` or object pinning. Main new thing that this allows: +``ffi.from_buffer(string)`` in CFFI. Additionally, and most +importantly, CFFI calls that take directly a string as argument don't +copy the string any more---this is like CFFI on CPython. + +.. branch: resource_warning + +Add a new command line option -X track-resources which will produce +ResourceWarnings when the GC closes unclosed files and sockets. + +.. branch: cpyext-realloc + +Implement PyObject_Realloc + +.. branch: inline-blocks + +Improve a little bit the readability of the generated C code + +.. branch: improve-vmprof-testing + +Improved vmprof support: now tries hard to not miss any Python-level +frame in the captured stacks, even if there is the metainterp or +blackhole interp involved. Also fix the stacklet (greenlet) support. + +.. branch: py2-mappingproxy + +``type.__dict__`` now returns a ``dict_proxy`` object, like on CPython. +Previously it returned what looked like a regular dict object (but it +was already read-only). + + +.. branch: const-fold-we-are-jitted + +Reduce the size of the generated C code by constant-folding ``we_are_jitted`` +in non-jitcode. + +.. branch: memoryview-attributes + +Support for memoryview attributes (format, itemsize, ...). +Extends the cpyext emulation layer. + +.. branch: redirect-assembler-jitlog + +Log more information to properly rebuild the redirected traces in jitviewer. + +.. branch: cpyext-subclass + +Copy Py_TPFLAGS_CHECKTYPES, Py_TPFLAGS_HAVE_INPLACEOPS when inheriting diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py --- a/pypy/module/_winreg/interp_winreg.py +++ b/pypy/module/_winreg/interp_winreg.py @@ -356,9 +356,15 @@ elif typ == rwinreg.REG_SZ or typ == rwinreg.REG_EXPAND_SZ: if not buflen: - return space.wrap("") - s = rffi.charp2strn(rffi.cast(rffi.CCHARP, buf), buflen) - return space.wrap(s) + s = "" + else: + # may or may not have a trailing NULL in the buffer. + buf = rffi.cast(rffi.CCHARP, buf) + if buf[buflen - 1] == '\x00': + buflen -= 1 + s = rffi.charp2strn(buf, buflen) + w_s = space.wrap(s) + return space.call_method(w_s, 'decode', space.wrap('mbcs')) elif typ == rwinreg.REG_MULTI_SZ: if not buflen: @@ -458,7 +464,7 @@ return space.newtuple([ convert_from_regdata(space, databuf, length, retType[0]), - space.wrap(retType[0]), + space.wrap(intmask(retType[0])), ]) @unwrap_spec(subkey=str) @@ -610,7 +616,7 @@ space.wrap(rffi.charp2str(valuebuf)), convert_from_regdata(space, databuf, length, retType[0]), - space.wrap(retType[0]), + space.wrap(intmask(retType[0])), ]) @unwrap_spec(index=int) diff --git a/pypy/module/_winreg/test/test_winreg.py b/pypy/module/_winreg/test/test_winreg.py --- a/pypy/module/_winreg/test/test_winreg.py +++ b/pypy/module/_winreg/test/test_winreg.py @@ -154,6 +154,7 @@ def test_readValues(self): from winreg import OpenKey, EnumValue, QueryValueEx, EnumKey + from winreg import REG_SZ, REG_EXPAND_SZ key = OpenKey(self.root_key, self.test_key_name) sub_key = OpenKey(key, "sub_key") index = 0 @@ -167,7 +168,10 @@ assert index == len(self.test_data) for name, value, type in self.test_data: - assert QueryValueEx(sub_key, name) == (value, type) + result = QueryValueEx(sub_key, name) + assert result == (value, type) + if type == REG_SZ or type == REG_EXPAND_SZ: + assert isinstance(result[0], unicode) # not string assert EnumKey(key, 0) == "sub_key" raises(EnvironmentError, EnumKey, key, 1) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -119,7 +119,7 @@ constant_names = """ Py_TPFLAGS_READY Py_TPFLAGS_READYING Py_TPFLAGS_HAVE_GETCHARBUFFER METH_COEXIST METH_STATIC METH_CLASS Py_TPFLAGS_BASETYPE -METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O +METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O Py_TPFLAGS_HAVE_INPLACEOPS Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_HAVE_NEWBUFFER Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES Py_CLEANUP_SUPPORTED @@ -975,13 +975,15 @@ py_type_ready(space, get_capsule_type()) INIT_FUNCTIONS.append(init_types) from pypy.module.posix.interp_posix import add_fork_hook - reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void, - compilation_info=eci) global py_fatalerror py_fatalerror = rffi.llexternal('%s_FatalError' % prefix, [CONST_STRING], lltype.Void, compilation_info=eci) - add_fork_hook('child', reinit_tls) + _reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], + lltype.Void, compilation_info=eci) + def reinit_tls(space): + _reinit_tls() + add_fork_hook('child', _reinit_tls) def init_function(func): INIT_FUNCTIONS.append(func) 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 "3.3.5" /* PyPy version as a string */ -#define PYPY_VERSION "5.3.2-alpha0" -#define PYPY_VERSION_NUM 0x05030200 +#define PYPY_VERSION "5.4.1-alpha0" +#define PYPY_VERSION_NUM 0x05040100 /* 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/buffer_test.c b/pypy/module/cpyext/test/buffer_test.c --- a/pypy/module/cpyext/test/buffer_test.c +++ b/pypy/module/cpyext/test/buffer_test.c @@ -1,3 +1,6 @@ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS 1 +#endif #include <Python.h> #include <stdlib.h> #include <stdio.h> @@ -10,7 +13,7 @@ /* Structure defines a 1-dimensional strided array */ typedef struct{ int* arr; - long length; + Py_ssize_t length; } MyArray; /* initialize the array with integers 0...length */ @@ -61,13 +64,13 @@ static int PyMyArray_init(PyMyArray *self, PyObject *args, PyObject *kwds) { + int length = 0; + static char *kwlist[] = {"length", NULL}; // init may have already been called if (self->arr.arr != NULL) { deallocate_MyArray(&self->arr); } - int length = 0; - static char *kwlist[] = {"length", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &length)) return -1; @@ -103,16 +106,19 @@ static int PyMyArray_getbuffer(PyObject *obj, Py_buffer *view, int flags) { + PyMyArray* self = (PyMyArray*)obj; + fprintf(stdout, "in PyMyArray_getbuffer\n"); if (view == NULL) { + fprintf(stdout, "view is NULL\n"); PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer"); return -1; } if (flags == 0) { + fprintf(stdout, "flags is 0\n"); PyErr_SetString(PyExc_ValueError, "flags == 0 in getbuffer"); return -1; } - PyMyArray* self = (PyMyArray*)obj; view->obj = (PyObject*)self; view->buf = (void*)self->arr.arr; view->len = self->arr.length * sizeof(int); @@ -218,7 +224,6 @@ #ifdef __GNUC__ extern __attribute__((visibility("default"))) #else -extern __declspec(dllexport) #endif PyMODINIT_FUNC diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py --- a/pypy/module/cpyext/test/test_arraymodule.py +++ b/pypy/module/cpyext/test/test_arraymodule.py @@ -77,4 +77,13 @@ module.switch_multiply() res = [1, 2, 3] * arr assert res == [2, 4, 6] + + def test_subclass(self): + module = self.import_module(name='array') + class Sub(module.array): + pass + + arr = Sub('i', [2]) + res = [1, 2, 3] * arr + assert res == [1, 2, 3, 1, 2, 3] diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -18,7 +18,8 @@ Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL, Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder, PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr, - Py_TPFLAGS_HAVE_NEWBUFFER) + Py_TPFLAGS_HAVE_NEWBUFFER, Py_TPFLAGS_CHECKTYPES, + Py_TPFLAGS_HAVE_INPLACEOPS) from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject, W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef, W_PyCMethodObject, W_PyCFunctionObject) @@ -386,6 +387,8 @@ pto.c_tp_basicsize = base_pto.c_tp_basicsize if pto.c_tp_itemsize < base_pto.c_tp_itemsize: pto.c_tp_itemsize = base_pto.c_tp_itemsize + pto.c_tp_flags |= base_pto.c_tp_flags & Py_TPFLAGS_CHECKTYPES + pto.c_tp_flags |= base_pto.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS flags = rffi.cast(lltype.Signed, pto.c_tp_flags) base_object_pyo = make_ref(space, space.w_object) base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo) @@ -721,8 +724,13 @@ # inheriting tp_as_* slots base = py_type.c_tp_base if base: - if not py_type.c_tp_as_number: py_type.c_tp_as_number = base.c_tp_as_number - if not py_type.c_tp_as_sequence: py_type.c_tp_as_sequence = base.c_tp_as_sequence + if not py_type.c_tp_as_number: + py_type.c_tp_as_number = base.c_tp_as_number + py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_CHECKTYPES + py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS + if not py_type.c_tp_as_sequence: + py_type.c_tp_as_sequence = base.c_tp_as_sequence + py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS if not py_type.c_tp_as_mapping: py_type.c_tp_as_mapping = base.c_tp_as_mapping if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -398,6 +398,8 @@ os.write(slave_fd, b'x\n') data = os.read(master_fd, 100) assert data.startswith(b'x') + os.close(master_fd) + os.close(slave_fd) if hasattr(__import__(os.name), "forkpty"): def test_forkpty(self): 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, 3, 2, "alpha", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (5, 4, 1, "alpha", 0) #XXX # sync patchlevel.h import pypy diff --git a/pypy/module/test_lib_pypy/test_gdbm_extra.py b/pypy/module/test_lib_pypy/test_gdbm_extra.py --- a/pypy/module/test_lib_pypy/test_gdbm_extra.py +++ b/pypy/module/test_lib_pypy/test_gdbm_extra.py @@ -15,3 +15,7 @@ assert len(g) == 2 del g['abc'] assert len(g) == 1 + +def test_unicode(): + path = unicode(udir.join('test_gdm_unicode')) + g = gdbm.open(path, 'c') # does not crash diff --git a/pypy/module/test_lib_pypy/test_resource.py b/pypy/module/test_lib_pypy/test_resource.py --- a/pypy/module/test_lib_pypy/test_resource.py +++ b/pypy/module/test_lib_pypy/test_resource.py @@ -1,4 +1,5 @@ from __future__ import absolute_import +import sys import os if os.name != 'posix': @@ -47,6 +48,9 @@ # minimal "does not crash" test x, y = resource.getrlimit(resource.RLIMIT_CPU) resource.setrlimit(resource.RLIMIT_CPU, (x, y)) - x += 0.2 - y += 0.3 - resource.setrlimit(resource.RLIMIT_CPU, (x, y)) # truncated to ints + # sometimes, x and y are very large (more than 53 bits). + # for these huge values, int(float(x)) > x... + xf = x + (0.2 if x >= 0 else -0.2) + yf = y + (0.3 if y >= 0 else -0.3) + if int(xf) == x and int(yf) == y: + resource.setrlimit(resource.RLIMIT_CPU, (x, y)) # truncated to ints diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py --- a/pypy/objspace/std/complexobject.py +++ b/pypy/objspace/std/complexobject.py @@ -346,9 +346,16 @@ def descr_hash(self, space): hashreal = _hash_float(space, self.realval) - hashimg = _hash_float(space, self.imagval) - combined = intmask(hashreal + HASH_IMAG * hashimg) - return space.newint(-2 if combined == -1 else combined) + hashimg = _hash_float(space, self.imagval) # 0 if self.imagval == 0 + h = intmask(hashreal + HASH_IMAG * hashimg) + h -= (h == -1) + return space.newint(h) + + def descr_coerce(self, space, w_other): + w_other = self._to_complex(space, w_other) + if w_other is None: + return space.w_NotImplemented + return space.newtuple([self, w_other]) def descr_format(self, space, w_format_spec): return newformat.run_formatter(space, w_format_spec, "format_complex", diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -399,7 +399,9 @@ descr_str = func_with_new_name(descr_repr, 'descr_str') def descr_hash(self, space): - return space.wrap(_hash_float(space, self.floatval)) + h = _hash_float(space, self.floatval) + h -= (h == -1) + return space.wrap(h) def descr_format(self, space, w_spec): return newformat.run_formatter(space, w_spec, "format_float", self) diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -991,7 +991,8 @@ if index != INVALID: attr = map.find_map_attr(attrname, index) if attr is not None: - # Note that if map.terminator is a DevolvedDictTerminator, + # Note that if map.terminator is a DevolvedDictTerminator + # or the class provides its own dict, not using mapdict, then: # map.find_map_attr will always return None if index==DICT. _fill_cache(pycode, nameindex, map, version_tag, attr.storageindex) return w_obj._mapdict_read_storage(attr.storageindex) @@ -1013,6 +1014,12 @@ def LOOKUP_METHOD_mapdict_fill_cache_method(space, pycode, name, nameindex, w_obj, w_type, w_method): + # if the layout has a dict itself, then mapdict is not used for normal + # attributes. Then the cache won't be able to spot changes to the dict. + # Thus we don't cache. see test_bug_builtin_types_callmethod + if w_type.layout.typedef.hasdict: + return + if w_method is None or isinstance(w_method, MutableCell): # don't cache the MutableCell XXX could be fixed return diff --git a/pypy/objspace/std/test/test_complexobject.py b/pypy/objspace/std/test/test_complexobject.py --- a/pypy/objspace/std/test/test_complexobject.py +++ b/pypy/objspace/std/test/test_complexobject.py @@ -671,3 +671,6 @@ assert sign(z2.real) == -1 assert sign(z2.real) == -1 + def test_hash_minus_one(self): + assert hash(-1.0 + 0j) == -2 + assert (-1.0 + 0j).__hash__() == -2 diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -475,6 +475,10 @@ s = '\U0001D7CF\U0001D7CE.4' # 𝟏𝟎.4 assert float(s) == 10.4 + def test_hash_minus_one(self): + assert hash(-1.0) == -2 + assert (-1.0).__hash__() == -2 + class AppTestFloatHex: spaceconfig = { diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -1238,6 +1238,42 @@ got = x.a assert got == 'd' + def test_bug_builtin_types_callmethod(self): + import sys + class D(type(sys)): + def mymethod(self): + return "mymethod" + + def foobar(): + return "foobar" + + d = D('d') + res1 = d.mymethod() + d.mymethod = foobar + res2 = d.mymethod() + assert res1 == "mymethod" + assert res2 == "foobar" + + def test_bug_builtin_types_load_attr(self): + import sys + class D(type(sys)): + def mymethod(self): + return "mymethod" + + def foobar(): + return "foobar" + + d = D('d') + m = d.mymethod + res1 = m() + d.mymethod = foobar + m = d.mymethod + res2 = m() + assert res1 == "mymethod" + assert res2 == "foobar" + + + class AppTestGlobalCaching(AppTestWithMapDict): spaceconfig = {"objspace.std.withmethodcachecounter": True} diff --git a/pypy/objspace/std/test/test_random_attr.py b/pypy/objspace/std/test/test_random_attr.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_random_attr.py @@ -0,0 +1,134 @@ +import pytest +import sys +from pypy.tool.pytest.objspace import gettestobjspace +try: + from hypothesis import given, strategies, settings +except ImportError: + pytest.skip("requires hypothesis") + +base_initargs = strategies.sampled_from([ + ("object", (), False), + ("type(sys)", ("fake", ), True), + ("NewBase", (), True), + ("OldBase", (), False), + ("object, OldBase", (), False), + ("type(sys), OldBase", ("fake", ), True), + ]) + +attrnames = strategies.sampled_from(["a", "b", "c"]) + +@strategies.composite +def make_code(draw): + # now here we can do this kind of thing: + baseclass, initargs, hasdict = draw(base_initargs) + # and with arbitrary strategies + + def class_attr(): + what = draw(strategies.sampled_from(["value", "method", "property"])) + if what == "value": + val = draw(strategies.integers()) + return val, str(val) + if what == "method": + val = draw(strategies.integers()) + return (lambda self, val=val: val, + "lambda self: %d" % val) + if what == "property": + val = draw(strategies.integers()) + return (property(lambda self, val=val: val, + lambda self, val: None, + lambda self: None), + "property(lambda self: %d, lambda self, val: None, lambda self: None)" % val) + + code = ["import sys", "class OldBase:pass", "class NewBase(object):pass", "class A(%s):" % baseclass] + dct = {} + if draw(strategies.booleans()): + slots = draw(strategies.lists(attrnames)) + if not hasdict and draw(strategies.booleans()): + slots.append("__dict__") + dct["__slots__"] = slots + code.append(" __slots__ = %s" % (slots, )) + for name in ["a", "b", "c"]: + if not draw(strategies.booleans()): + continue + dct[name], codeval = class_attr() + code.append(" %s = %s" % (name, codeval)) + class OldBase: pass + class NewBase(object): pass + evaldct = {'OldBase': OldBase, 'NewBase': NewBase} + if baseclass == 'OldBase': + metaclass = type(OldBase) + else: + metaclass = type + cls = metaclass("A", eval(baseclass+',', globals(), evaldct), dct) + inst = cls(*initargs) + code.append(" pass") + code.append("a = A(*%s)" % (initargs, )) + for attr in draw(strategies.lists(attrnames, min_size=1)): + op = draw(strategies.sampled_from(["read", "read", "read", + "write", "writemeth", "writeclass", "writebase", + "del", "delclass"])) + if op == "read": + try: + res = getattr(inst, attr) + except AttributeError: + code.append("raises(AttributeError, 'a.%s')" % (attr, )) + else: + if callable(res): + code.append("assert a.%s() == %s" % (attr, res())) + else: + code.append("assert a.%s == %s" % (attr, res)) + elif op == "write": + val = draw(strategies.integers()) + try: + setattr(inst, attr, val) + except AttributeError: + code.append("raises(AttributeError, 'a.%s=%s')" % (attr, val)) + else: + code.append("a.%s = %s" % (attr, val)) + elif op == "writemeth": + val = draw(strategies.integers()) + try: + setattr(inst, attr, lambda val=val: val) + except AttributeError: + code.append("raises(AttributeError, 'a.%s=0')" % (attr, )) + else: + code.append("a.%s = lambda : %s" % (attr, val)) + elif op == "writeclass": + val, codeval = class_attr() + setattr(cls, attr, val) + code.append("A.%s = %s" % (attr, codeval)) + elif op == "writebase": + val, codeval = class_attr() + setattr(OldBase, attr, val) + setattr(NewBase, attr, val) + code.append("OldBase.%s = NewBase.%s = %s" % (attr, attr , codeval)) + elif op == "del": + try: + delattr(inst, attr) + except AttributeError: + code.append("raises(AttributeError, 'del a.%s')" % (attr, )) + else: + code.append("del a.%s" % (attr, )) + elif op == "delclass": + try: + delattr(cls, attr) + except AttributeError: + code.append("raises(AttributeError, 'del A.%s')" % (attr, )) + else: + code.append("del A.%s" % (attr, )) + return "\n ".join(code) + + +@given(make_code()) +#@settings(max_examples=5000) +def test_random_attrs(code): + try: + import __pypy__ + except ImportError: + pass + else: + pytest.skip("makes no sense under pypy!") + space = gettestobjspace() + print code + exec "if 1:\n " + code + space.appexec([], "():\n " + code) diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1064,6 +1064,8 @@ else: assert mc.get_relative_pos() <= 13 mc.copy_to_raw_memory(oldadr) + # log the redirection of the call_assembler_* operation + jl.redirect_assembler(oldlooptoken, newlooptoken, target) def dump(self, text): if not self.verbose: diff --git a/rpython/rlib/rjitlog/rjitlog.py b/rpython/rlib/rjitlog/rjitlog.py --- a/rpython/rlib/rjitlog/rjitlog.py +++ b/rpython/rlib/rjitlog/rjitlog.py @@ -212,7 +212,7 @@ return method return decor -JITLOG_VERSION = 2 +JITLOG_VERSION = 3 JITLOG_VERSION_16BIT_LE = struct.pack("<H", JITLOG_VERSION) marks = [ @@ -244,6 +244,7 @@ ('COMMON_PREFIX',), ('ABORT_TRACE',), ('SOURCE_CODE',), + ('REDIRECT_ASSEMBLER',), ] start = 0x11 @@ -309,6 +310,17 @@ content = ''.join(list) jitlog_write_marked(content, len(content)) +def redirect_assembler(oldtoken, newtoken, target): + if not jitlog_enabled(): + return + descr_nmr = compute_unique_id(oldtoken) + new_descr_nmr = compute_unique_id(newtoken) + list = [MARK_REDIRECT_ASSEMBLER, encode_le_addr(descr_nmr), + encode_le_addr(new_descr_nmr), encode_le_addr(target)] + content = ''.join(list) + jitlog_write_marked(content, len(content)) + + class JitLogger(object): def __init__(self, cpu=None): self.cpu = cpu diff --git a/rpython/rlib/rjitlog/test/test_jitlog.py b/rpython/rlib/rjitlog/test/test_jitlog.py --- a/rpython/rlib/rjitlog/test/test_jitlog.py +++ b/rpython/rlib/rjitlog/test/test_jitlog.py @@ -6,6 +6,15 @@ from rpython.jit.backend.model import AbstractCPU from rpython.jit.metainterp.history import ConstInt, ConstPtr from rpython.rlib.rjitlog import rjitlog as jl +from rpython.jit.metainterp.history import AbstractDescr +from rpython.rlib.objectmodel import compute_unique_id + +class FakeCallAssemblerLoopToken(AbstractDescr): + def __init__(self, target): + self._ll_function_addr = target + + def repr_of_descr(self): + return 'looptoken' class FakeLog(object): def __init__(self): @@ -109,3 +118,31 @@ with py.test.raises(AssertionError): jl.commonprefix(None,None) + def test_redirect_assembler(self, tmpdir): + looptoken = FakeCallAssemblerLoopToken(0x0) + newlooptoken = FakeCallAssemblerLoopToken(0x1234) + # + logger = jl.JitLogger() + file = tmpdir.join('binary_file') + file.ensure() + fd = file.open('wb') + jl.jitlog_init(fd.fileno()) + logger.start_new_trace(self.make_metainterp_sd(), jd_name='jdname') + log_trace = logger.log_trace(jl.MARK_TRACE, None, None) + op = ResOperation(rop.CALL_ASSEMBLER_I, [], descr=looptoken) + log_trace.write([], [op]) + jl.redirect_assembler(looptoken, newlooptoken, 0x1234) + #the next line will close 'fd', instead of logger.finish() + fd.close() + binary = file.read() + opnum = jl.encode_le_16bit(rop.CALL_ASSEMBLER_I) + id_looptoken = compute_unique_id(looptoken) + new_id_looptoken = compute_unique_id(newlooptoken) + end = jl.MARK_RESOP_DESCR + opnum + jl.encode_str('i0,looptoken') + \ + jl.encode_le_addr(id_looptoken) + jl.encode_str('') + \ + jl.MARK_REDIRECT_ASSEMBLER + \ + jl.encode_le_addr(id_looptoken) + \ + jl.encode_le_addr(new_id_looptoken) + \ + jl.encode_le_addr(newlooptoken._ll_function_addr) + assert binary.endswith(end) + diff --git a/rpython/rlib/rsocket.py b/rpython/rlib/rsocket.py --- a/rpython/rlib/rsocket.py +++ b/rpython/rlib/rsocket.py @@ -1099,12 +1099,14 @@ AF_UNIX if defined on the platform; otherwise, the default is AF_INET. """ result = lltype.malloc(_c.socketpair_t, 2, flavor='raw') - res = _c.socketpair(family, type, proto, result) - if res < 0: - raise last_error() - fd0 = rffi.cast(lltype.Signed, result[0]) - fd1 = rffi.cast(lltype.Signed, result[1]) - lltype.free(result, flavor='raw') + try: + res = _c.socketpair(family, type, proto, result) + if res < 0: + raise last_error() + fd0 = rffi.cast(lltype.Signed, result[0]) + fd1 = rffi.cast(lltype.Signed, result[1]) + finally: + lltype.free(result, flavor='raw') return (make_socket(fd0, family, type, proto, SocketClass), make_socket(fd1, family, type, proto, SocketClass)) diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -237,8 +237,10 @@ " directly to a VOIDP argument") _oops._annspecialcase_ = 'specialize:memo' + nb_args = len(args) unrolling_arg_tps = unrolling_iterable(enumerate(args)) def wrapper(*args): + assert len(args) == nb_args real_args = () # XXX 'to_free' leaks if an allocation fails with MemoryError # and was not the first in this function diff --git a/rpython/rtyper/lltypesystem/test/test_rffi.py b/rpython/rtyper/lltypesystem/test/test_rffi.py --- a/rpython/rtyper/lltypesystem/test/test_rffi.py +++ b/rpython/rtyper/lltypesystem/test/test_rffi.py @@ -49,6 +49,7 @@ eci = ExternalCompilationInfo(includes=['stuff.h'], include_dirs=[udir]) z = llexternal('X', [Signed], Signed, compilation_info=eci) + py.test.raises(AssertionError, z, 8, 9) def f(): return z(8) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit