Author: Ronan Lamy <ronan.l...@gmail.com> Branch: multiphase Changeset: r92276:fdd1b3877173 Date: 2017-08-28 18:33 +0100 http://bitbucket.org/pypy/pypy/changeset/fdd1b3877173/
Log: hg merge py3.5 diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py --- a/lib-python/2.7/ctypes/__init__.py +++ b/lib-python/2.7/ctypes/__init__.py @@ -361,17 +361,20 @@ if handle is None: if flags & _FUNCFLAG_CDECL: - self._handle = _ffi.CDLL(name, mode) + pypy_dll = _ffi.CDLL(name, mode) else: - self._handle = _ffi.WinDLL(name, mode) - else: - self._handle = handle + pypy_dll = _ffi.WinDLL(name, mode) + self.__pypy_dll__ = pypy_dll + handle = int(pypy_dll) + if _sys.maxint > 2 ** 32: + handle = int(handle) # long -> int + self._handle = handle def __repr__(self): - return "<%s '%s', handle %r at 0x%x>" % ( - self.__class__.__name__, self._name, self._handle, - id(self) & (_sys.maxint * 2 + 1)) - + return "<%s '%s', handle %x at %x>" % \ + (self.__class__.__name__, self._name, + (self._handle & (_sys.maxint*2 + 1)), + id(self) & (_sys.maxint*2 + 1)) def __getattr__(self, name): if name.startswith('__') and name.endswith('__'): diff --git a/lib-python/3/ctypes/__init__.py b/lib-python/3/ctypes/__init__.py --- a/lib-python/3/ctypes/__init__.py +++ b/lib-python/3/ctypes/__init__.py @@ -346,16 +346,18 @@ if handle is None: if flags & _FUNCFLAG_CDECL: - self._handle = _ffi.CDLL(name, mode) + pypy_dll = _ffi.CDLL(name, mode) else: - self._handle = _ffi.WinDLL(name, mode) - else: - self._handle = handle + pypy_dll = _ffi.WinDLL(name, mode) + self.__pypy_dll__ = pypy_dll + handle = int(pypy_dll) + self._handle = handle def __repr__(self): - return "<%s '%s', handle %r at 0x%x>" % ( - self.__class__.__name__, self._name, self._handle, - id(self) & (_sys.maxsize * 2 + 1)) + return "<%s '%s', handle %x at 0x%x>" % \ + (self.__class__.__name__, self._name, + (self._handle & (_sys.maxsize*2 + 1)), + id(self) & (_sys.maxsize*2 + 1)) def __getattr__(self, name): if name.startswith('__') and name.endswith('__'): diff --git a/lib-python/3/datetime.py b/lib-python/3/datetime.py --- a/lib-python/3/datetime.py +++ b/lib-python/3/datetime.py @@ -810,7 +810,8 @@ month = self._month if day is None: day = self._day - return date(year, month, day) + # PyPy fix: returns type(self)() instead of date() + return type(self)(year, month, day) # Comparisons of date objects with other. @@ -1285,7 +1286,8 @@ microsecond = self.microsecond if tzinfo is True: tzinfo = self.tzinfo - return time(hour, minute, second, microsecond, tzinfo) + # PyPy fix: returns type(self)() instead of time() + return type(self)(hour, minute, second, microsecond, tzinfo) # Pickle support. @@ -1497,7 +1499,8 @@ microsecond = self.microsecond if tzinfo is True: tzinfo = self.tzinfo - return datetime(year, month, day, hour, minute, second, microsecond, + # PyPy fix: returns type(self)() instead of datetime() + return type(self)(year, month, day, hour, minute, second, microsecond, tzinfo) def astimezone(self, tz=None): diff --git a/lib-python/3/test/test_sysconfig.py b/lib-python/3/test/test_sysconfig.py --- a/lib-python/3/test/test_sysconfig.py +++ b/lib-python/3/test/test_sysconfig.py @@ -397,9 +397,16 @@ self.assertTrue('linux' in suffix, suffix) if re.match('(i[3-6]86|x86_64)$', machine): if ctypes.sizeof(ctypes.c_char_p()) == 4: - self.assertTrue(suffix.endswith('i386-linux-gnu.so') \ - or suffix.endswith('x86_64-linux-gnux32.so'), - suffix) + self.assertTrue( + suffix.endswith(( + 'i386-linux-gnu.so', + 'i486-linux-gnu.so', + 'i586-linux-gnu.so', + 'i686-linux-gnu.so', + 'x86_64-linux-gnux32.so', + )), + suffix, + ) else: # 8 byte pointer size self.assertTrue(suffix.endswith('x86_64-linux-gnu.so'), suffix) diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py --- a/lib_pypy/_ctypes/basics.py +++ b/lib_pypy/_ctypes/basics.py @@ -82,7 +82,7 @@ return False def in_dll(self, dll, name): - return self.from_address(dll._handle.getaddressindll(name)) + return self.from_address(dll.__pypy_dll__.getaddressindll(name)) def from_buffer(self, obj, offset=0): size = self._sizeofinstances() diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py --- a/lib_pypy/_ctypes/function.py +++ b/lib_pypy/_ctypes/function.py @@ -430,7 +430,7 @@ ffires = restype.get_ffi_argtype() return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_) - cdll = self.dll._handle + cdll = self.dll.__pypy_dll__ try: ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes] ffi_restype = restype.get_ffi_argtype() diff --git a/lib_pypy/pyrepl/reader.py b/lib_pypy/pyrepl/reader.py --- a/lib_pypy/pyrepl/reader.py +++ b/lib_pypy/pyrepl/reader.py @@ -239,6 +239,10 @@ def __init__(self, console): self.buffer = [] + # Enable the use of `insert` without a `prepare` call - necessary to + # facilitate the tab completion hack implemented for + # <https://bugs.python.org/issue25660>. + self.pos = 0 self.ps1 = "->> " self.ps2 = "/>> " self.ps3 = "|.. " diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py --- a/lib_pypy/pyrepl/readline.py +++ b/lib_pypy/pyrepl/readline.py @@ -314,7 +314,8 @@ # history item: we use \r\n instead of just \n. If the history # file is passed to GNU readline, the extra \r are just ignored. history = self.get_reader().history - f = open(os.path.expanduser(filename), 'r', encoding='utf-8') + f = open(os.path.expanduser(filename), 'r', encoding='utf-8', + errors='replace') buffer = [] for line in f: if line.endswith('\r\n'): diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -10,9 +10,10 @@ class Module(W_Root): """A module.""" - _immutable_fields_ = ["w_dict?"] + _immutable_fields_ = ["w_dict?", "w_userclass?"] _frozen = False + w_userclass = None def __init__(self, space, w_name, w_dict=None): self.space = space @@ -148,6 +149,26 @@ self) return space.call_function(space.w_list, w_dict) + # These three methods are needed to implement '__class__' assignment + # between a module and a subclass of module. They give every module + # the ability to have its '__class__' set, manually. Note that if + # you instantiate a subclass of ModuleType in the first place, then + # you get an RPython instance of a subclass of Module created in the + # normal way by typedef.py. That instance has got its own + # getclass(), getslotvalue(), etc. but provided it has no __slots__, + # it is compatible with ModuleType for '__class__' assignment. + + def getclass(self, space): + if self.w_userclass is None: + return W_Root.getclass(self, space) + return self.w_userclass + + def setclass(self, space, w_cls): + self.w_userclass = w_cls + + def user_setup(self, space, w_subtype): + self.w_userclass = w_subtype + def init_extra_module_attrs(space, w_mod): w_dict = w_mod.getdict(space) diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py --- a/pypy/interpreter/test/test_module.py +++ b/pypy/interpreter/test/test_module.py @@ -220,3 +220,45 @@ import sys m = type(sys).__new__(type(sys)) assert not m.__dict__ + + def test_class_assignment_for_module(self): + import sys + modtype = type(sys) + class X(modtype): + _foobar_ = 42 + + m = X("yytest_moduleyy") + assert type(m) is m.__class__ is X + assert m._foobar_ == 42 + m.__class__ = modtype + assert type(m) is m.__class__ is modtype + assert not hasattr(m, '_foobar_') + + m = modtype("xxtest_modulexx") + assert type(m) is m.__class__ is modtype + m.__class__ = X + assert m._foobar_ == 42 + assert type(m) is m.__class__ is X + + sys.__class__ = modtype + assert type(sys) is sys.__class__ is modtype + sys.__class__ = X + assert sys._foobar_ == 42 + sys.__class__ = modtype + + class XX(modtype): + __slots__ = ['a', 'b'] + + x = XX("zztest_modulezz") + assert x.__class__ is XX + raises(AttributeError, "x.a") + x.a = 42 + assert x.a == 42 + x.a = 43 + assert x.a == 43 + assert 'a' not in x.__dict__ + del x.a + raises(AttributeError, "x.a") + raises(AttributeError, "del x.a") + raises(TypeError, "x.__class__ = X") + raises(TypeError, "sys.__class__ = XX") diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -130,7 +130,7 @@ return subcls _unique_subclass_cache = {} -def _getusercls(cls, reallywantdict=False): +def _getusercls(cls): from rpython.rlib import objectmodel from pypy.objspace.std.objectobject import W_ObjectObject from pypy.objspace.std.mapdict import (BaseUserClassMapdict, @@ -144,7 +144,7 @@ else: base_mixin = MapdictStorageMixin copy_methods = [BaseUserClassMapdict] - if reallywantdict or not typedef.hasdict: + if not typedef.hasdict: # the type has no dict, mapdict to provide the dict copy_methods.append(MapdictDictSupport) name += "Dict" 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 @@ -1661,7 +1661,7 @@ assert cpyext_glob_tid_ptr[0] == 0 cpyext_glob_tid_ptr[0] = tid - preexist_error = PyErr_Occurred(space) is not None + preexist_error = PyErr_Occurred(space) try: # Call the function result = call_external_function(func, *boxed_args) @@ -1685,17 +1685,19 @@ has_result = ret is not None # Check for exception consistency - has_error = PyErr_Occurred(space) is not None - if not preexist_error: - if has_error and has_result: - raise oefmt(space.w_SystemError, - "An exception was set, but function returned a " - "value") - elif not expect_null and not has_error and not has_result: - raise oefmt(space.w_SystemError, - "Function returned a NULL result without setting " - "an exception") - if has_error: + # XXX best attempt, will miss preexisting error that is + # overwritten with a new error of the same type + error = PyErr_Occurred(space) + has_new_error = (error is not None) and (error is not preexist_error) + if not expect_null and has_new_error and has_result: + raise oefmt(space.w_SystemError, + "An exception was set, but function returned a " + "value") + elif not expect_null and not has_new_error and not has_result: + raise oefmt(space.w_SystemError, + "Function returned a NULL result without setting " + "an exception") + elif has_new_error: state = space.fromcache(State) state.check_and_raise_exception() diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h --- a/pypy/module/cpyext/include/object.h +++ b/pypy/module/cpyext/include/object.h @@ -273,6 +273,11 @@ #define _PyGC_FINALIZED(o) 1 #define PyType_IS_GC(tp) 1 +#define PyObject_GC_Track(o) do { } while(0) +#define PyObject_GC_UnTrack(o) do { } while(0) +#define _PyObject_GC_TRACK(o) do { } while(0) +#define _PyObject_GC_UNTRACK(o) do { } while(0) + /* Utility macro to help write tp_traverse functions. * To use this macro, the tp_traverse function must name its arguments * "visit" and "arg". This is intended to keep tp_traverse functions 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 @@ -80,24 +80,6 @@ def PyObject_GC_Del(space, obj): PyObject_Free(space, obj) -@cpython_api([rffi.VOIDP], lltype.Void) -def PyObject_GC_Track(space, op): - """Adds the object op to the set of container objects tracked by the - collector. The collector can run at unexpected times so objects must be - valid while being tracked. This should be called once all the fields - followed by the tp_traverse handler become valid, usually near the - end of the constructor.""" - pass - -@cpython_api([rffi.VOIDP], lltype.Void) -def PyObject_GC_UnTrack(space, op): - """Remove the object op from the set of container objects tracked by the - collector. Note that PyObject_GC_Track() can be called again on - this object to add it back to the set of tracked objects. The deallocator - (tp_dealloc handler) should call this for the object before any of - the fields used by the tp_traverse handler become invalid.""" - pass - @cpython_api([PyObject], PyObjectP, error=CANNOT_FAIL) def _PyObject_GetDictPtr(space, op): return lltype.nullptr(PyObjectP.TO) @@ -311,7 +293,7 @@ PyErr_BadInternalCall(space) @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1) -def PyObject_RichCompareBool(space, ref1, ref2, opid_int): +def PyObject_RichCompareBool(space, w_o1, w_o2, opid_int): """Compare the values of o1 and o2 using the operation specified by opid, which must be one of Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, or Py_GE, corresponding to <, @@ -321,13 +303,13 @@ opid.""" # Quick result when objects are the same. # Guarantees that identity implies equality. - if ref1 is ref2: + if space.is_w(w_o1, w_o2): opid = rffi.cast(lltype.Signed, opid_int) if opid == Py_EQ: return 1 if opid == Py_NE: return 0 - w_res = PyObject_RichCompare(space, ref1, ref2, opid_int) + w_res = PyObject_RichCompare(space, w_o1, w_o2, opid_int) return int(space.is_true(w_res)) @cpython_api([PyObject], PyObject, result_is_ll=True) diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -294,6 +294,23 @@ def getitems_fixedsize(self, w_list): return self.getitems_unroll(w_list) + def copy_into(self, w_list, w_other): + w_other.strategy = self + w_other.lstorage = self.getstorage_copy(w_list) + + def clone(self, w_list): + storage = self.getstorage_copy(w_list) + w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, + self) + return w_clone + + def getitems_copy(self, w_list): + return self.getitems(w_list) # getitems copies anyway + + def getstorage_copy(self, w_list): + lst = self.getitems(w_list) + return self.erase(CPyListStorage(w_list.space, lst)) + #------------------------------------------ # all these methods fail or switch strategy and then call ListObjectStrategy's method @@ -301,23 +318,9 @@ w_list.switch_to_object_strategy() w_list.strategy.setslice(w_list, start, stop, step, length) - def get_sizehint(self): - return -1 - def init_from_list_w(self, w_list, list_w): raise NotImplementedError - def clone(self, w_list): - storage = w_list.lstorage # lstorage is tuple, no need to clone - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, - self) - w_clone.switch_to_object_strategy() - return w_clone - - def copy_into(self, w_list, w_other): - w_list.switch_to_object_strategy() - w_list.strategy.copy_into(w_list, w_other) - def _resize_hint(self, w_list, hint): pass @@ -325,13 +328,6 @@ w_list.switch_to_object_strategy() return w_list.strategy.find(w_list, w_item, start, stop) - def getitems_copy(self, w_list): - w_list.switch_to_object_strategy() - return w_list.strategy.getitems_copy(w_list) - - def getstorage_copy(self, w_list): - raise NotImplementedError - def append(self, w_list, w_item): w_list.switch_to_object_strategy() w_list.strategy.append(w_list, w_item) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -625,18 +625,6 @@ resized object or NULL on failure.""" raise NotImplementedError -@cpython_api([PyObject], lltype.Void) -def _PyObject_GC_TRACK(space, op): - """A macro version of PyObject_GC_Track(). It should not be used for - extension modules.""" - raise NotImplementedError - -@cpython_api([PyObject], lltype.Void) -def _PyObject_GC_UNTRACK(space, op): - """A macro version of PyObject_GC_UnTrack(). It should not be used for - extension modules.""" - raise NotImplementedError - @cpython_api([PyFrameObject], PyObject) def PyGen_New(space, frame): """Create and return a new generator object based on the frame object. A @@ -1516,13 +1504,6 @@ raise NotImplementedError -@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) -def PyType_IS_GC(space, o): - """Return true if the type object includes support for the cycle detector; this - tests the type flag Py_TPFLAGS_HAVE_GC.""" - raise NotImplementedError - - @cpython_api([], rffi.INT_real, error=-1) def PyUnicode_ClearFreeList(space, ): """Clear the free list. Return the total number of freed items.""" 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 @@ -24,6 +24,10 @@ def PyPy_Crash2(space): 1/0 +@api.cpython_api([api.PyObject], api.PyObject, result_is_ll=True) +def PyPy_Noop(space, pyobj): + return pyobj + class TestApi: def test_signature(self): common_functions = api.FUNCTIONS_BY_HEADER[api.pypy_decl] @@ -665,6 +669,7 @@ body = """ PyAPI_FUNC(PyObject*) PyPy_Crash1(void); PyAPI_FUNC(long) PyPy_Crash2(void); + PyAPI_FUNC(PyObject*) PyPy_Noop(PyObject*); static PyObject* foo_crash1(PyObject* self, PyObject *args) { return PyPy_Crash1(); @@ -688,9 +693,27 @@ int a = PyPy_Crash2(); return PyFloat_FromDouble(a); } + static PyObject* foo_noop(PyObject* self, PyObject* args) + { + Py_INCREF(args); + return PyPy_Noop(args); + } + static PyObject* foo_set(PyObject* self, PyObject *args) + { + PyErr_SetString(PyExc_TypeError, "clear called with no error"); + if (PyLong_Check(args)) { + Py_INCREF(args); + return args; + } + return NULL; + } static PyObject* foo_clear(PyObject* self, PyObject *args) { PyErr_Clear(); + if (PyLong_Check(args)) { + Py_INCREF(args); + return args; + } return NULL; } static PyMethodDef methods[] = { @@ -698,7 +721,9 @@ { "crash2", foo_crash2, METH_NOARGS }, { "crash3", foo_crash3, METH_NOARGS }, { "crash4", foo_crash4, METH_NOARGS }, - { "clear", foo_clear, METH_NOARGS }, + { "clear", foo_clear, METH_O }, + { "set", foo_set, METH_O }, + { "noop", foo_noop, METH_O }, { NULL } }; static struct PyModuleDef moduledef = { @@ -710,15 +735,46 @@ }; """ module = self.import_module(name='foo', body=body) + # uncaught interplevel exceptions are turned into SystemError - raises(SystemError, module.crash1) - raises(SystemError, module.crash2) - # caught exception + expected = "ZeroDivisionError('integer division or modulo by zero',)" + exc = raises(SystemError, module.crash1) + assert exc.value.args[0] == expected + + exc = raises(SystemError, module.crash2) + assert exc.value.args[0] == expected + + # caught exception, api.cpython_api return value works assert module.crash3() == -1 - # An exception was set, but function returned a value - raises(SystemError, module.crash4) - # No exception set, but NULL returned - raises(SystemError, module.clear) + + expected = 'An exception was set, but function returned a value' + # PyPy only incompatibility/extension + exc = raises(SystemError, module.crash4) + assert exc.value.args[0] == expected + + # An exception was set by the previous call, it can pass + # cleanly through a call that doesn't check error state + assert module.noop(1) == 1 + + # clear the exception but return NULL, signalling an error + expected = 'Function returned a NULL result without setting an exception' + exc = raises(SystemError, module.clear, None) + assert exc.value.args[0] == expected + + # Set an exception and return NULL + raises(TypeError, module.set, None) + + # clear any exception and return a value + assert module.clear(1) == 1 + + # Set an exception, but return non-NULL + expected = 'An exception was set, but function returned a value' + exc = raises(SystemError, module.set, 1) + assert exc.value.args[0] == expected + + + # Clear the exception and return a value, all is OK + assert module.clear(1) == 1 def test_new_exception(self): mod = self.import_extension('foo', [ 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 @@ -416,7 +416,7 @@ Py_buffer passed to it. """ module = self.import_extension('foo', [ - ("fillinfo", "METH_VARARGS", + ("fillinfo", "METH_NOARGS", """ Py_buffer buf; PyObject *str = PyBytes_FromString("hello, world."); @@ -468,7 +468,7 @@ object. """ module = self.import_extension('foo', [ - ("fillinfo", "METH_VARARGS", + ("fillinfo", "METH_NOARGS", """ Py_buffer buf; PyObject *str = PyBytes_FromString("hello, world."); @@ -514,7 +514,7 @@ PyBuffer_FillInfo fails if WRITABLE is passed but object is readonly. """ module = self.import_extension('foo', [ - ("fillinfo", "METH_VARARGS", + ("fillinfo", "METH_NOARGS", """ Py_buffer buf; PyObject *str = PyBytes_FromString("hello, world."); @@ -541,7 +541,7 @@ decremented by PyBuffer_Release. """ module = self.import_extension('foo', [ - ("release", "METH_VARARGS", + ("release", "METH_NOARGS", """ Py_buffer buf; buf.obj = PyBytes_FromString("release me!"); @@ -560,3 +560,20 @@ Py_RETURN_NONE; """)]) assert module.release() is None + + +class AppTestPyBuffer_Release(AppTestCpythonExtensionBase): + def test_richcomp_nan(self): + module = self.import_extension('foo', [ + ("comp_eq", "METH_VARARGS", + """ + PyObject *a = PyTuple_GetItem(args, 0); + PyObject *b = PyTuple_GetItem(args, 1); + int res = PyObject_RichCompareBool(a, b, Py_EQ); + return PyLong_FromLong(res); + """),]) + a = float('nan') + b = float('nan') + assert a is b + res = module.comp_eq(a, b) + assert res == 1 diff --git a/pypy/module/cpyext/test/test_sequence.py b/pypy/module/cpyext/test/test_sequence.py --- a/pypy/module/cpyext/test/test_sequence.py +++ b/pypy/module/cpyext/test/test_sequence.py @@ -226,6 +226,15 @@ w_l.inplace_mul(2) assert space.int_w(space.len(w_l)) == 10 + def test_getstorage_copy(self, space, api): + w = space.wrap + w_l = w([1, 2, 3, 4]) + api.PySequence_Fast(w_l, "foo") # converts + + w_l1 = w([]) + space.setitem(w_l1, space.newslice(w(0), w(0), w(1)), w_l) + assert map(space.unwrap, space.unpackiterable(w_l1)) == [1, 2, 3, 4] + class AppTestSequenceObject(AppTestCpythonExtensionBase): def test_fast(self): diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -636,6 +636,14 @@ else: WINERROR_TO_ERRNO, DEFAULT_WIN32_ERRNO = {}, 22 # EINVAL +if rwin32.WIN32: + _winerror_property = dict( + winerror = readwrite_attrproperty_w('w_winerror', W_OSError), + ) +else: + _winerror_property = dict() + + W_OSError.typedef = TypeDef( 'OSError', W_Exception.typedef, @@ -648,9 +656,9 @@ strerror = readwrite_attrproperty_w('w_strerror', W_OSError), filename = readwrite_attrproperty_w('w_filename', W_OSError), filename2= readwrite_attrproperty_w('w_filename2',W_OSError), - winerror = readwrite_attrproperty_w('w_winerror', W_OSError), characters_written = GetSetProperty(W_OSError.descr_get_written, W_OSError.descr_set_written), + **_winerror_property ) W_BlockingIOError = _new_exception( diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py --- a/pypy/module/imp/test/test_app.py +++ b/pypy/module/imp/test/test_app.py @@ -81,15 +81,17 @@ def test_suffixes(self): import imp for suffix, mode, type in imp.get_suffixes(): - if mode == imp.PY_SOURCE: + if type == imp.PY_SOURCE: assert suffix == '.py' - assert type == 'r' - elif mode == imp.PY_COMPILED: + assert mode == 'r' + elif type == imp.PY_COMPILED: assert suffix in ('.pyc', '.pyo') - assert type == 'rb' - elif mode == imp.C_EXTENSION: + assert mode == 'rb' + elif type == imp.C_EXTENSION: assert suffix.endswith(('.pyd', '.so')) - assert type == 'rb' + assert mode == 'rb' + else: + assert False, ("Unknown type", suffix, mode, type) def test_ext_suffixes(self): import _imp diff --git a/pypy/module/readline/test/test_readline.py b/pypy/module/readline/test/test_readline.py --- a/pypy/module/readline/test/test_readline.py +++ b/pypy/module/readline/test/test_readline.py @@ -29,3 +29,14 @@ readline.add_history("dummy") assert readline.get_history_item(1) == "entrée 1" assert readline.get_history_item(2) == "entrée 22" + + + def test_insert_text_leading_tab(self): + """ + A literal tab can be inserted at the beginning of a line. + + See <https://bugs.python.org/issue25660> + """ + import readline + readline.insert_text("\t") + assert readline.get_line_buffer() == b"\t" diff --git a/pypy/module/test_lib_pypy/README.txt b/pypy/module/test_lib_pypy/README.txt --- a/pypy/module/test_lib_pypy/README.txt +++ b/pypy/module/test_lib_pypy/README.txt @@ -1,4 +1,7 @@ This directory contains app-level tests are supposed to be run *after* translation. So you run them by saying: -pypy pytest.py <testfile.py> +../../goal/pypy-c pytest.py <testfile.py> + +Note that if you run it with a PyPy from elsewhere, it will not pick +up the changes to lib-python and lib_pypy. diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py b/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_loading.py @@ -43,6 +43,12 @@ cdll.LoadLibrary(lib) CDLL(lib) + def test__handle(self): + lib = find_library("c") + if lib: + cdll = CDLL(lib) + assert type(cdll._handle) in (int, long) + if os.name in ("nt", "ce"): def test_load_library(self): if is_resource_enabled("printing"): diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -364,8 +364,8 @@ characters, all remaining cased characters have lowercase. """ - @unwrap_spec(w_deletechars=WrappedDefault('')) - def descr_translate(self, space, w_table, w_deletechars): + @unwrap_spec(w_delete=WrappedDefault('')) + def descr_translate(self, space, w_table, w_delete): """B.translate(table[, deletechars]) -> copy of B Return a copy of the string B, where all characters occurring diff --git a/pypy/objspace/std/objectobject.py b/pypy/objspace/std/objectobject.py --- a/pypy/objspace/std/objectobject.py +++ b/pypy/objspace/std/objectobject.py @@ -141,13 +141,17 @@ def descr_set___class__(space, w_obj, w_newcls): from pypy.objspace.std.typeobject import W_TypeObject + from pypy.interpreter.module import Module + # if not isinstance(w_newcls, W_TypeObject): raise oefmt(space.w_TypeError, - "__class__ must be set to new-style class, not '%T' " + "__class__ must be set to a class, not '%T' " "object", w_newcls) - if not w_newcls.is_heaptype(): + if not (w_newcls.is_heaptype() or + w_newcls is space.gettypeobject(Module.typedef)): raise oefmt(space.w_TypeError, - "__class__ assignment: only for heap types") + "__class__ assignment only supported for heap types " + "or ModuleType subclasses") w_oldcls = space.type(w_obj) assert isinstance(w_oldcls, W_TypeObject) if (w_oldcls.get_full_instance_layout() == diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -742,8 +742,8 @@ DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)]) # for bytes and bytearray, overridden by unicode - @unwrap_spec(w_deletechars=WrappedDefault('')) - def descr_translate(self, space, w_table, w_deletechars): + @unwrap_spec(w_delete=WrappedDefault('')) + def descr_translate(self, space, w_table, w_delete): if space.is_w(w_table, space.w_None): table = self.DEFAULT_NOOP_TABLE else: @@ -753,7 +753,7 @@ "translation table must be 256 characters long") string = self._val(space) - deletechars = self._op_val(space, w_deletechars) + deletechars = self._op_val(space, w_delete) if len(deletechars) == 0: buf = self._builder(len(string)) for char in string: diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1284,6 +1284,65 @@ raises(ValueError, type, 'A\x00B', (), {}) raises(TypeError, type, b'A', (), {}) + def test_incomplete_extend(self): """ + # Extending an unitialized type with type.__mro__ is None must + # throw a reasonable TypeError exception, instead of failing + # with a segfault. + class M(type): + def mro(cls): + if cls.__mro__ is None and cls.__name__ != 'X': + try: + class X(cls): + pass + except TypeError: + found.append(1) + return type.mro(cls) + found = [] + class A(metaclass=M): + pass + assert found == [1] + """ + + def test_incomplete_extend_2(self): """ + # Same as test_incomplete_extend, with multiple inheritance + class M(type): + def mro(cls): + if cls.__mro__ is None and cls.__name__ == 'Second': + try: + class X(First, cls): + pass + except TypeError: + found.append(1) + return type.mro(cls) + found = [] + class Base(metaclass=M): + pass + class First(Base): + pass + class Second(Base): + pass + assert found == [1] + """ + + def test_incomplete_extend_3(self): """ + # this case "works", but gives a slightly strange error message + # on both CPython and PyPy + class M(type): + def mro(cls): + if cls.__mro__ is None and cls.__name__ == 'A': + try: + Base.__new__(cls) + except TypeError: + found.append(1) + return type.mro(cls) + found = [] + class Base(metaclass=M): + pass + class A(Base): + pass + assert found == [1] + """ + class AppTestWithMethodCacheCounter: spaceconfig = {"objspace.std.withmethodcachecounter": True} diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -546,19 +546,24 @@ space = self.space if self.is_heaptype(): return self.getdictvalue(space, '__module__') + elif self.is_cpytype(): + dot = self.name.rfind('.') else: dot = self.name.find('.') - if dot >= 0: - mod = self.name[:dot] - else: - mod = "builtins" - return space.newtext(mod) + if dot >= 0: + mod = self.name[:dot] + else: + mod = "builtins" + return space.newtext(mod) def getname(self, space): if self.is_heaptype(): result = self.name else: - dot = self.name.find('.') + if self.is_cpytype(): + dot = self.name.rfind('.') + else: + dot = self.name.find('.') if dot >= 0: result = self.name[dot+1:] else: @@ -1036,6 +1041,9 @@ for w_candidate in bases_w: if not isinstance(w_candidate, W_TypeObject): continue + if not w_candidate.hasmro: + raise oefmt(w_candidate.space.w_TypeError, + "Cannot extend an incomplete type '%N'", w_candidate) if w_bestbase is None: w_bestbase = w_candidate # for now continue diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py --- a/rpython/jit/backend/llsupport/regalloc.py +++ b/rpython/jit/backend/llsupport/regalloc.py @@ -552,10 +552,11 @@ self.reg_bindings[result_v] = loc return loc if v not in self.reg_bindings: + # v not in a register. allocate one for result_v and move v there prev_loc = self.frame_manager.loc(v) - loc = self.force_allocate_reg(v, forbidden_vars) + loc = self.force_allocate_reg(result_v, forbidden_vars) self.assembler.regalloc_mov(prev_loc, loc) - assert v in self.reg_bindings + return loc if self.longevity[v][1] > self.position: # we need to find a new place for variable v and # store result in the same place diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -504,7 +504,7 @@ clt.frame_info = rffi.cast(jitframe.JITFRAMEINFOPTR, frame_info) clt.frame_info.clear() # for now - if log: + if log or self._debug: number = looptoken.number operations = self._inject_debugging_code(looptoken, operations, 'e', number) @@ -589,7 +589,7 @@ faildescr.adr_jump_offset) self.mc.force_frame_size(DEFAULT_FRAME_BYTES) descr_number = compute_unique_id(faildescr) - if log: + if log or self._debug: operations = self._inject_debugging_code(faildescr, operations, 'b', descr_number) arglocs = self.rebuild_faillocs_from_descr(faildescr, inputargs) @@ -1618,18 +1618,6 @@ else: not_implemented("save_into_mem size = %d" % size) - def _genop_getfield(self, op, arglocs, resloc): - base_loc, ofs_loc, size_loc, sign_loc = arglocs - assert isinstance(size_loc, ImmedLoc) - source_addr = AddressLoc(base_loc, ofs_loc) - self.load_from_mem(resloc, source_addr, size_loc, sign_loc) - - genop_getfield_gc_i = _genop_getfield - genop_getfield_gc_r = _genop_getfield - genop_getfield_gc_f = _genop_getfield - genop_getfield_raw_i = _genop_getfield - genop_getfield_raw_f = _genop_getfield - def _genop_gc_load(self, op, arglocs, resloc): base_loc, ofs_loc, size_loc, sign_loc = arglocs assert isinstance(size_loc, ImmedLoc) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1305,7 +1305,7 @@ self.rm.possibly_free_var(tmpbox_high) def compute_hint_frame_locations(self, operations): - # optimization only: fill in the 'hint_frame_locations' dictionary + # optimization only: fill in the 'hint_frame_pos' dictionary # of 'fm' based on the JUMP at the end of the loop, by looking # at where we would like the boxes to be after the jump. op = operations[-1] @@ -1320,7 +1320,7 @@ self._compute_hint_frame_locations_from_descr(descr) #else: # The loop ends in a JUMP going back to a LABEL in the same loop. - # We cannot fill 'hint_frame_locations' immediately, but we can + # We cannot fill 'hint_frame_pos' immediately, but we can # wait until the corresponding consider_label() to know where the # we would like the boxes to be after the jump. diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -205,6 +205,18 @@ if not is_valid_fd(fd): from errno import EBADF raise OSError(EBADF, 'Bad file descriptor') + + def _bound_for_write(fd, count): + if count > 32767 and c_isatty(fd): + # CPython Issue #11395, PyPy Issue #2636: the Windows console + # returns an error (12: not enough space error) on writing into + # stdout if stdout mode is binary and the length is greater than + # 66,000 bytes (or less, depending on heap usage). Can't easily + # test that, because we need 'fd' to be non-redirected... + count = 32767 + elif count > 0x7fffffff: + count = 0x7fffffff + return count else: def is_valid_fd(fd): return 1 @@ -213,6 +225,9 @@ def validate_fd(fd): pass + def _bound_for_write(fd, count): + return count + def closerange(fd_low, fd_high): # this behaves like os.closerange() from Python 2.6. for fd in xrange(fd_low, fd_high): @@ -449,6 +464,7 @@ def write(fd, data): count = len(data) validate_fd(fd) + count = _bound_for_write(fd, count) with rffi.scoped_nonmovingbuffer(data) as buf: return handle_posix_error('write', c_write(fd, buf, count)) diff --git a/rpython/rtyper/tool/rffi_platform.py b/rpython/rtyper/tool/rffi_platform.py --- a/rpython/rtyper/tool/rffi_platform.py +++ b/rpython/rtyper/tool/rffi_platform.py @@ -710,7 +710,8 @@ size, _ = expected_size_and_sign return lltype.FixedSizeArray(fieldtype.OF, size/_sizeof(fieldtype.OF)) raise TypeError("conflict between translating python and compiler field" - " type %r for %r" % (fieldtype, fieldname)) + " type %r for symbol %r, expected size+sign %r" % ( + fieldtype, fieldname, expected_size_and_sign)) def expose_value_as_rpython(value): if intmask(value) == value: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit