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

Reply via email to