[pypy-svn] pypy fast-forward: merge default

amauryfa commits-noreply at bitbucket.org
Sun Dec 26 22:21:47 CET 2010


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: fast-forward
Changeset: r40231:a73de8a29ef3
Date: 2010-12-26 22:21 +0100
http://bitbucket.org/pypy/pypy/changeset/a73de8a29ef3/

Log:	merge default


diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -105,14 +105,11 @@
         make_sure_not_resized(self.arguments_w)
         if w_stararg is not None:
             self._combine_starargs_wrapped(w_stararg)
-        if w_starstararg is not None:
-            self._combine_starstarargs_wrapped(w_starstararg)
-            # if we have a call where **args are used at the callsite
-            # we shouldn't let the JIT see the argument matching
-            self._dont_jit = True
-        else:
-            self._dont_jit = False
-        
+        # if we have a call where **args are used at the callsite
+        # we shouldn't let the JIT see the argument matching
+        self._dont_jit = (w_starstararg is not None and
+                          self._combine_starstarargs_wrapped(w_starstararg))
+
     def __repr__(self):
         """ NOT_RPYTHON """
         name = self.__class__.__name__
@@ -171,6 +168,14 @@
                                    "a mapping, not %s" % (typename,)))
                 raise
             keys_w = space.unpackiterable(w_keys)
+        if keys_w:
+            self._do_combine_starstarargs_wrapped(keys_w, w_starstararg)
+            return True
+        else:
+            return False    # empty dict; don't disable the JIT
+
+    def _do_combine_starstarargs_wrapped(self, keys_w, w_starstararg):
+        space = self.space
         keywords_w = [None] * len(keys_w)
         keywords = [None] * len(keys_w)
         i = 0


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
@@ -939,7 +939,9 @@
     if os.sep not in path:
         path = os.curdir + os.sep + path      # force a '/' in the path
     state = space.fromcache(State)
-    state.package_context = name
+    if state.find_extension(name, path) is not None:
+        return
+    state.package_context = name, path
     try:
         from pypy.rlib import rdynload
         try:
@@ -964,7 +966,8 @@
         generic_cpy_call(space, initfunc)
         state.check_and_raise_exception()
     finally:
-        state.package_context = None
+        state.package_context = None, None
+    state.fixup_extension(name, path)
 
 @specialize.ll()
 def generic_cpy_call(space, func, *args):



diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -95,4 +95,3 @@
     if pend:
         pend[0] = rffi.ptradd(str, len(s))
     return space.call_function(space.w_int, w_str, w_base)
-


diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py
--- a/pypy/module/_codecs/interp_codecs.py
+++ b/pypy/module/_codecs/interp_codecs.py
@@ -292,7 +292,7 @@
 
 def buffer_encode(space, s, errors='strict'):
     return space.newtuple([space.wrap(s), space.wrap(len(s))])
