Author: Manuel Jacob <m...@manueljacob.de> Branch: py3k Changeset: r84538:df5facd61ba8 Date: 2016-05-20 18:54 +0200 http://bitbucket.org/pypy/pypy/changeset/df5facd61ba8/
Log: hg merge default (+ fixes) Some tests still fail. E.g. test_verbose_flag_* in pypy/module/imp/test/test_import.py and test_sre in pypy/module/cpyext/test/test_typeobject.py. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -22,3 +22,4 @@ bbd45126bc691f669c4ebdfbd74456cd274c6b92 release-5.0.1 3260adbeba4a8b6659d1cc0d0b41f266769b74da release-5.1 b0a649e90b6642251fb4a765fe5b27a97b1319a9 release-5.1.1 +80ef432a32d9baa4b3c5a54c215e8ebe499f6374 release-5.1.2 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 @@ -93,3 +93,15 @@ .. branch: ufunc-outer Implement ufunc.outer on numpypy + +.. branch: verbose-imports + +Support ``pypy -v``: verbose imports. It does not log as much as +cpython, but it should be enough to help when debugging package layout +problems. + +.. branch: cpyext-macros-cast + +Fix some warnings when compiling CPython C extension modules + +.. branch: syntax_fix diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -526,6 +526,7 @@ unbuffered, ignore_environment, quiet, + verbose, **ignored): # with PyPy in top of CPython we can only have around 100 # but we need more in the translated PyPy for the compiler package @@ -658,6 +659,8 @@ inspect = True else: # If not interactive, just read and execute stdin normally. + if verbose: + print_banner(not no_site) @hidden_applevel def run_it(): co_stdin = compile(sys.stdin.read(), '<stdin>', 'exec', @@ -741,10 +744,10 @@ return status def print_banner(copyright): - print('Python %s on %s' % (sys.version, sys.platform)) + print('Python %s on %s' % (sys.version, sys.platform), file=sys.stderr) if copyright: print('Type "help", "copyright", "credits" or ' - '"license" for more information.') + '"license" for more information.', file=sys.stderr) STDLIB_WARNING = """\ debug: WARNING: Library path not found, using compiled-in sys.path. 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 @@ -51,6 +51,11 @@ space.newint(cache.misses.get(name, 0))]) def builtinify(space, w_func): + """To implement at app-level modules that are, in CPython, + implemented in C: this decorator protects a function from being ever + bound like a method. Useful because some tests do things like put + a "built-in" function on a class and access it via the instance. + """ from pypy.interpreter.function import Function, BuiltinFunction func = space.interp_w(Function, w_func) bltn = BuiltinFunction(func) 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 @@ -413,7 +413,16 @@ arg = rffi.cast(ARG, as_pyobj(space, input_arg)) else: arg = rffi.cast(ARG, input_arg) - elif is_PyObject(ARG) and is_wrapped: + elif ARG == rffi.VOIDP and not is_wrapped: + # unlike is_PyObject case above, we allow any kind of + # argument -- just, if it's an object, we assume the + # caller meant for it to become a PyObject*. + if input_arg is None or isinstance(input_arg, W_Root): + keepalives += (input_arg,) + arg = rffi.cast(ARG, as_pyobj(space, input_arg)) + else: + arg = rffi.cast(ARG, input_arg) + elif (is_PyObject(ARG) or ARG == rffi.VOIDP) and is_wrapped: # build a W_Root, possibly from a 'PyObject *' if is_pyobj(input_arg): arg = from_ref(space, input_arg) @@ -725,6 +734,7 @@ class WrapperGen(object): wrapper_second_level = None + A = lltype.Array(lltype.Char) def __init__(self, space, signature): self.space = space @@ -737,9 +747,13 @@ wrapper_second_level = self.wrapper_second_level name = callable.__name__ + pname = lltype.malloc(self.A, len(name), flavor='raw', immortal=True) + for i in range(len(name)): + pname[i] = name[i] + def wrapper(*args): # no GC here, not even any GC object - return wrapper_second_level(callable, name, *args) + return wrapper_second_level(callable, pname, *args) wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -747,22 +761,31 @@ @dont_inline +def _unpack_name(pname): + return ''.join([pname[i] for i in range(len(pname))]) + +@dont_inline def deadlock_error(funcname): + funcname = _unpack_name(funcname) fatalerror_notb("GIL deadlock detected when a CPython C extension " "module calls '%s'" % (funcname,)) @dont_inline def no_gil_error(funcname): + funcname = _unpack_name(funcname) fatalerror_notb("GIL not held when a CPython C extension " "module calls '%s'" % (funcname,)) @dont_inline def not_supposed_to_fail(funcname): - raise SystemError("The function '%s' was not supposed to fail" - % (funcname,)) + funcname = _unpack_name(funcname) + print "Error in cpyext, CPython compatibility layer:" + print "The function", funcname, "was not supposed to fail" + raise SystemError @dont_inline def unexpected_exception(funcname, e, tb): + funcname = _unpack_name(funcname) print 'Fatal error in cpyext, CPython compatibility layer, calling',funcname print 'Either report a bug or consider not using this particular extension' if not we_are_translated(): @@ -801,9 +824,8 @@ def invalid(err): "NOT_RPYTHON: translation-time crash if this ends up being called" raise ValueError(err) - invalid.__name__ = 'invalid_%s' % name - def wrapper_second_level(callable, name, *args): + def wrapper_second_level(callable, pname, *args): from pypy.module.cpyext.pyobject import make_ref, from_ref, is_pyobj from pypy.module.cpyext.pyobject import as_pyobj # we hope that malloc removal removes the newtuple() that is @@ -814,7 +836,7 @@ _gil_auto = (gil_auto_workaround and cpyext_glob_tid_ptr[0] != tid) if gil_acquire or _gil_auto: if cpyext_glob_tid_ptr[0] == tid: - deadlock_error(name) + deadlock_error(pname) rgil.acquire() assert cpyext_glob_tid_ptr[0] == 0 elif pygilstate_ensure: @@ -827,7 +849,7 @@ args += (pystate.PyGILState_UNLOCKED,) else: if cpyext_glob_tid_ptr[0] != tid: - no_gil_error(name) + no_gil_error(pname) cpyext_glob_tid_ptr[0] = 0 rffi.stackcounter.stacks_counter += 1 @@ -844,6 +866,10 @@ if is_PyObject(typ) and is_wrapped: assert is_pyobj(arg) arg_conv = from_ref(space, rffi.cast(PyObject, arg)) + elif typ == rffi.VOIDP and is_wrapped: + # Many macros accept a void* so that one can pass a + # PyObject* or a PySomeSubtype*. + arg_conv = from_ref(space, rffi.cast(PyObject, arg)) else: arg_conv = arg boxed_args += (arg_conv, ) @@ -873,7 +899,7 @@ if failed: if error_value is CANNOT_FAIL: - raise not_supposed_to_fail(name) + raise not_supposed_to_fail(pname) retval = error_value elif is_PyObject(restype): @@ -893,7 +919,7 @@ retval = rffi.cast(restype, result) except Exception as e: - unexpected_exception(name, e, tb) + unexpected_exception(pname, e, tb) return fatal_value assert lltype.typeOf(retval) == restype diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py --- a/pypy/module/cpyext/cdatetime.py +++ b/pypy/module/cpyext/cdatetime.py @@ -178,67 +178,67 @@ # Accessors -@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_GET_YEAR(space, w_obj): """Return the year, as a positive int. """ return space.int_w(space.getattr(w_obj, space.wrap("year"))) -@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_GET_MONTH(space, w_obj): """Return the month, as an int from 1 through 12. """ return space.int_w(space.getattr(w_obj, space.wrap("month"))) -@cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_GET_DAY(space, w_obj): """Return the day, as an int from 1 through 31. """ return space.int_w(space.getattr(w_obj, space.wrap("day"))) -@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DATE_GET_HOUR(space, w_obj): """Return the hour, as an int from 0 through 23. """ return space.int_w(space.getattr(w_obj, space.wrap("hour"))) -@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DATE_GET_MINUTE(space, w_obj): """Return the minute, as an int from 0 through 59. """ return space.int_w(space.getattr(w_obj, space.wrap("minute"))) -@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DATE_GET_SECOND(space, w_obj): """Return the second, as an int from 0 through 59. """ return space.int_w(space.getattr(w_obj, space.wrap("second"))) -@cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DATE_GET_MICROSECOND(space, w_obj): """Return the microsecond, as an int from 0 through 999999. """ return space.int_w(space.getattr(w_obj, space.wrap("microsecond"))) -@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_TIME_GET_HOUR(space, w_obj): """Return the hour, as an int from 0 through 23. """ return space.int_w(space.getattr(w_obj, space.wrap("hour"))) -@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_TIME_GET_MINUTE(space, w_obj): """Return the minute, as an int from 0 through 59. """ return space.int_w(space.getattr(w_obj, space.wrap("minute"))) -@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_TIME_GET_SECOND(space, w_obj): """Return the second, as an int from 0 through 59. """ return space.int_w(space.getattr(w_obj, space.wrap("second"))) -@cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_TIME_GET_MICROSECOND(space, w_obj): """Return the microsecond, as an int from 0 through 999999. """ @@ -248,14 +248,14 @@ # But it does not seem possible to expose a different structure # for types defined in a python module like lib/datetime.py. -@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DELTA_GET_DAYS(space, w_obj): return space.int_w(space.getattr(w_obj, space.wrap("days"))) -@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DELTA_GET_SECONDS(space, w_obj): return space.int_w(space.getattr(w_obj, space.wrap("seconds"))) -@cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL) def PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj): return space.int_w(space.getattr(w_obj, space.wrap("microseconds"))) diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py --- a/pypy/module/cpyext/floatobject.py +++ b/pypy/module/cpyext/floatobject.py @@ -48,7 +48,7 @@ def PyFloat_AsDouble(space, w_obj): return space.float_w(space.float(w_obj)) -@cpython_api([PyObject], lltype.Float, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], lltype.Float, error=CANNOT_FAIL) def PyFloat_AS_DOUBLE(space, w_float): """Return a C double representation of the contents of w_float, but without error checking.""" diff --git a/pypy/module/cpyext/include/listobject.h b/pypy/module/cpyext/include/listobject.h --- a/pypy/module/cpyext/include/listobject.h +++ b/pypy/module/cpyext/include/listobject.h @@ -1,1 +1,1 @@ -#define PyList_GET_ITEM PyList_GetItem +#define PyList_GET_ITEM(o, i) PyList_GetItem((PyObject*)(o), (i)) diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py --- a/pypy/module/cpyext/listobject.py +++ b/pypy/module/cpyext/listobject.py @@ -21,7 +21,7 @@ """ return space.newlist([None] * len) -@cpython_api([PyObject, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL, +@cpython_api([rffi.VOIDP, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL, result_borrowed=True) def PyList_SET_ITEM(space, w_list, index, w_item): """Macro form of PyList_SetItem() without error checking. This is normally @@ -87,7 +87,7 @@ space.call_method(space.w_list, "insert", w_list, space.wrap(index), w_item) return 0 -@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL) def PyList_GET_SIZE(space, w_list): """Macro form of PyList_Size() without error checking. """ 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 @@ -54,7 +54,7 @@ except OperationError: raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m))) -@cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True) +@cpython_api([rffi.VOIDP, Py_ssize_t], PyObject, result_borrowed=True) def PySequence_Fast_GET_ITEM(space, w_obj, index): """Return the ith element of o, assuming that o was returned by PySequence_Fast(), o is not NULL, and that i is within bounds. @@ -67,7 +67,7 @@ "PySequence_Fast_GET_ITEM called but object is not a list or " "sequence") -@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL) def PySequence_Fast_GET_SIZE(space, w_obj): """Returns the length of o, assuming that o was returned by PySequence_Fast() and that o is not NULL. The size can also be @@ -82,7 +82,7 @@ "PySequence_Fast_GET_SIZE called but object is not a list or " "sequence") -@cpython_api([PyObject], PyObjectP) +@cpython_api([rffi.VOIDP], PyObjectP) def PySequence_Fast_ITEMS(space, w_obj): """Return the underlying array of PyObject pointers. Assumes that o was returned by PySequence_Fast() and o is not NULL. @@ -119,7 +119,7 @@ space.delslice(w_obj, space.wrap(start), space.wrap(end)) return 0 -@cpython_api([PyObject, Py_ssize_t], PyObject) +@cpython_api([rffi.VOIDP, Py_ssize_t], PyObject) def PySequence_ITEM(space, w_obj, i): """Return the ith element of o or NULL on failure. Macro form of PySequence_GetItem() but without checking that diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -74,7 +74,7 @@ space.call_method(space.w_set, 'clear', w_set) return 0 -@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL) def PySet_GET_SIZE(space, w_s): """Macro form of PySet_Size() without error checking.""" return space.int_w(space.len(w_s)) diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py --- a/pypy/module/cpyext/test/test_datetime.py +++ b/pypy/module/cpyext/test/test_datetime.py @@ -117,3 +117,108 @@ datetime.timedelta, datetime.tzinfo) module.clear_types() + + def test_macros(self): + module = self.import_extension('foo', [ + ("test_date_macros", "METH_NOARGS", + """ + PyObject* obj; + PyDateTime_Date* d; + PyDateTime_IMPORT; + if (!PyDateTimeAPI) { + PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); + return NULL; + } + obj = PyDate_FromDate(2000, 6, 6); + d = (PyDateTime_Date*)obj; + + PyDateTime_GET_YEAR(obj); + PyDateTime_GET_YEAR(d); + + PyDateTime_GET_MONTH(obj); + PyDateTime_GET_MONTH(d); + + PyDateTime_GET_DAY(obj); + PyDateTime_GET_DAY(d); + + return obj; + """), + ("test_datetime_macros", "METH_NOARGS", + """ + PyDateTime_IMPORT; + if (!PyDateTimeAPI) { + PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); + return NULL; + } + PyObject* obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6, 6, 6); + PyDateTime_DateTime* dt = (PyDateTime_DateTime*)obj; + + PyDateTime_GET_YEAR(obj); + PyDateTime_GET_YEAR(dt); + + PyDateTime_GET_MONTH(obj); + PyDateTime_GET_MONTH(dt); + + PyDateTime_GET_DAY(obj); + PyDateTime_GET_DAY(dt); + + PyDateTime_DATE_GET_HOUR(obj); + PyDateTime_DATE_GET_HOUR(dt); + + PyDateTime_DATE_GET_MINUTE(obj); + PyDateTime_DATE_GET_MINUTE(dt); + + PyDateTime_DATE_GET_SECOND(obj); + PyDateTime_DATE_GET_SECOND(dt); + + PyDateTime_DATE_GET_MICROSECOND(obj); + PyDateTime_DATE_GET_MICROSECOND(dt); + + return obj; + """), + ("test_time_macros", "METH_NOARGS", + """ + PyDateTime_IMPORT; + if (!PyDateTimeAPI) { + PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); + return NULL; + } + PyObject* obj = PyTime_FromTime(6, 6, 6, 6); + PyDateTime_Time* t = (PyDateTime_Time*)obj; + + PyDateTime_TIME_GET_HOUR(obj); + PyDateTime_TIME_GET_HOUR(t); + + PyDateTime_TIME_GET_MINUTE(obj); + PyDateTime_TIME_GET_MINUTE(t); + + PyDateTime_TIME_GET_SECOND(obj); + PyDateTime_TIME_GET_SECOND(t); + + PyDateTime_TIME_GET_MICROSECOND(obj); + PyDateTime_TIME_GET_MICROSECOND(t); + + return obj; + """), + ("test_delta_macros", "METH_NOARGS", + """ + PyDateTime_IMPORT; + if (!PyDateTimeAPI) { + PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI"); + return NULL; + } + PyObject* obj = PyDelta_FromDSU(6, 6, 6); + PyDateTime_Delta* delta = (PyDateTime_Delta*)obj; + + PyDateTime_DELTA_GET_DAYS(obj); + PyDateTime_DELTA_GET_DAYS(delta); + + PyDateTime_DELTA_GET_SECONDS(obj); + PyDateTime_DELTA_GET_SECONDS(delta); + + PyDateTime_DELTA_GET_MICROSECONDS(obj); + PyDateTime_DELTA_GET_MICROSECONDS(delta); + + return obj; + """), + ]) diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py --- a/pypy/module/cpyext/test/test_floatobject.py +++ b/pypy/module/cpyext/test/test_floatobject.py @@ -77,3 +77,19 @@ neginf = module.return_neginf() assert neginf < 0 assert math.isinf(neginf) + + def test_macro_accepts_wrong_pointer_type(self): + import math + + module = self.import_extension('foo', [ + ("test_macros", "METH_NOARGS", + """ + PyObject* o = PyFloat_FromDouble(1.0); + // no PyFloatObject + char* dumb_pointer = (char*)o; + + PyFloat_AS_DOUBLE(o); + PyFloat_AS_DOUBLE(dumb_pointer); + + Py_RETURN_NONE;"""), + ]) diff --git a/pypy/module/cpyext/test/test_listobject.py b/pypy/module/cpyext/test/test_listobject.py --- a/pypy/module/cpyext/test/test_listobject.py +++ b/pypy/module/cpyext/test/test_listobject.py @@ -137,6 +137,33 @@ module.setlistitem(l,0) assert l == [None, 2, 3] + def test_list_macros(self): + """The PyList_* macros cast, and calls expecting that build.""" + module = self.import_extension('foo', [ + ("test_macro_invocations", "METH_NOARGS", + """ + PyObject* o = PyList_New(2); + PyListObject* l = (PyListObject*)o; + + + Py_INCREF(o); + PyList_SET_ITEM(o, 0, o); + Py_INCREF(o); + PyList_SET_ITEM(l, 1, o); + + PyList_GET_ITEM(o, 0); + PyList_GET_ITEM(l, 1); + + PyList_GET_SIZE(o); + PyList_GET_SIZE(l); + + return o; + """ + ) + ]) + x = module.test_macro_invocations() + assert x[0] is x[1] is x + def test_get_item_macro(self): module = self.import_extension('foo', [ ("test_get_item", "METH_NOARGS", 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 @@ -155,6 +155,29 @@ result = api.PySequence_Index(w_gen, w_tofind) assert result == 4 +class AppTestSetObject(AppTestCpythonExtensionBase): + def test_sequence_macro_cast(self): + module = self.import_extension('foo', [ + ("test_macro_cast", "METH_NOARGS", + """ + PyObject *o = PyList_New(0); + PyListObject* l; + PyList_Append(o, o); + l = (PyListObject*)o; + + PySequence_Fast_GET_ITEM(o, 0); + PySequence_Fast_GET_ITEM(l, 0); + + PySequence_Fast_GET_SIZE(o); + PySequence_Fast_GET_SIZE(l); + + PySequence_ITEM(o, 0); + PySequence_ITEM(l, 0); + + return o; + """ + ) + ]) class TestCPyListStrategy(BaseApiTest): def test_getitem_setitem(self, space, api): w_l = space.wrap([1, 2, 3, 4]) diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py --- a/pypy/module/cpyext/test/test_setobject.py +++ b/pypy/module/cpyext/test/test_setobject.py @@ -2,6 +2,7 @@ from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase from rpython.rtyper.lltypesystem import rffi, lltype @@ -45,3 +46,20 @@ w_frozenset = space.newfrozenset([space.wrap(i) for i in [1, 2, 3, 4]]) assert api.PyAnySet_CheckExact(w_set) assert api.PyAnySet_CheckExact(w_frozenset) + +class AppTestSetObject(AppTestCpythonExtensionBase): + def test_set_macro_cast(self): + module = self.import_extension('foo', [ + ("test_macro_cast", "METH_NOARGS", + """ + PyObject* o = PySet_New(NULL); + // no PySetObject + char* dumb_pointer = (char*) o; + + PySet_GET_SIZE(o); + PySet_GET_SIZE(dumb_pointer); + + return o; + """ + ) + ]) diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -160,6 +160,26 @@ assert module.compare("abc", b"") == 1 + def test_unicode_macros(self): + """The PyUnicode_* macros cast, and calls expecting that build.""" + module = self.import_extension('foo', [ + ("test_macro_invocations", "METH_NOARGS", + """ + PyObject* o = PyUnicode_FromString(""); + PyUnicodeObject* u = (PyUnicodeObject*)o; + + PyUnicode_GET_SIZE(u); + PyUnicode_GET_SIZE(o); + + PyUnicode_GET_DATA_SIZE(u); + PyUnicode_GET_DATA_SIZE(o); + + PyUnicode_AS_UNICODE(o); + PyUnicode_AS_UNICODE(u); + return o; + """)]) + assert module.test_macro_invocations() == u'' + class TestUnicode(BaseApiTest): def test_unicodeobject(self, space, api): assert api.PyUnicode_GET_SIZE(space.wrap(u'späm')) == 4 diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py --- a/pypy/module/cpyext/test/test_weakref.py +++ b/pypy/module/cpyext/test/test_weakref.py @@ -7,7 +7,6 @@ w_ref = api.PyWeakref_NewRef(w_obj, space.w_None) assert w_ref is not None assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj) - assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj) assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj) w_obj = space.newtuple([]) @@ -34,3 +33,26 @@ del w_obj import gc; gc.collect() assert space.is_w(api.PyWeakref_LockObject(w_ref), space.w_None) + + +class AppTestWeakReference(AppTestCpythonExtensionBase): + + def test_weakref_macro(self): + module = self.import_extension('foo', [ + ("test_macro_cast", "METH_NOARGS", + """ + // PyExc_Warning is some weak-reffable PyObject*. + char* dumb_pointer; + PyObject* weakref_obj = PyWeakref_NewRef(PyExc_Warning, NULL); + if (!weakref_obj) return weakref_obj; + // No public PyWeakReference type. + dumb_pointer = (char*) weakref_obj; + + PyWeakref_GET_OBJECT(weakref_obj); + PyWeakref_GET_OBJECT(dumb_pointer); + + return weakref_obj; + """ + ) + ]) + module.test_macro_cast() 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 @@ -18,8 +18,9 @@ Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL, Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder, PyObjectFields, Py_TPFLAGS_BASETYPE, Py_buffer) -from pypy.module.cpyext.methodobject import ( - PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef) +from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject, + PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef, + W_PyCMethodObject, W_PyCFunctionObject) from pypy.module.cpyext.modsupport import convert_method_defs from pypy.module.cpyext.pyobject import ( PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr, @@ -125,6 +126,14 @@ cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields, PyGetSetDescrObjectStruct, level=2) +PyMethodDescrObjectStruct = lltype.ForwardReference() +PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct) +PyMethodDescrObjectFields = PyDescrObjectFields + ( + ("d_method", lltype.Ptr(PyMethodDef)), + ) +cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields, + PyMethodDescrObjectStruct, level=2) + @bootstrap_function def init_memberdescrobject(space): make_typedescr(W_MemberDescr.typedef, @@ -136,6 +145,16 @@ basestruct=PyGetSetDescrObject.TO, attach=getsetdescr_attach, ) + make_typedescr(W_PyCClassMethodObject.typedef, + basestruct=PyMethodDescrObject.TO, + attach=methoddescr_attach, + realize=classmethoddescr_realize, + ) + make_typedescr(W_PyCMethodObject.typedef, + basestruct=PyMethodDescrObject.TO, + attach=methoddescr_attach, + realize=methoddescr_realize, + ) def memberdescr_attach(space, py_obj, w_obj): """ @@ -166,6 +185,30 @@ assert isinstance(w_obj, W_GetSetPropertyEx) py_getsetdescr.c_d_getset = w_obj.getset +def methoddescr_attach(space, py_obj, w_obj): + py_methoddescr = rffi.cast(PyMethodDescrObject, py_obj) + # XXX assign to d_dname, d_type? + assert isinstance(w_obj, W_PyCFunctionObject) + py_methoddescr.c_d_method = w_obj.ml + +def classmethoddescr_realize(space, obj): + # XXX NOT TESTED When is this ever called? + method = rffi.cast(lltype.Ptr(PyMethodDef), obj) + w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type)) + w_obj = space.allocate_instance(W_PyCClassMethodObject, w_type) + w_obj.__init__(space, method, w_type) + track_reference(space, obj, w_obj) + return w_obj + +def methoddescr_realize(space, obj): + # XXX NOT TESTED When is this ever called? + method = rffi.cast(lltype.Ptr(PyMethodDef), obj) + w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type)) + w_obj = space.allocate_instance(W_PyCMethodObject, w_type) + w_obj.__init__(space, method, w_type) + track_reference(space, obj, w_obj) + return w_obj + def convert_getset_defs(space, dict_w, getsets, w_type): getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets) if getsets: diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -183,19 +183,19 @@ """Get the maximum ordinal for a Unicode character.""" return runicode.UNICHR(runicode.MAXUNICODE) -@cpython_api([PyObject], rffi.CCHARP, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], rffi.CCHARP, error=CANNOT_FAIL) def PyUnicode_AS_DATA(space, ref): """Return a pointer to the internal buffer of the object. o has to be a PyUnicodeObject (not checked).""" return rffi.cast(rffi.CCHARP, PyUnicode_AS_UNICODE(space, ref)) -@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL) def PyUnicode_GET_DATA_SIZE(space, w_obj): """Return the size of the object's internal buffer in bytes. o has to be a PyUnicodeObject (not checked).""" return rffi.sizeof(lltype.UniChar) * PyUnicode_GET_SIZE(space, w_obj) -@cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL) +@cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL) def PyUnicode_GET_SIZE(space, w_obj): """Return the size of the object. o has to be a PyUnicodeObject (not checked).""" @@ -222,7 +222,7 @@ ref_unicode = rffi.cast(PyUnicodeObject, ref) if not ref_unicode.c_buffer: # Copy unicode buffer - w_unicode = from_ref(space, ref) + w_unicode = from_ref(space, rffi.cast(PyObject, ref)) u = space.unicode_w(w_unicode) ref_unicode.c_buffer = rffi.unicode2wcharp(u) return ref_unicode.c_buffer @@ -235,7 +235,7 @@ w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) if not space.is_true(space.issubtype(w_type, space.w_unicode)): raise oefmt(space.w_TypeError, "expected unicode object") - return PyUnicode_AS_UNICODE(space, ref) + return PyUnicode_AS_UNICODE(space, rffi.cast(rffi.VOIDP, ref)) @cpython_api([PyObject], rffi.CCHARP) def _PyUnicode_AsString(space, ref): @@ -267,8 +267,7 @@ string may or may not be 0-terminated. It is the responsibility of the caller to make sure that the wchar_t string is 0-terminated in case this is required by the application.""" - c_buffer = PyUnicode_AS_UNICODE(space, ref) - ref = rffi.cast(PyUnicodeObject, ref) + c_str = PyUnicode_AS_UNICODE(space, rffi.cast(rffi.VOIDP, ref)) c_length = ref.c_length # If possible, try to copy the 0-termination as well diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py --- a/pypy/module/cpyext/weakrefobject.py +++ b/pypy/module/cpyext/weakrefobject.py @@ -1,6 +1,7 @@ from pypy.module.cpyext.api import cpython_api from pypy.module.cpyext.pyobject import PyObject from pypy.module._weakref.interp__weakref import W_Weakref, proxy +from rpython.rtyper.lltypesystem import rffi @cpython_api([PyObject, PyObject], PyObject) def PyWeakref_NewRef(space, w_obj, w_callback): @@ -37,7 +38,7 @@ """ return space.call_function(w_ref) # borrowed ref -@cpython_api([PyObject], PyObject, result_borrowed=True) +@cpython_api([rffi.VOIDP], PyObject, result_borrowed=True) def PyWeakref_GET_OBJECT(space, w_ref): """Similar to PyWeakref_GetObject(), but implemented as a macro that does no error checking. diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -41,6 +41,14 @@ return '.' + soabi + SO +def log_pyverbose(space, level, message): + if space.sys.w_initialdict is None: + return # sys module not initialised, avoid recursion + verbose = space.sys.get_flag('verbose') + if verbose >= level: + w_stderr = space.sys.get('stderr') + space.call_method(w_stderr, "write", space.wrap(message)) + def has_so_extension(space): return (space.config.objspace.usemodules.cpyext or space.config.objspace.usemodules._cffi_backend) @@ -354,6 +362,9 @@ Load a module from a compiled file, execute it, and return its module object. """ + log_pyverbose(space, 1, "import %s # compiled from %s\n" % + (space.str_w(w_modulename), cpathname)) + if magic != get_pyc_magic(space): raise oefmt(space.w_ImportError, "Bad magic number in %s", cpathname) #print "loading pyc file:", cpathname diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -46,15 +46,13 @@ if pkgname: p = p.join(*pkgname.split('.')) p.ensure(dir=1) - f = p.join("__init__.py").open('w') - print >> f, "# package" - f.close() + with p.join("__init__.py").open('w') as f: + print >> f, "# package" for filename, content in entries.items(): filename += '.py' - f = p.join(filename).open('w') - print >> f, '#', filename - print >> f, content - f.close() + with p.join(filename).open('w') as f: + print >> f, '#', filename + print >> f, content return p def setup_directory_structure(cls): @@ -123,6 +121,9 @@ 'a=5\nb=6\rc="""hello\r\nworld"""\r', mode='wb') p.join('mod.py').write( 'a=15\nb=16\rc="""foo\r\nbar"""\r', mode='wb') + setuppkg("verbose1pkg", verbosemod='a = 1729') + setuppkg("verbose2pkg", verbosemod='a = 1729') + setuppkg("verbose0pkg", verbosemod='a = 1729') setuppkg("test_bytecode", a = '', b = '', @@ -565,9 +566,8 @@ import test_reload import time, imp time.sleep(1) - f = open(test_reload.__file__, "w") - f.write("a = 10 // 0\n") - f.close() + with open(test_reload.__file__, "w") as f: + f.write("a = 10 // 0\n") # A failing reload should leave the previous module in sys.modules raises(ZeroDivisionError, imp.reload, test_reload) @@ -710,7 +710,8 @@ import pkg import os pathname = os.path.join(os.path.dirname(pkg.__file__), 'a.py') - module = imp.load_module('a', open(pathname), + with open(pathname) as fid: + module = imp.load_module('a', fid, 'invalid_path_name', ('.py', 'r', imp.PY_SOURCE)) assert module.__name__ == 'a' assert module.__file__ == 'invalid_path_name' @@ -745,6 +746,68 @@ else: raise AssertionError("should have failed") + def test_verbose_flag_1(self): + output = [] + class StdErr(object): + def write(self, line): + output.append(line) + + import sys, imp + old_flags = sys.flags + + class Flags(object): + verbose = 1 + def __getattr__(self, name): + return getattr(old_flags, name) + + sys.flags = Flags() + sys.stderr = StdErr() + try: + import verbose1pkg.verbosemod + finally: + imp.reload(sys) + assert 'import verbose1pkg # ' in output[-2] + assert 'import verbose1pkg.verbosemod # ' in output[-1] + + def test_verbose_flag_2(self): + output = [] + class StdErr(object): + def write(self, line): + output.append(line) + + import sys, imp + old_flags = sys.flags + + class Flags(object): + verbose = 2 + def __getattr__(self, name): + return getattr(old_flags, name) + + sys.flags = Flags() + sys.stderr = StdErr() + try: + import verbose2pkg.verbosemod + finally: + imp.reload(sys) + assert any('import verbose2pkg # ' in line + for line in output[:-2]) + assert output[-2].startswith('# trying') + assert 'import verbose2pkg.verbosemod # ' in output[-1] + + def test_verbose_flag_0(self): + output = [] + class StdErr(object): + def write(self, line): + output.append(line) + + import sys, imp + sys.stderr = StdErr() + try: + import verbose0pkg.verbosemod + finally: + imp.reload(sys) + assert not output + def test_source_encoding(self): import imp import encoded diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh --- a/pypy/tool/release/repackage.sh +++ b/pypy/tool/release/repackage.sh @@ -1,26 +1,33 @@ # Edit these appropriately before running this script maj=5 min=1 -rev=1 +rev=2 branchname=release-$maj.x # ==OR== release-$maj.$min.x tagname=release-$maj.$min.$rev # ==OR== release-$maj.$min +echo checking hg log -r $branchname hg log -r $branchname || exit 1 +echo checking hg log -r $tagname hg log -r $tagname || exit 1 # This script will download latest builds from the buildmaster, rename the top # level directory, and repackage ready to be uploaded to bitbucket. It will also # download source, assuming a tag for the release already exists, and repackage them. # The script should be run in an empty directory, i.e. /tmp/release_xxx - for plat in linux linux64 linux-armhf-raspbian linux-armhf-raring linux-armel osx64 s390x do + echo downloading package for $plat wget http://buildbot.pypy.org/nightly/$branchname/pypy-c-jit-latest-$plat.tar.bz2 tar -xf pypy-c-jit-latest-$plat.tar.bz2 rm pypy-c-jit-latest-$plat.tar.bz2 - mv pypy-c-jit-*-$plat pypy-$maj.$min.$rev-$plat - tar --owner=root --group=root --numeric-owner -cvjf pypy-$maj.$min.$rev-$plat.tar.bz2 pypy-$maj.$min.$rev-$plat - rm -rf pypy-$maj.$min.$rev-$plat + plat_final=$plat + if [ $plat = linux ]; then + plat_final=linux32 + fi + mv pypy-c-jit-*-$plat pypy-$maj.$min.$rev-$plat_final + echo packaging $plat_final + tar --owner=root --group=root --numeric-owner -cvjf pypy-$maj.$min.$rev-$plat_final.tar.bz2 pypy-$maj.$min.$rev-$plat_final + rm -rf pypy-$maj.$min.$rev-$plat_final done plat=win32 diff --git a/pypy/tool/test/test_tab.py b/pypy/tool/test/test_tab.py --- a/pypy/tool/test/test_tab.py +++ b/pypy/tool/test/test_tab.py @@ -7,7 +7,11 @@ ROOT = os.path.abspath(os.path.join(pypydir, '..')) RPYTHONDIR = os.path.join(ROOT, "rpython") -EXCLUDE = {'/virt_test/lib/python2.7/site-packages/setuptools'} + +EXCLUDE = {'/virt_test'} +# ^^^ don't look inside this: it is created by virtualenv on buildslaves. +# It contains third-party installations that may include tabs in their +# .py files. def test_no_tabs(): diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py --- a/rpython/rlib/rawrefcount.py +++ b/rpython/rlib/rawrefcount.py @@ -27,13 +27,13 @@ """NOT_RPYTHON: set up rawrefcount with the GC. This is only used for tests; it should not be called at all during translation. """ - global _p_list, _o_list, _adr2pypy, _pypy2ob, _ob_set + global _p_list, _o_list, _adr2pypy, _pypy2ob, _pypy2ob_rev global _d_list, _dealloc_trigger_callback _p_list = [] _o_list = [] _adr2pypy = [None] _pypy2ob = {} - _ob_set = set() + _pypy2ob_rev = {} _d_list = [] _dealloc_trigger_callback = dealloc_trigger_callback @@ -41,23 +41,22 @@ "NOT_RPYTHON: a link where the PyPy object contains some or all the data" #print 'create_link_pypy\n\t%s\n\t%s' % (p, ob) assert p not in _pypy2ob - assert ob._obj not in _ob_set + assert ob._obj not in _pypy2ob_rev assert not ob.c_ob_pypy_link ob.c_ob_pypy_link = _build_pypy_link(p) _pypy2ob[p] = ob + _pypy2ob_rev[ob._obj] = p _p_list.append(ob) - _ob_set.add(ob._obj) def create_link_pyobj(p, ob): """NOT_RPYTHON: a link where the PyObject contains all the data. from_obj() will not work on this 'p'.""" #print 'create_link_pyobj\n\t%s\n\t%s' % (p, ob) assert p not in _pypy2ob - assert ob._obj not in _ob_set + assert ob._obj not in _pypy2ob_rev assert not ob.c_ob_pypy_link ob.c_ob_pypy_link = _build_pypy_link(p) _o_list.append(ob) - _ob_set.add(ob._obj) def from_obj(OB_PTR_TYPE, p): "NOT_RPYTHON" @@ -65,6 +64,7 @@ if ob is None: return lltype.nullptr(OB_PTR_TYPE.TO) assert lltype.typeOf(ob) == OB_PTR_TYPE + assert _pypy2ob_rev[ob._obj] is p return ob def to_obj(Class, ob): @@ -111,8 +111,10 @@ new_p_list.append(ob) else: p = detach(ob, wr_p_list) - del _pypy2ob[p] - del p + ob_test = _pypy2ob.pop(p) + p_test = _pypy2ob_rev.pop(ob_test._obj) + assert p_test is p + del p, p_test ob = None _p_list = Ellipsis @@ -156,6 +158,10 @@ p = attach(ob, wr, _p_list) if p is not None: _pypy2ob[p] = ob + _pypy2ob_rev.clear() # rebuild this dict from scratch + for p, ob in _pypy2ob.items(): + assert ob._obj not in _pypy2ob_rev + _pypy2ob_rev[ob._obj] = p _o_list = [] for ob, wr in wr_o_list: attach(ob, wr, _o_list) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit