class EnvironmentConfig(Plugin): """A plugin that supports configuration of environment options.""" implements(IEnvironmentConfig) implements(IPluginLoadPath) def __init__(self, namespace): self.namespace = namespace self.p = re.compile(namespace) declare_option("options", cls=DictOption, section=namespace) def get_option(self, option): try: return getattr(self.options, option) except AttributeError: return None def matches(self, namespace): if self.p.match(namespace) is None: return (False, 0) return (True, namespace.count('.') + 1) def get_load_path(self): ans = [] # # Look for load_path in the environment # try: ans.append( os.path.normcase(os.path.realpath(self.options.load_path))) except OptionError: pass except AttributeError: pass # # Look for the $HOME/.$name/plugin directory # if "HOME" in os.environ: dir = os.path.normcase( os.path.realpath( os.path.join(os.environ["HOME"], "." + self.namespace, "plugins"))) if os.path.exists(dir): ans.append(dir) # # Look for the $PLUGINPATH environment # if "PLUGINPATH" in os.environ: tmp = os.environ["PLUGINPATH"] if ';' in tmp: ans += tmp.split(';') elif ':' in tmp: ans += tmp.split(':') else: ans += re.split('[ \t]+', tmp) if __debug__ and logger.isEnabledFor(logging.DEBUG): logger.debug("Created load path: %s" % ans) return ans
class DefaultTestDriver(Plugin): """ This is the 'default' test driver, which simply prints the arguments being passed into a test. """ implements(plugins.ITestDriver) alias('default') def setUpClass(self, cls, options): """Set-up the class that defines the suite of tests""" def tearDownClass(self, cls, options): """Tear-down the class that defines the suite of tests""" def setUp(self, testcase, options): """Set-up a single test in the suite""" def tearDown(self, testcase, options): """Tear-down a single test in the suite""" sys.stdout.flush() def run_test(self, testcase, name, options): """Execute a single test in the suite""" print('run_test ' + name) print(options)
class YamlTestParser(SingletonPlugin): implements(plugins.ITestParser) def __init__(self, **kwds): SingletonPlugin.__init__(self, **kwds) self.name = 'yml' def load_test_config(self, filename): if using_yaml: INPUT = open(filename, 'r') repn = yaml.load(INPUT, yaml.SafeLoader) INPUT.close() return repn # # If PyYaml is not available, then we use a simple yaml parser # INPUT = open(filename, 'r') repn = pyutilib.misc.simple_yaml_parser(INPUT) INPUT.close() return repn def print_test_config(self, repn): print(repn) #pragma:nocover def enabled(self): return True
class DragonflySystemParticipant(SingletonPlugin): implements(ISystemParticipant) declare_option("engine", section="Dragonfly", default="auto") def __init__(self): self._engine = None self._loaded_engine_name = None #----------------------------------------------------------------------- # ISystemParticipant methods. def startup(self): self.shutdown() self._connect_engine() def shutdown(self): if self._engine: self._engine.disconnect() self._engine = None self._loaded_engine_name = None def config_changed(self): if self.engine == self._loaded_engine_name: # No change, return immediately. log.info("No change.") return self.shutdown() self.startup() #----------------------------------------------------------------------- # Internal methods. def _resolve_engine_name(self, engine_name): if not engine_name or engine_name == "auto": return None return engine_name def _connect_engine(self): engine_name = self._resolve_engine_name(self.engine) try: log.info("Importing Dragonfly library.") import dragonfly log.info("Locating SR engine {0}." "".format(engine_name or "(automatic selection)")) self._engine = dragonfly.get_engine(engine_name) log.info("Connecting to SR engine {0}.".format(self._engine)) self._engine.connect() except Exception, e: log.exception("Error during Dragonfly setup: {0}".format(e)) raise self._loaded_engine_name = self.engine
class WorkflowPlugin(Plugin, workflow.Workflow): implements(IWorkflowTask) def __init__(self, *args, **kwds): #pragma:nocover Plugin.__init__(self, *args, **kwds) workflow.Workflow.__init__(self, *args, **kwds) def __repr__(self): #pragma:nocover return workflow.Workflow.__repr__(self)
class TaskPlugin(Plugin, task.Task): implements(IWorkflowTask) def __init__(self, *args, **kwds): #pragma:nocover Plugin.__init__(self, *args, **kwds) task.Task.__init__(self, *args, **kwds) def __repr__(self): return task.Task.__repr__(self) #pragma:nocover
class FileOption(Option): """A class that converts option data into a path. Relative paths are converted using the path for the configuration file.""" implements(IFileOption, service=True) implements(IUpdatedOptionsAction, service=True) def __init__(self, name, **kwds): """ Constructor. By default, the current working directory is the path used in this data. """ self.dir = None Option.__init__(self, name, **kwds) def _parse_option(self, k, v): """Parse options that are specific to the FileOption class""" if k == "directory": self.dir = v else: Option._parse_option(self, k, v) def convert(self, value, default): """Conversion routine.""" val = value[-1] if not val: if default is None: return None return os.path.normcase(os.path.realpath(default)) if not os.path.isabs(val): val = os.path.join(self.dir, val) return os.path.normcase(os.path.realpath(val)) else: return os.path.normcase(os.path.realpath(val)) def set_dir(self, path): """Sets the path of the configuration data file.""" self.dir = path def reset_after_updates(self): if self.dir is None: #pragma:nocover raise OptionError("FileOption must have a directory specified.")
class OptionData(Plugin): """ A class that is used to share option data between Option objects. This data in this class represents option data as section -> option -> data Note: this class does not currentl support the situation where an option is removed. This would require a backwards map from option names to the Option classes that declare them. """ implements(IOptionDataProvider, service=True) def __init__(self): """Constructor""" self.ignore_missing = False self.data = {} def get_data(self): """Get the class data""" return self.data def set(self, section, name, value): """Set the value of an option in a specified section""" if section not in self.data: self.data[section] = {} self.data[section][name] = value def get(self, section, name): """Get the value of an option in a specified section""" try: return self.data[section][name] except Exception: if self.ignore_missing: return None if section in self.data: raise OptionError( "Problem retrieving the value of option %r from section %r. Valid keys are %s" % (name, section, self.data[section].keys())) else: raise OptionError( "Problem retrieving the value of option %r from section %r. Undefined section." % (name, section)) def clear(self, keys=None): """Clears the data""" if keys is None: self.data = {} else: for key in keys: if not key in self.data: continue del self.data[key]
class CommandSetBase(Plugin): implements(ICommandSet) observers = ExtensionPoint(ICommandSetObserver) def after_load(self): for observer in self.observers: observer.loaded_command_set(self) def after_unload(self): self.deactivate() for observer in self.observers: observer.unloaded_command_set(self)
class ExternalExecutable(Plugin): implements(IExternalExecutable, service=True) def __init__(self, **kwds): if 'doc' in kwds: self.exec_doc = kwds["doc"] else: self.exec_doc = "" if 'name' in kwds: self.name = kwds['name'] declare_option( kwds['name'], local_name="executable", section="executables", default=None, doc=self.exec_doc, cls=ExecutableOption) else: raise PluginError("An ExternalExectuable requires a name") if 'path' in kwds: self.path = kwds['path'] else: self.path = None if 'validate' in kwds: self.validate = kwds['validate'] else: self.validate = None self.find_executable() def find_executable(self): if not self.path is None: self.exec_default = self.path else: self.exec_default = pyutilib.misc.search_file( self.name, implicitExt=pyutilib.misc.executable_extension, executable=True, validate=self.validate) def enabled(self): return self._enable and ((self.executable is not None) or (self.exec_default is not None)) def get_path(self): if not self.enabled(): return None tmp = self.executable if tmp is None: return self.exec_default return tmp
class GrammarTreeUpdater(Plugin): implements(ICommandSetObserver) def __init__(self, grammar_tree): self._grammar_tree = grammar_tree def loaded_command_set(self, command_set): self.update() def unloaded_command_set(self, command_set): self.update() def update(self): command_sets = pyutilib.component.core.ExtensionPoint(ICommandSet) self._grammar_tree.update(tuple(command_sets))
class DummyOption1(Option): """A test class that converts option data into float values.""" implements(IDummyOption) def convert(self, value, default): """Conversion routine.""" val = value[-1] if not val: return 0 try: return float(val) except ValueError: raise OptionError('Expected float, got %s' % repr(value)) except TypeError: raise OptionError('Expected string or float type, got %s' % repr(value))
class TestDriverBase(Plugin): implements(ITestDriver) def setUpClass(self, cls, options): """Set-up the class that defines the suite of tests""" def tearDownClass(self, cls, options): """Tear-down the class that defines the suite of tests""" def setUp(self, testcase, options): """Set-up a single test in the suite""" def tearDown(self, testcase, options): """Tear-down a single test in the suite""" def run_test(self, testcase, name, options): """Execute a single test in the suite"""
class JsonTestParser(SingletonPlugin): implements(plugins.ITestParser) def __init__(self, **kwds): SingletonPlugin.__init__(self, **kwds) self.name = 'json' def load_test_config(self, filename): INPUT = open(filename, 'r') repn = json.load(INPUT) INPUT.close() return repn def print_test_config(self, repn): print(repn) #pragma:nocover def enabled(self): return json_available
class Configuration_ConfigParser(ManagedSingletonPlugin): """A configuration parser that uses the ConfigParser package.""" implements(IConfiguration) def __init__(self, **kwds): kwds['name'] = 'Configuration_ConfigParser' ManagedSingletonPlugin.__init__(self, **kwds) def load(self, filename): """Returns a list of tuples: [ (section,option,value) ]""" parser = ConfigParser.ConfigParser() if not os.path.exists(filename): raise ConfigurationError("File " + filename + " does not exist!") parser.read(filename) # # Collect data # data = [] for section in parser.sections(): for (option, value) in parser.items(section): data.append((section, option, value)) return data def save(self, filename, config, header=None): """Save configuration information to the specified file.""" if sys.version_info[:2] == (2, 6): parser = ConfigParser.ConfigParser(dict_type=OrderedDict) else: parser = ConfigParser.ConfigParser() for (section, option, value) in config: if not parser.has_section(section): parser.add_section(section) parser.set(section, option, str(value)) OUTPUT = open(filename, "w") if not header is None: for line in header.split("\n"): OUTPUT.write("; " + line + '\n') parser.write(OUTPUT) OUTPUT.close()
class EggLoader(ManagedPlugin): """ Loader that looks for Python egg files in the plugins directories. These files get exampled with the pkg_resources package, and Plugin classes are loaded. Note: this plugin should not be directly constructed. Instead, the user should employ the PluginFactory_EggLoader function. """ implements(IPluginLoader, service=True) def __init__(self, **kwds): """EggLoader constructor. The 'namespace' keyword option is required.""" if 'name' not in kwds: kwds['name'] = "EggLoader." + kwds['namespace'] super(EggLoader, self).__init__(**kwds) self.entry_point_name = kwds['namespace'] + ".plugins" if pkg_resources_avail is None: _check_pkg_resources() if not pkg_resources_avail: logger.warning( 'A dummy EggLoader service is being constructed, because the pkg_resources package is not available on this machine.' ) def load(self, env, search_path, disable_re, name_re): generate_debug_messages = __debug__ and env.log.isEnabledFor( logging.DEBUG) if not pkg_resources_avail: if generate_debug_messages: env.log.debug( 'The EggLoader service is terminating early because the pkg_resources package is not available on this machine.' ) return working_set = pkg_resources.working_set env.log.info('BEGIN - Loading plugins with an EggLoader service') distributions, errors = working_set.find_plugins( pkg_resources.Environment(search_path)) for dist in distributions: if name_re.match(str(dist)): if generate_debug_messages: env.log.debug('Adding plugin %r from %r', dist, dist.location) working_set.add(dist) else: if generate_debug_messages: env.log.debug('Ignoring plugin %r from %r', dist, dist.location) def _log_error(item, e): gen_debug = __debug__ and env.log.isEnabledFor(logging.DEBUG) if isinstance(e, pkg_resources.DistributionNotFound): if gen_debug: env.log.debug('Skipping "%s": ("%s" not found)', item, e) elif isinstance(e, pkg_resources.VersionConflict): if gen_debug: env.log.debug('Skipping "%s": (version conflict "%s")', item, e) elif isinstance(e, pkg_resources.UnknownExtra): env.log.error('Skipping "%s": (unknown extra "%s")', item, e) elif isinstance(e, ImportError): env.log.error('Skipping "%s": (can\'t import "%s")', item, e) else: env.log.error('Skipping "%s": (error "%s")', item, e) for dist, e in errors.items(): _log_error(dist, e) for entry in working_set.iter_entry_points(self.entry_point_name): if generate_debug_messages: env.log.debug('Loading %r from %r', entry.name, entry.dist.location) try: entry.load(require=True) except (ImportError, pkg_resources.DistributionNotFound, pkg_resources.VersionConflict, pkg_resources.UnknownExtra): e = sys.exc_info()[1] _log_error(entry, e) else: if not disable_re.match(os.path.dirname( entry.module_name)) is None: #_enable_plugin(env, entry.module_name) pass env.log.info('END - Loading plugins with an EggLoader service')
class LegacyDirectoryLoader(SingletonPlugin): implements(ICommandSetLoader) declare_option("directories", section="LegacyLoader") def __init__(self): self._modules = {} self._directories = [] self._directories_config = None def _parse_directories_config(self): # If config has not changed, return immediately. if self._directories_config == self.directories: return self._directories log.info("Config option directories has changed:" " {0!r}".format(self.directories)) directories = [] for line in self.directories.splitlines(): line = line.strip() # Skip blank lines and comments. if not line or line.startswith("#"): continue directory = os.path.abspath(line) if not os.path.isdir(directory): log.error("Not a directory: {0}".format(directory)) continue directories.append(directory) self._directories_config = self.directories self._directories = directories log.debug("Loading command modules from these directories:") for directory in directories: log.debug(" - {0}".format(directory)) return directories def update(self): # Parse directories configuration. directories = self._parse_directories_config() valid_paths = [] for directory in directories: valid_paths.extend(self._get_valid_paths(directory)) # Remove any deleted modules. for path, module in self._modules.items(): if path not in valid_paths: del self._modules[path] module.unload() # Add any new modules. for path in valid_paths: if path not in self._modules: module = LegacyCommandSet(path) module.load() self._modules[path] = module # Should check module freshness here. #else: # module = self._modules[path] def _get_valid_paths(self, directory): valid_paths = [] for filename in os.listdir(directory): path = os.path.abspath(os.path.join(directory, filename)) if not os.path.isfile(path): continue if not os.path.splitext(path)[1] == ".py": continue valid_paths.append(path) return valid_paths
class LoggingConfig(Plugin): """A plugin that supports global configuration of logging options.""" implements(IUpdatedOptionsAction) def __init__(self, namespace): """Initialize logging information for a specified namespace""" self._hdlr = None self.namespace = namespace self.env_plugins = ExtensionPoint(IEnvironmentConfig) if self.namespace == "": section = "logging" section_re = None else: section = "logging." + namespace section_re = "^logging$" # declare_option("timestamp", section=section, section_re=section_re, default=False, doc="""Add timestamp to logging information.""") # declare_option("log_dir", section=section, section_re=section_re, default=None, doc="""The logging directory. The default directory is the application directory plus 'log'.""") # declare_option("log_type", section=section, section_re=section_re, default='none', doc="""Logging facility to use. Should be one of (`none`, `file`, `stderr`, `syslog`, `winlog`).""") # declare_option( "log_file", section=section, section_re=section_re, default=namespace + '.log', doc= """If `log_type` is `file`, this should be a path to the log-file.""" ) # declare_option("log_level", section=section, section_re=section_re, default='WARN', doc="""Level of verbosity in log. Should be one of (`CRITICAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`).""") # declare_option("log_format", section=section, section_re=section_re, default=None, doc="""Custom logging format. If nothing is set, the following will be used: $(project)[$(env) $(module)] $(levelname): $(message) In addition to regular key names supported by the Python logger library library (see http://docs.python.org/lib/node422.html), one could use: - $(path)s the path for the current environment - $(basename)s the last path component of the current environment - $(app)s the name of the current application Note the usage of `$(...)s` instead of `%(...)s` as the latter form would be interpreted by the ConfigParser itself. """) def reset_after_updates(self): """ Configure the pyutilib.component logging facility. This will implicitly configure all of the environment-specific logging objects. """ sys.stdout.flush() logger = logging.getLogger('pyutilib.component.core.' + self.namespace) if not self._hdlr is None: logger.removeHandler(self._hdlr) # # Set logging level # level = self.log_level level = level.upper() if level in ('DEBUG', 'ALL'): logger.setLevel(logging.DEBUG) elif level == 'INFO': logger.setLevel(logging.INFO) elif level == 'ERROR': logger.setLevel(logging.ERROR) elif level == 'CRITICAL': logger.setLevel(logging.CRITICAL) else: logger.setLevel(logging.WARNING) # # Initialize the current path. Is there a rule to use for whic # environment will be used??? In practice, there is likely to be # only one environment. # if self.log_dir is None: path = None for plugin in self.env_plugins: (flag, count) = plugin.matches(self.namespace) tmp = plugin.get_option("path") if flag and not tmp is None: path = tmp break if path is None: path = os.getcwd() else: path = self.log_dir # # Setup the logging file # logtype = self.log_type.lower() if self.log_file is None: logfile = os.path.join(path, 'log') else: logfile = self.log_file if not os.path.isabs(logfile): logfile = os.path.join(path, logfile) # # Define the format # format = self.log_format if format is None: format = '[env=%(env)s where=%(module)s] %(levelname)s - %(message)s' if self.timestamp and logtype in ('file', 'stderr'): format = '%(asctime)s ' + format format = format.replace('$(', '%(') \ .replace('%(env)s', PluginGlobals.get_env().name) datefmt = '' if self.timestamp and self.log_type == 'stderr': datefmt = '%X' formatter = logging.Formatter(format, datefmt) # # Define the handler # if logtype == 'file': hdlr = logging.FileHandler(logfile) elif logtype in ('winlog', 'eventlog', 'nteventlog'): # Requires win32 extensions hdlr = handlers.NTEventLogHandler(logid, logtype='Application') elif logtype in ('syslog', 'unix'): hdlr = handlers.SysLogHandler('/dev/log') elif logtype in ('stderr'): hdlr = logging.StreamHandler(sys.stderr) else: hdlr = handlers.BufferingHandler(0) # Note: this _really_ throws away log events, as a `MemoryHandler` # would keep _all_ records in case there's no target handler (a bug?) self._hdlr = hdlr self._logtype = logtype self._logfile = logfile hdlr.setFormatter(formatter) logger.addHandler(hdlr) self._log = logger def flush(self): """Flush logging I/O""" self._hdlr.flush() def shutdown(self): # # Q: should this shutdown _all_ logging? # logging.shutdown() def log(self, message): self._log.info(message)
class TempfileManagerPlugin(ManagedSingletonPlugin): """A plugin that manages temporary files.""" implements(ITempfileManager) def __init__(self, **kwds): if getattr(self, '_initialized', False) is True: return self._initialized = True # kwds['name'] = 'TempfileManager' ManagedSingletonPlugin.__init__(self, **kwds) self._tempfiles = [[]] declare_option("tempdir", default=None) self._ctr = -1 def create_tempfile(self, suffix=None, prefix=None, text=False, dir=None): """ Return the absolute path of a temporary filename that is guaranteed to be unique. This function generates the file and returns the filename. """ if suffix is None: suffix = '' if prefix is None: prefix = 'tmp' if dir is None: dir = self.tempdir ans = tempfile.mkstemp(suffix=suffix, prefix=prefix, text=text, dir=dir) ans = list(ans) if not os.path.isabs(ans[1]): #pragma:nocover fname = os.path.join(dir, ans[1]) else: fname = ans[1] os.close(ans[0]) if self._ctr >= 0: new_fname = os.path.join(dir, prefix + str(self._ctr) + suffix) # Delete any file having the sequential name and then # rename if os.path.exists(new_fname): os.remove(new_fname) shutil.move(fname, new_fname) fname = new_fname self._ctr += 1 self._tempfiles[-1].append(fname) return fname def create_tempdir(self, suffix=None, prefix=None, dir=None): """ Return the absolute path of a temporary directory that is guaranteed to be unique. This function generates the directory and returns the directory name. """ if suffix is None: suffix = '' if prefix is None: prefix = 'tmp' if dir is None: dir = self.tempdir dirname = tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=dir) if self._ctr >= 0: new_dirname = os.path.join(dir, prefix + str(self._ctr) + suffix) # Delete any directory having the sequential name and then # rename if os.path.exists(new_dirname): shutil.rmtree(new_dirname) shutil.move(dirname, new_dirname) dirname = new_dirname self._ctr += 1 self._tempfiles[-1].append(dirname) return dirname def add_tempfile(self, filename, exists=True): """Declare this file to be temporary.""" tmp = os.path.abspath(filename) if exists and not os.path.exists(tmp): raise IOError("Temporary file does not exist: " + tmp) self._tempfiles[-1].append(tmp) def clear_tempfiles(self, remove=True): """Delete all temporary files.""" while len(self._tempfiles) > 1: self.pop(remove) self.pop(remove) def sequential_files(self, ctr=0): """Start generating sequential files, using the specified counter""" self._ctr = ctr def unique_files(self): """Stop generating sequential files, using the specified counter""" self._ctr = -1 # # Support "with" statements, where the pop automatically # takes place on exit. # def push(self): self._tempfiles.append([]) return self def __exit__(self, type, value, traceback): self.pop(remove=True) def pop(self, remove=True): files = self._tempfiles.pop() if remove: for filename in files: if os.path.exists(filename): if os.path.isdir(filename): shutil.rmtree( filename, ignore_errors=not deletion_errors_are_fatal) else: try: os.remove(filename) except WindowsError: # Sometimes Windows doesn't release the # file lock immediately when the process # terminates. If we get an error, wait a # second and try again. try: time.sleep(1) os.remove(filename) except WindowsError: if deletion_errors_are_fatal: raise else: # Failure to delete a tempfile # should NOT be fatal logger = logging.getLogger( 'pyutilib.component.config') logger.warning("Unable to delete temporary " "file %s" % (filename,)) if len(self._tempfiles) == 0: self._tempfiles = [[]]
class OptionPlugin(Plugin): """Manages the initialization of an Option.""" implements(IOption, service=True) def __init__(self): """ Declare an extension point for a data provider, and construct one if one hasn't already been provided. """ self.data = ExtensionPoint(IOptionDataProvider) if PluginGlobals._default_OptionData is None: PluginGlobals._default_OptionData = OptionData() # # This is a hack. We shouldn't need to test if len(self.data) is zero. # Somewhere in our tests, the weakref to the OptionData object is being # corrupted. Perhaps this is caused by 'nose' or 'import' logic? # if True and len(self.data) == 0: PluginGlobals.interface_services[IOptionDataProvider].add( PluginGlobals._default_OptionData._id) PluginGlobals.plugin_instances[ PluginGlobals._default_OptionData._id] = weakref.ref( PluginGlobals._default_OptionData) # if len(self.data) == 0: #if False: #print "ZZZ", ep.Xextensions() #print "HERE", PluginGlobals._default_OptionData._id, PluginGlobals._default_OptionData.ctr #print "HERE", PluginGlobals._default_OptionData #print "HERE - id", id(PluginGlobals._default_OptionData) #print "HERE", getattr(PluginGlobals._default_OptionData, '_HERE_', None) #print "HERE", PluginGlobals._default_OptionData.__interfaces__ #print "" #print "HERE", PluginGlobals.interface_services #print "HERE", PluginGlobals.plugin_instances.keys() #for exe_ in PluginGlobals._executables: #print exe_._id, exe_ #print "LEN", len(PluginGlobals.env) #for name_ in PluginGlobals.env: #env_ = PluginGlobals.env[name_] #print env_.name #print env_.nonsingleton_plugins #print [env_.singleton_services[cls_] for cls_ in env_.singleton_services] raise PluginError( "Problem constructing a global OptionData object %s" % self.name) def matches_section(self, section): """ This method returns true if the section name matches the option section, or if the option's section regular expression matches the section name. """ return (section == self.section) or ( self.section_re != None and (not self.section_p.match(section) is None)) def matches_name(self, name): """ This method returns true if the name matches the options' name. """ return (self.name == "") or (name == self.name) def convert(self, value, default): """Convert a value into a specific type. The default behavior is to take the list of values, and simply return the last one defined in the configuration.""" return value[-1] def get_value(self): """ Get the option value. """ return self.data.service().get(self.section, self.name) def set_value(self, _value_, raw=False): """ Set the option value. By default, the option is converted using the option-specific `convert` method, but the `raw` option can be specified to force the raw value to be inserted. """ if raw: self.data.service().set(self.section, self.name, _value_) else: if not type(_value_) is list or len(_value_) == 0: _value_ = [_value_] self.data.service().set(self.section, self.name, self.convert(_value_, self.default)) def load(self, _option_, _value_): """ Load an option value. This method assumes that the option value is provided in a list, which is the format used when interfacing with the Configure class. """ if type(_value_) is list and len(_value_) == 0: raise OptionError("Attempting to load option %r with empty data" % (self.name)) try: self.set_value(_value_) except OptionError: err = sys.exc_info()[1] raise OptionError("Error loading option %r: %s" % (str(_option_), str(err))) return True def reset(self): """Set option to its default value""" self.set_value(self.default, raw=True) def default_str(self): """Return a string value that describes the default option value""" return str(self.default)
class ImportLoader(ManagedSingletonPlugin): """Loader that looks for Python source files in the plugins directories, which simply get imported, thereby registering them with the component manager if they define any components. """ ep_services = ExtensionPoint(IIgnorePluginWhenLoading) implements(IPluginLoader) def load(self, env, search_path, disable_re, name_re): generate_debug_messages = __debug__ and env.log.isEnabledFor( logging.DEBUG) env.log.info('Loading plugins with ImportLoader') for path in search_path: plugin_files = glob(os.path.join(path, '*.py')) # # Note: for reproducibility, this fixes the order that # files are loaded # for plugin_file in sorted(plugin_files): #print("ImportLoader:",plugin_file) # # Load the module # module = None plugin_name = os.path.basename(plugin_file[:-3]) if plugin_name not in sys.modules and name_re.match( plugin_name): try: module = imp.load_source(plugin_name, plugin_file) if generate_debug_messages: env.log.debug('Loading file plugin %s from %s' % \ (plugin_name, plugin_file)) except Exception: e = sys.exc_info()[1] env.log.error('Failed to load plugin from %s', plugin_file, exc_info=True) env.log.error('Load error: %r' % str(e)) # # Disable singleton plugins that match # if not module is None: if not disable_re.match(plugin_name) is None: if generate_debug_messages: env.log.debug('Disabling services in module %s' % plugin_name) for item in dir(module): # # This seems like a hack, but # without this we can disable pyutilib # functionality! # flag = False for service in ImportLoader.ep_services: if service.ignore(item): flag = True break if flag: continue cls = getattr(module, item) try: is_instance = isinstance(cls, Plugin) except TypeError: #pragma:nocover is_instance = False try: is_plugin = issubclass(cls, Plugin) except TypeError: is_plugin = False try: is_singleton = not (cls.__instance__ is None) except AttributeError: #pragma:nocover is_singleton = False if is_singleton and is_plugin: if generate_debug_messages: env.log.debug('Disabling service %s' % item) cls.__instance__._enable = False if is_instance: if generate_debug_messages: env.log.debug('Disabling service %s' % item) cls._enable = False elif generate_debug_messages: env.log.debug('All services in module %s are enabled' % plugin_name)