Author: Ronan Lamy <[email protected]>
Branch: py3tests
Changeset: r96298:baa5e3964d15
Date: 2019-03-12 18:28 +0000
http://bitbucket.org/pypy/pypy/changeset/baa5e3964d15/

Log:    hg merge py3.6

diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -123,7 +123,9 @@
   Wenzhu Man
   Konstantin Lopuhin
   John Witulski
+  Stefan Beyer
   Jeremy Thurgood
+  Andrew Lawrence
   Greg Price
   Ivan Sichmann Freitas
   Dario Bertini
@@ -134,7 +136,6 @@
   Jean-Philippe St. Pierre
   Guido van Rossum
   Pavel Vinogradov
-  Stefan Beyer
   William Leslie
   Pawe&#322; Piotr Przeradowski
   marky1991
@@ -152,6 +153,7 @@
   Wanja Saatkamp
   Mike Blume
   Gerald Klix
+  Julian Berman
   Oscar Nierstrasz
   Rami Chowdhury
   Stefan H. Muller
@@ -174,6 +176,7 @@
   Anton Gulenko
   Sergey Matyunin
   Andrew Chambers
+  &#321;ukasz Langa
   Nicolas Chauvat
   Andrew Durdin
   Ben Young
@@ -296,7 +299,6 @@
   Bobby Impollonia
   Roberto De Ioris
   Jeong YunWon
-  andrewjlawrence
   Christopher Armstrong
   Aaron Tubbs
   Vasantha Ganesh K
@@ -328,7 +330,6 @@
   Ben Darnell
   Juan Francisco Cantero Hurtado
   Godefroid Chappelle
-  Julian Berman
   Stephan Busemann
   Dan Colish
   timo
diff --git a/extra_tests/ctypes_tests/test_structures.py 
b/extra_tests/ctypes_tests/test_structures.py
--- a/extra_tests/ctypes_tests/test_structures.py
+++ b/extra_tests/ctypes_tests/test_structures.py
@@ -119,12 +119,15 @@
             ms.n = 0xff00
             return repr(ba[:])
 
+        nstruct = dostruct(Native)
         if sys.byteorder == 'little':
-            assert dostruct(Native) == dostruct(Little)
-            assert dostruct(Native) != dostruct(Big)
+            assert nstruct == dostruct(Little)
+            assert nstruct != dostruct(Big)
+            assert Big._fields_[0][1] is not i
         else:
-            assert dostruct(Native) == dostruct(Big)
-            assert dostruct(Native) != dostruct(Little)
+            assert nstruct == dostruct(Big)
+            assert nstruct != dostruct(Little)
+            assert Little._fields_[0][1] is not i
 
 def test_from_buffer_copy():
     from array import array
@@ -185,3 +188,20 @@
     assert sizeof(s) == 3 * sizeof(c_int)
     assert s.a == 4     # 256 + 4
     assert s.b == -123
+
+def test_memoryview():
+    class S(Structure):
+        _fields_ = [('a', c_int16),
+                    ('b', c_int16),
+                   ]
+
+    S3 = S * 3
+    c_array = (2 * S3)(
+        S3(S(a=0, b=1), S(a=2, b=3), S(a=4,  b=5)),
+        S3(S(a=6, b=7), S(a=8, b=9), S(a=10, b=11)),
+        )
+
+    mv = memoryview(c_array)
+    assert mv.format == 'T{<h:a:<h:b:}'
+    assert mv.shape == (2, 3)
+    assert mv.itemsize == 4
diff --git a/extra_tests/requirements.txt b/extra_tests/requirements.txt
--- a/extra_tests/requirements.txt
+++ b/extra_tests/requirements.txt
@@ -1,3 +1,3 @@
-pytest
+pytest<=4.0
 hypothesis
 vmprof
diff --git a/lib_pypy/_blake2/_blake2_build.py 
b/lib_pypy/_blake2/_blake2_build.py
--- a/lib_pypy/_blake2/_blake2_build.py
+++ b/lib_pypy/_blake2/_blake2_build.py
@@ -8,11 +8,14 @@
 IS_WIN = sys.platform == 'win32'
 if IS_ARM:
     # XXX Choose neon accelaration
+    define_macros = []
     extra_compile_args = []
 elif IS_WIN:
-    extra_compile_args = ['/arch:SSE2']
+    extra_compile_args = []
+    define_macros = [('__SSE2__', '1')]
 else:
     extra_compile_args = ['-msse2']
+    define_macros = []
     
     
 
@@ -86,6 +89,7 @@
             ],
     include_dirs=[_libdir],
     extra_compile_args=extra_compile_args,
+    define_macros=define_macros,
 )
 
 def _replace_b2s(src):
@@ -102,6 +106,7 @@
             ],
     include_dirs=[_libdir],
     extra_compile_args=extra_compile_args,
+    define_macros=define_macros,
 )
 
 if __name__ == '__main__':
diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -4,6 +4,7 @@
 from _ctypes.basics import _CData, cdata_from_address, _CDataMeta, sizeof
 from _ctypes.basics import keepalive_key, store_reference, ensure_objects
 from _ctypes.basics import CArgObject, as_ffi_pointer
+import sys, __pypy__, struct
 
 class ArrayMeta(_CDataMeta):
     def __new__(self, name, cls, typedict):
@@ -247,6 +248,24 @@
     def _as_ffi_pointer_(self, ffitype):
         return as_ffi_pointer(self, ffitype)
 
+    def __buffer__(self, flags):
+        shape = []
+        obj = self
+        while 1:
+            shape.append(obj._length_)
+            try:
+                obj[0]._length_
+            except (AttributeError, IndexError):
+                break
+            obj = obj[0]
+
+        fmt = get_format_str(obj._type_)
+        try:
+            itemsize = struct.calcsize(fmt[1:])
+        except:
+            itemsize = sizeof(obj[0])
+        return __pypy__.newmemoryview(memoryview(self._buffer), itemsize, fmt, 
shape)
+
 ARRAY_CACHE = {}
 
 def create_array_type(base, length):
@@ -266,3 +285,31 @@
         cls = ArrayMeta(name, (Array,), tpdict)
         ARRAY_CACHE[key] = cls
         return cls
+
+byteorder = {'little': '<', 'big': '>'}
+swappedorder = {'little': '>', 'big': '<'}
+
+def get_format_str(typ):
+    if hasattr(typ, '_fields_'):
+        if hasattr(typ, '_swappedbytes_'):
+            bo = swappedorder[sys.byteorder]
+        else:
+            bo = byteorder[sys.byteorder]
+        flds = []
+        for name, obj in typ._fields_:
+            # Trim off the leading '<' or '>'
+            ch = get_format_str(obj)[1:]
+            if (ch) == 'B':
+                flds.append(byteorder[sys.byteorder])
+            else:
+                flds.append(bo)
+            flds.append(ch)
+            flds.append(':')
+            flds.append(name)
+            flds.append(':')
+        return 'T{' + ''.join(flds) + '}'
+    elif hasattr(typ, '_type_'):
+        ch = typ._type_
+        return byteorder[sys.byteorder] + ch
+    else:
+        raise ValueError('cannot get format string for %r' % typ)
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -2,8 +2,15 @@
 from _rawffi import alt as _ffi
 import sys
 
-try: from __pypy__ import builtinify
-except ImportError: builtinify = lambda f: f
+try:
+    from __pypy__ import builtinify
+except ImportError:
+    builtinify = lambda f: f
+
+try:
+    from __pypy__.bufferable import bufferable
+except ImportError:
+    bufferable = object
 
 keepalive_key = str # XXX fix this when provided with test
 
@@ -64,7 +71,7 @@
         'resbuffer' is a _rawffi array of length 1 containing the value,
         and this returns a general Python object that corresponds.
         """
-        res = object.__new__(self)
+        res = bufferable.__new__(self)
         res.__class__ = self
         res.__dict__['_buffer'] = resbuffer
         if base is not None:
@@ -148,7 +155,7 @@
     def __ne__(self, other):
         return self._obj != other
 
-class _CData(object, metaclass=_CDataMeta):
+class _CData(bufferable, metaclass=_CDataMeta):
     """ The most basic object for all ctypes types
     """
     _objects = None
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -7,8 +7,7 @@
 from _ctypes.array import Array, array_get_slice_params, array_slice_getitem,\
      array_slice_setitem
 
-try: from __pypy__ import builtinify
-except ImportError: builtinify = lambda f: f
+from __pypy__ import builtinify, newmemoryview
 
 # This cache maps types to pointers to them.
 _pointer_type_cache = {}
@@ -134,6 +133,9 @@
     def _as_ffi_pointer_(self, ffitype):
         return as_ffi_pointer(self, ffitype)
 
+    def __buffer__(self, flags):
+        mv = memoryview(self.getcontents())
+        return newmemoryview(mv, mv.itemsize, '&' + mv.format, mv.shape)
 
 def _cast_addr(obj, _, tp):
     if not (isinstance(tp, _CDataMeta) and tp._is_pointer_like()):
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -2,9 +2,9 @@
 import _rawffi
 from _ctypes.basics import _CData, _CDataMeta, keepalive_key,\
      store_reference, ensure_objects, CArgObject
-from _ctypes.array import Array
+from _ctypes.array import Array, get_format_str
 from _ctypes.pointer import _Pointer
-import inspect
+import inspect, __pypy__
 
 
 def names_and_fields(self, _fields_, superclass, anonymous_fields=None):
@@ -176,6 +176,11 @@
 class StructOrUnionMeta(_CDataMeta):
     def __new__(self, name, cls, typedict):
         res = type.__new__(self, name, cls, typedict)
+        if hasattr(res, '_swappedbytes_') and '_fields_' in typedict:
+            # Activate the stdlib ctypes._swapped_meta.__setattr__ to convert 
fields
+            tmp = res._fields_
+            delattr(res, '_fields_')
+            setattr(res, '_fields_', tmp)
         if "_abstract_" in typedict:
             return res
         cls = cls or (object,)
@@ -253,17 +258,7 @@
                                          or cls is union.Union):
             raise TypeError("abstract class")
         if hasattr(cls, '_swappedbytes_'):
-            fields = [None] * len(cls._fields_)
-            for i in range(len(cls._fields_)):
-                if cls._fields_[i][1] == 
cls._fields_[i][1].__dict__.get('__ctype_be__', None):
-                    swapped = cls._fields_[i][1].__dict__.get('__ctype_le__', 
cls._fields_[i][1])
-                else:
-                    swapped = cls._fields_[i][1].__dict__.get('__ctype_be__', 
cls._fields_[i][1])
-                if len(cls._fields_[i]) < 3:
-                    fields[i] = (cls._fields_[i][0], swapped)
-                else:
-                    fields[i] = (cls._fields_[i][0], swapped, 
cls._fields_[i][2])
-            names_and_fields(cls, fields, _CData, 
cls.__dict__.get('_anonymous_', None))
+            names_and_fields(cls, cls._fields_, _CData, 
cls.__dict__.get('_anonymous_', None))
         self = super(_CData, cls).__new__(cls)
         if hasattr(cls, '_ffistruct_'):
             self.__dict__['_buffer'] = self._ffistruct_(autofree=True)
@@ -303,6 +298,10 @@
     def _to_ffi_param(self):
         return self._buffer
 
+    def __buffer__(self, flags):
+        fmt = get_format_str(self)
+        itemsize = type(self)._sizeofinstances() 
+        return __pypy__.newmemoryview(memoryview(self._buffer), itemsize, fmt)
 
 class StructureMeta(StructOrUnionMeta):
     _is_union = False
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.12.1
+Version: 1.12.2
 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
@@ -5,8 +5,8 @@
 from .error import CDefError, FFIError, VerificationError, VerificationMissing
 from .error import PkgConfigError
 
-__version__ = "1.12.1"
-__version_info__ = (1, 12, 1)
+__version__ = "1.12.2"
+__version_info__ = (1, 12, 2)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
--- a/lib_pypy/cffi/_embedding.h
+++ b/lib_pypy/cffi/_embedding.h
@@ -221,7 +221,7 @@
 
         if (f != NULL && f != Py_None) {
             PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
-                               "\ncompiled with cffi version: 1.12.1"
+                               "\ncompiled with cffi version: 1.12.2"
                                "\n_cffi_backend module: ", f);
             modules = PyImport_GetModuleDict();
             mod = PyDict_GetItemString(modules, "_cffi_backend");
diff --git a/pypy/doc/__pypy__-module.rst b/pypy/doc/__pypy__-module.rst
--- a/pypy/doc/__pypy__-module.rst
+++ b/pypy/doc/__pypy__-module.rst
@@ -1,26 +1,186 @@
-.. comment: this document is very incomplete, should we generate
-            it automatically?
+.. comment: this document may get out of synch with the code, but to generate
+    it automatically we would need to use pypy to run sphinx-build
 
 The ``__pypy__`` module
 =======================
 
 The ``__pypy__`` module is the main entry point to special features provided
-by PyPy's standard interpreter. Its content depends on :doc:`configuration 
options <config/index>`
-which may add new functionality and functions whose existence or non-existence
-indicates the presence of such features.
-
+by PyPy's standard interpreter. Its content depends on :doc:`configuration
+options <config/index>` which may add new functionality and functions whose
+existence or non-existence indicates the presence of such features. These are
+generally used for compatibility when writing pure python modules that in
+CPython are written in C. Not available in CPython, and so must be used inside 
a
+``if platform.python_implementation == 'PyPy'`` block or otherwise hidden from
+the CPython interpreter.
 
 Generally available functionality
 ---------------------------------
 
- - ``internal_repr(obj)``: return the interpreter-level representation of an
-   object.
- - ``bytebuffer(length)``: return a new read-write buffer of the given length.
-   It works like a simplified array of characters (actually, depending on the
-   configuration the ``array`` module internally uses this).
- - ``attach_gdb()``: start a GDB at the interpreter-level (or a PDB before 
translation).
+  - ``internal_repr(obj)``: return the interpreter-level representation of an
+    object.
+  - ``bytebuffer(length)``: return a new read-write buffer of the given length.
+    It works like a simplified array of characters (actually, depending on the
+    configuration the ``array`` module internally uses this).
 
+  - ``attach_gdb()``: start a GDB at the interpreter-level (or a PDB before 
translation).
 
+ - ``newmemoryview(buffer, itemsize, format, shape=None, strides=None)``:
+   create a `memoryview` instance with the data from ``buffer`` and the
+   specified itemsize, format, and optional shape and strides.
+
+ - ``bufferable``: a base class that provides a ``__buffer__(self, flags)``
+   method for subclasses to override. This method should return a memoryview
+   instance of the class instance. It is called by the C-API's ``tp_as_buffer.
+   bf_getbuffer``.
+
+  - ``builtinify(func)``: To implement at app-level modules that are, in 
CPython,
+    implemented in C: this decorator protects a function from being ever bound
+    like a method.  Useful because some tests do things like put a "built-in"
+    function on a class and access it via the instance.
+
+  - ``hidden_applevel(func)``: Decorator that hides a function's frame from
+    app-level
+
+  - ``get_hidden_tb()``: Return the traceback of the current exception being
+    handled by a frame hidden from applevel.
+
+  - ``lookup_special(obj, meth)``: Lookup up a special method on an object.
+  - ``do_what_I_mean``
+
+  - ``resizelist_hint(...)``: Reallocate the underlying storage of the argument
+    list to sizehint
+
+  - ``newlist_hint(...)``: Create a new empty list that has an underlying
+    storage of length sizehint
+
+  - ``add_memory_pressure(bytes)``: Add memory pressure of estimate bytes.
+    Useful when calling a C function that internally allocates a big chunk of
+    memory. This instructs the GC to garbage collect sooner than it would
+    otherwise.
+
+  - ``newdict(type)``: Create a normal dict with a special implementation
+    strategy. ``type`` is a string and can be:
+
+    * ``"module"`` - equivalent to ``some_module.__dict__``
+
+    * ``"instance"`` - equivalent to an instance dict with a not-changing-much
+      set of keys
+
+    * ``"kwargs"`` - keyword args dict equivalent of what you get from
+      ``**kwargs`` in a function, optimized for passing around
+
+    * ``"strdict"`` - string-key only dict. This one should be chosen
+      automatically
+
+  - ``reversed_dict``: Enumerate the keys in a dictionary object in reversed
+    order.  This is a ``__pypy__`` function instead of being simply done by
+    calling reversed(), for CPython compatibility: dictionaries are ordered in
+    PyPY but not in Cpython2.7.  You should use the collections.OrderedDict
+    class for cases where ordering is important. That class implements
+    ``__reversed__`` by calling __pypy__.reversed_dict()
+
+  - ``dict_popitem_first``: Interp-level implementation of
+    ``OrderedDict.popitem(last=False)``.
+
+  - ``delitem_if_value_is`` Atomic equivalent to: ``if dict.get(key) is value:
+    del dict[key]``.
+
+    SPECIAL USE CASES ONLY!  Avoid using on dicts which are specialized,
+    e.g. to ``int`` or ``str`` keys, because it switches to the object
+    strategy. Also, the ``is`` operation is really pointer equality, so avoid
+    using it if ``value`` is an immutable object like ``int`` or ``str``.
+
+  - ``move_to_end``: Move the key in a dictionary object into the first or last
+    position. This is used in Python 3.x to implement 
``OrderedDict.move_to_end()``.
+
+  - ``strategy(dict or list or set)``: Return the underlying strategy currently
+    used by the object
+
+  - ``specialized_zip_2_lists``
+  - ``locals_to_fast``
+  - ``set_code_callback``
+  - ``save_module_content_for_future_reload``
+  - ``decode_long``
+  - ``side_effects_ok``: For use with the reverse-debugger: this function
+    normally returns True, but will return False if we are evaluating a
+    debugging command like a watchpoint.  You are responsible for not doing any
+    side effect at all (including no caching) when evaluating watchpoints. This
+    function is meant to help a bit---you can write::
+
+        if not __pypy__.side_effects_ok():
+            skip the caching logic
+
+    inside getter methods or properties, to make them usable from
+    watchpoints.  Note that you need to re-run ``REVDB=.. pypy``
+    after changing the Python code.
+
+  - ``stack_almost_full``: Return True if the stack is more than 15/16th full.
+  - ``pyos_inputhook``: Call PyOS_InputHook() from the CPython C API
+  - ``os.real_getenv(...)`` gets OS environment variables skipping python code
+  - ``_pypydatetime`` provides base classes with correct C API interactions for
+    the pure-python ``datetime`` stdlib module
+
+Fast String Concatenation
+-------------------------
+Rather than in-place concatenation ``+=``, use these to enable fast, minimal
+copy, string building.
+
+  - ``builders.StringBuilder``
+  - ``builders.UnicodeBuilder``
+
+Interacting with the PyPy debug log
+------------------------------------
+
+The following functions can be used to write your own content to the
+:ref:`PYPYLOG <pypylog>`.
+
+  - ``debug_start(category, timestamp=False)``: open a new section; if
+    ``timestamp`` is ``True``, also return the timestamp which was written to
+    the log.
+
+  - ``debug_stop(category, timestamp=False)``: close a section opened by
+    ``debug_start``.
+
+  - ``debug_print(...)``: print arbitrary text to the log.
+
+  - ``debug_print_once(category, ...)``: equivalent to ``debug_start`` +
+    ``debug_print`` + ``debug_stop``.
+
+  - ``debug_flush``: flush the log.
+
+  - ``debug_read_timestamp()``: read the timestamp from the same timer used by
+    the log.
+
+  - ``debug_get_timestamp_unit()``: get the unit of the value returned by
+    ``debug_read_timestamp()``.
+
+
+Depending on the architecture and operating system, PyPy uses different ways
+to read timestamps, so the timestamps used in the log file are expressed in
+varying units. It is possible to know which by calling
+``debug_get_timestamp_unit()``, which can be one of the following values:
+
+``tsc``
+    The default on ``x86`` machines: timestamps are expressed in CPU ticks, as
+    read by the `Time Stamp Counter`_.
+
+``ns``
+    Timestamps are expressed in nanoseconds.
+
+``QueryPerformanceCounter``
+    On Windows, in case for some reason ``tsc`` is not available: timestamps
+    are read using the win API ``QueryPerformanceCounter()``.
+
+
+Unfortunately, there does not seem to be a reliable standard way for
+converting ``tsc`` ticks into nanoseconds, although in practice on modern CPUs
+it is enough to divide the ticks by the maximum nominal frequency of the CPU.
+For this reason, PyPy gives the raw value, and leaves the job of doing the
+conversion to external libraries.
+
+.. _`Time Stamp Counter`: https://en.wikipedia.org/wiki/Time_Stamp_Counter    
+    
+   
 Transparent Proxy Functionality
 -------------------------------
 
@@ -34,6 +194,30 @@
    its controller. Otherwise return None.
 
 
+Additional Clocks for Timing
+----------------------------
+The ``time`` submodule exposes the platform-dependent clock types such as
+``CLOCK_BOOTTIME``, ``CLOCK_MONOTONIC``, ``CLOCK_MONOTONIC_COARSE``,
+``CLOCK_MONOTONIC_RAW`` and two functions:
+
+  - ``clock_gettime(m)`` which returns the clock type time in seconds and
+  - ``clock_getres(m)`` which returns the clock resolution in seconds.
+
+Extended Signal Handling
+------------------------
+``thread.signals_enbaled`` is a context manager to use in non-main threads.
+    enables receiving signals in a "with" statement.  More precisely, if a
+    signal is received by the process, then the signal handler might be
+    called either in the main thread (as usual) or within another thread
+    that is within a "with signals_enabled:".  This other thread should be
+    ready to handle unexpected exceptions that the signal handler might
+    raise --- notably KeyboardInterrupt.
+
+Integer Operations with Overflow
+--------------------------------
+  - ``intop`` provides a module with integer operations that have
+    two-complement overflow behaviour instead of overflowing to longs
+
 Functionality available on py.py (not after translation)
 --------------------------------------------------------
 
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -71,9 +71,9 @@
 #    module/cpyext/include/patchlevel.h
 #
 # The short X.Y version.
-version = '7.1'
+version = '7.2'
 # The full version, including alpha/beta/rc tags.
-release = '7.1.0'
+release = '7.2.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst
--- a/pypy/doc/contributor.rst
+++ b/pypy/doc/contributor.rst
@@ -90,7 +90,9 @@
   Wenzhu Man
   Konstantin Lopuhin
   John Witulski
+  Stefan Beyer
   Jeremy Thurgood
+  Andrew Lawrence
   Greg Price
   Ivan Sichmann Freitas
   Dario Bertini
@@ -101,7 +103,6 @@
   Jean-Philippe St. Pierre
   Guido van Rossum
   Pavel Vinogradov
-  Stefan Beyer
   William Leslie
   Pawe&#322; Piotr Przeradowski
   marky1991
@@ -119,6 +120,7 @@
   Wanja Saatkamp
   Mike Blume
   Gerald Klix
+  Julian Berman
   Oscar Nierstrasz
   Rami Chowdhury
   Stefan H. Muller
@@ -141,6 +143,7 @@
   Anton Gulenko
   Sergey Matyunin
   Andrew Chambers
+  &#321;ukasz Langa
   Nicolas Chauvat
   Andrew Durdin
   Ben Young
@@ -263,7 +266,6 @@
   Bobby Impollonia
   Roberto De Ioris
   Jeong YunWon
-  andrewjlawrence
   Christopher Armstrong
   Aaron Tubbs
   Vasantha Ganesh K
@@ -295,7 +297,6 @@
   Ben Darnell
   Juan Francisco Cantero Hurtado
   Godefroid Chappelle
-  Julian Berman
   Stephan Busemann
   Dan Colish
   timo
diff --git a/pypy/doc/gc_info.rst b/pypy/doc/gc_info.rst
--- a/pypy/doc/gc_info.rst
+++ b/pypy/doc/gc_info.rst
@@ -203,7 +203,7 @@
 
 ``duration``
     The total time spent inside minor collections since the last hook
-    call. See below for more information on the unit.
+    call, in seconds.
 
 ``duration_min``
     The duration of the fastest minor collection since the last hook call.
@@ -265,30 +265,6 @@
 ``gc-collect-done`` is used only to give additional stats, but doesn't do any
 actual work.
 
-A note about the ``duration`` field: depending on the architecture and
-operating system, PyPy uses different ways to read timestamps, so ``duration``
-is expressed in varying units. It is possible to know which by calling
-``__pypy__.debug_get_timestamp_unit()``, which can be one of the following
-values:
-
-``tsc``
-    The default on ``x86`` machines: timestamps are expressed in CPU ticks, as
-    read by the `Time Stamp Counter`_.
-
-``ns``
-    Timestamps are expressed in nanoseconds.
-
-``QueryPerformanceCounter``
-    On Windows, in case for some reason ``tsc`` is not available: timestamps
-    are read using the win API ``QueryPerformanceCounter()``.
-
-
-Unfortunately, there does not seem to be a reliable standard way for
-converting ``tsc`` ticks into nanoseconds, although in practice on modern CPUs
-it is enough to divide the ticks by the maximum nominal frequency of the CPU.
-For this reason, PyPy gives the raw value, and leaves the job of doing the
-conversion to external libraries.
-
 Here is an example of GC hooks in use::
 
     import sys
@@ -321,8 +297,6 @@
         lst = [lst, 1, 2, 3]
 
 
-.. _`Time Stamp Counter`: https://en.wikipedia.org/wiki/Time_Stamp_Counter    
-    
 .. _minimark-environment-variables:
 
 Environment variables
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
@@ -1,11 +1,12 @@
 Historical release notes
 ========================
 
-CPython 2.7 compatible versions
--------------------------------
+Combined releases
+-----------------
 
 .. toctree::
 
+   release-v7.1.0.rst
    release-v7.0.0.rst
    release-v6.0.0.rst
    release-v5.10.1.rst
@@ -14,6 +15,12 @@
    release-v5.8.0.rst
    release-v5.7.1.rst
    release-v5.7.0.rst
+
+CPython 2.7 compatible versions
+-------------------------------
+
+.. toctree::
+
    release-pypy2.7-v5.6.0.rst
    release-pypy2.7-v5.4.1.rst
    release-pypy2.7-v5.4.0.rst
@@ -61,15 +68,6 @@
    release-0.7.0.rst
    release-0.6
 
-CPython 3.5 compatible versions
--------------------------------
-
-.. toctree::
-
-   release-v5.8.0.rst
-   release-v5.7.1.rst
-   release-v5.7.0.rst
-
 CPython 3.3 compatible versions
 -------------------------------
 
diff --git a/pypy/doc/man/pypy.1.rst b/pypy/doc/man/pypy.1.rst
--- a/pypy/doc/man/pypy.1.rst
+++ b/pypy/doc/man/pypy.1.rst
@@ -99,6 +99,8 @@
     If set, equivalent to the ``-W`` option (warning control).
     The value should be a comma-separated list of ``-W`` parameters.
 
+.. _pypylog:
+
 ``PYPYLOG``
     If set to a non-empty value, enable logging, the format is:
 
diff --git a/pypy/doc/release-v7.1.0.rst b/pypy/doc/release-v7.1.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-v7.1.0.rst
@@ -0,0 +1,84 @@
+=========================================
+PyPy v7.1.0: release of 2.7, and 3.6-beta
+=========================================
+
+The PyPy team is proud to release the version 7.1.0 of PyPy, which includes
+two different interpreters:
+
+  - PyPy2.7, which is an interpreter supporting the syntax and the features of
+    Python 2.7
+
+  - PyPy3.6-beta: this is the second official release of PyPy to support 3.6
+    features, although it is still considered beta quality.
+    
+The interpreters are based on much the same codebase, thus the double
+release.
+
+This release, coming fast on the heels of 7.0 in February, finally merges the
+internal refactoring of unicode representation as UTF-8. Removing the
+conversions from strings to unicode internally lead to a nice speed bump.
+
+We also improved the ability to use the buffer protocol with ctype structures
+and arrays.
+
+Until we can work with downstream providers to distribute builds with PyPy, we
+have made packages for some common packages `available as wheels`_.
+
+As always, this release is 100% compatible with the previous one and fixed
+several issues and bugs raised by the growing community of PyPy users.
+We strongly recommend updating.
+
+The PyPy3.6 release is still not production quality so your mileage may vary.
+There are open issues with incomplete compatibility and c-extension support.
+
+You can download the v7.0 releases here:
+
+    http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project. If PyPy is not quite good enough for your needs, we are available for
+direct consulting work.
+
+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.
+
+.. _`PyPy`: index.html
+.. _`RPython`: https://rpython.readthedocs.org
+.. _`help`: project-ideas.html
+.. _`cffi`: http://cffi.readthedocs.io
+.. _`cppyy`: https://cppyy.readthedocs.io
+.. _`available as wheels`: https://github.com/antocuni/pypy-wheels
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7, 3.6. 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.
+
+The PyPy release supports:
+
+  * **x86** machines on most common operating systems
+    (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD)
+
+  * big- and little-endian variants of **PPC64** running Linux,
+
+  * **s390x** running Linux
+
+Unfortunately at the moment of writing our ARM buildbots are out of service,
+so for now we are **not** releasing any binary for the ARM architecture.
+
+.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org
+.. _`dynamic languages`: http://rpython.readthedocs.io/en/latest/examples.html
+
+
+Changelog
+=========
+
+If not specified, the changes are shared across versions
+
diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py
--- a/pypy/doc/tool/makecontributor.py
+++ b/pypy/doc/tool/makecontributor.py
@@ -1,4 +1,5 @@
 # NOTE: run this script with LANG=en_US.UTF-8
+# works with pip install mercurial==3.0
 
 import py
 import sys
@@ -89,6 +90,7 @@
     'Laurence Tratt': ['ltratt'],
     'Pieter Zieschang': ['pzieschang', '[email protected]'],
     'John Witulski': ['witulski'],
+    'Andrew Lawrence': ['[email protected]', 'andrewjlawrence'],
     }
 
 alias_map = {}
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,34 +1,6 @@
 ==========================
-What's new in PyPy2.7 7.0+
+What's new in PyPy2.7 7.1+
 ==========================
 
-.. this is a revision shortly after release-pypy-7.0.0
-.. startrev: 481c69f7d81f
-
-.. branch: zlib-copying-third-time-a-charm
-
-Make sure zlib decompressobjs have their streams deallocated immediately
-on flush.
-
-.. branch: zlib-copying-redux
-
-Fix calling copy on already-flushed compressobjs.
-
-
-
-.. branch: math-improvements
-
-Improve performance of long operations where one of the operands fits into
-an int.
-
-.. branch: regalloc-playground
-
-Improve register allocation in the JIT.
-
-.. branch: promote-unicode
-
-Implement rlib.jit.promote_unicode to complement promote_string
-
-.. branch: unicode-utf8
-
-Use utf8 internally to represent unicode, with the goal of never using 
rpython-level unicode
+.. this is a revision shortly after release-pypy-7.1.0
+.. startrev: 78914a03cf95
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-pypy2-7.1.0.rst
copy from pypy/doc/whatsnew-head.rst
copy to pypy/doc/whatsnew-pypy2-7.1.0.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-pypy2-7.1.0.rst
@@ -32,3 +32,10 @@
 .. branch: unicode-utf8
 
 Use utf8 internally to represent unicode, with the goal of never using 
rpython-level unicode
+
+.. branch: newmemoryview-app-level
+
+Since _ctypes is implemented in pure python over libffi, add interfaces and
+methods to support the buffer interface from python. Specifically, add a
+``__pypy__.newmemoryview`` function to create a memoryview and extend the use
+of the PyPy-specific ``__buffer__`` class method.
\ No newline at end of file
diff --git a/pypy/doc/whatsnew-pypy3-head.rst 
b/pypy/doc/whatsnew-pypy3-7.1.0.rst
copy from pypy/doc/whatsnew-pypy3-head.rst
copy to pypy/doc/whatsnew-pypy3-7.1.0.rst
diff --git a/pypy/doc/whatsnew-pypy3-head.rst b/pypy/doc/whatsnew-pypy3-head.rst
--- a/pypy/doc/whatsnew-pypy3-head.rst
+++ b/pypy/doc/whatsnew-pypy3-head.rst
@@ -1,11 +1,6 @@
 ========================
-What's new in PyPy3 7.0+
+What's new in PyPy3 7.1+
 ========================
 
-.. this is the revision after release-pypy3.6-v7.0
-.. startrev: 33fe3b2cf186
-
-.. branch: py3.5
-
-Merge in py.35 and use this branch as the primary pypy3 one
-
+.. this is the revision after release-pypy3.6-v7.1
+.. startrev: d642a3c217cb
diff --git a/pypy/interpreter/unicodehelper.py 
b/pypy/interpreter/unicodehelper.py
--- a/pypy/interpreter/unicodehelper.py
+++ b/pypy/interpreter/unicodehelper.py
@@ -362,6 +362,8 @@
     valid so we're trying to either raise or pack stuff with error handler.
     The key difference is that this is call_may_force
     """
+    if errors is None:
+        errors = 'strict'
     slen = len(s)
     res = StringBuilder(slen)
     pos = 0
diff --git a/pypy/module/__pypy__/interp_buffer.py 
b/pypy/module/__pypy__/interp_buffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/interp_buffer.py
@@ -0,0 +1,100 @@
+#
+# An app-level interface to tp_as_buffer->bf_getbuffer.
+#
+
+from pypy.interpreter.error import oefmt
+from pypy.interpreter.gateway import unwrap_spec, interp2app
+from pypy.objspace.std.memoryobject import BufferViewND
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.typedef import TypeDef, generic_new_descr
+
+class W_Bufferable(W_Root):
+    def __init__(self, space):
+        pass
+
+    def descr_buffer(self, space, w_flags):
+        if type(self) is W_Bufferable:
+            raise oefmt(space.w_ValueError, "override __buffer__ in a 
subclass")
+        return space.call_method(self, '__buffer__', w_flags)
+
+    def readbuf_w(self, space):
+        mv = space.call_method(self, '__buffer__', space.newint(0))
+        return mv.buffer_w(space, 0).as_readbuf()
+
+W_Bufferable.typedef = TypeDef("Bufferable", None, None, 'read-write',
+    __doc__ = """a helper class for a app-level class (like _ctypes.Array)
+that want to support tp_as_buffer.bf_getbuffer via a __buffer__ method""",
+    __new__ = generic_new_descr(W_Bufferable),
+    __buffer__ = interp2app(W_Bufferable.descr_buffer),
+)
+
+@unwrap_spec(itemsize=int, format='text')
+def newmemoryview(space, w_obj, itemsize, format, w_shape=None, 
w_strides=None):
+    '''
+    newmemoryview(buf, itemsize, format, shape=None, strides=None)
+    '''
+    if not space.isinstance_w(w_obj, space.w_memoryview):
+        raise oefmt(space.w_ValueError, "memoryview expected")
+    # minimal error checking
+    lgt = space.len_w(w_obj)
+    old_size = w_obj.getitemsize()
+    nbytes = lgt * old_size
+    if w_shape:
+        tot = 1
+        shape = []
+        for w_v in space.listview(w_shape):
+            v = space.int_w(w_v)
+            shape.append(v)
+            tot *= v
+        if tot * itemsize != nbytes:
+            raise oefmt(space.w_ValueError,
+                  "shape/itemsize %s/%d does not match obj len/itemsize %d/%d",
+                  str(shape), itemsize, lgt, old_size)
+    else:
+        if nbytes % itemsize != 0:
+            raise oefmt(space.w_ValueError,
+                  "itemsize %d does not match obj len/itemsize %d/%d",
+                  itemsize, lgt, old_size)
+        shape = [nbytes / itemsize,]
+    ndim = len(shape)
+    if w_strides:
+        strides = [] 
+        for w_v in space.listview(w_strides):
+            v = space.int_w(w_v)
+            strides.append(v)
+        if not w_shape and len(strides) != 1:
+            raise oefmt(space.w_ValueError,
+                  "strides must have one value if shape not provided")
+        if len(strides) != ndim:
+            raise oefmt(space.w_ValueError,
+                  "shape %s does not match strides %s",
+                  str(shape), str(strides))
+    else:
+        # start from the right, c-order layout
+        strides = [itemsize] * ndim
+        for v in range(ndim - 2, -1, -1):
+            strides[v] = strides[v + 1] * shape[v + 1]
+    # check that the strides are not too big
+    for i in range(ndim):
+        if strides[i] * shape[i] > nbytes:
+            raise oefmt(space.w_ValueError,
+                  "shape %s and strides %s exceed object size %d",
+                  shape, strides, nbytes)
+    view = space.buffer_w(w_obj, 0)
+    return space.newmemoryview(FormatBufferViewND(view, itemsize, format, ndim,
+                                                  shape, strides))
+
+class FormatBufferViewND(BufferViewND):
+    _immutable_ = True
+    _attrs_ = ['readonly', 'parent', 'ndim', 'shape', 'strides',
+               'format', 'itemsize']
+    def __init__(self, parent, itemsize, format, ndim, shape, strides):
+        BufferViewND.__init__(self, parent, ndim, shape, strides)
+        self.format = format
+        self.itemsize = itemsize
+
+    def getformat(self):
+        return self.format
+
+    def getitemsize(self):
+        return self.itemsize
diff --git a/pypy/module/__pypy__/moduledef.py 
b/pypy/module/__pypy__/moduledef.py
--- a/pypy/module/__pypy__/moduledef.py
+++ b/pypy/module/__pypy__/moduledef.py
@@ -62,11 +62,18 @@
 class PyPyDateTime(MixedModule):
     appleveldefs = {}
     interpleveldefs = {
-        'dateinterop': 'interp_pypydatetime.W_DateTime_Date',
-        'timeinterop'    : 'interp_pypydatetime.W_DateTime_Time',
-        'deltainterop'   : 'interp_pypydatetime.W_DateTime_Delta',
+        'dateinterop'  : 'interp_pypydatetime.W_DateTime_Date',
+        'timeinterop'  : 'interp_pypydatetime.W_DateTime_Time',
+        'deltainterop' : 'interp_pypydatetime.W_DateTime_Delta',
     }
 
+class PyPyBufferable(MixedModule):
+    appleveldefs = {}
+    interpleveldefs = {
+        'bufferable': 'interp_buffer.W_Bufferable',
+    }
+        
+
 class Module(MixedModule):
     """ PyPy specific "magic" functions. A lot of them are experimental and
     subject to change, many are internal. """
@@ -111,6 +118,7 @@
         'fsencode'                  : 'interp_magic.fsencode',
         'fsdecode'                  : 'interp_magic.fsdecode',
         'pyos_inputhook'            : 'interp_magic.pyos_inputhook',
+        'newmemoryview'             : 'interp_buffer.newmemoryview',
     }
 
     submodules = {
@@ -120,6 +128,7 @@
         "intop": IntOpModule,
         "os": OsModule,
         '_pypydatetime': PyPyDateTime,
+        'bufferable': PyPyBufferable,
     }
 
     def setup_after_space_initialization(self):
