[pypy-commit] pypy gc-del-3: hg merge default

arigo pypy.commits at gmail.com
Mon May 2 13:49:22 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: gc-del-3
Changeset: r84138:5c82986cf9e9
Date: 2016-05-02 19:49 +0200
http://bitbucket.org/pypy/pypy/changeset/5c82986cf9e9/

Log:	hg merge default

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
@@ -54,3 +54,10 @@
 generated subclasses.
 
 .. branch: share-cpyext-cpython-api
+
+.. branch: cpyext-auto-gil
+
+CPyExt tweak: instead of "GIL not held when a CPython C extension module
+calls PyXxx", we now silently acquire/release the GIL.  Helps with
+CPython C extension modules that call some PyXxx() functions without
+holding the GIL (arguably, they are theorically buggy).
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -78,7 +78,11 @@
     """
     try:
         # run it
-        f(*fargs, **fkwds)
+        try:
+            f(*fargs, **fkwds)
+        finally:
+            sys.settrace(None)
+            sys.setprofile(None)
 
         # we arrive here if no exception is raised.  stdout cosmetics...
         try:
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -436,7 +436,7 @@
             s = capi.c_resolve_name(self.space, s)
             if s != self.templ_args[i]:
                 raise OperationError(self.space.w_TypeError, self.space.wrap(
-                    "non-matching template (got %s where %s expected" % (s, self.templ_args[i])))
+                    "non-matching template (got %s where %s expected)" % (s, self.templ_args[i])))
         return W_CPPBoundMethod(cppthis, self)
 
     def bound_call(self, cppthis, args_w):
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
@@ -790,6 +790,8 @@
     from rpython.rlib import rgil
     argtypes_enum_ui = unrolling_iterable(enumerate(argtypesw))
     fatal_value = restype._defl()
+    gil_auto_workaround = (gil is None)  # automatically detect when we don't
+                                         # have the GIL, and acquire/release it
     gil_acquire = (gil == "acquire" or gil == "around")
     gil_release = (gil == "release" or gil == "around")
     pygilstate_ensure = (gil == "pygilstate_ensure")
@@ -825,7 +827,8 @@
 
         # see "Handling of the GIL" above (careful, we don't have the GIL here)
         tid = rthread.get_or_make_ident()
-        if gil_acquire:
+        _gil_auto = (gil_auto_workaround and cpyext_glob_tid_ptr[0] != tid)
+        if gil_acquire or _gil_auto:
             if cpyext_glob_tid_ptr[0] == tid:
                 deadlock_error(nameof(callable))
             rgil.acquire()
@@ -919,7 +922,7 @@
             arg = rffi.cast(lltype.Signed, args[-1])
             unlock = (arg == pystate.PyGILState_UNLOCKED)
         else:
-            unlock = gil_release
+            unlock = gil_release or _gil_auto
         if unlock:
             rgil.release()
         else:
diff --git a/pypy/module/unicodedata/interp_ucd.py b/pypy/module/unicodedata/interp_ucd.py
--- a/pypy/module/unicodedata/interp_ucd.py
+++ b/pypy/module/unicodedata/interp_ucd.py
@@ -4,7 +4,7 @@
 
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.typedef import TypeDef, interp_attrproperty
 from rpython.rlib.rarithmetic import r_longlong
 from rpython.rlib.objectmodel import we_are_translated
@@ -34,8 +34,9 @@
     # Target is wide build
     def unichr_to_code_w(space, w_unichr):
         if not space.isinstance_w(w_unichr, space.w_unicode):
-            raise OperationError(space.w_TypeError, space.wrap(
-                'argument 1 must be unicode'))
+            raise oefmt(
+                space.w_TypeError, 'argument 1 must be unicode, not %T',
+                w_unichr)
 
         if not we_are_translated() and sys.maxunicode == 0xFFFF:
             # Host CPython is narrow build, accept surrogates
@@ -54,8 +55,9 @@
     # Target is narrow build
     def unichr_to_code_w(space, w_unichr):
         if not space.isinstance_w(w_unichr, space.w_unicode):
-            raise OperationError(space.w_TypeError, space.wrap(
-                'argument 1 must be unicode'))
+            raise oefmt(
+                space.w_TypeError, 'argument 1 must be unicode, not %T',
+                w_unichr)
 
         if not we_are_translated() and sys.maxunicode > 0xFFFF:
             # Host CPython is wide build, forbid surrogates
@@ -179,7 +181,9 @@
     @unwrap_spec(form=str)
     def normalize(self, space, form, w_unistr):
         if not space.isinstance_w(w_unistr, space.w_unicode):
-            raise OperationError(space.w_TypeError, space.wrap('argument 2 must be unicode'))
+            raise oefmt(
+                space.w_TypeError, 'argument 2 must be unicode, not %T',
+                w_unistr)
         if form == 'NFC':
             composed = True
             decomposition = self._canon_decomposition
diff --git a/pypy/module/unicodedata/test/test_unicodedata.py b/pypy/module/unicodedata/test/test_unicodedata.py
--- a/pypy/module/unicodedata/test/test_unicodedata.py
+++ b/pypy/module/unicodedata/test/test_unicodedata.py
@@ -78,10 +78,15 @@
         import unicodedata
         assert unicodedata.lookup("GOTHIC LETTER FAIHU") == u'\U00010346'
 
-    def test_normalize(self):
+    def test_normalize_bad_argcount(self):
         import unicodedata
         raises(TypeError, unicodedata.normalize, 'x')
 
+    def test_normalize_nonunicode(self):
+        import unicodedata
+        exc_info = raises(TypeError, unicodedata.normalize, 'NFC', 'x')
+        assert str(exc_info.value).endswith('must be unicode, not str')
+
     @py.test.mark.skipif("sys.maxunicode < 0x10ffff")
     def test_normalize_wide(self):
         import unicodedata
@@ -103,6 +108,12 @@
         # For no reason, unicodedata.mirrored() returns an int, not a bool
         assert repr(unicodedata.mirrored(u' ')) == '0'
 
-    def test_bidirectional(self):
+    def test_bidirectional_not_one_character(self):
         import unicodedata
-        raises(TypeError, unicodedata.bidirectional, u'xx')
+        exc_info = raises(TypeError, unicodedata.bidirectional, u'xx')
+        assert str(exc_info.value) == 'need a single Unicode character as parameter'
+
+    def test_bidirectional_not_one_character(self):
+        import unicodedata
+        exc_info = raises(TypeError, unicodedata.bidirectional, 'x')
+        assert str(exc_info.value).endswith('must be unicode, not str')
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
@@ -703,10 +703,10 @@
         EMPTY = None, None
 
     def next(self):
-        if self.dictimplementation is None:
+        if self.w_dict is None:
             return EMPTY
         space = self.space
-        if self.len != self.dictimplementation.length():
+        if self.len != self.w_dict.length():
             self.len = -1   # Make this error state sticky
             raise oefmt(space.w_RuntimeError,
                         "dictionary changed size during iteration")
@@ -715,7 +715,7 @@
         if self.pos < self.len:
             result = getattr(self, 'next_' + TP + '_entry')()
             self.pos += 1
-            if self.strategy is self.dictimplementation.get_strategy():
+            if self.strategy is self.w_dict.get_strategy():
                 return result      # common case
             else:
                 # waaa, obscure case: the strategy changed, but not the
@@ -725,28 +725,28 @@
                 if TP == 'key' or TP == 'value':
                     return result
                 w_key = result[0]
-                w_value = self.dictimplementation.getitem(w_key)
+                w_value = self.w_dict.getitem(w_key)
                 if w_value is None:
                     self.len = -1   # Make this error state sticky
                     raise oefmt(space.w_RuntimeError,
                                 "dictionary changed during iteration")
                 return (w_key, w_value)
         # no more entries
-        self.dictimplementation = None
+        self.w_dict = None
         return EMPTY
     return func_with_new_name(next, 'next_' + TP)
 
 
 class BaseIteratorImplementation(object):
-    def __init__(self, space, strategy, implementation):
+    def __init__(self, space, strategy, w_dict):
         self.space = space
         self.strategy = strategy
-        self.dictimplementation = implementation
-        self.len = implementation.length()
+        self.w_dict = w_dict
+        self.len = w_dict.length()
         self.pos = 0
 
     def length(self):
-        if self.dictimplementation is not None and self.len != -1:
+        if self.w_dict is not None and self.len != -1:
             return self.len - self.pos
         return 0
 
@@ -781,9 +781,9 @@
             'setitem_untyped_%s' % dictimpl.__name__)
 
     class IterClassKeys(BaseKeyIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getiterkeys(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
+        def __init__(self, space, strategy, w_dict):
+            self.iterator = strategy.getiterkeys(w_dict)
+            BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
 
         def next_key_entry(self):
             for key in self.iterator:
@@ -792,9 +792,9 @@
                 return None
 
     class IterClassValues(BaseValueIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getitervalues(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
+        def __init__(self, space, strategy, w_dict):
+            self.iterator = strategy.getitervalues(w_dict)
+            BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
 
         def next_value_entry(self):
             for value in self.iterator:
@@ -803,9 +803,9 @@
                 return None
 
     class IterClassItems(BaseItemIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getiteritems_with_hash(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
+        def __init__(self, space, strategy, w_dict):
+            self.iterator = strategy.getiteritems_with_hash(w_dict)
+            BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
 
         def next_item_entry(self):
             for key, value, keyhash in self.iterator:
@@ -815,9 +815,9 @@
                 return None, None
 
     class IterClassReversed(BaseKeyIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getiterreversed(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
+        def __init__(self, space, strategy, w_dict):
+            self.iterator = strategy.getiterreversed(w_dict)
+            BaseIteratorImplementation.__init__(self, space, strategy, w_dict)
 
         def next_key_entry(self):
             for key in self.iterator:
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -833,15 +833,14 @@
     obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
 
 class MapDictIteratorKeys(BaseKeyIterator):
-    def __init__(self, space, strategy, dictimplementation):
-        BaseKeyIterator.__init__(self, space, strategy, dictimplementation)
-        w_obj = strategy.unerase(dictimplementation.dstorage)
+    def __init__(self, space, strategy, w_dict):
+        BaseKeyIterator.__init__(self, space, strategy, w_dict)
+        w_obj = strategy.unerase(w_dict.dstorage)
         self.w_obj = w_obj
         self.orig_map = self.curr_map = w_obj._get_mapdict_map()
 
     def next_key_entry(self):
-        implementation = self.dictimplementation
-        assert isinstance(implementation.get_strategy(), MapDictStrategy)
+        assert isinstance(self.w_dict.get_strategy(), MapDictStrategy)
         if self.orig_map is not self.w_obj._get_mapdict_map():
             return None
         if self.curr_map:
@@ -855,15 +854,14 @@
 
 
 class MapDictIteratorValues(BaseValueIterator):
-    def __init__(self, space, strategy, dictimplementation):
-        BaseValueIterator.__init__(self, space, strategy, dictimplementation)
-        w_obj = strategy.unerase(dictimplementation.dstorage)
+    def __init__(self, space, strategy, w_dict):
+        BaseValueIterator.__init__(self, space, strategy, w_dict)
+        w_obj = strategy.unerase(w_dict.dstorage)
         self.w_obj = w_obj
         self.orig_map = self.curr_map = w_obj._get_mapdict_map()
 
     def next_value_entry(self):
-        implementation = self.dictimplementation
-        assert isinstance(implementation.get_strategy(), MapDictStrategy)
+        assert isinstance(self.w_dict.get_strategy(), MapDictStrategy)
         if self.orig_map is not self.w_obj._get_mapdict_map():
             return None
         if self.curr_map:
@@ -876,15 +874,14 @@
 
 
 class MapDictIteratorItems(BaseItemIterator):
-    def __init__(self, space, strategy, dictimplementation):
-        BaseItemIterator.__init__(self, space, strategy, dictimplementation)
-        w_obj = strategy.unerase(dictimplementation.dstorage)
+    def __init__(self, space, strategy, w_dict):
+        BaseItemIterator.__init__(self, space, strategy, w_dict)
+        w_obj = strategy.unerase(w_dict.dstorage)
         self.w_obj = w_obj
         self.orig_map = self.curr_map = w_obj._get_mapdict_map()
 
     def next_item_entry(self):
-        implementation = self.dictimplementation
-        assert isinstance(implementation.get_strategy(), MapDictStrategy)
+        assert isinstance(self.w_dict.get_strategy(), MapDictStrategy)
         if self.orig_map is not self.w_obj._get_mapdict_map():
             return None, None
         if self.curr_map:
diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -560,7 +560,7 @@
                 msg = "Sign not allowed in string format specifier"
                 raise OperationError(space.w_ValueError, space.wrap(msg))
             if self._alternate:
-                msg = "Alternate form not allowed in string format specifier"
+                msg = "Alternate form (#) not allowed in string format specifier"
                 raise OperationError(space.w_ValueError, space.wrap(msg))
             if self._align == "=":
                 msg = "'=' alignment not allowed in string format specifier"
@@ -920,7 +920,7 @@
             flags = 0
             default_precision = 6
             if self._alternate:
-                msg = "alternate form not allowed in float formats"
+                msg = "Alternate form (#) not allowed in float formats"
                 raise OperationError(space.w_ValueError, space.wrap(msg))
             tp = self._type
             self._get_locale(tp)
@@ -998,9 +998,9 @@
                 raise OperationError(space.w_ValueError, space.wrap(msg))
             if self._alternate:
                 #alternate is invalid
-                msg = "Alternate form %s not allowed in complex format specifier"
+                msg = "Alternate form (#) not allowed in complex format specifier"
                 raise OperationError(space.w_ValueError,
-                                     space.wrap(msg % (self._alternate)))
+                                     space.wrap(msg))
             skip_re = 0
             add_parens = 0
             if tp == "\0":
diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py
--- a/pypy/objspace/std/test/test_typeobject.py
+++ b/pypy/objspace/std/test/test_typeobject.py
@@ -143,7 +143,6 @@
         e = E()
         D.__bases__ = (C,)
         D.__bases__ = (C2,)
-        #import pdb; pdb.set_trace()
         assert d.meth() == 1
         assert e.meth() == 1
         assert d.a == 2
@@ -184,7 +183,7 @@
 
         try:
             D.__bases__ = ()
-        except TypeError, msg:
+        except TypeError as msg:
             if str(msg) == "a new-style class can't have only classic bases":
                 assert 0, "wrong error message for .__bases__ = ()"
         else:
@@ -309,7 +308,7 @@
         except TypeError:
             pass
         else:
-            raise TestFailed, "didn't catch MRO conflict"
+            raise TestFailed("didn't catch MRO conflict")
 
     def test_mutable_bases_versus_nonheap_types(self):
         class A(int):
@@ -442,7 +441,7 @@
         except TypeError:
             pass
         else:
-            raise AssertionError, "this multiple inheritance should fail"
+            raise AssertionError("this multiple inheritance should fail")
 
     def test_outer_metaclass(self):
         class OuterMetaClass(type):
@@ -512,7 +511,7 @@
         try:
             assert NoDoc.__doc__ == None
         except AttributeError:
-            raise AssertionError, "__doc__ missing!"
+            raise AssertionError("__doc__ missing!")
 
     def test_explicitdoc(self):
         class ExplicitDoc(object):
@@ -539,7 +538,7 @@
             #       we always raise AttributeError.
             pass
         else:
-            raise AssertionError, '__doc__ should not be writable'
+            raise AssertionError('__doc__ should not be writable')
 
         assert ImmutableDoc.__doc__ == 'foo'
 
@@ -1048,14 +1047,14 @@
         try:
             class E(B, A):   # "best base" is B
                 __slots__ = ("__dict__",)
-        except TypeError, e:
+        except TypeError as e:
             assert 'we already got one' in str(e)
         else:
             raise AssertionError("TypeError not raised")
         try:
             class F(B, A):   # "best base" is B
                 __slots__ = ("__weakref__",)
-        except TypeError, e:
+        except TypeError as e:
             assert 'we already got one' in str(e)
         else:
             raise AssertionError("TypeError not raised")
diff --git a/rpython/translator/backendopt/test/test_finalizer.py b/rpython/translator/backendopt/test/test_finalizer.py
--- a/rpython/translator/backendopt/test/test_finalizer.py
+++ b/rpython/translator/backendopt/test/test_finalizer.py
@@ -39,31 +39,6 @@
         r = self.analyze(f, [])
         assert not r
 
-def test_various_ops():
-    from rpython.flowspace.model import SpaceOperation, Constant
-
-    X = lltype.Ptr(lltype.GcStruct('X'))
-    Z = lltype.Ptr(lltype.Struct('Z'))
-    S = lltype.GcStruct('S', ('x', lltype.Signed),
-                        ('y', X),
-                        ('z', Z))
-    v1 = varoftype(lltype.Bool)
-    v2 = varoftype(lltype.Signed)
-    f = FinalizerAnalyzer(None)
-    r = f.analyze(SpaceOperation('cast_int_to_bool', [v2],
-                                                       v1))
-    assert not r
-    v1 = varoftype(lltype.Ptr(S))
-    v2 = varoftype(lltype.Signed)
-    v3 = varoftype(X)
-    v4 = varoftype(Z)
-    assert not f.analyze(SpaceOperation('bare_setfield', [v1, Constant('x'),
-                                                          v2], None))
-    assert     f.analyze(SpaceOperation('bare_setfield', [v1, Constant('y'),
-                                                          v3], None))
-    assert not f.analyze(SpaceOperation('bare_setfield', [v1, Constant('z'),
-                                                          v4], None))
-
     def test_malloc(self):
         S = lltype.GcStruct('S')
 
@@ -104,6 +79,22 @@
             lltype.free(p, flavor='raw')
 
         r = self.analyze(g, [], f, backendopt=True)
+        assert r
+
+    def test_c_call_without_release_gil(self):
+        C = rffi.CArray(lltype.Signed)
+        c = rffi.llexternal('x', [lltype.Ptr(C)], lltype.Signed,
+                            releasegil=False)
+
+        def g():
+            p = lltype.malloc(C, 3, flavor='raw')
+            f(p)
+
+        def f(p):
+            c(rffi.ptradd(p, 0))
+            lltype.free(p, flavor='raw')
+
+        r = self.analyze(g, [], f, backendopt=True)
         assert not r
 
     def test_chain(self):
@@ -135,3 +126,30 @@
             pass
         self.analyze(g, []) # did not explode
         py.test.raises(FinalizerError, self.analyze, f, [])
+
+
+def test_various_ops():
+    from rpython.flowspace.model import SpaceOperation, Constant
+
+    X = lltype.Ptr(lltype.GcStruct('X'))
+    Z = lltype.Ptr(lltype.Struct('Z'))
+    S = lltype.GcStruct('S', ('x', lltype.Signed),
+                        ('y', X),
+                        ('z', Z))
+    v1 = varoftype(lltype.Bool)
+    v2 = varoftype(lltype.Signed)
+    f = FinalizerAnalyzer(None)
+    r = f.analyze(SpaceOperation('cast_int_to_bool', [v2],
+                                                       v1))
+    assert not r
+    v1 = varoftype(lltype.Ptr(S))
+    v2 = varoftype(lltype.Signed)
+    v3 = varoftype(X)
+    v4 = varoftype(Z)
+    assert not f.analyze(SpaceOperation('bare_setfield', [v1, Constant('x'),
+                                                          v2], None))
+    assert     f.analyze(SpaceOperation('bare_setfield', [v1, Constant('y'),
+                                                          v3], None))
+    assert not f.analyze(SpaceOperation('bare_setfield', [v1, Constant('z'),
+                                                          v4], None))
+


More information about the pypy-commit mailing list