Source code for pynsive.plugin.loader
import imp
import sys
import os
from ..common import *
[docs]class LoaderError(ImportError):
"""
This error is thrown when the module loader encounters an exception or
an unrecoverable state while attempting to load a dynamically located
module.
"""
def __init__(self, msg):
"""
Creates a loader error.
:param msg: the loader error message to relay upwards
"""
self.msg = msg
[docs]class ModuleLoader(object):
"""
As per PEP302, this module loader provides all of the necessary context
for loading a python file and executing its contents.
"""
def __init__(self, module_path, module_name, load_target, is_pkg):
"""
Creates a new module loader.
:param module_path: the path where the module resides
:param module_name: the full name of the module to load
:param load_target: the absolute path of the module file to load
:param is_pkg: true if this module is a package, false otherwise
"""
self.module_path = module_path
self.module_name = module_name
self.load_target = load_target
self.is_pkg = is_pkg
def _read_code(self):
"""
Simple abstraction to make reading a module file easy.
"""
fin = open(self.load_target, 'r')
code = fin.read()
fin.close()
return code
[docs] def load_module(self, module_name):
"""
Loads a module's code and sets the module's expected hidden
variables. For more information on these variables and what they
are for, please see PEP302.
:param module_name: the full name of the module to load
"""
if module_name != self.module_name:
raise LoaderError(
'Requesting a module that the loader is unaware of.')
if module_name in sys.modules:
return sys.modules[module_name]
code = self._read_code()
module = imp.new_module(module_name)
module.__file__ = self.load_target
module.__loader__ = self
if self.is_pkg:
module.__path__ = [self.module_path]
module.__package__ = module_name
else:
module.__package__ = module_name.rpartition('.')[0]
sys.modules[module_name] = module
exec(code, module.__dict__)
return module
[docs]class ModuleFinder(object):
"""
As per PEP302, this module loader provides all of the necessary context
for dynamically locating python modules based. This finder searches
directories based on paths added to its internal list of available
search directories.
"""
def __init__(self, paths=None):
"""
Creates a module finder.
:param paths: the paths to include in the search list by default
"""
self.paths = paths if paths else list()
[docs] def add_path(self, path):
"""
Adds a path to search through when attempting to look up a module.
:param path: the path the add to the list of searchable paths
"""
if path not in self.paths:
self.paths.append(path)
[docs] def find_module(self, module_name, path=None):
"""
Searches the paths for the required module.
:param module_name: the full name of the module to find
:param path: set to None when the module in being searched for is a
top-level module - otherwise this is set to
package.__path__ for submodules and subpackages (unused)
"""
module_path = os.path.join(*module_name.split(MODULE_PATH_SEP))
for search_root in self.paths:
target_path = os.path.join(search_root, module_path)
is_pkg = False
# If the target references a directory, try to load it as
# a module by referencing the __init__.py file, otherwise
# append .py and attempt to resolve it.
if os.path.isdir(target_path):
target_file = os.path.join(target_path, '__init__.py')
is_pkg = True
else:
target_file = '{}.py'.format(target_path)
if os.path.exists(target_file):
return ModuleLoader(
target_path, module_name, target_file, is_pkg)
return None