1
2/* Testing module for multi-phase initialization of extension modules (PEP 489)
3 */
4
5#include "Python.h"
6
7/* Example objects */
8typedef struct {
9    PyObject_HEAD
10    PyObject            *x_attr;        /* Attributes dictionary */
11} ExampleObject;
12
13/* Example methods */
14
15static int
16Example_traverse(ExampleObject *self, visitproc visit, void *arg)
17{
18    Py_VISIT(self->x_attr);
19    return 0;
20}
21
22static int
23Example_finalize(ExampleObject *self)
24{
25    Py_CLEAR(self->x_attr);
26    return 0;
27}
28
29static PyObject *
30Example_demo(ExampleObject *self, PyObject *args)
31{
32    PyObject *o = NULL;
33    if (!PyArg_ParseTuple(args, "|O:demo", &o))
34        return NULL;
35    if (o != NULL && PyUnicode_Check(o)) {
36        Py_INCREF(o);
37        return o;
38    }
39    Py_INCREF(Py_None);
40    return Py_None;
41}
42
43
44static PyMethodDef Example_methods[] = {
45    {"demo",            (PyCFunction)Example_demo,  METH_VARARGS,
46        PyDoc_STR("demo() -> None")},
47    {NULL,              NULL}           /* sentinel */
48};
49
50static PyObject *
51Example_getattro(ExampleObject *self, PyObject *name)
52{
53    if (self->x_attr != NULL) {
54        PyObject *v = PyDict_GetItem(self->x_attr, name);
55        if (v != NULL) {
56            Py_INCREF(v);
57            return v;
58        }
59    }
60    return PyObject_GenericGetAttr((PyObject *)self, name);
61}
62
63static int
64Example_setattr(ExampleObject *self, const char *name, PyObject *v)
65{
66    if (self->x_attr == NULL) {
67        self->x_attr = PyDict_New();
68        if (self->x_attr == NULL)
69            return -1;
70    }
71    if (v == NULL) {
72        int rv = PyDict_DelItemString(self->x_attr, name);
73        if (rv < 0)
74            PyErr_SetString(PyExc_AttributeError,
75                "delete non-existing Example attribute");
76        return rv;
77    }
78    else
79        return PyDict_SetItemString(self->x_attr, name, v);
80}
81
82static PyType_Slot Example_Type_slots[] = {
83    {Py_tp_doc, "The Example type"},
84    {Py_tp_finalize, Example_finalize},
85    {Py_tp_traverse, Example_traverse},
86    {Py_tp_getattro, Example_getattro},
87    {Py_tp_setattr, Example_setattr},
88    {Py_tp_methods, Example_methods},
89    {0, 0},
90};
91
92static PyType_Spec Example_Type_spec = {
93    "_testimportexec.Example",
94    sizeof(ExampleObject),
95    0,
96    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
97    Example_Type_slots
98};
99
100/* Function of two integers returning integer */
101
102PyDoc_STRVAR(testexport_foo_doc,
103"foo(i,j)\n\
104\n\
105Return the sum of i and j.");
106
107static PyObject *
108testexport_foo(PyObject *self, PyObject *args)
109{
110    long i, j;
111    long res;
112    if (!PyArg_ParseTuple(args, "ll:foo", &i, &j))
113        return NULL;
114    res = i + j;
115    return PyLong_FromLong(res);
116}
117
118/* Test that PyState registration fails  */
119
120PyDoc_STRVAR(call_state_registration_func_doc,
121"register_state(0): call PyState_FindModule()\n\
122register_state(1): call PyState_AddModule()\n\
123register_state(2): call PyState_RemoveModule()");
124
125static PyObject *
126call_state_registration_func(PyObject *mod, PyObject *args)
127{
128    int i, ret;
129    PyModuleDef *def = PyModule_GetDef(mod);
130    if (def == NULL) {
131        return NULL;
132    }
133    if (!PyArg_ParseTuple(args, "i:call_state_registration_func", &i))
134        return NULL;
135    switch (i) {
136        case 0:
137            mod = PyState_FindModule(def);
138            if (mod == NULL) {
139                Py_RETURN_NONE;
140            }
141            return mod;
142        case 1:
143            ret = PyState_AddModule(mod, def);
144            if (ret != 0) {
145                return NULL;
146            }
147            break;
148        case 2:
149            ret = PyState_RemoveModule(def);
150            if (ret != 0) {
151                return NULL;
152            }
153            break;
154    }
155    Py_RETURN_NONE;
156}
157
158
159static PyType_Slot Str_Type_slots[] = {
160    {Py_tp_base, NULL}, /* filled out in module exec function */
161    {0, 0},
162};
163
164static PyType_Spec Str_Type_spec = {
165    "_testimportexec.Str",
166    0,
167    0,
168    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
169    Str_Type_slots
170};
171
172static PyMethodDef testexport_methods[] = {
173    {"foo",             testexport_foo,         METH_VARARGS,
174        testexport_foo_doc},
175    {"call_state_registration_func",  call_state_registration_func,
176        METH_VARARGS, call_state_registration_func_doc},
177    {NULL,              NULL}           /* sentinel */
178};
179
180static int execfunc(PyObject *m)
181{
182    PyObject *temp = NULL;
183
184    /* Due to cross platform compiler issues the slots must be filled
185     * here. It's required for portability to Windows without requiring
186     * C++. */
187    Str_Type_slots[0].pfunc = &PyUnicode_Type;
188
189    /* Add a custom type */
190    temp = PyType_FromSpec(&Example_Type_spec);
191    if (temp == NULL)
192        goto fail;
193    if (PyModule_AddObject(m, "Example", temp) != 0)
194        goto fail;
195
196    /* Add an exception type */
197    temp = PyErr_NewException("_testimportexec.error", NULL, NULL);
198    if (temp == NULL)
199        goto fail;
200    if (PyModule_AddObject(m, "error", temp) != 0)
201        goto fail;
202
203    /* Add Str */
204    temp = PyType_FromSpec(&Str_Type_spec);
205    if (temp == NULL)
206        goto fail;
207    if (PyModule_AddObject(m, "Str", temp) != 0)
208        goto fail;
209
210    if (PyModule_AddIntConstant(m, "int_const", 1969) != 0)
211        goto fail;
212
213    if (PyModule_AddStringConstant(m, "str_const", "something different") != 0)
214        goto fail;
215
216    return 0;
217 fail:
218    return -1;
219}
220
221/* Helper for module definitions; there'll be a lot of them */
222#define TEST_MODULE_DEF(name, slots, methods) { \
223    PyModuleDef_HEAD_INIT,                      /* m_base */ \
224    name,                                       /* m_name */ \
225    PyDoc_STR("Test module " name),             /* m_doc */ \
226    0,                                          /* m_size */ \
227    methods,                                    /* m_methods */ \
228    slots,                                      /* m_slots */ \
229    NULL,                                       /* m_traverse */ \
230    NULL,                                       /* m_clear */ \
231    NULL,                                       /* m_free */ \
232}
233
234PyModuleDef_Slot main_slots[] = {
235    {Py_mod_exec, execfunc},
236    {0, NULL},
237};
238
239static PyModuleDef main_def = TEST_MODULE_DEF("main", main_slots, testexport_methods);
240
241PyMODINIT_FUNC
242PyInit__testmultiphase(PyObject *spec)
243{
244    return PyModuleDef_Init(&main_def);
245}
246
247
248/**** Importing a non-module object ****/
249
250static PyModuleDef def_nonmodule;
251static PyModuleDef def_nonmodule_with_methods;
252
253/* Create a SimpleNamespace(three=3) */
254static PyObject*
255createfunc_nonmodule(PyObject *spec, PyModuleDef *def)
256{
257    PyObject *dct, *ns, *three;
258
259    if (def != &def_nonmodule && def != &def_nonmodule_with_methods) {
260        PyErr_SetString(PyExc_SystemError, "def does not match");
261        return NULL;
262    }
263
264    dct = PyDict_New();
265    if (dct == NULL)
266        return NULL;
267
268    three = PyLong_FromLong(3);
269    if (three == NULL) {
270        Py_DECREF(dct);
271        return NULL;
272    }
273    PyDict_SetItemString(dct, "three", three);
274    Py_DECREF(three);
275
276    ns = _PyNamespace_New(dct);
277    Py_DECREF(dct);
278    return ns;
279}
280
281static PyModuleDef_Slot slots_create_nonmodule[] = {
282    {Py_mod_create, createfunc_nonmodule},
283    {0, NULL},
284};
285
286static PyModuleDef def_nonmodule = TEST_MODULE_DEF(
287    "_testmultiphase_nonmodule", slots_create_nonmodule, NULL);
288
289PyMODINIT_FUNC
290PyInit__testmultiphase_nonmodule(PyObject *spec)
291{
292    return PyModuleDef_Init(&def_nonmodule);
293}
294
295PyDoc_STRVAR(nonmodule_bar_doc,
296"bar(i,j)\n\
297\n\
298Return the difference of i - j.");
299
300static PyObject *
301nonmodule_bar(PyObject *self, PyObject *args)
302{
303    long i, j;
304    long res;
305    if (!PyArg_ParseTuple(args, "ll:bar", &i, &j))
306        return NULL;
307    res = i - j;
308    return PyLong_FromLong(res);
309}
310
311static PyMethodDef nonmodule_methods[] = {
312    {"bar", nonmodule_bar, METH_VARARGS, nonmodule_bar_doc},
313    {NULL, NULL}           /* sentinel */
314};
315
316static PyModuleDef def_nonmodule_with_methods = TEST_MODULE_DEF(
317    "_testmultiphase_nonmodule_with_methods", slots_create_nonmodule, nonmodule_methods);
318
319PyMODINIT_FUNC
320PyInit__testmultiphase_nonmodule_with_methods(PyObject *spec)
321{
322    return PyModuleDef_Init(&def_nonmodule_with_methods);
323}
324
325/**** Non-ASCII-named modules ****/
326
327static PyModuleDef def_nonascii_latin = { \
328    PyModuleDef_HEAD_INIT,                      /* m_base */
329    "_testmultiphase_nonascii_latin",           /* m_name */
330    PyDoc_STR("Module named in Czech"),         /* m_doc */
331    0,                                          /* m_size */
332    NULL,                                       /* m_methods */
333    NULL,                                       /* m_slots */
334    NULL,                                       /* m_traverse */
335    NULL,                                       /* m_clear */
336    NULL,                                       /* m_free */
337};
338
339PyMODINIT_FUNC
340PyInitU__testmultiphase_zkouka_naten_evc07gi8e(PyObject *spec)
341{
342    return PyModuleDef_Init(&def_nonascii_latin);
343}
344
345static PyModuleDef def_nonascii_kana = { \
346    PyModuleDef_HEAD_INIT,                      /* m_base */
347    "_testmultiphase_nonascii_kana",            /* m_name */
348    PyDoc_STR("Module named in Japanese"),      /* m_doc */
349    0,                                          /* m_size */
350    NULL,                                       /* m_methods */
351    NULL,                                       /* m_slots */
352    NULL,                                       /* m_traverse */
353    NULL,                                       /* m_clear */
354    NULL,                                       /* m_free */
355};
356
357PyMODINIT_FUNC
358PyInitU_eckzbwbhc6jpgzcx415x(PyObject *spec)
359{
360    return PyModuleDef_Init(&def_nonascii_kana);
361}
362
363/*** Module with a single-character name ***/
364
365PyMODINIT_FUNC
366PyInit_x(PyObject *spec)
367{
368    return PyModuleDef_Init(&main_def);
369}
370
371/**** Testing NULL slots ****/
372
373static PyModuleDef null_slots_def = TEST_MODULE_DEF(
374    "_testmultiphase_null_slots", NULL, NULL);
375
376PyMODINIT_FUNC
377PyInit__testmultiphase_null_slots(PyObject *spec)
378{
379    return PyModuleDef_Init(&null_slots_def);
380}
381
382/**** Problematic modules ****/
383
384static PyModuleDef_Slot slots_bad_large[] = {
385    {_Py_mod_LAST_SLOT + 1, NULL},
386    {0, NULL},
387};
388
389static PyModuleDef def_bad_large = TEST_MODULE_DEF(
390    "_testmultiphase_bad_slot_large", slots_bad_large, NULL);
391
392PyMODINIT_FUNC
393PyInit__testmultiphase_bad_slot_large(PyObject *spec)
394{
395    return PyModuleDef_Init(&def_bad_large);
396}
397
398static PyModuleDef_Slot slots_bad_negative[] = {
399    {-1, NULL},
400    {0, NULL},
401};
402
403static PyModuleDef def_bad_negative = TEST_MODULE_DEF(
404    "_testmultiphase_bad_slot_negative", slots_bad_negative, NULL);
405
406PyMODINIT_FUNC
407PyInit__testmultiphase_bad_slot_negative(PyObject *spec)
408{
409    return PyModuleDef_Init(&def_bad_negative);
410}
411
412static PyModuleDef def_create_int_with_state = { \
413    PyModuleDef_HEAD_INIT,                      /* m_base */
414    "create_with_state",                        /* m_name */
415    PyDoc_STR("Not a PyModuleObject object, but requests per-module state"),
416    10,                                         /* m_size */
417    NULL,                                       /* m_methods */
418    slots_create_nonmodule,                     /* m_slots */
419    NULL,                                       /* m_traverse */
420    NULL,                                       /* m_clear */
421    NULL,                                       /* m_free */
422};
423
424PyMODINIT_FUNC
425PyInit__testmultiphase_create_int_with_state(PyObject *spec)
426{
427    return PyModuleDef_Init(&def_create_int_with_state);
428}
429
430
431static PyModuleDef def_negative_size = { \
432    PyModuleDef_HEAD_INIT,                      /* m_base */
433    "negative_size",                            /* m_name */
434    PyDoc_STR("PyModuleDef with negative m_size"),
435    -1,                                         /* m_size */
436    NULL,                                       /* m_methods */
437    slots_create_nonmodule,                     /* m_slots */
438    NULL,                                       /* m_traverse */
439    NULL,                                       /* m_clear */
440    NULL,                                       /* m_free */
441};
442
443PyMODINIT_FUNC
444PyInit__testmultiphase_negative_size(PyObject *spec)
445{
446    return PyModuleDef_Init(&def_negative_size);
447}
448
449
450static PyModuleDef uninitialized_def = TEST_MODULE_DEF("main", main_slots, testexport_methods);
451
452PyMODINIT_FUNC
453PyInit__testmultiphase_export_uninitialized(PyObject *spec)
454{
455    return (PyObject*) &uninitialized_def;
456}
457
458PyMODINIT_FUNC
459PyInit__testmultiphase_export_null(PyObject *spec)
460{
461    return NULL;
462}
463
464PyMODINIT_FUNC
465PyInit__testmultiphase_export_raise(PyObject *spec)
466{
467    PyErr_SetString(PyExc_SystemError, "bad export function");
468    return NULL;
469}
470
471PyMODINIT_FUNC
472PyInit__testmultiphase_export_unreported_exception(PyObject *spec)
473{
474    PyErr_SetString(PyExc_SystemError, "bad export function");
475    return PyModuleDef_Init(&main_def);
476}
477
478static PyObject*
479createfunc_null(PyObject *spec, PyModuleDef *def)
480{
481    return NULL;
482}
483
484PyModuleDef_Slot slots_create_null[] = {
485    {Py_mod_create, createfunc_null},
486    {0, NULL},
487};
488
489static PyModuleDef def_create_null = TEST_MODULE_DEF(
490    "_testmultiphase_create_null", slots_create_null, NULL);
491
492PyMODINIT_FUNC
493PyInit__testmultiphase_create_null(PyObject *spec)
494{
495    return PyModuleDef_Init(&def_create_null);
496}
497
498static PyObject*
499createfunc_raise(PyObject *spec, PyModuleDef *def)
500{
501    PyErr_SetString(PyExc_SystemError, "bad create function");
502    return NULL;
503}
504
505static PyModuleDef_Slot slots_create_raise[] = {
506    {Py_mod_create, createfunc_raise},
507    {0, NULL},
508};
509
510static PyModuleDef def_create_raise = TEST_MODULE_DEF(
511    "_testmultiphase_create_null", slots_create_raise, NULL);
512
513PyMODINIT_FUNC
514PyInit__testmultiphase_create_raise(PyObject *spec)
515{
516    return PyModuleDef_Init(&def_create_raise);
517}
518
519static PyObject*
520createfunc_unreported_exception(PyObject *spec, PyModuleDef *def)
521{
522    PyErr_SetString(PyExc_SystemError, "bad create function");
523    return PyModule_New("foo");
524}
525
526static PyModuleDef_Slot slots_create_unreported_exception[] = {
527    {Py_mod_create, createfunc_unreported_exception},
528    {0, NULL},
529};
530
531static PyModuleDef def_create_unreported_exception = TEST_MODULE_DEF(
532    "_testmultiphase_create_unreported_exception", slots_create_unreported_exception, NULL);
533
534PyMODINIT_FUNC
535PyInit__testmultiphase_create_unreported_exception(PyObject *spec)
536{
537    return PyModuleDef_Init(&def_create_unreported_exception);
538}
539
540static PyModuleDef_Slot slots_nonmodule_with_exec_slots[] = {
541    {Py_mod_create, createfunc_nonmodule},
542    {Py_mod_exec, execfunc},
543    {0, NULL},
544};
545
546static PyModuleDef def_nonmodule_with_exec_slots = TEST_MODULE_DEF(
547    "_testmultiphase_nonmodule_with_exec_slots", slots_nonmodule_with_exec_slots, NULL);
548
549PyMODINIT_FUNC
550PyInit__testmultiphase_nonmodule_with_exec_slots(PyObject *spec)
551{
552    return PyModuleDef_Init(&def_nonmodule_with_exec_slots);
553}
554
555static int
556execfunc_err(PyObject *mod)
557{
558    return -1;
559}
560
561static PyModuleDef_Slot slots_exec_err[] = {
562    {Py_mod_exec, execfunc_err},
563    {0, NULL},
564};
565
566static PyModuleDef def_exec_err = TEST_MODULE_DEF(
567    "_testmultiphase_exec_err", slots_exec_err, NULL);
568
569PyMODINIT_FUNC
570PyInit__testmultiphase_exec_err(PyObject *spec)
571{
572    return PyModuleDef_Init(&def_exec_err);
573}
574
575static int
576execfunc_raise(PyObject *spec)
577{
578    PyErr_SetString(PyExc_SystemError, "bad exec function");
579    return -1;
580}
581
582static PyModuleDef_Slot slots_exec_raise[] = {
583    {Py_mod_exec, execfunc_raise},
584    {0, NULL},
585};
586
587static PyModuleDef def_exec_raise = TEST_MODULE_DEF(
588    "_testmultiphase_exec_raise", slots_exec_raise, NULL);
589
590PyMODINIT_FUNC
591PyInit__testmultiphase_exec_raise(PyObject *mod)
592{
593    return PyModuleDef_Init(&def_exec_raise);
594}
595
596static int
597execfunc_unreported_exception(PyObject *mod)
598{
599    PyErr_SetString(PyExc_SystemError, "bad exec function");
600    return 0;
601}
602
603static PyModuleDef_Slot slots_exec_unreported_exception[] = {
604    {Py_mod_exec, execfunc_unreported_exception},
605    {0, NULL},
606};
607
608static PyModuleDef def_exec_unreported_exception = TEST_MODULE_DEF(
609    "_testmultiphase_exec_unreported_exception", slots_exec_unreported_exception, NULL);
610
611PyMODINIT_FUNC
612PyInit__testmultiphase_exec_unreported_exception(PyObject *spec)
613{
614    return PyModuleDef_Init(&def_exec_unreported_exception);
615}
616
617/*** Helper for imp test ***/
618
619static PyModuleDef imp_dummy_def = TEST_MODULE_DEF("imp_dummy", main_slots, testexport_methods);
620
621PyMODINIT_FUNC
622PyInit_imp_dummy(PyObject *spec)
623{
624    return PyModuleDef_Init(&imp_dummy_def);
625}
626