[pypy-commit] pypy default: Expose a few members of the PyCodeObject structure

amauryfa noreply at buildbot.pypy.org
Fri Sep 9 01:27:31 CEST 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r47176:9962794cb329
Date: 2011-09-08 01:04 +0200
http://bitbucket.org/pypy/pypy/changeset/9962794cb329/

Log:	Expose a few members of the PyCodeObject structure

diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -10,7 +10,7 @@
 from pypy.interpreter.argument import Signature
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import NoneNotWrapped, unwrap_spec
-from pypy.interpreter.astcompiler.consts import (CO_OPTIMIZED,
+from pypy.interpreter.astcompiler.consts import (
     CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
     CO_GENERATOR, CO_CONTAINSGLOBALS)
 from pypy.rlib.rarithmetic import intmask
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
@@ -4,9 +4,21 @@
     cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, from_ref, Py_DecRef, make_typedescr, borrow_from)
+from pypy.rlib.unroll import unrolling_iterable
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.function import Function, Method
 from pypy.interpreter.pycode import PyCode
+from pypy.interpreter import pycode
+
+CODE_FLAGS = dict(
+    CO_OPTIMIZED   = 0x0001,
+    CO_NEWLOCALS   = 0x0002,
+    CO_VARARGS     = 0x0004,
+    CO_VARKEYWORDS = 0x0008,
+    CO_NESTED      = 0x0010,
+    CO_GENERATOR   = 0x0020,
+)
+ALL_CODE_FLAGS = unrolling_iterable(CODE_FLAGS.items())
 
 PyFunctionObjectStruct = lltype.ForwardReference()
 PyFunctionObject = lltype.Ptr(PyFunctionObjectStruct)
@@ -16,7 +28,12 @@
 
 PyCodeObjectStruct = lltype.ForwardReference()
 PyCodeObject = lltype.Ptr(PyCodeObjectStruct)
-cpython_struct("PyCodeObject", PyObjectFields, PyCodeObjectStruct)
+PyCodeObjectFields = PyObjectFields + \
+    (("co_name", PyObject),
+     ("co_flags", rffi.INT),
+     ("co_argcount", rffi.INT),
+    )
+cpython_struct("PyCodeObject", PyCodeObjectFields, PyCodeObjectStruct)
 
 @bootstrap_function
 def init_functionobject(space):
@@ -24,6 +41,10 @@
                    basestruct=PyFunctionObject.TO,
                    attach=function_attach,
                    dealloc=function_dealloc)
+    make_typedescr(PyCode.typedef,
+                   basestruct=PyCodeObject.TO,
+                   attach=code_attach,
+                   dealloc=code_dealloc)
 
 PyFunction_Check, PyFunction_CheckExact = build_type_checkers("Function", Function)
 PyMethod_Check, PyMethod_CheckExact = build_type_checkers("Method", Method)
@@ -40,6 +61,24 @@
     from pypy.module.cpyext.object import PyObject_dealloc
     PyObject_dealloc(space, py_obj)
 
+def code_attach(space, py_obj, w_obj):
+    py_code = rffi.cast(PyCodeObject, py_obj)
+    assert isinstance(w_obj, PyCode)
+    py_code.c_co_name = make_ref(space, space.wrap(w_obj.co_name))
+    co_flags = 0
+    for name, value in ALL_CODE_FLAGS:
+        if w_obj.co_flags & getattr(pycode, name):
+            co_flags |= value
+    rffi.setintfield(py_code, 'c_co_flags', co_flags)
+    rffi.setintfield(py_code, 'c_co_argcount', w_obj.co_argcount)
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def code_dealloc(space, py_obj):
+    py_code = rffi.cast(PyCodeObject, py_obj)
+    Py_DecRef(space, py_code.c_co_name)
+    from pypy.module.cpyext.object import PyObject_dealloc
+    PyObject_dealloc(space, py_obj)
+
 @cpython_api([PyObject], PyObject)
 def PyFunction_GetCode(space, w_func):
     """Return the code object associated with the function object op."""
diff --git a/pypy/module/cpyext/include/code.h b/pypy/module/cpyext/include/code.h
--- a/pypy/module/cpyext/include/code.h
+++ b/pypy/module/cpyext/include/code.h
@@ -4,7 +4,21 @@
 extern "C" {
 #endif
 
-typedef PyObject PyCodeObject;
+typedef struct {
+    PyObject_HEAD
+    PyObject *co_name;
+    int co_argcount;
+    int co_flags;
+} PyCodeObject;
+
+/* Masks for co_flags above */
+/* These values are also in funcobject.py */
+#define CO_OPTIMIZED	0x0001
+#define CO_NEWLOCALS	0x0002
+#define CO_VARARGS	0x0004
+#define CO_VARKEYWORDS	0x0008
+#define CO_NESTED       0x0010
+#define CO_GENERATOR    0x0020
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/test/test_funcobject.py b/pypy/module/cpyext/test/test_funcobject.py
--- a/pypy/module/cpyext/test/test_funcobject.py
+++ b/pypy/module/cpyext/test/test_funcobject.py
@@ -2,8 +2,12 @@
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
-from pypy.module.cpyext.funcobject import PyFunctionObject
+from pypy.module.cpyext.funcobject import (
+    PyFunctionObject, PyCodeObject, CODE_FLAGS)
 from pypy.interpreter.function import Function, Method
+from pypy.interpreter.pycode import PyCode
+
+globals().update(CODE_FLAGS)
 
 class TestFunctionObject(BaseApiTest):
     def test_function(self, space, api):
@@ -38,12 +42,36 @@
 
     def test_getcode(self, space, api):
         w_function = space.appexec([], """():
-            def func(x): return x
+            def func(x, y, z): return x
             return func
         """)
         w_code = api.PyFunction_GetCode(w_function)
         assert w_code.co_name == "func"
 
+        ref = make_ref(space, w_code)
+        assert (from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is
+                space.gettypeobject(PyCode.typedef))
+        assert "func" == space.unwrap(
+           from_ref(space, rffi.cast(PyCodeObject, ref).c_co_name))
+        assert 3 == rffi.cast(PyCodeObject, ref).c_co_argcount
+        api.Py_DecRef(ref)
+
+    def test_co_flags(self, space, api):
+        def get_flags(signature, body="pass"):
+            w_code = space.appexec([], """():
+                def func(%s): %s
+                return func.__code__
+            """ % (signature, body))
+            ref = make_ref(space, w_code)
+            co_flags = rffi.cast(PyCodeObject, ref).c_co_flags
+            api.Py_DecRef(ref)
+            return co_flags
+        assert get_flags("x") == CO_NESTED | CO_OPTIMIZED | CO_NEWLOCALS
+        assert get_flags("x", "exec x") == CO_NESTED | CO_NEWLOCALS
+        assert get_flags("x, *args") & CO_VARARGS
+        assert get_flags("x, **kw") & CO_VARKEYWORDS
+        assert get_flags("x", "yield x") & CO_GENERATOR
+
     def test_newcode(self, space, api):
         filename = rffi.str2charp('filename')
         funcname = rffi.str2charp('funcname')


More information about the pypy-commit mailing list