Author: Matti Picus <matti.pi...@gmail.com> Branch: py3.6 Changeset: r96097:805c1a75f5f0 Date: 2019-02-19 21:06 +0200 http://bitbucket.org/pypy/pypy/changeset/805c1a75f5f0/
Log: merge default into branch diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -175,7 +175,7 @@ value = misc.read_raw_ulong_data(cdata, self.size) # r_uint try: utf8 = rutf8.unichr_as_utf8(value, allow_surrogates=True) - except ValueError: + except rutf8.OutOfRange: if self.is_signed_wchar: s = hex(intmask(value)) else: diff --git a/pypy/module/_cffi_backend/wchar_helper.py b/pypy/module/_cffi_backend/wchar_helper.py --- a/pypy/module/_cffi_backend/wchar_helper.py +++ b/pypy/module/_cffi_backend/wchar_helper.py @@ -24,7 +24,7 @@ j += 1 try: rutf8.unichr_as_utf8_append(u, ch, allow_surrogates=True) - except ValueError: + except rutf8.OutOfRange: raise OutOfRange(ch) return u.build(), length 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 @@ -2,6 +2,7 @@ from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError from pypy.objspace.std.classdict import ClassDictStrategy +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.typedef import GetSetProperty from pypy.module.cpyext.api import ( cpython_api, CANNOT_FAIL, build_type_checkers_flags, Py_ssize_t, cts, @@ -71,68 +72,59 @@ @cpython_api([PyObject, PyObject], PyObject, error=CANNOT_FAIL, result_borrowed=True) def PyDict_GetItem(space, w_dict, w_key): - try: - w_res = space.getitem(w_dict, w_key) - except: - return None + if not isinstance(w_dict, W_DictMultiObject): + raise PyErr_BadInternalCall(space) # NOTE: this works so far because all our dict strategies store # *values* as full objects, which stay alive as long as the dict is # alive and not modified. So we can return a borrowed ref. # XXX this is wrong with IntMutableCell. Hope it works... - return w_res + return w_dict.getitem(w_key) @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1) def PyDict_SetItem(space, w_dict, w_key, w_obj): - if PyDict_Check(space, w_dict): - space.setitem(w_dict, w_key, w_obj) - return 0 - else: - PyErr_BadInternalCall(space) + if not isinstance(w_dict, W_DictMultiObject): + raise PyErr_BadInternalCall(space) + w_dict.setitem(w_key, w_obj) + return 0 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1) def PyDict_DelItem(space, w_dict, w_key): - if PyDict_Check(space, w_dict): - space.delitem(w_dict, w_key) - return 0 - else: - PyErr_BadInternalCall(space) + if not isinstance(w_dict, W_DictMultiObject): + raise PyErr_BadInternalCall(space) + w_dict.descr_delitem(space, w_key) + return 0 @cpython_api([PyObject, CONST_STRING, PyObject], rffi.INT_real, error=-1) def PyDict_SetItemString(space, w_dict, key_ptr, w_obj): - if PyDict_Check(space, w_dict): - key = rffi.charp2str(key_ptr) - space.setitem_str(w_dict, key, w_obj) - return 0 - else: - PyErr_BadInternalCall(space) + w_key = space.newtext(rffi.charp2str(key_ptr)) + if not isinstance(w_dict, W_DictMultiObject): + raise PyErr_BadInternalCall(space) + w_dict.setitem(w_key, w_obj) + return 0 @cpython_api([PyObject, CONST_STRING], PyObject, error=CANNOT_FAIL, result_borrowed=True) def PyDict_GetItemString(space, w_dict, key): """This is the same as PyDict_GetItem(), but key is specified as a char*, rather than a PyObject*.""" - try: - w_res = space.finditem_str(w_dict, rffi.charp2str(key)) - except: - w_res = None + w_key = space.newtext(rffi.charp2str(key)) + if not isinstance(w_dict, W_DictMultiObject): + raise PyErr_BadInternalCall(space) # NOTE: this works so far because all our dict strategies store # *values* as full objects, which stay alive as long as the dict is # alive and not modified. So we can return a borrowed ref. # XXX this is wrong with IntMutableCell. Hope it works... - return w_res + return w_dict.getitem(w_key) @cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=-1) def PyDict_DelItemString(space, w_dict, key_ptr): """Remove the entry in dictionary p which has a key specified by the string key. Return 0 on success or -1 on failure.""" - if PyDict_Check(space, w_dict): - key = rffi.charp2str(key_ptr) - # our dicts dont have a standardized interface, so we need - # to go through the space - space.delitem(w_dict, space.newtext(key)) - return 0 - else: - PyErr_BadInternalCall(space) + w_key = space.newtext(rffi.charp2str(key_ptr)) + if not isinstance(w_dict, W_DictMultiObject): + raise PyErr_BadInternalCall(space) + w_dict.descr_delitem(space, w_key) + return 0 @cpython_api([PyObject], Py_ssize_t, error=-1) def PyDict_Size(space, w_obj): @@ -191,7 +183,7 @@ """ override = rffi.cast(lltype.Signed, override) w_keys = space.call_method(w_b, "keys") - for w_key in space.iteriterable(w_keys): + for w_key in space.iteriterable(w_keys): if not _has_val(space, w_a, w_key) or override != 0: space.setitem(w_a, w_key, space.getitem(w_b, w_key)) return 0 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 @@ -332,3 +332,67 @@ assert module.dict_delitem(d, 'a') == 0 r = module.dict_next({'a': 1, 'b': 2}) assert r == 2 + + def test_subclassing(self): + module = self.import_extension('foo', [ + ("dict_setitem", "METH_VARARGS", + """ + PyObject *d, *key, *value; + if (!PyArg_ParseTuple(args, "OOO", &d, &key, &value)) { + return NULL; + } + if (PyDict_SetItem(d, key, value) < 0) { + return NULL; + } + Py_RETURN_NONE; + """), + ("dict_delitem", "METH_VARARGS", + """ + PyObject *d, *key; + if (!PyArg_ParseTuple(args, "OO", &d, &key)) { + return NULL; + } + if (PyDict_DelItem(d, key) < 0) { + return NULL; + } + Py_RETURN_NONE; + """), + ("dict_getitem", "METH_VARARGS", + """ + PyObject *d, *key, *result; + if (!PyArg_ParseTuple(args, "OO", &d, &key)) { + return NULL; + } + result = PyDict_GetItem(d, key); + Py_XINCREF(result); + return result; + """), + ]) + + class mydict(dict): + def __setitem__(self, key, value): + dict.__setitem__(self, key, 42) + + def __delitem__(self, key): + dict.__setitem__(self, key, None) + d = {} + module.dict_setitem(d, 1, 2) + assert d[1] == 2 + d = mydict() + d[1] = 2 + assert d[1] == 42 + module.dict_setitem(d, 2, 3) + assert d[2] == 3 + del d[2] + assert d[2] is None + module.dict_delitem(d, 2) + assert 2 not in d + + class mydict2(dict): + def __getitem__(self, key): + return 42 + + d = mydict2() + d[1] = 2 + assert d[1] == 42 + assert module.dict_getitem(d, 1) == 2 diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -479,7 +479,7 @@ if do_unicode: try: c = rutf8.unichr_as_utf8(r_uint(n)) - except ValueError: + except rutf8.OutOfRange: raise oefmt(space.w_OverflowError, "unicode character code out of range") self.std_wp(c, False) diff --git a/rpython/rlib/rutf8.py b/rpython/rlib/rutf8.py --- a/rpython/rlib/rutf8.py +++ b/rpython/rlib/rutf8.py @@ -30,6 +30,11 @@ MAXUNICODE = 0x10ffff allow_surrogate_by_default = False + +class OutOfRange(Exception): + def __init__(self, code): + self.code = code + # we need a way to accept both r_uint and int(nonneg=True) #@signature(types.int_nonneg(), types.bool(), returns=types.str()) def unichr_as_utf8(code, allow_surrogates=False): @@ -44,7 +49,7 @@ return chr((0xc0 | (code >> 6))) + chr((0x80 | (code & 0x3f))) if code <= r_uint(0xFFFF): if not allow_surrogates and 0xD800 <= code <= 0xDfff: - raise ValueError + raise OutOfRange(code) return (chr((0xe0 | (code >> 12))) + chr((0x80 | ((code >> 6) & 0x3f))) + chr((0x80 | (code & 0x3f)))) @@ -53,7 +58,7 @@ chr((0x80 | ((code >> 12) & 0x3f))) + chr((0x80 | ((code >> 6) & 0x3f))) + chr((0x80 | (code & 0x3f)))) - raise ValueError + raise OutOfRange(code) @try_inline def unichr_as_utf8_append(builder, code, allow_surrogates=False): @@ -89,7 +94,7 @@ builder.append(chr((0x80 | ((code >> 6) & 0x3f)))) builder.append(chr((0x80 | (code & 0x3f)))) return - raise ValueError('character U+%x is not in range [U+0000; U+10ffff]' % code) + raise OutOfRange(code) @dont_inline def _nonascii_unichr_as_utf8_append_nosurrogates(builder, code): @@ -110,7 +115,7 @@ builder.append(chr((0x80 | ((code >> 6) & 0x3f)))) builder.append(chr((0x80 | (code & 0x3f)))) return - raise ValueError + raise OutOfRange(code) # note - table lookups are really slow. Measured on various elements of obama diff --git a/rpython/rlib/test/test_rutf8.py b/rpython/rlib/test/test_rutf8.py --- a/rpython/rlib/test/test_rutf8.py +++ b/rpython/rlib/test/test_rutf8.py @@ -9,7 +9,7 @@ def test_unichr_as_utf8(c, allow_surrogates): i = ord(c) if not allow_surrogates and 0xD800 <= i <= 0xDFFF: - with pytest.raises(ValueError): + with pytest.raises(rutf8.OutOfRange): rutf8.unichr_as_utf8(i, allow_surrogates) else: u = rutf8.unichr_as_utf8(i, allow_surrogates) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit