[pypy-svn] r75182 - in pypy/branch/fast-forward: . lib-python py/_code pypy/annotation pypy/annotation/test pypy/doc pypy/jit/metainterp pypy/jit/metainterp/test pypy/module/_codecs pypy/module/cpyext pypy/module/cpyext/include pypy/module/cpyext/patches pypy/module/cpyext/test pypy/module/imp pypy/module/imp/test pypy/module/sys pypy/objspace/std pypy/rlib pypy/rlib/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/test pypy/tool/pytest pypy/tool/pytest/test

benjamin at codespeak.net benjamin at codespeak.net
Mon Jun 7 20:22:38 CEST 2010


Author: benjamin
Date: Mon Jun  7 20:22:34 2010
New Revision: 75182

Added:
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_translate.py
      - copied unchanged from r75181, pypy/trunk/pypy/module/cpyext/test/test_translate.py
Modified:
   pypy/branch/fast-forward/   (props changed)
   pypy/branch/fast-forward/lib-python/conftest.py
   pypy/branch/fast-forward/py/_code/source.py
   pypy/branch/fast-forward/pypy/annotation/binaryop.py
   pypy/branch/fast-forward/pypy/annotation/builtin.py
   pypy/branch/fast-forward/pypy/annotation/classdef.py
   pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py
   pypy/branch/fast-forward/pypy/doc/objspace.txt
   pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py
   pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/fast-forward/pypy/module/_codecs/interp_codecs.py
   pypy/branch/fast-forward/pypy/module/cpyext/api.py
   pypy/branch/fast-forward/pypy/module/cpyext/datetime.py
   pypy/branch/fast-forward/pypy/module/cpyext/include/Python.h
   pypy/branch/fast-forward/pypy/module/cpyext/include/datetime.h
   pypy/branch/fast-forward/pypy/module/cpyext/patches/boost.patch
   pypy/branch/fast-forward/pypy/module/cpyext/pyobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/sequence.py
   pypy/branch/fast-forward/pypy/module/cpyext/sliceobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/slotdefs.py
   pypy/branch/fast-forward/pypy/module/cpyext/stubs.py
   pypy/branch/fast-forward/pypy/module/cpyext/test/foo.c
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_datetime.py
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_longobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_sequence.py
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_sliceobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/test/test_typeobject.py
   pypy/branch/fast-forward/pypy/module/cpyext/typeobject.py
   pypy/branch/fast-forward/pypy/module/imp/importing.py
   pypy/branch/fast-forward/pypy/module/imp/test/test_import.py
   pypy/branch/fast-forward/pypy/module/sys/__init__.py
   pypy/branch/fast-forward/pypy/module/sys/interp_encoding.py
   pypy/branch/fast-forward/pypy/objspace/std/formatting.py
   pypy/branch/fast-forward/pypy/objspace/std/unicodetype.py
   pypy/branch/fast-forward/pypy/rlib/rarithmetic.py
   pypy/branch/fast-forward/pypy/rlib/test/test_rarithmetic.py
   pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py
   pypy/branch/fast-forward/pypy/rpython/rbuiltin.py
   pypy/branch/fast-forward/pypy/rpython/test/test_rbuiltin.py
   pypy/branch/fast-forward/pypy/tool/pytest/appsupport.py
   pypy/branch/fast-forward/pypy/tool/pytest/test/test_appsupport.py
Log:
merge from trunk

Modified: pypy/branch/fast-forward/lib-python/conftest.py
==============================================================================
--- pypy/branch/fast-forward/lib-python/conftest.py	(original)
+++ pypy/branch/fast-forward/lib-python/conftest.py	Mon Jun  7 20:22:34 2010
@@ -569,11 +569,14 @@
         return cache.get(name, None)
         
     def collect(self): 
+        we_are_in_modified = self.fspath == modregrtestdir
         l = []
-        for x in testmap:
+        for x in self.fspath.listdir():
             name = x.basename
             regrtest = self.get(name)
-            if regrtest is not None: 
+            if regrtest is not None:
+                if bool(we_are_in_modified) ^ regrtest.ismodified():
+                    continue
                 #if option.extracttests:  
                 #    l.append(InterceptedRunModule(name, self, regrtest))
                 #else:
@@ -581,7 +584,14 @@
         return l 
 
 def pytest_collect_directory(parent, path):
-    return RegrDirectory(path, parent)
+    # use RegrDirectory collector for both modified and unmodified tests
+    if path in (modregrtestdir, regrtestdir):
+        return RegrDirectory(path, parent)
+
+def pytest_ignore_collect(path):
+    # ignore all files - only RegrDirectory generates tests in lib-python
+    if path.check(file=1):
+        return True
 
 class RunFileExternal(py.test.collect.File):
     def __init__(self, name, parent, regrtest): 

Modified: pypy/branch/fast-forward/py/_code/source.py
==============================================================================
--- pypy/branch/fast-forward/py/_code/source.py	(original)
+++ pypy/branch/fast-forward/py/_code/source.py	Mon Jun  7 20:22:34 2010
@@ -17,8 +17,7 @@
     """ a immutable object holding a source code fragment,
         possibly deindenting it.
     """
-    _counter = 0
-
+    _compilecounter = 0
     def __init__(self, *parts, **kwargs):
         self.lines = lines = []
         de = kwargs.get('deindent', True)
@@ -197,12 +196,12 @@
             if _genframe is None:
                 _genframe = sys._getframe(1) # the caller
             fn,lineno = _genframe.f_code.co_filename, _genframe.f_lineno
+            base = "<%d-codegen " % self._compilecounter
+            self.__class__._compilecounter += 1
             if not filename:
-                filename = '<%d-codegen %s:%d>' % (self._counter, fn, lineno)
+                filename = base + '%s:%d>' % (fn, lineno)
             else:
-                filename = '<%d-codegen %r %s:%d>' % (self._counter, filename, fn, lineno)
-            self.__class__._counter += 1
-            
+                filename = base + '%r %s:%d>' % (filename, fn, lineno)
         source = "\n".join(self.lines) + '\n'
         try:
             co = cpy_compile(source, filename, mode, flag)
@@ -230,7 +229,6 @@
                 py.std.inspect.modulesbyfile[filename] = None
                 py.std.sys.modules[None] = m
                 m.__loader__ = 1
-            assert filename not in py.std.linecache.cache, filename
             py.std.linecache.cache[filename] = (1, None, lines, filename)
             return co
 

Modified: pypy/branch/fast-forward/pypy/annotation/binaryop.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/binaryop.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/binaryop.py	Mon Jun  7 20:22:34 2010
@@ -442,7 +442,7 @@
         return SomeUnicodeString()
 
 class __extend__(pairtype(SomeString, SomeUnicodeString),
-                 pairtype(SomeString, SomeUnicodeString)):
+                 pairtype(SomeUnicodeString, SomeString)):
     def mod((str, unistring)):
         raise NotImplementedError(
             "string formatting mixing strings and unicode not supported")

Modified: pypy/branch/fast-forward/pypy/annotation/builtin.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/builtin.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/builtin.py	Mon Jun  7 20:22:34 2010
@@ -272,6 +272,12 @@
 def OSError_init(s_self, *args):
     pass
 
+def UnicodeDecodeError_init(s_self, *args):
+    pass
+
+def UnicodeEncodeError_init(s_self, *args):
+    pass
+
 def WindowsError_init(s_self, *args):
     pass
 
@@ -390,6 +396,8 @@
 
 BUILTIN_ANALYZERS[getattr(OSError.__init__, 'im_func', OSError.__init__)] = (
     OSError_init)
+BUILTIN_ANALYZERS[getattr(UnicodeDecodeError.__init__, 'im_func', UnicodeDecodeError.__init__)] = UnicodeDecodeError_init
+BUILTIN_ANALYZERS[getattr(UnicodeEncodeError.__init__, 'im_func', UnicodeEncodeError.__init__)] = UnicodeEncodeError_init
 
 try:
     WindowsError

Modified: pypy/branch/fast-forward/pypy/annotation/classdef.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/classdef.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/classdef.py	Mon Jun  7 20:22:34 2010
@@ -3,7 +3,7 @@
 """
 from pypy.annotation.model import SomePBC, s_ImpossibleValue, unionof
 from pypy.annotation.model import SomeInteger, isdegenerated, SomeTuple,\
-     SomeString
+     SomeString, SomeUnicodeString
 from pypy.annotation import description
 
 
@@ -439,6 +439,16 @@
 
 FORCE_ATTRIBUTES_INTO_CLASSES = {
     OSError: {'errno': SomeInteger()},
+    UnicodeDecodeError: {'end': SomeInteger(),
+                         'start': SomeInteger(),
+                         'object': SomeString(),
+                         'encoding': SomeString(),
+                         'reason': SomeString()},
+    UnicodeEncodeError: {'end': SomeInteger(),
+                         'start': SomeInteger(),
+                         'object': SomeUnicodeString(),
+                         'encoding': SomeString(),
+                         'reason': SomeString()}
     }
 
 try:

Modified: pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py
==============================================================================
--- pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py	(original)
+++ pypy/branch/fast-forward/pypy/annotation/test/test_annrpython.py	Mon Jun  7 20:22:34 2010
@@ -3321,6 +3321,17 @@
         s = a.build_types(g, [int])
         assert a.bookkeeper.getdesc(f).getuniquegraph()
 
+    def test_unicode_decode_error(self):
+        def f():
+            try:
+                raise UnicodeDecodeError("x", "x", 0, 1, "reason")
+            except UnicodeDecodeError, ude:
+                return ude.end
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
 def g(n):
     return [0,1,2,n]
 

Modified: pypy/branch/fast-forward/pypy/doc/objspace.txt
==============================================================================
--- pypy/branch/fast-forward/pypy/doc/objspace.txt	(original)
+++ pypy/branch/fast-forward/pypy/doc/objspace.txt	Mon Jun  7 20:22:34 2010
@@ -552,7 +552,7 @@
 A number of options for configuration is here in `traceconfig.py`_.
 
 
-.. _`found here` : getting-started.html#tracing-bytecode-and-operations-on-objects
+.. _`found here` : getting-started-dev.html#tracing-bytecode-and-operations-on-objects
 .. _`Abstract Interpretation`: theory.html#abstract-interpretation
 .. _`traceconfig.py`: ../tool/traceconfig.py
 

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/optimizeopt.py	Mon Jun  7 20:22:34 2010
@@ -1066,7 +1066,7 @@
         return None
 
     def emitting_operation(self, op):
-        if op.has_no_side_effect():
+        if op.opnum != rop.CALL_PURE and op.has_no_side_effect():
             return
         if op.is_ovf():
             return
@@ -1079,6 +1079,7 @@
             return
         if (opnum == rop.CALL or
             opnum == rop.CALL_MAY_FORCE or
+            opnum == rop.CALL_PURE or
             opnum == rop.CALL_ASSEMBLER):
             if opnum == rop.CALL_ASSEMBLER:
                 effectinfo = None

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/pyjitpl.py	Mon Jun  7 20:22:34 2010
@@ -1719,7 +1719,8 @@
         self.history.record(rop.JUMP, exits, None)
         target_loop_token = compile.compile_new_bridge(self, loop_tokens,
                                                        self.resumekey)
-        assert target_loop_token is loop_tokens[0]
+        if target_loop_token is not loop_tokens[0]:
+            raise GiveUp
 
     def compile_exit_frame_with_exception(self, valuebox):
         self.gen_store_back_in_virtualizable()
@@ -1729,7 +1730,8 @@
         loop_tokens = sd.loop_tokens_exit_frame_with_exception_ref
         target_loop_token = compile.compile_new_bridge(self, loop_tokens,
                                                        self.resumekey)
-        assert target_loop_token is loop_tokens[0]
+        if target_loop_token is not loop_tokens[0]:
+            raise GiveUp
 
     def get_residual_args(self, specnodes, args):
         if specnodes is None:     # it is None only for tests

Modified: pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/fast-forward/pypy/jit/metainterp/test/test_optimizeopt.py	Mon Jun  7 20:22:34 2010
@@ -2586,6 +2586,16 @@
         '''
         self.optimize_loop(ops, 'Not, Not', ops)
 
+    def test_call_pure_invalidates_caches(self):
+        ops = '''
+        [p1, i1]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i3 = call_pure(p1, descr=plaincalldescr)
+        setfield_gc(p1, i3, descr=valuedescr)
+        jump(p1, i3)
+        '''
+        self.optimize_loop(ops, 'Not, Not', ops)        
+
     def test_vref_nonvirtual_nonescape(self):
         ops = """
         [p1]

Modified: pypy/branch/fast-forward/pypy/module/_codecs/interp_codecs.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_codecs/interp_codecs.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_codecs/interp_codecs.py	Mon Jun  7 20:22:34 2010
@@ -2,6 +2,7 @@
 from pypy.interpreter.gateway import ObjSpace, NoneNotWrapped, applevel
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.rlib.rstring import StringBuilder, UnicodeBuilder
+from pypy.rlib.objectmodel import we_are_translated
 
 class CodecState(object):
     def __init__(self, space):
@@ -52,6 +53,9 @@
                 return replace, newpos
         return unicode_call_errorhandler
 
+    def _freeze_(self):
+        assert not self.codec_search_path
+        return False
 
 def register_codec(space, w_search_function):
     """register(search_function)
@@ -75,6 +79,8 @@
     Looks up a codec tuple in the Python codec registry and returns
     a tuple of functions.
     """
+    assert not (space.config.translating and not we_are_translated()), \
+        "lookup_codec() should not be called during translation"
     state = space.fromcache(CodecState)
     normalized_encoding = encoding.replace(" ", "-").lower()    
     w_result = state.codec_search_cache.get(normalized_encoding, None)
@@ -215,11 +221,8 @@
     else:
         encoding = space.str_w(w_encoding)
     w_encoder = space.getitem(lookup_codec(space, encoding), space.wrap(0))
-    if space.is_true(w_encoder):
-        w_res = space.call_function(w_encoder, w_obj, space.wrap(errors))
-        return space.getitem(w_res, space.wrap(0))
-    else:
-        assert 0, "XXX, what to do here?"
+    w_res = space.call_function(w_encoder, w_obj, space.wrap(errors))
+    return space.getitem(w_res, space.wrap(0))
 encode.unwrap_spec = [ObjSpace, W_Root, W_Root, str]
 
 def buffer_encode(space, s, errors='strict'):

Modified: pypy/branch/fast-forward/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/api.py	Mon Jun  7 20:22:34 2010
@@ -11,6 +11,7 @@
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.translator.gensupp import NameManager
 from pypy.tool.udir import udir
 from pypy.translator import platform
 from pypy.module.cpyext.state import State
@@ -125,14 +126,18 @@
 # the error value specifed in the API.
 #
 
+cpyext_namespace = NameManager('cpyext_')
+
 class ApiFunction:
-    def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED):
+    def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED,
+                 c_name=None):
         self.argtypes = argtypes
         self.restype = restype
         self.functype = lltype.Ptr(lltype.FuncType(argtypes, restype))
         self.callable = callable
         if error is not _NOT_SPECIFIED:
             self.error_value = error
+        self.c_name = c_name
 
         # extract the signature from the (CPython-level) code object
         from pypy.interpreter import pycode
@@ -159,6 +164,8 @@
             wrapper = make_wrapper(space, self.callable)
             self._wrapper = wrapper
             wrapper.relax_sig_check = True
+            if self.c_name is not None:
+                wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
         return wrapper
 
 def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True):
@@ -182,11 +189,16 @@
 
     def decorate(func):
         func_name = func.func_name
-        api_function = ApiFunction(argtypes, restype, func, error)
+        if external:
+            c_name = None
+        else:
+            c_name = func_name
+        api_function = ApiFunction(argtypes, restype, func, error, c_name=c_name)
         func.api_func = api_function
 
-        assert func_name not in FUNCTIONS, "%s already registered" % func_name
-        assert func_name not in FUNCTIONS_STATIC
+        if external:
+            assert func_name not in FUNCTIONS, (
+                "%s already registered" % func_name)
 
         if error is _NOT_SPECIFIED:
             raise ValueError("function %s has no return value for exceptions"
@@ -261,8 +273,6 @@
         unwrapper_raise = make_unwrapper(False)
         if external:
             FUNCTIONS[func_name] = api_function
-        else:
-            FUNCTIONS_STATIC[func_name] = api_function
         INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests
         return unwrapper_raise # used in 'normal' RPython code.
     return decorate
@@ -277,7 +287,6 @@
 
 INTERPLEVEL_API = {}
 FUNCTIONS = {}
-FUNCTIONS_STATIC = {}
 SYMBOLS_C = [
     'Py_FatalError', 'PyOS_snprintf', 'PyOS_vsnprintf', 'PyArg_Parse',
     'PyArg_ParseTuple', 'PyArg_UnpackTuple', 'PyArg_ParseTupleAndKeywords',
@@ -439,6 +448,7 @@
 
 # Make the wrapper for the cases (1) and (2)
 def make_wrapper(space, callable):
+    "NOT_RPYTHON"
     names = callable.api_func.argnames
     argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes,
         [name.startswith("w_") for name in names])))
@@ -572,6 +582,7 @@
 # back into Pypy space functions
 # Do not call this more than once per process
 def build_bridge(space):
+    "NOT_RPYTHON"
     from pypy.module.cpyext.pyobject import make_ref
 
     export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS)
@@ -601,7 +612,10 @@
     for name, (typ, expr) in GLOBALS.iteritems():
         if "#" in name:
             continue
-        global_objects.append('%s %s = NULL;' % (typ, name))
+        if name.startswith('PyExc_'):
+            global_objects.append('%s %s;' % (typ[:-1], '_' + name))
+        else:
+            global_objects.append('%s %s = NULL;' % (typ, name))
     global_code = '\n'.join(global_objects)
 
     prologue = "#include <Python.h>\n"
@@ -621,7 +635,6 @@
     # load the bridge, and init structure
     import ctypes
     bridge = ctypes.CDLL(str(modulename), mode=ctypes.RTLD_GLOBAL)
-    pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI')
 
     # populate static data
     for name, (typ, expr) in GLOBALS.iteritems():
@@ -632,6 +645,9 @@
             isptr = False
         else:
             isptr = True
+        if name.startswith('PyExc_'):
+            isptr = False
+
         INTERPLEVEL_API[name] = w_obj
 
         name = name.replace('Py', 'PyPy')
@@ -640,8 +656,14 @@
             ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(make_ref(space, w_obj)),
                                     ctypes.c_void_p).value
         elif typ in ('PyObject*', 'PyTypeObject*'):
-            in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge,name)
-            py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll))
+            if name.startswith('PyPyExc_'):
+                # we already have the pointer
+                in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name)
+                py_obj = ll2ctypes.ctypes2lltype(PyObject, in_dll)
+            else:
+                # we have a structure, get its address
+                in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge, name)
+                py_obj = ll2ctypes.ctypes2lltype(PyObject, ctypes.pointer(in_dll))
             from pypy.module.cpyext.pyobject import (
                 track_reference, get_typedescr)
             w_type = space.type(w_obj)
@@ -654,8 +676,12 @@
         else:
             assert False, "Unknown static object: %s %s" % (typ, name)
 
+    pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI')
+
     # implement structure initialization code
     for name, func in FUNCTIONS.iteritems():
+        if name.startswith('cpyext_'): # XXX hack
+            continue
         pypyAPI[structindex[name]] = ctypes.cast(
             ll2ctypes.lltype2ctypes(func.get_llhelper(space)),
             ctypes.c_void_p)
@@ -666,6 +692,7 @@
     return modulename.new(ext='')
 
 def generate_macros(export_symbols, rename=True, do_deref=True):
+    "NOT_RPYTHON"
     pypy_macros = []
     renamed_symbols = []
     for name in export_symbols:
@@ -679,6 +706,8 @@
         if not rename:
             newname = name
         pypy_macros.append('#define %s %s' % (name, newname))
+        if name.startswith("PyExc_"):
+            pypy_macros.append('#define _%s _%s' % (name, newname))
         renamed_symbols.append(newname)
     if rename:
         export_symbols[:] = renamed_symbols
@@ -700,6 +729,7 @@
     pypy_macros_h.write('\n'.join(pypy_macros))
 
 def generate_decls_and_callbacks(db, export_symbols, api_struct=True):
+    "NOT_RPYTHON"
     # implement function callbacks and generate function decls
     functions = []
     pypy_decls = []
@@ -734,6 +764,8 @@
         if name.endswith('#'):
             name = name.replace("#", "")
             typ = typ.replace("*", "")
+        elif name.startswith('PyExc_'):
+            typ = 'PyObject*'
         pypy_decls.append('PyAPI_DATA(%s) %s;' % (typ, name))
 
     pypy_decls.append("#ifdef __cplusplus")
@@ -746,6 +778,7 @@
     return functions
 
 def build_eci(building_bridge, export_symbols, code):
+    "NOT_RPYTHON"
     # Build code and get pointer to the structure
     kwds = {}
     export_symbols_eci = export_symbols[:]
@@ -768,6 +801,9 @@
     for name, (typ, expr) in GLOBALS.iteritems():
         if name.endswith('#'):
             structs.append('%s %s;' % (typ[:-1], name[:-1]))
+        elif name.startswith('PyExc_'):
+            structs.append('extern PyTypeObject _%s;' % (name,))
+            structs.append('PyObject* %s = (PyObject*)&_%s;' % (name, name))
     struct_file.write('\n'.join(structs))
 
     eci = ExternalCompilationInfo(
@@ -793,6 +829,7 @@
 
 
 def setup_library(space):
+    "NOT_RPYTHON"
     from pypy.module.cpyext.pyobject import make_ref
 
     export_symbols = list(FUNCTIONS) + SYMBOLS_C + list(GLOBALS)
@@ -812,6 +849,8 @@
     # populate static data
     for name, (typ, expr) in GLOBALS.iteritems():
         name = name.replace("#", "")
+        if name.startswith('PyExc_'):
+            name = '_' + name
         from pypy.module import cpyext
         w_obj = eval(expr)
         struct_ptr = make_ref(space, w_obj)
@@ -822,8 +861,6 @@
     for name, func in FUNCTIONS.iteritems():
         deco = entrypoint("cpyext", func.argtypes, name, relax=True)
         deco(func.get_wrapper(space))
-    for name, func in FUNCTIONS_STATIC.iteritems():
-        func.get_wrapper(space).c_name = name
 
     setup_init_functions(eci)
     copy_header_files()

Modified: pypy/branch/fast-forward/pypy/module/cpyext/datetime.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/datetime.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/datetime.py	Mon Jun  7 20:22:34 2010
@@ -1,16 +1,220 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.pyobject import PyObject
-from pypy.module.cpyext.api import cpython_api
+from pypy.module.cpyext.api import (
+    cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields)
 from pypy.module.cpyext.import_ import PyImport_Import
+from pypy.interpreter.error import OperationError
+from pypy.tool.sourcetools import func_renamer
+
+# API import function
 
 @cpython_api([], lltype.Void)
-def PyDateTime_IMPORT(space):
+def _PyDateTime_Import(space):
     return
 
- at cpython_api([rffi.INT, rffi.INT, rffi.INT, rffi.INT], PyObject)
+PyDateTime_Date = PyObject
+PyDateTime_Time = PyObject
+PyDateTime_DateTime = PyObject
+
+PyDeltaObjectStruct = lltype.ForwardReference()
+cpython_struct("PyDateTime_Delta", PyObjectFields, PyDeltaObjectStruct)
+PyDateTime_Delta = lltype.Ptr(PyDeltaObjectStruct)
+
+# Check functions
+
+def make_check_function(func_name, type_name):
+    @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+    @func_renamer(func_name)
+    def check(space, w_obj):
+        try:
+            return space.is_true(
+                space.appexec([w_obj], """(obj):
+                    from datetime import %s as datatype
+                    return isinstance(obj, datatype)
+                    """ % (type_name,)))
+        except OperationError:
+            return 0
+
+    @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+    @func_renamer(func_name + "Exact")
+    def check_exact(space, w_obj):
+        try:
+            return space.is_true(
+                space.appexec([w_obj], """(obj):
+                    from datetime import %s as datatype
+                    return type(obj) is datatype
+                    """ % (type_name,)))
+        except OperationError:
+            return 0
+
+make_check_function("PyDateTime_Check", "datetime")
+make_check_function("PyDate_Check", "date")
+make_check_function("PyTime_Check", "time")
+make_check_function("PyDelta_Check", "timedelta")
+
+# Constructors
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
+def PyDate_FromDate(space, year, month, day):
+    """Return a datetime.date object with the specified year, month and day.
+    """
+    year = rffi.cast(lltype.Signed, year)
+    month = rffi.cast(lltype.Signed, month)
+    day = rffi.cast(lltype.Signed, day)
+    w_datetime = PyImport_Import(space, space.wrap("datetime"))
+    return space.call_method(
+        w_datetime, "date",
+        space.wrap(year), space.wrap(month), space.wrap(day))
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
 def PyTime_FromTime(space, hour, minute, second, usecond):
+    """Return a ``datetime.time`` object with the specified hour, minute, second and
+    microsecond."""
+    hour = rffi.cast(lltype.Signed, hour)
+    minute = rffi.cast(lltype.Signed, minute)
+    second = rffi.cast(lltype.Signed, second)
+    usecond = rffi.cast(lltype.Signed, usecond)
     w_datetime = PyImport_Import(space, space.wrap("datetime"))
     return space.call_method(
         w_datetime, "time",
         space.wrap(hour), space.wrap(minute), space.wrap(second),
         space.wrap(usecond))
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
+def PyDateTime_FromDateAndTime(space, year, month, day, hour, minute, second, usecond):
+    """Return a datetime.datetime object with the specified year, month, day, hour,
+    minute, second and microsecond.
+    """
+    year = rffi.cast(lltype.Signed, year)
+    month = rffi.cast(lltype.Signed, month)
+    day = rffi.cast(lltype.Signed, day)
+    hour = rffi.cast(lltype.Signed, hour)
+    minute = rffi.cast(lltype.Signed, minute)
+    second = rffi.cast(lltype.Signed, second)
+    usecond = rffi.cast(lltype.Signed, usecond)
+    w_datetime = PyImport_Import(space, space.wrap("datetime"))
+    return space.call_method(
+        w_datetime, "datetime",
+        space.wrap(year), space.wrap(month), space.wrap(day),
+        space.wrap(hour), space.wrap(minute), space.wrap(second),
+        space.wrap(usecond))
+    raise NotImplementedError
+
+ at cpython_api([PyObject], PyObject)
+def PyDateTime_FromTimestamp(space, w_args):
+    """Create and return a new datetime.datetime object given an argument tuple
+    suitable for passing to datetime.datetime.fromtimestamp().
+    """
+    w_datetime = PyImport_Import(space, space.wrap("datetime"))
+    w_type = space.getattr(w_datetime, space.wrap("datetime"))
+    w_method = space.getattr(w_type, space.wrap("fromtimestamp"))
+    return space.call(w_method, w_args)
+
+ at cpython_api([PyObject], PyObject)
+def PyDate_FromTimestamp(space, w_args):
+    """Create and return a new datetime.date object given an argument tuple
+    suitable for passing to datetime.date.fromtimestamp().
+    """
+    w_datetime = PyImport_Import(space, space.wrap("datetime"))
+    w_type = space.getattr(w_datetime, space.wrap("date"))
+    w_method = space.getattr(w_type, space.wrap("fromtimestamp"))
+    return space.call(w_method, w_args)
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
+def PyDelta_FromDSU(space, days, seconds, useconds):
+    """Return a datetime.timedelta object representing the given number of days,
+    seconds and microseconds.  Normalization is performed so that the resulting
+    number of microseconds and seconds lie in the ranges documented for
+    datetime.timedelta objects.
+    """
+    days = rffi.cast(lltype.Signed, days)
+    seconds = rffi.cast(lltype.Signed, seconds)
+    useconds = rffi.cast(lltype.Signed, useconds)
+    w_datetime = PyImport_Import(space, space.wrap("datetime"))
+    return space.call_method(
+        w_datetime, "timedelta",
+        space.wrap(days), space.wrap(seconds), space.wrap(useconds))
+
+# Accessors
+
+ at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_GET_YEAR(space, w_obj):
+    """Return the year, as a positive int.
+    """
+    return space.getattr(w_obj, space.wrap("year"))
+
+ at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_GET_MONTH(space, w_obj):
+    """Return the month, as an int from 1 through 12.
+    """
+    return space.getattr(w_obj, space.wrap("month"))
+
+ at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_GET_DAY(space, w_obj):
+    """Return the day, as an int from 1 through 31.
+    """
+    return space.getattr(w_obj, space.wrap("day"))
+
+ at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DATE_GET_HOUR(space, w_obj):
+    """Return the hour, as an int from 0 through 23.
+    """
+    return space.getattr(w_obj, space.wrap("hour"))
+
+ at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DATE_GET_MINUTE(space, w_obj):
+    """Return the minute, as an int from 0 through 59.
+    """
+    return space.getattr(w_obj, space.wrap("minute"))
+
+ at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DATE_GET_SECOND(space, w_obj):
+    """Return the second, as an int from 0 through 59.
+    """
+    return space.getattr(w_obj, space.wrap("second"))
+
+ at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
+    """Return the microsecond, as an int from 0 through 999999.
+    """
+    return space.getattr(w_obj, space.wrap("microsecond"))
+
+ at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_TIME_GET_HOUR(space, w_obj):
+    """Return the hour, as an int from 0 through 23.
+    """
+    return space.getattr(w_obj, space.wrap("hour"))
+
+ at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_TIME_GET_MINUTE(space, w_obj):
+    """Return the minute, as an int from 0 through 59.
+    """
+    return space.getattr(w_obj, space.wrap("minute"))
+
+ at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_TIME_GET_SECOND(space, w_obj):
+    """Return the second, as an int from 0 through 59.
+    """
+    return space.getattr(w_obj, space.wrap("second"))
+
+ at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
+    """Return the microsecond, as an int from 0 through 999999.
+    """
+    return space.getattr(w_obj, space.wrap("microsecond"))
+
+# XXX these functions are not present in the Python API
+# But it does not seem possible to expose a different structure
+# for types defined in a python module like lib/datetime.py.
+
+ at cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DELTA_GET_DAYS(space, w_obj):
+    return space.getattr(w_obj, space.wrap("days"))
+
+ at cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DELTA_GET_SECONDS(space, w_obj):
+    return space.getattr(w_obj, space.wrap("seconds"))
+
+ at cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+def PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
+    return space.getattr(w_obj, space.wrap("microseconds"))

Modified: pypy/branch/fast-forward/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/include/Python.h	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/include/Python.h	Mon Jun  7 20:22:34 2010
@@ -27,6 +27,7 @@
 # endif
 # define Py_LOCAL_INLINE(type) static __inline type __fastcall
 #endif
+#define DL_IMPORT(RTYPE) PyAPI_FUNC(RTYPE)
 
 #include <stdlib.h>
 
@@ -95,6 +96,7 @@
 #include "pycobject.h"
 #include "bufferobject.h"
 #include "sliceobject.h"
+#include "datetime.h"
 #include "pystate.h"
 
 // XXX This shouldn't be included here

Modified: pypy/branch/fast-forward/pypy/module/cpyext/include/datetime.h
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/include/datetime.h	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/include/datetime.h	Mon Jun  7 20:22:34 2010
@@ -0,0 +1,16 @@
+#ifndef DATETIME_H
+#define DATETIME_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PyDateTime_IMPORT _PyDateTime_Import()
+
+typedef struct {
+    PyObject_HEAD
+} PyDateTime_Delta;
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Modified: pypy/branch/fast-forward/pypy/module/cpyext/patches/boost.patch
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/patches/boost.patch	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/patches/boost.patch	Mon Jun  7 20:22:34 2010
@@ -1,16 +1,3 @@
-Index: libs/python/src/object/class.cpp
-===================================================================
---- libs/python/src/object/class.cpp	2009-11-13 01:40:01 +0100
-+++ libs/python/src/object/class.cpp	2010-06-02 23:25:08 +0200
-@@ -195,7 +195,7 @@
- 
- namespace objects
- {
--#if PY_VERSION_HEX < 0x03000000
-+#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION)
-   // XXX Not sure why this run into compiling error in Python 3
-   extern "C"
-   {
 Index: libs/python/src/object/function.cpp
 ===================================================================
 --- libs/python/src/object/function.cpp	2010-04-04 07:19:57 +0200
@@ -50,14 +37,21 @@
 ===================================================================
 --- tools/build/v2/user-config.jam	2008-07-15 15:53:41 +0200
 +++ tools/build/v2/user-config.jam	2010-06-02 23:46:13 +0200
-@@ -84,3 +84,9 @@
+@@ -84,3 +84,16 @@
  
  # Configure with an explicit installation prefix.
  # using qt : /usr/opt/qt ;
 +
++# -------------------
++# PyPy configuration.
++# -------------------
++
++PYPY_HOME = /home/amaury/trunk ;
++
 +using python : 2.5
-+             : /home/amaury/trunk/pypy/pypy-c 
-+             : /home/amaury/trunk/pypy/module/cpyext/include 
-+               /home/amaury/trunk/pypy/_interfaces
++             : $(PYPY_HOME)/pypy/pypy-c                # interpreter
++             : $(PYPY_HOME)/pypy/module/cpyext/include # include paths 
++               $(PYPY_HOME)/pypy/_interfaces
++             : $(PYPY_HOME)/pypy/_interfaces           # library path
 +             ;
 

Modified: pypy/branch/fast-forward/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/pyobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/pyobject.py	Mon Jun  7 20:22:34 2010
@@ -2,9 +2,9 @@
 
 from pypy.interpreter.baseobjspace import W_Root, SpaceCache
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, bootstrap_function, \
-     PyObject, PyObjectP, ADDR, CANNOT_FAIL, \
-     Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr
+from pypy.module.cpyext.api import (
+    cpython_api, bootstrap_function, PyObject, PyObjectP, ADDR,
+    CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr)
 from pypy.module.cpyext.state import State
 from pypy.objspace.std.typeobject import W_TypeObject
 from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -263,9 +263,9 @@
     Allocates a PyObject, and fills its fields with info from the given
     intepreter object.
     """
+    state = space.fromcache(RefcountState)
     w_type = space.type(w_obj)
     if w_type.is_cpytype():
-        state = space.fromcache(RefcountState)
         py_obj = state.get_from_lifeline(w_obj)
         if py_obj:
             Py_IncRef(space, py_obj)
@@ -274,7 +274,6 @@
     typedescr = get_typedescr(w_obj.typedef)
     py_obj = typedescr.allocate(space, w_type, itemcount=itemcount)
     if w_type.is_cpytype():
-        state = space.fromcache(RefcountState)
         state.set_lifeline(w_obj, py_obj)
     typedescr.attach(space, py_obj, w_obj)
     return py_obj
@@ -333,7 +332,7 @@
     # This reference is not yet a real interpreter object.
     # Realize it.
     ref_type = rffi.cast(PyObject, ref.c_ob_type)
-    if ref_type == ref:
+    if ref_type == ref: # recursion!
         raise InvalidPointerException(str(ref))
     w_type = from_ref(space, ref_type)
     assert isinstance(w_type, W_TypeObject)

Modified: pypy/branch/fast-forward/pypy/module/cpyext/sequence.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/sequence.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/sequence.py	Mon Jun  7 20:22:34 2010
@@ -6,6 +6,14 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.objspace.std import listobject, tupleobject
 
+ at cpython_api([PyObject, Py_ssize_t], PyObject)
+def PySequence_Repeat(space, w_obj, count):
+    """Return the result of repeating sequence object o count times, or NULL on
+    failure.  This is the equivalent of the Python expression o * count.
+    
+    This function used an int type for count. This might require
+    changes in your code for properly supporting 64-bit systems."""
+    return space.mul(w_obj, space.wrap(count))
 
 @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
 def PySequence_Check(space, w_obj):
@@ -91,6 +99,12 @@
     return space.getitem(w_obj, space.wrap(i))
 
 @cpython_api([PyObject], PyObject)
+def PySequence_List(space, w_obj):
+    """Return a list object with the same contents as the arbitrary sequence o.  The
+    returned list is guaranteed to be new."""
+    return space.call_function(space.w_list, w_obj)
+
+ at cpython_api([PyObject], PyObject)
 def PySequence_Tuple(space, w_obj):
     """Return a tuple object with the same contents as the arbitrary sequence o or
     NULL on failure.  If o is a tuple, a new reference will be returned,

Modified: pypy/branch/fast-forward/pypy/module/cpyext/sliceobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/sliceobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/sliceobject.py	Mon Jun  7 20:22:34 2010
@@ -56,6 +56,12 @@
     the same names.  Any of the values may be NULL, in which case the
     None will be used for the corresponding attribute.  Return NULL if
     the new object could not be allocated."""
+    if w_start is None:
+        w_start = space.w_None
+    if w_stop is None:
+        w_stop = space.w_None
+    if w_step is None:
+        w_step = space.w_None
     return W_SliceObject(w_start, w_stop, w_step)
 
 @cpython_api([PySliceObject, Py_ssize_t, Py_ssize_tP, Py_ssize_tP, Py_ssize_tP,

Modified: pypy/branch/fast-forward/pypy/module/cpyext/slotdefs.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/slotdefs.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/slotdefs.py	Mon Jun  7 20:22:34 2010
@@ -5,15 +5,17 @@
 from pypy.module.cpyext.typeobjectdefs import (
     unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
     getattrfunc, setattrofunc, lenfunc, ssizeargfunc, ssizessizeargfunc,
-    ssizeobjargproc, iternextfunc, initproc, richcmpfunc, hashfunc)
+    ssizeobjargproc, iternextfunc, initproc, richcmpfunc, hashfunc,
+    descrgetfunc, descrsetfunc)
 from pypy.module.cpyext.pyobject import from_ref
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.state import State
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.argument import Arguments
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.tool.sourcetools import func_with_new_name
-
+from pypy.rlib.objectmodel import specialize
+from pypy.tool.sourcetools import func_renamer
+from pypy.rpython.annlowlevel import llhelper
 
 # XXX: Also defined in object.h
 Py_LT = 0
@@ -39,7 +41,7 @@
     func_init = rffi.cast(initproc, func)
     res = generic_cpy_call(space, func_init, w_self, w_args, w_kwargs)
     if rffi.cast(lltype.Signed, res) == -1:
-        space.fromcache(State).check_and_raise_exception()
+        space.fromcache(State).check_and_raise_exception(always=True)
     return None
 
 def wrap_unaryfunc(space, w_self, w_args, func):
@@ -81,6 +83,44 @@
     if rffi.cast(lltype.Signed, res) == -1:
         space.fromcache(State).check_and_raise_exception(always=True)
 
+def wrap_descr_get(space, w_self, w_args, func):
+    func_target = rffi.cast(descrgetfunc, func)
+    args_w = space.fixedview(w_args)
+    if len(args_w) == 1:
+        w_obj, = args_w
+        w_type = None
+    elif len(args_w) == 2:
+        w_obj, w_type = args_w
+    else:
+        raise operationerrfmt(
+            space.w_TypeError,
+            "expected 1 or 2 arguments, got %d", len(args_w))
+    if w_obj is space.w_None:
+        w_obj = None
+    if w_type is space.w_None:
+        w_type = None
+    if w_obj is None and w_type is None:
+        raise OperationError(
+            space.w_TypeError,
+            space.wrap("__get__(None, None) is invalid"))
+    return generic_cpy_call(space, func_target, w_self, w_obj, w_type)
+
+def wrap_descr_set(space, w_self, w_args, func):
+    func_target = rffi.cast(descrsetfunc, func)
+    check_num_args(space, w_args, 2)
+    w_obj, w_value = space.fixedview(w_args)
+    res = generic_cpy_call(space, func_target, w_self, w_obj, w_value)
+    if rffi.cast(lltype.Signed, res) == -1:
+        space.fromcache(State).check_and_raise_exception(always=True)
+
+def wrap_descr_delete(space, w_self, w_args, func):
+    func_target = rffi.cast(descrsetfunc, func)
+    check_num_args(space, w_args, 1)
+    w_obj, = space.fixedview(w_args)
+    res = generic_cpy_call(space, func_target, w_self, w_obj, None)
+    if rffi.cast(lltype.Signed, res) == -1:
+        space.fromcache(State).check_and_raise_exception(always=True)
+
 def wrap_call(space, w_self, w_args, func, w_kwds):
     func_target = rffi.cast(ternaryfunc, func)
     return generic_cpy_call(space, func_target, w_self, w_args, w_kwds)
@@ -174,22 +214,64 @@
     return space.call(w_self, w_args, w_kwds)
 
 @cpython_api([PyObject], PyObject, external=False)
+def slot_tp_str(space, w_self):
+    return space.str(w_self)
+
+ at cpython_api([PyObject], PyObject, external=False)
 def slot_nb_int(space, w_self):
     return space.int(w_self)
 
- at cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, external=False)
-def slot_tp_setattro(space, w_self, w_name, w_value):
-    # XXX this is probably wrong when a subtype's tp_setattro
-    # delegates to PyType_Type.tp_setattro!
-    if w_value is not None:
-        space.setattr(w_self, w_name, w_value)
+from pypy.rlib.nonconst import NonConstant
+
+SLOTS = {}
+
+ at specialize.memo()
+def get_slot_tp_function(space, typedef, name):
+    key = (typedef, name)
+    try:
+        return SLOTS[key]
+    except KeyError:
+        ret = build_slot_tp_function(space, typedef, name)
+        SLOTS[key] = ret
+        return ret
+
+def build_slot_tp_function(space, typedef, name):
+    w_type = space.gettypeobject(typedef)
+
+    if name == 'tp_setattro':
+        setattr_fn = w_type.getdictvalue(space, '__setattr__')
+        delattr_fn = w_type.getdictvalue(space, '__delattr__')
+        if setattr_fn is None:
+            return
+
+        @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real,
+                     error=-1, external=True) # XXX should not be exported
+        @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,))
+        def slot_tp_setattro(space, w_self, w_name, w_value):
+            if w_value is not None:
+                space.call_function(setattr_fn, w_self, w_name, w_value)
+            else:
+                space.call_function(delattr_fn, w_self, w_name)
+            return 0
+        api_func = slot_tp_setattro.api_func
     else:
-        space.delattr(w_self, w_name)
-    return 0
+        return
+
+    return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
 
 PyWrapperFlag_KEYWORDS = 1
 
-# adopted from typeobject.c
+class TypeSlot:
+    def __init__(self, method_name, slot_name, function, wrapper1, wrapper2, doc):
+        self.method_name = method_name
+        self.slot_name = slot_name
+        self.slot_names = ("c_" + slot_name).split(".")
+        self.slot_func = function
+        self.wrapper_func = wrapper1
+        self.wrapper_func_kwds = wrapper2
+        self.doc = doc
+
+# adapted from typeobject.c
 def FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS):
     if WRAPPER is None:
         wrapper = None
@@ -201,23 +283,22 @@
         wrapper = wrap_getattr
 
     function = globals().get(FUNCTION, None)
-    slotname = ("c_" + SLOT).split(".")
     assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
     if FLAGS:
         if wrapper is Ellipsis:
+            @func_renamer(WRAPPER)
             def wrapper(space, w_self, w_args, func, w_kwds):
                 raise NotImplementedError("Wrapper for slot " + NAME)
-            wrapper = func_with_new_name(wrapper, WRAPPER)
         wrapper1 = None
         wrapper2 = wrapper
     else:
         if wrapper is Ellipsis:
+            @func_renamer(WRAPPER)
             def wrapper(space, w_self, w_args, func):
                 raise NotImplementedError("Wrapper for slot " + NAME)
-            wrapper = func_with_new_name(wrapper, WRAPPER)
         wrapper1 = wrapper
         wrapper2 = None
-    return (NAME, slotname, function, wrapper1, wrapper2, DOC)
+    return TypeSlot(NAME, SLOT, function, wrapper1, wrapper2, DOC)
 
 def TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
     return FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, 0)
@@ -470,7 +551,12 @@
 for regex, repl in slotdef_replacements:
     slotdefs_str = re.sub(regex, repl, slotdefs_str)
 
-slotdefs = unrolling_iterable(eval(slotdefs_str))
+slotdefs_for_tp_slots = unrolling_iterable(
+    [(x.method_name, x.slot_name, x.slot_names, x.slot_func)
+     for x in eval(slotdefs_str)])
+slotdefs_for_wrappers = unrolling_iterable(
+    [(x.method_name, x.slot_names, x.wrapper_func, x.wrapper_func_kwds, x.doc)
+     for x in eval(slotdefs_str)])
 
 if __name__ == "__main__":
     print slotdefs_str

Modified: pypy/branch/fast-forward/pypy/module/cpyext/stubs.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/stubs.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/stubs.py	Mon Jun  7 20:22:34 2010
@@ -23,7 +23,7 @@
 _inittab = lltype.Void
 PyThreadState = lltype.Void
 PyInterpreterState = lltype.Void
-PyOS_sighandler_t = lltype.Void
+#PyOS_sighandler_t = lltype.Void
 Py_UNICODE = lltype.Void
 PyCompilerFlags = lltype.Void
 _node = lltype.Void
@@ -574,62 +574,6 @@
     raise NotImplementedError
 
 @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyDate_Check(space, ob):
-    """Return true if ob is of type PyDateTime_DateType or a subtype of
-    PyDateTime_DateType.  ob must not be NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyDate_CheckExact(space, ob):
-    """Return true if ob is of type PyDateTime_DateType. ob must not be
-    NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_Check(space, ob):
-    """Return true if ob is of type PyDateTime_DateTimeType or a subtype of
-    PyDateTime_DateTimeType.  ob must not be NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_CheckExact(space, ob):
-    """Return true if ob is of type PyDateTime_DateTimeType. ob must not
-    be NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyTime_Check(space, ob):
-    """Return true if ob is of type PyDateTime_TimeType or a subtype of
-    PyDateTime_TimeType.  ob must not be NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyTime_CheckExact(space, ob):
-    """Return true if ob is of type PyDateTime_TimeType. ob must not be
-    NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyDelta_Check(space, ob):
-    """Return true if ob is of type PyDateTime_DeltaType or a subtype of
-    PyDateTime_DeltaType.  ob must not be NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyDelta_CheckExact(space, ob):
-    """Return true if ob is of type PyDateTime_DeltaType. ob must not be
-    NULL.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
 def PyTZInfo_Check(space, ob):
     """Return true if ob is of type PyDateTime_TZInfoType or a subtype of
     PyDateTime_TZInfoType.  ob must not be NULL.
@@ -643,108 +587,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDate_FromDate(space, year, month, day):
-    """Return a datetime.date object with the specified year, month and day.
-    """
-    raise NotImplementedError
-
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDateTime_FromDateAndTime(space, year, month, day, hour, minute, second, usecond):
-    """Return a datetime.datetime object with the specified year, month, day, hour,
-    minute, second and microsecond.
-    """
-    raise NotImplementedError
-
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real], PyObject)
-def PyDelta_FromDSU(space, days, seconds, useconds):
-    """Return a datetime.timedelta object representing the given number of days,
-    seconds and microseconds.  Normalization is performed so that the resulting
-    number of microseconds and seconds lie in the ranges documented for
-    datetime.timedelta objects.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_YEAR(space, o):
-    """Return the year, as a positive int.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_MONTH(space, o):
-    """Return the month, as an int from 1 through 12.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_DAY(space, o):
-    """Return the day, as an int from 1 through 31.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_HOUR(space, o):
-    """Return the hour, as an int from 0 through 23.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_MINUTE(space, o):
-    """Return the minute, as an int from 0 through 59.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_SECOND(space, o):
-    """Return the second, as an int from 0 through 59.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_MICROSECOND(space, o):
-    """Return the microsecond, as an int from 0 through 999999.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_HOUR(space, o):
-    """Return the hour, as an int from 0 through 23.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_MINUTE(space, o):
-    """Return the minute, as an int from 0 through 59.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_SECOND(space, o):
-    """Return the second, as an int from 0 through 59.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_MICROSECOND(space, o):
-    """Return the microsecond, as an int from 0 through 999999.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], PyObject)
-def PyDateTime_FromTimestamp(space, args):
-    """Create and return a new datetime.datetime object given an argument tuple
-    suitable for passing to datetime.datetime.fromtimestamp().
-    """
-    raise NotImplementedError
-
- at cpython_api([PyObject], PyObject)
-def PyDate_FromTimestamp(space, args):
-    """Create and return a new datetime.date object given an argument tuple
-    suitable for passing to datetime.date.fromtimestamp().
-    """
-    raise NotImplementedError
-
 @cpython_api([PyTypeObjectPtr, PyGetSetDef], PyObject)
 def PyDescr_NewGetSet(space, type, getset):
     raise NotImplementedError
@@ -2363,9 +2205,7 @@
 
 @cpython_api([PyObject], PyObject)
 def PyObject_Dir(space, o):
-    """This is equivalent to the Python expression dir(o), returning a (possibly
-    empty) list of strings appropriate for the object argument, or NULL if there
-    was an error.  If the argument is NULL, this is like the Python dir(),
+    """This is equivalent to the Python expression dir(o), returning a (possibly empty) list of strings appropriate for the object argument, or NULL if there was an error.  If the argument is NULL, this is like the Python dir(),
     returning the names of the current locals; in this case, if no execution frame
     is active then NULL is returned but PyErr_Occurred() will return false."""
     raise NotImplementedError
@@ -2403,15 +2243,6 @@
     func."""
     raise NotImplementedError
 
- at cpython_api([PyObject, Py_ssize_t], PyObject)
-def PySequence_Repeat(space, o, count):
-    """Return the result of repeating sequence object o count times, or NULL on
-    failure.  This is the equivalent of the Python expression o * count.
-    
-    This function used an int type for count. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject], PyObject)
 def PySequence_InPlaceConcat(space, o1, o2):
     """Return the concatenation of o1 and o2 on success, and NULL on failure.
@@ -2474,12 +2305,6 @@
     in your code for properly supporting 64-bit systems."""
     raise NotImplementedError
 
- at cpython_api([PyObject], PyObject)
-def PySequence_List(space, o):
-    """Return a list object with the same contents as the arbitrary sequence o.  The
-    returned list is guaranteed to be new."""
-    raise NotImplementedError
-
 @cpython_api([PyObject], PyObjectP, error=lltype.nullptr(PyObjectP.TO))
 def PySequence_Fast_ITEMS(space, o):
     """Return the underlying array of PyObject pointers.  Assumes that o was returned

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/foo.c	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/foo.c	Mon Jun  7 20:22:34 2010
@@ -483,6 +483,90 @@
     0           /*tp_weaklist*/
 };
 
+PyObject * prop_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+    if (obj == NULL)
+	obj = Py_None;
+    if (type == NULL)
+	type = Py_None;
+
+    return PyTuple_Pack(3, self, obj, type);
+}
+
+int prop_descr_set(PyObject *self, PyObject *obj, PyObject *value)
+{
+    int res;
+    if (value != NULL) {
+	PyObject *result = PyTuple_Pack(2, self, value);
+	res = PyObject_SetAttrString(obj, "y", result);
+	Py_DECREF(result);
+    }
+    else {
+	res = PyObject_SetAttrString(obj, "z", self);
+    }
+    return res;
+}
+
+
+PyTypeObject SimplePropertyType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "foo.Property",
+    sizeof(PyObject),
+    0,
+    0,          /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+
+    0,          /*tp_call*/
+    0,          /*tp_str*/
+    0,          /*tp_getattro*/
+    0,          /*tp_setattro*/
+    0,          /*tp_as_buffer*/
+
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    0,          /*tp_doc*/
+
+    0,          /*tp_traverse*/
+    0,          /*tp_clear*/
+
+    0,          /*tp_richcompare*/
+    0,          /*tp_weaklistoffset*/
+
+    0,          /*tp_iter*/
+    0,          /*tp_iternext*/
+
+    /* Attribute descriptor and subclassing stuff */
+
+    0,          /*tp_methods*/
+    0,          /*tp_members*/
+    0,          /*tp_getset*/
+    0,          /*tp_base*/
+    0,          /*tp_dict*/
+
+    prop_descr_get, /*tp_descr_get*/
+    prop_descr_set, /*tp_descr_set*/
+    0,          /*tp_dictoffset*/
+
+    0,          /*tp_init*/
+    0,          /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
+    0,          /*tp_new*/
+    0,          /*tp_free  Low-level free-memory routine */
+    0,          /*tp_is_gc For PyObject_IS_GC */
+    0,          /*tp_bases*/
+    0,          /*tp_mro method resolution order */
+    0,          /*tp_cache*/
+    0,          /*tp_subclasses*/
+    0           /*tp_weaklist*/
+};
+
 
 /* Initialize this module. */
 
@@ -506,6 +590,8 @@
         return;
     if (PyType_Ready(&InitErrType) < 0)
         return;
