You can register a custom MetaPathFinder as the first element of sys.meta_path. This finder can maintain a list of forbidden modules and only return None if the import is acceptable, in order to delegate to other finders; otherwise, it can raise an ImportError to indicate that the import is illegal.
from importlib.abc import MetaPathFinder
import sys
class ForbiddenModules(MetaPathFinder):
def __init__(self, modules):
super().__init__()
self.modules = modules
def find_spec(self, fullname, path, target=None):
if fullname in self.modules:
raise ImportError(fullname)
sys.meta_path.insert(0, ForbiddenModules({'typing'}))
import math # works
import typing # raises ImportError
However, at interpreter startup already a bunch of modules are automatically imported. You can check this by using the -v flag, e.g. python -vc "" (it's a long list, so I won't copy it here).
So you also need to remove those modules from sys.modules: sys.modules.clear().
Also note that the list of forbidden modules must include sys itself, because otherwise user code could simply remove the custom finder via sys.meta_path.pop(0) and then continue with importing forbidden modules. This implies that any module which depends on sys (i.e. imports sys) will be forbidden, too.
So this is the full code:
from importlib.abc import MetaPathFinder
import sys
class ForbiddenModules(MetaPathFinder):
def __init__(self, modules):
super().__init__()
self.modules = modules
def find_spec(self, fullname, path, target=None):
if fullname in self.modules:
raise ImportError(fullname)
sys.meta_path.insert(0, ForbiddenModules({'sys', ...}))
sys.modules.clear()
del MetaPathFinder, ForbiddenModules, sys