[pypy-commit] pypy pypy3-release-2.3.x: merge py3k

pjenvey noreply at buildbot.pypy.org
Thu Jun 19 18:17:26 CEST 2014


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: pypy3-release-2.3.x
Changeset: r72102:986752d005bb
Date: 2014-06-19 09:16 -0700
http://bitbucket.org/pypy/pypy/changeset/986752d005bb/

Log:	merge py3k

diff --git a/lib_pypy/gdbm.py b/lib_pypy/_gdbm.py
rename from lib_pypy/gdbm.py
rename to lib_pypy/_gdbm.py
--- a/lib_pypy/gdbm.py
+++ b/lib_pypy/_gdbm.py
@@ -1,4 +1,5 @@
 import cffi, os
+import sys
 
 ffi = cffi.FFI()
 ffi.cdef('''
@@ -46,12 +47,15 @@
     # failure must be due to missing gdbm dev libs
     raise ImportError('%s: %s' %(e.__class__.__name__, e))
 
-class error(Exception):
+class error(IOError):
     pass
 
 def _fromstr(key):
-    if not isinstance(key, str):
-        raise TypeError("gdbm mappings have string indices only")
+    if isinstance(key, str):
+        key = key.encode(sys.getdefaultencoding())
+    elif not isinstance(key, bytes):
+        msg = "gdbm mappings have bytes or string indices only, not {!r}"
+        raise TypeError(msg.format(type(key).__name__))
     return {'dptr': ffi.new("char[]", key), 'dsize': len(key)}
 
 class gdbm(object):
@@ -98,21 +102,27 @@
         return lib.gdbm_exists(self.ll_dbm, _fromstr(key))
     has_key = __contains__
 
-    def __getitem__(self, key):
+    def get(self, key, default=None):
         self._check_closed()
         drec = lib.gdbm_fetch(self.ll_dbm, _fromstr(key))
         if not drec.dptr:
-            raise KeyError(key)
-        res = str(ffi.buffer(drec.dptr, drec.dsize))
+            return default
+        res = bytes(ffi.buffer(drec.dptr, drec.dsize))
         lib.free(drec.dptr)
         return res
 
+    def __getitem__(self, key):
+        value = self.get(key)
+        if value is None:
+            raise KeyError(key)
+        return value
+
     def keys(self):
         self._check_closed()
         l = []
         key = lib.gdbm_firstkey(self.ll_dbm)
         while key.dptr:
-            l.append(str(ffi.buffer(key.dptr, key.dsize)))
+            l.append(bytes(ffi.buffer(key.dptr, key.dsize)))
             nextkey = lib.gdbm_nextkey(self.ll_dbm, key)
             lib.free(key.dptr)
             key = nextkey
@@ -122,7 +132,7 @@
         self._check_closed()
         key = lib.gdbm_firstkey(self.ll_dbm)
         if key.dptr:
-            res = str(ffi.buffer(key.dptr, key.dsize))
+            res = bytes(ffi.buffer(key.dptr, key.dsize))
             lib.free(key.dptr)
             return res
 
@@ -130,7 +140,7 @@
         self._check_closed()
         key = lib.gdbm_nextkey(self.ll_dbm, _fromstr(key))
         if key.dptr:
-            res = str(ffi.buffer(key.dptr, key.dsize))
+            res = bytes(ffi.buffer(key.dptr, key.dsize))
             lib.free(key.dptr)
             return res
 
@@ -149,7 +159,18 @@
         self._check_closed()
         lib.gdbm_sync(self.ll_dbm)
 
+    def setdefault(self, key, default=None):
+        value = self.get(key)
+        if value is not None:
+            return value
+        self[key] = default
+        return default
+
 def open(filename, flags='r', mode=0o666):
+    if not isinstance(filename, str):
+        raise TypeError("must be str, not %s" % type(filename).__name__)
+    filename = filename.encode(sys.getdefaultencoding())
+
     if flags[0] == 'r':
         iflags = lib.GDBM_READER
     elif flags[0] == 'w':
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -283,8 +283,7 @@
                     missing += 1
                     continue
                 name = signature.kwonlyargnames[i - co_argcount]
-                w_name = self.space.wrap(name)
-                w_def = self.space.finditem(w_kw_defs, w_name)
+                w_def = self.space.finditem_str(w_kw_defs, name)
                 if w_def is not None:
                     scope_w[i] = w_def
                 else:
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -36,44 +36,11 @@
 
     def setup(self, w_type, w_value=None):
         assert w_type is not None
-        from pypy.objspace.std.typeobject import W_TypeObject
         self.w_type = w_type
         self._w_value = w_value
-        # HACK: isinstance(w_type, W_TypeObject) won't translate under
-        # the fake objspace, but w_type.__class__ is W_TypeObject does
-        # and short circuits to a False constant there, causing the
-        # isinstance to be ignored =[
-        if (w_type is not None and w_type.__class__ is W_TypeObject and
-            isinstance(w_type, W_TypeObject)):
-            self.setup_context(w_type.space)
         if not we_are_translated():
             self.debug_excs = []
 
-    def setup_context(self, space):
-        # Implicit exception chaining
-        last_operror = space.getexecutioncontext().sys_exc_info()
-        if (last_operror is None or
-            last_operror is get_cleared_operation_error(space)):
-            return
-
-        # We must normalize the value right now to check for cycles
-        self.normalize_exception(space)
-        w_value = self.get_w_value(space)
-        w_last_value = last_operror.get_w_value(space)
-        if not space.is_w(w_value, w_last_value):
-            # Avoid reference cycles through the context chain. This is
-            # O(chain length) but context chains are usually very short.
-            w_obj = w_last_value
-            while True:
-                w_context = space.getattr(w_obj, space.wrap('__context__'))
-                if space.is_w(w_context, space.w_None):
-                    break
-                if space.is_w(w_context, w_value):
-                    space.setattr(w_obj, space.wrap('__context__'), space.w_None)
-                    break
-                w_obj = w_context
-            space.setattr(w_value, space.wrap('__context__'), w_last_value)
-
     def clear(self, space):
         # XXX remove this method.  The point is that we cannot always
         # hack at 'self' to clear w_type and _w_value, because in some
@@ -350,6 +317,53 @@
         """
         self._application_traceback = traceback
 
+    def record_context(self, space, frame):
+        """Record a __context__ for this exception from the current
+        frame if one exists.
+
+        __context__ is otherwise lazily determined from the
+        traceback. However the current frame.last_exception must be
+        checked for a __context__ before this OperationError overwrites
+        it (making the previous last_exception unavailable later on).
+        """
+        last_exception = frame.last_exception
+        if (last_exception is not None and not frame.hide() or
+            last_exception is get_cleared_operation_error(space)):
+            # normalize w_value so setup_context can check for cycles
+            self.normalize_exception(space)
+            w_value = self.get_w_value(space)
+            w_last = last_exception.get_w_value(space)
+            w_context = setup_context(space, w_value, w_last, lazy=True)
+            space.setattr(w_value, space.wrap('__context__'), w_context)
+
+
+def setup_context(space, w_exc, w_last, lazy=False):
+    """Determine the __context__ for w_exc from w_last and break
+    reference cycles in the __context__ chain.
+    """
+    from pypy.module.exceptions.interp_exceptions import W_BaseException
+    if space.is_w(w_exc, w_last):
+        w_last = space.w_None
+    # w_last may also be space.w_None if from ClearedOpErr
+    if not space.is_w(w_last, space.w_None):
+        # Avoid reference cycles through the context chain. This is
+        # O(chain length) but context chains are usually very short.
+        w_obj = w_last
+        while True:
+            assert isinstance(w_obj, W_BaseException)
+            if lazy:
+                w_context = w_obj.w_context
+            else:
+                # triggers W_BaseException._setup_context
+                w_context = space.getattr(w_obj, space.wrap('__context__'))
+            if space.is_none(w_context):
+                break
+            if space.is_w(w_context, w_exc):
+                w_obj.w_context = space.w_None
+                break
+            w_obj = w_context
+    return w_last
+
 
 class ClearedOpErr:
     def __init__(self, space):
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -202,18 +202,21 @@
             self._trace(frame, 'exception', None, operationerr)
         #operationerr.print_detailed_traceback(self.space)
 
+    @staticmethod
+    def last_operr(space, frame):
+        while frame:
+            last = frame.last_exception
+            if (last is not None and
+                (not frame.hide() or
+                 last is get_cleared_operation_error(space))):
+                    return last
+            frame = frame.f_backref()
+        return None
+
     def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!!
         """Implements sys.exc_info().
         Return an OperationError instance or None."""
-        frame = self.gettopframe()
-        while frame:
-            if frame.last_exception is not None:
-                if (not frame.hide() or
-                        frame.last_exception is
-                            get_cleared_operation_error(self.space)):
-                    return frame.last_exception
-            frame = frame.f_backref()
-        return None
+        return self.last_operr(self.space, self.gettopframe())
 
     def set_sys_exc_info(self, operror):
         frame = self.gettopframe_nohidden()
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -32,7 +32,8 @@
                           'w_func_globals?',
                           'closure?[*]',
                           'defs_w?[*]',
-                          'name?']
+                          'name?',
+                          'w_kw_defs?']
 
     def __init__(self, space, code, w_globals=None, defs_w=[], w_kw_defs=None,
                  closure=None, w_ann=None, forcename=None):
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -164,12 +164,9 @@
         for i in range(nfreevars):
             self.cells[i + ncellvars] = outer_func.closure[i]
 
-    def is_generator(self):
-        return self.getcode().co_flags & pycode.CO_GENERATOR
-            
     def run(self):
         """Start this frame's execution."""
-        if self.is_generator():
+        if self.getcode().co_flags & pycode.CO_GENERATOR:
             if self.getcode().co_flags & pycode.CO_YIELD_INSIDE_TRY:
                 from pypy.interpreter.generator import GeneratorIteratorWithDel
                 return self.space.wrap(GeneratorIteratorWithDel(self))
@@ -514,10 +511,10 @@
         for i in range(min(len(varnames), self.getcode().co_nlocals)):
             name = varnames[i]
             w_value = self.locals_stack_w[i]
-            w_name = self.space.wrap(name.decode('utf-8'))
             if w_value is not None:
-                self.space.setitem(self.w_locals, w_name, w_value)
+                self.space.setitem_str(self.w_locals, name, w_value)
             else:
+                w_name = self.space.wrap(name.decode('utf-8'))
                 try:
                     self.space.delitem(self.w_locals, w_name)
                 except OperationError as e:
@@ -537,8 +534,7 @@
             except ValueError:
                 pass
             else:
-                w_name = self.space.wrap(name)
-                self.space.setitem(self.w_locals, w_name, w_value)
+                self.space.setitem_str(self.w_locals, name, w_value)
 
 
     @jit.unroll_safe
@@ -551,13 +547,9 @@
         new_fastlocals_w = [None] * numlocals
 
         for i in range(min(len(varnames), numlocals)):
-            w_name = self.space.wrap(varnames[i].decode('utf-8'))
-            try:
-                w_value = self.space.getitem(self.w_locals, w_name)
-            except OperationError, e:
-                if not e.match(self.space, self.space.w_KeyError):
-                    raise
-            else:
+            name = varnames[i]
+            w_value = self.space.finditem_str(self.w_locals, name)
+            if w_value is not None:
                 new_fastlocals_w[i] = w_value
 
         self.setfastscope(new_fastlocals_w)
@@ -566,13 +558,8 @@
         for i in range(len(freevarnames)):
             name = freevarnames[i]
             cell = self.cells[i]
-            w_name = self.space.wrap(name)
-            try:
-                w_value = self.space.getitem(self.w_locals, w_name)
-            except OperationError, e:
-                if not e.match(self.space, self.space.w_KeyError):
-                    raise
-            else:
+            w_value = self.space.finditem_str(self.w_locals, name)
+            if w_value is not None:
                 cell.set(w_value)
 
     @jit.unroll_safe
diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py
--- a/pypy/interpreter/pytraceback.py
+++ b/pypy/interpreter/pytraceback.py
@@ -57,6 +57,7 @@
     tb = operror.get_traceback()
     tb = PyTraceback(space, frame, last_instruction, tb)
     operror.set_traceback(tb)
+    operror.record_context(space, frame)
 
 
 def check_traceback(space, w_tb, msg):
diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py
--- a/pypy/interpreter/test/test_raise.py
+++ b/pypy/interpreter/test/test_raise.py
@@ -369,6 +369,44 @@
         else:
             fail("No exception raised")
 
+    def test_context_once_removed(self):
+        context = IndexError()
+        def func1():
+            func2()
+        def func2():
+            try:
+                1/0
+            except ZeroDivisionError as e:
+                assert e.__context__ is context
+            else:
+                fail('No exception raised')
+        try:
+            raise context
+        except:
+            func1()
+
+    @py.test.mark.xfail(reason="A somewhat contrived case that may burden the "
+                        "JIT to fully support")
+    def test_frame_spanning_cycle_broken(self):
+        context = IndexError()
+        def func():
+            try:
+                1/0
+            except Exception as e1:
+                try:
+                    raise context
+                except Exception as e2:
+                    assert e2.__context__ is e1
+                    # XXX:
+                    assert e1.__context__ is None
+            else:
+                fail('No exception raised')
+        try:
+            raise context
+        except:
+            func()
+
+
 class AppTestTraceback:
 
     def test_raise_with___traceback__(self):
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
@@ -6,7 +6,8 @@
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
+from pypy.interpreter.gateway import (
+    interp2app, interpindirect2app, unwrap_spec)
 from pypy.interpreter.typedef import TypeDef
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import specialize
@@ -307,15 +308,19 @@
 
 
 class W_Range(W_Root):
-    def __init__(self, w_start, w_stop, w_step, w_length):
+    def __init__(self, w_start, w_stop, w_step, w_length, promote_step=False):
         self.w_start = w_start
         self.w_stop  = w_stop
         self.w_step  = w_step
         self.w_length = w_length
+        self.promote_step = promote_step
 
-    @unwrap_spec(w_step = WrappedDefault(1))
     def descr_new(space, w_subtype, w_start, w_stop=None, w_step=None):
         w_start = space.index(w_start)
+        promote_step = False
+        if space.is_none(w_step):  # no step argument provided
+            w_step = space.wrap(1)
+            promote_step = True
         if space.is_none(w_stop):  # only 1 argument provided
             w_start, w_stop = space.newint(0), w_start
         else:
@@ -331,7 +336,7 @@
                         "step argument must not be zero"))
         w_length = compute_range_length(space, w_start, w_stop, w_step)
         obj = space.allocate_instance(W_Range, w_subtype)
-        W_Range.__init__(obj, w_start, w_stop, w_step, w_length)
+        W_Range.__init__(obj, w_start, w_stop, w_step, w_length, promote_step)
         return space.wrap(obj)
 
     def descr_repr(self, space):
@@ -386,8 +391,19 @@
             return self._compute_item(space, w_index)
 
     def descr_iter(self, space):
-        return space.wrap(W_RangeIterator(
-                space, self.w_start, self.w_step, self.w_length))
+        try:
+            start = space.int_w(self.w_start)
+            stop = space.int_w(self.w_stop)
+            step = space.int_w(self.w_step)
+            length = space.int_w(self.w_length)
+        except OperationError as e:
+            pass
+        else:
+            if self.promote_step:
+                return W_IntRangeStepOneIterator(space, start, stop)
+            return W_IntRangeIterator(space, start, length, step)
+        return W_LongRangeIterator(space, self.w_start, self.w_step,
+                                   self.w_length)
 
     def descr_reversed(self, space):
         # lastitem = self.start + (self.length-1) * self.step
@@ -395,7 +411,7 @@
             self.w_start,
             space.mul(space.sub(self.w_length, space.newint(1)),
                       self.w_step))
-        return space.wrap(W_RangeIterator(
+        return space.wrap(W_LongRangeIterator(
                 space, w_lastitem, space.neg(self.w_step), self.w_length))
 
     def descr_reduce(self, space):
@@ -463,7 +479,22 @@
 W_Range.typedef.acceptable_as_base_class = False
 
 
-class W_RangeIterator(W_Root):
+class W_AbstractRangeIterator(W_Root):
+
+    def descr_iter(self, space):
+        return space.wrap(self)
+
+    def descr_len(self, space):
+        raise NotImplementedError
+
+    def descr_next(self, space):
+        raise NotImplementedError
+
+    def descr_reduce(self, space):
+        raise NotImplementedError
+
+
+class W_LongRangeIterator(W_AbstractRangeIterator):
     def __init__(self, space, w_start, w_step, w_len, w_index=None):
         self.w_start = w_start
         self.w_step = w_step
@@ -472,9 +503,6 @@
             w_index = space.newint(0)
         self.w_index = w_index
 
-    def descr_iter(self, space):
-        return space.wrap(self)
-
     def descr_next(self, space):
         if space.is_true(space.lt(self.w_index, self.w_len)):
             w_index = space.add(self.w_index, space.newint(1))
@@ -489,23 +517,75 @@
 
     def descr_reduce(self, space):
         from pypy.interpreter.mixedmodule import MixedModule
+        w_mod = space.getbuiltinmodule('_pickle_support')
+        mod = space.interp_w(MixedModule, w_mod)
+        w_args = space.newtuple([self.w_start, self.w_step, self.w_len,
+                                 self.w_index])
+        return space.newtuple([mod.get('longrangeiter_new'), w_args])
+
+
+class W_IntRangeIterator(W_AbstractRangeIterator):
+
+    def __init__(self, space, current, remaining, step):
+        self.current = current
+        self.remaining = remaining
+        self.step = step
+
+    def descr_next(self, space):
+        return self.next(space)
+
+    def next(self, space):
+        if self.remaining > 0:
+            item = self.current
+            self.current = item + self.step
+            self.remaining -= 1
+            return space.wrap(item)
+        raise OperationError(space.w_StopIteration, space.w_None)
+
+    def descr_len(self, space):
+        return self.get_remaining(space)
+
+    def descr_reduce(self, space):
+        from pypy.interpreter.mixedmodule import MixedModule
         w_mod    = space.getbuiltinmodule('_pickle_support')
         mod      = space.interp_w(MixedModule, w_mod)
+        new_inst = mod.get('intrangeiter_new')
+        w        = space.wrap
+        nt = space.newtuple
 
-        return space.newtuple(
-            [mod.get('rangeiter_new'),
-             space.newtuple([self.w_start, self.w_step,
-                             self.w_len, self.w_index]),
-             ])
+        tup = [w(self.current), self.get_remaining(space), w(self.step)]
+        return nt([new_inst, nt(tup)])
 
+    def get_remaining(self, space):
+        return space.wrap(self.remaining)
 
-W_RangeIterator.typedef = TypeDef("rangeiterator",
-    __iter__        = interp2app(W_RangeIterator.descr_iter),
-    __length_hint__ = interp2app(W_RangeIterator.descr_len),
-    __next__        = interp2app(W_RangeIterator.descr_next),
-    __reduce__      = interp2app(W_RangeIterator.descr_reduce),
+
+class W_IntRangeStepOneIterator(W_IntRangeIterator):
+    _immutable_fields_ = ['stop']
+
+    def __init__(self, space, start, stop):
+        self.current = start
+        self.stop = stop
+        self.step = 1
+
+    def next(self, space):
+        if self.current < self.stop:
+            item = self.current
+            self.current = item + 1
+            return space.wrap(item)
+        raise OperationError(space.w_StopIteration, space.w_None)
+
+    def get_remaining(self, space):
+        return space.wrap(self.stop - self.current)
+
+
+W_AbstractRangeIterator.typedef = TypeDef("rangeiterator",
+    __iter__        = interp2app(W_AbstractRangeIterator.descr_iter),
+    __length_hint__ = interpindirect2app(W_AbstractRangeIterator.descr_len),
+    __next__        = interpindirect2app(W_AbstractRangeIterator.descr_next),
+    __reduce__      = interpindirect2app(W_AbstractRangeIterator.descr_reduce),
 )
-W_RangeIterator.typedef.acceptable_as_base_class = False
+W_AbstractRangeIterator.typedef.acceptable_as_base_class = False
 
 
 class W_Map(W_Root):
diff --git a/pypy/module/_pickle_support/__init__.py b/pypy/module/_pickle_support/__init__.py
--- a/pypy/module/_pickle_support/__init__.py
+++ b/pypy/module/_pickle_support/__init__.py
@@ -19,7 +19,8 @@
         'frame_new'    : 'maker.frame_new',
         'traceback_new' : 'maker.traceback_new',
         'generator_new' : 'maker.generator_new',
-        'rangeiter_new': 'maker.rangeiter_new',
+        'longrangeiter_new': 'maker.longrangeiter_new',
+        'intrangeiter_new': 'maker.intrangeiter_new',
         'builtin_code': 'maker.builtin_code',
         'builtin_function' : 'maker.builtin_function',
         'enumerate_new': 'maker.enumerate_new',
diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py
--- a/pypy/module/_pickle_support/maker.py
+++ b/pypy/module/_pickle_support/maker.py
@@ -62,9 +62,15 @@
     new_generator = instantiate(GeneratorIteratorWithDel)
     return space.wrap(new_generator)
 
-def rangeiter_new(space, w_start, w_step, w_len, w_index):
-    from pypy.module.__builtin__.functional import W_RangeIterator
-    new_iter = W_RangeIterator(space, w_start, w_step, w_len, w_index)
+def longrangeiter_new(space, w_start, w_step, w_len, w_index):
+    from pypy.module.__builtin__.functional import W_LongRangeIterator
+    new_iter = W_LongRangeIterator(space, w_start, w_step, w_len, w_index)
+    return space.wrap(new_iter)
+
+ at unwrap_spec(current=int, remaining=int, step=int)
+def intrangeiter_new(space, current, remaining, step):
+    from pypy.module.__builtin__.functional import W_IntRangeIterator
+    new_iter = W_IntRangeIterator(space, current, remaining, step)
     return space.wrap(new_iter)
 
 def operationerror_new(space):
diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -76,8 +76,8 @@
 from pypy.interpreter.typedef import (TypeDef, GetSetProperty, descr_get_dict,
     descr_set_dict, descr_del_dict)
 from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.pytraceback import check_traceback
+from pypy.interpreter.error import OperationError, setup_context
+from pypy.interpreter.pytraceback import PyTraceback, check_traceback
 from rpython.rlib import rwin32
 
 
@@ -156,7 +156,27 @@
         self.w_cause = w_newcause
 
     def descr_getcontext(self, space):
-        return self.w_context
+        w_context = self.w_context
+        if w_context is None:
+            self.w_context = w_context = self._setup_context(space)
+        return w_context
+
+    def _setup_context(self, space):
+        """Lazily determine __context__ from w_traceback"""
+        # XXX: w_traceback can be overwritten: it's not necessarily the
+        # authoratative traceback!
+        last_operr = None
+        w_traceback = self.w_traceback
+        if w_traceback is not None and isinstance(w_traceback, PyTraceback):
+            ec = space.getexecutioncontext()
+            # search for __context__ beginning in the previous frame. A
+            # __context__ from the top most frame would have already
+            # been handled by OperationError.record_context
+            last_operr = ec.last_operr(space, w_traceback.frame.f_backref())
+        if last_operr is None:
+            # no __context__
+            return space.w_None
+        return setup_context(space, self, last_operr.get_w_value(space))
 
     def descr_setcontext(self, space, w_newcontext):
         if not (space.is_w(w_newcontext, space.w_None) or
@@ -167,7 +187,6 @@
         self.w_context = w_newcontext
 
     def descr_gettraceback(self, space):
-        from pypy.interpreter.pytraceback import PyTraceback
         tb = self.w_traceback
         if tb is not None and isinstance(tb, PyTraceback):
             # tb escapes to app level (see OperationError.get_traceback)
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
@@ -24,7 +24,7 @@
 
 class W_UnicodeObject(W_Root):
     import_from_mixin(StringMethods)
-    _immutable_fields_ = ['_value']
+    _immutable_fields_ = ['_value', '_utf8?']
 
     def __init__(w_self, unistr):
         assert isinstance(unistr, unicode)
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -133,7 +133,7 @@
     modules = ['_sqlite3']
     subprocess.check_call([str(pypy_c), '-c', 'import _sqlite3'])
     if not sys.platform == 'win32':
-        modules += ['_curses', 'syslog', 'gdbm', '_sqlite3']
+        modules += ['_curses', 'syslog', '_gdbm', '_sqlite3']
     if not options.no_tk:
         modules.append(('_tkinter'))
     for module in modules:
@@ -402,10 +402,10 @@
 
 '''
 
-gdbm_bit = '''gdbm
+gdbm_bit = '''_gdbm
 ----
 
-The gdbm module includes code from gdbm.h, which is distributed under the terms
+The _gdbm module includes code from gdbm.h, which is distributed under the terms
 of the GPL license version 2 or any later version.
 '''
 


More information about the pypy-commit mailing list