+    if (PyType_Ready(&SimplePropertyType) < 0)
+	return;
     m = Py_InitModule("foo", foo_functions);
     if (m == NULL)
         return;
@@ -522,4 +608,6 @@
         return;
     if (PyDict_SetItemString(d, "InitErrType", (PyObject *) &InitErrType) < 0)
         return;
+    if (PyDict_SetItemString(d, "Property", (PyObject *) &SimplePropertyType) < 0)
+        return;
 }

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/test_datetime.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/test_datetime.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/test_datetime.py	Mon Jun  7 20:22:34 2010
@@ -1,7 +1,81 @@
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 from pypy.module.cpyext.test.test_api import BaseApiTest
+import datetime
 
 class TestDatetime(BaseApiTest):
+    def test_date(self, space, api):
+        w_date = api.PyDate_FromDate(2010, 06, 03)
+        assert space.unwrap(space.str(w_date)) == '2010-06-03'
+
+        assert api.PyDate_Check(w_date)
+        assert api.PyDate_CheckExact(w_date)
+
+        assert space.unwrap(space.newtuple([
+            api.PyDateTime_GET_YEAR(w_date),
+            api.PyDateTime_GET_MONTH(w_date),
+            api.PyDateTime_GET_DAY(w_date)])) == (
+            2010, 06, 03)
+
     def test_time(self, space, api):
         w_time = api.PyTime_FromTime(23, 15, 40, 123456)
         assert space.unwrap(space.str(w_time)) == '23:15:40.123456'
+
+        assert api.PyTime_Check(w_time)
+        assert api.PyTime_CheckExact(w_time)
+
+        assert space.unwrap(space.newtuple([
+            api.PyDateTime_TIME_GET_HOUR(w_time),
+            api.PyDateTime_TIME_GET_MINUTE(w_time),
+            api.PyDateTime_TIME_GET_SECOND(w_time),
+            api.PyDateTime_TIME_GET_MICROSECOND(w_time)])) == (
+            23, 15, 40, 123456)
+
+    def test_datetime(self, space, api):
+        w_date = api.PyDateTime_FromDateAndTime(
+            2010, 06, 03, 23, 15, 40, 123456)
+        assert space.unwrap(space.str(w_date)) == '2010-06-03 23:15:40.123456'
+
+        assert api.PyDateTime_Check(w_date)
+        assert api.PyDateTime_CheckExact(w_date)
+        assert api.PyDate_Check(w_date)
+        assert not api.PyDate_CheckExact(w_date)
+
+        assert space.unwrap(space.newtuple([
+            api.PyDateTime_GET_YEAR(w_date),
+            api.PyDateTime_GET_MONTH(w_date),
+            api.PyDateTime_GET_DAY(w_date),
+            api.PyDateTime_DATE_GET_HOUR(w_date),
+            api.PyDateTime_DATE_GET_MINUTE(w_date),
+            api.PyDateTime_DATE_GET_SECOND(w_date),
+            api.PyDateTime_DATE_GET_MICROSECOND(w_date)])) == (
+            2010, 06, 03, 23, 15, 40, 123456)
+
+    def test_delta(self, space, api):
+        w_delta = space.appexec(
+            [space.wrap(3), space.wrap(15)], """(days, seconds):
+            from datetime import timedelta
+            return timedelta(days, seconds)
+        """)
+        assert api.PyDelta_Check(w_delta)
+        assert api.PyDelta_CheckExact(w_delta)
+
+        w_delta = api.PyDelta_FromDSU(10, 20, 30)
+        assert api.PyDelta_Check(w_delta)
+        assert api.PyDelta_CheckExact(w_delta)
+
+        assert space.unwrap(space.newtuple([
+            api.PyDateTime_DELTA_GET_DAYS(w_delta),
+            api.PyDateTime_DELTA_GET_SECONDS(w_delta),
+            api.PyDateTime_DELTA_GET_MICROSECONDS(w_delta)])) == (
+            10, 20, 30)
+
+    def test_fromtimestamp(self, space, api):
+        w_args = space.wrap((0,))
+        w_date = api.PyDate_FromTimestamp(w_args)
+        date = datetime.date.fromtimestamp(0)
+        assert space.unwrap(space.str(w_date)) == str(date)
+
+        w_args = space.wrap((0,))
+        w_date = api.PyDateTime_FromTimestamp(w_args)
+        date = datetime.datetime.fromtimestamp(0)
+        assert space.unwrap(space.str(w_date)) == str(date)

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/test_longobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/test_longobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/test_longobject.py	Mon Jun  7 20:22:34 2010
@@ -76,7 +76,8 @@
              """
                  return PyLong_FromUnsignedLong((unsigned long)-1);
              """)])
-        assert module.from_unsignedlong() == (1<<32) - 1
+        import sys
+        assert module.from_unsignedlong() == 2 * sys.maxint + 1
 
     def test_fromlonglong(self):
         module = self.import_extension('foo', [

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/test_sequence.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/test_sequence.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/test_sequence.py	Mon Jun  7 20:22:34 2010
@@ -8,7 +8,7 @@
     def test_sequence(self, space, api):
         w_t = space.wrap((1, 2, 3, 4))
         assert api.PySequence_Fast(w_t, "message") is w_t
-        w_l = space.wrap((1, 2, 3, 4))
+        w_l = space.wrap([1, 2, 3, 4])
         assert api.PySequence_Fast(w_l, "message") is w_l
 
         assert space.int_w(api.PySequence_Fast_GET_ITEM(w_l, 1)) == 2
@@ -23,6 +23,19 @@
         assert space.type(w_seq) is space.w_tuple
         assert sorted(space.unwrap(w_seq)) == [1, 2, 3, 4]
 
+        w_seq = api.PySequence_List(w_set)
+        assert space.type(w_seq) is space.w_list
+        assert sorted(space.unwrap(w_seq)) == [1, 2, 3, 4]
+
+    def test_repeat(self, space, api):
+        def test(seq, count):
+            w_seq = space.wrap(seq)
+            w_repeated = api.PySequence_Repeat(w_seq, count)
+            assert space.eq_w(w_repeated, space.wrap(seq * count))
+
+        test((1, 2, 3, 4), 3)
+        test([1, 2, 3, 4], 3)
+
     def test_concat(self, space, api):
         w_t1 = space.wrap(range(4))
         w_t2 = space.wrap(range(4, 8))

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/test_sliceobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/test_sliceobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/test_sliceobject.py	Mon Jun  7 20:22:34 2010
@@ -43,3 +43,12 @@
             ])
         s = slice(10, 20, 30)
         assert module.clone(s) == s
+
+    def test_nulls(self):
+        module = self.import_extension('foo', [
+            ("nullslice", "METH_NOARGS",
+             """
+                 return PySlice_New(NULL, NULL, NULL);
+             """),
+            ])
+        assert module.nullslice() == slice(None, None, None)

Modified: pypy/branch/fast-forward/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/test/test_typeobject.py	Mon Jun  7 20:22:34 2010
@@ -192,6 +192,41 @@
         assert d[cmpr] == 72
         assert d[3] == 72
 
+    def test_descriptor(self):
+        module = self.import_module("foo")
+        prop = module.Property()
+        class C(object):
+            x = prop
+        obj = C()
+        assert obj.x == (prop, obj, C)
+        assert C.x == (prop, None, C)
+
+        obj.x = 2
+        assert obj.y == (prop, 2)
+        del obj.x
+        assert obj.z == prop
+
+    def test_tp_dict(self):
+        foo = self.import_module("foo")
+        module = self.import_extension('test', [
+           ("read_tp_dict", "METH_O",
+            '''
+                 PyObject *method;
+                 if (!args->ob_type->tp_dict)
+                 {
+                     PyErr_SetNone(PyExc_ValueError);
+                     return NULL;
+                 }
+                 method = PyDict_GetItemString(
+                     args->ob_type->tp_dict, "copy");
+                 Py_INCREF(method);
+                 return method;
+             '''
+             )
+            ])
+        obj = foo.new()
+        assert module.read_tp_dict(obj) == foo.fooType.copy
+
 
 class TestTypes(BaseApiTest):
     def test_type_attributes(self, space, api):
@@ -240,11 +275,17 @@
                      PyErr_SetString(PyExc_ValueError, "missing tp_setattro");
                      return NULL;
                  }
