From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id BF6A4138A2F for ; Fri, 15 Aug 2014 22:32:46 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id B8E9FE0AD6; Fri, 15 Aug 2014 22:32:42 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 05C97E0AC3 for ; Fri, 15 Aug 2014 22:32:40 +0000 (UTC) Received: from spoonbill.gentoo.org (spoonbill.gentoo.org [81.93.255.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 5E2353405DF for ; Fri, 15 Aug 2014 22:32:39 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by spoonbill.gentoo.org (Postfix) with ESMTP id 5C9E318821 for ; Fri, 15 Aug 2014 22:32:36 +0000 (UTC) From: "Devan Franchini" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Devan Franchini" Message-ID: <1408138961.c7b86d60b7c32f5bc858a428547e175eab579967.twitch153@gentoo> Subject: [gentoo-commits] proj/layman:gsoc2014 commit in: layman/ X-VCS-Repository: proj/layman X-VCS-Files: layman/module.py X-VCS-Directories: layman/ X-VCS-Committer: twitch153 X-VCS-Committer-Name: Devan Franchini X-VCS-Revision: c7b86d60b7c32f5bc858a428547e175eab579967 X-VCS-Branch: gsoc2014 Date: Fri, 15 Aug 2014 22:32:36 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: f912968e-5749-4e63-b58e-270f779f54ce X-Archives-Hash: 2b3c273cea89170952b57518afb0f620 commit: c7b86d60b7c32f5bc858a428547e175eab579967 Author: Devan Franchini gentoo org> AuthorDate: Tue Jul 29 00:05:59 2014 +0000 Commit: Devan Franchini gentoo 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