[issue42617] Enhancement request for PyType_FromSpecWIthBases add option for meta class

2020-12-12 Thread Karl Nelson


Karl Nelson  added the comment:

Perhaps just having PyType_InitHeapFromSpec which have just heap type linkage 
and slot copy section would help with the issue.   The major problem I have is 
maintaining the slot code which may change at some point in the future.   There 
would still be some risk of missing a portion of the init procedure but it 
would be a bit safer some of the process was in Python.

--
title: Enhancement request  for PyType_FromSpecWIthBases add option for meta 
class -> Enhancement request for PyType_FromSpecWIthBases add option for meta 
class

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42617] Enhancement request for PyType_FromSpecWIthBases add option for meta class

2020-12-12 Thread hai shi


hai shi  added the comment:

>This code could be made much safer if there were a 
>PyType_FromSpecWithBasesMeta which used the meta class to allocate the memory

IMHO, `PyType_FromSpecWithBases` is a atomic API of `TypeObject`.
Adding a class as a param will result in `PyType_FromSpecWithBases` will be 
complicated(the logic of this function depends on the children's tp_alloc 
sometimes).

I add pter in this bpo, maybe he have some better ideas :)

--
nosy: +petr.viktorin, shihai1991
versions: +Python 3.10

___
Python tracker 

___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue42617] Enhancement request for PyType_FromSpecWIthBases add option for meta class

2020-12-10 Thread Karl Nelson


New submission from Karl Nelson :

PyType_FromSpecWithBases is missing an argument for taking a meta class.  As a 
result it is necessary to replicate a large portion of Python code when I need 
to create a new heap type with a specified meta class.  This is a maintenance 
issue as replicating Python code is likely to get broken in future.

I have replicated to code from JPype so that it is clear how the meta class is 
coming into place.   PyJPClass_Type is derived from a 
PyHeapType with additional slots for Java to use and overrides allocation slots 
to that it can add extra slots (needs true multiple inheritance as it needed to 
add Java slots to types with mismatching memory layouts object, long, float, 
exception, ...).

This code could be made much safer if there were a PyType_FromSpecWithBasesMeta 
which used the meta class to allocate the memory (then I could safely override 
the slots after creation).
 

```
PyObject* PyJPClass_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
JP_PY_TRY("PyJPClass_FromSpecWithBases");
// Python lacks a FromSpecWithMeta so we are going to have to fake it 
here.
PyTypeObject* type = (PyTypeObject*) 
PyJPClass_Type->tp_alloc(PyJPClass_Type, 0); // <== we need to use the meta 
class here
PyHeapTypeObject* heap = (PyHeapTypeObject*) type;
type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_HAVE_GC;
type->tp_name = spec->name;
const char *s = strrchr(spec->name, '.');
if (s == NULL)
s = spec->name;
else
s++;
heap->ht_qualname = PyUnicode_FromString(s);
heap->ht_name = heap->ht_qualname;
Py_INCREF(heap->ht_name);
if (bases == NULL)
type->tp_bases = PyTuple_Pack(1, (PyObject*) & 
PyBaseObject_Type);
else
{
type->tp_bases = bases;
Py_INCREF(bases);
}
type->tp_base = (PyTypeObject*) PyTuple_GetItem(type->tp_bases, 0);
Py_INCREF(type->tp_base);
type->tp_as_async = >as_async;
type->tp_as_buffer = >as_buffer;
type->tp_as_mapping = >as_mapping;
type->tp_as_number = >as_number;
type->tp_as_sequence = >as_sequence;
type->tp_basicsize = spec->basicsize;
if (spec->basicsize == 0)
type->tp_basicsize = type->tp_base->tp_basicsize;
type->tp_itemsize = spec->itemsize;
if (spec->itemsize == 0)
type->tp_itemsize = type->tp_base->tp_itemsize;

// <=== Replicated code from the meta class 
type->tp_alloc = PyJPValue_alloc;
type->tp_free = PyJPValue_free;
type->tp_finalize = (destructor) PyJPValue_finalize;

// <= Replicated code from Python
for (PyType_Slot* slot = spec->slots; slot->slot; slot++)
{
   switch (slot->slot)
{
case Py_tp_free:
type->tp_free = (freefunc) slot->pfunc;
break;
case Py_tp_new:
type->tp_new = (newfunc) slot->pfunc;
break;
case Py_tp_init:
type->tp_init = (initproc) slot->pfunc;
break;
case Py_tp_getattro:
type->tp_getattro = (getattrofunc) slot->pfunc;
break;
case Py_tp_setattro:
type->tp_setattro = (setattrofunc) slot->pfunc;
break;
case Py_tp_dealloc:
type->tp_dealloc = (destructor) slot->pfunc;
break;
case Py_tp_str:
type->tp_str = (reprfunc) slot->pfunc;
break;
case Py_tp_repr:
type->tp_repr = (reprfunc) slot->pfunc;
break;
case Py_tp_methods:
type->tp_methods = (PyMethodDef*) slot->pfunc;
break;
case Py_sq_item:
heap->as_sequence.sq_item = (ssizeargfunc) 
slot->pfunc;
break;
case Py_sq_length:
heap->as_sequence.sq_length = (lenfunc) 
slot->pfunc;
break;
case Py_mp_ass_subscript:
heap->as_mapping.mp_ass_subscript = 
(objobjargproc) slot->pfunc;
break;
case Py_tp_hash:
type->tp_hash = (hashfunc) slot->pfunc;
break;