This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author haberman2
Recipients Alexander.Belopolsky, Arfrever, Christian.Tismer, Robin.Schreiber, amaury.forgeotdarc, belopolsky, haberman2, jcea, jhaberman, lekma, loewis, mattip, petr.viktorin, pitrou
Date 2021-09-14.13:57:58
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1631627878.65.0.755255673452.issue15870@roundup.psfhosted.org>
In-reply-to
Content
I found a way to use metaclasses with the limited API.

I found that I can access PyType_Type.tp_new by creating a heap type derived from PyType_Type:

  static PyType_Slot dummy_slots[] = {
    {0, NULL}
  };

  static PyType_Spec dummy_spec = {
      "module.DummyClass", 0, 0, Py_TPFLAGS_DEFAULT, dummy_slots,
  };

  PyObject *bases = Py_BuildValue("(O)", &PyType_Type);
  PyObject *type = PyType_FromSpecWithBases(&dummy_spec, bases);
  Py_DECREF(bases);

  type_new = PyType_GetSlot((PyTypeObject*)type, Py_tp_new);
  Py_DECREF(type);

  #ifndef Py_LIMITED_API
    assert(type_new == PyType_Type.tp_new);
  #endif

  // Creates a type using a metaclass.
  PyObject *uses_metaclass = type_new(metaclass, args, NULL);

PyType_GetSlot() can't be used on PyType_Type directly, since it is not a heap type.  But a heap type derived from PyType_Type will inherit tp_new, and we can call PyType_GetSlot() on that.

Once we have PyType_Type.tp_new, we can use it to create a new type using a metaclass. This avoids any of the class-switching tricks I was trying before.  We can also get other slots of PyType_Type like tp_getattro to do the equivalent of super().

The PyType_FromSpecEx() function proposed in this bug would still be a nicer solution to my problem.  Calling type_new() doesn't let you specify object size or slots.  To work around this, I derive from a type I created with PyType_FromSpec(), relying on the fact that the size and slots will be inherited.  This works, but it introduces an extra class into the hierarchy that ideally could be avoided.

But I do have a workaround that appears to work, and avoids the problems associated with setting ob_type directly (like PyPy incompatibility).
History
Date User Action Args
2021-09-14 13:57:58haberman2setrecipients: + haberman2, loewis, jcea, amaury.forgeotdarc, belopolsky, pitrou, Arfrever, petr.viktorin, lekma, Alexander.Belopolsky, mattip, Robin.Schreiber, Christian.Tismer, jhaberman
2021-09-14 13:57:58haberman2setmessageid: <1631627878.65.0.755255673452.issue15870@roundup.psfhosted.org>
2021-09-14 13:57:58haberman2linkissue15870 messages
2021-09-14 13:57:58haberman2create