-buffer_encode.unwrap_spec = [ObjSpace, 'bufferstr', str]
+buffer_encode.unwrap_spec = [ObjSpace, 'bufferstr', 'str_or_None']
 
 def decode(space, w_obj, w_encoding=NoneNotWrapped, errors='strict'):
     """decode(obj, [encoding[,errors]]) -> object
@@ -380,18 +380,22 @@
     rname = "unicode_encode_%s" % (name.replace("_encode", ""), )
     assert hasattr(runicode, rname)
     def wrap_encoder(space, uni, errors="strict"):
+        if errors is None:
+            errors = 'strict'
         state = space.fromcache(CodecState)
         func = getattr(runicode, rname)
         result = func(uni, len(uni), errors, state.encode_error_handler)
         return space.newtuple([space.wrap(result), space.wrap(len(uni))])
     wrap_encoder.func_name = rname
-    wrap_encoder.unwrap_spec = [ObjSpace, unicode, str]
+    wrap_encoder.unwrap_spec = [ObjSpace, unicode, 'str_or_None']
     globals()[name] = wrap_encoder
 
 def make_decoder_wrapper(name):
     rname = "str_decode_%s" % (name.replace("_decode", ""), )
     assert hasattr(runicode, rname)
     def wrap_decoder(space, string, errors="strict", w_final=False):
+        if errors is None:
+            errors = 'strict'
         final = space.is_true(w_final)
         state = space.fromcache(CodecState)
         func = getattr(runicode, rname)
@@ -399,7 +403,7 @@
                                 final, state.decode_error_handler)
         return space.newtuple([space.wrap(result), space.wrap(consumed)])
     wrap_decoder.func_name = rname
-    wrap_decoder.unwrap_spec = [ObjSpace, 'bufferstr', str, W_Root]
+    wrap_decoder.unwrap_spec = [ObjSpace, 'bufferstr', 'str_or_None', W_Root]
     globals()[name] = wrap_decoder
 
 for encoders in [
@@ -439,6 +443,8 @@
     make_decoder_wrapper('mbcs_decode')
 
 def utf_16_ex_decode(space, data, errors='strict', byteorder=0, w_final=False):
+    if errors is None:
+        errors = 'strict'
     final = space.is_true(w_final)
     state = space.fromcache(CodecState)
     if byteorder == 0:
@@ -454,7 +460,7 @@
         data, len(data), errors, final, state.decode_error_handler, byteorder)
     return space.newtuple([space.wrap(res), space.wrap(consumed),
                            space.wrap(byteorder)])
-utf_16_ex_decode.unwrap_spec = [ObjSpace, str, str, int, W_Root]
+utf_16_ex_decode.unwrap_spec = [ObjSpace, str, 'str_or_None', int, W_Root]
 
 def utf_32_ex_decode(space, data, errors='strict', byteorder=0, w_final=False):
     final = space.is_true(w_final)
@@ -575,8 +581,10 @@
         raise OperationError(space.w_TypeError, space.wrap("invalid mapping"))
 
 
- at unwrap_spec(ObjSpace, str, str, W_Root)
+ at unwrap_spec(ObjSpace, str, 'str_or_None', W_Root)
 def charmap_decode(space, string, errors="strict", w_mapping=None):
+    if errors is None:
+        errors = 'strict'
     if len(string) == 0:
         return space.newtuple([space.wrap(u''), space.wrap(0)])
 
@@ -592,8 +600,10 @@
         final, state.decode_error_handler, mapping)
     return space.newtuple([space.wrap(result), space.wrap(consumed)])
 
- at unwrap_spec(ObjSpace, unicode, str, W_Root)
+ at unwrap_spec(ObjSpace, unicode, 'str_or_None', W_Root)
 def charmap_encode(space, uni, errors="strict", w_mapping=None):
+    if errors is None:
+        errors = 'strict'
     if space.is_w(w_mapping, space.w_None):
         mapping = None
     else:
@@ -633,8 +643,10 @@
             return -1
         return space.int_w(w_code)
 
- at unwrap_spec(ObjSpace, 'bufferstr', str, W_Root)
+ at unwrap_spec(ObjSpace, 'bufferstr', 'str_or_None', W_Root)
 def unicode_escape_decode(space, string, errors="strict", w_final=False):
+    if errors is None:
+        errors = 'strict'
     final = space.is_true(w_final)
     state = space.fromcache(CodecState)
     errorhandler=state.decode_error_handler
@@ -651,8 +663,10 @@
 # ____________________________________________________________
 # Unicode-internal
 
- at unwrap_spec(ObjSpace, W_Root, str)
+ at unwrap_spec(ObjSpace, W_Root, 'str_or_None')
 def unicode_internal_decode(space, w_string, errors="strict"):
+    if errors is None:
+        errors = 'strict'
     # special case for this codec: unicodes are returned as is
     if space.isinstance_w(w_string, space.w_unicode):
         return space.newtuple([w_string, space.len(w_string)])
@@ -673,13 +687,13 @@
 # support for the "string escape" codec
 # This is a bytes-to bytes transformation
 
- at unwrap_spec(ObjSpace, W_Root, str)
+ at unwrap_spec(ObjSpace, W_Root, 'str_or_None')
 def escape_encode(space, w_string, errors='strict'):
     w_repr = space.repr(w_string)
     w_result = space.getslice(w_repr, space.wrap(1), space.wrap(-1))
     return space.newtuple([w_result, space.len(w_string)])
 
- at unwrap_spec(ObjSpace, str, str)
+ at unwrap_spec(ObjSpace, str, 'str_or_None')
 def escape_decode(space, data, errors='strict'):
     from pypy.interpreter.pyparser.parsestring import PyString_DecodeEscape
     result = PyString_DecodeEscape(space, data, None)

diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -380,14 +380,18 @@
         return op
 
     def make_args_key(self, op):
-        args = []
-        for i in range(op.numargs()):
+        n = op.numargs()
+        args = [None] * (n + 1)
+        for i in range(n):
             arg = op.getarg(i)
-            if arg in self.values:
-                args.append(self.values[arg].get_key_box())
+            try:
+                value = self.values[arg]
+            except KeyError:
+                pass
             else:
-                args.append(arg)
-        args.append(ConstInt(op.getopnum()))
+                arg = value.get_key_box()
+            args[i] = arg
+        args[n] = ConstInt(op.getopnum())
         return args
 
     def optimize_default(self, op):

diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -387,8 +387,7 @@
         from pypy.annotation import model as annmodel
 
         if self.instance.__name__ == 'jit_merge_point':
-            if not self.annotate_hooks(**kwds_s):
-                return None      # wrong order, try again later
+            self.annotate_hooks(**kwds_s)
 
         driver = self.instance.im_self
         keys = kwds_s.keys()
@@ -424,13 +423,13 @@
         driver = self.instance.im_self
         s_jitcell = self.bookkeeper.valueoftype(BaseJitCell)
         h = self.annotate_hook
-        return (h(driver.get_jitcell_at, driver.greens, **kwds_s)
-            and h(driver.set_jitcell_at, driver.greens, [s_jitcell], **kwds_s)
-            and h(driver.get_printable_location, driver.greens, **kwds_s))
+        h(driver.get_jitcell_at, driver.greens, **kwds_s)
+        h(driver.set_jitcell_at, driver.greens, [s_jitcell], **kwds_s)
+        h(driver.get_printable_location, driver.greens, **kwds_s)
 
     def annotate_hook(self, func, variables, args_s=[], **kwds_s):
         if func is None:
-            return True
+            return
         bk = self.bookkeeper
         s_func = bk.immutablevalue(func)
         uniquekey = 'jitdriver.%s' % func.func_name
@@ -441,12 +440,13 @@
             else:
                 objname, fieldname = name.split('.')
                 s_instance = kwds_s['s_' + objname]
-                s_arg = s_instance.classdef.about_attribute(fieldname)
-                if s_arg is None:
-                    return False     # wrong order, try again later
+                attrdef = s_instance.classdef.find_attribute(fieldname)
+                position = self.bookkeeper.position_key
+                attrdef.read_locations[position] = True
+                s_arg = attrdef.getvalue()
+                assert s_arg is not None
             args_s.append(s_arg)
         bk.emulate_pbc_call(uniquekey, s_func, args_s)
-        return True
 
     def specialize_call(self, hop, **kwds_i):
         # XXX to be complete, this could also check that the concretetype

diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -213,12 +213,14 @@
         stream.truncate(size)
 
     def direct_write(self, data):
+        self.softspace = 0
         self.getstream().write(data)
 
     def direct_writelines(self, w_lines):    # note: a wrapped list!
         stream = self.getstream()
         space = self.space
         w_iterator = space.iter(w_lines)
+        self.softspace = 0
         while True:
             try:
                 w_line = space.next(w_iterator)




diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -9,7 +9,7 @@
 CPYTHON_VERSION            = (2, 7, 0, "final", 42)   #XXX # sync patchlevel.h
 CPYTHON_API_VERSION        = 1013   #XXX # sync with include/modsupport.h
 
-PYPY_VERSION               = (1, 4, 0, "beta", 0)    #XXX # sync patchlevel.h
+PYPY_VERSION               = (1, 4, 1, "beta", 0)    #XXX # sync patchlevel.h
 
 if platform.name == 'msvc':
     COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)

diff --git a/pypy/module/cpyext/test/test_longobject.py b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -1,4 +1,4 @@
-import sys
+import sys, py
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.objspace.std.intobject import W_IntObject
 from pypy.objspace.std.longobject import W_LongObject
@@ -97,6 +97,10 @@
         assert api.PyLong_AsVoidPtr(w_l) == lltype.nullptr(rffi.VOIDP_real.TO)
 
     def test_sign_and_bits(self, space, api):
+        if space.is_true(space.lt(space.sys.get('version_info'),
+                                  space.wrap((2, 7)))):
+            py.test.skip("unsupported before Python 2.7")
+
         assert api._PyLong_Sign(space.wrap(0L)) == 0
         assert api._PyLong_Sign(space.wrap(2L)) == 1
         assert api._PyLong_Sign(space.wrap(-2L)) == -1

diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -16,14 +16,19 @@
         self.operror = None
         self.new_method_def = lltype.nullptr(PyMethodDef)
 
-        # When importing a package, use this to keep track of its name.  This is
+        # When importing a package, use this to keep track
+        # of its name and path (as a 2-tuple).  This is
         # necessary because an extension module in a package might not supply
         # its own fully qualified name to Py_InitModule.  If it doesn't, we need
         # to be able to figure out what module is being initialized.  Recursive
         # imports will clobber this value, which might be confusing, but it
         # doesn't hurt anything because the code that cares about it will have
         # already read it by that time.
-        self.package_context = None
+        self.package_context = None, None
+
+        # A mapping {filename: copy-of-the-w_dict}, similar to CPython's
+        # variable 'extensions' in Python/import.c.
+        self.extensions = {}
 
     def set_exception(self, operror):
         self.clear_exception()
@@ -96,3 +101,29 @@
             self.programname = rffi.str2charp(progname)
             lltype.render_immortal(self.programname)
         return self.programname
+
+    def find_extension(self, name, path):
+        from pypy.module.cpyext.modsupport import PyImport_AddModule
+        from pypy.interpreter.module import Module
+        try:
+            w_dict = self.extensions[path]
+        except KeyError:
+            return None
+        w_mod = PyImport_AddModule(self.space, name)
+        assert isinstance(w_mod, Module)
+        w_mdict = w_mod.getdict()
+        self.space.call_method(w_mdict, 'update', w_dict)
+        return w_mod
+
+    def fixup_extension(self, name, path):
+        from pypy.interpreter.module import Module
+        space = self.space
+        w_modules = space.sys.get('modules')
+        w_mod = space.finditem_str(w_modules, name)
+        if not isinstance(w_mod, Module):
+            msg = "fixup_extension: module '%s' not loaded" % name
+            raise OperationError(space.w_SystemError,
+                                 space.wrap(msg))
+        w_dict = w_mod.getdict()
+        w_copy = space.call_method(w_dict, 'copy')
+        self.extensions[path] = w_copy

diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -95,6 +95,22 @@
         assert obj.char_member == "a"
         raises(TypeError, "obj.char_member = 'spam'")
         raises(TypeError, "obj.char_member = 42")
+        #
+        import sys
+        bignum = sys.maxint - 42
+        obj.short_member = -12345;     assert obj.short_member == -12345
+        obj.long_member = -bignum;     assert obj.long_member == -bignum
+        obj.ushort_member = 45678;     assert obj.ushort_member == 45678
+        obj.uint_member = 3000000000;  assert obj.uint_member == 3000000000
+        obj.ulong_member = 2*bignum;   assert obj.ulong_member == 2*bignum
+        obj.byte_member = -99;         assert obj.byte_member == -99
+        obj.ubyte_member = 199;        assert obj.ubyte_member == 199
+        obj.bool_member = True;        assert obj.bool_member is True
+        obj.float_member = 9.25;       assert obj.float_member == 9.25
+        obj.double_member = 9.25;      assert obj.double_member == 9.25
+        obj.longlong_member = -2**59;  assert obj.longlong_member == -2**59
+        obj.ulonglong_member = 2**63;  assert obj.ulonglong_member == 2**63
+        #
         self.cleanup_references()
 
     def test_staticmethod(self):


diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py
--- a/pypy/interpreter/test/test_interpreter.py
+++ b/pypy/interpreter/test/test_interpreter.py
@@ -156,6 +156,21 @@
             '''
         self.codetest(code, 'f', [])
 
+    def test_import_default_arg(self):
+        # CPython does not always call __import__() with 5 arguments,
+        # but only if the 5th one is not -1.
+        real_call_function = self.space.call_function
+        space = self.space
+        def safe_call_function(w_obj, *arg_w):
+            assert not arg_w or not space.eq_w(arg_w[-1], space.wrap(-1))
+            return real_call_function(w_obj, *arg_w)
+        self.space.call_function = safe_call_function
+        code = '''
+            def f():
+                import sys
+            '''
+        self.codetest(code, 'f', [])
+
     def test_call_star_starstar(self):
         code = '''\
             def f1(n):

diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -78,7 +78,13 @@
     old_dir = os.getcwd()
     try:
         os.chdir(str(builddir))
-        os.system("strip -x " + str(archive_pypy_c))    # ignore errors
+        #
+        # 'strip' fun: see https://codespeak.net/issue/pypy-dev/issue587
+        if sys.platform == 'darwin':
+            os.system("strip -x " + str(archive_pypy_c))    # ignore errors
+        else:
+            os.system("strip " + str(archive_pypy_c))    # ignore errors
+        #
         if USE_TARFILE_MODULE:
             import tarfile
             tf = tarfile.open(str(builddir.join(name + '.tar.bz2')), 'w:bz2')

diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -167,6 +167,9 @@
     if not we_are_translated():
         metainterp_sd.stats.compiled()
     metainterp_sd.log("compiled new bridge")
+    if metainterp_sd.warmrunnerdesc is not None:    # for tests
+        metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(
+            original_loop_token)
 
 # ____________________________________________________________
 

diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -692,8 +692,12 @@
         def test_mknod(self):
             import stat
             os = self.posix
-            # not very useful: os.mknod() without specifying 'mode'
-            os.mknod(self.path2 + 'test_mknod-1')
+            # os.mknod() may require root priviledges to work at all
+            try:
+                # not very useful: os.mknod() without specifying 'mode'
+                os.mknod(self.path2 + 'test_mknod-1')
+            except OSError, e:
+                skip("os.mknod(): got %r" % (e,))
             st = os.lstat(self.path2 + 'test_mknod-1')
             assert stat.S_ISREG(st.st_mode)
             # os.mknod() with S_IFIFO

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1122,6 +1122,11 @@
             buffer = self.buffer_w(w_obj)
             return buffer.as_str()
 
+    def str_or_None_w(self, w_obj):
+        if self.is_w(w_obj, self.w_None):
+            return None
+        return self.str_w(w_obj)
+
     def realstr_w(self, w_obj):
         # Like str_w, but only works if w_obj is really of type 'str'.
         if not self.is_true(self.isinstance(w_obj, self.w_str)):

diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py
--- a/pypy/module/_file/test/test_file.py
+++ b/pypy/module/_file/test/test_file.py
@@ -174,7 +174,18 @@
         raises(ValueError, self.file, self.temppath, "aU")
         raises(ValueError, self.file, self.temppath, "wU+")
         raises(ValueError, self.file, self.temppath, "")
-        
+
+    def test_write_resets_softspace(self):
+        f = self.file(self.temppath, "w")
+        print >> f, '.',
+        f.write(',')
+        print >> f, '.',
+        f.close()
+        f = self.file(self.temppath, "r")
+        res = f.read()
+        assert res == ".,."
+        f.close()
+
 class AppTestConcurrency(object):
     # these tests only really make sense on top of a translated pypy-c,
     # because on top of py.py the inner calls to os.write() don't



diff --git a/pypy/module/cpyext/test/test_memoryobject.py b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -1,7 +1,12 @@
+import py
 from pypy.module.cpyext.test.test_api import BaseApiTest
 
 class TestMemoryViewObject(BaseApiTest):
     def test_fromobject(self, space, api):
+        if space.is_true(space.lt(space.sys.get('version_info'),
+                                  space.wrap((2, 7)))):
+            py.test.skip("unsupported before Python 2.7")
+
         w_hello = space.wrap("hello")
         w_view = api.PyMemoryView_FromObject(w_hello)
         w_bytes = space.call_method(w_view, "tobytes")


diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -189,14 +189,14 @@
 
         @dont_look_inside
         def f(x, total):
-            if x <= 3:
+            if x <= 30:
                 raise ImDone(total * 10)
-            if x > 20:
+            if x > 200:
                 return 2
             raise ValueError
         @dont_look_inside
         def g(x):
-            if x > 15:
+            if x > 150:
                 raise ValueError
             return 2
         class Base:
@@ -207,7 +207,7 @@
                 return 1
         @dont_look_inside
         def h(x):
-            if x < 2000:
+            if x < 20000:
                 return Sub()
             else:
                 return Base()
@@ -238,8 +238,8 @@
         logfile = udir.join('test_ztranslation.log')
         os.environ['PYPYLOG'] = 'jit-log-opt:%s' % (logfile,)
         try:
-            res = self.meta_interp(main, [40])
-            assert res == main(40)
+            res = self.meta_interp(main, [400])
+            assert res == main(400)
         finally:
             del os.environ['PYPYLOG']
 
@@ -248,5 +248,7 @@
             if 'guard_class' in line:
                 guard_class += 1
         # if we get many more guard_classes, it means that we generate
-        # guards that always fail
-        assert 0 < guard_class <= 4
+        # guards that always fail (the following assert's original purpose
+        # is to catch the following case: each GUARD_CLASS is misgenerated
+        # and always fails with "gcremovetypeptr")
+        assert 0 < guard_class < 10


diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -46,6 +46,8 @@
 
     def test_dllhandle(self):
         import sys
+        if sys.version_info < (2, 6):
+            skip("Python >= 2.6 only")
         assert sys.dllhandle
         assert sys.dllhandle.getaddressindll('PyPyErr_NewException')
         import ctypes # slow
@@ -220,6 +222,12 @@
         else:
             return os.path.dirname(mod)
 
+    def reimport_module(self, mod, name):
+        api.load_extension_module(self.space, mod, name)
+        return self.space.getitem(
+            self.space.sys.get('modules'),
+            self.space.wrap(name))
+
     def import_extension(self, modname, functions, prologue=""):
         methods_table = []
         codes = []
@@ -259,6 +267,7 @@
         self.imported_module_names = []
 
         self.w_import_module = self.space.wrap(self.import_module)
+        self.w_reimport_module = self.space.wrap(self.reimport_module)
         self.w_import_extension = self.space.wrap(self.import_extension)
         self.w_compile_module = self.space.wrap(self.compile_module)
         self.w_record_imported_module = self.space.wrap(
@@ -707,3 +716,43 @@
         p = mod.get_programname()
         print p
         assert 'py' in p
+
+    def test_no_double_imports(self):
+        import sys, os
+        try:
+            init = """
+            static int _imported_already = 0;
+            FILE *f = fopen("_imported_already", "w");
+            fprintf(f, "imported_already: %d\\n", _imported_already);
+            fclose(f);
+            _imported_already = 1;
+            if (Py_IsInitialized()) {
+                Py_InitModule("foo", NULL);
+            }
+            """
+            self.import_module(name='foo', init=init)
+            assert 'foo' in sys.modules
+
+            f = open('_imported_already')
+            data = f.read()
+            f.close()
+            assert data == 'imported_already: 0\n'
+
+            f = open('_imported_already', 'w')
+            f.write('not again!\n')
+            f.close()
+            m1 = sys.modules['foo']
+            m2 = self.reimport_module(m1.__file__, name='foo')
+            assert m1 is m2
+            assert m1 is sys.modules['foo']
+
+            f = open('_imported_already')
+            data = f.read()
+            f.close()
+            assert data == 'not again!\n'
+
+        finally:
+            try:
+                os.unlink('_imported_already')
+            except OSError:
+                pass


diff --git a/pypy/tool/release/make_release.py b/pypy/tool/release/make_release.py
--- a/pypy/tool/release/make_release.py
+++ b/pypy/tool/release/make_release.py
@@ -4,7 +4,8 @@
 into release packages. Note: you must run apropriate buildbots first and
 make sure there are no failures. Use force-builds.py from the same directory.
 
-Usage: make_release.py release/<release name> release_version
+Usage: make_release.py  <branchname>  <version>
+ e.g.: make_release.py  release-1.4.1  1.4.1
 """
 
 import autopath
@@ -20,6 +21,7 @@
 import shutil
 
 BASEURL = 'http://buildbot.pypy.org/nightly/'
+PAUSE = False
 
 def browse_nightly(branch,
                    baseurl=BASEURL,
@@ -32,12 +34,12 @@
     dom = minidom.parseString(xml)
     refs = [node.getAttribute('href') for node in dom.getElementsByTagName('a')
             if 'pypy' in node.getAttribute('href')]
-    # all refs are of form: pypy-{type}-{revision}-{platform}.tar.bz2
-    r = re.compile('pypy-c-([\w\d]+)-(\d+)-([\w\d]+).tar.bz2$')
+    # all refs are of form: pypy-c-{type}-{revnum}-{hghash}-{platform}.tar.bz2
+    r = re.compile('pypy-c-([\w\d]+)-(\d+)-([0-9a-f]+)-([\w\d]+).tar.bz2$')
     d = {}
     for ref in refs:
-        kind, rev, platform = r.match(ref).groups()
-        rev = int(rev)
+        kind, revnum, hghash, platform = r.match(ref).groups()
+        rev = int(revnum)
         try:
             lastrev, _ = d[(kind, platform)]
         except KeyError:
@@ -51,8 +53,10 @@
     tmpdir = udir.join('download')
     tmpdir.ensure(dir=True)
     alltars = []
+    olddir = os.getcwd()
     try:
         os.chdir(str(tmpdir))
+        print 'Using tmpdir', str(tmpdir)
         for (kind, platform), (rev, name) in to_download.iteritems():
             if platform == 'win32':
                 print 'Ignoring %s, windows unsupported' % name
@@ -64,20 +68,23 @@
                 t = tarfile.open(str(tmpdir.join(name)))
                 dirname = t.getmembers()[0].name
                 t.extractall(path=str(tmpdir))
-                os.system('mv %s %s' % (str(tmpdir.join(dirname)),
-                                        str(tmpdir.join('pypy-%s' % release))))
                 if kind == 'jit':
                     kind = ''
                 else:
                     kind = '-' + kind
-                olddir = os.getcwd()
-                name = 'pypy-%s-%s%s.tar.bz2' % (release, platform, kind)
+                topdirname = 'pypy-%s-%s%s' % (release, platform, kind)
+                os.system('mv %s %s' % (str(tmpdir.join(dirname)),
+                                        str(tmpdir.join(topdirname))))
+                if PAUSE:
+                    print 'Pausing, press Enter...'
+                    raw_input()
+                name = '%s.tar.bz2' % topdirname
                 print "Building %s" % name
                 t = tarfile.open(name, 'w:bz2')
-                t.add('pypy-%s' % release)
+                t.add(topdirname)
                 alltars.append(name)
                 t.close()
-                shutil.rmtree(str(tmpdir.join('pypy-' + release)))
+                shutil.rmtree(str(tmpdir.join(topdirname)))
         for name in alltars:
             print "Uploading %s" % name
             os.system('scp %s codespeak.net:/www/pypy.org/htdocs/download' % name)


More information about the Pypy-commit mailing list