diff --git a/pypy/module/__pypy__/test/test_newmemoryview.py 
b/pypy/module/__pypy__/test/test_newmemoryview.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/test/test_newmemoryview.py
@@ -0,0 +1,32 @@
+
+
+class AppTestMinimal:
+    spaceconfig = dict(usemodules=['__pypy__'])
+
+    def test_newmemoryview(self):
+        from __pypy__ import newmemoryview
+        b = bytearray(12)
+        # The format can be anything, we only verify shape, strides, and 
itemsize
+        m = newmemoryview(memoryview(b), 2, 'T{<h:a}', shape=(2, 3))
+        assert m.strides == (6, 2)
+        m = newmemoryview(memoryview(b), 2, 'T{<h:a}', shape=(2, 3),
+                          strides=(6, 2))
+        assert m.strides == (6, 2)
+        assert m.format == 'T{<h:a}'
+        assert m.itemsize == 2
+
+    def test_bufferable(self):
+        from __pypy__ import bufferable, newmemoryview
+        class B(bufferable.bufferable):
+            def __init__(self):
+                self.data = bytearray(b'abc')
+
+            def __buffer__(self, flags):
+                return newmemoryview(memoryview(self.data), 1, 'B')
+
+
+        obj = B()
+        buf = memoryview(obj)
+        v = obj.data[2]
+        assert buf[2] == v
+
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
@@ -1,1 +1,1 @@
-VERSION = "1.12.1"
+VERSION = "1.12.2"
diff --git a/pypy/module/_cffi_backend/cerrno.py 
b/pypy/module/_cffi_backend/cerrno.py
--- a/pypy/module/_cffi_backend/cerrno.py
+++ b/pypy/module/_cffi_backend/cerrno.py
@@ -27,4 +27,4 @@
     if code == -1:
         code = GetLastError_alt_saved()
     message = FormatErrorW(code)
-    return space.newtuple([space.newint(code), space.newtext(message)])
+    return space.newtuple([space.newint(code), space.newtext(*message)])
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
@@ -238,26 +238,32 @@
         else:
             self.ctype.convert_from_object(cdata, w_ob)
 
+    def add_varsize_length(self, space, itemsize, varsizelength, optvarsize):
+        # returns an updated 'optvarsize' to account for an array of
+        # 'varsizelength' elements, each of size 'itemsize', that starts
+        # at 'self.offset'.
+        try:
+            varsize = ovfcheck(itemsize * varsizelength)
+            size = ovfcheck(self.offset + varsize)
+        except OverflowError:
+            raise oefmt(space.w_OverflowError,
+                        "array size would overflow a ssize_t")
+        assert size >= 0
+        return max(size, optvarsize)
+
     def write_v(self, cdata, w_ob, optvarsize):
         # a special case for var-sized C99 arrays
         from pypy.module._cffi_backend import ctypearray
         ct = self.ctype
+        space = ct.space
         if isinstance(ct, ctypearray.W_CTypeArray) and ct.length < 0:
-            space = ct.space
             w_ob, varsizelength = ct.get_new_array_length(w_ob)
             if optvarsize != -1:
                 # in this mode, the only purpose of this function is to compute
                 # the real size of the structure from a var-sized C99 array
                 assert cdata == lltype.nullptr(rffi.CCHARP.TO)
-                itemsize = ct.ctitem.size
-                try:
-                    varsize = ovfcheck(itemsize * varsizelength)
-                    size = ovfcheck(self.offset + varsize)
-                except OverflowError:
-                    raise oefmt(space.w_OverflowError,
-                                "array size would overflow a ssize_t")
-                assert size >= 0
-                return max(size, optvarsize)
+                return self.add_varsize_length(space, ct.ctitem.size,
+                    varsizelength, optvarsize)
             # if 'value' was only an integer, get_new_array_length() returns
             # w_ob = space.w_None.  Detect if this was the case,
             # and if so, stop here, leaving the content uninitialized
@@ -267,6 +273,12 @@
         #
         if optvarsize == -1:
             self.write(cdata, w_ob)
+        elif (isinstance(ct, W_CTypeStructOrUnion) and ct._with_var_array and
+              not isinstance(w_ob, cdataobj.W_CData)):
+            subsize = ct.size
+            subsize = ct.convert_struct_from_object(
+                lltype.nullptr(rffi.CCHARP.TO), w_ob, subsize)
+            optvarsize = self.add_varsize_length(space, 1, subsize, optvarsize)
         return optvarsize
 
     def convert_bitfield_to_object(self, cdata):
diff --git a/pypy/module/_cffi_backend/newtype.py 
b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -368,6 +368,16 @@
                 raise oefmt(space.w_TypeError,
                             "field '%s.%s' has ctype '%s' of unknown size",
                             w_ctype.name, fname, ftype.name)
+        elif isinstance(ftype, ctypestruct.W_CTypeStructOrUnion):
+            ftype.force_lazy_struct()
+            # GCC (or maybe C99) accepts var-sized struct fields that are not
+            # the last field of a larger struct.  That's why there is no
+            # check here for "last field": we propagate the flag
+            # '_with_var_array' to any struct that contains either an open-
+            # ended array or another struct that recursively contains an
+            # open-ended array.
+            if ftype._with_var_array:
+                with_var_array = True
         #
         if is_union:
             boffset = 0         # reset each field at offset 0
@@ -419,7 +429,6 @@
                 # a nested anonymous struct or union
                 # note: it seems we only get here with ffi.verify()
                 srcfield2names = {}
-                ftype.force_lazy_struct()
                 for name, srcfld in ftype._fields_dict.items():
                     srcfield2names[srcfld] = name
                 for srcfld in ftype._fields_list:
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.12.1", ("This test_c.py file is for testing a version"
+assert __version__ == "1.12.2", ("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,):
@@ -3441,6 +3441,15 @@
     assert p.a[1] == 20
     assert p.a[2] == 30
     assert p.a[3] == 0
+    #
+    # struct of struct of varsized array
+    BStruct2 = new_struct_type("bar")
+    complete_struct_or_union(BStruct2, [('head', BInt),
+                                        ('tail', BStruct)])
+    for i in range(2):   # try to detect heap overwrites
+        p = newp(new_pointer_type(BStruct2), [100, [200, list(range(50))]])
+        assert p.tail.y[49] == 49
+
 
 def test_struct_array_no_length_explicit_position():
     BInt = new_primitive_type("int")
diff --git a/pypy/module/_codecs/interp_codecs.py 
b/pypy/module/_codecs/interp_codecs.py
--- a/pypy/module/_codecs/interp_codecs.py
+++ b/pypy/module/_codecs/interp_codecs.py
@@ -304,7 +304,7 @@
         while pos < end:
             oc = ord(obj[pos])
             raw_unicode_escape_helper(builder, oc)
-            pos += 1 
+            pos += 1
         return space.newtuple([space.newtext(builder.build()), w_end])
     else:
         raise oefmt(space.w_TypeError,
@@ -526,7 +526,10 @@
 
 def _call_codec(space, w_coder, w_obj, action, encoding, errors):
     try:
-        w_res = space.call_function(w_coder, w_obj, space.newtext(errors))
+        if errors:
+            w_res = space.call_function(w_coder, w_obj, space.newtext(errors))
+        else:
+            w_res = space.call_function(w_coder, w_obj)
     except OperationError as operr:
         raise _wrap_codec_error(space, operr, action, encoding)
     if (not space.isinstance_w(w_res, space.w_tuple) or space.len_w(w_res) != 
2):
@@ -558,8 +561,8 @@
     return w_err_handler
 
 
-@unwrap_spec(errors='text')
-def encode(space, w_obj, w_encoding=None, errors='strict'):
+@unwrap_spec(encoding='text_or_none', errors='text_or_none')
+def encode(space, w_obj, encoding=None, errors=None):
     """encode(obj, [encoding[,errors]]) -> object
 
     Encodes obj using the codec registered for encoding. encoding defaults
@@ -569,20 +572,26 @@
     'xmlcharrefreplace' as well as any other name registered with
     codecs.register_error that can handle ValueErrors.
     """
-    if w_encoding is None:
+    if encoding is None:
         encoding = space.sys.defaultencoding
-    else:
-        encoding = space.text_w(w_encoding)
     w_encoder = space.getitem(lookup_codec(space, encoding), space.newint(0))
-    return _call_codec(space, w_encoder, w_obj, "encoding", encoding, errors)
+    w_retval =  _call_codec(space, w_encoder, w_obj, "encoding", encoding, 
errors)
+    if not space.isinstance_w(w_retval, space.w_bytes):
+        raise oefmt(space.w_TypeError,
+                    "'%s' encoder returned '%T' instead of 'bytes'; "
+                    "use codecs.encode() to encode to arbitrary types",
+                    encoding,
+                    w_retval)
+    return w_retval
 
 @unwrap_spec(errors='text_or_none')
 def readbuffer_encode(space, w_data, errors='strict'):
     s = space.getarg_w('s#', w_data)
     return space.newtuple([space.newbytes(s), space.newint(len(s))])
 
-@unwrap_spec(errors='text')
-def decode(space, w_obj, w_encoding=None, errors='strict'):
+@unwrap_spec(encoding='text_or_none', errors='text_or_none')
+def decode(space, w_obj, encoding=None, errors=None):
+    from pypy.objspace.std.unicodeobject import W_UnicodeObject
     """decode(obj, [encoding[,errors]]) -> object
 
     Decodes obj using the codec registered for encoding. encoding defaults
@@ -592,12 +601,17 @@
     as well as any other name registered with codecs.register_error that is
     able to handle ValueErrors.
     """
-    if w_encoding is None:
+    if encoding is None:
         encoding = space.sys.defaultencoding
-    else:
-        encoding = space.text_w(w_encoding)
     w_decoder = space.getitem(lookup_codec(space, encoding), space.newint(1))
-    return _call_codec(space, w_decoder, w_obj, "decoding", encoding, errors)
+    w_retval = _call_codec(space, w_decoder, w_obj, "decoding", encoding, 
errors)
+    if not isinstance(w_retval, W_UnicodeObject):
+        raise oefmt(space.w_TypeError,
+                    "'%s' decoder returned '%T' instead of 'str'; "
+                    "use codecs.decode() to decode to arbitrary types",
+                    encoding,
+                    w_retval)
+    return w_retval
 
 @unwrap_spec(errors='text')
 def register_error(space, errors, w_handler):
@@ -633,20 +647,6 @@
                     "use %s to handle arbitrary codecs", encoding, action)
     return codec_info
 
-def encode_text(space, w_obj, encoding, errors):
-    if errors is None:
-        errors = 'strict'
-    w_encoder = space.getitem(
-        lookup_text_codec(space, "codecs.encode()", encoding), space.newint(0))
-    return _call_codec(space, w_encoder, w_obj, "encoding", encoding, errors)
-
-def decode_text(space, w_obj, encoding, errors):
-    if errors is None:
-        errors = 'strict'
-    w_decoder = space.getitem(
-        lookup_text_codec(space, "codecs.decode()", encoding), space.newint(1))
-    return _call_codec(space, w_decoder, w_obj, "decoding", encoding, errors)
-
 # ____________________________________________________________
 
 def _find_implementation(impl_name):
@@ -736,7 +736,7 @@
         result = unicodehelper.utf8_encode_utf_8(utf8, errors,
                      state.encode_error_handler, allow_surrogates=False)
     except unicodehelper.ErrorHandlerError as e:
-        raise oefmt(space.w_IndexError, 
+        raise oefmt(space.w_IndexError,
                    "position %d from error handler invalid, already encoded 
%d",
                     e.new,e.old)
 
diff --git a/pypy/module/_codecs/test/test_codecs.py 
b/pypy/module/_codecs/test/test_codecs.py
--- a/pypy/module/_codecs/test/test_codecs.py
+++ b/pypy/module/_codecs/test/test_codecs.py
@@ -696,6 +696,22 @@
         exc = raises(RuntimeError, u"hello".encode, "test.failingenc")
         assert exc.value == to_raise
 
+    def test_one_arg_encoder(self):
+        import _codecs
+        def search_function(encoding):
+            def encode_one(u):
+                return (b'foo', len(u))
+            def decode_one(u):
+                return (u'foo', len(u))
+            if encoding == 'onearg':
+                return (encode_one, decode_one, None, None)
+            return None
+        _codecs.register(search_function)
+        assert u"hello".encode("onearg") == b'foo'
+        assert b"hello".decode("onearg") == u'foo'
+        assert _codecs.encode(u"hello", "onearg") == b'foo'
+        assert _codecs.decode(b"hello", "onearg") == u'foo'
+
     def test_cpytest_decode(self):
         import codecs
         assert codecs.decode(b'\xe4\xf6\xfc', 'latin-1') == '\xe4\xf6\xfc'
diff --git a/pypy/module/_multiprocessing/interp_win32_py3.py 
b/pypy/module/_multiprocessing/interp_win32_py3.py
--- a/pypy/module/_multiprocessing/interp_win32_py3.py
+++ b/pypy/module/_multiprocessing/interp_win32_py3.py
@@ -9,7 +9,7 @@
     message = rwin32.FormatErrorW(errno)
     w_errcode = space.newint(errno)
     return OperationError(space.w_WindowsError,
-                         space.newtuple([w_errcode, space.newtext(message),
+                         space.newtuple([w_errcode, space.newtext(*message),
                         space.w_None, w_errcode]))
 
 @unwrap_spec(handle=int)
diff --git a/pypy/module/_multiprocessing/test/test_semaphore.py 
b/pypy/module/_multiprocessing/test/test_semaphore.py
--- a/pypy/module/_multiprocessing/test/test_semaphore.py
+++ b/pypy/module/_multiprocessing/test/test_semaphore.py
@@ -11,7 +11,7 @@
                                    'binascii', 'struct', '_posixsubprocess'))
 
     if sys.platform == 'win32':
-        spaceconfig['usemodules'] += ('_rawffi',)
+        spaceconfig['usemodules'] += ('_rawffi', '_cffi_backend')
     else:
         spaceconfig['usemodules'] += ('fcntl',)
 
diff --git a/pypy/module/_multiprocessing/test/test_win32.py 
b/pypy/module/_multiprocessing/test/test_win32.py
--- a/pypy/module/_multiprocessing/test/test_win32.py
+++ b/pypy/module/_multiprocessing/test/test_win32.py
@@ -2,7 +2,7 @@
 import sys
 
 class AppTestWin32:
-    spaceconfig = dict(usemodules=('_multiprocessing',
+    spaceconfig = dict(usemodules=('_multiprocessing', '_cffi_backend',
                                    'signal', '_rawffi', 'binascii'))
 
     def setup_class(cls):
diff --git a/pypy/module/_rawffi/interp_rawffi.py 
b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -632,7 +632,7 @@
 if _MS_WINDOWS:
     @unwrap_spec(code=int)
     def FormatError(space, code):
-        return space.newtext(rwin32.FormatErrorW(code))
+        return space.newtext(*rwin32.FormatErrorW(code))
 
     @unwrap_spec(hresult=int)
     def check_HRESULT(space, hresult):
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
@@ -10,9 +10,9 @@
 def raiseWindowsError(space, errcode, context):
     message = rwin32.FormatErrorW(errcode)
     w_errcode = space.newint(errcode)
-    raise OperationError(space.w_WindowsError,
-                         space.newtuple([w_errcode, space.newtext(message),
-                                        space.w_None, w_errcode]))
+    w_t = space.newtuple([w_errcode, space.newtext(*message),
+                                        space.w_None, w_errcode])
+    raise OperationError(space.w_WindowsError, w_t)
 
 class W_HKEY(W_Root):
     def __init__(self, space, hkey):
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
@@ -30,6 +30,7 @@
 from pypy.objspace.std.unicodeobject import encode_object
 from pypy.module.__builtin__.descriptor import W_Property
 #from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.__pypy__.interp_buffer import W_Bufferable
 from rpython.rlib.entrypoint import entrypoint_lowlevel
 from rpython.rlib.rposix import FdValidator
 from rpython.rlib.unroll import unrolling_iterable
@@ -731,6 +732,7 @@
         'PyMethodDescr_Type': 
'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)',
         'PyWrapperDescr_Type': 
'space.gettypeobject(cpyext.methodobject.W_PyCWrapperObject.typedef)',
         'PyInstanceMethod_Type': 
'space.gettypeobject(cpyext.classobject.InstanceMethod.typedef)',
+        'PyBufferable_Type': 'space.gettypeobject(W_Bufferable.typedef)',
         }.items():
         register_global(cpyname, 'PyTypeObject*', pypyexpr, header=pypy_decl)
 
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
@@ -32,8 +32,8 @@
  *     module/sys/version.py
  *     doc/conf.py
  */
-#define PYPY_VERSION "7.1.0-alpha0"
-#define PYPY_VERSION_NUM  0x07010000
+#define PYPY_VERSION "7.2.0-alpha0"
+#define PYPY_VERSION_NUM  0x07020000
 /* Defined to mean a PyPy where cpyext holds more regular references
    to PyObjects, e.g. staying alive as long as the internal PyPy object
    stays alive. */
diff --git a/pypy/module/cpyext/memoryobject.py 
b/pypy/module/cpyext/memoryobject.py
--- a/pypy/module/cpyext/memoryobject.py
+++ b/pypy/module/cpyext/memoryobject.py
@@ -43,7 +43,9 @@
     fill_Py_buffer(space, w_obj.view, view)
     try:
         view.c_buf = rffi.cast(rffi.VOIDP, w_obj.view.get_raw_address())
-        view.c_obj = make_ref(space, w_userdata)
+        # not used in PyPy to keep something alive,
+        # but some c-extensions check the type without checking for NULL
+        view.c_obj = make_ref(space, space.w_None)
         rffi.setintfield(view, 'c_readonly', w_obj.view.readonly)
     except ValueError:
         w_s = w_obj.descr_tobytes(space)
diff --git a/pypy/module/cpyext/methodobject.py 
b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -46,15 +46,15 @@
     _dealloc(space, py_obj)
 
 def w_kwargs_from_args(space, __args__):
-    w_kwargs = None
-    if __args__.keywords:
-        # CCC: we should probably have a @jit.look_inside_iff if the
-        # keyword count is constant, as we do in Arguments.unpack
-        w_kwargs = space.newdict()
-        for i in range(len(__args__.keywords)):
-            key = __args__.keywords[i]
-            w_obj = __args__.keywords_w[i]
-            space.setitem(w_kwargs, space.newtext(key), w_obj)
+    if __args__.keywords is None:
+        return None
+    # CCC: we should probably have a @jit.look_inside_iff if the
+    # keyword count is constant, as we do in Arguments.unpack
+    w_kwargs = space.newdict()
+    for i in range(len(__args__.keywords)):
+        key = __args__.keywords[i]
+        w_obj = __args__.keywords_w[i]
+        space.setitem(w_kwargs, space.newtext(key), w_obj)
     return w_kwargs
 
 def undotted_name(name):
diff --git a/pypy/module/cpyext/parse/cpyext_memoryobject.h 
b/pypy/module/cpyext/parse/cpyext_memoryobject.h
--- a/pypy/module/cpyext/parse/cpyext_memoryobject.h
+++ b/pypy/module/cpyext/parse/cpyext_memoryobject.h
@@ -1,6 +1,12 @@
 /* The struct is declared here but it shouldn't
    be considered public. Don't access those fields directly,
    use the functions instead! */
+
+
+/* this is wrong, PyMemoryViewObject should use PyObject_VAR_HEAD, and use
+   ob_data[1] to hold the shapes, strides, and offsets for the view. Then
+   we should use specialized allocators (that break the cpyext model) to
+   allocate ob_data = malloc(sizeof(Py_ssize_t) * view.ndims * 3) */
 typedef struct {
     PyObject_HEAD
     Py_buffer view;
diff --git a/pypy/module/cpyext/parse/cpyext_object.h 
b/pypy/module/cpyext/parse/cpyext_object.h
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -52,7 +52,8 @@
 
 
 /* Py3k buffer interface, adapted for PyPy */
-#define Py_MAX_NDIMS 32
+/* XXX remove this constant, us a PyObject_VAR_HEAD instead */
+#define Py_MAX_NDIMS 36
 #define Py_MAX_FMT 128
 typedef struct bufferinfo {
     void *buf;
diff --git a/pypy/module/cpyext/test/test_memoryobject.py 
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -36,6 +36,23 @@
         decref(space, ref)
         decref(space, c_memoryview)
 
+    def test_class_with___buffer__(self, space, api):
+        w_obj = space.appexec([], """():
+            from __pypy__.bufferable import bufferable
+            class B(bufferable):
+                def __init__(self):
+                    self.buf = bytearray(10)
+
+                def __buffer__(self, flags):
+                    return memoryview(self.buf)
+            return B()""")
+        py_obj = make_ref(space, w_obj)
+        assert py_obj.c_ob_type.c_tp_as_buffer
+        assert py_obj.c_ob_type.c_tp_as_buffer.c_bf_getbuffer
+        assert py_obj.c_ob_type.c_tp_as_buffer.c_bf_getreadbuffer
+        assert py_obj.c_ob_type.c_tp_as_buffer.c_bf_getwritebuffer
+         
+
 class AppTestPyBuffer_FillInfo(AppTestCpythonExtensionBase):
     def test_fillWithObject(self):
         module = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/test/test_methodobject.py 
b/pypy/module/cpyext/test/test_methodobject.py
--- a/pypy/module/cpyext/test/test_methodobject.py
+++ b/pypy/module/cpyext/test/test_methodobject.py
@@ -87,6 +87,7 @@
         assert mod.getarg_KW(a=3, b=4) == ((), {'a': 3, 'b': 4})
         assert mod.getarg_KW(1, 2, a=3, b=4) == ((1, 2), {'a': 3, 'b': 4})
         assert mod.getarg_KW.__name__ == "getarg_KW"
+        assert mod.getarg_KW(*(), **{}) == ((), {})
 
 
     def test_func_attributes(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
@@ -13,7 +13,7 @@
 # make sure to keep PYPY_VERSION in sync with:
 #    module/cpyext/include/patchlevel.h
 #    doc/conf.py
-PYPY_VERSION               = (7, 1, 0, "alpha", 0)
+PYPY_VERSION               = (7, 2, 0, "alpha", 0)
 
 
 import pypy
diff --git a/pypy/objspace/std/stringmethods.py 
b/pypy/objspace/std/stringmethods.py
--- a/pypy/objspace/std/stringmethods.py
+++ b/pypy/objspace/std/stringmethods.py
@@ -193,8 +193,6 @@
         from pypy.objspace.std.unicodeobject import (
             get_encoding_and_errors, decode_object)
         encoding, errors = get_encoding_and_errors(space, w_encoding, w_errors)
-        if errors is None:
-            errors = 'strict'
         if encoding is None:
             encoding = 'utf8'
         if encoding == 'utf8' or encoding == 'utf-8':
diff --git a/pypy/objspace/std/unicodeobject.py 
b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -41,9 +41,9 @@
         if not we_are_translated():
             try:
                 # best effort, too expensive to handle surrogates
-                ulength = len(utf8str.decode('utf8'))
+                ulength = rutf8.codepoints_in_utf(utf8str)
             except:
-                ulength = length 
+                ulength = length
             assert ulength == length
 
 
@@ -135,7 +135,7 @@
         if strict:
             raise oefmt(space.w_TypeError,
                 "%s arg must be None, unicode or str", strict)
-        return unicode_from_encoded_object(space, w_other, 'utf8', "strict")
+        return decode_object(space, w_other, 'utf8', "strict")
 
     def convert_to_w_unicode(self, space):
         return self
@@ -203,8 +203,7 @@
                 if space.isinstance_w(w_object, space.w_unicode):
                     raise oefmt(space.w_TypeError,
                             "decoding str is not supported")
-                w_value = unicode_from_encoded_object(space, w_object,
-                                                  encoding, errors)
+                w_value = decode_object(space, w_object, encoding, errors)
         if space.is_w(w_unicodetype, space.w_unicode):
             return w_value
 
@@ -649,7 +648,7 @@
     def descr_startswith(self, space, w_prefix, w_start=None, w_end=None):
         start, end = self._unwrap_and_compute_idx_params(space, w_start, w_end)
         value = self._utf8
-        if (start > 0 and not space.is_none(w_end) and 
+        if (start > 0 and not space.is_none(w_end) and
                                 space.getindex_w(w_end, None) == 0):
             return space.w_False
         if space.isinstance_w(w_prefix, space.w_tuple):
@@ -674,7 +673,7 @@
         start, end = self._unwrap_and_compute_idx_params(space, w_start, w_end)
         value = self._utf8
         # match cpython behaviour
-        if (start > 0 and not space.is_none(w_end) and 
+        if (start > 0 and not space.is_none(w_end) and
                                 space.getindex_w(w_end, None) == 0):
             return space.w_False
         if space.isinstance_w(w_suffix, space.w_tuple):
@@ -1207,11 +1206,11 @@
     errors = None if w_errors is None else space.text_w(w_errors)
     return encoding, errors
 
-
-def encode_object(space, w_object, encoding, errors):
-    from pypy.module._codecs.interp_codecs import encode_text, CodecState
+def encode_object(space, w_obj, encoding, errors):
+    from pypy.module._codecs.interp_codecs import encode
     if errors is None or errors == 'strict':
-        utf8 = space.utf8_w(w_object)
+        # fast paths
+        utf8 = space.utf8_w(w_obj)
         if encoding is None or encoding == 'utf-8':
             try:
                 rutf8.check_utf8(utf8, False)
@@ -1230,22 +1229,12 @@
                     a.pos, a.pos + 1)
                 assert False, "always raises"
             return space.newbytes(utf8)
-    if encoding is None:
-        encoding = space.sys.defaultencoding
-    w_retval = encode_text(space, w_object, encoding, errors)
-    if not space.isinstance_w(w_retval, space.w_bytes):
-        raise oefmt(space.w_TypeError,
-                    "'%s' encoder returned '%T' instead of 'bytes'; "
-                    "use codecs.encode() to encode to arbitrary types",
-                    encoding,
-                    w_retval)
-    return w_retval
+    return encode(space, w_obj, encoding, errors)
 
 
-def decode_object(space, w_obj, encoding, errors='strict'):
-    assert errors is not None
-    assert encoding is not None
-    if errors == 'strict':
+def decode_object(space, w_obj, encoding, errors=None):
+    if errors == 'strict' or errors is None:
+        # fast paths
         if encoding == 'ascii':
             s = space.charbuf_w(w_obj)
             unicodehelper.check_ascii_or_raise(space, s)
@@ -1254,29 +1243,8 @@
             s = space.charbuf_w(w_obj)
             lgt = unicodehelper.check_utf8_or_raise(space, s)
             return space.newutf8(s, lgt)
-    from pypy.module._codecs.interp_codecs import decode_text
-    w_retval = decode_text(space, w_obj, encoding, errors)
-    if not isinstance(w_retval, W_UnicodeObject):
-        raise oefmt(space.w_TypeError,
-                    "'%s' decoder returned '%T' instead of 'str'; "
-                    "use codecs.decode() to decode to arbitrary types",
-                    encoding,
-                    w_retval)
-    return w_retval
-
-
-def unicode_from_encoded_object(space, w_obj, encoding, errors):
-    if errors is None:
-        errors = 'strict'
-    if encoding is None:
-        encoding = getdefaultencoding(space)
-    w_retval = decode_object(space, w_obj, encoding, errors)
-    if not isinstance(w_retval, W_UnicodeObject):
-        raise oefmt(space.w_TypeError,
-                    "decoder did not return a str object (type '%T')",
-                    w_retval)
-    return w_retval
-
+    from pypy.module._codecs.interp_codecs import decode
+    return decode(space, w_obj, encoding, errors)
 
 def unicode_from_object(space, w_obj):
     if space.is_w(space.type(w_obj), space.w_unicode):
@@ -1284,6 +1252,7 @@
     if space.lookup(w_obj, "__str__") is not None:
         return space.str(w_obj)
     return space.repr(w_obj)
+
 def ascii_from_object(space, w_obj):
     """Implements builtins.ascii()"""
     # repr is guaranteed to be unicode
@@ -1295,7 +1264,7 @@
     # this is a performance and bootstrapping hack
     encoding = getdefaultencoding(space)
     if encoding != 'ascii':
-        return unicode_from_encoded_object(space, w_bytes, encoding, "strict")
+        return decode_object(space, w_bytes, encoding, "strict")
     s = space.bytes_w(w_bytes)
     unicodehelper.check_ascii_or_raise(space, s)
     return W_UnicodeObject(s, len(s))
@@ -1900,7 +1869,7 @@
     if not isinstance(w_unistr, W_UnicodeObject):
         raise oefmt(space.w_TypeError, "expected unicode, got '%T'", w_unistr)
     utf8 = space.utf8_w(w_unistr)
-    lgt =  space.len_w(w_unistr) 
+    lgt =  space.len_w(w_unistr)
     result = StringBuilder(lgt)
     pos = 0
     for uchr in rutf8.Utf8StringIterator(utf8):
@@ -1923,7 +1892,7 @@
             raise OperationError(space.w_UnicodeEncodeError,
                                  space.newtuple([w_encoding, w_unistr,
                                                  w_start, w_end,
-                                                 w_reason]))            
+                                                 w_reason]))
         result.append(c)
         pos += 1
     return result.build()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to