Author: Philip Jenvey <pjen...@underboss.org>
Branch: py3k
Changeset: r64693:699f19dc7cde
Date: 2013-05-31 13:29 -0700
http://bitbucket.org/pypy/pypy/changeset/699f19dc7cde/

Log:    merge default

diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py
--- a/lib-python/2.7/socket.py
+++ b/lib-python/2.7/socket.py
@@ -96,6 +96,7 @@
 
 
 _realsocket = socket
+_type = type
 
 # WSA error codes
 if sys.platform.lower().startswith("win"):
@@ -173,31 +174,37 @@
 
     __doc__ = _realsocket.__doc__
 
+    __slots__ = ["_sock", "__weakref__"]
+
     def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
         if _sock is None:
             _sock = _realsocket(family, type, proto)
+        elif _type(_sock) is _realsocket:
+            _sock._reuse()
+        # PyPy note about refcounting: implemented with _reuse()/_drop()
+        # on the class '_socket.socket'.  Python 3 did it differently
+        # with a reference counter on this class 'socket._socketobject'
+        # instead, but it is a less compatible change (breaks eventlet).
         self._sock = _sock
-        self._io_refs = 0
-        self._closed = False
 
     def send(self, data, flags=0):
-        return self._sock.send(data, flags=flags)
+        return self._sock.send(data, flags)
     send.__doc__ = _realsocket.send.__doc__
 
     def recv(self, buffersize, flags=0):
-        return self._sock.recv(buffersize, flags=flags)
+        return self._sock.recv(buffersize, flags)
     recv.__doc__ = _realsocket.recv.__doc__
 
     def recv_into(self, buffer, nbytes=0, flags=0):
-        return self._sock.recv_into(buffer, nbytes=nbytes, flags=flags)
+        return self._sock.recv_into(buffer, nbytes, flags)
     recv_into.__doc__ = _realsocket.recv_into.__doc__
 
     def recvfrom(self, buffersize, flags=0):
-        return self._sock.recvfrom(buffersize, flags=flags)
+        return self._sock.recvfrom(buffersize, flags)
     recvfrom.__doc__ = _realsocket.recvfrom.__doc__
 
     def recvfrom_into(self, buffer, nbytes=0, flags=0):
-        return self._sock.recvfrom_into(buffer, nbytes=nbytes, flags=flags)
+        return self._sock.recvfrom_into(buffer, nbytes, flags)
     recvfrom_into.__doc__ = _realsocket.recvfrom_into.__doc__
 
     def sendto(self, data, param2, param3=None):
@@ -208,13 +215,17 @@
     sendto.__doc__ = _realsocket.sendto.__doc__
 
     def close(self):
-        # This function should not reference any globals. See issue #808164.
+        s = self._sock
+        if type(s) is _realsocket:
+            s._drop()
         self._sock = _closedsocket()
     close.__doc__ = _realsocket.close.__doc__
 
     def accept(self):
         sock, addr = self._sock.accept()
-        return _socketobject(_sock=sock), addr
+        sockobj = _socketobject(_sock=sock)
+        sock._drop()    # already a copy in the _socketobject()
+        return sockobj, addr
     accept.__doc__ = _realsocket.accept.__doc__
 
     def dup(self):
@@ -228,24 +239,7 @@
 
         Return a regular file object corresponding to the socket.  The mode
         and bufsize arguments are as for the built-in open() function."""
-        self._io_refs += 1
-        return _fileobject(self, mode, bufsize)
-
-    def _decref_socketios(self):
-        if self._io_refs > 0:
-            self._io_refs -= 1
-        if self._closed:
-            self.close()
-
-    def _real_close(self):
-        # This function should not reference any globals. See issue #808164.
-        self._sock.close()
-
-    def close(self):
-        # This function should not reference any globals. See issue #808164.
-        self._closed = True
-        if self._io_refs <= 0:
-            self._real_close()
+        return _fileobject(self._sock, mode, bufsize)
 
     family = property(lambda self: self._sock.family, doc="the socket family")
     type = property(lambda self: self._sock.type, doc="the socket type")
@@ -286,6 +280,8 @@
                  "_close"]
 
     def __init__(self, sock, mode='rb', bufsize=-1, close=False):
+        if type(sock) is _realsocket:
+            sock._reuse()
         self._sock = sock
         self.mode = mode # Not actually used in this version
         if bufsize < 0:
@@ -320,16 +316,11 @@
             if self._sock:
                 self.flush()
         finally:
-            if self._sock:
-                if self._close:
-                    self._sock.close()
-                else:
-                    try:
-                        self._sock._decref_socketios()
-                    except AttributeError:
-                        pass  # bah, someone built a _fileobject manually
-                              # with some unexpected replacement of the
-                              # _socketobject class
+            s = self._sock
+            if type(s) is _realsocket:
+                s._drop()
+            if self._close:
+                self._sock.close()
             self._sock = None
 
     def __del__(self):
diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info
new file mode 100644
--- /dev/null
+++ b/lib_pypy/greenlet.egg-info
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: greenlet
+Version: 0.4.0
+Summary: Lightweight in-process concurrent programming
+Home-page: https://github.com/python-greenlet/greenlet
+Author: Ralf Schmitt (for CPython), PyPy team
+Author-email: pypy-...@python.org
+License: MIT License
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -32,13 +32,12 @@
      "rctime" , "select", "zipimport", "_lsprof",
      "crypt", "signal", "_rawffi", "termios", "zlib", "bz2",
      "struct", "_hashlib", "_md5", "_minimal_curses",
-     "thread", "itertools", "pyexpat", "_ssl", "array",
+     "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
      "binascii", "_multiprocessing", '_warnings',
      "_collections", "_multibytecodec", "_ffi",
      "_continuation", "_csv", "_cffi_backend",
      "_posixsubprocess",  # "cppyy", "micronumpy",
      ]
-# disabled until problems are fixed
 ))
 
 translation_modules = default_modules.copy()
diff --git a/pypy/doc/rffi.rst b/pypy/doc/rffi.rst
--- a/pypy/doc/rffi.rst
+++ b/pypy/doc/rffi.rst
@@ -5,7 +5,7 @@
 Purpose
 -------
 
-This document describes an FFI for RPython language, concentrating
+This document describes an FFI for the RPython language, concentrating
 on low-level backends like C. It describes
 how to declare and call low-level (C) functions from RPython level.
 
@@ -50,7 +50,7 @@
 ------
 
 In rffi_ there are various declared types for C-structures, like CCHARP
-(char*), SIZE_T (size_t) and others. refer to file for details. 
+(char*), SIZE_T (size_t) and others. Refer to file for details. 
 Instances of non-primitive types must be alloced by hand, with call 
 to lltype.malloc, and freed by lltype.free both with keyword argument 
 flavor='raw'. There are several helpers like string -> char*
diff --git a/pypy/module/_ffi/test/test_funcptr.py 
b/pypy/module/_ffi/test/test_funcptr.py
--- a/pypy/module/_ffi/test/test_funcptr.py
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -46,6 +46,7 @@
         libm = CDLL(libm_name)
         pow = libm.getpointer('pow', [], types.void)
         pow_addr = rffi.cast(rffi.LONG, pow.funcsym)
+        cls._libm = libm     # otherwise it gets unloaded - argh!
         cls.w_pow_addr = space.wrap(pow_addr)
 
 class AppTestFFI(BaseAppTestFFI):
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -25,7 +25,7 @@
 from pypy.objspace.std.sliceobject import W_SliceObject
 from pypy.module.__builtin__.descriptor import W_Property
 from pypy.module.__builtin__.interp_memoryview import W_MemoryView
-from rpython.rlib.entrypoint import entrypoint
+from rpython.rlib.entrypoint import entrypoint_lowlevel
 from rpython.rlib.rposix import is_valid_fd, validate_fd
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.objectmodel import specialize
@@ -545,38 +545,37 @@
 def make_wrapper(space, callable):
     "NOT_RPYTHON"
     names = callable.api_func.argnames
-    argtypes = callable.api_func.argtypes
-    is_wrapped_list = [name.startswith("w_") for name in names]
+    argtypes_enum_ui = 
unrolling_iterable(enumerate(zip(callable.api_func.argtypes,
+        [name.startswith("w_") for name in names])))
     fatal_value = callable.api_func.restype._defl()
 
-    lines = []
-    for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)):
-        if is_PyObject(argtype) and is_wrapped:
-            new_lines = [
-                'if %(arg)s:',
-                '    %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))',
-                'else:',
-                '    %(arg)s = None',
-            ]
-            for j in range(len(new_lines)):
-                new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i}
-            lines += new_lines
-    middle = '\n            '.join(lines)
-    arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))])
-
-    source = py.code.Source("""
-    def wrapper(%(args)s):
+    @specialize.ll()
+    def wrapper(*args):
         from pypy.module.cpyext.pyobject import make_ref, from_ref
         from pypy.module.cpyext.pyobject import Reference
+        # we hope that malloc removal removes the newtuple() that is
+        # inserted exactly here by the varargs specializer
+        rffi.stackcounter.stacks_counter += 1
+        llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
         retval = fatal_value
         boxed_args = ()
         try:
             if not we_are_translated() and DEBUG_WRAPPER:
                 print >>sys.stderr, callable,
+            assert len(args) == len(callable.api_func.argtypes)
+            for i, (typ, is_wrapped) in argtypes_enum_ui:
+                arg = args[i]
+                if is_PyObject(typ) and is_wrapped:
+                    if arg:
+                        arg_conv = from_ref(space, rffi.cast(PyObject, arg))
+                    else:
+                        arg_conv = None
+                else:
+                    arg_conv = arg
+                boxed_args += (arg_conv, )
             state = space.fromcache(State)
-            %(middle)s
             try:
-                result = callable(space, %(args)s)
+                result = callable(space, *boxed_args)
                 if not we_are_translated() and DEBUG_WRAPPER:
                     print >>sys.stderr, " DONE"
             except OperationError, e:
@@ -598,8 +597,8 @@
             if failed:
                 error_value = callable.api_func.error_value
                 if error_value is CANNOT_FAIL:
-                    raise SystemError("The function '%%s' was not supposed to 
fail"
-                                      %% (callable.__name__,))
+                    raise SystemError("The function '%s' was not supposed to 
fail"
+                                      % (callable.__name__,))
                 retval = error_value
 
             elif is_PyObject(callable.api_func.restype):
@@ -626,13 +625,8 @@
             else:
                 print str(e)
                 pypy_debug_catch_fatal_exception()
+        rffi.stackcounter.stacks_counter -= 1
         return retval
-    """ % {"middle": middle, "args": arg_spec})
-    d = {}
-    d.update(locals())
-    d.update(globals())
-    exec source.compile() in d
-    wrapper = d['wrapper']
     callable._always_inline_ = 'try'
     wrapper.__name__ = "wrapper for %r" % (callable, )
     return wrapper
@@ -1027,7 +1021,7 @@
         export_struct(name, struct)
 
     for name, func in FUNCTIONS.iteritems():
-        deco = entrypoint("cpyext", func.argtypes, name)
+        deco = entrypoint_lowlevel("cpyext", func.argtypes, name, relax=True)
         deco(func.get_wrapper(space))
 
     setup_init_functions(eci, translating=True)
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -342,7 +342,7 @@
             return
 
         @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real,
-                     error=-1, external=False)
+                     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:
diff --git a/pypy/module/micronumpy/test/test_scalar.py 
b/pypy/module/micronumpy/test/test_scalar.py
--- a/pypy/module/micronumpy/test/test_scalar.py
+++ b/pypy/module/micronumpy/test/test_scalar.py
@@ -21,3 +21,7 @@
 
         a = zeros(3)
         assert loads(dumps(sum(a))) == sum(a)
+
+    def setup_class(cls):
+        import py
+        py.test.xfail("FIXME: dtype('int32') == dtype('int32') fails")
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py 
b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -184,7 +184,7 @@
 
     def match_by_id(self, id, expected_src, **kwds):
         ops = list(self.ops_by_id(id, **kwds))
-        matcher = OpMatcher(ops)
+        matcher = OpMatcher(ops, id)
         return matcher.match(expected_src)
 
 class PartialTraceWithIds(TraceWithIds):
@@ -260,8 +260,9 @@
 
 class OpMatcher(object):
 
-    def __init__(self, ops):
+    def __init__(self, ops, id=None):
         self.ops = ops
+        self.id = id
         self.src = '\n'.join(map(str, ops))
         self.alpha_map = {}
 
@@ -495,6 +496,7 @@
             print '@' * 40
             print "Loops don't match"
             print "================="
+            print 'loop id = %r' % (self.id,)
             print e.args
             print e.msg
             print
diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py 
b/pypy/module/pypyjit/test_pypy_c/test_bug.py
--- a/pypy/module/pypyjit/test_pypy_c/test_bug.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py
@@ -6,6 +6,11 @@
 def test_bug1():
     if not sys.platform.startswith('linux'):
         py.test.skip("linux-only test")
+    if '__pypy__' not in sys.builtin_module_names:
+        try:
+            import cffi
+        except ImportError, e:
+            py.test.skip(str(e))
 
     cmdline = ['taskset', '-c', '0',
                sys.executable, os.path.join(localdir, 'bug1.py')]
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py 
b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -254,17 +254,22 @@
                 return c
             #
             s = 0
-            for i in range(x):
+            i = 0
+            while i < x:
                 l = [i, x, 2]
                 s += g(*l)       # ID: g1
                 s += h(*l)       # ID: h1
                 s += g(i, x, 2)  # ID: g2
                 a = 0
-            for i in range(x):
+                i += 1
+            i = 0
+            while i < x:
                 l = [x, 2]
+                g(*l)
                 s += g(i, *l)    # ID: g3
                 s += h(i, *l)    # ID: h2
                 a = 0
+                i += 1
             return s
         #
         log = self.run(main, [1000])
@@ -339,6 +344,7 @@
         loop, = log.loops_by_filename(self.filepath)
         # the int strategy is used here
         assert loop.match_by_id('append', """
+            guard_not_invalidated?
             i13 = getfield_gc(p8, descr=<FieldS list.length .*>)
             i15 = int_add(i13, 1)
             # Will be killed by the backend
@@ -486,6 +492,7 @@
         assert loop.match("""
             i2 = int_lt(i0, i1)
             guard_true(i2, descr=...)
+            guard_not_invalidated?
             i3 = force_token()
             i4 = int_add(i0, 1)
             --TICK--
@@ -585,7 +592,7 @@
         """, [1000])
         loop, = log.loops_by_id('call')
         assert loop.match_by_id('call', '''
-        guard_not_invalidated(descr=...)
+        guard_not_invalidated?
         i1 = force_token()
         ''')
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py 
b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -13,6 +13,7 @@
             a = A()
             a.x = 1
             for s in sys.modules.keys() * 1000:
+                d.get(s)  # force pending setfields etc.
                 inc = a.x # ID: look
                 d[s] = d.get(s, 0) + inc
             return sum(d.values())
@@ -21,8 +22,7 @@
         assert log.result % 1000 == 0
         loop, = log.loops_by_filename(self.filepath)
         ops = loop.ops_by_id('look')
-        assert log.opnames(ops) == ['setfield_gc',
-                                    'guard_not_invalidated']
+        assert log.opnames(ops) == []
 
     def test_identitydict(self):
         def fn(n):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py 
b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
--- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
@@ -49,17 +49,20 @@
         label(..., descr=...)
         ...
         label(..., descr=...)
+        guard_not_invalidated?
         i17 = int_ge(i11, i7)
         guard_false(i17, descr=...)
         p18 = getarrayitem_gc(p5, i11, descr=...)
         i19 = int_add(i11, 1)
         setfield_gc(p2, i19, descr=...)
-        guard_class(p18, ConstClass(W_IntObject), descr=...)
+        guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...)
         i20 = getfield_gc_pure(p18, descr=...)
         i21 = int_gt(i20, i14)
         guard_true(i21, descr=...)
         jump(..., descr=...)
         ''')
+        # XXX could be "guard_class(p18)" instead; we lost somewhere
+        # the information that it cannot be null.
 
     def test_iter_max(self):
         def main():
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py 
b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -177,6 +177,7 @@
         assert log.result == 1000 * 999 / 2
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
+            guard_not_invalidated?
             i16 = int_ge(i11, i12)
             guard_false(i16, descr=...)
             i17 = int_mul(i11, i14)
@@ -184,7 +185,7 @@
             i20 = int_add(i11, 1)
             i21 = force_token()
             setfield_gc(p4, i20, descr=<.* 
.*W_AbstractSeqIterObject.inst_index .*>)
-            guard_not_invalidated(descr=...)
+            guard_not_invalidated?
             i23 = int_lt(i18, 0)
             guard_false(i23, descr=...)
             i25 = int_ge(i18, i9)
@@ -234,6 +235,7 @@
         assert log.result == 1000000
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match("""
+            guard_not_invalidated?
             i14 = getfield_gc(p12, descr=<FieldS list.length .*>)
             i16 = uint_ge(i12, i14)
             guard_false(i16, descr=...)
@@ -242,7 +244,7 @@
             i19 = int_add(i12, 1)
             setfield_gc(p9, i19, descr=<FieldS 
.*W_AbstractSeqIterObject.inst_index .*>)
             guard_nonnull_class(p17, ..., descr=...)
-            guard_not_invalidated(descr=...)
+            guard_not_invalidated?
             i21 = getfield_gc(p17, descr=<FieldS .*W_Array.*.inst_len .*>)
             i23 = int_lt(0, i21)
             guard_true(i23, descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py 
b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -157,7 +157,7 @@
             copystrcontent(p9, p21, 0, i25, i10)
             i33 = int_lt(i30, 23)
             guard_true(i33, descr=...)
-            p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, 
i30, descr=<Callr . ri EF=4>)
+            p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, 
i30, descr=<Callr . ri EF=4 OS=3>)
             guard_no_exception(descr=...)
             i37 = strlen(p35)
             i38 = int_add_ovf(i5, i37)
@@ -190,7 +190,7 @@
         assert len(loops) == 1
         for loop in loops:
             loop.match_by_id('getattr','''
-            guard_not_invalidated(descr=...)
+            guard_not_invalidated?
             i32 = strlen(p31)
             i34 = int_add(5, i32)
             p35 = newstr(i34)
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py 
b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py
@@ -98,10 +98,10 @@
         s = ffi.new("struct s1 *")
         setattr(s, name, value)
         assert getattr(s, name) == value
-        raw1 = bytes(ffi.buffer(s))
+        raw1 = ffi.buffer(s)[:]
         if lib is not None:
             t = lib.try_with_value(fnames.index(name), value)
-            raw2 = bytes(ffi.buffer(t, len(raw1)))
+            raw2 = ffi.buffer(t, len(raw1))[:]
             assert raw1 == raw2
 
     def test_bitfield_basic(self):
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -215,8 +215,9 @@
         if len(self._cache) != 1:
             raise NoStandardGraph(self)
         [graph] = self._cache.values()
+        relax_sig_check = getattr(self.pyobj, "relax_sig_check", False)
         if (graph.signature != self.signature or
-            graph.defaults  != self.defaults):
+            graph.defaults  != self.defaults) and not relax_sig_check:
             raise NoStandardGraph(self)
         return graph
 
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -3542,6 +3542,16 @@
         s = a.build_types(f, [int])
         assert s.knowntype is int
 
+    def test_relax(self):
+        def f(*args):
+            return args[0] + args[1]
+        f.relax_sig_check = True
+        def g(x):
+            return f(x, x - x)
+        a = self.RPythonAnnotator()
+        s = a.build_types(g, [int])
+        assert a.bookkeeper.getdesc(f).getuniquegraph()
+
     def test_cannot_raise_ll_exception(self):
         from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
         #
diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py
--- a/rpython/rlib/entrypoint.py
+++ b/rpython/rlib/entrypoint.py
@@ -5,13 +5,33 @@
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib.objectmodel import we_are_translated
 
+
+def entrypoint_lowlevel(key, argtypes, c_name=None, relax=False):
+    """ Note: entrypoint should call llop.gc_stack_bottom on it's own.
+    That's necessary for making it work with asmgcc and hence JIT
+
+    If in doubt, use entrypoint().
+
+    if key == 'main' than it's included by default
+    """
+    from rpython.translator.tool.cbuild import ExternalCompilationInfo
+
+    def deco(func):
+        secondary_entrypoints.setdefault(key, []).append((func, argtypes))
+        if c_name is not None:
+            func.c_name = c_name
+        if relax:
+            func.relax_sig_check = True
+        func._compilation_info = ExternalCompilationInfo(
+            export_symbols=[c_name or func.func_name])
+        return func
+    return deco
+
+
 pypy_debug_catch_fatal_exception = 
rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void)
 
 def entrypoint(key, argtypes, c_name=None):
-    """ Note: entrypoint should call llop.gc_stack_bottom on it's own.
-    That's necessary for making it work with asmgcc and hence JIT
-
-    if key == 'main' than it's included by default
+    """if key == 'main' than it's included by default
     """
     from rpython.translator.tool.cbuild import ExternalCompilationInfo
 
diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py
--- a/rpython/rlib/rStringIO.py
+++ b/rpython/rlib/rStringIO.py
@@ -101,7 +101,11 @@
         self.__pos = endp
 
     def seek(self, position, mode=0):
-        if mode == 1:
+        if mode == 0:
+            if position == self.getsize():
+                self.__pos = AT_END
+                return
+        elif mode == 1:
             if self.__pos == AT_END:
                 self.__pos = self.getsize()
             position += self.__pos
@@ -163,14 +167,24 @@
         return ''.join(self.__bigbuffer[p:i])
 
     def truncate(self, size):
+        """Warning, this gets us slightly strange behavior from the
+        point of view of a traditional Unix file, but consistent with
+        Python 2.7's cStringIO module: it will not enlarge the file,
+        and it will always seek to the (new) end of the file."""
         assert size >= 0
-        if self.__bigbuffer is None or size > len(self.__bigbuffer):
-            self.__copy_into_bigbuffer()
+        if size == 0:
+            self.__bigbuffer = None
+            self.__strings = None
         else:
-            # we can drop all extra strings
-            if self.__strings is not None:
-                self.__strings = None
-        if size < len(self.__bigbuffer):
-            del self.__bigbuffer[size:]
-        if len(self.__bigbuffer) == 0:
-            self.__bigbuffer = None
+            if self.__bigbuffer is None or size > len(self.__bigbuffer):
+                self.__copy_into_bigbuffer()
+            else:
+                # we can drop all extra strings
+                if self.__strings is not None:
+                    self.__strings = None
+            if size < len(self.__bigbuffer):
+                del self.__bigbuffer[size:]
+            if len(self.__bigbuffer) == 0:
+                self.__bigbuffer = None
+        # it always has the effect of seeking at the new end
+        self.__pos = AT_END
diff --git a/rpython/rlib/test/test_rStringIO.py 
b/rpython/rlib/test/test_rStringIO.py
--- a/rpython/rlib/test/test_rStringIO.py
+++ b/rpython/rlib/test/test_rStringIO.py
@@ -96,7 +96,15 @@
     f.truncate(20)
     assert f.getvalue() == ''
     assert f.tell() == 0
-    f.write('\x00' * 20)
+    f.write('\x00' * 25)
+    f.seek(12)
+    f.truncate(20)
+    assert f.getvalue() == '\x00' * 20
+    assert f.tell() == 20
+    f.write('more')
+    f.truncate(20)
+    assert f.getvalue() == '\x00' * 20
+    assert f.tell() == 20
     f.write('hello')
     f.write(' world')
     f.truncate(30)
@@ -109,6 +117,13 @@
     assert f.getvalue() == '\x00' * 3
     assert f.tell() == 3
 
+def test_truncate_end():
+    f = RStringIO()
+    f.write("abc")
+    f.seek(0)
+    f.truncate(0)
+    assert f.getvalue() == ""
+
 def test_bug():
     f = RStringIO()
     f.write('0')
diff --git a/rpython/rlib/test/test_rlocale.py 
b/rpython/rlib/test/test_rlocale.py
--- a/rpython/rlib/test/test_rlocale.py
+++ b/rpython/rlib/test/test_rlocale.py
@@ -20,8 +20,8 @@
 
     def test_setlocale_worked(self):
         assert u"&#260;".isupper()
-        raises(LocaleError, setlocale, LC_ALL, "bla bla bla")
-        raises(LocaleError, setlocale, 1234455, None)
+        py.test.raises(LocaleError, setlocale, LC_ALL, "bla bla bla")
+        py.test.raises(LocaleError, setlocale, 1234455, None)
 
     def test_lower_upper(self):
         assert isupper(ord("A"))
diff --git a/rpython/translator/c/test/test_genc.py 
b/rpython/translator/c/test/test_genc.py
--- a/rpython/translator/c/test/test_genc.py
+++ b/rpython/translator/c/test/test_genc.py
@@ -522,8 +522,9 @@
             f = getattr(self, "_f", None)
             if f is not None:
                 return f
-            f = lambda arg: self.func(arg)
+            f = lambda *args: self.func(*args)
             f.c_name = self.name
+            f.relax_sig_check = True
             f.__name__ = "WRAP%s" % (self.name, )
             self._f = f
             return f
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to