Skip to content

Conversation

@ofek
Copy link
Collaborator

@ofek ofek commented Nov 14, 2025

Resolves #894


After adding support for subclassing StructMeta in #890, users could define metaclasses like:

class IntegerStructMeta(StructMeta, ABCMeta): ...

and then use them for abstract Struct bases:

class IntegerStructBase(Struct, metaclass=IntegerStructMeta):
    @abstractmethod
    def to_integer(self) -> int: ...

At runtime this exposed two related problems:

  1. Original failure (user issue):
    issubclass(ConcreteIntStruct, IntegerStructBase) and isinstance(obj, IntegerStructBase) crashed with:

    AttributeError: type object 'IntegerStructBase' has no attribute '_abc_impl'
    

    This comes from the __instancecheck__/__subclasscheck__ methods of ABCMeta, which assume the ABC machinery has been initialized (_abc_init/update_abstractmethods have run and _abc_impl is present). Because StructMeta_new_inner built the type via PyType_Type.tp_new without calling any ABC helper, the ABC state was never initialized, so the cache object _abc_impl was missing.

  2. Follow-up failure when trying to just call __new__:
    An attempt to delegate to the "next" metaclass in the MRO (a C equivalent of super(StructMeta, mcls).__new__(...)) resulted in:

    TypeError: type.__new__(IntegerStructMeta) is not safe, use IntegerStructMeta.__new__()
    

    This comes from CPython's new safety check, which rejects calling a base type's __new__ when the static base has a different tp_new. This has been deprecated since 3.12 but is now officially unsupported starting in 3.14.

So mixing StructMeta and ABCMeta gave you either a crash in ABC’s internals or a TypeError from the metaclass construction path.

Taking inspiration from that new safety check, I think it's infeasible to support mixing with arbitrary metaclasses and now we have special logic for ABCMeta.

@ofek ofek force-pushed the metaclass-cooperative branch 2 times, most recently from 4289aee to 50d97ae Compare November 14, 2025 07:46
@ofek ofek force-pushed the metaclass-cooperative branch from 50d97ae to d091f65 Compare November 14, 2025 08:01
@ofek ofek marked this pull request as ready for review November 14, 2025 08:05
@ofek ofek merged commit 03c91d2 into main Nov 14, 2025
16 checks passed
@ofek ofek deleted the metaclass-cooperative branch November 14, 2025 08:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StructMeta / ABC Question - Docs

2 participants