Skip to content

ctypes Stucture._fields_ cannot be set when Structure has been subclassed #100980

Closed

Description

@ionite34

Bug report

Currently the method for defining Structure fields that cannot be defined within the class, is to define the class with pass and then set _fields_ outside. But ctypes.Structure incorrectly raises AttributeError, even when no class has ever set a _fields_.

from ctypes import *

class PyObject(Structure):
    pass

class PyVarObject(PyObject):
    pass

class PyTypeObject(PyVarObject):
    pass

PyObject._fields_ = [
    ("ob_refcnt", c_long),
    ("ob_type", POINTER(PyTypeObject)),
]
    PyObject._fields_ = [
    ^^^^^^^^^^^^^^^^^
AttributeError: _fields_ is final

Strangely, suppressing this Attribute error reveals the _fields_ attribute does actually get set?

with suppress(AttributeError):
    PyObject._fields_ = [
        ("ob_refcnt", c_long),
        ("ob_type", POINTER(PyTypeObject)),
    ]

print(PyObject._fields_)
>> [('ob_refcnt', <class 'ctypes.c_long'>), ('ob_type', <class '__main__.LP_PyTypeObject'>)]

Your environment

  • CPython versions tested on: 3.11.1, main
  • Operating system and architecture: macOS ARM, ubuntu x64

Linked PRs

Activity

  1. changed the title [-]ctypes._fields_ cannot be set when Structure has been subclassed[/-] [+]ctypes Stucture._fields_ cannot be set when Structure has been subclassed[/+] on Jan 12, 2023
  2. self-assigned this
    on Sep 18, 2024
  3. added a commit that references this issue on Sep 20, 2024
  4. encukou commented on Sep 20, 2024

    @encukou
    Member

    Subclassing a Structure finalizes it, which prevents setting _fields_. That is the intended behaviour: the superclass's fields are “inherited” (included in the subclass), so they must be known rather early, and they can't change when a new subclass is made. (AFAIK we could delay the finalization a bit more, but that would add hard-to-test edge cases, so let's not.)
    The docs could be clearer here.

    The bug here is that the _fields_ attribute is set despite AttributeError. This should not happen. (However, the setattr is just “cosmetic”: the internals aren't updated, in fact the attribute is never consulted again after finalization.)

    It's confusing that it's possible can finalize a class that doesn't have _fields_ set. However, this feature is useful for superclasses that don't add/affect C fields -- like Structure itself.

  5. added 2 commits that reference this issue on Sep 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions