1
1
import importlib .util
2
+ import os .path
2
3
import sys
3
4
import types
4
5
import unittest
5
6
from test .support import import_helper
6
7
from test .support .warnings_helper import check_warnings
7
8
8
9
_testlimitedcapi = import_helper .import_module ('_testlimitedcapi' )
10
+ NULL = None
9
11
10
12
11
13
class ImportTests (unittest .TestCase ):
@@ -36,7 +38,7 @@ def check_import_loaded_module(self, import_module):
36
38
def check_import_fresh_module (self , import_module ):
37
39
old_modules = dict (sys .modules )
38
40
try :
39
- for name in ('colorsys' , 'datetime' , ' math' ):
41
+ for name in ('colorsys' , 'math' ):
40
42
with self .subTest (name = name ):
41
43
sys .modules .pop (name , None )
42
44
module = import_module (name )
@@ -57,32 +59,43 @@ def test_getmodule(self):
57
59
self .assertIsNone (_testlimitedcapi .PyImport_GetModule ('' ))
58
60
self .assertIsNone (_testlimitedcapi .PyImport_GetModule (object ()))
59
61
60
- def check_addmodule (self , add_module ):
62
+ def check_addmodule (self , add_module , accept_nonstr = False ):
61
63
# create a new module
62
- name = 'nonexistent'
63
- self .assertNotIn (name , sys .modules )
64
- try :
65
- module = add_module (name )
66
- self .assertIsInstance (module , types .ModuleType )
67
- self .assertIs (module , sys .modules [name ])
68
- finally :
69
- sys .modules .pop (name , None )
64
+ names = ['nonexistent' ]
65
+ if accept_nonstr :
66
+ # PyImport_AddModuleObject() accepts non-string names
67
+ names .append (object ())
68
+ for name in names :
69
+ with self .subTest (name = name ):
70
+ self .assertNotIn (name , sys .modules )
71
+ try :
72
+ module = add_module (name )
73
+ self .assertIsInstance (module , types .ModuleType )
74
+ self .assertEqual (module .__name__ , name )
75
+ self .assertIs (module , sys .modules [name ])
76
+ finally :
77
+ sys .modules .pop (name , None )
70
78
71
79
# get an existing module
72
80
self .check_import_loaded_module (add_module )
73
81
74
82
def test_addmoduleobject (self ):
75
83
# Test PyImport_AddModuleObject()
76
- self .check_addmodule (_testlimitedcapi .PyImport_AddModuleObject )
84
+ self .check_addmodule (_testlimitedcapi .PyImport_AddModuleObject ,
85
+ accept_nonstr = True )
77
86
78
87
def test_addmodule (self ):
79
88
# Test PyImport_AddModule()
80
89
self .check_addmodule (_testlimitedcapi .PyImport_AddModule )
81
90
91
+ # CRASHES PyImport_AddModule(NULL)
92
+
82
93
def test_addmoduleref (self ):
83
94
# Test PyImport_AddModuleRef()
84
95
self .check_addmodule (_testlimitedcapi .PyImport_AddModuleRef )
85
96
97
+ # CRASHES PyImport_AddModuleRef(NULL)
98
+
86
99
def check_import_func (self , import_module ):
87
100
self .check_import_loaded_module (import_module )
88
101
self .check_import_fresh_module (import_module )
@@ -106,19 +119,121 @@ def test_importmodulenoblock(self):
106
119
with check_warnings (('' , DeprecationWarning )):
107
120
self .check_import_func (_testlimitedcapi .PyImport_ImportModuleNoBlock )
108
121
109
- # TODO: test PyImport_ExecCodeModule()
110
- # TODO: test PyImport_ExecCodeModuleEx()
111
- # TODO: test PyImport_ExecCodeModuleWithPathnames()
112
- # TODO: test PyImport_ExecCodeModuleObject()
113
- # TODO: test PyImport_ImportModuleLevel()
114
- # TODO: test PyImport_ImportModuleLevelObject()
115
- # TODO: test PyImport_ImportModuleEx()
122
+ def check_frozen_import (self , import_frozen_module ):
123
+ # Importing a frozen module executes its code, so starts by unloading
124
+ # the module to execute the code in a new (temporary) module.
125
+ old_zipimport = sys .modules .pop ('zipimport' )
126
+ try :
127
+ self .assertEqual (import_frozen_module ('zipimport' ), 1 )
128
+ finally :
129
+ sys .modules ['zipimport' ] = old_zipimport
130
+
131
+ # not a frozen module
132
+ self .assertEqual (import_frozen_module ('sys' ), 0 )
133
+
134
+ def test_importfrozenmodule (self ):
135
+ # Test PyImport_ImportFrozenModule()
136
+ self .check_frozen_import (_testlimitedcapi .PyImport_ImportFrozenModule )
137
+
138
+ # CRASHES PyImport_ImportFrozenModule(NULL)
139
+
140
+ def test_importfrozenmoduleobject (self ):
141
+ # Test PyImport_ImportFrozenModuleObject()
142
+ PyImport_ImportFrozenModuleObject = _testlimitedcapi .PyImport_ImportFrozenModuleObject
143
+ self .check_frozen_import (PyImport_ImportFrozenModuleObject )
144
+
145
+ # Bad name is treated as "not found"
146
+ self .assertEqual (PyImport_ImportFrozenModuleObject (None ), 0 )
147
+
148
+ def test_importmoduleex (self ):
149
+ # Test PyImport_ImportModuleEx()
150
+ def import_module (name ):
151
+ return _testlimitedcapi .PyImport_ImportModuleEx (
152
+ name , globals (), {}, [])
153
+
154
+ self .check_import_func (import_module )
155
+
156
+ def test_importmodulelevel (self ):
157
+ # Test PyImport_ImportModuleLevel()
158
+ def import_module (name ):
159
+ return _testlimitedcapi .PyImport_ImportModuleLevel (
160
+ name , globals (), {}, [], 0 )
161
+
162
+ self .check_import_func (import_module )
163
+
164
+ def test_importmodulelevelobject (self ):
165
+ # Test PyImport_ImportModuleLevelObject()
166
+ def import_module (name ):
167
+ return _testlimitedcapi .PyImport_ImportModuleLevelObject (
168
+ name , globals (), {}, [], 0 )
169
+
170
+ self .check_import_func (import_module )
171
+
172
+ def check_executecodemodule (self , execute_code , pathname = None ):
173
+ name = 'test_import_executecode'
174
+ try :
175
+ # Create a temporary module where the code will be executed
176
+ self .assertNotIn (name , sys .modules )
177
+ module = _testlimitedcapi .PyImport_AddModuleRef (name )
178
+ self .assertNotHasAttr (module , 'attr' )
179
+
180
+ # Execute the code
181
+ if pathname is not None :
182
+ code_filename = pathname
183
+ else :
184
+ code_filename = '<string>'
185
+ code = compile ('attr = 1' , code_filename , 'exec' )
186
+ module2 = execute_code (name , code )
187
+ self .assertIs (module2 , module )
188
+
189
+ # Check the function side effects
190
+ self .assertEqual (module .attr , 1 )
191
+ if pathname is not None :
192
+ self .assertEqual (module .__spec__ .origin , pathname )
193
+ finally :
194
+ sys .modules .pop (name , None )
195
+
196
+ def test_executecodemodule (self ):
197
+ # Test PyImport_ExecCodeModule()
198
+ self .check_executecodemodule (_testlimitedcapi .PyImport_ExecCodeModule )
199
+
200
+ def test_executecodemoduleex (self ):
201
+ # Test PyImport_ExecCodeModuleEx()
202
+ pathname = os .path .abspath ('pathname' )
203
+
204
+ def execute_code (name , code ):
205
+ return _testlimitedcapi .PyImport_ExecCodeModuleEx (name , code ,
206
+ pathname )
207
+ self .check_executecodemodule (execute_code , pathname )
208
+
209
+ def check_executecode_pathnames (self , execute_code_func ):
210
+ # Test non-NULL pathname and NULL cpathname
211
+ pathname = os .path .abspath ('pathname' )
212
+
213
+ def execute_code1 (name , code ):
214
+ return execute_code_func (name , code , pathname , NULL )
215
+ self .check_executecodemodule (execute_code1 , pathname )
216
+
217
+ # Test NULL pathname and non-NULL cpathname
218
+ pyc_filename = importlib .util .cache_from_source (__file__ )
219
+ py_filename = importlib .util .source_from_cache (pyc_filename )
220
+
221
+ def execute_code2 (name , code ):
222
+ return execute_code_func (name , code , NULL , pyc_filename )
223
+ self .check_executecodemodule (execute_code2 , py_filename )
224
+
225
+ def test_executecodemodulewithpathnames (self ):
226
+ # Test PyImport_ExecCodeModuleWithPathnames()
227
+ self .check_executecode_pathnames (_testlimitedcapi .PyImport_ExecCodeModuleWithPathnames )
228
+
229
+ def test_executecodemoduleobject (self ):
230
+ # Test PyImport_ExecCodeModuleObject()
231
+ self .check_executecode_pathnames (_testlimitedcapi .PyImport_ExecCodeModuleObject )
232
+
116
233
# TODO: test PyImport_GetImporter()
117
234
# TODO: test PyImport_ReloadModule()
118
- # TODO: test PyImport_ImportFrozenModuleObject()
119
- # TODO: test PyImport_ImportFrozenModule()
120
- # TODO: test PyImport_AppendInittab()
121
235
# TODO: test PyImport_ExtendInittab()
236
+ # PyImport_AppendInittab() is tested by test_embed
122
237
123
238
124
239
if __name__ == "__main__" :
0 commit comments