this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "Python.h"
3#include "gtest/gtest.h"
4
5#include "capi-fixture.h"
6#include "capi-testing.h"
7
8namespace py {
9namespace testing {
10
11using ModuleExtensionApiTest = ExtensionApi;
12// Used to convert non-capturing closures into function pointers.
13using slot_func = int (*)(PyObject*);
14
15TEST_F(ModuleExtensionApiTest, SpamModule) {
16 static PyModuleDef def;
17 def = {
18 PyModuleDef_HEAD_INIT,
19 "spam",
20 };
21
22 // PyInit_spam
23 const long val = 5;
24 {
25 PyObjectPtr m(PyModule_Create(&def));
26 PyObject* de = PyDict_New();
27 PyModule_AddObject(m, "constants", de);
28
29 const char* c = "CONST";
30 PyObjectPtr u(PyUnicode_FromString(c));
31 PyObjectPtr v(PyLong_FromLong(val));
32 PyModule_AddIntConstant(m, c, val);
33 PyDict_SetItem(de, v, u);
34 ASSERT_EQ(testing::moduleSet("__main__", "spam", m), 0);
35 }
36
37 PyRun_SimpleString("x = spam.CONST");
38
39 PyObjectPtr x(testing::mainModuleGet("x"));
40 long result = PyLong_AsLong(x);
41 ASSERT_EQ(result, val);
42}
43
44TEST_F(ModuleExtensionApiTest, GetDictReturnsMapping) {
45 PyRun_SimpleString(R"(
46foo = 42
47)");
48 PyObjectPtr name(PyUnicode_FromString("__main__"));
49 PyObjectPtr main(importGetModule(name));
50 ASSERT_TRUE(PyModule_Check(main));
51 PyObject* module_dict = PyModule_GetDict(main);
52 PyObjectPtr value(PyMapping_GetItemString(module_dict, "foo"));
53 EXPECT_TRUE(isLongEqualsLong(value, 42));
54}
55
56TEST_F(ModuleExtensionApiTest, NewObjectWithNonStringNameReturnsModule) {
57 testing::PyObjectPtr long_name(PyLong_FromLong(2));
58 testing::PyObjectPtr module(PyModule_NewObject(long_name));
59 ASSERT_TRUE(PyModule_CheckExact(module));
60
61 testing::PyObjectPtr mod_name(PyObject_GetAttrString(module, "__name__"));
62 EXPECT_EQ(mod_name, long_name);
63 EXPECT_EQ(PyErr_Occurred(), nullptr);
64}
65
66TEST_F(ModuleExtensionApiTest, NewObjectDoesNotAddModuleToModuleDict) {
67 testing::PyObjectPtr name(PyUnicode_FromString("mymodule"));
68 testing::PyObjectPtr module(PyModule_NewObject(name));
69 ASSERT_TRUE(PyModule_CheckExact(module));
70
71 PyObject* mods = PyImport_GetModuleDict();
72 PyObject* item = PyDict_GetItem(mods, name);
73 EXPECT_EQ(item, nullptr);
74
75 EXPECT_EQ(PyErr_Occurred(), nullptr);
76}
77
78TEST_F(ModuleExtensionApiTest, NewWithEmptyStringReturnsModule) {
79 testing::PyObjectPtr module(PyModule_New(""));
80 ASSERT_TRUE(PyModule_CheckExact(module));
81
82 testing::PyObjectPtr mod_name(PyObject_GetAttrString(module, "__name__"));
83 EXPECT_TRUE(isUnicodeEqualsCStr(mod_name, ""));
84 EXPECT_EQ(PyErr_Occurred(), nullptr);
85}
86
87TEST_F(ModuleExtensionApiTest, NewDoesNotAddModuleToModuleDict) {
88 testing::PyObjectPtr module(PyModule_New("mymodule"));
89 ASSERT_TRUE(PyModule_CheckExact(module));
90
91 PyObject* mods = PyImport_GetModuleDict();
92 testing::PyObjectPtr name(PyUnicode_FromString("mymodule"));
93 PyObject* item = PyDict_GetItem(mods, name);
94 EXPECT_EQ(item, nullptr);
95
96 EXPECT_EQ(PyErr_Occurred(), nullptr);
97}
98
99TEST_F(ModuleExtensionApiTest, CreateAddsDocstring) {
100 const char* mod_doc = "documentation for spam";
101 static PyModuleDef def;
102 def = {
103 PyModuleDef_HEAD_INIT,
104 "mymodule",
105 mod_doc,
106 };
107
108 PyObjectPtr module(PyModule_Create(&def));
109 ASSERT_NE(module, nullptr);
110 EXPECT_TRUE(PyModule_CheckExact(module));
111
112 PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__"));
113 EXPECT_TRUE(isUnicodeEqualsCStr(doc, mod_doc));
114 EXPECT_EQ(PyErr_Occurred(), nullptr);
115}
116
117TEST_F(ModuleExtensionApiTest, CreateSetsStateNull) {
118 static PyModuleDef def;
119 def = {
120 PyModuleDef_HEAD_INIT,
121 "mymodule",
122 };
123
124 testing::PyObjectPtr module(PyModule_Create(&def));
125 ASSERT_NE(module, nullptr);
126 EXPECT_TRUE(PyModule_CheckExact(module));
127
128 ASSERT_EQ(PyModule_GetState(module), nullptr);
129 EXPECT_EQ(PyErr_Occurred(), nullptr);
130}
131
132TEST_F(ModuleExtensionApiTest, GetStateAllocatesAndAllowsMutation) {
133 struct MyState {
134 char letter;
135 int number;
136 double big_number;
137 PyObject* object;
138 };
139
140 static PyModuleDef def;
141 def = {
142 PyModuleDef_HEAD_INIT,
143 "mymodule",
144 "doc",
145 sizeof(MyState),
146 };
147
148 testing::PyObjectPtr module(PyModule_Create(&def));
149 ASSERT_NE(module, nullptr);
150 ASSERT_EQ(PyState_AddModule(module, &def), 0);
151 EXPECT_TRUE(PyModule_CheckExact(module));
152
153 void* state = PyModule_GetState(module);
154 ASSERT_NE(state, nullptr);
155 MyState* mod_state = static_cast<MyState*>(state);
156 mod_state->letter = 'a';
157 mod_state->number = 2;
158 mod_state->big_number = 2.1;
159 testing::PyObjectPtr unique_obj(PyTuple_New(0));
160 mod_state->object = unique_obj;
161
162 ASSERT_EQ(PyModule_GetState(module), state);
163 EXPECT_EQ(mod_state->letter, 'a');
164 EXPECT_EQ(mod_state->number, 2);
165 EXPECT_EQ(mod_state->big_number, 2.1);
166 EXPECT_EQ(mod_state->object, unique_obj);
167
168 EXPECT_EQ(PyErr_Occurred(), nullptr);
169}
170
171TEST_F(ModuleExtensionApiTest, GetStateFailsOnNonModule) {
172 testing::PyObjectPtr not_a_module(PyLong_FromLong(0));
173
174 EXPECT_EQ(PyModule_GetState(not_a_module), nullptr);
175 ASSERT_NE(PyErr_Occurred(), nullptr);
176 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
177}
178
179TEST_F(ModuleExtensionApiTest, GetStateReturnsValidStateAfterGarbageCollected) {
180 struct MyState {
181 char letter;
182 };
183
184 static PyModuleDef def;
185 def = {
186 PyModuleDef_HEAD_INIT,
187 "mymodule",
188 "doc",
189 sizeof(MyState),
190 };
191
192 PyObject* module = PyModule_Create(&def);
193 ASSERT_NE(module, nullptr);
194 ASSERT_EQ(PyState_AddModule(module, &def), 0);
195 EXPECT_TRUE(PyModule_CheckExact(module));
196
197 void* state = PyModule_GetState(module);
198 ASSERT_NE(state, nullptr);
199 MyState* mod_state = static_cast<MyState*>(state);
200 mod_state->letter = 'a';
201
202 // Decrease the reference count to zero.
203 Py_DECREF(module);
204
205 // Trigger GC to remove the module object from the handle table.
206 collectGarbage();
207
208 // Verify that the module still retains the state.
209 module = PyState_FindModule(&def);
210 ASSERT_NE(module, nullptr);
211 ASSERT_EQ(PyModule_GetState(module), state);
212 mod_state = static_cast<MyState*>(state);
213 EXPECT_EQ(mod_state->letter, 'a');
214 EXPECT_EQ(PyErr_Occurred(), nullptr);
215}
216
217TEST_F(ModuleExtensionApiTest, GetDefWithExtensionModuleRetunsNonNull) {
218 static PyModuleDef def;
219 def = {
220 PyModuleDef_HEAD_INIT,
221 "mymodule",
222 "mydoc",
223 };
224
225 PyObjectPtr module(PyModule_Create(&def));
226 ASSERT_NE(module, nullptr);
227
228 PyModuleDef* result = PyModule_GetDef(module);
229 EXPECT_EQ(result, &def);
230}
231
232TEST_F(ModuleExtensionApiTest, GetDefWithNonModuleRetunsNull) {
233 PyObject* integer = PyBool_FromLong(0);
234 PyModuleDef* result = PyModule_GetDef(integer);
235 EXPECT_EQ(result, nullptr);
236}
237
238TEST_F(ModuleExtensionApiTest, GetDefWithNonExtensionModuleReturnsNull) {
239 PyRun_SimpleString("");
240 PyObjectPtr module_name(PyUnicode_FromString("__main__"));
241 PyObjectPtr main_module(testing::importGetModule(module_name));
242 PyModuleDef* result = PyModule_GetDef(main_module);
243 EXPECT_EQ(result, nullptr);
244}
245
246TEST_F(ModuleExtensionApiTest, CheckTypeOnNonModuleReturnsZero) {
247 PyObjectPtr pylong(PyLong_FromLong(10));
248 EXPECT_FALSE(PyModule_Check(pylong));
249 EXPECT_FALSE(PyModule_CheckExact(pylong));
250 EXPECT_EQ(PyErr_Occurred(), nullptr);
251}
252
253TEST_F(ModuleExtensionApiTest, CheckTypeOnModuleReturnsOne) {
254 static PyModuleDef def;
255 def = {
256 PyModuleDef_HEAD_INIT,
257 "mymodule",
258 };
259 PyObjectPtr module(PyModule_Create(&def));
260 EXPECT_TRUE(PyModule_Check(module));
261 EXPECT_TRUE(PyModule_CheckExact(module));
262 EXPECT_EQ(PyErr_Occurred(), nullptr);
263}
264
265TEST_F(ModuleExtensionApiTest, SetDocStringChangesDoc) {
266 const char* mod_doc = "mymodule doc";
267 static PyModuleDef def;
268 def = {
269 PyModuleDef_HEAD_INIT,
270 "mymodule",
271 mod_doc,
272 };
273
274 PyObjectPtr module(PyModule_Create(&def));
275 ASSERT_NE(module, nullptr);
276 EXPECT_TRUE(PyModule_CheckExact(module));
277
278 PyObjectPtr orig_doc(PyObject_GetAttrString(module, "__doc__"));
279 EXPECT_TRUE(isUnicodeEqualsCStr(orig_doc, mod_doc));
280 EXPECT_EQ(PyErr_Occurred(), nullptr);
281
282 const char* edit_mod_doc = "edited doc";
283 int result = PyModule_SetDocString(module, edit_mod_doc);
284 ASSERT_EQ(result, 0);
285
286 PyObjectPtr edit_doc(PyObject_GetAttrString(module, "__doc__"));
287 EXPECT_TRUE(isUnicodeEqualsCStr(edit_doc, edit_mod_doc));
288 EXPECT_EQ(PyErr_Occurred(), nullptr);
289}
290
291TEST_F(ModuleExtensionApiTest, SetDocStringCreatesDoc) {
292 static PyModuleDef def;
293 def = {
294 PyModuleDef_HEAD_INIT,
295 "mymodule",
296 };
297
298 PyObjectPtr module(PyModule_Create(&def));
299 ASSERT_NE(module, nullptr);
300 EXPECT_TRUE(PyModule_CheckExact(module));
301
302 const char* edit_mod_doc = "edited doc";
303 ASSERT_EQ(PyModule_SetDocString(module, edit_mod_doc), 0);
304
305 PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__"));
306 EXPECT_TRUE(isUnicodeEqualsCStr(doc, edit_mod_doc));
307 EXPECT_EQ(PyErr_Occurred(), nullptr);
308}
309
310TEST_F(ModuleExtensionApiTest, SetDocStringSetsObjectAttribute) {
311 PyRun_SimpleString(R"(
312class C: pass
313not_a_module = C()
314)");
315 PyObjectPtr not_a_module(mainModuleGet("not_a_module"));
316 EXPECT_EQ(PyModule_SetDocString(not_a_module, "baz"), 0);
317 PyObjectPtr value(PyObject_GetAttrString(not_a_module, "__doc__"));
318 EXPECT_TRUE(isUnicodeEqualsCStr(value, "baz"));
319}
320
321TEST_F(ModuleExtensionApiTest, ModuleCreateDoesNotAddToModuleDict) {
322 const char* name = "mymodule";
323 static PyModuleDef def;
324 def = {
325 PyModuleDef_HEAD_INIT,
326 name,
327 };
328 PyObjectPtr module(PyModule_Create(&def));
329 ASSERT_NE(module, nullptr);
330 PyObject* mods = PyImport_GetModuleDict();
331 PyObjectPtr name_obj(PyUnicode_FromString(name));
332 EXPECT_EQ(PyDict_GetItem(mods, name_obj), nullptr);
333}
334
335TEST_F(ModuleExtensionApiTest, GetNameObjectGetsName) {
336 const char* mod_name = "mymodule";
337 static PyModuleDef def;
338 def = {
339 PyModuleDef_HEAD_INIT,
340 mod_name,
341 };
342
343 PyObject* module = PyModule_Create(&def);
344 ASSERT_NE(module, nullptr);
345 EXPECT_TRUE(PyModule_Check(module));
346
347 PyObject* result = PyModule_GetNameObject(module);
348 EXPECT_TRUE(isUnicodeEqualsCStr(result, mod_name));
349 EXPECT_EQ(PyErr_Occurred(), nullptr);
350 Py_DECREF(result);
351
352 Py_DECREF(module);
353}
354
355TEST_F(ModuleExtensionApiTest, GetNameObjectFailsIfNotModule) {
356 PyObject* not_a_module = PyTuple_New(10);
357 PyObject* result = PyModule_GetNameObject(not_a_module);
358 EXPECT_EQ(result, nullptr);
359
360 ASSERT_NE(PyErr_Occurred(), nullptr);
361 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
362
363 Py_DECREF(not_a_module);
364}
365
366TEST_F(ModuleExtensionApiTest, GetNameObjectFailsIfNotString) {
367 static PyModuleDef def;
368 def = {
369 PyModuleDef_HEAD_INIT,
370 "mymodule",
371 };
372
373 PyObject* module = PyModule_Create(&def);
374 ASSERT_NE(module, nullptr);
375 EXPECT_TRUE(PyModule_CheckExact(module));
376
377 PyObject* not_a_module = PyTuple_New(10);
378 PyObject_SetAttrString(module, "__name__", not_a_module);
379 PyObject* result = PyModule_GetNameObject(module);
380 EXPECT_EQ(result, nullptr);
381
382 ASSERT_NE(PyErr_Occurred(), nullptr);
383 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
384
385 Py_DECREF(module);
386 Py_DECREF(not_a_module);
387}
388
389TEST_F(ModuleExtensionApiTest, GetNameObjectWithModuleSubclassReturnsString) {
390 PyRun_SimpleString(R"(
391import builtins
392ModuleType = type(builtins)
393class C(ModuleType):
394 pass
395module = C("foo")
396)");
397 PyObjectPtr module(mainModuleGet("module"));
398 PyObjectPtr result(PyModule_GetNameObject(module));
399 EXPECT_TRUE(isUnicodeEqualsCStr(result, "foo"));
400}
401
402TEST_F(ModuleExtensionApiTest, GetFilenameObjectReturnsFilename) {
403 static PyModuleDef def;
404 def = {
405 PyModuleDef_HEAD_INIT,
406 "mymodule",
407 };
408
409 testing::PyObjectPtr module(PyModule_Create(&def));
410 ASSERT_NE(module, nullptr);
411 EXPECT_TRUE(PyModule_Check(module));
412
413 const char* filename = "file";
414 PyModule_AddObject(module, "__file__", PyUnicode_FromString(filename));
415 testing::PyObjectPtr result(PyModule_GetFilenameObject(module));
416 EXPECT_TRUE(isUnicodeEqualsCStr(result, filename));
417 EXPECT_EQ(PyErr_Occurred(), nullptr);
418}
419
420TEST_F(ModuleExtensionApiTest, GetFilenameObjectWithSubclassReturnsFilename) {
421 PyRun_SimpleString(R"(
422import builtins
423ModuleType = type(builtins)
424class C(ModuleType):
425 __file__ = "bar"
426module = C("foo")
427module.__file__ = "baz"
428)");
429 PyObjectPtr module(mainModuleGet("module"));
430 PyObjectPtr result(PyModule_GetFilenameObject(module));
431 EXPECT_TRUE(isUnicodeEqualsCStr(result, "baz"));
432}
433
434TEST_F(ModuleExtensionApiTest, GetFilenameObjectFailsIfNotModule) {
435 testing::PyObjectPtr not_a_module(PyLong_FromLong(1));
436 testing::PyObjectPtr result(PyModule_GetFilenameObject(not_a_module));
437 EXPECT_EQ(result, nullptr);
438 ASSERT_NE(PyErr_Occurred(), nullptr);
439 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
440}
441
442TEST_F(ModuleExtensionApiTest, GetFilenameObjectFailsIfFilenameNotString) {
443 static PyModuleDef def;
444 def = {
445 PyModuleDef_HEAD_INIT,
446 "mymodule",
447 };
448
449 PyObjectPtr module(PyModule_Create(&def));
450 ASSERT_NE(module, nullptr);
451 EXPECT_TRUE(PyModule_CheckExact(module));
452
453 PyObject* not_a_string = PyLong_FromLong(1);
454
455 PyModule_AddObject(module, "__file__", not_a_string);
456 testing::PyObjectPtr result(PyModule_GetFilenameObject(module));
457 EXPECT_EQ(result, nullptr);
458
459 ASSERT_NE(PyErr_Occurred(), nullptr);
460 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
461}
462
463TEST_F(ModuleExtensionApiTest, ExecDefReturnsZeroWithNoSlots) {
464 static PyModuleDef def;
465 def = {
466 PyModuleDef_HEAD_INIT,
467 "mymodule",
468 };
469
470 testing::PyObjectPtr module(PyModule_Create(&def));
471 ASSERT_NE(module, nullptr);
472 EXPECT_TRUE(PyModule_CheckExact(module));
473
474 EXPECT_EQ(PyModule_ExecDef(module, &def), 0);
475 EXPECT_EQ(PyErr_Occurred(), nullptr);
476}
477
478TEST_F(ModuleExtensionApiTest, ExecDefFailsIfPassedNamelessModule) {
479 static PyModuleDef def;
480 def = {
481 PyModuleDef_HEAD_INIT,
482 "mymodule",
483 };
484
485 testing::PyObjectPtr module(PyModule_NewObject(Py_None));
486 ASSERT_NE(module, nullptr);
487 EXPECT_TRUE(PyModule_CheckExact(module));
488
489 EXPECT_EQ(PyModule_ExecDef(module, &def), -1);
490 EXPECT_NE(PyErr_Occurred(), nullptr);
491}
492
493// TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython
494TEST_F(ModuleExtensionApiTest, ExecDefFailsIfDefHasUnknownSlotPyro) {
495 slot_func mod_exec = [](PyObject* module) {
496 PyModule_SetDocString(module, "testing");
497 return 0;
498 };
499
500 static PyModuleDef_Slot slots[] = {
501 {-1, reinterpret_cast<void*>(mod_exec)},
502 {0, nullptr},
503 };
504 static PyModuleDef def;
505 def = {
506 PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots,
507 };
508
509 testing::PyObjectPtr module(PyModule_Create(&def));
510 ASSERT_NE(module, nullptr);
511 EXPECT_TRUE(PyModule_CheckExact(module));
512
513 EXPECT_EQ(PyModule_ExecDef(module, &def), -1);
514 ASSERT_NE(PyErr_Occurred(), nullptr);
515 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
516}
517
518// TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython
519TEST_F(ModuleExtensionApiTest, ExecDefRunsCorrectSingleSlotPyro) {
520 slot_func mod_exec = [](PyObject* module) {
521 PyModule_SetDocString(module, "testing");
522 return 0;
523 };
524
525 static PyModuleDef_Slot slots[] = {
526 {Py_mod_exec, reinterpret_cast<void*>(mod_exec)},
527 {0, nullptr},
528 };
529 static PyModuleDef def;
530 def = {
531 PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots,
532 };
533
534 testing::PyObjectPtr module(PyModule_Create(&def));
535 ASSERT_NE(module, nullptr);
536 EXPECT_TRUE(PyModule_CheckExact(module));
537
538 EXPECT_EQ(PyModule_ExecDef(module, &def), 0);
539
540 testing::PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__"));
541 EXPECT_TRUE(isUnicodeEqualsCStr(doc, "testing"));
542 EXPECT_EQ(PyErr_Occurred(), nullptr);
543}
544
545// TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython
546TEST_F(ModuleExtensionApiTest, ExecDefRunsMultipleSlotsInOrderPyro) {
547 slot_func mod_exec = [](PyObject* module) {
548 PyModule_SetDocString(module, "doc test");
549 return 0;
550 };
551
552 slot_func mod_exec_second = [](PyObject* module) {
553 PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__"));
554 if (doc != nullptr) {
555 PyObjectPtr attr(PyUnicode_FromString("testing1"));
556 PyObject_SetAttrString(module, "test1", attr);
557 }
558 return 0;
559 };
560
561 slot_func mod_exec_third = [](PyObject* module) {
562 PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__"));
563 if (doc != nullptr) {
564 PyObjectPtr attr(PyUnicode_FromString("testing2"));
565 PyObject_SetAttrString(module, "test2", attr);
566 }
567 return 0;
568 };
569
570 static PyModuleDef_Slot slots[] = {
571 {Py_mod_exec, reinterpret_cast<void*>(mod_exec)},
572 {Py_mod_exec, reinterpret_cast<void*>(mod_exec_second)},
573 {Py_mod_exec, reinterpret_cast<void*>(mod_exec_third)},
574 {0, nullptr},
575 };
576 static PyModuleDef def;
577 def = {
578 PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots,
579 };
580
581 testing::PyObjectPtr module(PyModule_Create(&def));
582 ASSERT_NE(module, nullptr);
583 EXPECT_TRUE(PyModule_CheckExact(module));
584
585 EXPECT_EQ(PyModule_ExecDef(module, &def), 0);
586
587 testing::PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__"));
588 EXPECT_TRUE(isUnicodeEqualsCStr(doc, "doc test"));
589 testing::PyObjectPtr test_attr_one(PyObject_GetAttrString(module, "test1"));
590 EXPECT_TRUE(isUnicodeEqualsCStr(test_attr_one, "testing1"));
591 testing::PyObjectPtr test_attr_two(PyObject_GetAttrString(module, "test2"));
592 EXPECT_TRUE(isUnicodeEqualsCStr(test_attr_two, "testing2"));
593 EXPECT_EQ(PyErr_Occurred(), nullptr);
594}
595
596// TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython
597TEST_F(ModuleExtensionApiTest, ExecDefFailsIfSlotHasErrorButReturnsZeroPyro) {
598 slot_func mod_exec_fail_silently = [](PyObject* module) {
599 testing::PyObjectPtr attr(PyObject_GetAttrString(module, "non-existent"));
600 static_cast<void>(attr);
601 return 0;
602 };
603
604 static PyModuleDef_Slot slots[] = {
605 {Py_mod_exec, reinterpret_cast<void*>(mod_exec_fail_silently)},
606 {0, nullptr},
607 };
608 static PyModuleDef def;
609 def = {
610 PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots,
611 };
612
613 testing::PyObjectPtr module(PyModule_Create(&def));
614 ASSERT_NE(module, nullptr);
615 EXPECT_TRUE(PyModule_CheckExact(module));
616
617 EXPECT_EQ(PyModule_ExecDef(module, &def), -1);
618 ASSERT_NE(PyErr_Occurred(), nullptr);
619 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
620}
621
622// TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython
623TEST_F(ModuleExtensionApiTest, ExecDefFailsIfSlotFailsButDoesntSetErrorPyro) {
624 slot_func mod_exec_fail_no_error = [](PyObject* module) {
625 testing::PyObjectPtr attr(PyObject_GetAttrString(module, "non-existent"));
626 static_cast<void>(attr);
627 PyErr_Clear();
628 return -1;
629 };
630
631 static PyModuleDef_Slot slots[] = {
632 {Py_mod_exec, reinterpret_cast<void*>(mod_exec_fail_no_error)},
633 {0, nullptr},
634 };
635 static PyModuleDef def;
636 def = {
637 PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots,
638 };
639
640 testing::PyObjectPtr module(PyModule_Create(&def));
641 ASSERT_NE(module, nullptr);
642 EXPECT_TRUE(PyModule_CheckExact(module));
643
644 EXPECT_EQ(PyModule_ExecDef(module, &def), -1);
645 ASSERT_NE(PyErr_Occurred(), nullptr);
646 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
647}
648
649// TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython
650TEST_F(ModuleExtensionApiTest, ExecDefFailsIfSlotFailsAndPropogatesErrorPyro) {
651 slot_func mod_exec_fail = [](PyObject* module) {
652 testing::PyObjectPtr attr(PyObject_GetAttrString(module, "non-existent"));
653 static_cast<void>(attr);
654 return -1;
655 };
656
657 static PyModuleDef_Slot slots[] = {
658 {Py_mod_exec, reinterpret_cast<void*>(mod_exec_fail)},
659 {0, nullptr},
660 };
661 static PyModuleDef def;
662 def = {
663 PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots,
664 };
665
666 testing::PyObjectPtr module(PyModule_Create(&def));
667 ASSERT_NE(module, nullptr);
668 EXPECT_TRUE(PyModule_CheckExact(module));
669
670 EXPECT_EQ(PyModule_ExecDef(module, &def), -1);
671 ASSERT_NE(PyErr_Occurred(), nullptr);
672 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
673}
674
675TEST_F(ModuleExtensionApiTest, GetNameGetsName) {
676 const char* mod_name = "mymodule";
677 static PyModuleDef def;
678 def = {
679 PyModuleDef_HEAD_INIT,
680 mod_name,
681 };
682
683 testing::PyObjectPtr module(PyModule_Create(&def));
684 ASSERT_NE(module, nullptr);
685 EXPECT_TRUE(PyModule_Check(module));
686
687 EXPECT_STREQ(PyModule_GetName(module), mod_name);
688 EXPECT_EQ(PyErr_Occurred(), nullptr);
689}
690
691TEST_F(ModuleExtensionApiTest, GetNameReturnsNullIfNoName) {
692 testing::PyObjectPtr not_a_module(PyLong_FromLong(1));
693 EXPECT_EQ(PyModule_GetName(not_a_module), nullptr);
694 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
695}
696
697TEST_F(ModuleExtensionApiTest, GetNameDoesNotIncrementModuleNameRefcount) {
698 const char* mod_name = "mymodule";
699 static PyModuleDef def;
700 def = {
701 PyModuleDef_HEAD_INIT,
702 mod_name,
703 };
704
705 testing::PyObjectPtr module(PyModule_Create(&def));
706 ASSERT_NE(module, nullptr);
707 EXPECT_TRUE(PyModule_Check(module));
708
709 PyObjectPtr name(PyModule_GetNameObject(module));
710 EXPECT_TRUE(isUnicodeEqualsCStr(name, mod_name));
711
712 Py_ssize_t name_count = Py_REFCNT(name);
713 EXPECT_STREQ(PyModule_GetName(module), mod_name);
714 EXPECT_EQ(Py_REFCNT(name), name_count);
715 EXPECT_EQ(PyErr_Occurred(), nullptr);
716}
717
718TEST_F(ModuleExtensionApiTest, MethodWithClassFlagRaisesException) {
719 binaryfunc foo_func = [](PyObject*, PyObject*) {
720 return PyLong_FromLong(10);
721 };
722 PyMethodDef foo_methods[] = {
723 {"longValue", foo_func, METH_NOARGS | METH_CLASS}, {nullptr}};
724 static PyModuleDef def;
725 def = {
726 PyModuleDef_HEAD_INIT, "foo", nullptr, 0, foo_methods,
727 };
728 PyObjectPtr module(PyModule_Create(&def));
729 EXPECT_EQ(module, nullptr);
730 EXPECT_NE(PyErr_Occurred(), nullptr);
731 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
732}
733
734static PyObject* init_extra_builtin_module(void) {
735 static PyModuleDef def;
736 def = {PyModuleDef_HEAD_INIT, "extra_builtin"};
737 return PyModule_Create(&def);
738}
739
740static PyObject* init_extra_extra_builtin_module(void) {
741 static PyModuleDef def;
742 def = {PyModuleDef_HEAD_INIT, "extra_extra_builtin"};
743 return PyModule_Create(&def);
744}
745
746TEST(ModuleExtensionApiTestNoFixture, PyImportAppendInittabExtendInittab) {
747 resetPythonEnv();
748 PyImport_AppendInittab("extra_builtin", init_extra_builtin_module);
749 PyImport_AppendInittab("extra_extra_builtin",
750 init_extra_extra_builtin_module);
751 Py_Initialize();
752
753 PyRun_SimpleString(R"(
754import sys
755a = "extra_builtin" in sys.builtin_module_names
756b = "extra_extra_builtin" in sys.builtin_module_names
757c = "not_added" in sys.builtin_module_names
758)");
759 ASSERT_EQ(PyErr_Occurred(), nullptr);
760 PyObjectPtr pybool_true(PyBool_FromLong(1));
761 PyObjectPtr pybool_false(PyBool_FromLong(0));
762 PyObjectPtr a(mainModuleGet("a"));
763 PyObjectPtr b(mainModuleGet("b"));
764 PyObjectPtr c(mainModuleGet("c"));
765
766 ASSERT_EQ(pybool_true, a);
767 ASSERT_EQ(pybool_true, b);
768 ASSERT_EQ(pybool_false, c);
769
770 Py_FinalizeEx();
771}
772
773} // namespace testing
774} // namespace py