Author: Mark Young <marky1...@gmail.com> Branch: py3k-clock_get_info Changeset: r84756:a491593ec0e7 Date: 2016-05-20 21:22 -0400 http://bitbucket.org/pypy/pypy/changeset/a491593ec0e7/
Log: Merge with upstream. 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/lib-python/3/test/test_descr.py b/lib-python/3/test/test_descr.py --- a/lib-python/3/test/test_descr.py +++ b/lib-python/3/test/test_descr.py @@ -4674,6 +4674,7 @@ class MiscTests(unittest.TestCase): + @support.cpython_only def test_type_lookup_mro_reference(self): # Issue #14199: _PyType_Lookup() has to keep a strong reference to # the type MRO because it may be modified during the lookup, if diff --git a/lib-python/3/test/test_socket.py b/lib-python/3/test/test_socket.py --- a/lib-python/3/test/test_socket.py +++ b/lib-python/3/test/test_socket.py @@ -691,10 +691,11 @@ # wrong number of args with self.assertRaises(TypeError) as cm: s.sendto(b'foo') - self.assertIn(' given)', str(cm.exception)) + if support.check_impl_detail(): + self.assertIn(' given)', str(cm.exception)) with self.assertRaises(TypeError) as cm: s.sendto(b'foo', 0, sockname, 4) - self.assertIn(' given)', str(cm.exception)) + self.assertIn(' given', str(cm.exception)) def testCrucialConstants(self): # Testing for mission critical constants 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/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -677,9 +677,9 @@ exc = raises(TypeError, (lambda: 0), b=3) assert str(exc.value) == "<lambda>() got an unexpected keyword argument 'b'" exc = raises(TypeError, (lambda a, b: 0), 1, 2, 3, a=1) - assert str(exc.value) == "<lambda>() takes 2 positional arguments but 3 were given" + assert str(exc.value) == "<lambda>() got multiple values for argument 'a'" exc = raises(TypeError, (lambda a, b=1: 0), 1, 2, 3, a=1) - assert str(exc.value) == "<lambda>() takes from 1 to 2 positional arguments but 3 were given" + assert str(exc.value) == "<lambda>() got multiple values for argument 'a'" exc = raises(TypeError, (lambda a, **kw: 0), 1, 2, 3) assert str(exc.value) == "<lambda>() takes 1 positional argument but 3 were given" exc = raises(TypeError, (lambda a, b=1, **kw: 0), 1, 2, 3) 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/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py --- a/pypy/module/_socket/interp_socket.py +++ b/pypy/module/_socket/interp_socket.py @@ -12,8 +12,8 @@ from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.typedef import ( - GetSetProperty, TypeDef, interp_attrproperty, make_weakref_descr -) + GetSetProperty, TypeDef, generic_new_descr, interp_attrproperty, + make_weakref_descr) # XXX Hack to seperate rpython and pypy @@ -39,7 +39,7 @@ # Linux abstract namespace return space.wrapbytes(path) else: - return space.wrap(path) + return space.wrap_fsdecoded(path) elif rsocket.HAS_AF_NETLINK and isinstance(addr, rsocket.NETLINKAddress): return space.newtuple([space.wrap(addr.get_pid()), space.wrap(addr.get_groups())]) @@ -159,15 +159,14 @@ class W_Socket(W_Root): - def __init__(self, space, sock): + def __init__(self, space, sock=None): self.space = space - self.sock = sock - register_socket(space, sock) - - def descr_new(space, w_subtype, __args__): - sock = space.allocate_instance(W_Socket, w_subtype) - W_Socket.__init__(sock, space, RSocket.empty_rsocket()) - return space.wrap(sock) + if sock is None: + self.sock = RSocket.empty_rsocket() + else: + register_socket(space, sock) + self.sock = sock + self.register_finalizer(space) @unwrap_spec(family=int, type=int, proto=int, w_fileno=WrappedDefault(None)) @@ -184,12 +183,15 @@ raise converted_error(space, e) def _finalize_(self): - self.clear_all_weakrefs() - if self.sock.fd != rsocket.INVALID_SOCKET: + sock = self.sock + if sock.fd != rsocket.INVALID_SOCKET: try: self._dealloc_warn() finally: - self.close_w(self.space) + try: + sock.close() + except SocketError: + pass def get_type_w(self, space): return space.wrap(self.sock.type) @@ -734,7 +736,7 @@ shutdown(how) -- shut down traffic in one or both directions [*] not available on all platforms!""", - __new__ = interp2app(W_Socket.descr_new.im_func), + __new__ = generic_new_descr(W_Socket), __init__ = interp2app(W_Socket.descr_init), __repr__ = interp2app(W_Socket.descr_repr), type = GetSetProperty(W_Socket.get_type_w), diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -137,6 +137,11 @@ space.wrap(lib_str) if lib_str else space.w_None) return OperationError(w_exception_class, w_exception) +def timeout_error(space, msg): + w_exc_class = interp_socket.get_error(space, 'timeout') + w_exc = space.call_function(w_exc_class, space.wrap(msg)) + return OperationError(w_exc_class, w_exc) + class SSLNpnProtocols(object): def __init__(self, ctx, protos): @@ -334,7 +339,7 @@ sockstate = checkwait(space, w_socket, True) if sockstate == SOCKET_HAS_TIMED_OUT: - raise ssl_error(space, "The write operation timed out") + raise timeout_error(space, "The write operation timed out") elif sockstate == SOCKET_HAS_BEEN_CLOSED: raise ssl_error(space, "Underlying socket has been closed.") elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT: @@ -355,7 +360,7 @@ sockstate = SOCKET_OPERATION_OK if sockstate == SOCKET_HAS_TIMED_OUT: - raise ssl_error(space, "The write operation timed out") + raise timeout_error(space, "The write operation timed out") elif sockstate == SOCKET_HAS_BEEN_CLOSED: raise ssl_error(space, "Underlying socket has been closed.") elif sockstate == SOCKET_IS_NONBLOCKING: @@ -392,7 +397,7 @@ if not count: sockstate = checkwait(space, w_socket, False) if sockstate == SOCKET_HAS_TIMED_OUT: - raise ssl_error(space, "The read operation timed out") + raise timeout_error(space, "The read operation timed out") elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT: raise ssl_error(space, "Underlying socket too large for select().") @@ -432,7 +437,7 @@ sockstate = SOCKET_OPERATION_OK if sockstate == SOCKET_HAS_TIMED_OUT: - raise ssl_error(space, "The read operation timed out") + raise timeout_error(space, "The read operation timed out") elif sockstate == SOCKET_IS_NONBLOCKING: break @@ -481,7 +486,7 @@ else: sockstate = SOCKET_OPERATION_OK if sockstate == SOCKET_HAS_TIMED_OUT: - raise ssl_error(space, "The handshake operation timed out") + raise timeout_error(space, "The handshake operation timed out") elif sockstate == SOCKET_HAS_BEEN_CLOSED: raise ssl_error(space, "Underlying socket has been closed.") elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT: @@ -549,9 +554,9 @@ if sockstate == SOCKET_HAS_TIMED_OUT: if ssl_err == SSL_ERROR_WANT_READ: - raise ssl_error(space, "The read operation timed out") + raise timeout_error(space, "The read operation timed out") else: - raise ssl_error(space, "The write operation timed out") + raise timeout_error(space, "The write operation timed out") elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT: raise ssl_error(space, "Underlying socket too large for select().") 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,8 @@ 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_buffer = 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/support.py b/pypy/module/imp/test/support.py --- a/pypy/module/imp/test/support.py +++ b/pypy/module/imp/test/support.py @@ -4,14 +4,57 @@ def setup_class(cls): space = cls.space - testfn = u'test_tmp' - testfn_unencodable = None + cls.w_testfn_unencodable = space.wrap(get_unencodable()) + cls.w_special_char = space.wrap(get_special_char()) - if sys.platform == 'win32': - testfn_unencodable = testfn + u"-\u5171\u0141\u2661\u0363\uDC80" - elif sys.platform != 'darwin': - try: - '\xff'.decode(sys.getfilesystemencoding()) - except UnicodeDecodeError: - testfn_unencodable = testfn + u'-\udcff' - cls.w_testfn_unencodable = space.wrap(testfn_unencodable) +def get_unencodable(): + """Copy of the stdlib's support.TESTFN_UNENCODABLE: + + A filename (py3k str type) that should *not* be able to be encoded + by the filesystem encoding (in strict mode). It can be None if we + cannot generate such filename. + """ + testfn_unencodable = None + testfn = u'test_tmp' + + if sys.platform == 'win32': + testfn_unencodable = testfn + u"-\u5171\u0141\u2661\u0363\uDC80" + elif sys.platform != 'darwin': + try: + '\xff'.decode(sys.getfilesystemencoding()) + except UnicodeDecodeError: + testfn_unencodable = testfn + u'-\udcff' + return testfn_unencodable + +def get_special_char(): + """Copy of the stdlib's test_imp.test_issue5604 special_char: + + A non-ascii filename (py3k str type) that *should* be able to be + encoded by the filesystem encoding (in strict mode). It can be None + if we cannot generate such filename. + """ + fsenc = sys.getfilesystemencoding() + # covers utf-8 and Windows ANSI code pages one non-space symbol from + # every page (http://en.wikipedia.org/wiki/Code_page) + known_locales = { + 'utf-8' : b'\xc3\xa4', + 'cp1250' : b'\x8C', + 'cp1251' : b'\xc0', + 'cp1252' : b'\xc0', + 'cp1253' : b'\xc1', + 'cp1254' : b'\xc0', + 'cp1255' : b'\xe0', + 'cp1256' : b'\xe0', + 'cp1257' : b'\xc0', + 'cp1258' : b'\xc0', + } + + if sys.platform == 'darwin': + # Mac OS X uses the Normal Form D decomposition + # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html + special_char = b'a\xcc\x88' + else: + special_char = known_locales.get(fsenc) + + if special_char: + return special_char.decode(fsenc) 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 = '', @@ -132,34 +133,11 @@ line2 = "# encoding: iso-8859-1\n", bad = "# encoding: uft-8\n") - fsenc = sys.getfilesystemencoding() - # covers utf-8 and Windows ANSI code pages one non-space symbol from - # every page (http://en.wikipedia.org/wiki/Code_page) - known_locales = { - 'utf-8' : b'\xc3\xa4', - 'cp1250' : b'\x8C', - 'cp1251' : b'\xc0', - 'cp1252' : b'\xc0', - 'cp1253' : b'\xc1', - 'cp1254' : b'\xc0', - 'cp1255' : b'\xe0', - 'cp1256' : b'\xe0', - 'cp1257' : b'\xc0', - 'cp1258' : b'\xc0', - } - - if sys.platform == 'darwin': - # Mac OS X uses the Normal Form D decomposition - # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html - special_char = b'a\xcc\x88' - else: - special_char = known_locales.get(fsenc) - - if special_char: + w_special_char = getattr(cls, 'w_special_char', None) + if not space.is_none(w_special_char): + special_char = space.unicode_w(w_special_char).encode( + sys.getfilesystemencoding()) p.join(special_char + '.py').write('pass') - cls.w_special_char = space.wrap(special_char.decode(fsenc)) - else: - cls.w_special_char = space.w_None # create a .pyw file p = setuppkg("windows", x = "x = 78") @@ -588,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) @@ -733,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' @@ -768,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 @@ -781,9 +821,9 @@ raises(SyntaxError, imp.find_module, 'bad', encoded.__path__) def test_find_module_fsdecode(self): - import sys name = self.special_char if not name: + import sys skip("can't run this test with %s as filesystem encoding" % sys.getfilesystemencoding()) import imp diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py --- a/pypy/module/zipimport/test/test_zipimport.py +++ b/pypy/module/zipimport/test/test_zipimport.py @@ -349,14 +349,23 @@ assert sys.path_hooks.count(zipimport.zipimporter) == 1 def w__make_unicode_filename(self): + if not self.testfn_unencodable: + import sys + skip("can't run this test with %s as filesystem encoding" + % sys.getfilesystemencoding()) import os head, tail = os.path.split(self.zipfile) - self.zipfile = head + os.path.sep + tail[:4] + '_ä' + tail[4:] + self.zipfile = (head + os.path.sep + tail[:4] + + self.testfn_unencodable + tail[4:]) def test_unicode_filename_notfound(self): + if not self.special_char: + import sys + skip("can't run this test with %s as filesystem encoding" + % sys.getfilesystemencoding()) import zipimport raises(zipimport.ZipImportError, - zipimport.zipimporter, 'caf\xe9') + zipimport.zipimporter, self.special_char) def test_unicode_filename_invalid_zippath(self): import zipimport diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1071,6 +1071,16 @@ class D(A, B): # "best base" is A __slots__ = ("__weakref__",) + def test_slot_shadows_class_variable(self): + try: + class X: + __slots__ = ["foo"] + foo = None + except ValueError as e: + assert str(e) == "'foo' in __slots__ conflicts with class variable" + else: + assert False, "ValueError expected" + def test_metaclass_calc(self): """ # issue1294232: correct metaclass calculation @@ -1318,15 +1328,6 @@ assert b == 1 - def test_slots_with_method_in_class(self): - # this works in cpython... - class A(object): - __slots__ = ["f"] - def f(self, x): - return x + 1 - a = A() - assert a.f(1) == 2 - def test_eq_returns_notimplemented(self): assert type.__eq__(int, 42) is NotImplemented assert type.__ne__(dict, 42) is NotImplemented diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -1041,7 +1041,8 @@ "__weakref__ slot disallowed: we already got one") wantweakref = True else: - index_next_extra_slot = create_slot(w_self, slot_name, + index_next_extra_slot = create_slot(w_self, w_slot_name, + slot_name, index_next_extra_slot) wantdict = wantdict or hasoldstylebase if wantdict: @@ -1057,13 +1058,17 @@ return Layout(base_layout.typedef, index_next_extra_slot, base_layout=base_layout) -def create_slot(w_self, slot_name, index_next_extra_slot): +def create_slot(w_self, w_slot_name, slot_name, index_next_extra_slot): space = w_self.space if not valid_slot_name(slot_name): raise oefmt(space.w_TypeError, "__slots__ must be identifiers") # create member slot_name = mangle(slot_name, w_self.name) - if slot_name not in w_self.dict_w: + if slot_name in w_self.dict_w: + raise oefmt(space.w_ValueError, + "%R in __slots__ conflicts with class variable", + w_slot_name) + else: # Force interning of slot names. slot_name = space.str_w(space.new_interned_str(slot_name)) # in cpython it is ignored less, but we probably don't care 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) diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -1045,15 +1045,23 @@ win32traits = make_win32_traits(traits) path1 = traits.as_str0(path1) path2 = traits.as_str0(path2) - if not win32traits.MoveFile(path1, path2): + if not win32traits.MoveFileEx(path1, path2, 0): raise rwin32.lastSavedWindowsError() @specialize.argtype(0, 1) def replace(path1, path2): - if os.name == 'nt': - raise NotImplementedError( - 'On windows, os.replace() should overwrite the destination') - return rename(path1, path2) + if _WIN32: + traits = _preferred_traits(path1) + win32traits = make_win32_traits(traits) + path1 = traits.as_str0(path1) + path2 = traits.as_str0(path2) + ret = win32traits.MoveFileEx(path1, path2, + win32traits.MOVEFILE_REPLACE_EXISTING) + if not ret: + raise rwin32.lastSavedWindowsError() + else: + ret = rename(path1, path2) + return ret #___________________________________________________________________ diff --git a/rpython/rlib/rwin32file.py b/rpython/rlib/rwin32file.py --- a/rpython/rlib/rwin32file.py +++ b/rpython/rlib/rwin32file.py @@ -45,6 +45,8 @@ 'INVALID_FILE_ATTRIBUTES') ERROR_SHARING_VIOLATION = platform.ConstantInteger( 'ERROR_SHARING_VIOLATION') + MOVEFILE_REPLACE_EXISTING = platform.ConstantInteger( + 'MOVEFILE_REPLACE_EXISTING') _S_IFDIR = platform.ConstantInteger('_S_IFDIR') _S_IFREG = platform.ConstantInteger('_S_IFREG') _S_IFCHR = platform.ConstantInteger('_S_IFCHR') @@ -103,7 +105,7 @@ FILE_WRITE_ATTRIBUTES OPEN_EXISTING FILE_FLAG_BACKUP_SEMANTICS VOLUME_NAME_DOS VOLUME_NAME_NT ERROR_FILE_NOT_FOUND ERROR_NO_MORE_FILES - ERROR_SHARING_VIOLATION + ERROR_SHARING_VIOLATION MOVEFILE_REPLACE_EXISTING '''.split(): locals()[name] = config[name] LPWIN32_FIND_DATA = lltype.Ptr(WIN32_FIND_DATA) @@ -199,9 +201,9 @@ rwin32.BOOL, save_err=rffi.RFFI_SAVE_LASTERROR) - MoveFile = external( - 'MoveFile' + suffix, - [traits.CCHARP, traits.CCHARP], + MoveFileEx = external( + 'MoveFileEx' + suffix, + [traits.CCHARP, traits.CCHARP, rwin32.DWORD], rwin32.BOOL, save_err=rffi.RFFI_SAVE_LASTERROR) diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py --- a/rpython/rlib/test/test_rposix.py +++ b/rpython/rlib/test/test_rposix.py @@ -334,6 +334,11 @@ self.path = UnicodeWithEncoding(self.ufilename) self.path2 = UnicodeWithEncoding(self.ufilename + ".new") + def _teardown_method(self, method): + for path in [self.ufilename + ".new", self.ufilename]: + if os.path.exists(path): + os.unlink(path) + def test_open(self): def f(): try: @@ -390,6 +395,14 @@ assert not os.path.exists(self.ufilename) assert os.path.exists(self.ufilename + '.new') + def test_replace(self): + def f(): + return rposix.replace(self.path, self.path2) + + interpret(f, []) + assert not os.path.exists(self.ufilename) + assert os.path.exists(self.ufilename + '.new') + def test_listdir(self): udir = UnicodeWithEncoding(os.path.dirname(self.ufilename)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit