[pypy-commit] pypy py3.7: merge py3.6

cfbolz pypy.commits at gmail.com
Tue Jan 14 07:23:00 EST 2020


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: py3.7
Changeset: r98528:54bf5e2f78e0
Date: 2020-01-14 13:15 +0100
http://bitbucket.org/pypy/pypy/changeset/54bf5e2f78e0/

Log:	merge py3.6

diff --git a/extra_tests/cffi_tests/cffi0/backend_tests.py b/extra_tests/cffi_tests/cffi0/backend_tests.py
--- a/extra_tests/cffi_tests/cffi0/backend_tests.py
+++ b/extra_tests/cffi_tests/cffi0/backend_tests.py
@@ -1242,7 +1242,7 @@
             py.test.skip(str(e))
         f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
         f.seek(0)
-        assert f.read() == array.array('i', range(1000)).tostring()
+        assert f.read() == arraytostring(array.array('i', range(1000)))
         f.seek(0)
         b = ffi.new("int[]", 1005)
         f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
@@ -1261,7 +1261,7 @@
             py.test.skip(str(e))
         f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
         f.seek(0)
-        assert f.read() == array.array('i', range(1000)).tostring()
+        assert f.read() == arraytostring(array.array('i', range(1000)))
         f.seek(0)
         b = ffi.new("int[]", 1005)
         f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
diff --git a/extra_tests/cffi_tests/cffi0/test_zdistutils.py b/extra_tests/cffi_tests/cffi0/test_zdistutils.py
--- a/extra_tests/cffi_tests/cffi0/test_zdistutils.py
+++ b/extra_tests/cffi_tests/cffi0/test_zdistutils.py
@@ -90,7 +90,7 @@
         csrc = '/*hi there %s!2*/\n#include <math.h>\n' % self
         v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                      libraries=[self.lib_m])
-        basename = self.__class__.__name__ + 'test_compile_module'
+        basename = self.__class__.__name__[:10] + '_test_compile_module'
         v.modulefilename = filename = str(udir.join(basename + '.so'))
         v.compile_module()
         assert filename == v.modulefilename
diff --git a/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py b/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py
--- a/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py
+++ b/extra_tests/cffi_tests/cffi1/test_new_ffi_1.py
@@ -1221,7 +1221,7 @@
             py.test.skip(str(e))
         f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
         f.seek(0)
-        assert f.read() == array.array('i', range(1000)).tostring()
+        assert f.read() == arraytostring(array.array('i', range(1000)))
         f.seek(0)
         b = ffi.new("int[]", 1005)
         f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
@@ -1239,7 +1239,7 @@
             py.test.skip(str(e))
         f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
         f.seek(0)
-        assert f.read() == array.array('i', range(1000)).tostring()
+        assert f.read() == arraytostring(array.array('i', range(1000)))
         f.seek(0)
         b = ffi.new("int[]", 1005)
         f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
diff --git a/extra_tests/cffi_tests/cffi1/test_recompiler.py b/extra_tests/cffi_tests/cffi1/test_recompiler.py
--- a/extra_tests/cffi_tests/cffi1/test_recompiler.py
+++ b/extra_tests/cffi_tests/cffi1/test_recompiler.py
@@ -27,13 +27,14 @@
 
 def verify(ffi, module_name, source, *args, **kwds):
     no_cpp = kwds.pop('no_cpp', False)
+    ignore_warnings = kwds.pop('ignore_warnings', False)
     kwds.setdefault('undef_macros', ['NDEBUG'])
     module_name = '_CFFI_' + module_name
     ffi.set_source(module_name, source)
     if not os.environ.get('NO_CPP') and not no_cpp:   # test the .cpp mode too
         kwds.setdefault('source_extension', '.cpp')
         source = 'extern "C" {\n%s\n}' % (source,)
-    elif sys.platform != 'win32':
+    elif sys.platform != 'win32' and not ignore_warnings:
         # add '-Werror' to the existing 'extra_compile_args' flags
         from extra_tests.cffi_tests.support import extra_compile_args
         kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) +
@@ -137,7 +138,8 @@
     import math
     ffi = FFI()
     ffi.cdef("float sin(double); double cos(double);")
-    lib = verify(ffi, 'test_math_sin', '#include <math.h>')
+    lib = verify(ffi, 'test_math_sin', '#include <math.h>',
+                 ignore_warnings=True)
     assert lib.cos(1.43) == math.cos(1.43)
 
 def test_repr_lib():
