Author: Ronny Pfannschmidt <opensou...@ronnypfannschmidt.de> Branch: refine-testrunner Changeset: r73240:a9df5830e867 Date: 2014-02-02 17:22 +0100 http://bitbucket.org/pypy/pypy/changeset/a9df5830e867/
Log: merge from default diff too long, truncating to 2000 out of 5591 lines diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -426,25 +426,12 @@ Could we use LLVM? ------------------ -In theory yes. But we tried to use it 5 or 6 times already, as a -translation backend or as a JIT backend --- and failed each time. +There is a (static) translation backend using LLVM in the branch +``llvm-translation-backend``. It can translate PyPy with or without the JIT on +Linux. -In more details: using LLVM as a (static) translation backend is -pointless nowadays because you can generate C code and compile it with -clang. (Note that compiling PyPy with clang gives a result that is not -faster than compiling it with gcc.) We might in theory get extra -benefits from LLVM's GC integration, but this requires more work on the -LLVM side before it would be remotely useful. Anyway, it could be -interfaced via a custom primitive in the C code. - -On the other hand, using LLVM as our JIT backend looks interesting as -well --- but again we made an attempt, and it failed: LLVM has no way to -patch the generated machine code. - -So the position of the core PyPy developers is that if anyone wants to -make an N+1'th attempt with LLVM, they are welcome, and will be happy to -provide help in the IRC channel, but they are left with the burden of proof -that (a) it works and (b) it gives important benefits. +Using LLVM as our JIT backend looks interesting as well -- we made an attempt, +but it failed: LLVM has no way to patch the generated machine code. ---------------------- How do I compile PyPy? diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -52,3 +52,8 @@ .. branch: annotator Remove FlowObjSpace. Improve cohesion between rpython.flowspace and rpython.annotator. + +.. branch: detect-immutable-fields +mapdicts keep track of whether or not an attribute is every assigned to +multiple times. If it's only assigned once then an elidable lookup is used when +possible. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -232,9 +232,8 @@ raise operationerrfmt(space.w_TypeError, msg, w_result) def ord(self, space): - typename = space.type(self).getname(space) - msg = "ord() expected string of length 1, but %s found" - raise operationerrfmt(space.w_TypeError, msg, typename) + msg = "ord() expected string of length 1, but %T found" + raise operationerrfmt(space.w_TypeError, msg, self) def __spacebind__(self, space): return self diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -6,7 +6,7 @@ from errno import EINTR from rpython.rlib import jit -from rpython.rlib.objectmodel import we_are_translated +from rpython.rlib.objectmodel import we_are_translated, specialize from pypy.interpreter import debug @@ -40,12 +40,11 @@ self.debug_excs = [] def clear(self, space): - # for sys.exc_clear() - self.w_type = space.w_None - self._w_value = space.w_None - self._application_traceback = None - if not we_are_translated(): - del self.debug_excs[:] + # XXX remove this method. The point is that we cannot always + # hack at 'self' to clear w_type and _w_value, because in some + # corner cases the OperationError will be used again: see + # test_interpreter.py:test_with_statement_and_sys_clear. + pass def match(self, space, w_check_class): "Check if this application-level exception matches 'w_check_class'." @@ -300,6 +299,10 @@ """ self._application_traceback = traceback +@specialize.memo() +def get_cleared_operation_error(space): + return OperationError(space.w_None, space.w_None) + # ____________________________________________________________ # optimization only: avoid the slowest operation -- the string # formatting with '%' -- in the common case were we don't @@ -371,8 +374,8 @@ class OpErrFmtNoArgs(OperationError): def __init__(self, w_type, value): + self._value = value self.setup(w_type) - self._value = value def get_w_value(self, space): w_value = self._w_value diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -1,5 +1,5 @@ import sys -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, get_cleared_operation_error from rpython.rlib.unroll import unrolling_iterable from rpython.rlib import jit @@ -217,6 +217,17 @@ if frame: # else, the exception goes nowhere and is lost frame.last_exception = operror + def clear_sys_exc_info(self): + # Find the frame out of which sys_exc_info() would return its result, + # and hack this frame's last_exception to become the cleared + # OperationError (which is different from None!). + frame = self.gettopframe_nohidden() + while frame: + if frame.last_exception is not None: + frame.last_exception = get_cleared_operation_error(self.space) + break + frame = self.getnextframe_nohidden(frame) + @jit.dont_look_inside def settrace(self, w_func): """Set the global trace function.""" diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -744,6 +744,9 @@ else: raise OperationError(space.w_TypeError, space.wrap("raise: no active exception to re-raise")) + if operror.w_type is space.w_None: + raise OperationError(space.w_TypeError, + space.wrap("raise: the exception to re-raise was cleared")) # re-raise, no new traceback obj will be attached self.last_exception = operror raise RaiseWithExplicitTraceback(operror) diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py --- a/pypy/interpreter/test/test_interpreter.py +++ b/pypy/interpreter/test/test_interpreter.py @@ -311,3 +311,73 @@ assert str(e) == "maximum recursion depth exceeded" else: assert 0, "should have raised!" + + def test_with_statement_and_sys_clear(self): + import sys + class CM(object): + def __enter__(self): + return self + def __exit__(self, exc_type, exc_value, tb): + sys.exc_clear() + try: + with CM(): + 1 / 0 + raise AssertionError("should not be reached") + except ZeroDivisionError: + pass + + def test_sys_clear_while_handling_exception(self): + import sys + def f(): + try: + some_missing_name + except NameError: + g() + assert sys.exc_info()[0] is NameError + def g(): + assert sys.exc_info()[0] is NameError + try: + 1 / 0 + except ZeroDivisionError: + assert sys.exc_info()[0] is ZeroDivisionError + sys.exc_clear() + assert sys.exc_info()[0] is None + h() + assert sys.exc_info()[0] is None + def h(): + assert sys.exc_info()[0] is None + f() + + def test_sys_clear_while_handling_exception_nested(self): + import sys + def f(): + try: + some_missing_name + except NameError: + g() + assert sys.exc_info()[0] is NameError + def g(): + assert sys.exc_info()[0] is NameError + try: + 1 / 0 + except ZeroDivisionError: + assert sys.exc_info()[0] is ZeroDivisionError + h1() + assert sys.exc_info()[0] is None + h() + assert sys.exc_info()[0] is None + def h(): + assert sys.exc_info()[0] is None + def h1(): + sys.exc_clear() + f() + + def test_sys_clear_reraise(self): + import sys + def f(): + try: + 1 / 0 + except ZeroDivisionError: + sys.exc_clear() + raise + raises(TypeError, f) diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -3,7 +3,7 @@ from rpython.rlib.objectmodel import we_are_translated from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.typeobject import MethodCache -from pypy.objspace.std.mapdict import IndexCache +from pypy.objspace.std.mapdict import MapAttrCache from rpython.rlib import rposix, rgc @@ -35,7 +35,7 @@ cache.misses = {} cache.hits = {} if space.config.objspace.std.withmapdict: - cache = space.fromcache(IndexCache) + cache = space.fromcache(MapAttrCache) cache.misses = {} cache.hits = {} @@ -45,7 +45,7 @@ in the mapdict cache with the given attribute name.""" assert space.config.objspace.std.withmethodcachecounter assert space.config.objspace.std.withmapdict - cache = space.fromcache(IndexCache) + cache = space.fromcache(MapAttrCache) return space.newtuple([space.newint(cache.hits.get(name, 0)), space.newint(cache.misses.get(name, 0))]) 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 @@ -400,16 +400,16 @@ '_PyObject_CallFunction_SizeT', '_PyObject_CallMethod_SizeT', 'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject', - 'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', '_Py_init_bufferobject', + 'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', '_Py_get_buffer_type', 'PyCObject_FromVoidPtr', 'PyCObject_FromVoidPtrAndDesc', 'PyCObject_AsVoidPtr', 'PyCObject_GetDesc', 'PyCObject_Import', 'PyCObject_SetVoidPtr', - 'PyCObject_Type', '_Py_init_pycobject', + 'PyCObject_Type', '_Py_get_cobject_type', 'PyCapsule_New', 'PyCapsule_IsValid', 'PyCapsule_GetPointer', 'PyCapsule_GetName', 'PyCapsule_GetDestructor', 'PyCapsule_GetContext', 'PyCapsule_SetPointer', 'PyCapsule_SetName', 'PyCapsule_SetDestructor', - 'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', '_Py_init_capsule', + 'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', '_Py_get_capsule_type', 'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer', @@ -691,17 +691,25 @@ prefix = 'PyPy' else: prefix = 'cpyexttest' - init_buffer = rffi.llexternal('_%s_init_bufferobject' % prefix, [], lltype.Void, - compilation_info=eci, releasegil=False) - init_pycobject = rffi.llexternal('_%s_init_pycobject' % prefix, [], lltype.Void, - compilation_info=eci, releasegil=False) - init_capsule = rffi.llexternal('_%s_init_capsule' % prefix, [], lltype.Void, - compilation_info=eci, releasegil=False) - INIT_FUNCTIONS.extend([ - lambda space: init_buffer(), - lambda space: init_pycobject(), - lambda space: init_capsule(), - ]) + # jump through hoops to avoid releasing the GIL during initialization + # of the cpyext module. The C functions are called with no wrapper, + # but must not do anything like calling back PyType_Ready(). We + # use them just to get a pointer to the PyTypeObjects defined in C. + get_buffer_type = rffi.llexternal('_%s_get_buffer_type' % prefix, + [], PyTypeObjectPtr, + compilation_info=eci, _nowrapper=True) + get_cobject_type = rffi.llexternal('_%s_get_cobject_type' % prefix, + [], PyTypeObjectPtr, + compilation_info=eci, _nowrapper=True) + get_capsule_type = rffi.llexternal('_%s_get_capsule_type' % prefix, + [], PyTypeObjectPtr, + compilation_info=eci, _nowrapper=True) + def init_types(space): + from pypy.module.cpyext.typeobject import py_type_ready + py_type_ready(space, get_buffer_type()) + py_type_ready(space, get_cobject_type()) + py_type_ready(space, get_capsule_type()) + INIT_FUNCTIONS.append(init_types) from pypy.module.posix.interp_posix import add_fork_hook reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void, compilation_info=eci) diff --git a/pypy/module/cpyext/include/pyconfig.h b/pypy/module/cpyext/include/pyconfig.h --- a/pypy/module/cpyext/include/pyconfig.h +++ b/pypy/module/cpyext/include/pyconfig.h @@ -15,6 +15,8 @@ #define HAVE_UNICODE #define WITHOUT_COMPLEX #define HAVE_WCHAR_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_STAT_H 1 /* PyPy supposes Py_UNICODE == wchar_t */ #define HAVE_USABLE_WCHAR_T 1 diff --git a/pypy/module/cpyext/include/pyport.h b/pypy/module/cpyext/include/pyport.h --- a/pypy/module/cpyext/include/pyport.h +++ b/pypy/module/cpyext/include/pyport.h @@ -64,4 +64,45 @@ # error "Python needs a typedef for Py_uintptr_t in pyport.h." #endif /* HAVE_UINTPTR_T */ +/******************************* + * stat() and fstat() fiddling * + *******************************/ + +/* We expect that stat and fstat exist on most systems. + * It's confirmed on Unix, Mac and Windows. + * If you don't have them, add + * #define DONT_HAVE_STAT + * and/or + * #define DONT_HAVE_FSTAT + * to your pyconfig.h. Python code beyond this should check HAVE_STAT and + * HAVE_FSTAT instead. + * Also + * #define HAVE_SYS_STAT_H + * if <sys/stat.h> exists on your platform, and + * #define HAVE_STAT_H + * if <stat.h> does. + */ +#ifndef DONT_HAVE_STAT +#define HAVE_STAT +#endif + +#ifndef DONT_HAVE_FSTAT +#define HAVE_FSTAT +#endif + +#ifdef RISCOS +#include <sys/types.h> +#include "unixstuff.h" +#endif + +#ifdef HAVE_SYS_STAT_H +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#include <sys/types.h> +#endif +#include <sys/stat.h> +#elif defined(HAVE_STAT_H) +#include <stat.h> +#else +#endif + #endif /* Py_PYPORT_H */ diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c --- a/pypy/module/cpyext/src/bufferobject.c +++ b/pypy/module/cpyext/src/bufferobject.c @@ -783,9 +783,9 @@ return size; } -void _Py_init_bufferobject(void) +PyTypeObject *_Py_get_buffer_type(void) { - PyType_Ready(&PyBuffer_Type); + return &PyBuffer_Type; } static PySequenceMethods buffer_as_sequence = { diff --git a/pypy/module/cpyext/src/capsule.c b/pypy/module/cpyext/src/capsule.c --- a/pypy/module/cpyext/src/capsule.c +++ b/pypy/module/cpyext/src/capsule.c @@ -321,8 +321,7 @@ PyCapsule_Type__doc__ /*tp_doc*/ }; -void _Py_init_capsule() +PyTypeObject *_Py_get_capsule_type(void) { - PyType_Ready(&PyCapsule_Type); + return &PyCapsule_Type; } - diff --git a/pypy/module/cpyext/src/cobject.c b/pypy/module/cpyext/src/cobject.c --- a/pypy/module/cpyext/src/cobject.c +++ b/pypy/module/cpyext/src/cobject.c @@ -156,7 +156,7 @@ PyCObject_Type__doc__ /*tp_doc*/ }; -void _Py_init_pycobject() +PyTypeObject *_Py_get_cobject_type(void) { - PyType_Ready(&PyCObject_Type); + return &PyCObject_Type; } 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 @@ -549,11 +549,14 @@ pto.c_tp_flags |= Py_TPFLAGS_READY return pto +def py_type_ready(space, pto): + if pto.c_tp_flags & Py_TPFLAGS_READY: + return + type_realize(space, rffi.cast(PyObject, pto)) + @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1) def PyType_Ready(space, pto): - if pto.c_tp_flags & Py_TPFLAGS_READY: - return 0 - type_realize(space, rffi.cast(PyObject, pto)) + py_type_ready(space, pto) return 0 def type_realize(space, py_obj): diff --git a/pypy/module/gc/interp_gc.py b/pypy/module/gc/interp_gc.py --- a/pypy/module/gc/interp_gc.py +++ b/pypy/module/gc/interp_gc.py @@ -12,8 +12,8 @@ cache = space.fromcache(MethodCache) cache.clear() if space.config.objspace.std.withmapdict: - from pypy.objspace.std.mapdict import IndexCache - cache = space.fromcache(IndexCache) + from pypy.objspace.std.mapdict import MapAttrCache + cache = space.fromcache(MapAttrCache) cache.clear() rgc.collect() return space.wrap(0) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -394,6 +394,9 @@ class W_Float64Box(W_FloatingBox, PrimitiveBox): descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") + def descr_as_integer_ratio(self, space): + return space.call_method(self.item(space), 'as_integer_ratio') + class W_ComplexFloatingBox(W_InexactBox): def descr_get_real(self, space): dtype = self._COMPONENTS_BOX._get_dtype(space) @@ -719,6 +722,7 @@ __module__ = "numpy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), __reduce__ = interp2app(W_Float64Box.descr_reduce), + as_integer_ratio = interp2app(W_Float64Box.descr_as_integer_ratio), ) W_ComplexFloatingBox.typedef = TypeDef("complexfloating", W_InexactBox.typedef, diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -903,8 +903,8 @@ w_res = self.descr_mul(space, other) assert isinstance(w_res, W_NDimArray) return w_res.descr_sum(space, space.wrap(-1), out) - dtype = interp_ufuncs.find_binop_result_dtype(space, - self.get_dtype(), other.get_dtype()) + dtype = interp_ufuncs.find_binop_result_dtype(space, self.get_dtype(), + other.get_dtype()) if self.get_size() < 1 and other.get_size() < 1: # numpy compatability return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) @@ -912,25 +912,27 @@ out_shape, other_critical_dim = _match_dot_shapes(space, self, other) if out: matches = True - if len(out.get_shape()) != len(out_shape): + if dtype != out.get_dtype(): + matches = False + elif not out.implementation.order == "C": + matches = False + elif len(out.get_shape()) != len(out_shape): matches = False else: for i in range(len(out_shape)): if out.get_shape()[i] != out_shape[i]: matches = False break - if dtype != out.get_dtype(): - matches = False - if not out.implementation.order == "C": - matches = False if not matches: raise OperationError(space.w_ValueError, space.wrap( - 'output array is not acceptable (must have the right type, nr dimensions, and be a C-Array)')) + 'output array is not acceptable (must have the right type, ' + 'nr dimensions, and be a C-Array)')) w_res = out + w_res.fill(space, self.get_dtype().coerce(space, None)) else: w_res = W_NDimArray.from_shape(space, out_shape, dtype, w_instance=self) # This is the place to add fpypy and blas - return loop.multidim_dot(space, self, other, w_res, dtype, + return loop.multidim_dot(space, self, other, w_res, dtype, other_critical_dim) def descr_mean(self, space, __args__): diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py --- a/pypy/module/micronumpy/interp_ufuncs.py +++ b/pypy/module/micronumpy/interp_ufuncs.py @@ -254,6 +254,13 @@ return out return res + def descr_outer(self, space, __args__): + return self._outer(space, __args__) + + def _outer(self, space, __args__): + raise OperationError(space.w_ValueError, + space.wrap("outer product only supported for binary functions")) + class W_Ufunc1(W_Ufunc): _immutable_fields_ = ["func", "bool_result"] argcount = 1 @@ -432,6 +439,7 @@ nin = interp_attrproperty("argcount", cls=W_Ufunc), reduce = interp2app(W_Ufunc.descr_reduce), + outer = interp2app(W_Ufunc.descr_outer), ) diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -146,8 +146,7 @@ while not obj_iter.done(): reduce_driver.jit_merge_point(shapelen=shapelen, func=func, done_func=done_func, - calc_dtype=calc_dtype, - ) + calc_dtype=calc_dtype) rval = obj_iter.getitem().convert_to(space, calc_dtype) if done_func is not None and done_func(calc_dtype, rval): return rval @@ -172,8 +171,7 @@ shapelen = len(obj.get_shape()) while not obj_iter.done(): reduce_cum_driver.jit_merge_point(shapelen=shapelen, func=func, - dtype=calc_dtype, - ) + dtype=calc_dtype) rval = obj_iter.getitem().convert_to(space, calc_dtype) cur_value = func(calc_dtype, cur_value, rval) out_iter.setitem(cur_value) @@ -271,8 +269,7 @@ iter.next() shapelen = len(arr.get_shape()) while not iter.done(): - arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, - ) + arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) w_val = iter.getitem() new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) if dtype.itemtype.ne(new_best, cur_best): @@ -311,6 +308,7 @@ if i != right_critical_dim] right_skip = range(len(left_shape) - 1) result_skip = [len(result.get_shape()) - (len(right_shape) > 1)] + assert result.get_dtype() == dtype outi = result.create_dot_iter(broadcast_shape, result_skip) lefti = left.create_dot_iter(broadcast_shape, left_skip) righti = right.create_dot_iter(broadcast_shape, right_skip) @@ -318,10 +316,10 @@ dot_driver.jit_merge_point(dtype=dtype) lval = lefti.getitem().convert_to(space, dtype) rval = righti.getitem().convert_to(space, dtype) - outval = outi.getitem().convert_to(space, dtype) + outval = outi.getitem() v = dtype.itemtype.mul(lval, rval) - value = dtype.itemtype.add(v, outval).convert_to(space, dtype) - outi.setitem(value) + v = dtype.itemtype.add(v, outval) + outi.setitem(v) outi.next() righti.next() lefti.next() @@ -652,8 +650,8 @@ out_iter = out.create_iter(shape) while not arr_iter.done(): round_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) - w_v = dtype.itemtype.round(arr_iter.getitem().convert_to(space, dtype), - decimals) + w_v = arr_iter.getitem().convert_to(space, dtype) + w_v = dtype.itemtype.round(w_v, decimals) out_iter.setitem(w_v) arr_iter.next() out_iter.next() diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py --- a/pypy/module/micronumpy/test/test_arrayops.py +++ b/pypy/module/micronumpy/test/test_arrayops.py @@ -56,6 +56,10 @@ b = arange(12).reshape(4, 3) c = a.dot(b) assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all() + c = a.dot(b.astype(float)) + assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all() + c = a.astype(float).dot(b) + assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all() a = arange(24).reshape(2, 3, 4) raises(ValueError, "a.dot(a)") @@ -91,9 +95,11 @@ out = arange(9).reshape(3, 3) c = dot(a, b, out=out) assert (c == out).all() - out = arange(9,dtype=float).reshape(3, 3) + assert (c == [[42, 48, 54], [114, 136, 158], [186, 224, 262]]).all() + out = arange(9, dtype=float).reshape(3, 3) exc = raises(ValueError, dot, a, b, out) - assert exc.value[0].find('not acceptable') > 0 + assert exc.value[0] == ('output array is not acceptable (must have the ' + 'right type, nr dimensions, and be a C-Array)') def test_choose_basic(self): from numpypy import array diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -181,6 +181,11 @@ s = np.dtype([('a', 'int64'), ('b', 'int64')]).type('a' * 16) assert s.view('S16') == 'a' * 16 + def test_as_integer_ratio(self): + import numpy as np + raises(AttributeError, 'np.float32(1.5).as_integer_ratio()') + assert np.float64(1.5).as_integer_ratio() == (3, 2) + def test_complex_scalar_complex_cast(self): import numpy as np for tp in [np.csingle, np.cdouble, np.clongdouble]: diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -1052,3 +1052,9 @@ np.array([0, -1, -3, -6, -10])).all() assert (np.divide.accumulate(todivide) == np.array([2., 4., 16.])).all() + + def test_outer(self): + import numpy as np + from numpypy import absolute + exc = raises(ValueError, np.absolute.outer, [-1, -2]) + assert exc.value[0] == 'outer product only supported for binary functions' diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py --- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py +++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py @@ -7,9 +7,9 @@ from rpython.rlib.test.test_clibffi import get_libm_name def main(libm_name): try: - from _ffi import CDLL, types + from _rawffi.alt import CDLL, types except ImportError: - sys.stderr.write('SKIP: cannot import _ffi\n') + sys.stderr.write('SKIP: cannot import _rawffi.alt\n') return 0 libm = CDLL(libm_name) @@ -45,9 +45,9 @@ from rpython.rlib.test.test_clibffi import get_libm_name def main(libm_name): try: - from _ffi import CDLL, types + from _rawffi.alt import CDLL, types except ImportError: - sys.stderr.write('SKIP: cannot import _ffi\n') + sys.stderr.write('SKIP: cannot import _rawffi.alt\n') return 0 libm = CDLL(libm_name) @@ -82,12 +82,12 @@ from threading import Thread # if os.name == 'nt': - from _ffi import WinDLL, types + from _rawffi.alt import WinDLL, types libc = WinDLL('Kernel32.dll') sleep = libc.getfunc('Sleep', [types.uint], types.uint) delays = [0]*n + [1000] else: - from _ffi import CDLL, types + from _rawffi.alt import CDLL, types libc = CDLL(libc_name) sleep = libc.getfunc('sleep', [types.uint], types.uint) delays = [0]*n + [1] @@ -144,7 +144,7 @@ def test__ffi_struct(self): def main(): - from _ffi import _StructDescr, Field, types + from _rawffi.alt import _StructDescr, Field, types fields = [ Field('x', types.slong), ] diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -35,7 +35,7 @@ class A(object): pass a = A() - a.x = 2 + a.x = 1 def main(n): i = 0 while i < n: @@ -49,8 +49,7 @@ i9 = int_lt(i5, i6) guard_true(i9, descr=...) guard_not_invalidated(descr=...) - i10 = int_add_ovf(i5, i7) - guard_no_overflow(descr=...) + i10 = int_add(i5, 1) --TICK-- jump(..., descr=...) """) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -155,9 +155,7 @@ to exc_info() will return (None,None,None) until another exception is raised and caught in the current thread or the execution stack returns to a frame where another exception is being handled.""" - operror = space.getexecutioncontext().sys_exc_info() - if operror is not None: - operror.clear(space) + space.getexecutioncontext().clear_sys_exc_info() def settrace(space, w_func): """Set the global debug tracing function. It will be called on each diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -1,20 +1,21 @@ """The builtin bytearray implementation""" +from rpython.rlib.objectmodel import ( + import_from_mixin, newlist_hint, resizelist_hint) +from rpython.rlib.rstring import StringBuilder + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec from pypy.interpreter.signature import Signature from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringmethods import StringMethods from pypy.objspace.std.util import get_positive_index -from rpython.rlib.objectmodel import newlist_hint, resizelist_hint, import_from_mixin -from rpython.rlib.rstring import StringBuilder +NON_HEX_MSG = "non-hexadecimal number found in fromhex() arg at position %d" -def _make_data(s): - return [s[i] for i in range(len(s))] class W_BytearrayObject(W_Root): import_from_mixin(StringMethods) @@ -23,7 +24,7 @@ w_self.data = data def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, ''.join(w_self.data)) def _new(self, value): @@ -127,11 +128,6 @@ @staticmethod def descr_fromhex(space, w_bytearraytype, w_hexstring): - "bytearray.fromhex(string) -> bytearray\n" - "\n" - "Create a bytearray object from a string of hexadecimal numbers.\n" - "Spaces between two numbers are accepted.\n" - "Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef')." hexstring = space.str_w(w_hexstring) hexstring = hexstring.lower() data = [] @@ -143,18 +139,15 @@ i += 1 if i >= length: break - if i+1 == length: - raise OperationError(space.w_ValueError, space.wrap( - "non-hexadecimal number found in fromhex() arg at position %d" % i)) + if i + 1 == length: + raise operationerrfmt(space.w_ValueError, NON_HEX_MSG, i) top = _hex_digit_to_int(hexstring[i]) if top == -1: - raise OperationError(space.w_ValueError, space.wrap( - "non-hexadecimal number found in fromhex() arg at position %d" % i)) + raise operationerrfmt(space.w_ValueError, NON_HEX_MSG, i) bot = _hex_digit_to_int(hexstring[i+1]) if bot == -1: - raise OperationError(space.w_ValueError, space.wrap( - "non-hexadecimal number found in fromhex() arg at position %d" % (i+1,))) + raise operationerrfmt(space.w_ValueError, NON_HEX_MSG, i + 1) data.append(chr(top*16 + bot)) # in CPython bytearray.fromhex is a staticmethod, so @@ -178,23 +171,25 @@ from pypy.objspace.std.unicodeobject import ( _get_encoding_and_errors, encode_object ) - encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) + encoding, errors = _get_encoding_and_errors(space, w_encoding, + w_errors) - # if w_source is an integer this correctly raises a TypeError - # the CPython error message is: "encoding or errors without a string argument" - # ours is: "expected unicode, got int object" + # if w_source is an integer this correctly raises a + # TypeError the CPython error message is: "encoding or + # errors without a string argument" ours is: "expected + # unicode, got int object" w_source = encode_object(space, w_source, encoding, errors) # Is it an int? try: count = space.int_w(w_source) - except OperationError, e: + except OperationError as e: if not e.match(space, space.w_TypeError): raise else: if count < 0: - raise OperationError(space.w_ValueError, - space.wrap("bytearray negative count")) + raise operationerrfmt(space.w_ValueError, + "bytearray negative count") self.data = ['\0'] * count return @@ -224,8 +219,8 @@ elif not '\x20' <= c < '\x7f': n = ord(c) buf.append('\\x') - buf.append("0123456789abcdef"[n>>4]) - buf.append("0123456789abcdef"[n&0xF]) + buf.append("0123456789abcdef"[n >> 4]) + buf.append("0123456789abcdef"[n & 0xF]) else: buf.append(c) @@ -238,51 +233,60 @@ def descr_eq(self, space, w_other): try: - return space.newbool(self._val(space) == self._op_val(space, w_other)) - except OperationError, e: + res = self._val(space) == self._op_val(space, w_other) + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise + return space.newbool(res) def descr_ne(self, space, w_other): try: - return space.newbool(self._val(space) != self._op_val(space, w_other)) - except OperationError, e: + res = self._val(space) != self._op_val(space, w_other) + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise + return space.newbool(res) def descr_lt(self, space, w_other): try: - return space.newbool(self._val(space) < self._op_val(space, w_other)) - except OperationError, e: + res = self._val(space) < self._op_val(space, w_other) + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise + return space.newbool(res) def descr_le(self, space, w_other): try: - return space.newbool(self._val(space) <= self._op_val(space, w_other)) - except OperationError, e: + res = self._val(space) <= self._op_val(space, w_other) + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise + return space.newbool(res) def descr_gt(self, space, w_other): try: - return space.newbool(self._val(space) > self._op_val(space, w_other)) - except OperationError, e: + res = self._val(space) > self._op_val(space, w_other) + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise + return space.newbool(res) def descr_ge(self, space, w_other): try: - return space.newbool(self._val(space) >= self._op_val(space, w_other)) - except OperationError, e: + res = self._val(space) >= self._op_val(space, w_other) + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise + return space.newbool(res) + + def descr_iter(self, space): + return space.newseqiter(self) def descr_buffer(self, space): return BytearrayBuffer(self.data) @@ -297,7 +301,7 @@ def descr_inplace_mul(self, space, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise @@ -312,12 +316,13 @@ _setitem_slice_helper(space, self.data, start, step, slicelength, sequence2, empty_elem='\x00') else: - idx = space.getindex_w(w_index, space.w_IndexError, "bytearray index") + idx = space.getindex_w(w_index, space.w_IndexError, + "bytearray index") try: self.data[idx] = getbytevalue(space, w_other) except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("bytearray index out of range")) + raise operationerrfmt(space.w_IndexError, + "bytearray index out of range") def descr_delitem(self, space, w_idx): if isinstance(w_idx, W_SliceObject): @@ -325,12 +330,13 @@ len(self.data)) _delitem_slice_helper(space, self.data, start, step, slicelength) else: - idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index") + idx = space.getindex_w(w_idx, space.w_IndexError, + "bytearray index") try: del self.data[idx] except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("bytearray deletion index out of range")) + raise operationerrfmt(space.w_IndexError, + "bytearray deletion index out of range") def descr_append(self, space, w_item): self.data.append(getbytevalue(space, w_item)) @@ -357,10 +363,9 @@ result = self.data.pop(index) except IndexError: if not self.data: - raise OperationError(space.w_IndexError, space.wrap( - "pop from empty bytearray")) - raise OperationError(space.w_IndexError, space.wrap( - "pop index out of range")) + raise operationerrfmt(space.w_IndexError, + "pop from empty bytearray") + raise operationerrfmt(space.w_IndexError, "pop index out of range") return space.wrap(ord(result)) def descr_remove(self, space, w_char): @@ -368,27 +373,55 @@ try: self.data.remove(chr(char)) except ValueError: - raise OperationError(space.w_ValueError, space.wrap( - "value not found in bytearray")) + raise operationerrfmt(space.w_ValueError, + "value not found in bytearray") + + _StringMethods_descr_contains = descr_contains + def descr_contains(self, space, w_sub): + if space.isinstance_w(w_sub, space.w_int): + char = space.int_w(w_sub) + return _descr_contains_bytearray(self.data, space, char) + return self._StringMethods_descr_contains(space, w_sub) def descr_reverse(self, space): self.data.reverse() + +# ____________________________________________________________ +# helpers for slow paths, moved out because they contain loops + +def _make_data(s): + return [s[i] for i in range(len(s))] + + +def _descr_contains_bytearray(data, space, char): + if not 0 <= char < 256: + raise operationerrfmt(space.w_ValueError, + "byte must be in range(0, 256)") + for c in data: + if ord(c) == char: + return space.w_True + return space.w_False + +# ____________________________________________________________ + + def getbytevalue(space, w_value): if space.isinstance_w(w_value, space.w_str): string = space.str_w(w_value) if len(string) != 1: - raise OperationError(space.w_ValueError, space.wrap( - "string must be of size 1")) + raise operationerrfmt(space.w_ValueError, + "string must be of size 1") return string[0] value = space.getindex_w(w_value, None) if not 0 <= value < 256: # this includes the OverflowError in case the long is too large - raise OperationError(space.w_ValueError, space.wrap( - "byte must be in range(0, 256)")) + raise operationerrfmt(space.w_ValueError, + "byte must be in range(0, 256)") return chr(value) + def new_bytearray(space, w_bytearraytype, data): w_obj = space.allocate_instance(W_BytearrayObject, w_bytearraytype) W_BytearrayObject.__init__(w_obj, data) @@ -399,7 +432,7 @@ # String-like argument try: string = space.bufferstr_new_w(w_source) - except OperationError, e: + except OperationError as e: if not e.match(space, space.w_TypeError): raise else: @@ -413,7 +446,7 @@ while True: try: w_item = space.next(w_iter) - except OperationError, e: + except OperationError as e: if not e.match(space, space.w_StopIteration): raise break @@ -424,6 +457,7 @@ resizelist_hint(data, extended) return data + def _hex_digit_to_int(d): val = ord(d) if 47 < val < 58: @@ -560,12 +594,12 @@ def decode(): """B.decode(encoding=None, errors='strict') -> unicode - Decode B using the codec registered for encoding. encoding defaults - to the default encoding. errors may be given to set a different error - handling scheme. Default is 'strict' meaning that encoding errors raise - a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' - as well as any other name registered with codecs.register_error that is - able to handle UnicodeDecodeErrors. + Decode B using the codec registered for encoding. encoding defaults to + the default encoding. errors may be given to set a different error + handling scheme. Default is 'strict' meaning that encoding errors + raise a UnicodeDecodeError. Other possible values are 'ignore' and + 'replace' as well as any other name registered with + codecs.register_error that is able to handle UnicodeDecodeErrors. """ def endswith(): @@ -602,7 +636,7 @@ """ def fromhex(): - """bytearray.fromhex(string) -> bytearray (static method) + r"""bytearray.fromhex(string) -> bytearray (static method) Create a bytearray object from a string of hexadecimal numbers. Spaces between two numbers are accepted. @@ -884,6 +918,8 @@ __ge__ = interp2app(W_BytearrayObject.descr_ge, doc=BytearrayDocstrings.__ge__.__doc__), + __iter__ = interp2app(W_BytearrayObject.descr_iter, + doc=BytearrayDocstrings.__iter__.__doc__), __len__ = interp2app(W_BytearrayObject.descr_len, doc=BytearrayDocstrings.__len__.__doc__), __contains__ = interp2app(W_BytearrayObject.descr_contains, @@ -1024,9 +1060,10 @@ _space_chars = ''.join([chr(c) for c in [9, 10, 11, 12, 13, 32]]) -#XXX share the code again with the stuff in listobject.py + +# XXX share the code again with the stuff in listobject.py def _delitem_slice_helper(space, items, start, step, slicelength): - if slicelength==0: + if slicelength == 0: return if step < 0: @@ -1056,6 +1093,7 @@ assert start >= 0 # annotator hint del items[start:] + def _setitem_slice_helper(space, items, start, step, slicelength, sequence2, empty_elem): assert slicelength >= 0 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 @@ -1,19 +1,23 @@ """The builtin str implementation""" +from rpython.rlib.jit import we_are_jitted +from rpython.rlib.objectmodel import ( + compute_hash, compute_unique_id, import_from_mixin) +from rpython.rlib.rstring import StringBuilder, replace + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.buffer import StringBuffer from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault, interpindirect2app +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) from pypy.objspace.std import newformat from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.formatting import mod_format from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringmethods import StringMethods -from pypy.objspace.std.unicodeobject import (unicode_from_string, - decode_object, unicode_from_encoded_object, _get_encoding_and_errors) -from rpython.rlib.jit import we_are_jitted -from rpython.rlib.objectmodel import compute_hash, compute_unique_id, import_from_mixin -from rpython.rlib.rstring import StringBuilder, replace +from pypy.objspace.std.unicodeobject import ( + _get_encoding_and_errors, decode_object, unicode_from_encoded_object, + unicode_from_string) class W_AbstractBytesObject(W_Root): @@ -184,8 +188,8 @@ def descr_format(self, space, __args__): """S.format(*args, **kwargs) -> string - Return a formatted version of S, using substitutions from args and kwargs. - The substitutions are identified by braces ('{' and '}'). + Return a formatted version of S, using substitutions from args and + kwargs. The substitutions are identified by braces ('{' and '}'). """ def descr_index(self, space, w_sub, w_start=None, w_end=None): @@ -319,8 +323,8 @@ """S.rpartition(sep) -> (head, sep, tail) Search for the separator sep in S, starting at the end of S, and return - the part before it, the separator itself, and the part after it. If the - separator is not found, return two empty strings and S. + the part before it, the separator itself, and the part after it. If + the separator is not found, return two empty strings and S. """ @unwrap_spec(maxsplit=int) @@ -432,7 +436,7 @@ self._value = str def __repr__(self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%r)" % (self.__class__.__name__, self._value) def unwrap(self, space): @@ -521,7 +525,7 @@ return space.newlist_bytes(lst) @staticmethod - @unwrap_spec(w_object = WrappedDefault("")) + @unwrap_spec(w_object=WrappedDefault("")) def descr_new(space, w_stringtype, w_object): # NB. the default value of w_object is really a *wrapped* empty string: # there is gateway magic at work @@ -624,7 +628,8 @@ _StringMethods_descr_add = descr_add def descr_add(self, space, w_other): if space.isinstance_w(w_other, space.w_unicode): - self_as_unicode = unicode_from_encoded_object(space, self, None, None) + self_as_unicode = unicode_from_encoded_object(space, self, None, + None) return space.add(self_as_unicode, w_other) elif space.isinstance_w(w_other, space.w_bytearray): # XXX: eliminate double-copy @@ -635,7 +640,7 @@ from pypy.objspace.std.strbufobject import W_StringBufferObject try: other = self._op_val(space, w_other) - except OperationError, e: + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise @@ -648,24 +653,32 @@ _StringMethods__startswith = _startswith def _startswith(self, space, value, w_prefix, start, end): if space.isinstance_w(w_prefix, space.w_unicode): - self_as_unicode = unicode_from_encoded_object(space, self, None, None) - return self_as_unicode._startswith(space, self_as_unicode._value, w_prefix, start, end) - return self._StringMethods__startswith(space, value, w_prefix, start, end) + self_as_unicode = unicode_from_encoded_object(space, self, None, + None) + return self_as_unicode._startswith(space, self_as_unicode._value, + w_prefix, start, end) + return self._StringMethods__startswith(space, value, w_prefix, start, + end) _StringMethods__endswith = _endswith def _endswith(self, space, value, w_suffix, start, end): if space.isinstance_w(w_suffix, space.w_unicode): - self_as_unicode = unicode_from_encoded_object(space, self, None, None) - return self_as_unicode._endswith(space, self_as_unicode._value, w_suffix, start, end) - return self._StringMethods__endswith(space, value, w_suffix, start, end) + self_as_unicode = unicode_from_encoded_object(space, self, None, + None) + return self_as_unicode._endswith(space, self_as_unicode._value, + w_suffix, start, end) + return self._StringMethods__endswith(space, value, w_suffix, start, + end) _StringMethods_descr_contains = descr_contains def descr_contains(self, space, w_sub): if space.isinstance_w(w_sub, space.w_unicode): from pypy.objspace.std.unicodeobject import W_UnicodeObject assert isinstance(w_sub, W_UnicodeObject) - self_as_unicode = unicode_from_encoded_object(space, self, None, None) - return space.newbool(self_as_unicode._value.find(w_sub._value) >= 0) + self_as_unicode = unicode_from_encoded_object(space, self, None, + None) + return space.newbool( + self_as_unicode._value.find(w_sub._value) >= 0) return self._StringMethods_descr_contains(space, w_sub) _StringMethods_descr_replace = descr_replace @@ -685,16 +698,19 @@ try: res = replace(input, sub, by, count) except OverflowError: - raise OperationError(space.w_OverflowError, - space.wrap("replace string is too long")) + raise operationerrfmt(space.w_OverflowError, + "replace string is too long") return self_as_uni._new(res) return self._StringMethods_descr_replace(space, w_old, w_new, count) - def descr_lower(self, space): - return W_BytesObject(self._value.lower()) - - def descr_upper(self, space): - return W_BytesObject(self._value.upper()) + _StringMethods_descr_join = descr_join + def descr_join(self, space, w_list): + l = space.listview_bytes(w_list) + if l is not None: + if len(l) == 1: + return space.wrap(l[0]) + return space.wrap(self._val(space).join(l)) + return self._StringMethods_descr_join(space, w_list) def _join_return_one(self, space, w_obj): return (space.is_w(space.type(w_obj), space.w_str) or @@ -714,6 +730,12 @@ w_u = space.call_function(space.w_unicode, self) return space.call_method(w_u, "join", w_list) + def descr_lower(self, space): + return W_BytesObject(self._value.lower()) + + def descr_upper(self, space): + return W_BytesObject(self._value.upper()) + def descr_formatter_parser(self, space): from pypy.objspace.std.newformat import str_template_formatter tformat = str_template_formatter(space, space.str_w(self)) @@ -751,6 +773,7 @@ return W_BytesObject.EMPTY return W_BytesObject(s) + def wrapchar(space, c): if space.config.objspace.std.withprebuiltchar and not we_are_jitted(): return W_BytesObject.PREBUILT[ord(c)] @@ -830,7 +853,8 @@ __format__ = interpindirect2app(W_BytesObject.descr__format__), __mod__ = interpindirect2app(W_BytesObject.descr_mod), __buffer__ = interpindirect2app(W_AbstractBytesObject.descr_buffer), - __getnewargs__ = interpindirect2app(W_AbstractBytesObject.descr_getnewargs), + __getnewargs__ = interpindirect2app( + W_AbstractBytesObject.descr_getnewargs), _formatter_parser = interp2app(W_BytesObject.descr_formatter_parser), _formatter_field_name_split = interp2app(W_BytesObject.descr_formatter_field_name_split), @@ -865,8 +889,8 @@ buf.append_slice(s, startslice, i) startslice = i + 1 buf.append('\\x') - buf.append("0123456789abcdef"[n>>4]) - buf.append("0123456789abcdef"[n&0xF]) + buf.append("0123456789abcdef"[n >> 4]) + buf.append("0123456789abcdef"[n & 0xF]) if use_bs_char: if i != startslice: diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -162,9 +162,9 @@ return self @staticmethod - def newlist_bytes(space, list_s): + def newlist_bytes(space, list_b): strategy = space.fromcache(BytesListStrategy) - storage = strategy.erase(list_s) + storage = strategy.erase(list_b) return W_ListObject.from_storage_and_strategy(space, storage, strategy) @staticmethod diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -1,15 +1,16 @@ import weakref -from rpython.rlib import jit, objectmodel, debug + +from rpython.rlib import jit, objectmodel, debug, rerased from rpython.rlib.rarithmetic import intmask, r_uint -from rpython.rlib import rerased from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy -from pypy.objspace.std.dictmultiobject import BaseKeyIterator, BaseValueIterator, BaseItemIterator -from pypy.objspace.std.dictmultiobject import _never_equal_to_string -from pypy.objspace.std.objectobject import W_ObjectObject +from pypy.objspace.std.dictmultiobject import ( + W_DictMultiObject, DictStrategy, ObjectDictStrategy, BaseKeyIterator, + BaseValueIterator, BaseItemIterator, _never_equal_to_string +) from pypy.objspace.std.typeobject import TypeCell + # ____________________________________________________________ # attribute shapes @@ -19,7 +20,7 @@ # we want to propagate knowledge that the result cannot be negative class AbstractAttribute(object): - _immutable_fields_ = ['terminator'] + _immutable_fields_ = ['terminator', 'ever_mutated?'] cache_attrs = None _size_estimate = 0 @@ -27,46 +28,60 @@ self.space = space assert isinstance(terminator, Terminator) self.terminator = terminator + self.ever_mutated = False def read(self, obj, selector): - index = self.index(selector) - if index < 0: + attr = self.find_map_attr(selector) + if attr is None: return self.terminator._read_terminator(obj, selector) - return obj._mapdict_read_storage(index) + if ( + jit.isconstant(attr.storageindex) and + jit.isconstant(obj) and + not attr.ever_mutated + ): + return self._pure_mapdict_read_storage(obj, attr.storageindex) + else: + return obj._mapdict_read_storage(attr.storageindex) + + @jit.elidable + def _pure_mapdict_read_storage(self, obj, storageindex): + return obj._mapdict_read_storage(storageindex) def write(self, obj, selector, w_value): - index = self.index(selector) - if index < 0: + attr = self.find_map_attr(selector) + if attr is None: return self.terminator._write_terminator(obj, selector, w_value) - obj._mapdict_write_storage(index, w_value) + if not attr.ever_mutated: + attr.ever_mutated = True + obj._mapdict_write_storage(attr.storageindex, w_value) return True def delete(self, obj, selector): return None - def index(self, selector): + def find_map_attr(self, selector): if jit.we_are_jitted(): # hack for the jit: - # the _index method is pure too, but its argument is never + # the _find_map_attr method is pure too, but its argument is never # constant, because it is always a new tuple - return self._index_jit_pure(selector[0], selector[1]) + return self._find_map_attr_jit_pure(selector[0], selector[1]) else: - return self._index_indirection(selector) + return self._find_map_attr_indirection(selector) @jit.elidable - def _index_jit_pure(self, name, index): - return self._index_indirection((name, index)) + def _find_map_attr_jit_pure(self, name, index): + return self._find_map_attr_indirection((name, index)) @jit.dont_look_inside - def _index_indirection(self, selector): + def _find_map_attr_indirection(self, selector): if (self.space.config.objspace.std.withmethodcache): - return self._index_cache(selector) - return self._index(selector) + return self._find_map_attr_cache(selector) + return self._find_map_attr(selector) @jit.dont_look_inside - def _index_cache(self, selector): + def _find_map_attr_cache(self, selector): space = self.space - cache = space.fromcache(IndexCache) + cache = space.fromcache(MapAttrCache) SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp SHIFT1 = SHIFT2 - 5 attrs_as_int = objectmodel.current_object_addr_as_int(self) @@ -74,32 +89,32 @@ # _pure_lookup_where_with_method_cache() hash_selector = objectmodel.compute_hash(selector) product = intmask(attrs_as_int * hash_selector) - index_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2 + attr_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2 # ^^^Note2: same comment too - cached_attr = cache.attrs[index_hash] + cached_attr = cache.attrs[attr_hash] if cached_attr is self: - cached_selector = cache.selectors[index_hash] + cached_selector = cache.selectors[attr_hash] if cached_selector == selector: - index = cache.indices[index_hash] + attr = cache.cached_attrs[attr_hash] if space.config.objspace.std.withmethodcachecounter: name = selector[0] cache.hits[name] = cache.hits.get(name, 0) + 1 - return index - index = self._index(selector) - cache.attrs[index_hash] = self - cache.selectors[index_hash] = selector - cache.indices[index_hash] = index + return attr + attr = self._find_map_attr(selector) + cache.attrs[attr_hash] = self + cache.selectors[attr_hash] = selector + cache.cached_attrs[attr_hash] = attr if space.config.objspace.std.withmethodcachecounter: name = selector[0] cache.misses[name] = cache.misses.get(name, 0) + 1 - return index + return attr - def _index(self, selector): + def _find_map_attr(self, selector): while isinstance(self, PlainAttribute): if selector == self.selector: - return self.position + return self self = self.back - return -1 + return None def copy(self, obj): raise NotImplementedError("abstract base class") @@ -155,7 +170,7 @@ # the order is important here: first change the map, then the storage, # for the benefit of the special subclasses obj._set_mapdict_map(attr) - obj._mapdict_write_storage(attr.position, w_value) + obj._mapdict_write_storage(attr.storageindex, w_value) def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") @@ -261,11 +276,11 @@ return Terminator.set_terminator(self, obj, terminator) class PlainAttribute(AbstractAttribute): - _immutable_fields_ = ['selector', 'position', 'back'] + _immutable_fields_ = ['selector', 'storageindex', 'back'] def __init__(self, selector, back): AbstractAttribute.__init__(self, back.space, back.terminator) self.selector = selector - self.position = back.length() + self.storageindex = back.length() self.back = back self._size_estimate = self.length() * NUM_DIGITS_POW2 @@ -288,7 +303,7 @@ return new_obj def length(self): - return self.position + 1 + return self.storageindex + 1 def set_terminator(self, obj, terminator): new_obj = self.back.set_terminator(obj, terminator) @@ -304,7 +319,7 @@ new_obj = self.back.materialize_r_dict(space, obj, dict_w) if self.selector[1] == DICT: w_attr = space.wrap(self.selector[0]) - dict_w[w_attr] = obj._mapdict_read_storage(self.position) + dict_w[w_attr] = obj._mapdict_read_storage(self.storageindex) else: self._copy_attr(obj, new_obj) return new_obj @@ -316,21 +331,21 @@ return new_obj def __repr__(self): - return "<PlainAttribute %s %s %r>" % (self.selector, self.position, self.back) + return "<PlainAttribute %s %s %r>" % (self.selector, self.storageindex, self.back) def _become(w_obj, new_obj): # this is like the _become method, really, but we cannot use that due to # RPython reasons w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map) -class IndexCache(object): +class MapAttrCache(object): def __init__(self, space): assert space.config.objspace.std.withmethodcache SIZE = 1 << space.config.objspace.std.methodcachesizeexp self.attrs = [None] * SIZE self._empty_selector = (None, INVALID) self.selectors = [self._empty_selector] * SIZE - self.indices = [0] * SIZE + self.cached_attrs = [None] * SIZE if space.config.objspace.std.withmethodcachecounter: self.hits = {} self.misses = {} @@ -340,6 +355,8 @@ self.attrs[i] = None for i in range(len(self.selectors)): self.selectors[i] = self._empty_selector + for i in range(len(self.cached_attrs)): + self.cached_attrs[i] = None # ____________________________________________________________ # object implementation @@ -416,16 +433,16 @@ self.typedef is W_InstanceObject.typedef) self._init_empty(w_subtype.terminator) - def getslotvalue(self, index): - key = ("slot", SLOTS_STARTING_FROM + index) + def getslotvalue(self, slotindex): + key = ("slot", SLOTS_STARTING_FROM + slotindex) return self._get_mapdict_map().read(self, key) - def setslotvalue(self, index, w_value): - key = ("slot", SLOTS_STARTING_FROM + index) + def setslotvalue(self, slotindex, w_value): + key = ("slot", SLOTS_STARTING_FROM + slotindex) self._get_mapdict_map().write(self, key, w_value) - def delslotvalue(self, index): - key = ("slot", SLOTS_STARTING_FROM + index) + def delslotvalue(self, slotindex): + key = ("slot", SLOTS_STARTING_FROM + slotindex) new_obj = self._get_mapdict_map().delete(self, key) if new_obj is None: return False @@ -460,11 +477,13 @@ self.map = map self.storage = make_sure_not_resized([None] * map.size_estimate()) - def _mapdict_read_storage(self, index): - assert index >= 0 - return self.storage[index] - def _mapdict_write_storage(self, index, value): - self.storage[index] = value + def _mapdict_read_storage(self, storageindex): + assert storageindex >= 0 + return self.storage[storageindex] + + def _mapdict_write_storage(self, storageindex, value): + self.storage[storageindex] = value + def _mapdict_storage_length(self): return len(self.storage) def _set_mapdict_storage_and_map(self, storage, map): @@ -519,7 +538,6 @@ rangenmin1 = unroll.unrolling_iterable(range(nmin1)) class subcls(BaseMapdictObject, supercls): def _init_empty(self, map): - from rpython.rlib.debug import make_sure_not_resized for i in rangen: setattr(self, "_value%s" % i, erase_item(None)) self.map = map @@ -531,26 +549,26 @@ erased = getattr(self, "_value%s" % nmin1) return unerase_list(erased) - def _mapdict_read_storage(self, index): - assert index >= 0 - if index < nmin1: + def _mapdict_read_storage(self, storageindex): + assert storageindex >= 0 + if storageindex < nmin1: for i in rangenmin1: - if index == i: + if storageindex == i: erased = getattr(self, "_value%s" % i) return unerase_item(erased) if self._has_storage_list(): - return self._mapdict_get_storage_list()[index - nmin1] + return self._mapdict_get_storage_list()[storageindex - nmin1] erased = getattr(self, "_value%s" % nmin1) return unerase_item(erased) - def _mapdict_write_storage(self, index, value): + def _mapdict_write_storage(self, storageindex, value): erased = erase_item(value) for i in rangenmin1: - if index == i: + if storageindex == i: setattr(self, "_value%s" % i, erased) return if self._has_storage_list(): - self._mapdict_get_storage_list()[index - nmin1] = value + self._mapdict_get_storage_list()[storageindex - nmin1] = value return setattr(self, "_value%s" % nmin1, erased) @@ -785,7 +803,7 @@ class CacheEntry(object): version_tag = None - index = 0 + storageindex = 0 w_method = None # for callmethod success_counter = 0 failure_counter = 0 @@ -818,14 +836,14 @@ pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries @jit.dont_look_inside -def _fill_cache(pycode, nameindex, map, version_tag, index, w_method=None): +def _fill_cache(pycode, nameindex, map, version_tag, storageindex, w_method=None): entry = pycode._mapdict_caches[nameindex] if entry is INVALID_CACHE_ENTRY: entry = CacheEntry() pycode._mapdict_caches[nameindex] = entry entry.map_wref = weakref.ref(map) entry.version_tag = version_tag - entry.index = index + entry.storageindex = storageindex entry.w_method = w_method if pycode.space.config.objspace.std.withmethodcachecounter: entry.failure_counter += 1 @@ -837,7 +855,7 @@ map = w_obj._get_mapdict_map() if entry.is_valid_for_map(map) and entry.w_method is None: # everything matches, it's incredibly fast - return w_obj._mapdict_read_storage(entry.index) + return w_obj._mapdict_read_storage(entry.storageindex) return LOAD_ATTR_slowpath(pycode, w_obj, nameindex, map) LOAD_ATTR_caching._always_inline_ = True @@ -871,19 +889,19 @@ selector = ("slot", SLOTS_STARTING_FROM + w_descr.index) else: # There is a non-data descriptor in the class. If there is - # also a dict attribute, use the latter, caching its position. + # also a dict attribute, use the latter, caching its storageindex. # If not, we loose. We could do better in this case too, # but we don't care too much; the common case of a method # invocation is handled by LOOKUP_METHOD_xxx below. selector = (name, DICT) # if selector[1] != INVALID: - index = map.index(selector) - if index >= 0: + attr = map.find_map_attr(selector) + if attr is not None: # Note that if map.terminator is a DevolvedDictTerminator, - # map.index() will always return -1 if selector[1]==DICT. - _fill_cache(pycode, nameindex, map, version_tag, index) - return w_obj._mapdict_read_storage(index) + # map.find_map_attr will always return None if selector[1]==DICT. + _fill_cache(pycode, nameindex, map, version_tag, attr.storageindex) + return w_obj._mapdict_read_storage(attr.storageindex) if space.config.objspace.std.withmethodcachecounter: INVALID_CACHE_ENTRY.failure_counter += 1 return space.getattr(w_obj, w_name) 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 @@ -1,18 +1,22 @@ -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import unwrap_spec, WrappedDefault -from pypy.objspace.std import slicetype -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +"""Functionality shared between bytes/bytearray/unicode""" + from rpython.rlib import jit from rpython.rlib.objectmodel import specialize from rpython.rlib.rarithmetic import ovfcheck -from rpython.rlib.rstring import split, rsplit, replace, startswith, endswith +from rpython.rlib.rstring import endswith, replace, rsplit, split, startswith + +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import WrappedDefault, unwrap_spec +from pypy.objspace.std import slicetype +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice class StringMethods(object): def _sliced(self, space, s, start, stop, orig_obj): assert start >= 0 assert stop >= 0 - #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), space.w_str): + #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), + # space.w_str): # return orig_obj return self._new(s[start:stop]) @@ -21,7 +25,7 @@ value = self._val(space) lenself = len(value) start, end = slicetype.unwrap_start_stop( - space, lenself, w_start, w_end, upper_bound=upper_bound) + space, lenself, w_start, w_end, upper_bound=upper_bound) return (value, start, end) def descr_len(self, space): @@ -31,17 +35,14 @@ # pass def descr_contains(self, space, w_sub): - from pypy.objspace.std.bytearrayobject import W_BytearrayObject - if (isinstance(self, W_BytearrayObject) and - space.isinstance_w(w_sub, space.w_int)): - char = space.int_w(w_sub) - return _descr_contains_bytearray(self.data, space, char) - return space.newbool(self._val(space).find(self._op_val(space, w_sub)) >= 0) + value = self._val(space) + other = self._op_val(space, w_sub) + return space.newbool(value.find(other) >= 0) def descr_add(self, space, w_other): try: other = self._op_val(space, w_other) - except OperationError, e: + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise @@ -50,7 +51,7 @@ def descr_mul(self, space, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: + except OperationError as e: if e.match(space, space.w_TypeError): return space.w_NotImplemented raise @@ -82,12 +83,11 @@ if index < 0: index += selflen if index < 0 or index >= selflen: - raise OperationError(space.w_IndexError, - space.wrap("string index out of range")) + raise operationerrfmt(space.w_IndexError, + "string index out of range") from pypy.objspace.std.bytearrayobject import W_BytearrayObject if isinstance(self, W_BytearrayObject): return space.wrap(ord(selfvalue[index])) - #return wrapchar(space, selfvalue[index]) return self._new(selfvalue[index]) def descr_getslice(self, space, w_start, w_stop): @@ -115,35 +115,39 @@ value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: - raise OperationError(space.w_TypeError, - space.wrap("center() argument 2 must be a single character")) + raise operationerrfmt(space.w_TypeError, + "center() argument 2 must be a single " + "character") d = width - len(value) - if d>0: + if d > 0: offset = d//2 + (d & width & 1) fillchar = fillchar[0] # annotator hint: it's a single character - u_centered = offset * fillchar + value + (d - offset) * fillchar + centered = offset * fillchar + value + (d - offset) * fillchar else: - u_centered = value + centered = value - return self._new(u_centered) + return self._new(centered) def descr_count(self, space, w_sub, w_start=None, w_end=None): value, start, end = self._convert_idx_params(space, w_start, w_end) - return space.newint(value.count(self._op_val(space, w_sub), start, end)) + return space.newint(value.count(self._op_val(space, w_sub), start, + end)) def descr_decode(self, space, w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \ - unicode_from_string, decode_object - encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) + from pypy.objspace.std.unicodeobject import ( + _get_encoding_and_errors, decode_object, unicode_from_string) + encoding, errors = _get_encoding_and_errors(space, w_encoding, + w_errors) if encoding is None and errors is None: return unicode_from_string(space, self) return decode_object(space, self, encoding, errors) def descr_encode(self, space, w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \ - encode_object - encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) + from pypy.objspace.std.unicodeobject import ( + _get_encoding_and_errors, encode_object) + encoding, errors = _get_encoding_and_errors(space, w_encoding, + w_errors) return encode_object(space, self, encoding, errors) @unwrap_spec(tabsize=int) @@ -156,18 +160,19 @@ try: ovfcheck(len(splitted) * tabsize) except OverflowError: - raise OperationError(space.w_OverflowError, - space.wrap("new string is too long")) + raise operationerrfmt(space.w_OverflowError, + "new string is too long") expanded = oldtoken = splitted.pop(0) for token in splitted: - expanded += self._chr(' ') * self._tabindent(oldtoken, tabsize) + token + expanded += self._chr(' ') * self._tabindent(oldtoken, + tabsize) + token oldtoken = token return self._new(expanded) def _tabindent(self, token, tabsize): - "calculates distance behind the token to the next tabstop" + """calculates distance behind the token to the next tabstop""" distance = tabsize if token: @@ -203,8 +208,8 @@ (value, start, end) = self._convert_idx_params(space, w_start, w_end) res = value.find(self._op_val(space, w_sub), start, end) if res < 0: - raise OperationError(space.w_ValueError, - space.wrap("substring not found in string.index")) + raise operationerrfmt(space.w_ValueError, + "substring not found in string.index") return space.wrap(res) @@ -212,8 +217,8 @@ (value, start, end) = self._convert_idx_params(space, w_start, w_end) res = value.rfind(self._op_val(space, w_sub), start, end) if res < 0: - raise OperationError(space.w_ValueError, - space.wrap("substring not found in string.rindex")) + raise operationerrfmt(space.w_ValueError, + "substring not found in string.rindex") return space.wrap(res) @@ -307,22 +312,6 @@ return space.newbool(cased) def descr_join(self, space, w_list): - from pypy.objspace.std.bytesobject import W_BytesObject - from pypy.objspace.std.unicodeobject import W_UnicodeObject - - if isinstance(self, W_BytesObject): - l = space.listview_bytes(w_list) - if l is not None: - if len(l) == 1: - return space.wrap(l[0]) - return space.wrap(self._val(space).join(l)) - elif isinstance(self, W_UnicodeObject): - l = space.listview_unicode(w_list) - if l is not None: - if len(l) == 1: - return space.wrap(l[0]) - return space.wrap(self._val(space).join(l)) - list_w = space.listview(w_list) size = len(list_w) @@ -349,8 +338,7 @@ if check_item == 1: raise operationerrfmt( space.w_TypeError, - "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space)) + "sequence item %d: expected string, %T found", i, w_s) elif check_item == 2: return self._join_autoconvert(space, list_w) prealloc_size += len(self._op_val(space, w_s)) @@ -370,9 +358,9 @@ value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: - raise OperationError(space.w_TypeError, - space.wrap("ljust() argument 2 must be a single character")) - + raise operationerrfmt(space.w_TypeError, + "ljust() argument 2 must be a single " + "character") d = width - len(value) if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character @@ -385,9 +373,9 @@ value = self._val(space) fillchar = self._op_val(space, w_fillchar) if len(fillchar) != 1: - raise OperationError(space.w_TypeError, - space.wrap("rjust() argument 2 must be a single character")) - + raise operationerrfmt(space.w_TypeError, + "rjust() argument 2 must be a single " + "character") d = width - len(value) if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character @@ -406,8 +394,7 @@ value = self._val(space) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit