[pypy-commit] pypy unicode-utf8-py3: merge py3.5 into branch

mattip pypy.commits at gmail.com
Sun Sep 23 09:20:43 EDT 2018


Author: Matti Picus <matti.picus at gmail.com>
Branch: unicode-utf8-py3
Changeset: r95158:5a2d488be5e6
Date: 2018-09-23 16:08 +0300
http://bitbucket.org/pypy/pypy/changeset/5a2d488be5e6/

Log:	merge py3.5 into branch

diff --git a/lib-python/3/test/test_inspect.py b/lib-python/3/test/test_inspect.py
--- a/lib-python/3/test/test_inspect.py
+++ b/lib-python/3/test/test_inspect.py
@@ -61,6 +61,9 @@
 
 git = mod.StupidGit()
 
+class ExampleClassWithSlot(object):
+    __slots__ = 'myslot'
+
 class IsTestBase(unittest.TestCase):
     predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
                       inspect.isframe, inspect.isfunction, inspect.ismethod,
@@ -131,8 +134,11 @@
             self.istest(inspect.iscoroutinefunction, 'coroutine_function_example')
 
         if hasattr(types, 'MemberDescriptorType'):
-            self.istest(inspect.ismemberdescriptor,
-                        'type(lambda: None).__globals__')
+            # App-level slots are member descriptors on both PyPy and
+            # CPython, but the various built-in attributes are all
+            # getsetdescriptors on PyPy.  So check ismemberdescriptor()
+            # with an app-level slot.
+            self.istest(inspect.ismemberdescriptor, 'ExampleClassWithSlot.myslot')
         else:
             self.assertFalse(inspect.ismemberdescriptor(datetime.timedelta.days))
 
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -486,6 +486,8 @@
         return cobj, cobj._to_ffi_param(), type(cobj)
 
     def _convert_args_for_callback(self, argtypes, args):
+        from _ctypes.structure import StructOrUnion
+        #
         assert len(argtypes) == len(args)
         newargs = []
         for argtype, arg in zip(argtypes, args):
@@ -495,6 +497,10 @@
                 param = param._get_buffer_value()
             elif self._is_primitive(argtype):
                 param = param.value
+            elif isinstance(param, StructOrUnion):   # not a *pointer* to struct
+                newparam = StructOrUnion.__new__(type(param))
+                param._copy_to(newparam._buffer.buffer)
+                param = newparam
             newargs.append(param)
         return newargs
 
diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py
--- a/lib_pypy/cffi/setuptools_ext.py
+++ b/lib_pypy/cffi/setuptools_ext.py
@@ -162,6 +162,17 @@
             module_path = module_name.split('.')
             module_path[-1] += '.py'
             generate_mod(os.path.join(self.build_lib, *module_path))
+        def get_source_files(self):
+            # This is called from 'setup.py sdist' only.  Exclude
+            # the generate .py module in this case.
+            saved_py_modules = self.py_modules
+            try:
+                if saved_py_modules:
+                    self.py_modules = [m for m in saved_py_modules
+                                         if m != module_name]
+                return base_class.get_source_files(self)
+            finally:
+                self.py_modules = saved_py_modules
     dist.cmdclass['build_py'] = build_py_make_mod
 
     # distutils and setuptools have no notion I could find of a
@@ -171,6 +182,7 @@
     # the module.  So we add it here, which gives a few apparently
     # harmless warnings about not finding the file outside the
     # build directory.
+    # Then we need to hack more in get_source_files(); see above.
     if dist.py_modules is None:
         dist.py_modules = []
     dist.py_modules.append(module_name)
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
@@ -36,7 +36,10 @@
 
 Small refactorings in the Python parser.
 
+.. branch: fix-readme-typo
+
 .. branch: unicode-utf8-re
+
 .. branch: utf8-io
 
 Utf8 handling for unicode
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -108,101 +108,99 @@
 max_jitdriver = jit.JitDriver(name='max',
         greens=['has_key', 'has_item', 'w_type'], reds='auto')
 
-def make_min_max(unroll):
-    @specialize.arg(2)
-    def min_max_impl(space, args, implementation_of):
-        if implementation_of == "max":
-            compare = space.gt
-            jitdriver = max_jitdriver
+ at specialize.arg(4)
+def min_max_sequence(space, w_sequence, w_key, w_default, implementation_of):
+    if implementation_of == "max":
+        compare = space.gt
+        jitdriver = max_jitdriver
+    else:
+        compare = space.lt
+        jitdriver = min_jitdriver
+    w_iter = space.iter(w_sequence)
+    w_type = space.type(w_iter)
+    has_key = w_key is not None
+    has_item = False
+    w_max_item = w_default
+    w_max_val = None
+    while True:
+        jitdriver.jit_merge_point(has_key=has_key, has_item=has_item,
+                                  w_type=w_type)
+        try:
+            w_item = space.next(w_iter)
+        except OperationError as e:
+            if not e.match(space, space.w_StopIteration):
+                raise
+            break
+        if has_key:
+            w_compare_with = space.call_function(w_key, w_item)
         else:
-            compare = space.lt
-            jitdriver = min_jitdriver
-        any_kwds = bool(args.keywords)
-        args_w = args.arguments_w
-        if len(args_w) > 1:
-            if unroll and len(args_w) == 2 and not any_kwds:
-                # a fast path for the common case, useful for interpreted
-                # mode and to reduce the length of the jit trace
-                w0, w1 = args_w
-                if space.is_true(compare(w1, w0)):
-                    return w1
-                else:
-                    return w0
-            w_sequence = space.newtuple(args_w)
-        elif len(args_w):
-            w_sequence = args_w[0]
+            w_compare_with = w_item
+        if (not has_item or
+                space.is_true(compare(w_compare_with, w_max_val))):
+            has_item = True
+            w_max_item = w_item
+            w_max_val = w_compare_with
+    if w_max_item is None:
+        raise oefmt(space.w_ValueError, "arg is an empty sequence")
+    return w_max_item
+
+ at specialize.arg(3)
+ at jit.look_inside_iff(lambda space, args_w, w_key, implementation_of:
+        jit.loop_unrolling_heuristic(args_w, len(args_w), 3))
+def min_max_multiple_args(space, args_w, w_key, implementation_of):
+    # case of multiple arguments (at least two).  We unroll it if there
+    # are 2 or 3 arguments.
+    if implementation_of == "max":
+        compare = space.gt
+    else:
+        compare = space.lt
+    w_max_item = args_w[0]
+    if w_key is not None:
+        w_max_val = space.call_function(w_key, w_max_item)
+    else:
+        w_max_val = w_max_item
+    for i in range(1, len(args_w)):
+        w_item = args_w[i]
+        if w_key is not None:
+            w_compare_with = space.call_function(w_key, w_item)
         else:
-            raise oefmt(space.w_TypeError,
-                        "%s() expects at least one argument",
-                        implementation_of)
-        w_key = None
-        w_default = None
-        if any_kwds:
-            kwds = args.keywords
-            for n in range(len(kwds)):
-                if kwds[n] == "key":
-                    w_key = args.keywords_w[n]
-                elif kwds[n] == "default":
-                    w_default = args.keywords_w[n]
-                else:
-                    raise oefmt(space.w_TypeError,
-                                "%s() got unexpected keyword argument",
-                                implementation_of)
+            w_compare_with = w_item
+        if space.is_true(compare(w_compare_with, w_max_val)):
+            w_max_item = w_item
+            w_max_val = w_compare_with
+    return w_max_item
 
-        if w_default is not None and len(args_w) > 1:
-            raise oefmt(space.w_TypeError,
-                "Cannot specify a default for %s() with multiple positional arguments",
-                implementation_of)
-
-        w_iter = space.iter(w_sequence)
-        w_type = space.type(w_iter)
-        has_key = w_key is not None
-        has_item = False
-        w_max_item = None
-        w_max_val = None
-        while True:
-            if not unroll:
-                jitdriver.jit_merge_point(has_key=has_key, has_item=has_item, w_type=w_type)
-            try:
-                w_item = space.next(w_iter)
-            except OperationError as e:
-                if not e.match(space, space.w_StopIteration):
-                    raise
-                break
-            if has_key:
-                w_compare_with = space.call_function(w_key, w_item)
-            else:
-                w_compare_with = w_item
-            if not has_item or \
-                    space.is_true(compare(w_compare_with, w_max_val)):
-                has_item = True
-                w_max_item = w_item
-                w_max_val = w_compare_with
-        if w_max_item is None:
-            if w_default is not None:
-                w_max_item = w_default
-            else:
-                raise oefmt(space.w_ValueError, "arg is an empty sequence")
-        return w_max_item
-    if unroll:
-        min_max_impl = jit.unroll_safe(min_max_impl)
-    return min_max_impl
-
-min_max_unroll = make_min_max(True)
-min_max_normal = make_min_max(False)
-
+ at jit.unroll_safe     # the loop over kwds
 @specialize.arg(2)
 def min_max(space, args, implementation_of):
-    # the 'normal' version includes a JIT merge point, which will make a
-    # new loop (from the interpreter or from another JIT loop).  If we
-    # give exactly two arguments to the call to max(), or a JIT virtual
-    # list of arguments, then we pick the 'unroll' version with no JIT
-    # merge point.
-    if jit.isvirtual(args.arguments_w) or len(args.arguments_w) == 2:
-        return min_max_unroll(space, args, implementation_of)
+    w_key = None
+    w_default = None
+    if bool(args.keywords):
+        kwds = args.keywords
+        for n in range(len(kwds)):
+            if kwds[n] == "key":
+                w_key = args.keywords_w[n]
+            elif kwds[n] == "default":
+                w_default = args.keywords_w[n]
+            else:
+                raise oefmt(space.w_TypeError,
+                            "%s() got unexpected keyword argument",
+                            implementation_of)
+    #
+    args_w = args.arguments_w
+    if len(args_w) > 1:
+        if w_default is not None:
+            raise oefmt(space.w_TypeError,
+                "Cannot specify a default for %s() with multiple "
+                "positional arguments", implementation_of)
+        return min_max_multiple_args(space, args_w, w_key, implementation_of)
+    elif len(args_w):
+        return min_max_sequence(space, args_w[0], w_key, w_default,
+                                implementation_of)
     else:
-        return min_max_normal(space, args, implementation_of)
-min_max._always_inline = True
+        raise oefmt(space.w_TypeError,
+                    "%s() expects at least one argument",
+                    implementation_of)
 
 def max(space, __args__):
     """max(iterable[, key=func]) -> value
diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -654,6 +654,10 @@
         raises(TypeError, max, 1, default=0)
         raises(TypeError, max, default=1)
 
+    def test_max_list_and_key(self):
+        assert max(["100", "50", "30", "-200"], key=int) == "100"
+        assert max("100", "50", "30", "-200", key=int) == "100"
+
 
 try:
     from hypothesis import given, strategies, example
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
@@ -3957,6 +3957,7 @@
     z3 = cast(BVoidP, 0)
     z4 = cast(BUCharP, 0)
     with warnings.catch_warnings(record=True) as w:
+        warnings.simplefilter("always")
         newp(new_pointer_type(BIntP), z1)    # warn
         assert len(w) == 1
         newp(new_pointer_type(BVoidP), z1)   # fine
diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
--- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
@@ -30,37 +30,42 @@
             sa = 0
             while i < 30000:
                 lst = range(i % 1000 + 2)
-                sa += max(*lst) # ID: max
+                sa += max(*lst)  # ID: callmax
                 i += 1
             return sa
         log = self.run(main, [])
         assert log.result == main()
         loop, = log.loops_by_filename(self.filepath)
-        assert loop.match("""
+        assert loop.match_by_id('callmax', """
             ...
-            p76 = call_assembler_r(..., descr=...)
+            p76 = call_may_force_r(_, _, _, _, descr=...)
             ...
         """)
-        loop2 = log.loops[0]
-        loop2.match('''
-        ...
-        label(..., descr=...)
-        ...
-        label(..., descr=...)
-        guard_not_invalidated?
-        i17 = int_ge(i11, i7)
-        guard_false(i17, descr=...)
-        p18 = getarrayitem_gc_r(p5, i11, descr=...)
-        i19 = int_add(i11, 1)
-        setfield_gc(p2, i19, descr=...)
-        guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...)
-        i20 = getfield_gc_i(p18, descr=...)
-        i21 = int_gt(i20, i14)
-        guard_true(i21, descr=...)
-        jump(..., descr=...)
-        ''')
-        # XXX could be "guard_class(p18)" instead; we lost somewhere
-        # the information that it cannot be null.
+        
+        #----- the following logic used to check the content of the assembly
+        #----- generated for the loop in max(), but now we no longer produce
+        #----- any custom assembly in this case.  It used to say
+        #----- 'call_assembler_r' above, and now it says 'call_may_force_r'.
+        #loop2 = log.loops[0]
+        #loop2.match('''
+        #...
+        #label(..., descr=...)
+        #...
+        #label(..., descr=...)
+        #guard_not_invalidated?
+        #i17 = int_ge(i11, i7)
+        #guard_false(i17, descr=...)
+        #p18 = getarrayitem_gc_r(p5, i11, descr=...)
+        #i19 = int_add(i11, 1)
+        #setfield_gc(p2, i19, descr=...)
+        #guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...)
+        #i20 = getfield_gc_i(p18, descr=...)
+        #i21 = int_gt(i20, i14)
+        #guard_true(i21, descr=...)
+        #jump(..., descr=...)
+        #''')
+        ## XXX could be "guard_class(p18)" instead; we lost somewhere
+        ## the information that it cannot be null.
 
     def test_iter_max(self):
         def main():
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1387,6 +1387,7 @@
         ffi = FFI(backend=self.Backend())
         ffi.cdef("enum foo;")
         with warnings.catch_warnings(record=True) as log:
+            warnings.simplefilter("always")
             n = ffi.cast("enum foo", -1)
             assert int(n) == 0xffffffff
         assert str(log[0].message) == (
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
@@ -46,14 +46,14 @@
         assert x != math.sin(1.23)    # rounding effects
         assert abs(x - math.sin(1.23)) < 1E-6
 
-    def test_sin_no_return_value(self):
+    def test_lround_no_return_value(self):
         # check that 'void'-returning functions work too
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
-            void sin(double x);
+            void lround(double x);
         """)
         m = ffi.dlopen(lib_m)
-        x = m.sin(1.23)
+        x = m.lround(1.23)
         assert x is None
 
     def test_dlopen_filename(self):
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_callbacks.py
@@ -160,15 +160,17 @@
 
         proto = CFUNCTYPE(c_int, RECT)
         def callback(point):
+            point.left *= -1
             return point.left+point.top+point.right+point.bottom
 
         cbp = proto(callback)
 
-        rect = RECT(1000,100,10,1)
+        rect = RECT(-1000,100,10,1)
 
         res = cbp(rect)
 
         assert res == 1111
+        assert rect.left == -1000   # must not have been changed!
 
     def test_callback_from_c_with_struct_argument(self):
         import conftest
diff --git a/rpython/translator/platform/windows.py b/rpython/translator/platform/windows.py
--- a/rpython/translator/platform/windows.py
+++ b/rpython/translator/platform/windows.py
@@ -186,7 +186,7 @@
             self.cc = cc
 
         # detect version of current compiler
-        returncode, stdout, stderr = _run_subprocess(self.cc, '',
+        returncode, stdout, stderr = _run_subprocess(self.cc, [],
                                                      env=self.c_environ)
         r = re.search(r'Microsoft.+C/C\+\+.+\s([0-9]+)\.([0-9]+).*', stderr)
         if r is not None:
@@ -196,7 +196,7 @@
             self.version = 0
 
         # Try to find a masm assembler
-        returncode, stdout, stderr = _run_subprocess('ml.exe', '',
+        returncode, stdout, stderr = _run_subprocess('ml.exe', [],
                                                      env=self.c_environ)
         r = re.search('Macro Assembler', stderr)
         if r is None and os.path.exists('c:/masm32/bin/ml.exe'):


More information about the pypy-commit mailing list