Skip to content

Commit 14d4444

Browse files
committed
Implement C API functions PyStructSequence_InitType and PyStructSequence_InitType2.
1 parent be22a2a commit 14d4444

File tree

2 files changed

+71
-4
lines changed

2 files changed

+71
-4
lines changed

graalpython/com.oracle.graal.python.cext/src/structseq.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,61 @@
4040
*/
4141
#include "capi.h"
4242

43-
/* StructSequences */
43+
/* StructSequences a.k.a. 'namedtuple' */
4444
UPCALL_ID(PyStructSequence_New);
4545
PyObject* PyStructSequence_New(PyTypeObject* o) {
46-
return UPCALL_CEXT_O(_jls_PyStructSequence_New, native_to_java((PyObject*)o));
46+
return UPCALL_CEXT_O(_jls_PyStructSequence_New, native_type_to_java(o));
4747
}
48+
49+
UPCALL_ID(PyStructSequence_InitType2);
50+
int PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) {
51+
PyObject *dict;
52+
PyMemberDef* members;
53+
Py_ssize_t n_members, n_unnamed_members, i, k;
54+
PyObject *v;
55+
56+
memset(type, 0, sizeof(PyTypeObject));
57+
58+
// put field names and doc strings into two tuples
59+
PyObject* field_names = PyTuple_New(n_members);
60+
PyObject* field_docs = PyTuple_New(n_members);
61+
PyStructSequence_Field* fields = desc->fields;
62+
for (i = 0; i < n_members; i++) {
63+
PyTuple_SetItem(field_names, i, polyglot_from_string(fields[i].name, SRC_CS));
64+
PyTuple_SetItem(field_docs, i, polyglot_from_string(fields[i].doc, SRC_CS));
65+
}
66+
67+
// we create the new type managed
68+
PyTypeObject* newType = (PyTypeObject*) UPCALL_CEXT_O(_jls_PyStructSequence_InitType2,
69+
polyglot_from_string(desc->name, SRC_CS),
70+
polyglot_from_string(desc->doc, SRC_CS),
71+
native_to_java(field_names),
72+
native_to_java(field_docs));
73+
74+
// copy generic fields (CPython mem-copies a template)
75+
type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
76+
type->tp_itemsize = sizeof(PyObject *);
77+
type->tp_repr = newType->tp_repr;
78+
type->tp_flags = Py_TPFLAGS_DEFAULT;
79+
type->tp_members = NULL;
80+
type->tp_new = newType->tp_new;
81+
type->tp_base = &PyTuple_Type;
82+
83+
// now copy specific fields
84+
type->tp_name = newType->tp_name;
85+
type->tp_doc = newType->tp_doc;
86+
type->tp_dict = newType->tp_dict;
87+
88+
// now initialize the type
89+
if (PyType_Ready(type) < 0)
90+
return -1;
91+
Py_INCREF(type);
92+
93+
return 0;
94+
}
95+
96+
// taken from CPython "Objects/structseq.c"
97+
void PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) {
98+
(void)PyStructSequence_InitType2(type, desc);
99+
}
100+

graalpython/lib-graalpython/python_cext.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,9 +724,23 @@ def PyModule_AddObject(m, k, v):
724724
return None
725725

726726

727-
from posix import stat_result
728727
def PyStructSequence_New(typ):
729-
return stat_result([None] * stat_result.n_sequence_fields * 2)
728+
return typ()
729+
730+
731+
namedtuple_type = None
732+
def PyStructSequence_InitType2(type_name, type_doc, field_names, field_docs):
733+
assert len(field_names) == len(field_docs)
734+
global namedtuple_type
735+
if not namedtuple_type:
736+
from collections import namedtuple as namedtuple_type
737+
new_type = namedtuple_type(type_name, field_names)
738+
new_type.__doc__ = type_doc
739+
for i in range(len(field_names)):
740+
prop = getattr(new_type, field_names[i])
741+
assert isinstance(prop, property)
742+
prop.__doc__ = field_docs[i]
743+
return new_type
730744

731745

732746
def METH_UNSUPPORTED(fun):

0 commit comments

Comments
 (0)