Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r59435:1fe71cc07c8c
Date: 2012-12-14 20:28 -0800
http://bitbucket.org/pypy/pypy/changeset/1fe71cc07c8c/
Log: merge default into branch
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
import types
from pypy.tool.ansi_print import ansi_log
from pypy.tool.pairtype import pair
@@ -373,7 +375,12 @@
# Merge the new 'cells' with each of the block's existing input
# variables.
oldcells = [self.binding(a) for a in block.inputargs]
- unions = [annmodel.unionof(c1,c2) for c1, c2 in
zip(oldcells,inputcells)]
+ try:
+ unions = [annmodel.unionof(c1,c2) for c1, c2 in
zip(oldcells,inputcells)]
+ except annmodel.UnionError, e:
+ e.args = e.args + (
+ ErrorWrapper(gather_error(self, graph, block, None)),)
+ raise
# if the merged cells changed, we must redo the analysis
if unions != oldcells:
self.bindinputargs(graph, block, unions)
diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py
--- a/pypy/annotation/bookkeeper.py
+++ b/pypy/annotation/bookkeeper.py
@@ -1,6 +1,9 @@
"""
The Bookkeeper class.
"""
+
+from __future__ import absolute_import
+
import sys, types, inspect, weakref
from pypy.objspace.flow.model import Constant
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -1,4 +1,6 @@
+from __future__ import absolute_import
import types, py
+from pypy.annotation.signature import enforce_signature_args,
enforce_signature_return
from pypy.objspace.flow.model import Constant, FunctionGraph
from pypy.objspace.flow.bytecode import cpython_code_signature
from pypy.objspace.flow.argument import rawshape, ArgErr
@@ -275,12 +277,17 @@
policy = self.bookkeeper.annotator.policy
self.specializer = policy.get_specializer(tag)
enforceargs = getattr(self.pyobj, '_annenforceargs_', None)
+ signature = getattr(self.pyobj, '_signature_', None)
+ if enforceargs and signature:
+ raise Exception("%r: signature and enforceargs cannot both be
used" % (self,))
if enforceargs:
if not callable(enforceargs):
from pypy.annotation.policy import Sig
enforceargs = Sig(*enforceargs)
self.pyobj._annenforceargs_ = enforceargs
enforceargs(self, inputcells) # can modify inputcells in-place
+ if signature:
+ enforce_signature_args(self, signature[0], inputcells) # mutates
inputcells
if getattr(self.pyobj, '_annspecialcase_',
'').endswith("call_location"):
return self.specializer(self, inputcells, op)
else:
@@ -297,6 +304,10 @@
new_args = args.unmatch_signature(self.signature, inputcells)
inputcells = self.parse_arguments(new_args, graph)
result = schedule(graph, inputcells)
+ signature = getattr(self.pyobj, '_signature_', None)
+ if signature:
+ result = enforce_signature_return(self, signature[1], result)
+ self.bookkeeper.annotator.addpendingblock(graph,
graph.returnblock, [result])
# Some specializations may break the invariant of returning
# annotations that are always more general than the previous time.
# We restore it here:
diff --git a/pypy/annotation/model.py b/pypy/annotation/model.py
--- a/pypy/annotation/model.py
+++ b/pypy/annotation/model.py
@@ -27,6 +27,7 @@
# \_____________________________________________________/
#
+from __future__ import absolute_import
from types import BuiltinFunctionType, MethodType, FunctionType
import pypy
diff --git a/pypy/annotation/signature.py b/pypy/annotation/signature.py
--- a/pypy/annotation/signature.py
+++ b/pypy/annotation/signature.py
@@ -1,3 +1,5 @@
+
+from __future__ import absolute_import
import types
from pypy.annotation.model import SomeBool, SomeInteger, SomeString,\
@@ -128,3 +130,25 @@
s_arg,
s_input))
inputcells[:] = args_s
+
+def finish_type(paramtype, bookkeeper, func):
+ from pypy.rlib.types import SelfTypeMarker
+ if isinstance(paramtype, SomeObject):
+ return paramtype
+ elif isinstance(paramtype, SelfTypeMarker):
+ raise Exception("%r argument declared as annotation.types.self();
class needs decorator rlib.signature.finishsigs()" % (func,))
+ else:
+ return paramtype(bookkeeper)
+
+def enforce_signature_args(funcdesc, paramtypes, actualtypes):
+ assert len(paramtypes) == len(actualtypes)
+ params_s = [finish_type(paramtype, funcdesc.bookkeeper, funcdesc.pyobj)
for paramtype in paramtypes]
+ for i, (s_param, s_actual) in enumerate(zip(params_s, actualtypes)):
+ if not s_param.contains(s_actual):
+ raise Exception("%r argument %d:\n"
+ "expected %s,\n"
+ " got %s" % (funcdesc, i+1, s_param, s_actual))
+ actualtypes[:] = params_s
+
+def enforce_signature_return(funcdesc, sigtype, inferredtype):
+ return finish_type(sigtype, funcdesc.bookkeeper, funcdesc.pyobj)
diff --git a/pypy/annotation/unaryop.py b/pypy/annotation/unaryop.py
--- a/pypy/annotation/unaryop.py
+++ b/pypy/annotation/unaryop.py
@@ -2,6 +2,8 @@
Unary operations on SomeValues.
"""
+from __future__ import absolute_import
+
from types import MethodType
from pypy.annotation.model import \
SomeObject, SomeInteger, SomeBool, SomeString, SomeChar, SomeList, \
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -320,6 +320,30 @@
.. _JVM: translation.html#genjvm
.. _`translation document`: translation.html
+------------------
+Could we use LLVM?
+------------------
+
+In theory yes. But we tried to use it 5 or 6 times already, as a
+translation backend or as a JIT backend --- and failed each time.
+
+In more details: using LLVM as a (static) translation backend is
+pointless nowadays because you can generate C code and compile it with
+clang. (Note that compiling PyPy with clang gives a result that is not
+faster than compiling it with gcc.) We might in theory get extra
+benefits from LLVM's GC integration, but this requires more work on the
+LLVM side before it would be remotely useful. Anyway, it could be
+interfaced via a custom primitive in the C code.
+
+On the other hand, using LLVM as our JIT backend looks interesting as
+well --- but again we made an attempt, and it failed: LLVM has no way to
+patch the generated machine code.
+
+So the position of the core PyPy developers is that if anyone wants to
+make an N+1'th attempt with LLVM, he is welcome, and he will receive a
+bit of help on the IRC channel, but he is left with the burden of proof
+that it works.
+
----------------------
How do I compile PyPy?
----------------------
diff --git a/pypy/module/_cffi_backend/ctypeenum.py
b/pypy/module/_cffi_backend/ctypeenum.py
--- a/pypy/module/_cffi_backend/ctypeenum.py
+++ b/pypy/module/_cffi_backend/ctypeenum.py
@@ -37,6 +37,13 @@
space.setitem(w_dct, space.wrap(enumvalue),
space.wrap(enumerator))
return w_dct
+ if attrchar == 'R': # relements
+ space = self.space
+ w_dct = space.newdict()
+ for enumerator, enumvalue in self.enumerators2values.iteritems():
+ space.setitem(w_dct, space.wrap(enumerator),
+ space.wrap(enumvalue))
+ return w_dct
return W_CTypePrimitiveSigned._fget(self, attrchar)
def string(self, cdataobj, maxlen):
diff --git a/pypy/module/_cffi_backend/ctypeobj.py
b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -188,7 +188,7 @@
if attrchar == 'c': # cname
return space.wrap(self.name)
raise operationerrfmt(space.w_AttributeError,
- "cdata '%s' has no such attribute",
+ "ctype '%s' has no such attribute",
self.name)
def fget_kind(self, space): return self._fget('k')
@@ -201,6 +201,7 @@
def fget_ellipsis(self, space): return self._fget('E')
def fget_abi(self, space): return self._fget('A')
def fget_elements(self, space): return self._fget('e')
+ def fget_relements(self, space):return self._fget('R')
W_CType.typedef = TypeDef(
@@ -218,6 +219,8 @@
ellipsis = GetSetProperty(W_CType.fget_ellipsis, doc="function has '...'"),
abi = GetSetProperty(W_CType.fget_abi, doc="function ABI"),
elements = GetSetProperty(W_CType.fget_elements, doc="enum elements"),
+ relements = GetSetProperty(W_CType.fget_relements,
+ doc="enum elements, reversed"),
__dir__ = interp2app(W_CType.dir),
)
W_CType.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1272,6 +1272,10 @@
# 'elements' is not the real dict, but merely a copy
BEnum.elements[2] = '??'
assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
+ #
+ BEnum = new_enum_type("bar", ('ab', 'cd'), (5, 5))
+ assert BEnum.elements == {5: 'ab'}
+ assert BEnum.relements == {'ab': 5, 'cd': 5}
def test_cast_to_enum():
BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
diff --git a/pypy/module/_ffi/test/test_struct.py
b/pypy/module/_ffi/test/test_struct.py
--- a/pypy/module/_ffi/test/test_struct.py
+++ b/pypy/module/_ffi/test/test_struct.py
@@ -53,7 +53,10 @@
array = ptr_array[0]
lst = [array[i] for i in range(length)]
return space.wrap(lst)
- cls.w_read_raw_mem = cls.space.wrap(interp2app(read_raw_mem))
+ if cls.runappdirect:
+ cls.w_read_raw_mem = lambda self, *args: read_raw_mem(cls.space,
*args)
+ else:
+ cls.w_read_raw_mem = cls.space.wrap(interp2app(read_raw_mem))
#
from pypy.rlib import clibffi
from pypy.rlib.rarithmetic import r_uint
diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py
--- a/pypy/module/_ssl/thread_lock.py
+++ b/pypy/module/_ssl/thread_lock.py
@@ -62,13 +62,14 @@
}
"""
+from pypy.module.thread import ll_thread
-eci = ExternalCompilationInfo(
+eci = ll_thread.eci.merge(ExternalCompilationInfo(
separate_module_sources=[separate_module_source],
post_include_bits=[
"int _PyPy_SSL_SetupThreads(void);"],
export_symbols=['_PyPy_SSL_SetupThreads'],
-)
+))
_PyPy_SSL_SetupThreads = rffi.llexternal('_PyPy_SSL_SetupThreads',
[], rffi.INT,
diff --git a/pypy/module/bz2/test/test_bz2_compdecomp.py
b/pypy/module/bz2/test/test_bz2_compdecomp.py
--- a/pypy/module/bz2/test/test_bz2_compdecomp.py
+++ b/pypy/module/bz2/test/test_bz2_compdecomp.py
@@ -46,7 +46,10 @@
def setup_class(cls):
cls.w_TEXT = cls.space.wrap(TEXT)
- cls.w_decompress = cls.space.wrap(interp2app(decompress))
+ if cls.runappdirect:
+ cls.w_decompress = lambda self, *args: decompress(cls.space, *args)
+ else:
+ cls.w_decompress = cls.space.wrap(interp2app(decompress))
cls.w_HUGE_OK = cls.space.wrap(HUGE_OK)
def test_creation(self):
@@ -184,7 +187,10 @@
def setup_class(cls):
cls.w_TEXT = cls.space.wrap(TEXT)
cls.w_DATA = cls.space.wrap(DATA)
- cls.w_decompress = cls.space.wrap(interp2app(decompress))
+ if cls.runappdirect:
+ cls.w_decompress = lambda self, *args: decompress(cls.space, *args)
+ else:
+ cls.w_decompress = cls.space.wrap(interp2app(decompress))
cls.w_HUGE_OK = cls.space.wrap(HUGE_OK)
def test_compress_function(self):
diff --git a/pypy/module/bz2/test/test_bz2_file.py
b/pypy/module/bz2/test/test_bz2_file.py
--- a/pypy/module/bz2/test/test_bz2_file.py
+++ b/pypy/module/bz2/test/test_bz2_file.py
@@ -66,10 +66,12 @@
str(py.test.ensuretemp("bz2").join("foo")))
if cls.runappdirect:
cls.w_create_temp_file = create_temp_file
+ cls.w_create_broken_temp_file = lambda self:
create_broken_temp_file()
+ cls.w_decompress = lambda self, *args: decompress(cls.space, *args)
else:
cls.w_create_temp_file =
cls.space.wrap(interp2app(create_temp_file))
- cls.w_decompress = cls.space.wrap(interp2app(decompress))
- cls.w_create_broken_temp_file =
cls.space.wrap(interp2app(create_broken_temp_file))
+ cls.w_create_broken_temp_file =
cls.space.wrap(interp2app(create_broken_temp_file))
+ cls.w_decompress = cls.space.wrap(interp2app(decompress))
cls.w_random_data = cls.space.wrap(RANDOM_DATA)
def test_attributes(self):
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
@@ -248,7 +248,7 @@
space.sys.get('modules'),
space.wrap(name))
else:
- return os.path.dirname(mod)
+ return space.wrap(os.path.dirname(mod))
@unwrap_spec(mod=str, name=str)
def reimport_module(space, mod, name):
diff --git a/pypy/module/math/test/test_direct.py
b/pypy/module/math/test/test_direct.py
--- a/pypy/module/math/test/test_direct.py
+++ b/pypy/module/math/test/test_direct.py
@@ -72,9 +72,10 @@
('exp', (9999.9,), OverflowError),
('pow', (10.0, 40000.0), OverflowError),
('ldexp', (10.0, 40000), OverflowError),
- ('log', (0.0,), ValueError),
+ ('log', (0.0,), ValueError), #cpython does it this way
+ ('log1p', (-1.0,), OverflowError),
('log', (-1.,), ValueError),
- ('log10', (0.0,), ValueError),
+ ('log10', (0.0,), ValueError), #cpython does it this way
]
INFCASES = [
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
@@ -17,7 +17,8 @@
if type(expected) is type and issubclass(expected, Exception):
expected = getattr(space, "w_%s" % expected.__name__)
elif callable(expected):
- expected = cls.make_callable_wrapper(expected)
+ if not cls.runappdirect:
+ expected = cls.make_callable_wrapper(expected)
else:
expected = space.wrap(expected)
cases.append(space.newtuple([space.wrap(a), space.wrap(b),
expected]))
diff --git a/pypy/module/micronumpy/test/test_complex.py
b/pypy/module/micronumpy/test/test_complex.py
--- a/pypy/module/micronumpy/test/test_complex.py
+++ b/pypy/module/micronumpy/test/test_complex.py
@@ -94,30 +94,42 @@
cls.w_testcases128 = cls.space.wrap(list(parse_testfile(fname128)))
cls.w_testcases64 = cls.space.wrap(list(parse_testfile(fname64)))
- def cls_c_pow(space, args_w):
- try:
- retVal = c_pow(*map(space.unwrap, args_w))
- return space.wrap(retVal)
- except ValueError, e:
- if option.runappdirect:
- raise
- raise OperationError(cls.space.w_ValueError,
- cls.space.wrap(e.message))
- cls.w_c_pow = cls.space.wrap(interp2app(cls_c_pow))
cls.w_runAppDirect = cls.space.wrap(option.runappdirect)
cls.w_isWindows = cls.space.wrap(os.name == 'nt')
- def cls_rAlmostEqual(space, __args__):
- args, kwargs = __args__.unpack()
- args = map(space.unwrap, args)
- kwargs = dict([
- (k, space.unwrap(v))
- for k, v in kwargs.iteritems()
- ])
- if '__pypy__' not in sys.builtin_module_names:
- kwargs['isnumpy'] = True
- return space.wrap(rAlmostEqual(*args, **kwargs))
- cls.w_rAlmostEqual = cls.space.wrap(interp2app(cls_rAlmostEqual))
+ if cls.runappdirect:
+ def cls_rAlmostEqual(space, *args, **kwargs):
+ return rAlmostEqual(*args, **kwargs)
+ cls.w_rAlmostEqual = cls.space.wrap(cls_rAlmostEqual)
+ def cls_c_pow(space, *args):
+ return c_pow(*args)
+ cls.w_c_pow = cls.space.wrap(cls_c_pow)
+ else:
+ def cls_rAlmostEqual(space, __args__):
+ args, kwargs = __args__.unpack()
+ args = map(space.unwrap, args)
+ kwargs = dict([
+ (k, space.unwrap(v))
+ for k, v in kwargs.iteritems()
+ ])
+ if '__pypy__' not in sys.builtin_module_names:
+ kwargs['isnumpy'] = True
+ return space.wrap(rAlmostEqual(*args, **kwargs))
+ cls.w_rAlmostEqual = cls.space.wrap(interp2app(cls_rAlmostEqual))
+ def cls_c_pow(space, args_w):
+ try:
+ retVal = c_pow(*map(space.unwrap, args_w))
+ return space.wrap(retVal)
+ except ZeroDivisionError, e:
+ raise OperationError(cls.space.w_ZeroDivisionError,
+ cls.space.wrap(e.message))
+ except OverflowError, e:
+ raise OperationError(cls.space.w_OverflowError,
+ cls.space.wrap(e.message))
+ except ValueError, e:
+ raise OperationError(cls.space.w_ValueError,
+ cls.space.wrap(e.message))
+ cls.w_c_pow = cls.space.wrap(interp2app(cls_c_pow))
def test_fabs(self):
from _numpypy import fabs, complex128
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
@@ -13,11 +13,13 @@
import signal
def setup_module(mod):
+ usemodules = ['binascii', 'posix', 'struct', 'rctime']
if os.name != 'nt':
- mod.space = gettestobjspace(usemodules=['posix', 'fcntl', 'struct'])
+ usemodules += ['fcntl']
else:
# On windows, os.popen uses the subprocess module
- mod.space = gettestobjspace(usemodules=['posix', '_rawffi', 'thread',
'struct'])
+ usemodules += ['_rawffi', 'thread']
+ mod.space = gettestobjspace(usemodules=usemodules)
mod.path = udir.join('posixtestfile.txt')
mod.path.write("this is a test")
mod.path2 = udir.join('test_posix2-')
@@ -50,9 +52,6 @@
class AppTestPosix:
- spaceconfig = {
- "usemodules": ["binascii", "struct", "rctime"],
- }
def setup_class(cls):
cls.space = space
@@ -326,7 +325,11 @@
u = "caf\xe9".decode(sys.getfilesystemencoding())
except UnicodeDecodeError:
# Could not decode, listdir returned the byte string
- assert (str, "caf\xe9") in typed_result
+ if sys.platform != 'darwin':
+ assert (str, "caf\xe9") in typed_result
+ else:
+ # darwin 'normalized' it
+ assert (unicode, 'caf%E9') in typed_result
else:
assert (unicode, u) in typed_result
diff --git a/pypy/module/select/test/test_select.py
b/pypy/module/select/test/test_select.py
--- a/pypy/module/select/test/test_select.py
+++ b/pypy/module/select/test/test_select.py
@@ -272,6 +272,7 @@
w_import = space.getattr(space.builtin, space.wrap("__import__"))
w_socketmod = space.call_function(w_import, space.wrap("socket"))
cls.w_sock = cls.space.call_method(w_socketmod, "socket")
+ cls.w_sock_err = space.getattr(w_socketmod, space.wrap("error"))
try_ports = [1023] + range(20000, 30000, 437)
for port in try_ports:
@@ -279,11 +280,8 @@
cls.w_sockaddress = space.wrap(('127.0.0.1', port))
try:
space.call_method(cls.w_sock, "bind", cls.w_sockaddress)
- print 'works'
break
- except OperationError, e: # should get a "Permission denied"
- if not e.match(space, space.getattr(w_socketmod,
space.wrap("error"))):
- raise
+ except cls.w_sock_err, e: # should get a "Permission denied"
print e
else:
raise e
diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -3,6 +3,8 @@
RPython-compliant way.
"""
+from __future__ import absolute_import
+
import py
import sys
import types
@@ -194,6 +196,7 @@
return decorator
+
# ____________________________________________________________
class Symbolic(object):
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -273,6 +273,8 @@
def frombytes(s, byteorder, signed):
if byteorder not in ('big', 'little'):
raise InvalidEndiannessError()
+ if not s:
+ return NULLRBIGINT
if byteorder != BYTEORDER:
msb = ord(s[0])
diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -170,13 +170,17 @@
result = formatd(value, tp, precision, flags)
return result, special
-def round_double(value, ndigits):
+def round_double(value, ndigits, half_even=False):
+ """Round a float half away from zero.
+
+ Specify half_even=True to round half even instead.
+ """
if USE_SHORT_FLOAT_REPR:
- return round_double_short_repr(value, ndigits)
+ return round_double_short_repr(value, ndigits, half_even)
else:
- return round_double_fallback_repr(value, ndigits)
+ return round_double_fallback_repr(value, ndigits, half_even)
-def round_double_short_repr(value, ndigits):
+def round_double_short_repr(value, ndigits, half_even):
# The basic idea is very simple: convert and round the double to
# a decimal string using _Py_dg_dtoa, then convert that decimal
# string back to a double with _Py_dg_strtod. There's one minor
@@ -209,7 +213,7 @@
# determine whether this is a halfway case.
halfway_case = 0
- if expo == -ndigits - 1:
+ if not half_even and expo == -ndigits - 1:
if ndigits >= 0:
halfway_case = 1
elif ndigits >= -22:
@@ -224,7 +228,7 @@
# round to a decimal string; use an extra place for halfway case
strvalue = formatd(value, 'f', ndigits + halfway_case)
- if halfway_case:
+ if not half_even and halfway_case:
buf = [c for c in strvalue]
if ndigits >= 0:
endpos = len(buf) - 1
@@ -263,7 +267,7 @@
# fallback version, to be used when correctly rounded
# binary<->decimal conversions aren't available
-def round_double_fallback_repr(value, ndigits):
+def round_double_fallback_repr(value, ndigits, half_even):
if ndigits >= 0:
if ndigits > 22:
# pow1 and pow2 are each safe from overflow, but
@@ -284,12 +288,17 @@
pow2 = 1.0 # unused; for translation
y = value / pow1
- if y >= 0.0:
- z = math.floor(y + 0.5)
+ if half_even:
+ z = round_away(y)
+ if math.fabs(y - z) == 0.5:
+ z = 2.0 * round_away(y / 2.0)
else:
- z = math.ceil(y - 0.5)
- if math.fabs(y-z) == 1.0: # obscure case, see the test
- z = y
+ if y >= 0.0:
+ z = math.floor(y + 0.5)
+ else:
+ z = math.ceil(y - 0.5)
+ if math.fabs(y - z) == 1.0: # obscure case, see the test
+ z = y
if ndigits >= 0:
z = (z / pow2) / pow1
diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py
--- a/pypy/rlib/rgc.py
+++ b/pypy/rlib/rgc.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
import gc
import types
diff --git a/pypy/rlib/signature.py b/pypy/rlib/signature.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/signature.py
@@ -0,0 +1,39 @@
+from pypy.rlib import types
+
+def signature(*paramtypes, **kwargs):
+ """Decorate a function to specify its type signature.
+
+ Usage:
+ @signature(param1type, param2type, ..., returns=returntype)
+ def foo(...)
+
+ The arguments paramNtype and returntype should be instances
+ of the classes in pypy.annotation.types.
+ """
+ returntype = kwargs.pop('returns', None)
+ if returntype is None:
+ raise TypeError, "signature: parameter 'returns' required"
+
+ def decorator(f):
+ f._signature_ = (paramtypes, returntype)
+ return f
+ return decorator
+
+
+def finishsigs(cls):
+ """Decorate a class to finish any method signatures involving types.self().
+
+ This is required if any method has a signature with types.self() in it.
+ """
+ # A bit annoying to have to use this, but it avoids performing any
+ # terrible hack in the implementation. Eventually we'll offer signatures
+ # on classes, and then that decorator can do this on the side.
+ def fix(sigtype):
+ if isinstance(sigtype, types.SelfTypeMarker):
+ return types.instance(cls)
+ return sigtype
+ for attr in cls.__dict__.values():
+ if hasattr(attr, '_signature_'):
+ paramtypes, returntype = attr._signature_
+ attr._signature_ = (tuple(fix(t) for t in paramtypes),
fix(returntype))
+ return cls
diff --git a/pypy/rlib/test/test_objectmodel.py
b/pypy/rlib/test/test_objectmodel.py
--- a/pypy/rlib/test/test_objectmodel.py
+++ b/pypy/rlib/test/test_objectmodel.py
@@ -1,5 +1,7 @@
import py
from pypy.rlib.objectmodel import *
+from pypy.rlib import types
+from pypy.annotation import model
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
from pypy.rpython.test.test_llinterp import interpret
@@ -486,6 +488,7 @@
TYPES = [v.concretetype for v in graph.getargs()]
assert TYPES == [lltype.Signed, lltype.Float]
+
def getgraph(f, argtypes):
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator.backendopt.all import backend_optimizations
diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py
--- a/pypy/rlib/test/test_rbigint.py
+++ b/pypy/rlib/test/test_rbigint.py
@@ -771,6 +771,8 @@
assert res == -42.0
def test_frombytes(self):
+ bigint = rbigint.frombytes('', byteorder='big', signed=True)
+ assert bigint.tolong() == 0
s = "\xFF\x12\x34\x56"
bigint = rbigint.frombytes(s, byteorder="big", signed=False)
assert bigint.tolong() == 0xFF123456
diff --git a/pypy/rlib/test/test_signature.py b/pypy/rlib/test/test_signature.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/test/test_signature.py
@@ -0,0 +1,212 @@
+import py
+from pypy.rlib.signature import signature, finishsigs
+from pypy.rlib import types
+from pypy.annotation import model
+from pypy.translator.translator import TranslationContext, graphof
+
+
+def annotate_at(f):
+ t = TranslationContext()
+ a = t.buildannotator()
+ a.annotate_helper(f, [model.s_ImpossibleValue]*f.func_code.co_argcount)
+ return a
+
+def sigof(a, f):
+ # returns [param1, param2, ..., ret]
+ g = graphof(a.translator, f)
+ return [a.bindings[v] for v in g.startblock.inputargs] +
[a.bindings[g.getreturnvar()]]
+
+def getsig(f):
+ a = annotate_at(f)
+ return sigof(a, f)
+
+def check_annotator_fails(caller):
+ exc = py.test.raises(Exception, annotate_at, caller).value
+ assert caller.func_name in repr(exc.args)
+
+
+def test_signature_bookkeeping():
+ @signature('x', 'y', returns='z')
+ def f(a, b):
+ return a + len(b)
+ f.foo = 'foo'
+ assert f._signature_ == (('x', 'y'), 'z')
+ assert f.func_name == 'f'
+ assert f.foo == 'foo'
+ assert f(1, 'hello') == 6
+
+def test_signature_basic():
+ @signature(types.int(), types.str(), returns=types.char())
+ def f(a, b):
+ return b[a]
+ assert getsig(f) == [model.SomeInteger(), model.SomeString(),
model.SomeChar()]
+
+def test_signature_arg_errors():
+ @signature(types.int(), types.str(), returns=types.int())
+ def f(a, b):
+ return a + len(b)
+ @check_annotator_fails
+ def ok_for_body(): # would give no error without signature
+ f(2.0, 'b')
+ @check_annotator_fails
+ def bad_for_body(): # would give error inside 'f' body, instead errors at
call
+ f('a', 'b')
+
+def test_signature_return():
+ @signature(returns=types.str())
+ def f():
+ return 'a'
+ assert getsig(f) == [model.SomeString()]
+
+ @signature(types.str(), returns=types.str())
+ def f(x):
+ return x
+ def g():
+ return f('a')
+ a = annotate_at(g)
+ assert sigof(a, f) == [model.SomeString(), model.SomeString()]
+
+def test_signature_return_errors():
+ @check_annotator_fails
+ @signature(returns=types.int())
+ def int_not_char():
+ return 'a'
+ @check_annotator_fails
+ @signature(types.str(), returns=types.int())
+ def str_to_int(s):
+ return s
+
+
+def test_signature_none():
+ @signature(returns=types.none())
+ def f():
+ pass
+ assert getsig(f) == [model.s_None]
+
+def test_signature_float():
+ @signature(types.longfloat(), types.singlefloat(), returns=types.float())
+ def f(a, b):
+ return 3.0
+ assert getsig(f) == [model.SomeLongFloat(), model.SomeSingleFloat(),
model.SomeFloat()]
+
+def test_signature_unicode():
+ @signature(types.unicode(), returns=types.int())
+ def f(u):
+ return len(u)
+ assert getsig(f) == [model.SomeUnicodeString(), model.SomeInteger()]
+
+
+def test_signature_list():
+ @signature(types.list(types.int()), returns=types.int())
+ def f(a):
+ return len(a)
+ argtype = getsig(f)[0]
+ assert isinstance(argtype, model.SomeList)
+ item = argtype.listdef.listitem
+ assert item.s_value == model.SomeInteger()
+ assert item.resized == True
+
+ @check_annotator_fails
+ def ok_for_body():
+ f(['a'])
+ @check_annotator_fails
+ def bad_for_body():
+ f('a')
+
+ @signature(returns=types.list(types.char()))
+ def ff():
+ return ['a']
+ @check_annotator_fails
+ def mutate_broader():
+ ff()[0] = 'abc'
+ @check_annotator_fails
+ def mutate_unrelated():
+ ff()[0] = 1
+ @check_annotator_fails
+ @signature(types.list(types.char()), returns=types.int())
+ def mutate_in_body(l):
+ l[0] = 'abc'
+ return len(l)
+
+ def can_append():
+ l = ff()
+ l.append('b')
+ getsig(can_append)
+
+def test_signature_array():
+ @signature(returns=types.array(types.int()))
+ def f():
+ return [1]
+ rettype = getsig(f)[0]
+ assert isinstance(rettype, model.SomeList)
+ item = rettype.listdef.listitem
+ assert item.s_value == model.SomeInteger()
+ assert item.resized == False
+
+ def try_append():
+ l = f()
+ l.append(2)
+ check_annotator_fails(try_append)
+
+def test_signature_dict():
+ @signature(returns=types.dict(types.str(), types.int()))
+ def f():
+ return {'a': 1, 'b': 2}
+ rettype = getsig(f)[0]
+ assert isinstance(rettype, model.SomeDict)
+ assert rettype.dictdef.dictkey.s_value == model.SomeString()
+ assert rettype.dictdef.dictvalue.s_value == model.SomeInteger()
+
+
+def test_signature_instance():
+ class C1(object):
+ pass
+ class C2(C1):
+ pass
+ class C3(C2):
+ pass
+ @signature(types.instance(C3), returns=types.instance(C2))
+ def f(x):
+ assert isinstance(x, C2)
+ return x
+ argtype, rettype = getsig(f)
+ assert isinstance(argtype, model.SomeInstance)
+ assert argtype.classdef.classdesc.pyobj == C3
+ assert isinstance(rettype, model.SomeInstance)
+ assert rettype.classdef.classdesc.pyobj == C2
+
+ @check_annotator_fails
+ def ok_for_body():
+ f(C2())
+ @check_annotator_fails
+ def bad_for_body():
+ f(C1())
+
+def test_signature_self():
+ @finishsigs
+ class C(object):
+ @signature(types.self(), types.self(), returns=types.none())
+ def f(self, other):
+ pass
+ class D1(C):
+ pass
+ class D2(C):
+ pass
+
+ def g():
+ D1().f(D2())
+ a = annotate_at(g)
+
+ argtype = sigof(a, C.__dict__['f'])[0]
+ assert isinstance(argtype, model.SomeInstance)
+ assert argtype.classdef.classdesc.pyobj == C
+
+def test_signature_self_error():
+ class C(object):
+ @signature(types.self(), returns=types.none())
+ def incomplete_sig_meth(self):
+ pass
+
+ exc = py.test.raises(Exception, annotate_at, C.incomplete_sig_meth).value
+ assert 'incomplete_sig_meth' in repr(exc.args)
+ assert 'finishsigs' in repr(exc.args)
diff --git a/pypy/rlib/types.py b/pypy/rlib/types.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/types.py
@@ -0,0 +1,54 @@
+from pypy.annotation import model
+from pypy.annotation.listdef import ListDef
+from pypy.annotation.dictdef import DictDef
+
+
+def none():
+ return model.s_None
+
+
+def float():
+ return model.SomeFloat()
+
+def singlefloat():
+ return model.SomeSingleFloat()
+
+def longfloat():
+ return model.SomeLongFloat()
+
+
+def int():
+ return model.SomeInteger()
+
+
+def unicode():
+ return model.SomeUnicodeString()
+
+def str():
+ return model.SomeString()
+
+def char():
+ return model.SomeChar()
+
+
+def list(element):
+ listdef = ListDef(None, element, mutated=True, resized=True)
+ return model.SomeList(listdef)
+
+def array(element):
+ listdef = ListDef(None, element, mutated=True, resized=False)
+ return model.SomeList(listdef)
+
+def dict(keytype, valuetype):
+ dictdef = DictDef(None, keytype, valuetype)
+ return model.SomeDict(dictdef)
+
+
+def instance(class_):
+ return lambda bookkeeper:
model.SomeInstance(bookkeeper.getuniqueclassdef(class_))
+
+class SelfTypeMarker(object):
+ pass
+
+def self():
+ return SelfTypeMarker()
diff --git a/pypy/rpython/lltypesystem/module/ll_math.py
b/pypy/rpython/lltypesystem/module/ll_math.py
--- a/pypy/rpython/lltypesystem/module/ll_math.py
+++ b/pypy/rpython/lltypesystem/module/ll_math.py
@@ -368,6 +368,8 @@
if x == 0.0:
return x # returns 0.0 or -0.0
if x <= -1.0:
+ if x == -1:
+ raise OverflowError("math range error")
raise ValueError("math domain error")
return math_log1p(x)
diff --git a/pypy/rpython/test/test_rfloat.py b/pypy/rpython/test/test_rfloat.py
--- a/pypy/rpython/test/test_rfloat.py
+++ b/pypy/rpython/test/test_rfloat.py
@@ -215,6 +215,174 @@
# https://bugzilla.novell.com/show_bug.cgi?id=692493
assert not self.interpret(fn, [1e200, 1e200]) # nan
+ def test_break_up_float(self):
+ from pypy.rlib.rfloat import break_up_float
+ assert break_up_float('1') == ('', '1', '', '')
+ assert break_up_float('+1') == ('+', '1', '', '')
+ assert break_up_float('-1') == ('-', '1', '', '')
+
+ assert break_up_float('.5') == ('', '', '5', '')
+
+ assert break_up_float('1.2e3') == ('', '1', '2', '3')
+ assert break_up_float('1.2e+3') == ('', '1', '2', '+3')
+ assert break_up_float('1.2e-3') == ('', '1', '2', '-3')
+
+ # some that will get thrown out on return:
+ assert break_up_float('.') == ('', '', '', '')
+ assert break_up_float('+') == ('+', '', '', '')
+ assert break_up_float('-') == ('-', '', '', '')
+ assert break_up_float('e1') == ('', '', '', '1')
+
+ raises(ValueError, break_up_float, 'e')
+
+ def test_formatd(self):
+ from pypy.rlib.rfloat import formatd
+ def f(x):
+ return formatd(x, 'f', 2, 0)
+ res = self.ll_to_string(self.interpret(f, [10/3.0]))
+ assert res == '3.33'
+
+ def test_formatd_repr(self):
+ from pypy.rlib.rfloat import formatd
+ def f(x):
+ return formatd(x, 'r', 0, 0)
+ res = self.ll_to_string(self.interpret(f, [1.1]))
+ assert res == '1.1'
+
+ def test_formatd_huge(self):
+ from pypy.rlib.rfloat import formatd
+ def f(x):
+ return formatd(x, 'f', 1234, 0)
+ res = self.ll_to_string(self.interpret(f, [1.0]))
+ assert res == '1.' + 1234 * '0'
+
+ def test_formatd_F(self):
+ from pypy.translator.c.test.test_genc import compile
+ from pypy.rlib.rfloat import formatd
+
+ def func(x):
+ # Test the %F format, which is not supported by
+ # the Microsoft's msvcrt library.
+ return formatd(x, 'F', 4)
+
+ f = compile(func, [float])
+ assert f(10/3.0) == '3.3333'
+
+ def test_parts_to_float(self):
+ from pypy.rlib.rfloat import parts_to_float, break_up_float
+ def f(x):
+ if x == 0:
+ s = '1.0'
+ else:
+ s = '1e-100'
+ sign, beforept, afterpt, expt = break_up_float(s)
+ return parts_to_float(sign, beforept, afterpt, expt)
+ res = self.interpret(f, [0])
+ assert res == 1.0
+
+ res = self.interpret(f, [1])
+ assert res == 1e-100
+
+ def test_string_to_float(self):
+ from pypy.rlib.rfloat import rstring_to_float
+ def func(x):
+ if x == 0:
+ s = '1e23'
+ else:
+ s = '-1e23'
+ return rstring_to_float(s)
+
+ assert self.interpret(func, [0]) == 1e23
+ assert self.interpret(func, [1]) == -1e23
+
+ def test_copysign(self):
+ from pypy.rlib.rfloat import copysign
+ assert copysign(1, 1) == 1
+ assert copysign(-1, 1) == 1
+ assert copysign(-1, -1) == -1
+ assert copysign(1, -1) == -1
+ assert copysign(1, -0.) == -1
+
+ def test_round_away(self):
+ from pypy.rlib.rfloat import round_away
+ assert round_away(.1) == 0.
+ assert round_away(.5) == 1.
+ assert round_away(.7) == 1.
+ assert round_away(1.) == 1.
+ assert round_away(-.5) == -1.
+ assert round_away(-.1) == 0.
+ assert round_away(-.7) == -1.
+ assert round_away(0.) == 0.
+
+ def test_round_double(self):
+ from pypy.rlib.rfloat import round_double
+ def almost_equal(x, y):
+ assert round(abs(x-y), 7) == 0
+
+ almost_equal(round_double(0.125, 2), 0.13)
+ almost_equal(round_double(0.375, 2), 0.38)
+ almost_equal(round_double(0.625, 2), 0.63)
+ almost_equal(round_double(0.875, 2), 0.88)
+ almost_equal(round_double(-0.125, 2), -0.13)
+ almost_equal(round_double(-0.375, 2), -0.38)
+ almost_equal(round_double(-0.625, 2), -0.63)
+ almost_equal(round_double(-0.875, 2), -0.88)
+
+ almost_equal(round_double(0.25, 1), 0.3)
+ almost_equal(round_double(0.75, 1), 0.8)
+ almost_equal(round_double(-0.25, 1), -0.3)
+ almost_equal(round_double(-0.75, 1), -0.8)
+
+ round_double(-6.5, 0) == -7.0
+ round_double(-5.5, 0) == -6.0
+ round_double(-1.5, 0) == -2.0
+ round_double(-0.5, 0) == -1.0
+ round_double(0.5, 0) == 1.0
+ round_double(1.5, 0) == 2.0
+ round_double(2.5, 0) == 3.0
+ round_double(3.5, 0) == 4.0
+ round_double(4.5, 0) == 5.0
+ round_double(5.5, 0) == 6.0
+ round_double(6.5, 0) == 7.0
+
+ round_double(-25.0, -1) == -30.0
+ round_double(-15.0, -1) == -20.0
+ round_double(-5.0, -1) == -10.0
+ round_double(5.0, -1) == 10.0
+ round_double(15.0, -1) == 20.0
+ round_double(25.0, -1) == 30.0
+ round_double(35.0, -1) == 40.0
+ round_double(45.0, -1) == 50.0
+ round_double(55.0, -1) == 60.0
+ round_double(65.0, -1) == 70.0
+ round_double(75.0, -1) == 80.0
+ round_double(85.0, -1) == 90.0
+ round_double(95.0, -1) == 100.0
+ round_double(12325.0, -1) == 12330.0
+
+ round_double(350.0, -2) == 400.0
+ round_double(450.0, -2) == 500.0
+
+ almost_equal(round_double(0.5e21, -21), 1e21)
+ almost_equal(round_double(1.5e21, -21), 2e21)
+ almost_equal(round_double(2.5e21, -21), 3e21)
+ almost_equal(round_double(5.5e21, -21), 6e21)
+ almost_equal(round_double(8.5e21, -21), 9e21)
+
+ almost_equal(round_double(-1.5e22, -22), -2e22)
+ almost_equal(round_double(-0.5e22, -22), -1e22)
+ almost_equal(round_double(0.5e22, -22), 1e22)
+ almost_equal(round_double(1.5e22, -22), 2e22)
+
+ def test_round_half_even(self):
+ from pypy.rlib import rfloat
+ for func in (rfloat.round_double_short_repr,
+ rfloat.round_double_fallback_repr):
+ # 2.x behavior
+ assert func(2.5, 0, False) == 3.0
+ # 3.x behavior
+ assert func(2.5, 0, True) == 2.0
+
class TestLLtype(BaseTestRfloat, LLRtypeMixin):
@@ -226,4 +394,15 @@
class TestOOtype(BaseTestRfloat, OORtypeMixin):
- pass
+
+ def test_formatd(self):
+ skip('formatd is broken on ootype')
+
+ def test_formatd_repr(self):
+ skip('formatd is broken on ootype')
+
+ def test_formatd_huge(self):
+ skip('formatd is broken on ootype')
+
+ def test_string_to_float(self):
+ skip('string_to_float is broken on ootype')
diff --git a/pypy/tool/pytest/objspace.py b/pypy/tool/pytest/objspace.py
--- a/pypy/tool/pytest/objspace.py
+++ b/pypy/tool/pytest/objspace.py
@@ -66,8 +66,11 @@
py.test.skip("cannot runappdirect test: space needs %s = %s, "\
"while pypy-c was built with %s" % (key, value, has))
- for name in ('int', 'long', 'str', 'unicode', 'None'):
+ for name in ('int', 'long', 'str', 'unicode', 'None', 'ValueError',
+ 'OverflowError'):
setattr(self, 'w_' + name, eval(name))
+ import __builtin__ as __builtin__
+ self.builtin = __builtin__
def appexec(self, args, body):
body = body.lstrip()
diff --git a/pypy/translator/platform/linux.py
b/pypy/translator/platform/linux.py
--- a/pypy/translator/platform/linux.py
+++ b/pypy/translator/platform/linux.py
@@ -13,7 +13,8 @@
+ os.environ.get('LDFLAGS', '').split())
extra_libs = ('-lrt',)
cflags = tuple(
- ['-O3', '-pthread', '-fomit-frame-pointer',
+ ['-Os', # more compact and actually a bit faster
+ '-pthread', '-fomit-frame-pointer',
'-Wall', '-Wno-unused']
+ os.environ.get('CFLAGS', '').split())
standalone_only = ()
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit