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 list_frozen(names): submodules = set() for name in _imp._frozen_module_names(): # To skip __hello__, __hello_alias__ and etc. if name.startswith('__'): continue if '.' in name: submodules.add(name) else: names.add(name) # Make sure all frozen submodules have a known parent. for name in list(submodules): if name.partition('.')[0] in names: submodules.remove(name) if submodules: raise Exception(f'unexpected frozen submodules: {sorted(submodules)}')