Package: nsimport
With creating individual namespaces for python import mechanism, we can use NsImporter to load modules without conflict, loading modules to different namespaces (not inject them into global namespace).All modules loaded by NsImporters will be added to NsImporter’s own namespace (access with self.sys), and sys.module contains no them.So we can import our modules without conflict such as modules with same name, different packages versions or other situations we do not want loaded modules present in sys.modules.This library is modified fromimportlibof python3.8, but there are only 2 differences between nsimport and importlib:__init__.py of importlib is edited to be nsimporter_internal.py by creating a class type to implement namespace initializing before being used to import modules. The class is initialized by set namespace’s sys to parametersyspassed to it.new __init__.py for whole library.APIsAll available defined APIs can be found in __init__.py and nsimporter_internal.py.But it is disencouraged to directly use APIs exceptnsimport.get_NsImporter(path: list)which returns a new NsImporter initialized with a copied sys module.If you know exactly what module sys do when interpreter imports modules, you can create your own namespace and pass it tonsimport.NsImporter(sys)and it will be use to initialize the importer.Different NsImporters have different namespaces (if different sys modules are passed to it), so it is feasible to use 2 or more importer at the same time.You can access namespace’ssysmodule by accessing instance’s membersysusingself.sys, and access namespace’s importlib bootstrap usingself._bootstrapandself._bootstrap_external.Parametersnsimport.get_NsImporter(path: list)pathis a python list that indicates folders PathFinder use to find modules.
Inside the importer, self.sys.path will be assignedpath + sys.path, and it acts as sys.path in importer’s own namespace.nsimport.NsImporter(sys: module)sysis a module with attributes sys.path, sys.modules, sys.meta_path, sys.path_hooks and sys.path_importer_cache = {}. All of these  attributes should be independent to sys of global namespace, otherwise the importer will still add module to global sys.modules.nsimport.get_NsImporterprovides a convenient way to create neededsysand passes it to NsImporter to create instance.Example>>>importnsimport>>>importer=nsimport.get_NsImporter([])>>>importer<nsimport.nsimporter_internal.implibobjectat0x7fae0568fdc0>>>>importer.import_module('os')<module'os'from'/usr/local/lib/python3.8/os.py'>>>>importer.import_module('codeop')<module'codeop'from'/usr/local/lib/python3.8/codeop.py'>>>>'codeop'insys.modulesFalse>>>'codeop'inimporter.sys.modulesTrueNoticeFor every NsImporter has its own namespace, all modules loaded by now loading module will be injected to NsImporter’s sys.modules but global sys.modules.Only test on python3.8, and you can run scriptimport_tests.pyto check if the library works.Though try best to make sure the modules in sys.modules are isolated to namespace’s sys.modules, modules imported before importing _bootsrap_external may still use global sys in its namespace. Not essential modules before _bootstrap_external are removed with functionconvert_modules_sysinnsimporter_internal.py, and other modules will be copied and set new sys module. Unit testtest_issue_pre_loaded_modulesandtest_issue_pre_loaded_modules_solved_no_leakageare for this problem. Another implementation does not face this problem.Details of implementation are in functionnsimporter_internal.implib.__init__which replaces sys module of namespaces of _bootstrap functions with its own sys.AdvanceAnother implementation of namespace specific importer is inmoduleimporter, and it provide more general apis, wrapper objects, and reflection mechanism for python modules.