def test_frozentable(self): # Python exports a PyImport_FrozenModules symbol. This is a # pointer to an array of struct _frozen entries. The end of the # array is marked by an entry containing a NULL name and zero # size. # In standard Python, this table contains a __hello__ # module, and a __phello__ package containing a spam # module. class struct_frozen(Structure): _fields_ = [ ("name", c_char_p), ("code", POINTER(c_ubyte)), ("size", c_int), ("is_package", c_bool), ("get_code", POINTER(c_ubyte)), # Function ptr ] FrozenTable = POINTER(struct_frozen) modules = [] for group in ["Bootstrap", "Stdlib", "Test"]: ft = FrozenTable.in_dll(pythonapi, f"_PyImport_Frozen{group}") # ft is a pointer to the struct_frozen entries: for entry in ft: # This is dangerous. We *can* iterate over a pointer, but # the loop will not terminate (maybe with an access # violation;-) because the pointer instance has no size. if entry.name is None: break modname = entry.name.decode("ascii") modules.append(modname) with self.subTest(modname): if entry.size != 0: # Do a sanity check on entry.size and entry.code. self.assertGreater(abs(entry.size), 10) self.assertTrue( [entry.code[i] for i in range(abs(entry.size))]) # Check the module's package-ness. with import_helper.frozen_modules(): spec = importlib.util.find_spec(modname) if entry.is_package: # It's a package. self.assertIsNotNone(spec.submodule_search_locations) else: self.assertIsNone(spec.submodule_search_locations) with import_helper.frozen_modules(): expected = _imp._frozen_module_names() self.maxDiff = None self.assertEqual( modules, expected, "_PyImport_FrozenBootstrap example " "in Doc/library/ctypes.rst may be out of date") from ctypes import _pointer_type_cache del _pointer_type_cache[struct_frozen]
def test_frozen_submodule_in_unfrozen_package(self): with import_helper.CleanImport('__phello__', '__phello__.spam'): with import_helper.frozen_modules(enabled=False): import __phello__ with import_helper.frozen_modules(enabled=True): import __phello__.spam as spam self.assertIs(spam, __phello__.spam) self.assertIsNot(__phello__.__spec__.loader, importlib.machinery.FrozenImporter) self.assertIs(spam.__spec__.loader, importlib.machinery.FrozenImporter)
def exec_module(self, name, origname=None): with import_helper.frozen_modules(): is_package = self.machinery.FrozenImporter.is_package(name) spec = self.machinery.ModuleSpec( name, self.machinery.FrozenImporter, origin='frozen', is_package=is_package, loader_state=types.SimpleNamespace( origname=origname or name, filename=resolve_stdlib_file(origname or name, is_package), ), ) module = types.ModuleType(name) module.__spec__ = spec assert not hasattr(module, 'initialized') with fresh(name): self.machinery.FrozenImporter.exec_module(module) with captured_stdout() as stdout: module.main() self.assertTrue(module.initialized) self.assertTrue(hasattr(module, '__spec__')) self.assertEqual(module.__spec__.origin, 'frozen') return module, stdout.getvalue()
def test_unloadable(self): with import_helper.frozen_modules(): with deprecated(): assert self.machinery.FrozenImporter.find_module('_not_real') is None with self.assertRaises(ImportError) as cm: self.load_module('_not_real') self.assertEqual(cm.exception.name, '_not_real')
def exec_module(self, name): with import_helper.frozen_modules(): is_package = self.machinery.FrozenImporter.is_package(name) code = _imp.get_frozen_object(name) data = marshal.dumps(code) spec = self.machinery.ModuleSpec( name, self.machinery.FrozenImporter, origin='frozen', is_package=is_package, loader_state=data, ) module = types.ModuleType(name) module.__spec__ = spec assert not hasattr(module, 'initialized') with fresh(name): self.machinery.FrozenImporter.exec_module(module) with captured_stdout() as stdout: module.main() self.assertTrue(module.initialized) self.assertTrue(hasattr(module, '__spec__')) self.assertEqual(module.__spec__.origin, 'frozen') return module, stdout.getvalue()
def test_failure(self): # Raise ImportError for modules that are not frozen. for meth_name in ('get_code', 'get_source', 'is_package'): method = getattr(self.machinery.FrozenImporter, meth_name) with self.assertRaises(ImportError) as cm: with import_helper.frozen_modules(): method('importlib') self.assertEqual(cm.exception.name, 'importlib')
def test_is_package(self): # Should be able to tell what is a package. test_for = (('__hello__', False), ('__phello__', True), ('__phello__.spam', False)) for name, is_package in test_for: with import_helper.frozen_modules(): result = self.machinery.FrozenImporter.is_package(name) self.assertEqual(bool(result), is_package)
def fresh(name, *, oldapi=False): with util.uncache(name): with import_helper.frozen_modules(): if oldapi: with deprecated(): yield else: yield
def check_data(self, spec): with import_helper.frozen_modules(): expected = _imp.get_frozen_object(spec.name) data = spec.loader_state # We can't compare the marshaled data directly because # marshal.dumps() would mark "expected" as a ref, which slightly # changes the output. (See https://bugs.python.org/issue34093.) code = marshal.loads(data) self.assertEqual(code, expected)
def test_not_using_frozen(self): finder = self.machinery.FrozenImporter with import_helper.frozen_modules(enabled=False): # both frozen and not frozen spec1 = finder.find_spec('__hello__') # only frozen spec2 = finder.find_spec('__hello_only__') self.assertIsNone(spec1) self.assertIsNone(spec2)
def test_frozen(self): name = '__hello__' if name in sys.modules: del sys.modules[name] with import_helper.frozen_modules(): import __hello__ with captured_stdout() as out: __hello__.main() self.assertEqual(out.getvalue(), 'Hello world!\n')
def test_get_code(self): # Make sure that the code object is good. name = '__hello__' with import_helper.frozen_modules(): code = self.machinery.FrozenImporter.get_code(name) mod = types.ModuleType(name) exec(code, mod.__dict__) with captured_stdout() as stdout: mod.main() self.assertTrue(hasattr(mod, 'initialized')) self.assertEqual(stdout.getvalue(), 'Hello world!\n')
def check_loader_state(self, spec, origname=None, filename=None): if not filename: if not origname: origname = spec.name actual = dict(vars(spec.loader_state)) # Check the code object used to import the frozen module. # We can't compare the marshaled data directly because # marshal.dumps() would mark "expected" (below) as a ref, # which slightly changes the output. # (See https://bugs.python.org/issue34093.) data = actual.pop('data') with import_helper.frozen_modules(): expected = _imp.get_frozen_object(spec.name) code = marshal.loads(data) self.assertEqual(code, expected) # Check the rest of spec.loader_state. expected = dict(origname=origname, ) self.assertDictEqual(actual, expected)
def find(self, name, **kwargs): finder = self.machinery.FrozenImporter with import_helper.frozen_modules(): return finder.find_spec(name, **kwargs)
def find(self, name, path=None): finder = self.machinery.FrozenImporter with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) with import_helper.frozen_modules(): return finder.find_module(name, path)
def test_get_source(self): # Should always return None. with import_helper.frozen_modules(): result = self.machinery.FrozenImporter.get_source('__hello__') self.assertIsNone(result)