[pypy-commit] pypy default: Implement cpyext.is_cpyext_function()

rlamy pypy.commits at gmail.com
Mon Nov 13 15:31:00 EST 2017


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: 
Changeset: r93005:a305590465d6
Date: 2017-11-13 20:30 +0000
http://bitbucket.org/pypy/pypy/changeset/a305590465d6/

Log:	Implement cpyext.is_cpyext_function()

	inspect.isbuiltin() now returns True for functions implemented in C,
	like on CPython.

diff --git a/lib-python/2.7/inspect.py b/lib-python/2.7/inspect.py
--- a/lib-python/2.7/inspect.py
+++ b/lib-python/2.7/inspect.py
@@ -40,6 +40,10 @@
 import linecache
 from operator import attrgetter
 from collections import namedtuple
+try:
+    from cpyext import is_cpyext_function as _is_cpyext_function
+except ImportError:
+    _is_cpyext_function = lambda obj: False
 
 # These constants are from Include/code.h.
 CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8
@@ -230,7 +234,7 @@
         __doc__         documentation string
         __name__        original name of this function or method
         __self__        instance to which a method is bound, or None"""
-    return isinstance(object, types.BuiltinFunctionType)
+    return isinstance(object, types.BuiltinFunctionType) or _is_cpyext_function(object)
 
 def isroutine(object):
     """Return true if the object is any kind of function or method."""
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
@@ -5,6 +5,7 @@
 class Module(MixedModule):
     interpleveldefs = {
         'load_module': 'api.load_extension_module',
+        'is_cpyext_function': 'interp_cpyext.is_cpyext_function',
     }
 
     appleveldefs = {
diff --git a/pypy/module/cpyext/interp_cpyext.py b/pypy/module/cpyext/interp_cpyext.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/interp_cpyext.py
@@ -0,0 +1,4 @@
+from .methodobject import W_PyCFunctionObject
+
+def is_cpyext_function(space, w_arg):
+    return space.newbool(isinstance(w_arg, W_PyCFunctionObject))
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -381,6 +381,11 @@
 
     def test_export_function(self):
         import sys
+        if '__pypy__' in sys.modules:
+            from cpyext import is_cpyext_function
+        else:
+            import inspect
+            is_cpyext_function = inspect.isbuiltin
         init = """
         if (Py_IsInitialized())
             Py_InitModule("foo", methods);
@@ -399,6 +404,7 @@
         assert 'foo' in sys.modules
         assert 'return_pi' in dir(module)
         assert module.return_pi is not None
+        assert is_cpyext_function(module.return_pi)
         assert module.return_pi() == 3.14
         assert module.return_pi.__module__ == 'foo'
 
@@ -777,14 +783,14 @@
         # Set an exception and return NULL
         raises(TypeError, module.set, None)
 
-        # clear any exception and return a value 
+        # clear any exception and return a value
         assert module.clear(1) == 1
 
         # Set an exception, but return non-NULL
         expected = 'An exception was set, but function returned a value'
         exc = raises(SystemError, module.set, 1)
         assert exc.value[0] == expected
-        
+
 
         # Clear the exception and return a value, all is OK
         assert module.clear(1) == 1
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
@@ -104,8 +104,10 @@
         class A(object): pass
         A.f = mod.f
         A.g = lambda: 42
+        # Unbound method
         assert A.f() == 42
         raises(TypeError, A.g)
+        # Bound method
         assert A().f() == 42
         raises(TypeError, A().g)
 


More information about the pypy-commit mailing list