Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #197798 > unrolled thread

PyObjects From Python Via ctypes

Started byLawrence D’Oliveiro <ldo@nz.invalid>
First post2026-06-11 07:41 +0000
Last post2026-06-11 07:44 +0000
Articles 2 — 1 participant

Back to article view | Back to comp.lang.python


Contents

  PyObjects From Python Via ctypes Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-11 07:41 +0000
    Re: PyObjects From Python Via ctypes Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-06-11 07:44 +0000

#197798 — PyObjects From Python Via ctypes

FromLawrence D’Oliveiro <ldo@nz.invalid>
Date2026-06-11 07:41 +0000
SubjectPyObjects From Python Via ctypes
Message-ID<110doqv$19tv7$1@dont-email.me>
I see ctypes has a py_object type, but you can’t seem to do much with
it. The following might be more useful:

---- file: pyobjhack.py
import ctypes as ct

def _init_hack() :
    # works out the values of TRACE_REFS and PYOBJECT_HEADER_SIZE.
    global TRACE_REFS, PYOBJECT_HEADER_SIZE
    o = object()
    # CPython implementation detail: “id()” function returns address of object header
    if ct.c_size_t.from_address(id(o)).value == 1 :
        TRACE_REFS = False
        PYOBJECT_HEADER_SIZE = 2
    elif ct.c_size_t.from_address(id(o) + 2 * ct.sizeof(ct.c_void_p)).value == 1 :
        TRACE_REFS = True
        PYOBJECT_HEADER_SIZE = 4
    else :
        raise RuntimeError("cannot determine pyobject header size")
    #end if
      # header of every PyObject has ob_refcnt (type ssize_t) followed by ob_type (type pointer),
      # but these might be preceded by a pair of next/prev pointers if Py_TRACE_REFS is defined.
      # Only way I can figure out to determine which is the case is to construct an object
      # with a known refcount of 1, and see if I can find the value 1 at the start.
    # Confirm that the refcount field behaves as expected:
    o2 = o
    assert ct.c_size_t.from_address(id(o) + (PYOBJECT_HEADER_SIZE - 2) * ct.sizeof(ct.c_void_p)).value == 2
    del o2
    assert ct.c_size_t.from_address(id(o) + (PYOBJECT_HEADER_SIZE - 2) * ct.sizeof(ct.c_void_p)).value == 1
#end _init_hack
_init_hack()
del _init_hack

class PyObject(ct.Structure) :
    "header part of a PyObject structure."

    _fields_ = \
        (
            (
                [],
                [
                    ("_ob_next", ct.c_void_p),
                    ("_ob_prev", ct.c_void_p),
                ],
            )[TRACE_REFS]
        +
            [
                ("ob_refcnt", ct.c_ssize_t),
                ("ob_type", ct.c_void_p),
            ]
        )

    @classmethod
    def from_obj(celf, obj) :
        "aliases the object header to a PyObject struct."
        return \
            celf.from_address(id(obj))
    #end from_obj

#end PyObject

[toc] | [next] | [standalone]


#197799

FromLawrence D’Oliveiro <ldo@nz.invalid>
Date2026-06-11 07:44 +0000
Message-ID<110dp0f$19tv7$2@dont-email.me>
In reply to#197798
On Thu, 11 Jun 2026 07:41:20 -0000 (UTC), I wrote:

> I see ctypes has a py_object type, but you can’t seem to do much
> with it. The following might be more useful:

Example use: accessing a more powerful Cairo wrapper in a context
where the GUI toolkit wrapper (e.g. PyGObject for GTK) wants to
give you only a pycairo object.

----
import ctypes as ct
import qahirah as qah
from pyobjhack import PyObject

class PyCairo_Context(ct.Structure) :
    "extract cairo_t pointer from pycairo.Context object."
    _fields_ = \
        [
            ("header", PyObject),
            ("ctx", ct.c_void_p),
        ]

    @classmethod
    def get_ctx(celf, pyctx) :
        return \
            ct.c_void_p(celf.from_address(id(pyctx)).ctx).value
    #end get_ctx

#end PyCairo_Context

def pycairo_to_qah(ctx) :
    "returns a qah.Context object wrapping the cairo_t pointer from" \
    " a given cairo.Context object."
    gx = PyCairo_Context.get_ctx(ctx)
    qah.cairo.cairo_reference(gx) # grab one for myself
    return \
        qah.Context(gx)
#end pycairo_to_qah

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web