@@ -646,7 +648,7 @@
     ffi.cdef("sshort_t ff3(sshort_t);")
     lib = verify(ffi, "test_include_3",
                  "typedef short sshort_t; //usually from a #include\n"
-                 "sshort_t ff3(sshort_t x) { return x + 42; }")
+                 "sshort_t ff3(sshort_t x) { return (sshort_t)(x + 42); }")
     assert lib.ff3(10) == 52
     assert ffi.typeof(ffi.cast("sshort_t", 42)) is ffi.typeof("short")
     assert ffi1.typeof("sshort_t") is ffi.typeof("sshort_t")
@@ -755,7 +757,7 @@
     ffi = FFI()
     ffi.cdef(unicode("float sin(double); double cos(double);"))
     lib = verify(ffi, 'test_math_sin_unicode', unicode('#include <math.h>'),
-                 libraries=[unicode(lib_m)])
+                 libraries=[unicode(lib_m)], ignore_warnings=True)
     assert lib.cos(1.43) == math.cos(1.43)
 
 def test_incomplete_struct_as_arg():
@@ -883,15 +885,20 @@
     e5 = py.test.raises(TypeError, lib.foo2)
     e6 = py.test.raises(TypeError, lib.foo2, 42)
     e7 = py.test.raises(TypeError, lib.foo2, 45, 46, 47)
