File imp.py of Package failed_python-visvis
# Minimal compatibility shim for the removed 'imp' module (Python 3.12+)
# Provides a small subset of the old imp API used by some packages (e.g. visvis)
# so code that still does "import imp" can keep working without modifying it.
#
# This shim intentionally implements only the functions typically used by
# dynamic importers:
# - find_module(name, path=None)
# - load_module(name, file, pathname, description)
# - load_source(name, pathname)
#
# It uses importlib machinery under the hood.
import importlib.util
import importlib.machinery
import sys
import os
import types
from typing import Optional, Tuple, Any, Iterable
# A very small descriptor tuple to mimic legacy imp.find_module return.
# Historically imp.find_module returned (file, pathname, description)
# where description is a tuple (suffix, mode, type). We return a similar
# placeholder for compatibility.
def _make_description():
return ('.py', 'rb', importlib.machinery.SOURCE)
def find_module(name: str, path: Optional[Iterable[str]] = None) -> Tuple[Any, str, Tuple[str,str,int]]:
"""
Try to locate a module by name in the given path (or sys.path if None).
Returns (open_fileobj, pathname, description_tuple) similar to imp.find_module.
Raises ImportError if not found.
"""
search_paths = list(path) if path is not None else list(sys.path)
# If name is a dotted name, only take last part for file lookups
base = name.rsplit('.', 1)[-1]
for directory in search_paths:
if not directory:
directory = os.getcwd()
# check for simple module file
candidate = os.path.join(directory, base + ".py")
if os.path.isfile(candidate):
f = open(candidate, "rb")
return f, candidate, _make_description()
# check for package directory with __init__.py
pkg_init = os.path.join(directory, base, "__init__.py")
if os.path.isfile(pkg_init):
f = open(pkg_init, "rb")
return f, pkg_init, _make_description()
raise ImportError(f"Module {name!r} not found in path")
def load_module(name: str, fileobj, pathname: str, description: Tuple[str,str,int]):
"""
Load a module from the given pathname. This mimics imp.load_module behavior
sufficiently for typical uses: it creates a module object, inserts it into
sys.modules under `name`, and executes the source.
"""
# Use SourceFileLoader to load the source file.
loader = importlib.machinery.SourceFileLoader(name, pathname)
spec = importlib.util.spec_from_loader(name, loader, origin=pathname)
module = importlib.util.module_from_spec(spec)
# Insert into sys.modules before execution, like old imp did.
sys.modules[name] = module
try:
loader.exec_module(module)
except Exception:
# If execution fails, ensure we don't leave a broken module in sys.modules
try:
del sys.modules[name]
except Exception:
pass
raise
return module
def load_source(name: str, pathname: str):
"""
Legacy convenience function imp.load_source(name, pathname).
Load module directly from source file pathname.
"""
loader = importlib.machinery.SourceFileLoader(name, pathname)
spec = importlib.util.spec_from_loader(name, loader, origin=pathname)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
try:
loader.exec_module(module)
except Exception:
try:
del sys.modules[name]
except Exception:
pass
raise
return module
# Provide a minimal get_tagged_suffixes / get_suffixes compatibility if asked.
def get_suffixes():
# mimic imp.get_suffixes() returning list of (suffix, mode, type)
return [('.py', 'rb', importlib.machinery.SOURCE)]
# simple API marker for code expecting imp.is_builtin
def is_builtin(name: str) -> bool:
return name in sys.builtin_module_names
# Expose a small set of names that some legacy code may import from imp
__all__ = [
"find_module",
"load_module",
"load_source",
"get_suffixes",
"is_builtin",
]