[pypy-commit] pypy multiphase: hg merge py3.5
rlamy
pypy.commits at gmail.com
Mon Aug 28 17:52:53 EDT 2017
Author: Ronan Lamy <ronan.lamy at 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)
- at 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
-
- at 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
- at 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
-
- at 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
- at 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
+ at 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:
More information about the pypy-commit
mailing list