-    assert str(e1.value) == "foo0() takes no arguments (1 given)"
-    assert str(e2.value) == "foo0() takes no arguments (2 given)"
-    assert str(e3.value) == "foo1() takes exactly one argument (0 given)"
-    assert str(e4.value) == "foo1() takes exactly one argument (2 given)"
-    assert str(e5.value) in ["foo2 expected 2 arguments, got 0",
+    def st1(s):
+        s = str(s)
+        if s.startswith("_CFFI_test_unpack_args.CompiledLib."):
+            s = s[len("_CFFI_test_unpack_args.CompiledLib."):]
+        return s
+    assert st1(e1.value) == "foo0() takes no arguments (1 given)"
+    assert st1(e2.value) == "foo0() takes no arguments (2 given)"
+    assert st1(e3.value) == "foo1() takes exactly one argument (0 given)"
+    assert st1(e4.value) == "foo1() takes exactly one argument (2 given)"
+    assert st1(e5.value) in ["foo2 expected 2 arguments, got 0",
                              "foo2() takes exactly 2 arguments (0 given)"]
-    assert str(e6.value) in ["foo2 expected 2 arguments, got 1",
+    assert st1(e6.value) in ["foo2 expected 2 arguments, got 1",
                              "foo2() takes exactly 2 arguments (1 given)"]
-    assert str(e7.value) in ["foo2 expected 2 arguments, got 3",
+    assert st1(e7.value) in ["foo2 expected 2 arguments, got 3",
                              "foo2() takes exactly 2 arguments (3 given)"]
 
 def test_address_of_function():
@@ -899,7 +906,7 @@
     ffi.cdef("long myfunc(long x);")
     lib = verify(ffi, "test_addressof_function", """
         char myfunc(char x) { return (char)(x + 42); }
-    """)
+    """, ignore_warnings=True)
     assert lib.myfunc(5) == 47
     assert lib.myfunc(0xABC05) == 47
     assert not isinstance(lib.myfunc, ffi.CData)
@@ -1172,7 +1179,7 @@
     lib = verify(ffi, 'test_some_float_invalid_3', """
         typedef long double foo_t;
         foo_t neg(foo_t x) { return -x; }
-    """)
+    """, ignore_warnings=True)
     if ffi.sizeof("long double") == ffi.sizeof("double"):
         assert lib.neg(12.3) == -12.3
     else:
@@ -1846,7 +1853,7 @@
     ffi = FFI()
     ffi.cdef("float f1(double);")
     lib = verify(ffi, 'test_introspect_function', """
-        float f1(double x) { return x; }
+        float f1(double x) { return (float)x; }
     """)
     assert dir(lib) == ['f1']
     FUNC = ffi.typeof(lib.f1)
@@ -2151,7 +2158,8 @@
     lib = verify(ffi, "test_call_with_nested_anonymous_struct", """
         struct foo { int a; union { int b, c; }; };
         struct foo f(void) {
-            struct foo s = { 40 };
+            struct foo s;
+            s.a = 40;
             s.b = 200;
             return s;
         }
diff --git a/extra_tests/cffi_tests/support.py b/extra_tests/cffi_tests/support.py
--- a/extra_tests/cffi_tests/support.py
+++ b/extra_tests/cffi_tests/support.py
@@ -2,7 +2,7 @@
 import sys, os
 
 if sys.version_info < (3,):
-    __all__ = ['u']
+    __all__ = ['u', 'arraytostring']
 
     class U(object):
         def __add__(self, other):
@@ -13,12 +13,16 @@
     assert u+'a\x00b' == eval(r"u'a\x00b'")
     assert u+'a\u1234b' == eval(r"u'a\u1234b'")
     assert u+'a\U00012345b' == eval(r"u'a\U00012345b'")
+    def arraytostring(a):
+        return a.tostring()
 
 else:
-    __all__ = ['u', 'unicode', 'long']
+    __all__ = ['u', 'unicode', 'long', 'arraytostring']
     u = ""
     unicode = str
     long = int
+    def arraytostring(a):
+        return a.tobytes()
 
 
 class StdErrCapture(object):
diff --git a/extra_tests/test_sqlite3.py b/extra_tests/test_sqlite3.py
--- a/extra_tests/test_sqlite3.py
+++ b/extra_tests/test_sqlite3.py
@@ -88,8 +88,7 @@
     with pytest.raises(StopIteration):
         next(cur)
 
-    with pytest.raises(_sqlite3.ProgrammingError):
-        cur.executemany('select 1', [])
+    cur.executemany('select 1', [])
     with pytest.raises(StopIteration):
         next(cur)
 
@@ -201,8 +200,8 @@
 
 def test_explicit_begin(con):
     con.execute('BEGIN')
-    con.execute('BEGIN ')
-    con.execute('BEGIN')
+    with pytest.raises(_sqlite3.OperationalError):
+        con.execute('BEGIN ')
     con.commit()
     con.execute('BEGIN')
     con.commit()
@@ -212,7 +211,6 @@
     con.execute('select 1')
 
 def test_returning_blob_must_own_memory(con):
-    import gc
     con.create_function("returnblob", 0, lambda: memoryview(b"blob"))
     cur = con.execute("select returnblob()")
     val = cur.fetchone()[0]
@@ -228,15 +226,15 @@
     cur = con.cursor()
     cur.execute("create table test(a)")
     cur.executemany("insert into test values (?)", [[1], [2], [3]])
-    assert cur.lastrowid is None
+    assert cur.lastrowid == 0
     # issue 2682
     cur.execute('''insert
                 into test
                 values (?)
                 ''', (1, ))
-    assert cur.lastrowid is not None
+    assert cur.lastrowid
     cur.execute('''insert\t into test values (?) ''', (1, ))
-    assert cur.lastrowid is not None
+    assert cur.lastrowid
 
 def test_authorizer_bad_value(con):
     def authorizer_cb(action, arg1, arg2, dbname, source):
@@ -312,3 +310,24 @@
     gc.collect()
     gc.collect()
     assert SQLiteBackend.success
+
+def test_locked_table(con):
+    con.execute("CREATE TABLE foo(x)")
+    con.execute("INSERT INTO foo(x) VALUES (?)", [42])
+    cur = con.execute("SELECT * FROM foo")  # foo() is locked while cur is active
+    with pytest.raises(_sqlite3.OperationalError):
+        con.execute("DROP TABLE foo")
+
+def test_cursor_close(con):
+    con.execute("CREATE TABLE foo(x)")
+    con.execute("INSERT INTO foo(x) VALUES (?)", [42])
+    cur = con.execute("SELECT * FROM foo")
+    cur.close()
+    con.execute("DROP TABLE foo")  # no error
+
+def test_cursor_del(con):
+    con.execute("CREATE TABLE foo(x)")
+    con.execute("INSERT INTO foo(x) VALUES (?)", [42])
+    con.execute("SELECT * FROM foo")
+    import gc; gc.collect()
+    con.execute("DROP TABLE foo")  # no error
diff --git a/lib-python/3/sqlite3/test/regression.py b/lib-python/3/sqlite3/test/regression.py
--- a/lib-python/3/sqlite3/test/regression.py
+++ b/lib-python/3/sqlite3/test/regression.py
@@ -127,6 +127,7 @@
         con.execute("create table foo(bar timestamp)")
         con.execute("insert into foo(bar) values (?)", (datetime.datetime.now(),))
         con.execute(SELECT)
+        support.gc_collect()  # PyPy change
         con.execute("drop table foo")
         con.execute("create table foo(bar integer)")
         con.execute("insert into foo(bar) values (5)")
diff --git a/lib_pypy/_curses_build.py b/lib_pypy/_curses_build.py
--- a/lib_pypy/_curses_build.py
+++ b/lib_pypy/_curses_build.py
@@ -6,9 +6,7 @@
     static const int NCURSES_VERSION_MINOR;
 '''
 
-version = (0, 0)
 def find_library(options):
-    global version
     for library in options:
         ffi = FFI()
         ffi.cdef(version_str)
@@ -17,7 +15,6 @@
             ffi.compile()
             import _curses_cffi_check
             lib = _curses_cffi_check.lib
-            version = (lib.NCURSES_VERSION_MAJOR, lib.NCURSES_VERSION_MINOR)
         except VerificationError as e:
             e_last = e
             continue
@@ -385,7 +382,7 @@
 void _m_getsyx(int *yx);
 """)
 
-if version > (5, 7):
+if 'ncursesw' in libs:
     ffi.cdef("""
 typedef int... wint_t;
 int wget_wch(WINDOW *, wint_t *);
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -233,7 +233,6 @@
         self.text_factory = _unicode_text_factory
 
         self._detect_types = detect_types
-        self._in_transaction = False
         self.isolation_level = isolation_level
 
         self.__cursors = []
@@ -433,7 +432,7 @@
 
     def _begin(self):
         statement_star = _ffi.new('sqlite3_stmt **')
-        ret = _lib.sqlite3_prepare_v2(self._db, self.__begin_statement, -1,
+        ret = _lib.sqlite3_prepare_v2(self._db, self._begin_statement, -1,
                                       statement_star, _ffi.NULL)
         try:
             if ret != _lib.SQLITE_OK:
@@ -441,14 +440,13 @@
             ret = _lib.sqlite3_step(statement_star[0])
             if ret != _lib.SQLITE_DONE:
                 raise self._get_exception(ret)
-            self._in_transaction = True
         finally:
             _lib.sqlite3_finalize(statement_star[0])
 
     def commit(self):
         self._check_thread()
         self._check_closed()
-        if not self._in_transaction:
+        if not self.in_transaction:
             return
 
         # PyPy fix for non-refcounting semantics: since 2.7.13 (and in
@@ -473,14 +471,13 @@
             ret = _lib.sqlite3_step(statement_star[0])
             if ret != _lib.SQLITE_DONE:
                 raise self._get_exception(ret)
-            self._in_transaction = False
         finally:
             _lib.sqlite3_finalize(statement_star[0])
 
     def rollback(self):
         self._check_thread()
         self._check_closed()
-        if not self._in_transaction:
+        if not self.in_transaction:
             return
 
         self.__do_all_statements(Statement._reset, True)
@@ -494,7 +491,6 @@
             ret = _lib.sqlite3_step(statement_star[0])
             if ret != _lib.SQLITE_DONE:
                 raise self._get_exception(ret)
-            self._in_transaction = False
         finally:
             _lib.sqlite3_finalize(statement_star[0])
 
@@ -687,10 +683,10 @@
                 self.__func_cache[callable] = trace_callback
         _lib.sqlite3_trace(self._db, trace_callback, _ffi.NULL)
 
-    if sys.version_info[0] >= 3:
-        def __get_in_transaction(self):
-            return self._in_transaction
-        in_transaction = property(__get_in_transaction)
+    @property
+    @_check_closed_wrap
+    def in_transaction(self):
+        return not _lib.sqlite3_get_autocommit(self._db)
 
     def __get_total_changes(self):
         self._check_closed()
@@ -710,7 +706,7 @@
             stmt = str("BEGIN " + val).upper()
             if stmt not in BEGIN_STATMENTS:
                 raise ValueError("invalid value for isolation_level")
-            self.__begin_statement = stmt.encode('utf-8')
+            self._begin_statement = stmt.encode('utf-8')
         self._isolation_level = val
     isolation_level = property(__get_isolation_level, __set_isolation_level)
 
@@ -745,6 +741,11 @@
 
         self.__initialized = True
 
+    def __del__(self):
+        # Since statements are cached, they can outlive their parent cursor
+        if self.__statement:
+            self.__statement._reset()
+
     def close(self):
         if not self.__initialized:
             raise ProgrammingError("Base Cursor.__init__ not called.")
@@ -876,24 +877,13 @@
             except AttributeError:
                 pass
             self.__rowcount = -1
+            if self.__statement:
+                self.__statement._reset()
             self.__statement = self.__connection._statement_cache.get(sql)
 
-            if self.__connection._isolation_level is not None:
-                if self.__statement._type in (
-                    _STMT_TYPE_UPDATE,
-                    _STMT_TYPE_DELETE,
-                    _STMT_TYPE_INSERT,
-                    _STMT_TYPE_REPLACE
-                ):
-                    if not self.__connection._in_transaction:
-                        self.__connection._begin()
-                elif self.__statement._type == _STMT_TYPE_OTHER:
-                    if self.__connection._in_transaction:
-                        self.__connection.commit()
-                elif self.__statement._type == _STMT_TYPE_SELECT:
-                    if multiple:
-                        raise ProgrammingError("You cannot execute SELECT "
-                                               "statements in executemany().")
+            if self.__connection._begin_statement and self.__statement._is_dml:
+                if _lib.sqlite3_get_autocommit(self.__connection._db):
+                    self.__connection._begin()
 
             for params in many_params:
                 self.__statement._set_params(params)
@@ -911,6 +901,16 @@
                     self.__connection._reset_already_committed_statements()
                     ret = _lib.sqlite3_step(self.__statement._statement)
 
+                if self.__statement._is_dml:
+                    if self.__rowcount == -1:
+                        self.__rowcount = 0
+                    self.__rowcount += _lib.sqlite3_changes(self.__connection._db)
+                else:
+                    self.__rowcount = -1
+
+                if not multiple:
+                    self.__lastrowid = _lib.sqlite3_last_insert_rowid(self.__connection._db)
+
                 if ret == _lib.SQLITE_ROW:
                     if multiple:
                         raise ProgrammingError("executemany() can only execute DML statements.")
@@ -923,28 +923,9 @@
                     self.__statement._reset()
                     raise self.__connection._get_exception(ret)
 
-                if self.__statement._type in (
-                    _STMT_TYPE_UPDATE,
-                    _STMT_TYPE_DELETE,
-                    _STMT_TYPE_INSERT,
-                    _STMT_TYPE_REPLACE
-                ):
-                    if self.__rowcount == -1:
-                        self.__rowcount = 0
-                    self.__rowcount += _lib.sqlite3_changes(self.__connection._db)
-
-                if not multiple and self.__statement._type in (
-                        # REPLACE is an alias for INSERT OR REPLACE
-                        _STMT_TYPE_INSERT, _STMT_TYPE_REPLACE):
-                    self.__lastrowid = _lib.sqlite3_last_insert_rowid(self.__connection._db)
-                else:
-                    self.__lastrowid = None
-
                 if multiple:
                     self.__statement._reset()
         finally:
-            self.__connection._in_transaction = \
-                not _lib.sqlite3_get_autocommit(self.__connection._db)
             self.__locked = False
         return self
 
@@ -1086,38 +1067,19 @@
         if '\0' in sql:
             raise ValueError("the query contains a null character")
 
-        
-        if sql:
-            first_word = sql.lstrip().split()[0].upper()
-            if first_word == '':
-                self._type = _STMT_TYPE_INVALID
-            if first_word == "SELECT":
-                self._type = _STMT_TYPE_SELECT
-            elif first_word == "INSERT":
-                self._type = _STMT_TYPE_INSERT
-            elif first_word == "UPDATE":
-                self._type = _STMT_TYPE_UPDATE
-            elif first_word == "DELETE":
-                self._type = _STMT_TYPE_DELETE
-            elif first_word == "REPLACE":
-                self._type = _STMT_TYPE_REPLACE
-            else:
-                self._type = _STMT_TYPE_OTHER
-        else:
-            self._type = _STMT_TYPE_INVALID
+        to_check = sql.lstrip().upper()
+        self._valid = bool(to_check)
+        self._is_dml = to_check.startswith(('INSERT', 'UPDATE', 'DELETE', 'REPLACE'))
 
-        if isinstance(sql, unicode):
-            sql = sql.encode('utf-8')
         statement_star = _ffi.new('sqlite3_stmt **')
         next_char = _ffi.new('char **')
-        c_sql = _ffi.new("char[]", sql)
+        c_sql = _ffi.new("char[]", sql.encode('utf-8'))
         ret = _lib.sqlite3_prepare_v2(self.__con._db, c_sql, -1,
                                       statement_star, next_char)
         self._statement = statement_star[0]
 
         if ret == _lib.SQLITE_OK and not self._statement:
             # an empty statement, work around that, as it's the least trouble
-            self._type = _STMT_TYPE_SELECT
             c_sql = _ffi.new("char[]", b"select 42")
             ret = _lib.sqlite3_prepare_v2(self.__con._db, c_sql, -1,
                                           statement_star, next_char)
@@ -1238,12 +1200,7 @@
             raise ValueError("parameters are of unsupported type")
 
     def _get_description(self):
-        if self._type in (
-            _STMT_TYPE_INSERT,
-            _STMT_TYPE_UPDATE,
-            _STMT_TYPE_DELETE,
-            _STMT_TYPE_REPLACE
-        ):
+        if self._is_dml:
             return None
         desc = []
         for i in xrange(_lib.sqlite3_column_count(self._statement)):
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -1216,7 +1216,8 @@
             size_of_result = '(int)sizeof(%s)' % (
                 tp.result.get_c_name('', context),)
         prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name)
-        prnt('  { "%s.%s", %s };' % (self.module_name, name, size_of_result))
+        prnt('  { "%s.%s", %s, 0, 0 };' % (
+            self.module_name, name, size_of_result))
         prnt()
         #
         arguments = []
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
@@ -8,3 +8,7 @@
 .. branch: cpyext-speedup-tests-py36
 
 Make cpyext test faster, especially on py3.6
+
+.. branch: py3.6-sqlite
+
+Follow CPython's behaviour more closely in sqlite3
diff --git a/pypy/module/__builtin__/abstractinst.py b/pypy/module/__builtin__/abstractinst.py
--- a/pypy/module/__builtin__/abstractinst.py
+++ b/pypy/module/__builtin__/abstractinst.py
@@ -202,6 +202,19 @@
     return BaseObjSpace.exception_getclass(space, w_obj)
 
 def exception_issubclass_w(space, w_cls1, w_cls2):
+    if (space.type(w_cls1) is space.w_type and
+        space.type(w_cls2) is space.w_type):
+        return BaseObjSpace.exception_issubclass_w(space, w_cls1, w_cls2)
+    #
+    if (not exception_is_valid_class_w(space, w_cls2) or
+        not exception_is_valid_class_w(space, w_cls1)):
+        return False
+    #
+    # The rest is the rare slow case.  Use the general logic of issubclass()
+    # (issue #3149).  CPython 3.x doesn't do that (but there is a
+    # many-years issue report: https://bugs.python.org/issue12029), and
+    # there are probably tests, so we won't call abstract_issubclass_w()
+    # either in PyPy3.
     return BaseObjSpace.exception_issubclass_w(space, w_cls1, w_cls2)
 
 # ____________________________________________________________
diff --git a/pypy/module/__builtin__/test/test_abstractinst.py b/pypy/module/__builtin__/test/test_abstractinst.py
--- a/pypy/module/__builtin__/test/test_abstractinst.py
+++ b/pypy/module/__builtin__/test/test_abstractinst.py
@@ -249,3 +249,25 @@
                 return False
 
         assert issubclass(42, M()) is False
+
+    def test_exception_match_does_not_call_subclasscheck(self):
+        class Special(Exception):
+            class __metaclass__(type):
+                def __subclasscheck__(cls1, cls2):
+                    return True
+        try:
+            raise ValueError
+        except ValueError:       # Python 3.x behaviour
+            pass
+
+    def test_exception_raising_does_not_call_subclasscheck(self):
+        # test skipped: unsure how to get a non-normalized exception
+        # from pure Python.
+        class Special(Exception):
+            class __metaclass__(type):
+                def __subclasscheck__(cls1, cls2):
+                    return True
+        try:
+            skip("non-normalized exception") #raise Special, ValueError()
+        except Special:
+            pass
diff --git a/pypy/module/cpyext/include/pyport.h b/pypy/module/cpyext/include/pyport.h
--- a/pypy/module/cpyext/include/pyport.h
+++ b/pypy/module/cpyext/include/pyport.h
@@ -5,68 +5,34 @@
 #include <stdint.h>
 #endif
 
-/* typedefs for some C9X-defined synonyms for integral types. */
-#ifdef HAVE_LONG_LONG
+/* long long is required. Ensure HAVE_LONG_LONG is defined for compatibility. */
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG 1
+#endif
 #ifndef PY_LONG_LONG
 #define PY_LONG_LONG long long
-#if defined(LLONG_MAX)
 /* If LLONG_MAX is defined in limits.h, use that. */
 #define PY_LLONG_MIN LLONG_MIN
 #define PY_LLONG_MAX LLONG_MAX
 #define PY_ULLONG_MAX ULLONG_MAX
-#elif defined(__LONG_LONG_MAX__)
-/* Otherwise, if GCC has a builtin define, use that. */
-#define PY_LLONG_MAX __LONG_LONG_MAX__
-#define PY_LLONG_MIN (-PY_LLONG_MAX-1)
-#define PY_ULLONG_MAX (__LONG_LONG_MAX__*2ULL + 1ULL)
-#else
-/* Otherwise, rely on two's complement. */
-#define PY_ULLONG_MAX (~0ULL)
-#define PY_LLONG_MAX  ((long long)(PY_ULLONG_MAX>>1))
-#define PY_LLONG_MIN (-PY_LLONG_MAX-1)
-#endif /* LLONG_MAX */
-#endif
-#endif /* HAVE_LONG_LONG */
-
-/* Largest possible value of size_t.
-   SIZE_MAX is part of C99, so it might be defined on some
-   platforms. If it is not defined, (size_t)-1 is a portable
-   definition for C89, due to the way signed->unsigned 
-   conversion is defined. */
-#ifdef SIZE_MAX
-#define PY_SIZE_MAX SIZE_MAX
-#else
-#define PY_SIZE_MAX ((size_t)-1)
 #endif
 
-/* CPython needs this for the c-extension datetime, which is pure python on PyPy 
-   downstream packages assume it is here (Pandas for instance) */
-#include <time.h> 
+#define PY_UINT32_T uint32_t
+#define PY_UINT64_T uint64_t
+
+/* Signed variants of the above */
+#define PY_INT32_T int32_t
+#define PY_INT64_T int64_t
+
 
 /* uintptr_t is the C9X name for an unsigned integral type such that a
  * legitimate void* can be cast to uintptr_t and then back to void* again
  * without loss of information.  Similarly for intptr_t, wrt a signed
  * integral type.
  */
-#ifdef HAVE_UINTPTR_T
-typedef uintptr_t   Py_uintptr_t;
-typedef intptr_t    Py_intptr_t;
+typedef uintptr_t       Py_uintptr_t;
+typedef intptr_t        Py_intptr_t;
 
-#elif SIZEOF_VOID_P <= SIZEOF_INT
-typedef unsigned int    Py_uintptr_t;
-typedef int     Py_intptr_t;
-
-#elif SIZEOF_VOID_P <= SIZEOF_LONG
-typedef unsigned long   Py_uintptr_t;
-typedef long        Py_intptr_t;
-
-#elif defined(HAVE_LONG_LONG) && (SIZEOF_VOID_P <= SIZEOF_LONG_LONG)
-typedef unsigned PY_LONG_LONG   Py_uintptr_t;
-typedef PY_LONG_LONG        Py_intptr_t;
-
-#else
-#   error "Python needs a typedef for Py_uintptr_t in pyport.h."
-#endif /* HAVE_UINTPTR_T */
 
 /* Py_hash_t is the same size as a pointer. */
 #define SIZEOF_PY_HASH_T SIZEOF_SIZE_T
@@ -75,17 +41,19 @@
 #define SIZEOF_PY_UHASH_T SIZEOF_SIZE_T
 typedef size_t Py_uhash_t;
 
+/* Largest possible value of size_t. */
+#define PY_SIZE_MAX SIZE_MAX
+
+/* Largest positive value of type Py_ssize_t. */
+#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1))
+/* Smallest negative value of type Py_ssize_t. */
+#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1)
+
 #include <stdarg.h>
 
-#ifdef __va_copy
-#define Py_VA_COPY __va_copy
-#else
-#ifdef VA_LIST_IS_ARRAY
-#define Py_VA_COPY(x, y) Py_MEMCPY((x), (y), sizeof(va_list))
-#else
-#define Py_VA_COPY(x, y) (x) = (y)
-#endif
-#endif
+/* CPython needs this for the c-extension datetime, which is pure python on PyPy
+   downstream packages assume it is here (Pandas for instance) */
+#include <time.h>
 
 /*******************************
  * stat() and fstat() fiddling *
@@ -132,8 +100,7 @@
  * Hide GCC attributes from compilers that don't support them.
  */
 #if (!defined(__GNUC__) || __GNUC__ < 2 || \
-     (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ) && \
-    !defined(RISCOS)
+     (__GNUC__ == 2 && __GNUC_MINOR__ < 7) )
 #define Py_GCC_ATTRIBUTE(x)
 #else
 #define Py_GCC_ATTRIBUTE(x) __attribute__(x)
@@ -148,10 +115,13 @@
 #define Py_ALIGNED(x)
 #endif
 
-/*
- * Older Microsoft compilers don't support the C99 long long literal suffixes,
- * so these will be defined in PC/pyconfig.h for those compilers.
+/* Eliminate end-of-loop code not reached warnings from SunPro C
+ * when using do{...}while(0) macros
  */
+#ifdef __SUNPRO_C
+#pragma error_messages (off,E_END_OF_LOOP_CODE_NOT_REACHED)
+#endif
+
 #ifndef Py_LL
 #define Py_LL(x) x##LL
 #endif
@@ -160,4 +130,7 @@
 #define Py_ULL(x) Py_LL(x##U)
 #endif
 
+#define Py_VA_COPY va_copy
+
+
 #endif /* Py_PYPORT_H */
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
@@ -1,6 +1,6 @@
 #pragma once
 
-typedef long Py_ssize_t;
+typedef long Py_ssize_t;  /* CPython defines it in pyport.h */
 
 #define PyObject_HEAD  \
     Py_ssize_t ob_refcnt;        \
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -448,6 +448,10 @@
     def get_empty_storage(self):
         raise NotImplementedError
 
+    def setitem_str(self, w_dict, key, w_value):
+        w_dict.setitem(self.space.newtext(key), w_value)
+
+
     @jit.look_inside_iff(lambda self, w_dict:
                          w_dict_unrolling_heuristic(w_dict))
     def w_keys(self, w_dict):
diff --git a/pypy/objspace/std/jsondict.py b/pypy/objspace/std/jsondict.py
--- a/pypy/objspace/std/jsondict.py
+++ b/pypy/objspace/std/jsondict.py
@@ -89,6 +89,10 @@
         self.switch_to_unicode_strategy(w_dict)
         w_dict.setitem(w_key, w_value)
 
+    # for setitem_str use the default implementation
+    # because the jsonmap needs a wrapped key anyway
+
+
     def setdefault(self, w_dict, w_key, w_default):
         if self.is_correct_type(w_key):
             w_result = self.getitem_unicode(w_dict, w_key)
diff --git a/pypy/objspace/std/test/test_jsondict.py b/pypy/objspace/std/test/test_jsondict.py
--- a/pypy/objspace/std/test/test_jsondict.py
+++ b/pypy/objspace/std/test/test_jsondict.py
@@ -103,3 +103,16 @@
         str(d)
         repr(d)
 
+    def test_objdict_bug(self):
+        import _pypyjson
+        a = """{"foo": "bar"}"""
+        d = _pypyjson.loads(a)
+        d['foo'] = 'x'
+
+        class Obj(object):
+            pass
+
+        x = Obj()
+        x.__dict__ = d
+
+        x.foo = 'baz'  # used to segfault on pypy3
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -1174,7 +1174,7 @@
     def lshift(self, int_other):
         if int_other < 0:
             raise ValueError("negative shift count")
-        elif int_other == 0:
+        elif int_other == 0 or self.sign == 0:
             return self
 
         # wordshift, remshift = divmod(int_other, SHIFT)
@@ -1183,8 +1183,6 @@
 
         if not remshift:
             # So we can avoid problems with eq, AND avoid the need for normalize.
-            if self.sign == 0:
-                return self
             return rbigint([NULLDIGIT] * wordshift + self._digits, self.sign, self.numdigits() + wordshift)
 
         oldsize = self.numdigits()
diff --git a/rpython/rlib/test/test_rbigint.py b/rpython/rlib/test/test_rbigint.py
--- a/rpython/rlib/test/test_rbigint.py
+++ b/rpython/rlib/test/test_rbigint.py
@@ -704,6 +704,10 @@
         # Chek value accuracy.
         assert rbigint.fromlong(18446744073709551615L).rshift(1).tolong() == 18446744073709551615L >> 1
 
+    def test_shift_optimization(self):
+        # does not crash with memory error
+        assert rbigint.fromint(0).lshift(sys.maxint).tolong() == 0
+
     def test_qshift(self):
         for x in range(10):
             for y in range(1, 161, 16):


More information about the pypy-commit mailing list