+                 if (args->ob_type->tp_setattro ==
+                     args->ob_type->tp_base->tp_setattro)
+                 {
+                     PyErr_SetString(PyExc_ValueError, "recursive tp_setattro");
+                     return NULL;
+                 }
                  Py_RETURN_TRUE;
              '''
              )
             ])
-        assert module.test_type(None)
+        assert module.test_type(type(None))
 
     def test_nb_int(self):
         module = self.import_extension('foo', [
@@ -283,3 +324,21 @@
             def __call__(self, *args):
                 return args
         assert module.tp_call(C(), ('x', 2)) == ('x', 2)
+
+    def test_tp_str(self):
+        module = self.import_extension('foo', [
+           ("tp_str", "METH_O",
+            '''
+                 if (!args->ob_type->tp_str)
+                 {
+                     PyErr_SetNone(PyExc_ValueError);
+                     return NULL;
+                 }
+                 return args->ob_type->tp_str(args);
+             '''
+             )
+            ])
+        class C:
+            def __str__(self):
+                return "text"
+        assert module.tp_str(C()) == "text"

Modified: pypy/branch/fast-forward/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/fast-forward/pypy/module/cpyext/typeobject.py	Mon Jun  7 20:22:34 2010
@@ -25,7 +25,8 @@
 from pypy.module.cpyext.typeobjectdefs import (
     PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
     PyNumberMethods)
-from pypy.module.cpyext.slotdefs import slotdefs
+from pypy.module.cpyext.slotdefs import (
+    slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
 from pypy.interpreter.error import OperationError
 from pypy.rlib.rstring import rsplit
 from pypy.rlib.objectmodel import specialize
@@ -102,48 +103,60 @@
 
 def update_all_slots(space, w_type, pto):
     #  XXX fill slots in pto
-    for method_name, slot_name, slot_func, _, _, _ in slotdefs:
+
+    typedef = w_type.instancetypedef
+    for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
         w_descr = w_type.lookup(method_name)
         if w_descr is None:
             # XXX special case iternext
             continue
-        if slot_func is None:
+
+        slot_func_helper = None
+
+        if slot_func is None and typedef is not None:
+            get_slot = get_slot_tp_function(space, typedef, slot_name)
+            if get_slot:
+                slot_func_helper = get_slot()
+        elif slot_func:
+            slot_func_helper = llhelper(slot_func.api_func.functype,
+                                        slot_func.api_func.get_wrapper(space))
+
+        if slot_func_helper is None:
             if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
                 os.write(2, method_name + " defined by the type but no slot function defined!\n")
             continue
-        slot_func_helper = llhelper(slot_func.api_func.functype,
-                slot_func.api_func.get_wrapper(space))
+
         # XXX special case wrapper-functions and use a "specific" slot func
 
-        if len(slot_name) == 1:
-            setattr(pto, slot_name[0], slot_func_helper)
+        if len(slot_names) == 1:
+            setattr(pto, slot_names[0], slot_func_helper)
         else:
-            assert len(slot_name) == 2
-            struct = getattr(pto, slot_name[0])
+            assert len(slot_names) == 2
+            struct = getattr(pto, slot_names[0])
             if not struct:
-                if slot_name[0] == 'c_tp_as_number':
+                if slot_names[0] == 'c_tp_as_number':
                     STRUCT_TYPE = PyNumberMethods
                 else:
                     raise AssertionError(
-                        "Structure not allocated: %s" % (slot_name[0],))
+                        "Structure not allocated: %s" % (slot_names[0],))
                 struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
-                setattr(pto, slot_name[0], struct)
+                setattr(pto, slot_names[0], struct)
 
-            setattr(struct, slot_name[1], slot_func_helper)
+            setattr(struct, slot_names[1], slot_func_helper)
 
 def add_operators(space, dict_w, pto):
     # XXX support PyObject_HashNotImplemented
-    for method_name, slot_name, _, wrapper_func, wrapper_func_kwds, doc in slotdefs:
+    for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
         if method_name in dict_w:
             continue
-        if len(slot_name) == 1:
-            func = getattr(pto, slot_name[0])
+        if len(slot_names) == 1:
+            func = getattr(pto, slot_names[0])
         else:
-            assert len(slot_name) == 2
-            struct = getattr(pto, slot_name[0])
+            assert len(slot_names) == 2
+            struct = getattr(pto, slot_names[0])
             if not struct:
                 continue
-            func = getattr(struct, slot_name[1])
+            func = getattr(struct, slot_names[1])
         func_voidp = rffi.cast(rffi.VOIDP_real, func)
         if not func:
             continue
@@ -363,12 +376,13 @@
 
 @cpython_api([PyObject], lltype.Void, external=False)
 def type_dealloc(space, obj):
+    from pypy.module.cpyext.object import PyObject_dealloc
     obj_pto = rffi.cast(PyTypeObjectPtr, obj)
-    type_pto = obj.c_ob_type
     base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
     Py_DecRef(space, obj_pto.c_tp_bases)
     Py_DecRef(space, obj_pto.c_tp_mro)
     Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython
+    Py_DecRef(space, obj_pto.c_tp_dict)
     if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
         if obj_pto.c_tp_as_buffer:
             lltype.free(obj_pto.c_tp_as_buffer, flavor='raw')
@@ -376,11 +390,7 @@
             lltype.free(obj_pto.c_tp_as_number, flavor='raw')
         Py_DecRef(space, base_pyo)
         rffi.free_charp(obj_pto.c_tp_name)
-        obj_pto_voidp = rffi.cast(rffi.VOIDP_real, obj_pto)
-        generic_cpy_call(space, type_pto.c_tp_free, obj_pto_voidp)
-        if type_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
-            pto = rffi.cast(PyObject, type_pto)
-            Py_DecRef(space, pto)
+        PyObject_dealloc(space, obj)
 
 
 def type_attach(space, py_obj, w_type):
@@ -494,6 +504,8 @@
         # XXX check for correct GC flags!
         if not pto.c_tp_free:
             pto.c_tp_free = base.c_tp_free
+        if not pto.c_tp_setattro:
+            pto.c_tp_setattro = base.c_tp_setattro
     finally:
         Py_DecRef(space, base_pyo)
 
@@ -532,8 +544,6 @@
     """
     Sets up tp_bases, necessary before creating the interpreter type.
     """
-    pto.c_tp_dict = lltype.nullptr(PyObject.TO) # not supported
-
     base = pto.c_tp_base
     base_pyo = rffi.cast(PyObject, pto.c_tp_base)
     if base and not base.c_tp_flags & Py_TPFLAGS_READY:
@@ -558,6 +568,16 @@
     for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
         inherit_slots(space, pto, w_base)
 
+    if not pto.c_tp_setattro:
+        from pypy.module.cpyext.object import PyObject_GenericSetAttr
+        pto.c_tp_setattro = llhelper(
+            PyObject_GenericSetAttr.api_func.functype,
+            PyObject_GenericSetAttr.api_func.get_wrapper(space))
+
+    if w_obj.is_cpytype():
+        Py_DecRef(space, pto.c_tp_dict)
+        pto.c_tp_dict = make_ref(space, w_obj.getdict())
+
 @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
 def PyType_IsSubtype(space, a, b):
     """Return true if a is a subtype of b.

Modified: pypy/branch/fast-forward/pypy/module/imp/importing.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/imp/importing.py	(original)
+++ pypy/branch/fast-forward/pypy/module/imp/importing.py	Mon Jun  7 20:22:34 2010
@@ -145,7 +145,7 @@
         msg = "Attempted relative import in non-package"
         raise OperationError(space.w_ValueError, w(msg))
     w_mod = absolute_import_try(space, modulename, 0, fromlist_w)
-    if w_mod is None and not space.is_w(w_mod, space.w_None):
+    if w_mod is None or space.is_w(w_mod, space.w_None):
         w_mod = absolute_import(space, modulename, 0, fromlist_w, tentative=0)
     if rel_modulename is not None:
         space.setitem(space.sys.get('modules'), w(rel_modulename), space.w_None)
@@ -178,13 +178,11 @@
     else:
         level = 0
         first = None
-        while last_dot != -1:
-            assert last_dot >= 0 # bah
+        while last_dot >= 0:
             last_dot = modulename.find('.', last_dot + 1)
-            if last_dot == -1:
+            if last_dot < 0:
                 w_mod = check_sys_modules_w(space, modulename)
             else:
-                assert last_dot >= 0
                 w_mod = check_sys_modules_w(space, modulename[:last_dot])
             if w_mod is None or space.is_w(w_mod, space.w_None):
                 return None

Modified: pypy/branch/fast-forward/pypy/module/imp/test/test_import.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/imp/test/test_import.py	(original)
+++ pypy/branch/fast-forward/pypy/module/imp/test/test_import.py	Mon Jun  7 20:22:34 2010
@@ -457,6 +457,16 @@
     def test_reload_infinite(self):
         import infinite_reload
 
+    def test_explicitly_missing(self):
+        import sys
+        sys.modules['foobarbazmod'] = None
+        try:
+            import foobarbazmod
+            assert False, "should have failed, got instead %r" % (
+                foobarbazmod,)
+        except ImportError:
+            pass
+
 def _getlong(data):
     x = marshal.dumps(data)
     return x[-4:]

Modified: pypy/branch/fast-forward/pypy/module/sys/__init__.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/sys/__init__.py	(original)
+++ pypy/branch/fast-forward/pypy/module/sys/__init__.py	Mon Jun  7 20:22:34 2010
@@ -1,5 +1,6 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from pypy.interpreter.error import OperationError
+from pypy.rlib.objectmodel import we_are_translated
 import sys
 
 class Module(MixedModule):
@@ -95,8 +96,12 @@
         self.space.setitem(w_modules, w_name, w_module)
 
     def startup(self, space):
-        from pypy.module.sys.interp_encoding import _getfilesystemencoding
-        self.filesystemencoding = _getfilesystemencoding(space)
+        if space.config.translating and not we_are_translated():
+            # don't get the filesystemencoding at translation time
+            assert self.filesystemencoding is None
+        else:
+            from pypy.module.sys.interp_encoding import _getfilesystemencoding
+            self.filesystemencoding = _getfilesystemencoding(space)
 
     def getmodule(self, name): 
         space = self.space

Modified: pypy/branch/fast-forward/pypy/module/sys/interp_encoding.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/sys/interp_encoding.py	(original)
+++ pypy/branch/fast-forward/pypy/module/sys/interp_encoding.py	Mon Jun  7 20:22:34 2010
@@ -1,5 +1,6 @@
 import sys
 from pypy.rlib import rlocale
+from pypy.rlib.objectmodel import we_are_translated
 
 def getdefaultencoding(space):
     """Return the current default string encoding used by the Unicode 
@@ -18,6 +19,8 @@
     space.sys.defaultencoding = encoding
 
 def get_w_default_encoder(space):
+    assert not (space.config.translating and not we_are_translated()), \
+        "get_w_default_encoder() should not be called during translation"
     w_encoding = space.wrap(space.sys.defaultencoding)
     mod = space.getbuiltinmodule("_codecs")
     w_lookup = space.getattr(mod, space.wrap("lookup"))
@@ -40,6 +43,8 @@
         rlocale.setlocale(rlocale.LC_CTYPE, "")
         loc_codeset = rlocale.nl_langinfo(rlocale.CODESET)
         if loc_codeset:
+            if loc_codeset == 'ANSI_X3.4-1968':
+                loc_codeset = 'ascii'
             codecmod = space.getbuiltinmodule('_codecs')
             w_res = space.call_function(space.getattr(codecmod,
                                                       space.wrap('lookup')),

Modified: pypy/branch/fast-forward/pypy/objspace/std/formatting.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/formatting.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/formatting.py	Mon Jun  7 20:22:34 2010
@@ -474,12 +474,6 @@
     [_name[-1] for _name in dir(StringFormatter)
                if len(_name) == 5 and _name.startswith('fmt_')])
 
-def is_list_of_chars_or_unichars(ann, bk):
-    from pypy.annotation.model import SomeChar, SomeUnicodeCodePoint
-    if not isinstance(ann.listdef.listitem.s_value,
-                      (SomeChar, SomeUnicodeCodePoint)):
-        raise TypeError("Formatter should return as a result a list of chars or unichars, otherwise we miss important optimization")
-
 def format(space, w_fmt, values_w, w_valuedict=None, do_unicode=False):
     "Entry point"
     if not do_unicode:

Modified: pypy/branch/fast-forward/pypy/objspace/std/unicodetype.py
==============================================================================
--- pypy/branch/fast-forward/pypy/objspace/std/unicodetype.py	(original)
+++ pypy/branch/fast-forward/pypy/objspace/std/unicodetype.py	Mon Jun  7 20:22:34 2010
@@ -3,6 +3,8 @@
 from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
 from pypy.objspace.std.register_all import register_all
 from pypy.objspace.std.basestringtype import basestring_typedef
+from pypy.rlib.runicode import str_decode_utf_8, str_decode_ascii,\
+     unicode_encode_utf_8, unicode_encode_ascii
 
 from sys import maxint
 
@@ -185,13 +187,27 @@
     return encoding, errors
 
 def encode_object(space, w_object, encoding, errors):
-    # XXX write down shortcuts for performance for common encodings,
-    #     just like CPython
     if encoding is None:
         # Get the encoder functions as a wrapped object.
         # This lookup is cached.
         w_encoder = space.sys.get_w_default_encoder()
     else:
+        if errors is None or errors == 'strict':
+            try:
+                if encoding == 'ascii':
+                    u = space.unicode_w(w_object)
+                    return space.wrap(unicode_encode_ascii(u, len(u), None))
+                if encoding == 'utf-8':
+                    u = space.unicode_w(w_object)
+                    return space.wrap(unicode_encode_utf_8(u, len(u), None))
+            except UnicodeEncodeError, uee:
+                raise OperationError(space.w_UnicodeEncodeError,
+                                     space.newtuple([
+                                         space.wrap(uee.encoding),
+                                         space.wrap(uee.object),
+                                         space.wrap(uee.start),
+                                         space.wrap(uee.end),
+                                         space.wrap(uee.reason)]))
         from pypy.module._codecs.interp_codecs import lookup_codec
         w_encoder = space.getitem(lookup_codec(space, encoding), space.wrap(0))
     if errors is None:
@@ -207,9 +223,23 @@
     return w_retval
 
 def decode_object(space, w_obj, encoding, errors):
-    w_codecs = space.getbuiltinmodule("_codecs")
     if encoding is None:
         encoding = getdefaultencoding(space)
+    if errors is None or errors == 'strict':
+        try:
+            if encoding == 'ascii':
+                # XXX error handling
+                s = space.bufferstr_w(w_obj)
+                return space.wrap(str_decode_ascii(s, len(s), None)[0])
+            if encoding == 'utf-8':
+                s = space.bufferstr_w(w_obj)
+                return space.wrap(str_decode_utf_8(s, len(s), None)[0])
+        except UnicodeDecodeError, ude:
+            raise OperationError(space.w_UnicodeDecodeError, space.newtuple(
+                [space.wrap(ude.encoding), space.wrap(ude.object),
+                 space.wrap(ude.start), space.wrap(ude.end),
+                 space.wrap(ude.reason)]))
+    w_codecs = space.getbuiltinmodule("_codecs")
     w_decode = space.getattr(w_codecs, space.wrap("decode"))
     if errors is None:
         w_retval = space.call_function(w_decode, w_obj, space.wrap(encoding))

Modified: pypy/branch/fast-forward/pypy/rlib/rarithmetic.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/rarithmetic.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/rarithmetic.py	Mon Jun  7 20:22:34 2010
@@ -178,12 +178,6 @@
         else:
             return super(base_int, klass).__new__(klass, val)
 
-    def __int__(self):
-        if self < LONG_TEST:
-            return long.__int__(self)
-        else:
-            return intmask(self)
-
     def __add__(self, other):
         x = long(self)
         y = long(other)

Modified: pypy/branch/fast-forward/pypy/rlib/test/test_rarithmetic.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/test/test_rarithmetic.py	(original)
+++ pypy/branch/fast-forward/pypy/rlib/test/test_rarithmetic.py	Mon Jun  7 20:22:34 2010
@@ -114,7 +114,10 @@
         #self.binary_test(lambda x, y: pow(x, y, 42), (2, 3, 5, 1000))
 
     def test_back_to_int(self):
-        assert int(r_uint(-1)) == -1
+        #assert int(r_uint(-1)) == -1
+        # ^^^ that looks wrong IMHO: int(x) should not by itself return
+        #     an integer that has a different value than x, especially
+        #     if x is a subclass of long.
         assert int(r_uint(1)) == 1
 
     def unary_test(self, f):

Modified: pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/lltypesystem/rstr.py	Mon Jun  7 20:22:34 2010
@@ -18,6 +18,7 @@
 from pypy.rpython.rmodel import Repr
 from pypy.rpython.lltypesystem import llmemory
 from pypy.tool.sourcetools import func_with_new_name
+from pypy.rpython.annlowlevel import hlstr
 
 # ____________________________________________________________
 #
@@ -296,7 +297,7 @@
         s = mallocunicode(lgt)
         for i in range(lgt):
             if ord(str.chars[i]) > 127:
-                raise UnicodeDecodeError
+                raise UnicodeDecodeError("ascii", hlstr(str), 0, lgt, "ascii codec can't encode %d" % ord(str.chars[i]))
             s.chars[i] = cast_primitive(UniChar, str.chars[i])
         return s
     ll_str2unicode.oopspec = 'str.str2unicode(str)'

Modified: pypy/branch/fast-forward/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/rbuiltin.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/rbuiltin.py	Mon Jun  7 20:22:34 2010
@@ -270,6 +270,37 @@
         v_errno = hop.inputarg(lltype.Signed, arg=1)
         r_self.setfield(v_self, 'errno', v_errno, hop.llops)
 
+def rtype_UnicodeDecodeError_init(hop):
+    if hop.nb_args != 6:
+        raise TypeError("UnicodeDecodeError() should be called with 5 "
+                        "arguments")
+    r_self = hop.args_r[0]
+    r_str = hop.rtyper.type_system.rstr.string_repr
+    TPS = [hop.args_r[0], r_str, r_str, lltype.Signed, lltype.Signed,
+           r_str]
+    v_self, v_encoding, v_obj, v_start, v_end, v_msg = hop.inputargs(*TPS)
+    r_self.setfield(v_self, 'encoding', v_encoding, hop.llops)
+    r_self.setfield(v_self, 'object', v_obj, hop.llops)
+    r_self.setfield(v_self, 'start', v_start, hop.llops)
+    r_self.setfield(v_self, 'end', v_end, hop.llops)
+    r_self.setfield(v_self, 'reason', v_msg, hop.llops)
+
+def rtype_UnicodeEncodeError_init(hop):
+    if hop.nb_args != 6:
+        raise TypeError("UnicodeEncodeError() should be called with 5 "
+                        "arguments")
+    r_self = hop.args_r[0]
+    r_str = hop.rtyper.type_system.rstr.string_repr
+    r_unicode = hop.rtyper.type_system.rstr.unicode_repr
+    TPS = [hop.args_r[0], r_str, r_unicode, lltype.Signed, lltype.Signed,
+           r_str]
+    v_self, v_encoding, v_obj, v_start, v_end, v_msg = hop.inputargs(*TPS)
+    r_self.setfield(v_self, 'encoding', v_encoding, hop.llops)
+    r_self.setfield(v_self, 'object', v_obj, hop.llops)
+    r_self.setfield(v_self, 'start', v_start, hop.llops)
+    r_self.setfield(v_self, 'end', v_end, hop.llops)
+    r_self.setfield(v_self, 'reason', v_msg, hop.llops)
+
 def rtype_WindowsError__init__(hop):
     if hop.nb_args == 2:
         raise TyperError("WindowsError() should not be called with "
@@ -329,6 +360,8 @@
 
 BUILTIN_TYPER[getattr(OSError.__init__, 'im_func', OSError.__init__)] = (
     rtype_OSError__init__)
+BUILTIN_TYPER[getattr(UnicodeDecodeError.__init__, 'im_func', UnicodeDecodeError.__init__)] = rtype_UnicodeDecodeError_init
+BUILTIN_TYPER[getattr(UnicodeEncodeError.__init__, 'im_func', UnicodeEncodeError.__init__)] = rtype_UnicodeEncodeError_init
 
 try:
     WindowsError

Modified: pypy/branch/fast-forward/pypy/rpython/test/test_rbuiltin.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rpython/test/test_rbuiltin.py	(original)
+++ pypy/branch/fast-forward/pypy/rpython/test/test_rbuiltin.py	Mon Jun  7 20:22:34 2010
@@ -496,6 +496,35 @@
         res = self.interpret(llf, [rffi.r_short(123)], policy=LowLevelAnnotatorPolicy())
         assert res == 123
 
+    def test_unicode_errors(self):
+        def f():
+            try:
+                raise UnicodeDecodeError("xx", "x", 0, 1, "reason")
+            except UnicodeDecodeError, ude:
+                assert ude.start == 0
+                assert ude.encoding == "xx"
+                assert ude.object == "x"
+                assert ude.start == 0
+                assert ude.reason == "reason"
+                return ude.end
+
+        res = self.interpret(f, [])
+        assert res == f()
+
+        def f():
+            try:
+                raise UnicodeEncodeError("xx", u"x", 0, 1, "reason")
+            except UnicodeEncodeError, ude:
+                assert ude.start == 0
+                assert ude.encoding == "xx"
+                assert ude.object == u"x"
+                assert ude.start == 0
+                assert ude.reason == "reason"
+                return ude.end 
+
+        res = self.interpret(f, [])
+        assert res == f()        
+
 class TestLLtype(BaseTestRbuiltin, LLRtypeMixin):
 
     def test_isinstance_obj(self):

Modified: pypy/branch/fast-forward/pypy/tool/pytest/appsupport.py
==============================================================================
--- pypy/branch/fast-forward/pypy/tool/pytest/appsupport.py	(original)
+++ pypy/branch/fast-forward/pypy/tool/pytest/appsupport.py	Mon Jun  7 20:22:34 2010
@@ -86,11 +86,18 @@
         if debug_excs:
             self._excinfo = debug_excs[0]
 
+    def __repr__(self):
+        return "<AppExceptionInfo %s>" % self.operr.errorstr(self.space)
+
     def exconly(self, tryshort=True):
         return '(application-level) ' + self.operr.errorstr(self.space)
 
     def errisinstance(self, exc): 
         clsname = exc.__name__ 
+        # we can only check for builtin exceptions
+        # as there is no canonical applevel one for custom interplevel ones
+        if exc.__module__ != "exceptions":
+            return False 
         try: 
             w_exc = getattr(self.space, 'w_' + clsname) 
         except KeyboardInterrupt: 

Modified: pypy/branch/fast-forward/pypy/tool/pytest/test/test_appsupport.py
==============================================================================
--- pypy/branch/fast-forward/pypy/tool/pytest/test/test_appsupport.py	(original)
+++ pypy/branch/fast-forward/pypy/tool/pytest/test/test_appsupport.py	Mon Jun  7 20:22:34 2010
@@ -113,6 +113,19 @@
         "*E*application-level*NameError*x*not defined",
     ])
 
+def test_applevel_raise_keyerror(testdir):
+    setpypyconftest(testdir)
+    p = testdir.makepyfile("""
+        def app_test_raises():
+            raise KeyError(42)
+            pass
+    """)
+    result = testdir.runpytest(p, "-s")
+    assert result.ret == 1
+    result.stdout.fnmatch_lines([
+        "*E*application-level*KeyError*42*",
+    ])
+
 def app_test_raises():
     info = raises(TypeError, id)
     assert info.type is TypeError



More information about the Pypy-commit mailing list