File: test_module.py

package info (click to toggle)
pypy3 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 111,848 kB
  • sloc: python: 1,291,746; ansic: 74,281; asm: 5,187; cpp: 3,017; sh: 2,533; makefile: 544; xml: 243; lisp: 45; csh: 21; awk: 4
file content (250 lines) | stat: -rw-r--r-- 9,886 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
import pytest
from pypy.interpreter.error import OperationError
from pypy.module.cpyext.modsupport import PyModule_New, PyModule_GetName
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
from rpython.rtyper.lltypesystem import rffi


class TestModuleObject(BaseApiTest):
    def test_module_new(self, space):
        with rffi.scoped_str2charp('testname') as buf:
            w_mod = PyModule_New(space, buf)
        assert space.eq_w(space.getattr(w_mod, space.newtext('__name__')),
                          space.newtext('testname'))

    def test_module_getname(self, space):
        w_sys = space.wrap(space.sys)
        p = PyModule_GetName(space, w_sys)
        assert rffi.charp2str(p) == 'sys'
        p2 = PyModule_GetName(space, w_sys)
        assert p2 == p
        with pytest.raises(OperationError) as excinfo:
            PyModule_GetName(space, space.w_True)
        assert excinfo.value.w_type is space.w_SystemError


class AppTestModuleObject(AppTestCpythonExtensionBase):
    def test_getdef(self):
        module = self.import_extension('foo', [
            ("check_getdef_same", "METH_NOARGS",
             """
                 return PyBool_FromLong(PyModule_GetDef(self) == &moduledef);
             """
            )], prologue="""
            static struct PyModuleDef moduledef;
            """)
        assert module.check_getdef_same()

    def test_getstate(self):
        module = self.import_extension('foo', [
            ("check_mod_getstate", "METH_NOARGS",
             """
                 struct module_state { int foo[51200]; };
                 static struct PyModuleDef moduledef = {
                     PyModuleDef_HEAD_INIT,
                     "module_getstate_myextension",
                     NULL,
                     sizeof(struct module_state)
                 };
                 PyObject *module = PyModule_Create(&moduledef);
                 int *p = (int *)PyModule_GetState(module);
                 int i;
                 for (i = 0; i < 51200; i++)
                     if (p[i] != 0)
                         return PyBool_FromLong(0);
                 Py_DECREF(module);
                 return PyBool_FromLong(1);
             """
            )])
        assert module.check_mod_getstate()


class AppTestMultiPhase(AppTestCpythonExtensionBase):
    def test_basic(self):
        from types import ModuleType
        module = self.import_module(name='multiphase')
        assert isinstance(module, ModuleType)
        assert module.__name__ == 'multiphase'
        assert module.__doc__ == "example docstring"

    def test_getdef(self):
        from types import ModuleType
        module = self.import_module(name='multiphase')
        assert module.check_getdef_same()

    def test_slots(self):
        from types import ModuleType
        body = """
        static PyModuleDef multiphase_def;

        static PyObject* multiphase_create(PyObject *spec, PyModuleDef *def) {
            PyObject *module = PyModule_New("altname");
            PyObject_SetAttrString(module, "create_spec", spec);
            PyObject_SetAttrString(module, "create_def_eq",
                                   PyBool_FromLong(def == &multiphase_def));
            return module;
        }

        static int multiphase_exec(PyObject* module) {
            Py_INCREF(Py_True);
            PyObject_SetAttrString(module, "exec_called", Py_True);
            return 0;
        }

        static PyModuleDef_Slot multiphase_slots[] = {
            {Py_mod_create, multiphase_create},
            {Py_mod_exec, multiphase_exec},
            {0, NULL}
        };

        static PyModuleDef multiphase_def = {
            PyModuleDef_HEAD_INIT,                      /* m_base */
            "multiphase",                               /* m_name */
            "example docstring",                        /* m_doc */
            0,                                          /* m_size */
            NULL,                                       /* m_methods */
            multiphase_slots,                           /* m_slots */
            NULL,                                       /* m_traverse */
            NULL,                                       /* m_clear */
            NULL,                                       /* m_free */
        };
        """
        init = """
        return PyModuleDef_Init(&multiphase_def);
        """
        module = self.import_module(name='multiphase', body=body, init=init)
        assert module.create_spec
        assert module.create_spec is module.__spec__
        assert module.create_def_eq
        assert module.exec_called

    def test_forget_init(self):
        from types import ModuleType
        body = """
        static PyModuleDef multiphase_def = {
            PyModuleDef_HEAD_INIT,                      /* m_base */
            "multiphase",                               /* m_name */
            "example docstring",                        /* m_doc */
            0,                                          /* m_size */
        };
        """
        init = """
        return (PyObject *) &multiphase_def;
        """
        raises(SystemError, self.import_module, name='multiphase', body=body,
               init=init)

class AppTestMultiPhase2(AppTestCpythonExtensionBase):
    def setup_class(cls):
        cls.w_name = cls.space.wrap('multiphase2')
        AppTestCpythonExtensionBase.setup_class.im_func(cls)

    def test_multiphase2(self):
        import sys
        from importlib import machinery, util
        module = self.import_module(name=self.name)
        finder = machinery.FileFinder(None)
        spec = util.find_spec(self.name)
        assert spec
        assert module.__name__ == self.name
        #assert module.__file__ == spec.origin
        assert module.__package__ == ''
        raises(AttributeError, 'module.__path__')
        assert module is sys.modules[self.name]
        assert isinstance(module.__loader__, machinery.ExtensionFileLoader)

    def test_functionality(self):
        import types
        module = self.import_module(name=self.name)
        assert isinstance(module, types.ModuleType)
        ex = module.Example()
        assert ex.demo('abcd') == 'abcd'
        assert ex.demo() is None
        raises(AttributeError, 'ex.abc')
        ex.abc = 0
        assert ex.abc == 0
        assert module.foo(9, 9) == 18
        assert isinstance(module.Str(), str)
        assert module.Str(1) + '23' == '123'
        raises(module.error, 'raise module.error()')
        assert module.int_const == 1969
        assert module.str_const == 'something different'

    def test_reload(self):
        import importlib
        module = self.import_module(name=self.name)
        ex_class = module.Example
        # Simulate what importlib.reload() does, without recomputing the spec
        module.__spec__.loader.exec_module(module)
        assert ex_class is module.Example

    def w_load_from_name(self, name, origin=None, use_prefix=True):
        from importlib import machinery, util
        if not origin:
            module = self.import_module(name=self.name)
            origin = module.__loader__.path
        if use_prefix:
            name = '_testmultiphase_' + name
        loader = machinery.ExtensionFileLoader(name, origin)
        spec = util.spec_from_loader(name, loader)
        module = util.module_from_spec(spec)
        loader.exec_module(module)
        return module

    def test_bad_modules(self):
        # XXX: not a very good test, since most internal issues in cpyext
        # cause SystemErrors.
        module = self.import_module(name=self.name)
        origin = module.__loader__.path
        for name in [
                'bad_slot_large',
                'bad_slot_negative',
                'create_int_with_state',
                'negative_size',
                'create_null',
                'create_raise',
                'create_unreported_exception',
                'nonmodule_with_exec_slots',
                'exec_err',
                'exec_raise',
                'exec_unreported_exception',
                ]:
            raises(SystemError, self.load_from_name, name, origin)

    def test_export_null(self):
        excinfo = raises(SystemError, self.load_from_name, 'export_null')
        assert "initialization" in excinfo.value.args[0]
        assert "without raising" in excinfo.value.args[0]

    def test_export_uninit(self):
        excinfo = raises(SystemError, self.load_from_name, 'export_uninitialized')
        assert "init function" in excinfo.value.args[0]
        assert "uninitialized object" in excinfo.value.args[0]

    def test_export_raise(self):
        excinfo = raises(SystemError, self.load_from_name, 'export_raise')
        assert "bad export function" == excinfo.value.args[0]

    def test_export_unreported(self):
        excinfo = raises(SystemError, self.load_from_name, 'export_unreported_exception')
        assert "initialization" in excinfo.value.args[0]
        assert "unreported exception" in excinfo.value.args[0]

    def test_unloadable_nonascii(self):
        name = u"fo\xf3"
        excinfo = raises(ImportError, self.load_from_name, name)
        assert excinfo.value.name == '_testmultiphase_' + name

    def test_nonascii(self):
        module = self.import_module(name=self.name)
        origin = module.__loader__.path
        cases = [
            ('_testmultiphase_zkou\u0161ka_na\u010dten\xed', 'Czech'),
            ('\uff3f\u30a4\u30f3\u30dd\u30fc\u30c8\u30c6\u30b9\u30c8',
             'Japanese'),
            ]
        for name, lang in cases:
            module = self.load_from_name(name, origin=origin, use_prefix=False)
            assert module.__name__ == name
            assert module.__doc__ == "Module named in %s" % lang