commit:     c7b86d60b7c32f5bc858a428547e175eab579967
Author:     Devan Franchini <twitch153 <AT> gentoo <DOT> org>
AuthorDate: Tue Jul 29 00:05:59 2014 +0000
Commit:     Devan Franchini <twitch153 <AT> gentoo <DOT> org>
CommitDate: Fri Aug 15 21:42:41 2014 +0000
URL:        
http://git.overlays.gentoo.org/gitweb/?p=proj/layman.git;a=commit;h=c7b86d60

module.py: Adds modular plugin system

---
 layman/module.py | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 211 insertions(+)

diff --git a/layman/module.py b/layman/module.py
new file mode 100644
index 0000000..6d7a40b
--- /dev/null
+++ b/layman/module.py
@@ -0,0 +1,211 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import os
+
+from layman.output import Message
+
+class InvalidModuleName(Exception):
+    '''An invalid or unknown module name.'''
+
+class Module(object):
+    '''
+    Class to define and hold our plugin-module
+
+    @type name: string
+    @param name: The module name
+    @type namepath: string
+    @param namepath: The path to the new module
+    @param output: The output for any information
+    '''
+    def __init__(self, name, namepath, output):
+        self.name = name
+        self._namepath = namepath
+        self.kids_names = []
+        self.kids = {}
+        self.output = output
+        self.initialized = self._initialize()
+
+
+    def _initialize(self):
+        '''
+        Initializes the plug-in module
+
+        @rtype bool: reflects success or failure to initialize the module
+        '''
+        self.valid = False
+        try:
+            mod_name = '.'.join([self._namepath, self.name])
+            self._module = __import__(mod_name, [], [], ['not empty'])
+            self.valid = True
+        except ImportError as e:
+            self.output.error('Module._initialize(); failed to import %(mod) '\
+                'error was: %(err)' % ({'err': e, 'mod': mod_name}))
+            return False
+        self.module_spec = self._module.module_spec
+        for submodule in self.module_spec['provides']:
+            kid = self.module_spec['provides'][submodule]
+            kidname = kid['name']
+            kid['module_name'] = '.'.join([mod_name, self.name])
+            kid['is_imported'] = False
+            self.kids[kidname] = kid
+            self.kids_names.append(kidname)
+        return True
+
+
+    def get_class(self, name):
+        '''
+        Retrieves a module class desired
+
+        @type name: string
+        @param name: the plug-in module's name
+        @rtype mod_class: instance of plug-in module's class
+        '''
+        if not name or name not in self.kids_names:
+            raise InvalidModuleName('Module name "%(name)" was invalid or not'\
+                    'part of the module "%(mod_name)"' ({'mod_name':self.name,
+                                                         'name': name}))
+        kid = self.kids[name]
+        if kid['is_imported']:
+            module = kid['instance']
+        else:
+            try:
+                module = __import__(kid['module_name'], [], [], ["not empty"])
+                kid['instance'] = module
+                kid['is_imported'] = True
+            except ImportError:
+                raise
+        mod_class = getattr(module, kid['class'])
+        return mod_class
+
+
+class Modules(object):
+    '''
+    Dynamic module system for loading and retrieving any of the
+    installed layman modules and/or provided class'
+
+    @param path: Optional path to the "modules" directory or defaults to
+                 the directory of this file + "/modules"
+    @param namepath: Optional python import path to the "modules" directory or
+                     defaults to the directory name of this file + ".modules"
+    @param output: Optional output, defaults to layman.output.Message object
+    '''
+    def __init__(self, path=None, namepath=None, output=None):
+        if path:
+            self._module_path = path
+        else:
+            self._module_path = os.path.join(
+                (os.path.dirname(os.path.realpath(__file__))), 'modules')
+        if namepath:
+            self._namepath = namepath
+        else:
+            self._namepath = '.'.join(os.path.dirname(
+                os.path.realpath(__file__)), 'modules')
+        if output:
+            self.output = output
+        else:
+            self.output = Message()
+        self._modules = self._get_all_modules()
+        self.module_names = sorted(self._modules)
+
+
+    def _get_all_modules(self):
+        '''
+        Scans the overlay modules dir for loadable modules
+
+        @rtype dict of module_plugins
+        '''
+        module_dir = self._module_path
+        importables = []
+        names = os.listdir(module_dir)
+        for entry in names:
+            if entry.startswith('__'):
+                continue
+            try:
+                os.lstat(os.path.join(module_dir, entry, '__init__.py'))
+                importables.append(entry)
+            except EnvironmentError:
+                pass
+
+        kids = {}
+        for entry in importables:
+            new_module = Module(entry, self._namepath, self.output)
+            for module_name in new_module.kids:
+                kid = new_module.kids[module_name]
+                kid['parent'] = new_module
+                kids[kid['name']] = kid
+        return kids
+
+
+    def get_module_names(self):
+        '''
+        Retrieves all available module names
+
+        @rtype: list of installed module names available
+        '''
+        return self.module_names
+
+
+    def get_class(self, modname):
+        '''
+        Retrieves a module class desired
+
+        @type modname: string
+        @param modname: the module class name
+        '''
+        if modname and modname in self.module_names:
+            mod = self._modules[modname]['parent'].get_class(modname)
+        else:
+            raise InvalidModuleName('Module name "%(name)s" was invalid or'\
+                ' not found.' % ({'name': modname}))
+        return mod
+
+
+    def get_description(self, modname):
+        '''
+        Retrieves the module class decription
+
+        @type modname: string
+        @param modname: the module class name
+        @rtype: string of modules class decription
+        '''
+        if modname and modname in self.module_names:
+            mod = self._modules[modname]['description']
+        else:
+            raise InvalidModuleName('Module name "%(name)s" was invalid or'\
+                ' not found.' % ({'name': modname}))
+        return mod
+
+
+    def get_functions(self, modname):
+        '''
+        Retrieves the module class exported function names
+
+        @type modname: string
+        @param modname: the module class name
+        @rtype: list of the modules class exported function names
+        '''
+        if modname and modname in self.module_names:
+            mod = self._modules[modname]['functions']
+        else:
+            raise InvalidModuleName('Module name "%(name)s" was invalid or'\
+                ' not found.' % ({'name': modname}))
+        return mod
+
+
+    def get_func_descriptions(self, modname):
+        '''
+        Retrieves the module class  exported functions descriptions
+
+        @type modname: string
+        @param modname: the module class name
+        @rtype: dict of the modules class exported functions descriptions
+        '''
+        if modname and modname in self.module_names:
+            desc = self._modules[modname]['func_desc']
+        else:
+            raise InvalidModuleName('Module name "%(name)s" was invalid or'\
+                ' not found.' % ({'name': modname}))
+        return desc

Reply via email to