[pypy-commit] pypy fix-broken-types: hg merge default
rlamy
pypy.commits at gmail.com
Sat Nov 18 23:33:20 EST 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: fix-broken-types
Changeset: r93078:93d764ccc576
Date: 2016-11-24 02:11 +0000
http://bitbucket.org/pypy/pypy/changeset/93d764ccc576/
Log: hg merge default
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -111,7 +111,9 @@
self.keywords = self.keywords + keywords
self.keywords_w = self.keywords_w + values_w
return
+ is_dict = False
if space.isinstance_w(w_starstararg, space.w_dict):
+ is_dict = True
keys_w = space.unpackiterable(w_starstararg)
else:
try:
@@ -125,7 +127,9 @@
keys_w = space.unpackiterable(w_keys)
keywords_w = [None] * len(keys_w)
keywords = [None] * len(keys_w)
- _do_combine_starstarargs_wrapped(space, keys_w, w_starstararg, keywords, keywords_w, self.keywords)
+ _do_combine_starstarargs_wrapped(
+ space, keys_w, w_starstararg, keywords, keywords_w, self.keywords,
+ is_dict)
self.keyword_names_w = keys_w
if self.keywords is None:
self.keywords = keywords
@@ -355,7 +359,7 @@
key)
def _do_combine_starstarargs_wrapped(space, keys_w, w_starstararg, keywords,
- keywords_w, existingkeywords):
+ keywords_w, existingkeywords, is_dict):
i = 0
for w_key in keys_w:
try:
@@ -374,7 +378,16 @@
"got multiple values for keyword argument '%s'",
key)
keywords[i] = key
- keywords_w[i] = space.getitem(w_starstararg, w_key)
+ if is_dict:
+ # issue 2435: bug-to-bug compatibility with cpython. for a subclass of
+ # dict, just ignore the __getitem__ and access the underlying dict
+ # directly
+ from pypy.objspace.descroperation import dict_getitem
+ w_descr = dict_getitem(space)
+ w_value = space.get_and_call_function(w_descr, w_starstararg, w_key)
+ else:
+ w_value = space.getitem(w_starstararg, w_key)
+ keywords_w[i] = w_value
i += 1
@jit.look_inside_iff(
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -120,6 +120,12 @@
raise OperationError(AttributeError, name)
return method(*args)
+ def lookup_in_type_where(self, cls, name):
+ return 'hopefully not needed', getattr(cls, name)
+
+ def get_and_call_function(self, w_descr, w_obj, *args):
+ return w_descr.__get__(w_obj)(*args)
+
def type(self, obj):
class Type:
def getname(self, space):
@@ -805,3 +811,19 @@
assert str(e) == "myerror"
else:
assert False, "Expected TypeError"
+
+ def test_dict_subclass_with_weird_getitem(self):
+ # issue 2435: bug-to-bug compatibility with cpython. for a subclass of
+ # dict, just ignore the __getitem__ and behave like ext_do_call in ceval.c
+ # which just uses the underlying dict
+ class d(dict):
+ def __getitem__(self, key):
+ return key
+
+ for key in ["foo", u"foo"]:
+ q = d()
+ q[key] = "bar"
+
+ def test(**kwargs):
+ return kwargs
+ assert test(**q) == {"foo": "bar"}
diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py
--- a/pypy/module/cpyext/dictobject.py
+++ b/pypy/module/cpyext/dictobject.py
@@ -137,8 +137,7 @@
"""This is the same as PyDict_Merge(a, b, 1) in C, or a.update(b) in
Python. Return 0 on success or -1 if an exception was raised.
"""
- space.call_method(space.w_dict, "update", w_obj, w_other)
- return 0
+ return PyDict_Merge(space, w_obj, w_other, 1)
@cpython_api([PyObject], PyObject)
def PyDict_Keys(space, w_obj):
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -252,7 +252,10 @@
def PyObject_Format(space, w_obj, w_format_spec):
if w_format_spec is None:
w_format_spec = space.wrap('')
- return space.call_method(w_obj, '__format__', w_format_spec)
+ w_ret = space.call_method(w_obj, '__format__', w_format_spec)
+ if space.isinstance_w(w_format_spec, space.w_unicode):
+ return space.unicode_from_object(w_ret)
+ return w_ret
@cpython_api([PyObject], PyObject)
def PyObject_Unicode(space, w_obj):
diff --git a/pypy/module/cpyext/test/test_dictobject.py b/pypy/module/cpyext/test/test_dictobject.py
--- a/pypy/module/cpyext/test/test_dictobject.py
+++ b/pypy/module/cpyext/test/test_dictobject.py
@@ -103,6 +103,17 @@
api.PyDict_Update(w_d, w_d2)
assert space.unwrap(w_d) == dict(a='b', c='d', e='f')
+ def test_update_doesnt_accept_list_of_tuples(self, space, api):
+ w_d = space.newdict()
+ space.setitem(w_d, space.wrap("a"), space.wrap("b"))
+
+ w_d2 = space.wrap([("c", "d"), ("e", "f")])
+
+ api.PyDict_Update(w_d, w_d2)
+ assert api.PyErr_Occurred() is space.w_AttributeError
+ api.PyErr_Clear()
+ assert space.unwrap(w_d) == dict(a='b') # unchanged
+
def test_iter(self, space, api):
w_dict = space.sys.getdict(space)
py_dict = make_ref(space, w_dict)
@@ -199,3 +210,18 @@
"""),
])
assert module.dict_proxy({'a': 1, 'b': 2}) == 2
+
+ def test_update(self):
+ module = self.import_extension('foo', [
+ ("update", "METH_VARARGS",
+ '''
+ if (PyDict_Update(PyTuple_GetItem(args, 0), PyTuple_GetItem(args, 1)))
+ return NULL;
+ Py_RETURN_NONE;
+ ''')])
+ d = {"a": 1}
+ module.update(d, {"c": 2})
+ assert d == dict(a=1, c=2)
+ d = {"a": 1}
+ raises(AttributeError, module.update, d, [("c", 2)])
+
diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -312,6 +312,16 @@
assert isinstance(dict(), collections.Mapping)
assert module.ismapping(dict())
+ def test_format_returns_unicode(self):
+ module = self.import_extension('foo', [
+ ("empty_format", "METH_O",
+ """
+ PyObject* empty_unicode = PyUnicode_FromStringAndSize("", 0);
+ PyObject* obj = PyObject_Format(args, empty_unicode);
+ return obj;
+ """)])
+ a = module.empty_format('hello')
+ assert isinstance(a, unicode)
class AppTestPyBuffer_FillInfo(AppTestCpythonExtensionBase):
"""
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -331,12 +331,34 @@
PyHeapTypeObject *heaptype = (PyHeapTypeObject *)args;
Py_INCREF(heaptype->ht_name);
return heaptype->ht_name;
+ '''),
+ ("setattr", "METH_O",
'''
- )
+ int ret;
+ PyObject* name = PyString_FromString("mymodule");
+ PyObject *obj = PyType_Type.tp_alloc(&PyType_Type, 0);
+ PyHeapTypeObject *type = (PyHeapTypeObject*)obj;
+ if ((type->ht_type.tp_flags & Py_TPFLAGS_HEAPTYPE) == 0)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Py_TPFLAGS_HEAPTYPE not set");
+ return NULL;
+ }
+ type->ht_type.tp_name = ((PyTypeObject*)args)->tp_name;
+ PyType_Ready(&type->ht_type);
+ ret = PyObject_SetAttrString((PyObject*)&type->ht_type,
+ "__module__", name);
+ Py_DECREF(name);
+ if (ret < 0)
+ return NULL;
+ return PyLong_FromLong(ret);
+ '''),
])
class C(object):
pass
assert module.name_by_heaptype(C) == "C"
+ assert module.setattr(C) == 0
+
def test_type_dict(self):
foo = self.import_module("foo")
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -469,7 +469,7 @@
W_TypeObject.__init__(self, space, name,
bases_w or [space.w_object], dict_w, force_new_layout=new_layout)
self.flag_cpytype = True
- self.flag_heaptype = False
+ self.flag_heaptype = pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE
# if a sequence or a mapping, then set the flag to force it
if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
self.flag_map_or_seq = 'S'
@@ -852,14 +852,14 @@
w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
track_reference(space, py_obj, w_obj)
# __init__ wraps all slotdefs functions from py_type via add_operators
- w_obj.__init__(space, py_type)
+ w_obj.__init__(space, py_type)
w_obj.ready()
finish_type_2(space, py_type, w_obj)
base = py_type.c_tp_base
if base:
# XXX refactor - parts of this are done in finish_type_2 -> inherit_slots
- if not py_type.c_tp_as_number:
+ if not py_type.c_tp_as_number:
py_type.c_tp_as_number = base.c_tp_as_number
py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_CHECKTYPES
py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -61,16 +61,24 @@
@specialize.memo()
def str_getitem(space):
"Utility that returns the app-level descriptor str.__getitem__."
- w_src, w_iter = space.lookup_in_type_where(space.w_str,
- '__getitem__')
- return w_iter
+ w_src, w_getitem = space.lookup_in_type_where(space.w_str,
+ '__getitem__')
+ return w_getitem
@specialize.memo()
def unicode_getitem(space):
"Utility that returns the app-level descriptor unicode.__getitem__."
- w_src, w_iter = space.lookup_in_type_where(space.w_unicode,
- '__getitem__')
- return w_iter
+ w_src, w_getitem = space.lookup_in_type_where(space.w_unicode,
+ '__getitem__')
+ return w_getitem
+
+ at specialize.memo()
+def dict_getitem(space):
+ "Utility that returns the app-level descriptor dict.__getitem__."
+ w_src, w_getitem = space.lookup_in_type_where(space.w_dict,
+ '__getitem__')
+ return w_getitem
+
def raiseattrerror(space, w_obj, name, w_descr=None):
if w_descr is None:
diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -22,7 +22,8 @@
"""Block annotator for RPython.
See description in doc/translation.txt."""
- def __init__(self, translator=None, policy=None, bookkeeper=None):
+ def __init__(self, translator=None, policy=None, bookkeeper=None,
+ keepgoing=False):
import rpython.rtyper.extfuncregistry # has side effects
if translator is None:
@@ -50,6 +51,9 @@
if bookkeeper is None:
bookkeeper = Bookkeeper(self)
self.bookkeeper = bookkeeper
+ self.keepgoing = keepgoing
+ self.failed_blocks = set()
+ self.errors = []
# temporary feature flag, see config.translation.brokentypes
# defaults to True in real translations
self.allow_bad_unions = False
@@ -206,6 +210,12 @@
else:
newgraphs = self.translator.graphs #all of them
got_blocked_blocks = False in self.annotated.values()
+ if self.failed_blocks:
+ text = ('Annotation failed, %s errors were recorded:' %
+ len(self.errors))
+ text += '\n-----'.join(str(e) for e in self.errors)
+ raise annmodel.AnnotatorError(text)
+
if got_blocked_blocks:
for graph in self.blocked_graphs.values():
self.blocked_graphs[graph] = True
@@ -352,6 +362,8 @@
#print '* processblock', block, cells
self.annotated[block] = graph
+ if block in self.failed_blocks:
+ return
if block in self.blocked_blocks:
del self.blocked_blocks[block]
try:
@@ -396,6 +408,10 @@
except annmodel.UnionError as e:
# Add source code to the UnionError
e.source = '\n'.join(source_lines(graph, block, None, long=True))
+ if self.keepgoing:
+ self.errors.append(e)
+ self.failed_blocks.add(block)
+ return
raise
# if the merged cells changed, we must redo the analysis
if unions != oldcells:
@@ -486,6 +502,10 @@
except annmodel.AnnotatorError as e: # note that UnionError is a subclass
e.source = gather_error(self, graph, block, i)
+ if self.keepgoing:
+ self.errors.append(e)
+ self.failed_blocks.add(block)
+ return
raise
else:
diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -193,6 +193,10 @@
"When true, enable the use of tagged pointers. "
"If false, use normal boxing",
default=False),
+ BoolOption("keepgoing",
+ "Continue annotating when errors are encountered, and report "
+ "them all at the end of the annotation phase",
+ default=False, cmdline="--keepgoing"),
BoolOption("lldebug",
"If true, makes an lldebug build", default=False,
cmdline="--lldebug"),
diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py
--- a/rpython/jit/metainterp/optimizeopt/intbounds.py
+++ b/rpython/jit/metainterp/optimizeopt/intbounds.py
@@ -399,9 +399,9 @@
def optimize_INT_EQ(self, op):
arg0 = self.get_box_replacement(op.getarg(0))
+ b1 = self.getintbound(arg0)
arg1 = self.get_box_replacement(op.getarg(1))
- b1 = self.getintbound(op.getarg(0))
- b2 = self.getintbound(op.getarg(1))
+ b2 = self.getintbound(arg1)
if b1.known_gt(b2):
self.make_constant_int(op, 0)
elif b1.known_lt(b2):
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -323,6 +323,8 @@
def register_replacement_for(replaced_function, sandboxed_name=None):
def wrap(func):
from rpython.rtyper.extregistry import ExtRegistryEntry
+ # to support calling func directly
+ func._sandbox_external_name = sandboxed_name
class ExtRegistry(ExtRegistryEntry):
_about_ = replaced_function
def compute_annotation(self):
diff --git a/rpython/rlib/rfloat.py b/rpython/rlib/rfloat.py
--- a/rpython/rlib/rfloat.py
+++ b/rpython/rlib/rfloat.py
@@ -1,6 +1,7 @@
"""Float constants"""
import math, struct
+from math import isinf, isnan, copysign, acosh, asinh, atanh, log1p, expm1
from rpython.annotator.model import SomeString, SomeChar
from rpython.rlib import objectmodel, unroll
@@ -184,104 +185,6 @@
INFINITY = 1e200 * 1e200
NAN = abs(INFINITY / INFINITY) # bah, INF/INF gives us -NAN?
-try:
- # Try to get math functions added in 2.6.
- from math import isinf, isnan, copysign, acosh, asinh, atanh, log1p
-except ImportError:
- @not_rpython
- def isinf(x):
- return x == INFINITY or x == -INFINITY
-
- @not_rpython
- def isnan(v):
- return v != v
-
- @not_rpython
- def copysign(x, y):
- """Return x with the sign of y"""
- if x < 0.:
- x = -x
- if y > 0. or (y == 0. and math.atan2(y, -1.) > 0.):
- return x
- else:
- return -x
-
- _2_to_m28 = 3.7252902984619141E-09; # 2**-28
- _2_to_p28 = 268435456.0; # 2**28
- _ln2 = 6.93147180559945286227E-01
-
- @not_rpython
- def acosh(x):
- if isnan(x):
- return NAN
- if x < 1.:
- raise ValueError("math domain error")
- if x >= _2_to_p28:
- if isinf(x):
- return x
- else:
- return math.log(x) + _ln2
- if x == 1.:
- return 0.
- if x >= 2.:
- t = x * x
- return math.log(2. * x - 1. / (x + math.sqrt(t - 1.0)))
- t = x - 1.0
- return log1p(t + math.sqrt(2. * t + t * t))
-
- @not_rpython
- def asinh(x):
- absx = abs(x)
- if not isfinite(x):
- return x
- if absx < _2_to_m28:
- return x
- if absx > _2_to_p28:
- w = math.log(absx) + _ln2
- elif absx > 2.:
- w = math.log(2. * absx + 1. / (math.sqrt(x * x + 1.) + absx))
- else:
- t = x * x
- w = log1p(absx + t / (1. + math.sqrt(1. + t)))
- return copysign(w, x)
-
- @not_rpython
- def atanh(x):
- if isnan(x):
- return x
- absx = abs(x)
- if absx >= 1.:
- raise ValueError("math domain error")
- if absx < _2_to_m28:
- return x
- if absx < .5:
- t = absx + absx
- t = .5 * log1p(t + t * absx / (1. - absx))
- else:
- t = .5 * log1p((absx + absx) / (1. - absx))
- return copysign(t, x)
-
- @not_rpython
- def log1p(x):
- if abs(x) < DBL_EPSILON // 2.:
- return x
- elif -.5 <= x <= 1.:
- y = 1. + x
- return math.log(y) - ((y - 1.) - x) / y
- else:
- return math.log(1. + x)
-
-try:
- from math import expm1 # Added in Python 2.7.
-except ImportError:
- @not_rpython
- def expm1(x):
- if abs(x) < .7:
- u = math.exp(x)
- if u == 1.:
- return x
- return (u - 1.) * x / math.log(u)
- return math.exp(x) - 1.
def log2(x):
# Uses an algorithm that should:
diff --git a/rpython/translator/sandbox/test/test_sandbox.py b/rpython/translator/sandbox/test/test_sandbox.py
--- a/rpython/translator/sandbox/test/test_sandbox.py
+++ b/rpython/translator/sandbox/test/test_sandbox.py
@@ -65,6 +65,24 @@
f.close()
assert tail == ""
+def test_open_dup_rposix():
+ from rpython.rlib import rposix
+ def entry_point(argv):
+ fd = rposix.open("/tmp/foobar", os.O_RDONLY, 0777)
+ assert fd == 77
+ fd2 = rposix.dup(fd)
+ assert fd2 == 78
+ return 0
+
+ exe = compile(entry_point)
+ g, f = run_in_subprocess(exe)
+ expect(f, g, "ll_os.ll_os_open", ("/tmp/foobar", os.O_RDONLY, 0777), 77)
+ expect(f, g, "ll_os.ll_os_dup", (77, True), 78)
+ g.close()
+ tail = f.read()
+ f.close()
+ assert tail == ""
+
def test_read_write():
def entry_point(argv):
fd = os.open("/tmp/foobar", os.O_RDONLY, 0777)
diff --git a/rpython/translator/translator.py b/rpython/translator/translator.py
--- a/rpython/translator/translator.py
+++ b/rpython/translator/translator.py
@@ -67,7 +67,8 @@
if self.annotator is not None:
raise ValueError("we already have an annotator")
from rpython.annotator.annrpython import RPythonAnnotator
- self.annotator = RPythonAnnotator(self, policy=policy)
+ self.annotator = RPythonAnnotator(
+ self, policy=policy, keepgoing=self.config.translation.keepgoing)
self.annotator.allow_bad_unions = self.config.translation.brokentypes
return self.annotator
More information about the pypy-commit
mailing list