Author: Matti Picus <matti.pi...@gmail.com> Branch: py3.5 Changeset: r94538:5f017005bd26 Date: 2018-05-12 21:01 +0300 http://bitbucket.org/pypy/pypy/changeset/5f017005bd26/
Log: merge default into py3.5 diff --git a/pypy/doc/config/objspace.usemodules._cppyy.txt b/pypy/doc/config/objspace.usemodules._cppyy.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.usemodules._cppyy.txt @@ -0,0 +1,1 @@ +The internal backend for cppyy diff --git a/pypy/doc/config/objspace.usemodules._rawffi.txt b/pypy/doc/config/objspace.usemodules._rawffi.txt --- a/pypy/doc/config/objspace.usemodules._rawffi.txt +++ b/pypy/doc/config/objspace.usemodules._rawffi.txt @@ -1,3 +1,3 @@ -An experimental module providing very low-level interface to +A module providing very low-level interface to C-level libraries, for use when implementing ctypes, not -intended for a direct use at all. \ No newline at end of file +intended for a direct use at all. diff --git a/pypy/doc/config/objspace.usemodules.cpyext.txt b/pypy/doc/config/objspace.usemodules.cpyext.txt --- a/pypy/doc/config/objspace.usemodules.cpyext.txt +++ b/pypy/doc/config/objspace.usemodules.cpyext.txt @@ -1,1 +1,1 @@ -Use (experimental) cpyext module, that tries to load and run CPython extension modules +Use cpyext module to load and run CPython extension modules diff --git a/pypy/doc/contributing.rst b/pypy/doc/contributing.rst --- a/pypy/doc/contributing.rst +++ b/pypy/doc/contributing.rst @@ -293,7 +293,8 @@ You will need the `build requirements`_ to run tests successfully, since many of them compile little pieces of PyPy and then run the tests inside that minimal -interpreter +interpreter. The `cpyext` tests also require `pycparser`, and many tests build +cases with `hypothesis`. Now on to running some tests. PyPy has many different test directories and you can use shell completion to point at directories or files:: @@ -325,6 +326,24 @@ .. _py.test usage and invocations: http://pytest.org/latest/usage.html#usage .. _`build requirements`: build.html#install-build-time-dependencies +Testing After Translation +^^^^^^^^^^^^^^^^^^^^^^^^^ + +While the usual invocation of `pytest` translates a piece of RPython code and +runs it, we have a test extension to run tests without translation, directly +on the host python. This is very convenient for modules such as `cpyext`, to +compare and contrast test results between CPython and PyPy. Untranslated tests +are invoked by using the `-A` or `--runappdirect` option to `pytest`:: + + python2 pytest.py -A pypy/module/cpyext/test + +where `python2` can be either `python2` or `pypy2`. On the `py3` branch, the +collection phase must be run with `python2` so untranslated tests are run +with:: + + cpython2 pytest.py -A pypy/module/cpyext/test --python=path/to/pypy3 + + Tooling & Utilities ^^^^^^^^^^^^^^^^^^^ diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -41,7 +41,7 @@ ---------- .. toctree:: - :maxdepth: 1 + :maxdepth: 2 cpython_differences extending @@ -56,7 +56,7 @@ ----------- .. toctree:: - :maxdepth: 1 + :maxdepth: 2 contributing architecture diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -529,7 +529,8 @@ def visit_kwonly(self, typ): raise FastFuncNotSupported - + + @staticmethod def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) @@ -560,7 +561,6 @@ exec compile2(source) in unwrap_info.miniglobals, d fastfunc = d['fastfunc_%s_%d' % (func.__name__.replace('-', '_'), narg)] return narg, fastfunc - make_fastfunc = staticmethod(make_fastfunc) def int_unwrapping_space_method(typ): diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -27,10 +27,9 @@ @unwrap_spec(code=int) def chr(space, code): "Return a Unicode string of one character with the given ordinal." - try: - c = UNICHR(code) - except ValueError: + if code < 0 or code > 0x10FFFF: raise oefmt(space.w_ValueError, "chr() arg out of range") + c = UNICHR(code) return space.newunicode(c) def len(space, w_obj): diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -76,6 +76,7 @@ import pypy.module.cpyext.pytraceback import pypy.module.cpyext.methodobject import pypy.module.cpyext.dictproxyobject +import pypy.module.cpyext.marshal import pypy.module.cpyext.genobject import pypy.module.cpyext.namespaceobject 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 @@ -61,7 +61,7 @@ configure_eci = ExternalCompilationInfo( include_dirs=include_dirs, - includes=['Python.h', 'stdarg.h', 'structmember.h'], + includes=['Python.h', 'stdarg.h', 'structmember.h', 'marshal.h'], compile_extra=['-DPy_BUILD_CORE']) class CConfig: @@ -119,6 +119,7 @@ pypy_decl = 'pypy_decl.h' udir.join(pypy_decl).write("/* Will be filled later */\n") udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n") +udir.join('pypy_marshal_decl.h').write("/* Will be filled later */\n") udir.join('pypy_macros.h').write("/* Will be filled later */\n") constant_names = """ @@ -1233,14 +1234,11 @@ global_objects.append('PyTypeObject _PyExc_%s;' % name) global_code = '\n'.join(global_objects) - prologue = ("#include <Python.h>\n" - "#include <structmember.h>\n" + prologue = ("#include <Python.h>\n" + + "#include <structmember.h>\n" + + "#include <marshal.h>\n" + + ("#include <pypy_numpy.h>\n" if use_micronumpy else "") + "#include <src/thread.c>\n") - if use_micronumpy: - prologue = ("#include <Python.h>\n" - "#include <structmember.h>\n" - "#include <pypy_numpy.h>\n" - "#include <src/thread.c>\n") code = (prologue + struct_declaration_code + global_code + diff --git a/pypy/module/cpyext/include/marshal.h b/pypy/module/cpyext/include/marshal.h new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/include/marshal.h @@ -0,0 +1,13 @@ +#ifndef Py_MARSHAL_H +#define Py_MARSHAL_H +#ifdef __cplusplus +extern "C" { +#endif + +#define Py_MARSHAL_VERSION 2 +#include "pypy_marshal_decl.h" + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MARSHAL_H */ diff --git a/pypy/module/cpyext/marshal.py b/pypy/module/cpyext/marshal.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/marshal.py @@ -0,0 +1,17 @@ +from rpython.rtyper.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import cpython_api, Py_ssize_t +from pypy.module.cpyext.pyobject import PyObject + + +_HEADER = 'pypy_marshal_decl.h' + +@cpython_api([rffi.CCHARP, Py_ssize_t], PyObject, header=_HEADER) +def PyMarshal_ReadObjectFromString(space, p, size): + from pypy.module.marshal.interp_marshal import loads + s = rffi.charpsize2str(p, size) + return loads(space, space.newbytes(s)) + +@cpython_api([PyObject, rffi.INT_real], PyObject, header=_HEADER) +def PyMarshal_WriteObjectToString(space, w_x, version): + from pypy.module.marshal.interp_marshal import dumps + return dumps(space, w_x, space.newint(version)) 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 @@ -172,6 +172,17 @@ return space.newtext(txtsig) return space.w_None + def fget_module(self, space): + if self.w_module is None: + return space.w_None + return self.w_module + + def fset_module(self, space, w_module): + self.w_module = w_module + + def fdel_module(self, space): + self.w_module = space.w_None + class W_PyCMethodObject(W_PyCFunctionObject): def __init__(self, space, ml, w_type): @@ -333,7 +344,9 @@ __call__ = interp2app(W_PyCFunctionObject.descr_call), __doc__ = GetSetProperty(W_PyCFunctionObject.get_doc), __text_signature__ = GetSetProperty(W_PyCFunctionObject.get_txtsig), - __module__ = interp_attrproperty_w('w_module', cls=W_PyCFunctionObject), + __module__ = GetSetProperty(W_PyCFunctionObject.fget_module, + W_PyCFunctionObject.fset_module, + W_PyCFunctionObject.fdel_module), __name__ = interp_attrproperty('name', cls=W_PyCFunctionObject, wrapfn="newtext_or_none"), ) 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 @@ -12,6 +12,7 @@ from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.bytesobject import invoke_bytes_method from pypy.interpreter.error import OperationError, oefmt +from pypy.interpreter.executioncontext import ExecutionContext import pypy.module.__builtin__.operation as operation @@ -420,3 +421,27 @@ def _PyPyGC_AddMemoryPressure(space, report): from rpython.rlib import rgc rgc.add_memory_pressure(report) + + +ExecutionContext.cpyext_recursive_repr = None + +@cpython_api([PyObject], rffi.INT_real, error=-1) +def Py_ReprEnter(space, w_obj): + ec = space.getexecutioncontext() + d = ec.cpyext_recursive_repr + if d is None: + d = ec.cpyext_recursive_repr = {} + if w_obj in d: + return 1 + d[w_obj] = None + return 0 + +@cpython_api([PyObject], lltype.Void) +def Py_ReprLeave(space, w_obj): + ec = space.getexecutioncontext() + d = ec.cpyext_recursive_repr + if d is not None: + try: + del d[w_obj] + except KeyError: + pass diff --git a/pypy/module/cpyext/test/test_marshal.py b/pypy/module/cpyext/test/test_marshal.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_marshal.py @@ -0,0 +1,33 @@ +from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase + + +class AppTestMarshal(AppTestCpythonExtensionBase): + def test_PyMarshal_ReadObjectFromString(self): + module = self.import_extension('foo', [ + ("mloads", "METH_O", + """ + char *input = PyString_AsString(args); + Py_ssize_t length = PyString_Size(args); + return PyMarshal_ReadObjectFromString(input, length); + """)], + prologue='#include <marshal.h>') + import marshal + assert module.mloads(marshal.dumps(42.5)) == 42.5 + x = [None, True, (4, 5), b"adkj", u"\u1234"] + assert module.mloads(marshal.dumps(x)) == x + + def test_PyMarshal_WriteObjectToString(self): + module = self.import_extension('foo', [ + ("mdumps", "METH_VARARGS", + """ + PyObject *obj; + int version; + if (!PyArg_ParseTuple(args, "Oi", &obj, &version)) + return NULL; + return PyMarshal_WriteObjectToString(obj, version); + """)], + prologue='#include <marshal.h>') + import marshal + for x in [42, b"foo", u"\u2345", (4, None, False)]: + for version in [0, 1, 2]: + assert module.mdumps(x, version) == marshal.dumps(x, version) diff --git a/pypy/module/cpyext/test/test_methodobject.py b/pypy/module/cpyext/test/test_methodobject.py --- a/pypy/module/cpyext/test/test_methodobject.py +++ b/pypy/module/cpyext/test/test_methodobject.py @@ -172,6 +172,20 @@ assert mod.check(A.meth) == 0 assert mod.check(A.stat) == 0 + def test_module_attribute(self): + mod = self.import_extension('MyModule', [ + ('getarg_NO', 'METH_NOARGS', + ''' + Py_INCREF(Py_None); + return Py_None; + ''' + ), + ]) + assert mod.getarg_NO() is None + assert mod.getarg_NO.__module__ == 'MyModule' + mod.getarg_NO.__module__ = 'foobar' + assert mod.getarg_NO.__module__ == 'foobar' + def test_text_signature(self): mod = self.import_module('docstrings') assert mod.no_doc.__doc__ is None diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py --- a/pypy/module/cpyext/test/test_object.py +++ b/pypy/module/cpyext/test/test_object.py @@ -411,6 +411,47 @@ module.foo(35000) assert self.cur_memory_pressure() == 65536 + 80000 + 70000 + def test_repr_enter_leave(self): + module = self.import_extension('foo', [ + ("enter", "METH_O", + """ + return PyInt_FromLong(Py_ReprEnter(args)); + """), + ("leave", "METH_O", + """ + Py_ReprLeave(args); + Py_INCREF(Py_None); + return Py_None; + """)]) + obj1 = [42] + obj2 = [42] # another list + + n = module.enter(obj1) + assert n == 0 + module.leave(obj1) + + n = module.enter(obj1) + assert n == 0 + n = module.enter(obj1) + assert n == 1 + n = module.enter(obj1) + assert n == 1 + module.leave(obj1) + + n = module.enter(obj1) + assert n == 0 + n = module.enter(obj2) + assert n == 0 + n = module.enter(obj1) + assert n == 1 + n = module.enter(obj2) + assert n == 1 + module.leave(obj1) + n = module.enter(obj2) + assert n == 1 + module.leave(obj2) + + class AppTestPyBuffer_FillInfo(AppTestCpythonExtensionBase): """ PyBuffer_FillInfo populates the fields of a Py_buffer from its arguments. diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -688,6 +688,16 @@ assert isinstance(dictvalue(s), annmodel.SomeInteger) assert not dictvalue(s).nonneg + def test_dict_get(self): + def f1(i, j): + d = {i: ''} + return d.get(j) + a = self.RPythonAnnotator() + s = a.build_types(f1, [int, int]) + assert isinstance(s, annmodel.SomeString) + assert s.can_be_None + + def test_exception_deduction(self): a = self.RPythonAnnotator() s = a.build_types(snippet.exception_deduction, []) diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -496,7 +496,7 @@ return SomeTuple((s_key, s_Int)) raise ValueError(variant) - def method_get(self, key, dfl): + def method_get(self, key, dfl=s_None): position = getbookkeeper().position_key self.dictdef.generalize_key(key) self.dictdef.generalize_value(dfl) diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py --- a/rpython/rtyper/lltypesystem/rordereddict.py +++ b/rpython/rtyper/lltypesystem/rordereddict.py @@ -283,8 +283,12 @@ return DictIteratorRepr(self, *variant) def rtype_method_get(self, hop): - v_dict, v_key, v_default = hop.inputargs(self, self.key_repr, - self.value_repr) + if hop.nb_args == 3: + v_dict, v_key, v_default = hop.inputargs(self, self.key_repr, + self.value_repr) + else: + v_dict, v_key = hop.inputargs(self, self.key_repr) + v_default = hop.inputconst(self.value_repr, None) hop.exception_cannot_occur() v_res = hop.gendirectcall(ll_dict_get, v_dict, v_key, v_default) return self.recast_value(hop.llops, v_res) diff --git a/rpython/rtyper/test/test_rdict.py b/rpython/rtyper/test/test_rdict.py --- a/rpython/rtyper/test/test_rdict.py +++ b/rpython/rtyper/test/test_rdict.py @@ -208,6 +208,16 @@ res = self.interpret(func, ()) assert res == 421 + def test_dict_get_no_second_arg(self): + def func(): + dic = self.newdict() + x1 = dic.get('hi', 'a') + x2 = dic.get('blah') + return (x1 == 'a') * 10 + (x2 is None) + return x1 * 10 + x2 + res = self.interpret(func, ()) + assert res == 11 + def test_dict_get_empty(self): def func(): # this time without writing to the dict _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit