Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3.5 Changeset: r89500:d33af2cf0f9f Date: 2017-01-11 18:43 +0000 http://bitbucket.org/pypy/pypy/changeset/d33af2cf0f9f/
Log: hg merge default 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 @@ -98,6 +98,7 @@ is readonly) without pinning it. .. branch: cpyext-cleanup +.. branch: api_func-refactor Refactor cpyext initialisation. @@ -105,3 +106,7 @@ Fix a test failure introduced by strbuf-as-buffer +.. branch: cpyext-FromBuffer + +Do not recreate the object in PyMemoryView_FromBuffer, rather pass it to +the returned PyMemoryViewObject, to take ownership of it. Fixes a ref leak. diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py --- a/pypy/module/cppyy/test/conftest.py +++ b/pypy/module/cppyy/test/conftest.py @@ -23,6 +23,10 @@ def pytest_ignore_collect(path, config): if py.path.local.sysfind('genreflex') is None and config.option.runappdirect: return True # "can't run dummy tests in -A" + if disabled: + return True + +disabled = None def pytest_configure(config): if py.path.local.sysfind('genreflex') is None: @@ -37,7 +41,7 @@ # build dummy backend (which has reflex info and calls hard-wired) import os from rpython.translator.tool.cbuild import ExternalCompilationInfo - from rpython.translator.platform import platform + from rpython.translator.platform import platform, CompilationError from rpython.translator import cdir from rpython.rtyper.lltypesystem import rffi @@ -55,9 +59,16 @@ use_cpp_linker=True, ) - soname = platform.compile( - [], eci, - outputfilename='libcppyy_dummy_backend', - standalone=False) + try: + soname = platform.compile( + [], eci, + outputfilename='libcppyy_dummy_backend', + standalone=False) + except CompilationError as e: + if '-std=c++11' in str(e): + global disabled + disabled = str(e) + return + raise lcapi.reflection_library = str(soname) 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 @@ -124,6 +124,7 @@ Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_MAX_NDIMS Py_CLEANUP_SUPPORTED +PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES """.split() for name in constant_names: setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name)) @@ -248,14 +249,13 @@ cpyext_namespace = NameManager('cpyext_') class ApiFunction(object): - def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED, + def __init__(self, argtypes, restype, callable, error=CANNOT_FAIL, c_name=None, gil=None, result_borrowed=False, result_is_ll=False): self.argtypes = argtypes self.restype = restype self.functype = lltype.Ptr(lltype.FuncType(argtypes, restype)) self.callable = callable - if error is not _NOT_SPECIFIED: - self.error_value = error + self.error_value = error self.c_name = c_name # extract the signature from the (CPython-level) code object @@ -300,7 +300,7 @@ argtypesw = zip(self.argtypes, [_name.startswith("w_") for _name in self.argnames]) - error_value = getattr(self, "error_value", CANNOT_FAIL) + error_value = self.error_value if (isinstance(self.restype, lltype.Ptr) and error_value is not CANNOT_FAIL): assert lltype.typeOf(error_value) == self.restype @@ -332,66 +332,19 @@ wrapper.c_name = cpyext_namespace.uniquename(self.c_name) return wrapper -DEFAULT_HEADER = 'pypy_decl.h' -def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header=DEFAULT_HEADER, - gil=None, result_borrowed=False, result_is_ll=False): - """ - Declares a function to be exported. - - `argtypes`, `restype` are lltypes and describe the function signature. - - `error` is the value returned when an applevel exception is raised. The - special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual - exception into a wrapped SystemError. Unwrapped exceptions also cause a - SytemError. - - `header` is the header file to export the function in, Set to None to get - a C function pointer, but not exported by the API headers. - - set `gil` to "acquire", "release" or "around" to acquire the GIL, - release the GIL, or both - """ - if isinstance(restype, lltype.Typedef): - real_restype = restype.OF - else: - real_restype = restype - - if error is _NOT_SPECIFIED: - if isinstance(real_restype, lltype.Ptr): - error = lltype.nullptr(real_restype.TO) - elif real_restype is lltype.Void: - error = CANNOT_FAIL - if type(error) is int: - error = rffi.cast(real_restype, error) - expect_integer = (isinstance(real_restype, lltype.Primitive) and - rffi.cast(restype, 0) == 0) - - def decorate(func): - func._always_inline_ = 'try' - func_name = func.func_name - if header is not None: - c_name = None - if func_name in FUNCTIONS_BY_HEADER[header]: - raise ValueError("%s already registered" % func_name) - else: - c_name = func_name - api_function = ApiFunction(argtypes, restype, func, error, - c_name=c_name, gil=gil, - result_borrowed=result_borrowed, - result_is_ll=result_is_ll) - func.api_func = api_function - - if error is _NOT_SPECIFIED: - raise ValueError("function %s has no return value for exceptions" - % func) - names = api_function.argnames - types_names_enum_ui = unrolling_iterable(enumerate( - zip(api_function.argtypes, - [tp_name.startswith("w_") for tp_name in names]))) + def get_unwrapper(self): + names = self.argnames + argtypesw = zip(self.argtypes, + [_name.startswith("w_") for _name in self.argnames]) + types_names_enum_ui = unrolling_iterable(enumerate(argtypesw)) @specialize.ll() def unwrapper(space, *args): - from pypy.module.cpyext.pyobject import Py_DecRef, is_pyobj + from pypy.module.cpyext.pyobject import is_pyobj from pypy.module.cpyext.pyobject import from_ref, as_pyobj newargs = () keepalives = () - assert len(args) == len(api_function.argtypes) + assert len(args) == len(self.argtypes) for i, (ARG, is_wrapped) in types_names_enum_ui: input_arg = args[i] if is_PyObject(ARG) and not is_wrapped: @@ -416,33 +369,81 @@ arg = from_ref(space, input_arg) else: arg = input_arg - - ## ZZZ: for is_pyobj: - ## try: - ## arg = from_ref(space, - ## rffi.cast(PyObject, input_arg)) - ## except TypeError, e: - ## err = oefmt(space.w_TypeError, - ## "could not cast arg to PyObject") - ## if not catch_exception: - ## raise err - ## state = space.fromcache(State) - ## state.set_exception(err) - ## if is_PyObject(restype): - ## return None - ## else: - ## return api_function.error_value else: # arg is not declared as PyObject, no magic arg = input_arg newargs += (arg, ) try: - return func(space, *newargs) + return self.callable(space, *newargs) finally: keepalive_until_here(*keepalives) + return unwrapper - unwrapper.func = func - unwrapper.api_func = api_function + def get_c_restype(self, c_writer): + return c_writer.gettype(self.restype).replace('@', '').strip() + + def get_c_args(self, c_writer): + args = [] + for i, argtype in enumerate(self.argtypes): + if argtype is CONST_STRING: + arg = 'const char *@' + elif argtype is CONST_STRINGP: + arg = 'const char **@' + elif argtype is CONST_WSTRING: + arg = 'const wchar_t *@' + else: + arg = c_writer.gettype(argtype) + arg = arg.replace('@', 'arg%d' % (i,)).strip() + args.append(arg) + args = ', '.join(args) or "void" + return args + + def get_api_decl(self, name, c_writer): + restype = self.get_c_restype(c_writer) + args = self.get_c_args(c_writer) + return "PyAPI_FUNC({restype}) {name}({args});".format(**locals()) + + def get_ptr_decl(self, name, c_writer): + restype = self.get_c_restype(c_writer) + args = self.get_c_args(c_writer) + return "{restype} (*{name})({args});".format(**locals()) + + def get_ctypes_impl(self, name, c_writer): + restype = self.get_c_restype(c_writer) + args = self.get_c_args(c_writer) + callargs = ', '.join('arg%d' % (i,) + for i in range(len(self.argtypes))) + if self.restype is lltype.Void: + body = "{ _pypyAPI.%s(%s); }" % (name, callargs) + else: + body = "{ return _pypyAPI.%s(%s); }" % (name, callargs) + return '%s %s(%s)\n%s' % (restype, name, args, body) + + +DEFAULT_HEADER = 'pypy_decl.h' +def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header=DEFAULT_HEADER, + gil=None, result_borrowed=False, result_is_ll=False): + """ + Declares a function to be exported. + - `argtypes`, `restype` are lltypes and describe the function signature. + - `error` is the value returned when an applevel exception is raised. The + special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual + exception into a wrapped SystemError. Unwrapped exceptions also cause a + SytemError. + - `header` is the header file to export the function in. + - set `gil` to "acquire", "release" or "around" to acquire the GIL, + release the GIL, or both + """ + assert header is not None + def decorate(func): + if func.__name__ in FUNCTIONS_BY_HEADER[header]: + raise ValueError("%s already registered" % func.__name__) + func._always_inline_ = 'try' + api_function = ApiFunction( + argtypes, restype, func, + error=_compute_error(error, restype), gil=gil, + result_borrowed=result_borrowed, result_is_ll=result_is_ll) + FUNCTIONS_BY_HEADER[header][func.__name__] = api_function # ZZZ is this whole logic really needed??? It seems to be only # for RPython code calling PyXxx() functions directly. I would @@ -452,25 +453,61 @@ try: res = unwrapper(space, *args) except OperationError as e: - if not hasattr(api_function, "error_value"): + if not hasattr(unwrapper.api_func, "error_value"): raise state = space.fromcache(State) state.set_exception(e) if is_PyObject(restype): return None else: - return api_function.error_value + return unwrapper.api_func.error_value got_integer = isinstance(res, (int, long, float)) + if isinstance(restype, lltype.Typedef): + real_restype = restype.OF + else: + real_restype = restype + expect_integer = (isinstance(real_restype, lltype.Primitive) and + rffi.cast(restype, 0) == 0) assert got_integer == expect_integer, ( 'got %r not integer' % (res,)) return res + INTERPLEVEL_API[func.__name__] = unwrapper_catch # used in tests - if header is not None: - FUNCTIONS_BY_HEADER[header][func_name] = api_function - INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests - return unwrapper # used in 'normal' RPython code. + unwrapper = api_function.get_unwrapper() + unwrapper.func = func + unwrapper.api_func = api_function + return unwrapper return decorate +def slot_function(argtypes, restype, error=_NOT_SPECIFIED): + def decorate(func): + func._always_inline_ = 'try' + api_function = ApiFunction( + argtypes, restype, func, + error=_compute_error(error, restype), + c_name=func.__name__) + unwrapper = api_function.get_unwrapper() + unwrapper.func = func + unwrapper.api_func = api_function + return unwrapper + return decorate + +def _compute_error(error, restype): + """Convert error specification to actual error value of type restype.""" + if isinstance(restype, lltype.Typedef): + real_restype = restype.OF + else: + real_restype = restype + if error is _NOT_SPECIFIED: + if isinstance(real_restype, lltype.Ptr): + error = lltype.nullptr(real_restype.TO) + elif real_restype is lltype.Void: + error = CANNOT_FAIL + if type(error) is int: + error = rffi.cast(real_restype, error) + return error + + def cpython_struct(name, fields, forward=None, level=1): configname = name.replace(' ', '__') if level == 1: @@ -981,23 +1018,6 @@ for func in BOOTSTRAP_FUNCTIONS: func(space) -def c_function_signature(db, func): - restype = db.gettype(func.restype).replace('@', '').strip() - args = [] - for i, argtype in enumerate(func.argtypes): - if argtype is CONST_STRING: - arg = 'const char *@' - elif argtype is CONST_STRINGP: - arg = 'const char **@' - elif argtype is CONST_WSTRING: - arg = 'const wchar_t *@' - else: - arg = db.gettype(argtype) - arg = arg.replace('@', 'arg%d' % (i,)).strip() - args.append(arg) - args = ', '.join(args) or "void" - return restype, args - #_____________________________________________________ # Build the bridge DLL, Allow extension DLLs to call # back into Pypy space functions @@ -1017,15 +1037,8 @@ structindex = {} for header, header_functions in FUNCTIONS_BY_HEADER.iteritems(): for name, func in header_functions.iteritems(): - restype, args = c_function_signature(db, func) - callargs = ', '.join('arg%d' % (i,) - for i in range(len(func.argtypes))) - if func.restype is lltype.Void: - body = "{ _pypyAPI.%s(%s); }" % (name, callargs) - else: - body = "{ return _pypyAPI.%s(%s); }" % (name, callargs) - functions.append('%s %s(%s)\n%s' % (restype, name, args, body)) - members.append('%s (*%s)(%s);' % (restype, name, args)) + functions.append(func.get_ctypes_impl(name, db)) + members.append(func.get_ptr_decl(name, db)) structindex[name] = len(structindex) structmembers = '\n'.join(members) struct_declaration_code = """\ @@ -1220,8 +1233,7 @@ for name, func in sorted(header_functions.iteritems()): _name = mangle_name(prefix, name) header.append("#define %s %s" % (name, _name)) - restype, args = c_function_signature(db, func) - header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args)) + header.append(func.get_api_decl(name, db)) for name, (typ, expr) in GLOBALS.iteritems(): if '#' in name: diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py --- a/pypy/module/cpyext/bytesobject.py +++ b/pypy/module/cpyext/bytesobject.py @@ -2,7 +2,7 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, build_type_checkers, - PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL) + PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL, slot_function) from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, @@ -25,14 +25,14 @@ ## ## In the PyBytesObject returned, the ob_sval buffer may be modified as ## long as the freshly allocated PyBytesObject is not "forced" via a call -## to any of the more sophisticated C-API functions. +## to any of the more sophisticated C-API functions. ## ## Care has been taken in implementing the functions below, so that -## if they are called with a non-forced PyBytesObject, they will not +## if they are called with a non-forced PyBytesObject, they will not ## unintentionally force the creation of a RPython object. As long as only these ## are used, the ob_sval buffer is still modifiable: -## -## PyBytes_AsString / PyString_AsString +## +## PyBytes_AsString / PyString_AsString ## PyBytes_AS_STRING / PyString_AS_STRING ## PyBytes_AsStringAndSize / PyString_AsStringAndSize ## PyBytes_Size / PyString_Size @@ -40,7 +40,7 @@ ## _PyBytes_Resize / _PyString_Resize (raises if called with a forced object) ## ## - There could be an (expensive!) check in from_ref() that the buffer still -## corresponds to the pypy gc-managed string, +## corresponds to the pypy gc-managed string, ## PyBytesObjectStruct = lltype.ForwardReference() @@ -105,7 +105,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def bytes_dealloc(space, py_obj): """Frees allocated PyBytesObject resources. """ diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py --- a/pypy/module/cpyext/dictobject.py +++ b/pypy/module/cpyext/dictobject.py @@ -6,8 +6,8 @@ from pypy.module.cpyext.api import ( cpython_api, CANNOT_FAIL, build_type_checkers, Py_ssize_t, Py_ssize_tP, CONST_STRING, PyObjectFields, cpython_struct, - bootstrap_function) -from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, as_pyobj, + bootstrap_function, slot_function) +from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, as_pyobj, make_typedescr, track_reference, create_ref, from_ref, decref, Py_IncRef) from pypy.module.cpyext.object import _dealloc @@ -36,7 +36,7 @@ py_dict.c__tmpkeys = lltype.nullptr(PyObject.TO) # Problems: if this dict is a typedict, we may have unbound GetSetProperty # functions in the dict. The corresponding PyGetSetDescrObject must be - # bound to a class, but the actual w_type will be unavailable later on. + # bound to a class, but the actual w_type will be unavailable later on. # Solution: use the w_userdata argument when assigning a PyTypeObject's # tp_dict slot to pass a w_type in, and force creation of the pair here if not space.is_w(w_userdata, space.gettypefor(GetSetProperty)): @@ -55,7 +55,7 @@ w_obj = space.newdict() track_reference(space, py_obj, w_obj) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def dict_dealloc(space, py_obj): py_dict = rffi.cast(PyDictObject, py_obj) decref(space, py_dict.c__tmpkeys) diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py --- a/pypy/module/cpyext/frameobject.py +++ b/pypy/module/cpyext/frameobject.py @@ -1,7 +1,7 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, bootstrap_function, PyObjectFields, cpython_struct, - CANNOT_FAIL) + CANNOT_FAIL, slot_function) from pypy.module.cpyext.pyobject import ( PyObject, Py_DecRef, make_ref, from_ref, track_reference, make_typedescr, get_typedescr) @@ -39,7 +39,7 @@ py_frame.c_f_locals = make_ref(space, frame.get_w_locals()) rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def frame_dealloc(space, py_obj): py_frame = rffi.cast(PyFrameObject, py_obj) py_code = rffi.cast(PyObject, py_frame.c_f_code) diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py --- a/pypy/module/cpyext/funcobject.py +++ b/pypy/module/cpyext/funcobject.py @@ -1,7 +1,8 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t, - cpython_api, bootstrap_function, cpython_struct, build_type_checkers) + cpython_api, bootstrap_function, cpython_struct, build_type_checkers, + slot_function) from pypy.module.cpyext.pyobject import ( PyObject, make_ref, from_ref, Py_DecRef, make_typedescr) from rpython.rlib.unroll import unrolling_iterable @@ -56,7 +57,7 @@ assert isinstance(w_obj, Function) py_func.c_func_name = make_ref(space, space.wrap(w_obj.name)) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def function_dealloc(space, py_obj): py_func = rffi.cast(PyFunctionObject, py_obj) Py_DecRef(space, py_func.c_func_name) @@ -75,7 +76,7 @@ rffi.setintfield(py_code, 'c_co_flags', co_flags) rffi.setintfield(py_code, 'c_co_argcount', w_obj.co_argcount) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def code_dealloc(space, py_obj): py_code = rffi.cast(PyCodeObject, py_obj) Py_DecRef(space, py_code.c_co_name) diff --git a/pypy/module/cpyext/memoryobject.py b/pypy/module/cpyext/memoryobject.py --- a/pypy/module/cpyext/memoryobject.py +++ b/pypy/module/cpyext/memoryobject.py @@ -1,10 +1,10 @@ -from pypy.module.cpyext.api import (cpython_api, Py_buffer, CANNOT_FAIL, - Py_MAX_FMT, Py_MAX_NDIMS, build_type_checkers, - Py_ssize_tP, PyObjectFields, cpython_struct, - generic_cpy_call, - bootstrap_function, Py_bufferP) -from pypy.module.cpyext.pyobject import (PyObject, make_ref, as_pyobj, incref, - decref, from_ref, make_typedescr) +from pypy.module.cpyext.api import ( + cpython_api, Py_buffer, CANNOT_FAIL, Py_MAX_FMT, Py_MAX_NDIMS, + build_type_checkers, Py_ssize_tP, PyObjectFields, cpython_struct, + bootstrap_function, Py_bufferP, generic_cpy_call, slot_function) +from pypy.module.cpyext.pyobject import ( + PyObject, make_ref, as_pyobj, incref, decref, from_ref, make_typedescr, + get_typedescr, track_reference) from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rlib.rarithmetic import widen from pypy.interpreter.error import oefmt @@ -30,7 +30,7 @@ basestruct=PyMemoryViewObject.TO, attach=memory_attach, dealloc=memory_dealloc, - #realize=memory_realize, + realize=memory_realize, ) def memory_attach(space, py_obj, w_obj, w_userdata=None): @@ -56,13 +56,37 @@ track_allocation=False)) rffi.setintfield(view, 'c_readonly', 1) -def memory_realize(space, py_obj): +def memory_realize(space, obj): """ Creates the memory object in the interpreter """ - raise oefmt(space.w_NotImplementedError, "cannot call this yet") + from pypy.module.cpyext.slotdefs import CPyBuffer, fq + py_mem = rffi.cast(PyMemoryViewObject, obj) + view = py_mem.c_view + ndim = widen(view.c_ndim) + shape = None + if view.c_shape: + shape = [view.c_shape[i] for i in range(ndim)] + strides = None + if view.c_strides: + strides = [view.c_strides[i] for i in range(ndim)] + format = 'B' + if view.c_format: + format = rffi.charp2str(view.c_format) + buf = CPyBuffer(space, view.c_buf, view.c_len, from_ref(space, view.c_obj), + format=format, shape=shape, strides=strides, + ndim=ndim, itemsize=view.c_itemsize, + readonly=widen(view.c_readonly)) + # Ensure view.c_buf is released upon object finalization + fq.register_finalizer(buf) + # Allow subclassing W_MemeoryView + w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type)) + w_obj = space.allocate_instance(W_MemoryView, w_type) + w_obj.__init__(buf) + track_reference(space, obj, w_obj) + return w_obj -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def memory_dealloc(space, py_obj): mem_obj = rffi.cast(PyMemoryViewObject, py_obj) if mem_obj.c_view.c_obj: @@ -199,17 +223,41 @@ py_memview = make_ref(space, w_memview, w_obj) return py_memview -@cpython_api([Py_bufferP], PyObject) +@cpython_api([Py_bufferP], PyObject, result_is_ll=True) def PyMemoryView_FromBuffer(space, view): """Create a memoryview object wrapping the given buffer structure view. The memoryview object then owns the buffer represented by view, which means you shouldn't try to call PyBuffer_Release() yourself: it will be done on deallocation of the memoryview object.""" - assert view.c_obj - w_obj = from_ref(space, view.c_obj) - if isinstance(w_obj, W_MemoryView): - return w_obj - return space.call_method(space.builtin, "memoryview", w_obj) + # XXX this should allocate a PyMemoryViewObject and + # copy view into obj.c_view, without creating a new view.c_obj + typedescr = get_typedescr(W_MemoryView.typedef) + py_obj = typedescr.allocate(space, space.w_memoryview) + py_mem = rffi.cast(PyMemoryViewObject, py_obj) + mview = py_mem.c_view + mview.c_buf = view.c_buf + mview.c_obj = view.c_obj + mview.c_len = view.c_len + mview.c_itemsize = view.c_itemsize + mview.c_readonly = view.c_readonly + mview.c_ndim = view.c_ndim + mview.c_format = view.c_format + if view.c_strides == rffi.cast(Py_ssize_tP, view.c__strides): + py_mem.c_view.c_strides = rffi.cast(Py_ssize_tP, py_mem.c_view.c__strides) + for i in range(view.c_ndim): + py_mem.c_view.c_strides[i] = view.c_strides[i] + else: + # some externally allocated memory chunk + py_mem.c_view.c_strides = view.c_strides + if view.c_shape == rffi.cast(Py_ssize_tP, view.c__shape): + py_mem.c_view.c_shape = rffi.cast(Py_ssize_tP, py_mem.c_view.c__shape) + for i in range(view.c_ndim): + py_mem.c_view.c_shape[i] = view.c_shape[i] + else: + # some externally allocated memory chunk + py_mem.c_view.c_shape = view.c_shape + # XXX ignore suboffsets? + return py_obj @cpython_api([PyObject], PyObject) def PyMemoryView_GET_BASE(space, w_obj): diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -11,7 +11,7 @@ CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O, METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function, build_type_checkers, cpython_api, cpython_struct, generic_cpy_call, - PyTypeObjectPtr) + PyTypeObjectPtr, slot_function) from pypy.module.cpyext.pyobject import ( Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr) @@ -51,7 +51,7 @@ py_func.c_m_self = make_ref(space, w_obj.w_self) py_func.c_m_module = make_ref(space, w_obj.w_module) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def cfunction_dealloc(space, py_obj): py_func = rffi.cast(PyCFunctionObject, py_obj) Py_DecRef(space, py_func.c_m_self) diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py --- a/pypy/module/cpyext/object.py +++ b/pypy/module/cpyext/object.py @@ -1,7 +1,8 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, - PyVarObject, Py_buffer, size_t, + PyVarObject, Py_buffer, size_t, slot_function, + PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES, Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite) from pypy.module.cpyext.pyobject import ( @@ -58,7 +59,7 @@ w_obj = PyObject_InitVar(space, py_objvar, type, itemcount) return py_obj -@cpython_api([PyObject], lltype.Void) +@slot_function([PyObject], lltype.Void) def PyObject_dealloc(space, obj): return _dealloc(space, obj) @@ -489,22 +490,28 @@ Fills in a buffer-info structure correctly for an exporter that can only share a contiguous chunk of memory of "unsigned bytes" of the given length. Returns 0 on success and -1 (with raising an error) on error. - - This is not a complete re-implementation of the CPython API; it only - provides a subset of CPython's behavior. """ if rffi.cast(lltype.Signed, flags) & PyBUF_WRITABLE and readonly: raise oefmt(space.w_ValueError, "Object is not writable") view.c_buf = buf view.c_len = length view.c_obj = obj - Py_IncRef(space, obj) + if obj: + Py_IncRef(space, obj) view.c_itemsize = 1 rffi.setintfield(view, 'c_readonly', readonly) - rffi.setintfield(view, 'c_ndim', 0) + rffi.setintfield(view, 'c_ndim', 1) view.c_format = lltype.nullptr(rffi.CCHARP.TO) + if (flags & PyBUF_FORMAT) == PyBUF_FORMAT: + view.c_format = rffi.str2charp("B") view.c_shape = lltype.nullptr(Py_ssize_tP.TO) + if (flags & PyBUF_ND) == PyBUF_ND: + view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape) + view.c_shape[0] = view.c_len view.c_strides = lltype.nullptr(Py_ssize_tP.TO) + if (flags & PyBUF_STRIDES) == PyBUF_STRIDES: + view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides) + view.c_strides[0] = view.c_itemsize view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO) view.c_internal = lltype.nullptr(rffi.VOIDP.TO) diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -87,7 +87,7 @@ alloc : allocate and basic initialization of a raw PyObject attach : Function called to tie a raw structure to a pypy object realize : Function called to create a pypy object from a raw struct - dealloc : a cpython_api(header=None), similar to PyObject_dealloc + dealloc : a @slot_function(), similar to PyObject_dealloc """ tp_basestruct = kw.pop('basestruct', PyObject.TO) diff --git a/pypy/module/cpyext/pytraceback.py b/pypy/module/cpyext/pytraceback.py --- a/pypy/module/cpyext/pytraceback.py +++ b/pypy/module/cpyext/pytraceback.py @@ -1,7 +1,8 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t, - cpython_api, bootstrap_function, cpython_struct, build_type_checkers) + cpython_api, bootstrap_function, cpython_struct, build_type_checkers, + slot_function) from pypy.module.cpyext.pyobject import ( PyObject, make_ref, from_ref, Py_DecRef, make_typedescr) from pypy.module.cpyext.frameobject import PyFrameObject @@ -40,7 +41,7 @@ rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti) rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno()) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def traceback_dealloc(space, py_obj): py_traceback = rffi.cast(PyTracebackObject, py_obj) Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next)) diff --git a/pypy/module/cpyext/sliceobject.py b/pypy/module/cpyext/sliceobject.py --- a/pypy/module/cpyext/sliceobject.py +++ b/pypy/module/cpyext/sliceobject.py @@ -1,7 +1,7 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, build_type_checkers, - CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, PyObjectFields) + CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, PyObjectFields, slot_function) from pypy.module.cpyext.pyobject import ( Py_DecRef, PyObject, make_ref, make_typedescr) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall @@ -36,7 +36,7 @@ py_slice.c_stop = make_ref(space, w_obj.w_stop) py_slice.c_step = make_ref(space, w_obj.w_step) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def slice_dealloc(space, py_obj): """Frees allocated PySliceObject resources. """ diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py --- a/pypy/module/cpyext/slotdefs.py +++ b/pypy/module/cpyext/slotdefs.py @@ -6,7 +6,7 @@ from rpython.rlib.rarithmetic import widen from rpython.rlib import rgc # Force registration of gc.collect from pypy.module.cpyext.api import ( - cpython_api, generic_cpy_call, PyObject, Py_ssize_t, + slot_function, generic_cpy_call, PyObject, Py_ssize_t, pypy_decl, Py_buffer, Py_bufferP) from pypy.module.cpyext.typeobjectdefs import ( unaryfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc, @@ -64,7 +64,7 @@ @not_rpython def llslot(space, func): - return llhelper(func.api_func.functype, func.api_func.get_wrapper(space)) + return func.api_func.get_llhelper(space) @register_flow_sc(llslot) def sc_llslot(ctx, v_space, v_func): @@ -315,7 +315,7 @@ def __init__(self, space, ptr, size, w_obj, format='B', shape=None, strides=None, ndim=1, itemsize=1, readonly=True, - releasebuffer=None): + releasebufferproc=rffi.cast(rffi.VOIDP, 0)): self.space = space self.ptr = ptr self.size = size @@ -333,7 +333,7 @@ self.ndim = ndim self.itemsize = itemsize self.readonly = readonly - self.releasebufferproc = releasebuffer + self.releasebufferproc = releasebufferproc def releasebuffer(self): if self.pyobj: @@ -351,7 +351,10 @@ for i in range(self.ndim): pybuf.c_shape[i] = self.shape[i] pybuf.c_strides[i] = self.strides[i] - pybuf.c_format = rffi.str2charp(self.format) + if self.format: + pybuf.c_format = rffi.str2charp(self.format) + else: + pybuf.c_format = rffi.str2charp("B") generic_cpy_call(self.space, func_target, self.pyobj, pybuf) self.releasebufferproc = rffi.cast(rffi.VOIDP, 0) @@ -398,9 +401,9 @@ func_target = rffi.cast(readbufferproc, func) py_obj = make_ref(space, w_self) py_type = py_obj.c_ob_type - releasebuffer = rffi.cast(rffi.VOIDP, 0) + rbp = rffi.cast(rffi.VOIDP, 0) if py_type.c_tp_as_buffer: - releasebuffer = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer) + rbp = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer) decref(space, py_obj) with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr: index = rffi.cast(Py_ssize_t, 0) @@ -408,7 +411,7 @@ if size < 0: space.fromcache(State).check_and_raise_exception(always=True) buf = CPyBuffer(space, ptr[0], size, w_self, - releasebuffer=releasebuffer) + releasebufferproc=rbp) fq.register_finalizer(buf) return space.newbuffer(buf) @@ -417,16 +420,16 @@ py_obj = make_ref(space, w_self) py_type = py_obj.c_ob_type decref(space, py_obj) - releasebuffer = rffi.cast(rffi.VOIDP, 0) + rbp = rffi.cast(rffi.VOIDP, 0) if py_type.c_tp_as_buffer: - releasebuffer = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer) + rbp = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer) with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr: index = rffi.cast(Py_ssize_t, 0) size = generic_cpy_call(space, func_target, w_self, index, ptr) if size < 0: space.fromcache(State).check_and_raise_exception(always=True) buf = CPyBuffer(space, ptr[0], size, w_self, readonly=False, - releasebuffer=releasebuffer) + releasebufferproc=rbp) fq.register_finalizer(buf) return space.newbuffer(buf) @@ -434,9 +437,9 @@ func_target = rffi.cast(getbufferproc, func) py_obj = make_ref(space, w_self) py_type = py_obj.c_ob_type - releasebuffer = rffi.cast(rffi.VOIDP, 0) + rbp = rffi.cast(rffi.VOIDP, 0) if py_type.c_tp_as_buffer: - releasebuffer = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer) + rbp = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer) decref(space, py_obj) with lltype.scoped_alloc(Py_buffer) as pybuf: _flags = 0 @@ -465,7 +468,7 @@ ndim=ndim, shape=shape, strides=strides, itemsize=pybuf.c_itemsize, readonly=widen(pybuf.c_readonly), - releasebuffer = releasebuffer) + releasebufferproc = rbp) fq.register_finalizer(buf) return space.newbuffer(buf) @@ -515,9 +518,6 @@ def build_slot_tp_function(space, typedef, name): w_type = space.gettypeobject(typedef) - header = pypy_decl - if not (name.startswith('Py') or name.startswith('_Py')): - header = None handled = False # unary functions for tp_name, attr in [('tp_as_number.c_nb_int', '__int__'), @@ -537,7 +537,7 @@ if slot_fn is None: return - @cpython_api([PyObject], PyObject, header=header) + @slot_function([PyObject], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_func(space, w_self): return space.call_function(slot_fn, w_self) @@ -563,7 +563,7 @@ if slot_fn is None: return - @cpython_api([PyObject, PyObject], PyObject, header=header) + @slot_function([PyObject, PyObject], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_func(space, w_self, w_arg): return space.call_function(slot_fn, w_self, w_arg) @@ -580,7 +580,7 @@ if slot_fn is None: return - @cpython_api([PyObject, Py_ssize_t], PyObject, header=header) + @slot_function([PyObject, Py_ssize_t], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_func(space, w_self, arg): return space.call_function(slot_fn, w_self, space.wrap(arg)) @@ -594,7 +594,7 @@ if slot_fn is None: return - @cpython_api([PyObject, PyObject, PyObject], PyObject, header=header) + @slot_function([PyObject, PyObject, PyObject], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_func(space, w_self, w_arg1, w_arg2): return space.call_function(slot_fn, w_self, w_arg1, w_arg2) @@ -608,8 +608,8 @@ if setattr_fn is None: return - @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, header=header) + @slot_function([PyObject, PyObject, PyObject], rffi.INT_real, + error=-1) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: @@ -623,7 +623,7 @@ if getattr_fn is None: return - @cpython_api([PyObject, PyObject], PyObject, header=header) + @slot_function([PyObject, PyObject], PyObject) @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,)) def slot_tp_getattro(space, w_self, w_name): return space.call_function(getattr_fn, w_self, w_name) @@ -634,7 +634,7 @@ if call_fn is None: return - @cpython_api([PyObject, PyObject, PyObject], PyObject, header=header) + @slot_function([PyObject, PyObject, PyObject], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_tp_call(space, w_self, w_args, w_kwds): args = Arguments(space, [w_self], @@ -647,7 +647,7 @@ if iternext_fn is None: return - @cpython_api([PyObject], PyObject, header=header) + @slot_function([PyObject], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_tp_iternext(space, w_self): try: @@ -663,8 +663,7 @@ if init_fn is None: return - @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1, - header=header) + @slot_function([PyObject, PyObject, PyObject], rffi.INT_real, error=-1) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_tp_init(space, w_self, w_args, w_kwds): args = Arguments(space, [w_self], @@ -677,7 +676,7 @@ if new_fn is None: return - @cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, header=None) + @slot_function([PyTypeObjectPtr, PyObject, PyObject], PyObject) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def slot_tp_new(space, w_self, w_args, w_kwds): args = Arguments(space, [w_self], @@ -688,8 +687,8 @@ buff_fn = w_type.getdictvalue(space, '__buffer__') if buff_fn is None: return - @cpython_api([PyObject, Py_bufferP, rffi.INT_real], - rffi.INT_real, header=None, error=-1) + @slot_function([PyObject, Py_bufferP, rffi.INT_real], + rffi.INT_real, error=-1) @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) def buff_w(space, w_self, view, flags): args = Arguments(space, [space.newint(flags)]) diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py --- a/pypy/module/cpyext/test/test_api.py +++ b/pypy/module/cpyext/test/test_api.py @@ -2,20 +2,14 @@ from rpython.rtyper.lltypesystem import lltype from pypy.interpreter.baseobjspace import W_Root from pypy.module.cpyext.state import State -from pypy.module.cpyext import api +from pypy.module.cpyext.api import ( + slot_function, cpython_api, copy_header_files, INTERPLEVEL_API, + Py_ssize_t, Py_ssize_tP, PyObject) from pypy.module.cpyext.test.test_cpyext import freeze_refcnts, LeakCheckingTest -PyObject = api.PyObject from pypy.interpreter.error import OperationError from rpython.rlib import rawrefcount import os -@api.cpython_api([PyObject], lltype.Void) -def PyPy_GetWrapped(space, w_arg): - assert isinstance(w_arg, W_Root) -@api.cpython_api([PyObject], lltype.Void) -def PyPy_GetReference(space, arg): - assert lltype.typeOf(arg) == PyObject - class BaseApiTest(LeakCheckingTest): def setup_class(cls): space = cls.space @@ -35,7 +29,7 @@ def __getattr__(self, name): return getattr(cls.space, name) cls.api = CAPI() - CAPI.__dict__.update(api.INTERPLEVEL_API) + CAPI.__dict__.update(INTERPLEVEL_API) print 'DONT_FREE_ANY_MORE' rawrefcount._dont_free_any_more() @@ -71,31 +65,39 @@ if self.check_and_print_leaks(): assert False, "Test leaks or loses object(s)." -@api.cpython_api([api.Py_ssize_t], api.Py_ssize_t, error=-1) +@slot_function([PyObject], lltype.Void) +def PyPy_GetWrapped(space, w_arg): + assert isinstance(w_arg, W_Root) + +@slot_function([PyObject], lltype.Void) +def PyPy_GetReference(space, arg): + assert lltype.typeOf(arg) == PyObject + +@cpython_api([Py_ssize_t], Py_ssize_t, error=-1) def PyPy_TypedefTest1(space, arg): - assert lltype.typeOf(arg) == api.Py_ssize_t + assert lltype.typeOf(arg) == Py_ssize_t return 0 -@api.cpython_api([api.Py_ssize_tP], api.Py_ssize_tP) +@cpython_api([Py_ssize_tP], Py_ssize_tP) def PyPy_TypedefTest2(space, arg): - assert lltype.typeOf(arg) == api.Py_ssize_tP + assert lltype.typeOf(arg) == Py_ssize_tP return None class TestConversion(BaseApiTest): - def test_conversions(self, space, api): - api.PyPy_GetWrapped(space.w_None) - api.PyPy_GetReference(space.w_None) + def test_conversions(self, space): + PyPy_GetWrapped(space, space.w_None) + PyPy_GetReference(space, space.w_None) def test_typedef(self, space): from rpython.translator.c.database import LowLevelDatabase db = LowLevelDatabase() - assert (api.c_function_signature(db, PyPy_TypedefTest1.api_func) - == ('Py_ssize_t', 'Py_ssize_t arg0')) - assert (api.c_function_signature(db, PyPy_TypedefTest2.api_func) - == ('Py_ssize_t *', 'Py_ssize_t *arg0')) + assert PyPy_TypedefTest1.api_func.get_c_restype(db) == 'Py_ssize_t' + assert PyPy_TypedefTest1.api_func.get_c_args(db) == 'Py_ssize_t arg0' + assert PyPy_TypedefTest2.api_func.get_c_restype(db) == 'Py_ssize_t *' + assert PyPy_TypedefTest2.api_func.get_c_args(db) == 'Py_ssize_t *arg0' PyPy_TypedefTest1(space, 0) - ppos = lltype.malloc(api.Py_ssize_tP.TO, 1, flavor='raw') + ppos = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') ppos[0] = 0 PyPy_TypedefTest2(space, ppos) lltype.free(ppos, flavor='raw') @@ -103,7 +105,7 @@ @pytest.mark.skipif(os.environ.get('USER')=='root', reason='root can write to all files') def test_copy_header_files(tmpdir): - api.copy_header_files(tmpdir, True) + copy_header_files(tmpdir, True) def check(name): f = tmpdir.join(name) assert f.check(file=True) diff --git a/pypy/module/cpyext/test/test_memoryobject.py b/pypy/module/cpyext/test/test_memoryobject.py --- a/pypy/module/cpyext/test/test_memoryobject.py +++ b/pypy/module/cpyext/test/test_memoryobject.py @@ -30,7 +30,7 @@ assert view.c_len == 5 o = rffi.charp2str(view.c_buf) assert o == 'hello' - w_mv = api.PyMemoryView_FromBuffer(view) + w_mv = from_ref(space, api.PyMemoryView_FromBuffer(view)) for f in ('format', 'itemsize', 'ndim', 'readonly', 'shape', 'strides', 'suboffsets'): w_f = space.wrap(f) @@ -43,6 +43,7 @@ ("fillinfo", "METH_VARARGS", """ Py_buffer buf; + PyObject * ret = NULL; PyObject *str = PyBytes_FromString("hello, world."); if (PyBuffer_FillInfo(&buf, str, PyBytes_AsString(str), 13, 0, 0)) { @@ -54,7 +55,14 @@ */ Py_DECREF(str); - return PyMemoryView_FromBuffer(&buf); + ret = PyMemoryView_FromBuffer(&buf); + if (((PyMemoryViewObject*)ret)->view.obj != buf.obj) + { + PyErr_SetString(PyExc_ValueError, "leaked ref"); + Py_DECREF(ret); + return NULL; + } + return ret; """)]) result = module.fillinfo() assert b"hello, world." == result diff --git a/pypy/module/cpyext/test/test_translate.py b/pypy/module/cpyext/test/test_translate.py --- a/pypy/module/cpyext/test/test_translate.py +++ b/pypy/module/cpyext/test/test_translate.py @@ -1,6 +1,6 @@ from rpython.translator.c.test.test_genc import compile import pypy.module.cpyext.api -from pypy.module.cpyext.api import cpython_api +from pypy.module.cpyext.api import slot_function from rpython.rtyper.annlowlevel import llhelper from rpython.rtyper.lltypesystem import lltype from rpython.rlib.objectmodel import specialize @@ -19,7 +19,7 @@ @specialize.memo() def get_tp_function(space, typedef): - @cpython_api([], lltype.Signed, error=-1, header=None) + @slot_function([], lltype.Signed, error=-1) def slot_tp_function(space): return typedef.value diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -1,11 +1,11 @@ from pypy.interpreter.error import oefmt from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.debug import fatalerror_notb -from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, - build_type_checkers, PyVarObjectFields, - cpython_struct, bootstrap_function) -from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef, - make_ref, from_ref, decref, incref, pyobj_has_w_obj, +from pypy.module.cpyext.api import ( + cpython_api, Py_ssize_t, build_type_checkers, + PyVarObjectFields, cpython_struct, bootstrap_function, slot_function) +from pypy.module.cpyext.pyobject import ( + PyObject, PyObjectP, make_ref, from_ref, decref, incref, track_reference, make_typedescr, get_typedescr) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.tupleobject import W_TupleObject @@ -74,7 +74,7 @@ if py_tup.c_ob_size < length: raise oefmt(space.w_ValueError, "tuple_attach called on object with ob_size %d but trying to store %d", - py_tup.c_ob_size, length) + py_tup.c_ob_size, length) i = 0 try: while i < length: @@ -113,7 +113,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def tuple_dealloc(space, py_obj): """Frees allocated PyTupleObject resources. """ 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 @@ -2,21 +2,20 @@ from rpython.rlib import jit from rpython.rlib.objectmodel import specialize -from rpython.rlib.rstring import rsplit from rpython.rtyper.lltypesystem import rffi, lltype from pypy.interpreter.baseobjspace import W_Root, DescrMismatch from pypy.interpreter.error import oefmt -from pypy.interpreter.typedef import (GetSetProperty, TypeDef, - interp_attrproperty, interp_attrproperty, interp2app) +from pypy.interpreter.typedef import ( + GetSetProperty, TypeDef, interp_attrproperty, interp2app) from pypy.module.__builtin__.abstractinst import abstract_issubclass_w from pypy.module.cpyext import structmemberdefs from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP, - generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, Py_buffer, + slot_function, generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, Py_buffer, Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL, - Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder, - PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr, + Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, + PyObjectFields, PyTypeObject, PyTypeObjectPtr, Py_TPFLAGS_HAVE_INPLACEOPS) from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject, W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef, @@ -345,7 +344,7 @@ if pto.c_tp_new: add_tp_new_wrapper(space, dict_w, pto) -@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None) +@slot_function([PyObject, PyObject, PyObject], PyObject) def tp_new_wrapper(space, self, w_args, w_kwds): self_pytype = rffi.cast(PyTypeObjectPtr, self) tp_new = self_pytype.c_tp_new @@ -504,7 +503,7 @@ realize=type_realize, dealloc=type_dealloc) -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def subtype_dealloc(space, obj): pto = obj.c_ob_type base = pto @@ -519,8 +518,7 @@ # hopefully this does not clash with the memory model assumed in # extension modules -@cpython_api([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real, - header=None, error=-1) +@slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real, error=-1) def bytes_getbuffer(space, w_str, view, flags): from pypy.module.cpyext.bytesobject import PyBytes_AsString from pypy.module.cpyext.object import PyBuffer_FillInfo @@ -528,8 +526,7 @@ return PyBuffer_FillInfo(space, view, w_str, c_buf, space.len_w(w_str), 1, flags) -@cpython_api([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real, - header=None, error=-1) +@slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real, error=-1) def bf_getbuffer(space, w_obj, view, flags): from pypy.module.cpyext.object import PyBuffer_FillInfo buf = space.buffer_w(w_obj, rffi.cast(lltype.Signed, flags)) @@ -550,7 +547,7 @@ pto.c_tp_as_buffer = c_buf pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def type_dealloc(space, obj): from pypy.module.cpyext.object import _dealloc obj_pto = rffi.cast(PyTypeObjectPtr, obj) 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 @@ -4,7 +4,7 @@ from pypy.module.cpyext.api import ( CANNOT_FAIL, Py_ssize_t, build_type_checkers, cpython_api, bootstrap_function, PyObjectFields, cpython_struct, CONST_STRING, - CONST_WSTRING, Py_CLEANUP_SUPPORTED) + CONST_WSTRING, Py_CLEANUP_SUPPORTED, slot_function) from pypy.module.cpyext.pyerrors import PyErr_BadArgument from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, @@ -78,7 +78,7 @@ track_reference(space, py_obj, w_obj) return w_obj -@cpython_api([PyObject], lltype.Void, header=None) +@slot_function([PyObject], lltype.Void) def unicode_dealloc(space, py_obj): py_unicode = rffi.cast(PyUnicodeObject, py_obj) if py_unicode.c_buffer: diff --git a/rpython/rlib/test/test_rposix_stat.py b/rpython/rlib/test/test_rposix_stat.py --- a/rpython/rlib/test/test_rposix_stat.py +++ b/rpython/rlib/test/test_rposix_stat.py @@ -29,7 +29,10 @@ check(os.environ['TEMP']) else: check('/') - check('/tmp') + check('/dev') + # don't test with /tmp, because if another process is also + # creating files in /tmp it is more likely that the mtime + # we get during successive calls was actually changed check(sys.executable) def test_fstat(self): diff --git a/rpython/rlib/unicodedata/test/test_unicodedata.py b/rpython/rlib/unicodedata/test/test_unicodedata.py --- a/rpython/rlib/unicodedata/test/test_unicodedata.py +++ b/rpython/rlib/unicodedata/test/test_unicodedata.py @@ -5,7 +5,8 @@ import py from rpython.rlib.unicodedata import ( - unicodedb_3_2_0, unicodedb_5_2_0, unicodedb_6_0_0, unicodedb_6_2_0) + unicodedb_3_2_0, unicodedb_5_2_0, unicodedb_6_0_0, unicodedb_6_2_0, + unicodedb_8_0_0) class TestUnicodeData(object): @@ -141,3 +142,9 @@ def test_islower(self): assert unicodedb_6_2_0.islower(0x2177) + + +class TestUnicodeData800(object): + def test_changed_in_version_8(self): + assert unicodedb_6_2_0.toupper_full(0x025C) == [0x025C] + assert unicodedb_8_0_0.toupper_full(0x025C) == [0xA7AB] _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit