[pypy-commit] pypy step-one-xrange: merge default
hakanardo
noreply at buildbot.pypy.org
Fri May 11 14:44:50 CEST 2012
Author: Hakan Ardo <hakan at debian.org>
Branch: step-one-xrange
Changeset: r55038:a40f78826fc8
Date: 2012-05-11 14:35 +0200
http://bitbucket.org/pypy/pypy/changeset/a40f78826fc8/
Log: merge default
diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -18,6 +18,7 @@
from pypy.tool.pytest import appsupport
from pypy.tool.pytest.confpath import pypydir, testdir, testresultdir
+from pypy.config.parse import parse_info
pytest_plugins = "resultlog",
rsyncdirs = ['.', '../pypy/']
@@ -599,8 +600,9 @@
# check modules
info = py.process.cmdexec("%s --info" % execpath)
+ info = parse_info(info)
for mod in regrtest.usemodules:
- if "objspace.usemodules.%s: False" % mod in info:
+ if info.get('objspace.usemodules.%s' % mod) is not True:
py.test.skip("%s module not included in %s" % (mod,
execpath))
diff --git a/pypy/bin/rpython b/pypy/bin/rpython
old mode 100755
new mode 100644
diff --git a/pypy/config/parse.py b/pypy/config/parse.py
new file mode 100644
--- /dev/null
+++ b/pypy/config/parse.py
@@ -0,0 +1,55 @@
+
+
+def parse_info(text):
+ """See test_parse.py."""
+ text = text.lstrip()
+ result = {}
+ if (text+':').index(':') > (text+'=').index('='):
+ # found a '=' before a ':' means that we have the new format
+ current = {0: ''}
+ indentation_prefix = None
+ for line in text.splitlines():
+ line = line.rstrip()
+ if not line:
+ continue
+ realline = line.lstrip()
+ indent = len(line) - len(realline)
+ #
+ # 'indentation_prefix' is set when the previous line was a [group]
+ if indentation_prefix is not None:
+ assert indent > max(current) # missing indent?
+ current[indent] = indentation_prefix
+ indentation_prefix = None
+ #
+ else:
+ # in case of dedent, must kill the extra items from 'current'
+ for n in current.keys():
+ if n > indent:
+ del current[n]
+ #
+ prefix = current[indent] # KeyError if bad dedent
+ #
+ if realline.startswith('[') and realline.endswith(']'):
+ indentation_prefix = prefix + realline[1:-1] + '.'
+ else:
+ # build the whole dotted key and evaluate the value
+ i = realline.index(' = ')
+ key = prefix + realline[:i]
+ value = realline[i+3:]
+ value = eval(value, {})
+ result[key] = value
+ #
+ else:
+ # old format
+ for line in text.splitlines():
+ i = line.index(':')
+ key = line[:i].strip()
+ value = line[i+1:].strip()
+ try:
+ value = int(value)
+ except ValueError:
+ if value in ('True', 'False', 'None'):
+ value = eval(value, {})
+ result[key] = value
+ #
+ return result
diff --git a/pypy/config/test/test_parse.py b/pypy/config/test/test_parse.py
new file mode 100644
--- /dev/null
+++ b/pypy/config/test/test_parse.py
@@ -0,0 +1,38 @@
+from pypy.config.parse import parse_info
+
+
+def test_parse_new_format():
+ assert (parse_info("[foo]\n"
+ " bar = True\n")
+ == {'foo.bar': True})
+
+ assert (parse_info("[objspace]\n"
+ " x = 'hello'\n"
+ "[translation]\n"
+ " bar = 42\n"
+ " [egg]\n"
+ " something = None\n"
+ " foo = True\n")
+ == {
+ 'translation.foo': True,
+ 'translation.bar': 42,
+ 'translation.egg.something': None,
+ 'objspace.x': 'hello',
+ })
+
+ assert parse_info("simple = 43\n") == {'simple': 43}
+
+
+def test_parse_old_format():
+ assert (parse_info(" objspace.allworkingmodules: True\n"
+ " objspace.disable_call_speedhacks: False\n"
+ " objspace.extmodules: None\n"
+ " objspace.name: std\n"
+ " objspace.std.prebuiltintfrom: -5\n")
+ == {
+ 'objspace.allworkingmodules': True,
+ 'objspace.disable_call_speedhacks': False,
+ 'objspace.extmodules': None,
+ 'objspace.name': 'std',
+ 'objspace.std.prebuiltintfrom': -5,
+ })
diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -562,7 +562,7 @@
ops.WITH_CLEANUP : -1,
ops.POP_BLOCK : 0,
- ops.END_FINALLY : -3,
+ ops.END_FINALLY : -1,
ops.SETUP_WITH : 1,
ops.SETUP_FINALLY : 0,
ops.SETUP_EXCEPT : 0,
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -564,7 +564,8 @@
self.visit_sequence(handler.body)
self.emit_jump(ops.JUMP_FORWARD, end)
self.use_next_block(next_except)
- self.emit_op(ops.END_FINALLY)
+ self.emit_op(ops.END_FINALLY) # this END_FINALLY will always re-raise
+ self.is_dead_code()
self.use_next_block(otherwise)
self.visit_sequence(te.orelse)
self.use_next_block(end)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -801,6 +801,18 @@
return obj
interp_w._annspecialcase_ = 'specialize:arg(1)'
+ def _check_constant_interp_w_or_w_None(self, RequiredClass, w_obj):
+ """
+ This method should NOT be called unless you are really sure about
+ it. It is used inside the implementation of end_finally() in
+ pyopcode.py, and it's there so that it can be overridden by the
+ FlowObjSpace.
+ """
+ if self.is_w(w_obj, self.w_None):
+ return True
+ obj = self.interpclass_w(w_obj)
+ return isinstance(obj, RequiredClass)
+
def unpackiterable(self, w_iterable, expected_length=-1):
"""Unpack an iterable object into a real (interpreter-level) list.
Raise an OperationError(w_ValueError) if the length is wrong."""
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -600,16 +600,28 @@
block.cleanup(self) # the block knows how to clean up the value stack
def end_finally(self):
- # unlike CPython, when we reach this opcode the value stack has
- # always been set up as follows (topmost first):
- # [exception type or None]
- # [exception value or None]
- # [wrapped stack unroller ]
- self.popvalue() # ignore the exception type
- self.popvalue() # ignore the exception value
- w_unroller = self.popvalue()
- unroller = self.space.interpclass_w(w_unroller)
- return unroller
+ # unlike CPython, there are two statically distinct cases: the
+ # END_FINALLY might be closing an 'except' block or a 'finally'
+ # block. In the first case, the stack contains three items:
+ # [exception type we are now handling]
+ # [exception value we are now handling]
+ # [wrapped SApplicationException]
+ # In the case of a finally: block, the stack contains only one
+ # item (unlike CPython which can have 1, 2 or 3 items):
+ # [wrapped subclass of SuspendedUnroller]
+ w_top = self.popvalue()
+ # the following logic is a mess for the flow objspace,
+ # so we hide it specially in the space :-/
+ if self.space._check_constant_interp_w_or_w_None(SuspendedUnroller, w_top):
+ # case of a finally: block
+ unroller = self.space.interpclass_w(w_top)
+ return unroller
+ else:
+ # case of an except: block. We popped the exception type
+ self.popvalue() # Now we pop the exception value
+ unroller = self.space.interpclass_w(self.popvalue())
+ assert unroller is not None
+ return unroller
def BUILD_CLASS(self, oparg, next_instr):
w_methodsdict = self.popvalue()
@@ -939,17 +951,13 @@
# Implementation since 2.7a0: 62191 (introduce SETUP_WITH)
or self.pycode.magic >= 0xa0df2d1):
# implementation since 2.6a1: 62161 (WITH_CLEANUP optimization)
- self.popvalue()
- self.popvalue()
w_unroller = self.popvalue()
w_exitfunc = self.popvalue()
self.pushvalue(w_unroller)
- self.pushvalue(self.space.w_None)
- self.pushvalue(self.space.w_None)
elif self.pycode.magic >= 0xa0df28c:
# Implementation since 2.5a0: 62092 (changed WITH_CLEANUP opcode)
w_exitfunc = self.popvalue()
- w_unroller = self.peekvalue(2)
+ w_unroller = self.peekvalue(0)
else:
raise NotImplementedError("WITH_CLEANUP for CPython <= 2.4")
@@ -966,7 +974,7 @@
w_traceback)
if self.space.is_true(w_suppress):
# __exit__() returned True -> Swallow the exception.
- self.settopvalue(self.space.w_None, 2)
+ self.settopvalue(self.space.w_None)
else:
self.call_contextmanager_exit_function(
w_exitfunc,
@@ -1346,25 +1354,12 @@
_opname = 'SETUP_FINALLY'
handling_mask = -1 # handles every kind of SuspendedUnroller
- def cleanup(self, frame):
- # upon normal entry into the finally: part, the standard Python
- # bytecode pushes a single None for END_FINALLY. In our case we
- # always push three values into the stack: the wrapped ctlflowexc,
- # the exception value and the exception type (which are all None
- # here).
- self.cleanupstack(frame)
- # one None already pushed by the bytecode
- frame.pushvalue(frame.space.w_None)
- frame.pushvalue(frame.space.w_None)
-
def handle(self, frame, unroller):
# any abnormal reason for unrolling a finally: triggers the end of
# the block unrolling and the entering the finally: handler.
# see comments in cleanup().
self.cleanupstack(frame)
frame.pushvalue(frame.space.wrap(unroller))
- frame.pushvalue(frame.space.w_None)
- frame.pushvalue(frame.space.w_None)
return r_uint(self.handlerposition) # jump to the handler
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5068,6 +5068,7 @@
self.optimize_strunicode_loop(ops, expected)
def test_call_pure_vstring_const(self):
+ py.test.skip("implement me")
ops = """
[]
p0 = newstr(3)
diff --git a/pypy/module/__pypy__/interp_time.py b/pypy/module/__pypy__/interp_time.py
--- a/pypy/module/__pypy__/interp_time.py
+++ b/pypy/module/__pypy__/interp_time.py
@@ -1,5 +1,5 @@
from __future__ import with_statement
-import sys
+import os
from pypy.interpreter.error import exception_from_errno
from pypy.interpreter.gateway import unwrap_spec
@@ -7,11 +7,15 @@
from pypy.rpython.tool import rffi_platform
from pypy.translator.tool.cbuild import ExternalCompilationInfo
+if os.name == 'nt':
+ libraries = []
+else:
+ libraries = ["rt"]
class CConfig:
_compilation_info_ = ExternalCompilationInfo(
includes=["time.h"],
- libraries=["rt"],
+ libraries=libraries,
)
HAS_CLOCK_GETTIME = rffi_platform.Has('clock_gettime')
@@ -22,11 +26,6 @@
CLOCK_PROCESS_CPUTIME_ID = rffi_platform.DefinedConstantInteger("CLOCK_PROCESS_CPUTIME_ID")
CLOCK_THREAD_CPUTIME_ID = rffi_platform.DefinedConstantInteger("CLOCK_THREAD_CPUTIME_ID")
- TIMESPEC = rffi_platform.Struct("struct timespec", [
- ("tv_sec", rffi.TIME_T),
- ("tv_nsec", rffi.LONG),
- ])
-
cconfig = rffi_platform.configure(CConfig)
HAS_CLOCK_GETTIME = cconfig["HAS_CLOCK_GETTIME"]
@@ -37,29 +36,36 @@
CLOCK_PROCESS_CPUTIME_ID = cconfig["CLOCK_PROCESS_CPUTIME_ID"]
CLOCK_THREAD_CPUTIME_ID = cconfig["CLOCK_THREAD_CPUTIME_ID"]
-TIMESPEC = cconfig["TIMESPEC"]
+if HAS_CLOCK_GETTIME:
+ #redo it for timespec
+ CConfig.TIMESPEC = rffi_platform.Struct("struct timespec", [
+ ("tv_sec", rffi.TIME_T),
+ ("tv_nsec", rffi.LONG),
+ ])
+ cconfig = rffi_platform.configure(CConfig)
+ TIMESPEC = cconfig['TIMESPEC']
-c_clock_gettime = rffi.llexternal("clock_gettime",
- [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT,
- compilation_info=CConfig._compilation_info_, threadsafe=False
-)
-c_clock_getres = rffi.llexternal("clock_getres",
- [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT,
- compilation_info=CConfig._compilation_info_, threadsafe=False
-)
+ c_clock_gettime = rffi.llexternal("clock_gettime",
+ [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT,
+ compilation_info=CConfig._compilation_info_, threadsafe=False
+ )
+ c_clock_getres = rffi.llexternal("clock_getres",
+ [lltype.Signed, lltype.Ptr(TIMESPEC)], rffi.INT,
+ compilation_info=CConfig._compilation_info_, threadsafe=False
+ )
- at unwrap_spec(clk_id="c_int")
-def clock_gettime(space, clk_id):
- with lltype.scoped_alloc(TIMESPEC) as tp:
- ret = c_clock_gettime(clk_id, tp)
- if ret != 0:
- raise exception_from_errno(space, space.w_IOError)
- return space.wrap(tp.c_tv_sec + tp.c_tv_nsec * 1e-9)
+ @unwrap_spec(clk_id="c_int")
+ def clock_gettime(space, clk_id):
+ with lltype.scoped_alloc(TIMESPEC) as tp:
+ ret = c_clock_gettime(clk_id, tp)
+ if ret != 0:
+ raise exception_from_errno(space, space.w_IOError)
+ return space.wrap(tp.c_tv_sec + tp.c_tv_nsec * 1e-9)
- at unwrap_spec(clk_id="c_int")
-def clock_getres(space, clk_id):
- with lltype.scoped_alloc(TIMESPEC) as tp:
- ret = c_clock_getres(clk_id, tp)
- if ret != 0:
- raise exception_from_errno(space, space.w_IOError)
- return space.wrap(tp.c_tv_sec + tp.c_tv_nsec * 1e-9)
+ @unwrap_spec(clk_id="c_int")
+ def clock_getres(space, clk_id):
+ with lltype.scoped_alloc(TIMESPEC) as tp:
+ ret = c_clock_getres(clk_id, tp)
+ if ret != 0:
+ raise exception_from_errno(space, space.w_IOError)
+ return space.wrap(tp.c_tv_sec + tp.c_tv_nsec * 1e-9)
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
@@ -265,14 +265,6 @@
if option.runappdirect:
py.test.skip("works with internals of _file impl on py.py")
- import platform
- if platform.system() == 'Windows':
- # XXX This test crashes until someone implements something like
- # XXX verify_fd from
- # XXX http://hg.python.org/cpython/file/80ddbd822227/Modules/posixmodule.c#l434
- # XXX and adds it to fopen
- assert False
-
state = [0]
def read(fd, n=None):
if fd != 42:
@@ -286,7 +278,7 @@
return ''
os.read = read
stdin = W_File(cls.space)
- stdin.file_fdopen(42, "r", 1)
+ stdin.file_fdopen(42, 'rb', 1)
stdin.name = '<stdin>'
cls.w_stream = stdin
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -616,8 +616,9 @@
cli.send('foobar' * 70)
except timeout:
pass
- # test sendall() timeout
- raises(timeout, cli.sendall, 'foobar' * 70)
+ # test sendall() timeout, be sure to send data larger than the
+ # socket buffer
+ raises(timeout, cli.sendall, 'foobar' * 7000)
# done
cli.close()
t.close()
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -4,25 +4,50 @@
from pypy.interpreter.gateway import interp2app, ObjSpace
from pypy.interpreter.typedef import TypeDef
from pypy.rlib import jit
+from pypy.rlib.rshrinklist import AbstractShrinkList
+from pypy.rlib.objectmodel import specialize
import weakref
+class WRefShrinkList(AbstractShrinkList):
+ def must_keep(self, wref):
+ return wref() is not None
+
+
class WeakrefLifeline(W_Root):
- cached_weakref_index = -1
- cached_proxy_index = -1
+ cached_weakref = None
+ cached_proxy = None
+ other_refs_weak = None
def __init__(self, space):
self.space = space
- self.refs_weak = []
+
+ def append_wref_to(self, w_ref):
+ if self.other_refs_weak is None:
+ self.other_refs_weak = WRefShrinkList()
+ self.other_refs_weak.append(weakref.ref(w_ref))
+
+ @specialize.arg(1)
+ def traverse(self, callback, arg=None):
+ if self.cached_weakref is not None:
+ arg = callback(self, self.cached_weakref, arg)
+ if self.cached_proxy is not None:
+ arg = callback(self, self.cached_proxy, arg)
+ if self.other_refs_weak is not None:
+ for ref_w_ref in self.other_refs_weak.items():
+ arg = callback(self, ref_w_ref, arg)
+ return arg
+
+ def _clear_wref(self, wref, _):
+ w_ref = wref()
+ if w_ref is not None:
+ w_ref.clear()
def clear_all_weakrefs(self):
"""Clear all weakrefs. This is called when an app-level object has
a __del__, just before the app-level __del__ method is called.
"""
- for ref_w_ref in self.refs_weak:
- w_ref = ref_w_ref()
- if w_ref is not None:
- w_ref.clear()
+ self.traverse(WeakrefLifeline._clear_wref)
# Note that for no particular reason other than convenience,
# weakref callbacks are not invoked eagerly here. They are
# invoked by self.__del__() anyway.
@@ -30,49 +55,46 @@
def get_or_make_weakref(self, w_subtype, w_obj):
space = self.space
w_weakreftype = space.gettypeobject(W_Weakref.typedef)
- is_weakreftype = space.is_w(w_weakreftype, w_subtype)
- if is_weakreftype and self.cached_weakref_index >= 0:
- w_cached = self.refs_weak[self.cached_weakref_index]()
- if w_cached is not None:
- return w_cached
- else:
- self.cached_weakref_index = -1
- w_ref = space.allocate_instance(W_Weakref, w_subtype)
- index = len(self.refs_weak)
- W_Weakref.__init__(w_ref, space, w_obj, None)
- self.refs_weak.append(weakref.ref(w_ref))
- if is_weakreftype:
- self.cached_weakref_index = index
+ #
+ if space.is_w(w_weakreftype, w_subtype):
+ if self.cached_weakref is not None:
+ w_cached = self.cached_weakref()
+ if w_cached is not None:
+ return w_cached
+ w_ref = W_Weakref(space, w_obj, None)
+ self.cached_weakref = weakref.ref(w_ref)
+ else:
+ # subclass: cannot cache
+ w_ref = space.allocate_instance(W_Weakref, w_subtype)
+ W_Weakref.__init__(w_ref, space, w_obj, None)
+ self.append_wref_to(w_ref)
return w_ref
def get_or_make_proxy(self, w_obj):
space = self.space
- if self.cached_proxy_index >= 0:
- w_cached = self.refs_weak[self.cached_proxy_index]()
+ if self.cached_proxy is not None:
+ w_cached = self.cached_proxy()
if w_cached is not None:
return w_cached
- else:
- self.cached_proxy_index = -1
- index = len(self.refs_weak)
if space.is_true(space.callable(w_obj)):
w_proxy = W_CallableProxy(space, w_obj, None)
else:
w_proxy = W_Proxy(space, w_obj, None)
- self.refs_weak.append(weakref.ref(w_proxy))
- self.cached_proxy_index = index
+ self.cached_proxy = weakref.ref(w_proxy)
return w_proxy
def get_any_weakref(self, space):
- if self.cached_weakref_index != -1:
- w_ref = self.refs_weak[self.cached_weakref_index]()
+ if self.cached_weakref is not None:
+ w_ref = self.cached_weakref()
if w_ref is not None:
return w_ref
- w_weakreftype = space.gettypeobject(W_Weakref.typedef)
- for i in range(len(self.refs_weak)):
- w_ref = self.refs_weak[i]()
- if (w_ref is not None and
- space.is_true(space.isinstance(w_ref, w_weakreftype))):
- return w_ref
+ if self.other_refs_weak is not None:
+ w_weakreftype = space.gettypeobject(W_Weakref.typedef)
+ for wref in self.other_refs_weak.items():
+ w_ref = wref()
+ if (w_ref is not None and
+ space.is_true(space.isinstance(w_ref, w_weakreftype))):
+ return w_ref
return space.w_None
@@ -80,10 +102,10 @@
def __init__(self, space, oldlifeline=None):
self.space = space
- if oldlifeline is None:
- self.refs_weak = []
- else:
- self.refs_weak = oldlifeline.refs_weak
+ if oldlifeline is not None:
+ self.cached_weakref = oldlifeline.cached_weakref
+ self.cached_proxy = oldlifeline.cached_proxy
+ self.other_refs_weak = oldlifeline.other_refs_weak
def __del__(self):
"""This runs when the interp-level object goes away, and allows
@@ -91,8 +113,11 @@
callbacks even if there is no __del__ method on the interp-level
W_Root subclass implementing the object.
"""
- for i in range(len(self.refs_weak) - 1, -1, -1):
- w_ref = self.refs_weak[i]()
+ if self.other_refs_weak is None:
+ return
+ items = self.other_refs_weak.items()
+ for i in range(len(items)-1, -1, -1):
+ w_ref = items[i]()
if w_ref is not None and w_ref.w_callable is not None:
w_ref.enqueue_for_destruction(self.space,
W_WeakrefBase.activate_callback,
@@ -102,7 +127,7 @@
space = self.space
w_ref = space.allocate_instance(W_Weakref, w_subtype)
W_Weakref.__init__(w_ref, space, w_obj, w_callable)
- self.refs_weak.append(weakref.ref(w_ref))
+ self.append_wref_to(w_ref)
return w_ref
def make_proxy_with_callback(self, w_obj, w_callable):
@@ -111,7 +136,7 @@
w_proxy = W_CallableProxy(space, w_obj, w_callable)
else:
w_proxy = W_Proxy(space, w_obj, w_callable)
- self.refs_weak.append(weakref.ref(w_proxy))
+ self.append_wref_to(w_proxy)
return w_proxy
# ____________________________________________________________
@@ -247,30 +272,33 @@
)
+def _weakref_count(lifeline, wref, count):
+ if wref() is not None:
+ count += 1
+ return count
+
def getweakrefcount(space, w_obj):
"""Return the number of weak references to 'obj'."""
lifeline = w_obj.getweakref()
if lifeline is None:
return space.wrap(0)
else:
- result = 0
- for i in range(len(lifeline.refs_weak)):
- if lifeline.refs_weak[i]() is not None:
- result += 1
+ result = lifeline.traverse(_weakref_count, 0)
return space.wrap(result)
+def _get_weakrefs(lifeline, wref, result):
+ w_ref = wref()
+ if w_ref is not None:
+ result.append(w_ref)
+ return result
+
def getweakrefs(space, w_obj):
"""Return a list of all weak reference objects that point to 'obj'."""
+ result = []
lifeline = w_obj.getweakref()
- if lifeline is None:
- return space.newlist([])
- else:
- result = []
- for i in range(len(lifeline.refs_weak)):
- w_ref = lifeline.refs_weak[i]()
- if w_ref is not None:
- result.append(w_ref)
- return space.newlist(result)
+ if lifeline is not None:
+ lifeline.traverse(_get_weakrefs, result)
+ return space.newlist(result)
#_________________________________________________________________
# Proxy
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
@@ -26,6 +26,7 @@
from pypy.module.__builtin__.interp_classobj import W_ClassObject
from pypy.module.__builtin__.interp_memoryview import W_MemoryView
from pypy.rlib.entrypoint import entrypoint
+from pypy.rlib.rposix import is_valid_fd, validate_fd
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.objectmodel import specialize
from pypy.rlib.exports import export_struct
@@ -79,20 +80,39 @@
# FILE* interface
FILEP = rffi.COpaquePtr('FILE')
-fopen = rffi.llexternal('fopen', [CONST_STRING, CONST_STRING], FILEP)
-fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
-fwrite = rffi.llexternal('fwrite',
- [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, FILEP],
- rffi.SIZE_T)
-fread = rffi.llexternal('fread',
- [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, FILEP],
- rffi.SIZE_T)
-feof = rffi.llexternal('feof', [FILEP], rffi.INT)
+
if sys.platform == 'win32':
fileno = rffi.llexternal('_fileno', [FILEP], rffi.INT)
else:
fileno = rffi.llexternal('fileno', [FILEP], rffi.INT)
+fopen = rffi.llexternal('fopen', [CONST_STRING, CONST_STRING], FILEP)
+
+_fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
+def fclose(fp):
+ if not is_valid_fd(fileno(fp)):
+ return -1
+ return _fclose(fp)
+
+_fwrite = rffi.llexternal('fwrite',
+ [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, FILEP],
+ rffi.SIZE_T)
+def fwrite(buf, sz, n, fp):
+ validate_fd(fileno(fp))
+ return _fwrite(buf, sz, n, fp)
+
+_fread = rffi.llexternal('fread',
+ [rffi.VOIDP, rffi.SIZE_T, rffi.SIZE_T, FILEP],
+ rffi.SIZE_T)
+def fread(buf, sz, n, fp):
+ validate_fd(fileno(fp))
+ return _fread(buf, sz, n, fp)
+
+_feof = rffi.llexternal('feof', [FILEP], rffi.INT)
+def feof(fp):
+ validate_fd(fileno(fp))
+ return _feof(fp)
+
constant_names = """
Py_TPFLAGS_READY Py_TPFLAGS_READYING Py_TPFLAGS_HAVE_GETCHARBUFFER
diff --git a/pypy/module/math/test/test_math.py b/pypy/module/math/test/test_math.py
--- a/pypy/module/math/test/test_math.py
+++ b/pypy/module/math/test/test_math.py
@@ -271,5 +271,6 @@
assert math.trunc(foo()) == "truncated"
def test_copysign_nan(self):
+ skip('sign of nan is undefined')
import math
assert math.copysign(1.0, float('-nan')) == -1.0
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -233,12 +233,15 @@
assert a[1] == 0
def test_signbit(self):
- from _numpypy import signbit, copysign
+ from _numpypy import signbit
- assert (signbit([0, 0.0, 1, 1.0, float('inf'), float('nan')]) ==
- [False, False, False, False, False, False]).all()
- assert (signbit([-0, -0.0, -1, -1.0, float('-inf'), -float('nan'), float('-nan')]) ==
- [False, True, True, True, True, True, True]).all()
+ assert (signbit([0, 0.0, 1, 1.0, float('inf')]) ==
+ [False, False, False, False, False]).all()
+ assert (signbit([-0, -0.0, -1, -1.0, float('-inf')]) ==
+ [False, True, True, True, True]).all()
+ skip('sign of nan is non-determinant')
+ assert (signbit([float('nan'), float('-nan'), -float('nan')]) ==
+ [False, True, True]).all()
def test_reciporocal(self):
from _numpypy import array, reciprocal
@@ -267,8 +270,8 @@
assert ([ninf, -1.0, -1.0, -1.0, 0.0, 1.0, 2.0, 1.0, inf] == ceil(a)).all()
assert ([ninf, -1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 0.0, inf] == trunc(a)).all()
assert all([math.isnan(f(float("nan"))) for f in floor, ceil, trunc])
- assert all([math.copysign(1, f(float("nan"))) == 1 for f in floor, ceil, trunc])
- assert all([math.copysign(1, f(float("-nan"))) == -1 for f in floor, ceil, trunc])
+ assert all([math.copysign(1, f(abs(float("nan")))) == 1 for f in floor, ceil, trunc])
+ assert all([math.copysign(1, f(-abs(float("nan")))) == -1 for f in floor, ceil, trunc])
def test_copysign(self):
from _numpypy import array, copysign
diff --git a/pypy/module/mmap/test/test_mmap.py b/pypy/module/mmap/test/test_mmap.py
--- a/pypy/module/mmap/test/test_mmap.py
+++ b/pypy/module/mmap/test/test_mmap.py
@@ -548,6 +548,8 @@
assert len(b) == 6
assert b[3] == "b"
assert b[:] == "foobar"
+ m.close()
+ f.close()
def test_offset(self):
from mmap import mmap, ALLOCATIONGRANULARITY
diff --git a/pypy/module/rctime/test/test_rctime.py b/pypy/module/rctime/test/test_rctime.py
--- a/pypy/module/rctime/test/test_rctime.py
+++ b/pypy/module/rctime/test/test_rctime.py
@@ -213,6 +213,7 @@
def test_strftime(self):
import time as rctime
+ import os
t = rctime.time()
tt = rctime.gmtime(t)
@@ -228,6 +229,14 @@
exp = '2000 01 01 00 00 00 1 001'
assert rctime.strftime("%Y %m %d %H %M %S %w %j", (0,)*9) == exp
+ # Guard against invalid/non-supported format string
+ # so that Python don't crash (Windows crashes when the format string
+ # input to [w]strftime is not kosher.
+ if os.name == 'nt':
+ raises(ValueError, rctime.strftime, '%f')
+ else:
+ assert rctime.strftime('%f') == '%f'
+
def test_strftime_ext(self):
import time as rctime
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -15,7 +15,8 @@
def setup():
for key, value in cpy_signal.__dict__.items():
- if key.startswith('SIG') and is_valid_int(value):
+ if (key.startswith('SIG') or key.startswith('CTRL_')) and \
+ is_valid_int(value):
globals()[key] = value
yield key
@@ -23,6 +24,10 @@
SIG_DFL = cpy_signal.SIG_DFL
SIG_IGN = cpy_signal.SIG_IGN
signal_names = list(setup())
+signal_values = [globals()[key] for key in signal_names]
+signal_values = {}
+for key in signal_names:
+ signal_values[globals()[key]] = None
includes = ['stdlib.h', 'src/signals.h']
if sys.platform != 'win32':
@@ -242,9 +247,11 @@
return space.w_None
def check_signum(space, signum):
- if signum < 1 or signum >= NSIG:
- raise OperationError(space.w_ValueError,
- space.wrap("signal number out of range"))
+ if signum in signal_values:
+ return
+ raise OperationError(space.w_ValueError,
+ space.wrap("invalid signal value"))
+
@jit.dont_look_inside
@unwrap_spec(signum=int)
diff --git a/pypy/module/signal/test/test_interp_signal.py b/pypy/module/signal/test/test_interp_signal.py
--- a/pypy/module/signal/test/test_interp_signal.py
+++ b/pypy/module/signal/test/test_interp_signal.py
@@ -6,6 +6,8 @@
def setup_module(mod):
if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
py.test.skip("requires os.kill() and os.getpid()")
+ if not hasattr(interp_signal, 'SIGUSR1'):
+ py.test.skip("requires SIGUSR1 in signal")
def check(expected):
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -8,6 +8,8 @@
def setup_class(cls):
if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
py.test.skip("requires os.kill() and os.getpid()")
+ if not hasattr(cpy_signal, 'SIGUSR1'):
+ py.test.skip("requires SIGUSR1 in signal")
cls.space = gettestobjspace(usemodules=['signal'])
def test_checksignals(self):
@@ -36,8 +38,6 @@
class AppTestSignal:
def setup_class(cls):
- if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
- py.test.skip("requires os.kill() and os.getpid()")
space = gettestobjspace(usemodules=['signal'])
cls.space = space
cls.w_signal = space.appexec([], "(): import signal; return signal")
@@ -45,64 +45,72 @@
def test_exported_names(self):
self.signal.__dict__ # crashes if the interpleveldefs are invalid
- def test_usr1(self):
- import types, posix
+ def test_basics(self):
+ import types, os
+ if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
+ skip("requires os.kill() and os.getpid()")
signal = self.signal # the signal module to test
+ if hasattr(signal,'SIGUSR1'):
+ signum = signal.SIGUSR1
+ else:
+ signum = signal.CTRL_BREAK_EVENT
received = []
def myhandler(signum, frame):
assert isinstance(frame, types.FrameType)
received.append(signum)
- signal.signal(signal.SIGUSR1, myhandler)
+ signal.signal(signum, myhandler)
- posix.kill(posix.getpid(), signal.SIGUSR1)
+ print dir(os)
+
+ os.kill(os.getpid(), signum)
# the signal should be delivered to the handler immediately
- assert received == [signal.SIGUSR1]
+ assert received == [signum]
del received[:]
- posix.kill(posix.getpid(), signal.SIGUSR1)
+ os.kill(os.getpid(), signum)
# the signal should be delivered to the handler immediately
- assert received == [signal.SIGUSR1]
+ assert received == [signum]
del received[:]
- signal.signal(signal.SIGUSR1, signal.SIG_IGN)
+ signal.signal(signum, signal.SIG_IGN)
- posix.kill(posix.getpid(), signal.SIGUSR1)
+ os.kill(os.getpid(), signum)
for i in range(10000):
# wait a bit - signal should not arrive
if received:
break
assert received == []
- signal.signal(signal.SIGUSR1, signal.SIG_DFL)
+ signal.signal(signum, signal.SIG_DFL)
def test_default_return(self):
"""
Test that signal.signal returns SIG_DFL if that is the current handler.
"""
- from signal import signal, SIGUSR1, SIG_DFL, SIG_IGN
+ from signal import signal, SIGINT, SIG_DFL, SIG_IGN
try:
for handler in SIG_DFL, SIG_IGN, lambda *a: None:
- signal(SIGUSR1, SIG_DFL)
- assert signal(SIGUSR1, handler) == SIG_DFL
+ signal(SIGINT, SIG_DFL)
+ assert signal(SIGINT, handler) == SIG_DFL
finally:
- signal(SIGUSR1, SIG_DFL)
+ signal(SIGINT, SIG_DFL)
def test_ignore_return(self):
"""
Test that signal.signal returns SIG_IGN if that is the current handler.
"""
- from signal import signal, SIGUSR1, SIG_DFL, SIG_IGN
+ from signal import signal, SIGINT, SIG_DFL, SIG_IGN
try:
for handler in SIG_DFL, SIG_IGN, lambda *a: None:
- signal(SIGUSR1, SIG_IGN)
- assert signal(SIGUSR1, handler) == SIG_IGN
+ signal(SIGINT, SIG_IGN)
+ assert signal(SIGINT, handler) == SIG_IGN
finally:
- signal(SIGUSR1, SIG_DFL)
+ signal(SIGINT, SIG_DFL)
def test_obj_return(self):
@@ -110,43 +118,47 @@
Test that signal.signal returns a Python object if one is the current
handler.
"""
- from signal import signal, SIGUSR1, SIG_DFL, SIG_IGN
+ from signal import signal, SIGINT, SIG_DFL, SIG_IGN
def installed(*a):
pass
try:
for handler in SIG_DFL, SIG_IGN, lambda *a: None:
- signal(SIGUSR1, installed)
- assert signal(SIGUSR1, handler) is installed
+ signal(SIGINT, installed)
+ assert signal(SIGINT, handler) is installed
finally:
- signal(SIGUSR1, SIG_DFL)
+ signal(SIGINT, SIG_DFL)
def test_getsignal(self):
"""
Test that signal.getsignal returns the currently installed handler.
"""
- from signal import getsignal, signal, SIGUSR1, SIG_DFL, SIG_IGN
+ from signal import getsignal, signal, SIGINT, SIG_DFL, SIG_IGN
def handler(*a):
pass
try:
- assert getsignal(SIGUSR1) == SIG_DFL
- signal(SIGUSR1, SIG_DFL)
- assert getsignal(SIGUSR1) == SIG_DFL
- signal(SIGUSR1, SIG_IGN)
- assert getsignal(SIGUSR1) == SIG_IGN
- signal(SIGUSR1, handler)
- assert getsignal(SIGUSR1) is handler
+ assert getsignal(SIGINT) == SIG_DFL
+ signal(SIGINT, SIG_DFL)
+ assert getsignal(SIGINT) == SIG_DFL
+ signal(SIGINT, SIG_IGN)
+ assert getsignal(SIGINT) == SIG_IGN
+ signal(SIGINT, handler)
+ assert getsignal(SIGINT) is handler
finally:
- signal(SIGUSR1, SIG_DFL)
+ signal(SIGINT, SIG_DFL)
raises(ValueError, getsignal, 4444)
raises(ValueError, signal, 4444, lambda *args: None)
+ raises(ValueError, signal, 42, lambda *args: None)
def test_alarm(self):
- from signal import alarm, signal, SIG_DFL, SIGALRM
+ try:
+ from signal import alarm, signal, SIG_DFL, SIGALRM
+ except:
+ skip('no alarm on this platform')
import time
l = []
def handler(*a):
@@ -163,10 +175,13 @@
signal(SIGALRM, SIG_DFL)
def test_set_wakeup_fd(self):
- import signal, posix, fcntl
+ try:
+ import signal, posix, fcntl
+ except ImportError:
+ skip('cannot import posix or fcntl')
def myhandler(signum, frame):
pass
- signal.signal(signal.SIGUSR1, myhandler)
+ signal.signal(signal.SIGINT, myhandler)
#
def cannot_read():
try:
@@ -187,17 +202,19 @@
old_wakeup = signal.set_wakeup_fd(fd_write)
try:
cannot_read()
- posix.kill(posix.getpid(), signal.SIGUSR1)
+ posix.kill(posix.getpid(), signal.SIGINT)
res = posix.read(fd_read, 1)
assert res == '\x00'
cannot_read()
finally:
old_wakeup = signal.set_wakeup_fd(old_wakeup)
#
- signal.signal(signal.SIGUSR1, signal.SIG_DFL)
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
def test_siginterrupt(self):
import signal, os, time
+ if not hasattr(signal, 'siginterrupt'):
+ skip('non siginterrupt in signal')
signum = signal.SIGUSR1
def readpipe_is_not_interrupted():
# from CPython's test_signal.readpipe_interrupted()
diff --git a/pypy/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -18,7 +18,7 @@
'allocate_lock': 'os_lock.allocate_lock',
'allocate': 'os_lock.allocate_lock', # obsolete synonym
'LockType': 'os_lock.Lock',
- #'_local': 'os_local.Local', # only if 'rweakref'
+ '_local': 'os_local.Local',
'error': 'space.fromcache(error.Cache).w_error',
}
@@ -34,8 +34,3 @@
from pypy.module.posix.interp_posix import add_fork_hook
from pypy.module.thread.os_thread import reinit_threads
add_fork_hook('child', reinit_threads)
-
- def setup_after_space_initialization(self):
- """NOT_RPYTHON"""
- if self.space.config.translation.rweakref:
- self.extra_interpdef('_local', 'os_local.Local')
diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py
--- a/pypy/module/thread/os_local.py
+++ b/pypy/module/thread/os_local.py
@@ -1,16 +1,26 @@
-from pypy.rlib.rweakref import RWeakKeyDictionary
+import weakref
+from pypy.rlib import jit
from pypy.interpreter.baseobjspace import Wrappable, W_Root
from pypy.interpreter.executioncontext import ExecutionContext
from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty,
descr_get_dict)
+from pypy.rlib.rshrinklist import AbstractShrinkList
+
+class WRefShrinkList(AbstractShrinkList):
+ def must_keep(self, wref):
+ return wref() is not None
+
+
+ExecutionContext._thread_local_objs = None
class Local(Wrappable):
"""Thread-local data"""
+ @jit.dont_look_inside
def __init__(self, space, initargs):
self.initargs = initargs
- self.dicts = RWeakKeyDictionary(ExecutionContext, W_Root)
+ self.dicts = {} # mapping ExecutionContexts to the wraped dict
# The app-level __init__() will be called by the general
# instance-creation logic. It causes getdict() to be
# immediately called. If we don't prepare and set a w_dict
@@ -18,26 +28,42 @@
# to call __init__() a second time.
ec = space.getexecutioncontext()
w_dict = space.newdict(instance=True)
- self.dicts.set(ec, w_dict)
+ self.dicts[ec] = w_dict
+ self._register_in_ec(ec)
+
+ def _register_in_ec(self, ec):
+ if not ec.space.config.translation.rweakref:
+ return # without weakrefs, works but 'dicts' is never cleared
+ if ec._thread_local_objs is None:
+ ec._thread_local_objs = WRefShrinkList()
+ ec._thread_local_objs.append(weakref.ref(self))
+
+ @jit.dont_look_inside
+ def create_new_dict(self, ec):
+ # create a new dict for this thread
+ space = ec.space
+ w_dict = space.newdict(instance=True)
+ self.dicts[ec] = w_dict
+ # call __init__
+ try:
+ w_self = space.wrap(self)
+ w_type = space.type(w_self)
+ w_init = space.getattr(w_type, space.wrap("__init__"))
+ space.call_obj_args(w_init, w_self, self.initargs)
+ except:
+ # failed, forget w_dict and propagate the exception
+ del self.dicts[ec]
+ raise
+ # ready
+ self._register_in_ec(ec)
+ return w_dict
def getdict(self, space):
ec = space.getexecutioncontext()
- w_dict = self.dicts.get(ec)
- if w_dict is None:
- # create a new dict for this thread
- w_dict = space.newdict(instance=True)
- self.dicts.set(ec, w_dict)
- # call __init__
- try:
- w_self = space.wrap(self)
- w_type = space.type(w_self)
- w_init = space.getattr(w_type, space.wrap("__init__"))
- space.call_obj_args(w_init, w_self, self.initargs)
- except:
- # failed, forget w_dict and propagate the exception
- self.dicts.set(ec, None)
- raise
- # ready
+ try:
+ w_dict = self.dicts[ec]
+ except KeyError:
+ w_dict = self.create_new_dict(ec)
return w_dict
def descr_local__new__(space, w_subtype, __args__):
@@ -55,3 +81,13 @@
__init__ = interp2app(Local.descr_local__init__),
__dict__ = GetSetProperty(descr_get_dict, cls=Local),
)
+
+def thread_is_stopping(ec):
+ tlobjs = ec._thread_local_objs
+ if tlobjs is None:
+ return
+ ec._thread_local_objs = None
+ for wref in tlobjs.items():
+ local = wref()
+ if local is not None:
+ del local.dicts[ec]
diff --git a/pypy/module/thread/threadlocals.py b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -54,4 +54,8 @@
def leave_thread(self, space):
"Notification that the current thread is about to stop."
- self.setvalue(None)
+ from pypy.module.thread.os_local import thread_is_stopping
+ try:
+ thread_is_stopping(self.getvalue())
+ finally:
+ self.setvalue(None)
diff --git a/pypy/objspace/flow/objspace.py b/pypy/objspace/flow/objspace.py
--- a/pypy/objspace/flow/objspace.py
+++ b/pypy/objspace/flow/objspace.py
@@ -204,6 +204,14 @@
return obj
return None
+ def _check_constant_interp_w_or_w_None(self, RequiredClass, w_obj):
+ """
+ WARNING: this implementation is not complete at all. It's just enough
+ to be used by end_finally() inside pyopcode.py.
+ """
+ return w_obj == self.w_None or (isinstance(w_obj, Constant) and
+ isinstance(w_obj.value, RequiredClass))
+
def getexecutioncontext(self):
return getattr(self, 'executioncontext', None)
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -413,8 +413,8 @@
'retrace_limit': 'how many times we can try retracing before giving up',
'max_retrace_guards': 'number of extra guards a retrace can cause',
'max_unroll_loops': 'number of extra unrollings a loop can cause',
- 'enable_opts': 'INTERNAL USE ONLY: optimizations to enable, or all = %s' %
- ENABLE_ALL_OPTS,
+ 'enable_opts': 'INTERNAL USE ONLY (MAY NOT WORK OR LEAD TO CRASHES): '
+ 'optimizations to enable, or all = %s' % ENABLE_ALL_OPTS,
}
PARAMETERS = {'threshold': 1039, # just above 1024, prime
diff --git a/pypy/rlib/rarithmetic.py b/pypy/rlib/rarithmetic.py
--- a/pypy/rlib/rarithmetic.py
+++ b/pypy/rlib/rarithmetic.py
@@ -71,7 +71,7 @@
# used in tests for ctypes and for genc and friends
# to handle the win64 special case:
-is_emulated_long = _long_typecode <> 'l'
+is_emulated_long = _long_typecode != 'l'
LONG_BIT = _get_long_bit()
LONG_MASK = (2**LONG_BIT)-1
diff --git a/pypy/rlib/rmmap.py b/pypy/rlib/rmmap.py
--- a/pypy/rlib/rmmap.py
+++ b/pypy/rlib/rmmap.py
@@ -739,14 +739,35 @@
# assume -1 and 0 both mean invalid file descriptor
# to 'anonymously' map memory.
if fileno != -1 and fileno != 0:
- fh = rwin32._get_osfhandle(fileno)
- if fh == INVALID_HANDLE:
- errno = rposix.get_errno()
- raise OSError(errno, os.strerror(errno))
+ fh = rwin32.get_osfhandle(fileno)
# Win9x appears to need us seeked to zero
# SEEK_SET = 0
# libc._lseek(fileno, 0, SEEK_SET)
+ # check file size
+ try:
+ low, high = _get_file_size(fh)
+ except OSError:
+ pass # ignore non-seeking files and errors and trust map_size
+ else:
+ if not high and low <= sys.maxint:
+ size = low
+ else:
+ # not so sure if the signed/unsigned strictness is a good idea:
+ high = rffi.cast(lltype.Unsigned, high)
+ low = rffi.cast(lltype.Unsigned, low)
+ size = (high << 32) + low
+ size = rffi.cast(lltype.Signed, size)
+ if map_size == 0:
+ if offset > size:
+ raise RValueError(
+ "mmap offset is greater than file size")
+ map_size = int(size - offset)
+ if map_size != size - offset:
+ raise RValueError("mmap length is too large")
+ elif offset + map_size > size:
+ raise RValueError("mmap length is greater than file size")
+
m = MMap(access, offset)
m.file_handle = INVALID_HANDLE
m.map_handle = INVALID_HANDLE
diff --git a/pypy/rlib/rposix.py b/pypy/rlib/rposix.py
--- a/pypy/rlib/rposix.py
+++ b/pypy/rlib/rposix.py
@@ -98,16 +98,16 @@
_set_errno(rffi.cast(INT, errno))
if os.name == 'nt':
- _validate_fd = rffi.llexternal(
+ is_valid_fd = rffi.llexternal(
"_PyVerify_fd", [rffi.INT], rffi.INT,
compilation_info=errno_eci,
)
@jit.dont_look_inside
def validate_fd(fd):
- if not _validate_fd(fd):
+ if not is_valid_fd(fd):
raise OSError(get_errno(), 'Bad file descriptor')
else:
- def _validate_fd(fd):
+ def is_valid_fd(fd):
return 1
def validate_fd(fd):
@@ -117,7 +117,8 @@
# this behaves like os.closerange() from Python 2.6.
for fd in xrange(fd_low, fd_high):
try:
- os.close(fd)
+ if is_valid_fd(fd):
+ os.close(fd)
except OSError:
pass
diff --git a/pypy/rlib/rshrinklist.py b/pypy/rlib/rshrinklist.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/rshrinklist.py
@@ -0,0 +1,34 @@
+
+class AbstractShrinkList(object):
+ """A mixin base class. You should subclass it and add a method
+ must_keep(). Behaves like a list with the method append(), and
+ you can read *for reading* the list of items by calling items().
+ The twist is that occasionally append() will throw away the
+ items for which must_keep() returns False. (It does so without
+ changing the order.)
+ """
+ _mixin_ = True
+
+ def __init__(self):
+ self._list = []
+ self._next_shrink = 16
+
+ def append(self, x):
+ self._do_shrink()
+ self._list.append(x)
+
+ def items(self):
+ return self._list
+
+ def _do_shrink(self):
+ if len(self._list) >= self._next_shrink:
+ rest = 0
+ for x in self._list:
+ if self.must_keep(x):
+ self._list[rest] = x
+ rest += 1
+ del self._list[rest:]
+ self._next_shrink = 16 + 2 * rest
+
+ def must_keep(self, x):
+ raise NotImplementedError
diff --git a/pypy/rlib/rwin32.py b/pypy/rlib/rwin32.py
--- a/pypy/rlib/rwin32.py
+++ b/pypy/rlib/rwin32.py
@@ -8,6 +8,7 @@
from pypy.translator.platform import CompilationError
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.rposix import validate_fd
from pypy.rlib import jit
import os, sys, errno
@@ -78,6 +79,7 @@
for name in """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM
MAX_PATH
WAIT_OBJECT_0 WAIT_TIMEOUT INFINITE
+ ERROR_INVALID_HANDLE
""".split():
locals()[name] = rffi_platform.ConstantInteger(name)
@@ -126,6 +128,13 @@
_get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], HANDLE)
+ def get_osfhandle(fd):
+ validate_fd(fd)
+ handle = _get_osfhandle(fd)
+ if handle == INVALID_HANDLE_VALUE:
+ raise WindowsError(ERROR_INVALID_HANDLE, "Invalid file handle")
+ return handle
+
def build_winerror_to_errno():
"""Build a dictionary mapping windows error numbers to POSIX errno.
The function returns the dict, and the default value for codes not
diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py
--- a/pypy/rlib/streamio.py
+++ b/pypy/rlib/streamio.py
@@ -175,24 +175,23 @@
if sys.platform == "win32":
- from pypy.rlib import rwin32
+ from pypy.rlib.rwin32 import BOOL, HANDLE, get_osfhandle, GetLastError
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rpython.lltypesystem import rffi
- import errno
_eci = ExternalCompilationInfo()
- _get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], rffi.LONG,
- compilation_info=_eci)
_setmode = rffi.llexternal('_setmode', [rffi.INT, rffi.INT], rffi.INT,
compilation_info=_eci)
- SetEndOfFile = rffi.llexternal('SetEndOfFile', [rffi.LONG], rwin32.BOOL,
+ SetEndOfFile = rffi.llexternal('SetEndOfFile', [HANDLE], BOOL,
compilation_info=_eci)
# HACK: These implementations are specific to MSVCRT and the C backend.
# When generating on CLI or JVM, these are patched out.
# See PyPyTarget.target() in targetpypystandalone.py
def _setfd_binary(fd):
- _setmode(fd, os.O_BINARY)
+ #Allow this to succeed on invalid fd's
+ if rposix.is_valid_fd(fd):
+ _setmode(fd, os.O_BINARY)
def ftruncate_win32(fd, size):
curpos = os.lseek(fd, 0, 1)
@@ -200,11 +199,9 @@
# move to the position to be truncated
os.lseek(fd, size, 0)
# Truncate. Note that this may grow the file!
- handle = _get_osfhandle(fd)
- if handle == -1:
- raise OSError(errno.EBADF, "Invalid file handle")
+ handle = get_osfhandle(fd)
if not SetEndOfFile(handle):
- raise WindowsError(rwin32.GetLastError(),
+ raise WindowsError(GetLastError(),
"Could not truncate file")
finally:
# we restore the file pointer position in any case
diff --git a/pypy/rlib/test/test_rmmap.py b/pypy/rlib/test/test_rmmap.py
--- a/pypy/rlib/test/test_rmmap.py
+++ b/pypy/rlib/test/test_rmmap.py
@@ -33,8 +33,6 @@
interpret(f, [])
def test_file_size(self):
- if os.name == "nt":
- skip("Only Unix checks file size")
def func(no):
try:
@@ -433,15 +431,16 @@
def test_windows_crasher_1(self):
if sys.platform != "win32":
skip("Windows-only test")
-
- m = mmap.mmap(-1, 1000, tagname="foo")
- # same tagname, but larger size
- try:
- m2 = mmap.mmap(-1, 5000, tagname="foo")
- m2.getitem(4500)
- except WindowsError:
- pass
- m.close()
+ def func():
+ m = mmap.mmap(-1, 1000, tagname="foo")
+ # same tagname, but larger size
+ try:
+ m2 = mmap.mmap(-1, 5000, tagname="foo")
+ m2.getitem(4500)
+ except WindowsError:
+ pass
+ m.close()
+ interpret(func, [])
def test_windows_crasher_2(self):
if sys.platform != "win32":
diff --git a/pypy/rlib/test/test_rposix.py b/pypy/rlib/test/test_rposix.py
--- a/pypy/rlib/test/test_rposix.py
+++ b/pypy/rlib/test/test_rposix.py
@@ -132,14 +132,12 @@
except Exception:
pass
- def test_validate_fd(self):
+ def test_is_valid_fd(self):
if os.name != 'nt':
skip('relevant for windows only')
- assert rposix._validate_fd(0) == 1
+ assert rposix.is_valid_fd(0) == 1
fid = open(str(udir.join('validate_test.txt')), 'w')
fd = fid.fileno()
- assert rposix._validate_fd(fd) == 1
+ assert rposix.is_valid_fd(fd) == 1
fid.close()
- assert rposix._validate_fd(fd) == 0
-
-
+ assert rposix.is_valid_fd(fd) == 0
diff --git a/pypy/rlib/test/test_rshrinklist.py b/pypy/rlib/test/test_rshrinklist.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/test/test_rshrinklist.py
@@ -0,0 +1,30 @@
+from pypy.rlib.rshrinklist import AbstractShrinkList
+
+class Item:
+ alive = True
+
+class ItemList(AbstractShrinkList):
+ def must_keep(self, x):
+ return x.alive
+
+def test_simple():
+ l = ItemList()
+ l2 = [Item() for i in range(150)]
+ for x in l2:
+ l.append(x)
+ assert l.items() == l2
+ #
+ for x in l2[::2]:
+ x.alive = False
+ l3 = [Item() for i in range(150 + 16)]
+ for x in l3:
+ l.append(x)
+ assert l.items() == l2[1::2] + l3 # keeps the order
+
+def test_append_dead_items():
+ l = ItemList()
+ for i in range(150):
+ x = Item()
+ l.append(x)
+ x.alive = False
+ assert len(l.items()) <= 16
diff --git a/pypy/rlib/test/test_rweakkeydict.py b/pypy/rlib/test/test_rweakkeydict.py
--- a/pypy/rlib/test/test_rweakkeydict.py
+++ b/pypy/rlib/test/test_rweakkeydict.py
@@ -135,3 +135,32 @@
d = RWeakKeyDictionary(KX, VY)
d.set(KX(), VX())
py.test.raises(Exception, interpret, g, [1])
+
+
+def test_rpython_free_values():
+ import py; py.test.skip("XXX not implemented, messy")
+ class VXDel:
+ def __del__(self):
+ state.freed.append(1)
+ class State:
+ pass
+ state = State()
+ state.freed = []
+ #
+ def add_me():
+ k = KX()
+ v = VXDel()
+ d = RWeakKeyDictionary(KX, VXDel)
+ d.set(k, v)
+ return d
+ def f():
+ del state.freed[:]
+ d = add_me()
+ rgc.collect()
+ # we want the dictionary to be really empty here. It's hard to
+ # ensure in the current implementation after just one collect(),
+ # but at least two collects should be enough.
+ rgc.collect()
+ return len(state.freed)
+ assert f() == 1
+ assert interpret(f, []) == 1
diff --git a/pypy/rlib/test/test_rwin32.py b/pypy/rlib/test/test_rwin32.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/test/test_rwin32.py
@@ -0,0 +1,28 @@
+import os
+if os.name != 'nt':
+ skip('tests for win32 only')
+
+from pypy.rlib import rwin32
+from pypy.tool.udir import udir
+
+
+def test_get_osfhandle():
+ fid = open(str(udir.join('validate_test.txt')), 'w')
+ fd = fid.fileno()
+ rwin32.get_osfhandle(fd)
+ fid.close()
+ raises(OSError, rwin32.get_osfhandle, fd)
+ rwin32.get_osfhandle(0)
+
+def test_get_osfhandle_raising():
+ #try to test what kind of exception get_osfhandle raises w/out fd validation
+ skip('Crashes python')
+ fid = open(str(udir.join('validate_test.txt')), 'w')
+ fd = fid.fileno()
+ fid.close()
+ def validate_fd(fd):
+ return 1
+ _validate_fd = rwin32.validate_fd
+ rwin32.validate_fd = validate_fd
+ raises(WindowsError, rwin32.get_osfhandle, fd)
+ rwin32.validate_fd = _validate_fd
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -152,7 +152,8 @@
etype = frame.op_direct_call(exdata.fn_type_of_exc_inst, evalue)
if etype == klass:
return cls
- raise ValueError, "couldn't match exception"
+ raise ValueError("couldn't match exception, maybe it"
+ " has RPython attributes like OSError?")
def get_transformed_exc_data(self, graph):
if hasattr(graph, 'exceptiontransformed'):
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -397,6 +397,7 @@
os_dup = self.llexternal(underscore_on_windows+'dup', [rffi.INT], rffi.INT)
def dup_llimpl(fd):
+ rposix.validate_fd(fd)
newfd = rffi.cast(lltype.Signed, os_dup(rffi.cast(rffi.INT, fd)))
if newfd == -1:
raise OSError(rposix.get_errno(), "dup failed")
@@ -411,6 +412,7 @@
[rffi.INT, rffi.INT], rffi.INT)
def dup2_llimpl(fd, newfd):
+ rposix.validate_fd(fd)
error = rffi.cast(lltype.Signed, os_dup2(rffi.cast(rffi.INT, fd),
rffi.cast(rffi.INT, newfd)))
if error == -1:
@@ -891,6 +893,7 @@
def os_read_llimpl(fd, count):
if count < 0:
raise OSError(errno.EINVAL, None)
+ rposix.validate_fd(fd)
raw_buf, gc_buf = rffi.alloc_buffer(count)
try:
void_buf = rffi.cast(rffi.VOIDP, raw_buf)
@@ -916,6 +919,7 @@
def os_write_llimpl(fd, data):
count = len(data)
+ rposix.validate_fd(fd)
buf = rffi.get_nonmovingbuffer(data)
try:
written = rffi.cast(lltype.Signed, os_write(
@@ -940,6 +944,7 @@
rffi.INT, threadsafe=False)
def close_llimpl(fd):
+ rposix.validate_fd(fd)
error = rffi.cast(lltype.Signed, os_close(rffi.cast(rffi.INT, fd)))
if error == -1:
raise OSError(rposix.get_errno(), "close failed")
@@ -972,9 +977,10 @@
os_lseek = self.llexternal(funcname,
[rffi.INT, rffi.LONGLONG, rffi.INT],
- rffi.LONGLONG)
+ rffi.LONGLONG, macro=True)
def lseek_llimpl(fd, pos, how):
+ rposix.validate_fd(fd)
how = fix_seek_arg(how)
res = os_lseek(rffi.cast(rffi.INT, fd),
rffi.cast(rffi.LONGLONG, pos),
@@ -1000,6 +1006,7 @@
[rffi.INT, rffi.LONGLONG], rffi.INT)
def ftruncate_llimpl(fd, length):
+ rposix.validate_fd(fd)
res = rffi.cast(rffi.LONG,
os_ftruncate(rffi.cast(rffi.INT, fd),
rffi.cast(rffi.LONGLONG, length)))
@@ -1018,6 +1025,7 @@
os_fsync = self.llexternal('_commit', [rffi.INT], rffi.INT)
def fsync_llimpl(fd):
+ rposix.validate_fd(fd)
res = rffi.cast(rffi.SIGNED, os_fsync(rffi.cast(rffi.INT, fd)))
if res < 0:
raise OSError(rposix.get_errno(), "fsync failed")
@@ -1030,6 +1038,7 @@
os_fdatasync = self.llexternal('fdatasync', [rffi.INT], rffi.INT)
def fdatasync_llimpl(fd):
+ rposix.validate_fd(fd)
res = rffi.cast(rffi.SIGNED, os_fdatasync(rffi.cast(rffi.INT, fd)))
if res < 0:
raise OSError(rposix.get_errno(), "fdatasync failed")
@@ -1042,6 +1051,7 @@
os_fchdir = self.llexternal('fchdir', [rffi.INT], rffi.INT)
def fchdir_llimpl(fd):
+ rposix.validate_fd(fd)
res = rffi.cast(rffi.SIGNED, os_fchdir(rffi.cast(rffi.INT, fd)))
if res < 0:
raise OSError(rposix.get_errno(), "fchdir failed")
@@ -1357,6 +1367,7 @@
os_isatty = self.llexternal(underscore_on_windows+'isatty', [rffi.INT], rffi.INT)
def isatty_llimpl(fd):
+ rposix.validate_fd(fd)
res = rffi.cast(lltype.Signed, os_isatty(rffi.cast(rffi.INT, fd)))
return res != 0
@@ -1534,6 +1545,7 @@
os_umask = self.llexternal(underscore_on_windows+'umask', [rffi.MODE_T], rffi.MODE_T)
def umask_llimpl(fd):
+ rposix.validate_fd(fd)
res = os_umask(rffi.cast(rffi.MODE_T, fd))
return rffi.cast(lltype.Signed, res)
diff --git a/pypy/rpython/module/ll_os_stat.py b/pypy/rpython/module/ll_os_stat.py
--- a/pypy/rpython/module/ll_os_stat.py
+++ b/pypy/rpython/module/ll_os_stat.py
@@ -402,8 +402,7 @@
lltype.free(data, flavor='raw')
def win32_fstat_llimpl(fd):
- handle = rwin32._get_osfhandle(fd)
-
+ handle = rwin32.get_osfhandle(fd)
filetype = win32traits.GetFileType(handle)
if filetype == win32traits.FILE_TYPE_CHAR:
# console or LPT device
diff --git a/pypy/rpython/module/test/test_ll_os.py b/pypy/rpython/module/test/test_ll_os.py
--- a/pypy/rpython/module/test/test_ll_os.py
+++ b/pypy/rpython/module/test/test_ll_os.py
@@ -85,8 +85,10 @@
if (len == 0) and "WINGDB_PYTHON" in os.environ:
# the ctypes call seems not to work in the Wing debugger
return
- assert str(buf.value).lower() == pwd
- # ctypes returns the drive letter in uppercase, os.getcwd does not
+ assert str(buf.value).lower() == pwd.lower()
+ # ctypes returns the drive letter in uppercase,
+ # os.getcwd does not,
+ # but there may be uppercase in os.getcwd path
pwd = os.getcwd()
try:
@@ -188,7 +190,67 @@
OSError, ll_execve, "/etc/passwd", [], {})
assert info.value.errno == errno.EACCES
+def test_os_write():
+ #Same as test in rpython/test/test_rbuiltin
+ fname = str(udir.join('os_test.txt'))
+ fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
+ assert fd >= 0
+ f = getllimpl(os.write)
+ f(fd, 'Hello world')
+ os.close(fd)
+ with open(fname) as fid:
+ assert fid.read() == "Hello world"
+ fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
+ os.close(fd)
+ raises(OSError, f, fd, 'Hello world')
+def test_os_close():
+ fname = str(udir.join('os_test.txt'))
+ fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
+ assert fd >= 0
+ os.write(fd, 'Hello world')
+ f = getllimpl(os.close)
+ f(fd)
+ raises(OSError, f, fd)
+
+def test_os_lseek():
+ fname = str(udir.join('os_test.txt'))
+ fd = os.open(fname, os.O_RDWR|os.O_CREAT, 0777)
+ assert fd >= 0
+ os.write(fd, 'Hello world')
+ f = getllimpl(os.lseek)
+ f(fd,0,0)
+ assert os.read(fd, 11) == 'Hello world'
+ os.close(fd)
+ raises(OSError, f, fd, 0, 0)
+
+def test_os_fsync():
+ fname = str(udir.join('os_test.txt'))
+ fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
+ assert fd >= 0
+ os.write(fd, 'Hello world')
+ f = getllimpl(os.fsync)
+ f(fd)
+ os.close(fd)
+ fid = open(fname)
+ assert fid.read() == 'Hello world'
+ fid.close()
+ raises(OSError, f, fd)
+
+def test_os_fdatasync():
+ try:
+ f = getllimpl(os.fdatasync)
+ except:
+ skip('No fdatasync in os')
+ fname = str(udir.join('os_test.txt'))
+ fd = os.open(fname, os.O_WRONLY|os.O_CREAT, 0777)
+ assert fd >= 0
+ os.write(fd, 'Hello world')
+ f(fd)
+ fid = open(fname)
+ assert fid.read() == 'Hello world'
+ os.close(fd)
+ raises(OSError, f, fd)
class ExpectTestOs:
def setup_class(cls):
diff --git a/pypy/rpython/test/test_llinterp.py b/pypy/rpython/test/test_llinterp.py
--- a/pypy/rpython/test/test_llinterp.py
+++ b/pypy/rpython/test/test_llinterp.py
@@ -34,7 +34,7 @@
#start = time.time()
res = call(*args, **kwds)
#elapsed = time.time() - start
- #print "%.2f secs" %(elapsed,)
+ #print "%.2f secs" % (elapsed,)
return res
def gengraph(func, argtypes=[], viewbefore='auto', policy=None,
@@ -137,9 +137,9 @@
info = py.test.raises(LLException, "interp.eval_graph(graph, values)")
try:
got = interp.find_exception(info.value)
- except ValueError:
- got = None
- assert got is exc, "wrong exception type"
+ except ValueError as message:
+ got = 'None %r' % message
+ assert got is exc, "wrong exception type, expected %r got %r" % (exc, got)
#__________________________________________________________________
# tests
diff --git a/pypy/rpython/test/test_rbuiltin.py b/pypy/rpython/test/test_rbuiltin.py
--- a/pypy/rpython/test/test_rbuiltin.py
+++ b/pypy/rpython/test/test_rbuiltin.py
@@ -201,6 +201,9 @@
os.close(res)
hello = open(tmpdir).read()
assert hello == "hello world"
+ fd = os.open(tmpdir, os.O_WRONLY|os.O_CREAT, 777)
+ os.close(fd)
+ raises(OSError, os.write, fd, "hello world")
def test_os_write_single_char(self):
tmpdir = str(udir.udir.join("os_write_test_char"))
diff --git a/pypy/translator/c/src/main.h b/pypy/translator/c/src/main.h
--- a/pypy/translator/c/src/main.h
+++ b/pypy/translator/c/src/main.h
@@ -19,10 +19,6 @@
#define PYPY_MAIN_FUNCTION main
#endif
-#ifdef MS_WINDOWS
-#include "src/winstuff.c"
-#endif
-
#ifdef __GNUC__
/* Hack to prevent this function from being inlined. Helps asmgcc
because the main() function has often a different prologue/epilogue. */
@@ -50,10 +46,6 @@
}
#endif
-#ifdef MS_WINDOWS
- pypy_Windows_startup();
-#endif
-
errmsg = RPython_StartupCode();
if (errmsg) goto error;
diff --git a/pypy/translator/c/src/winstuff.c b/pypy/translator/c/src/winstuff.c
deleted file mode 100644
--- a/pypy/translator/c/src/winstuff.c
+++ /dev/null
@@ -1,37 +0,0 @@
-
-/************************************************************/
- /***** Windows-specific stuff. *****/
-
-
-/* copied from CPython. */
-
-#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
-/* crt variable checking in VisualStudio .NET 2005 */
-#include <crtdbg.h>
-
-/* Invalid parameter handler. Sets a ValueError exception */
-static void
-InvalidParameterHandler(
- const wchar_t * expression,
- const wchar_t * function,
- const wchar_t * file,
- unsigned int line,
- uintptr_t pReserved)
-{
- /* Do nothing, allow execution to continue. Usually this
- * means that the CRT will set errno to EINVAL
- */
-}
-#endif
-
-
-void pypy_Windows_startup(void)
-{
-#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
- /* Set CRT argument error handler */
- _set_invalid_parameter_handler(InvalidParameterHandler);
- /* turn off assertions within CRT in debug mode;
- instead just return EINVAL */
- _CrtSetReportMode(_CRT_ASSERT, 0);
-#endif
-}
diff --git a/pypy/translator/c/test/test_extfunc.py b/pypy/translator/c/test/test_extfunc.py
--- a/pypy/translator/c/test/test_extfunc.py
+++ b/pypy/translator/c/test/test_extfunc.py
@@ -134,6 +134,13 @@
res = os.lseek(fd, -r5200000000, 2)
assert res == r4800000000
os.close(fd)
+ try:
+ os.lseek(fd, 0, 0)
+ except OSError:
+ pass
+ else:
+ print "DID NOT RAISE"
+ raise AssertionError
st = os.stat(filename)
assert st.st_size == r10000000000
does_stuff()
diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py
--- a/pypy/translator/goal/app_main.py
+++ b/pypy/translator/goal/app_main.py
@@ -121,8 +121,18 @@
else:
optitems = options.items()
optitems.sort()
- for name, value in optitems:
- print ' %51s: %s' % (name, value)
+ current = []
+ for key, value in optitems:
+ group = key.split('.')
+ name = group.pop()
+ n = 0
+ while n < min(len(current), len(group)) and current[n] == group[n]:
+ n += 1
+ while n < len(group):
+ print '%s[%s]' % (' ' * n, group[n])
+ n += 1
+ print '%s%s = %r' % (' ' * n, name, value)
+ current = group
raise SystemExit
def print_help(*args):
diff --git a/pypy/translator/goal/test2/test_app_main.py b/pypy/translator/goal/test2/test_app_main.py
--- a/pypy/translator/goal/test2/test_app_main.py
+++ b/pypy/translator/goal/test2/test_app_main.py
@@ -787,6 +787,37 @@
assert data.startswith("15\xe2\x82\xac")
+class TestAppMain:
+
+ def test_print_info(self):
+ from pypy.translator.goal import app_main
+ import sys, cStringIO
+ prev_so = sys.stdout
+ prev_ti = getattr(sys, 'pypy_translation_info', 'missing')
+ sys.pypy_translation_info = {
+ 'translation.foo': True,
+ 'translation.bar': 42,
+ 'translation.egg.something': None,
+ 'objspace.x': 'hello',
+ }
+ try:
+ sys.stdout = f = cStringIO.StringIO()
+ py.test.raises(SystemExit, app_main.print_info)
+ finally:
+ sys.stdout = prev_so
+ if prev_ti == 'missing':
+ del sys.pypy_translation_info
+ else:
+ sys.pypy_translation_info = prev_ti
+ assert f.getvalue() == ("[objspace]\n"
+ " x = 'hello'\n"
+ "[translation]\n"
+ " bar = 42\n"
+ " [egg]\n"
+ " something = None\n"
+ " foo = True\n")
+
+
class AppTestAppMain:
def setup_class(self):
diff --git a/pypy/translator/goal/win32/gc_patch_windows.py b/pypy/translator/goal/win32/gc_patch_windows.py
deleted file mode 100644
--- a/pypy/translator/goal/win32/gc_patch_windows.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# patches for the Boehm GC for PyPy under Windows
-
-"""
-This file is obsolete now since gc-7.0 / gc-7.1 .
-Please use the instructions in pypy\doc\windows.rst .
-
-How to build a pypy compatible version of the Boehm collector
-for Windows and Visual Studio .net 2003.
-
-First of all, download the official Boehm collector suite
-from http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/gc.tar.gz
-At the time of writing (2005-10-06) this contains version gc6.5 .
-
-Unpack this folder somewhere, for instance to "d:\tmp".
-Change to this folder using
-
-d:
-cd \tmp\gc6.5
-
-Then copy the file NT_THREADS_MAKEFILE to Makefile:
-
-copy NT_THREADS_MAKEFILE Makefile
-
-This file is the general-purpose gc dll makefile. For some internal
-reasons, this file's defaults are bad for PyPy. The early initialisation
-in DllMain() inhibits the changes necessary for PyPy. Use this script to
-do a patch: (assuming that you have d:\pypy\dist\pypy\translator\goal)
-
-python d:\pypy\dist\pypy\translator\goal\win32\gc_patch_windows.py
-
-Now, your makefile is patched a little bit. In particular,
-
-ALL_INTERIOR_POINTERS is now undefined, which PyPy wants to have
-NO_GETENV is specified, since we don't want dependencies
-
-and the name of the .lib and .dll files is changed to gc_pypy.???
-
-Now you need to build your gc, either as a debug or as a release
-build. First of all, make sure that you have your environment prepared.
-Please note that you will need to use Microsoft's cmd, as cygwin bash
-doesn't correctly handle the batch file in the next step.
-
-With my setup, I have to do
-
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat"
-
-After that, you can either build a release or a debug gc.
-
-After a successful build, you need to enable gc_pypy.dll for your compiler.
-There are many ways to install this. The following recommendation just
-works without changing your environment variables. I think this is the
-easiest way possible, but this is a matter of taste. What I did is:
-
-nmake CFG="gc - Win32 Release"
-
-After the build, you will find a gc_pypy.dll file in the Release folder.
-Copy this file to c:\windows\system32 or any other folder that is always
-in your PATH variable.
-
-Also, copy Release\gc_pypy.lib to (in my case)
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\lib";
-
-finally, copy d:\tmp\gc6.5\include to
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\include"
-and rename this folder to "gc", so that "gc/gc.h" is valid.
-
-That's all, folks!
-
-In case of a debug build, replace "Release" by "Debug", and also copy
-gc_pypy.pdb to your lib folder. This allows you to use source-level
-debugging. Please note: If you want to both build the default gc.dll
-and gc_pypy.dll, please delete the Debug resp. Release folders in
-between. The generated .sbr files are in the way.
-
-Please use the above recipe and report any bugs to me.
-In case of trouble, I also can provide you with pre-built dlls.
-Note: We also could have solved this by including the gc source
-into the PyPy build. This may or may not become necessary if something
-changes dramatically, again. As long as this is not needed, I prefer
-this simple solution.
-
-Summary transcript of the steps involved: (please adjust paths)
-
-d:
-cd \tmp\gc6.5
-copy NT_THREADS_MAKEFILE Makefile
-python d:\pypy\dist\pypy\translator\goal\win32\gc_patch_windows.py
-"e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat"
-nmake CFG="gc - Win32 Release"
-copy Release\gc_pypy.dll c:\windows\system32
-copy Release\gc_pypy.lib "e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\lib"
-mkdir "e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\include\gc"
-copy include "e:\Programme\Microsoft Visual Studio .NET 2003\Vc7\include\gc"
-
-cheers - chris
-"""
-
-REPLACE = {
- '"ALL_INTERIOR_POINTERS"': '"NO_GETENV"',
- }
-
-for ending in "lib exp map pdb bsc dll pch".split():
- REPLACE["gc.%s" % ending] = "gc_pypy.%s" % ending
-
-def change_settings(src):
- for old, new in REPLACE.items():
- newsrc = src.replace(old, new)
- if newsrc == src:
- raise ValueError, "this makefile does not contain %s" % old
- src = newsrc
- return src
-
-def find_file():
- import os
- for name in os.listdir("."):
- if name.lower() == 'makefile':
- return name
- else:
- raise ValueError, 'Makefile not found'
-
-try:
- name = find_file()
- source = change_settings(file(name).read())
- file(name, "w").write(source)
- print "Updated your Makefile to fit PyPy's needs. Your lib will be named gc_pypy.dll"
- print "and gc_pypy.lib. Please put them into appropriate places, see __doc__."
-except:
- print __doc__
- raise
diff --git a/pypy/translator/platform/__init__.py b/pypy/translator/platform/__init__.py
--- a/pypy/translator/platform/__init__.py
+++ b/pypy/translator/platform/__init__.py
@@ -299,10 +299,11 @@
def set_platform(new_platform, cc):
global platform
- log.msg("Setting platform to %r cc=%s" % (new_platform,cc))
platform = pick_platform(new_platform, cc)
if not platform:
- raise ValueError("pick_platform failed")
+ raise ValueError("pick_platform(%r, %s) failed"%(new_platform, cc))
+ log.msg("Set platform with %r cc=%s, using cc=%r" % (new_platform, cc,
+ getattr(platform, 'cc','Unknown')))
if new_platform == 'host':
global host
diff --git a/pypy/translator/platform/windows.py b/pypy/translator/platform/windows.py
--- a/pypy/translator/platform/windows.py
+++ b/pypy/translator/platform/windows.py
@@ -83,13 +83,9 @@
if env is not None:
return env
-
log.error("Could not find a Microsoft Compiler")
# Assume that the compiler is already part of the environment
-msvc_compiler_environ32 = find_msvc_env(False)
-msvc_compiler_environ64 = find_msvc_env(True)
-
class MsvcPlatform(Platform):
name = "msvc"
so_ext = 'dll'
@@ -108,10 +104,7 @@
def __init__(self, cc=None, x64=False):
self.x64 = x64
- if x64:
- msvc_compiler_environ = msvc_compiler_environ64
- else:
- msvc_compiler_environ = msvc_compiler_environ32
+ msvc_compiler_environ = find_msvc_env(x64)
Platform.__init__(self, 'cl.exe')
if msvc_compiler_environ:
self.c_environ = os.environ.copy()
More information about the pypy-commit
mailing list