summaryrefslogtreecommitdiffstats
path: root/base/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'base/base.py')
-rw-r--r--base/base.py216
1 files changed, 216 insertions, 0 deletions
diff --git a/base/base.py b/base/base.py
new file mode 100644
index 0000000..214d1d5
--- /dev/null
+++ b/base/base.py
@@ -0,0 +1,216 @@
+import logging
+import os
+
+from inspect import isclass
+from collections import deque
+from os.path import join
+
+
+from module import Module
+from vars import __description__, __version__, header, prompt
+
+
+log = logging.getLogger('devshell')
+modules = {}
+
+def print_docstrings(module=None):
+ """
+ Print out the docstrings for all methods in the specified module.
+ If no module is specified, then display docstrings for all modules.
+
+ Arguments:
+ module: an object subclassing Module (optional)
+ """
+ def _print_docstrings(name, module):
+ log.info(header(name))
+ for prop in filter(lambda x: x[0] != '_', dir(module)):
+ if callable(getattr(module, prop)) and hasattr(module, '__doc__') \
+ and getattr(module, prop).__doc__:
+ log.info(" |- [%s] %s" % (prop,
+ getattr(module, prop).__doc__.strip()))
+ if not module:
+ for name, module in modules.items():
+ _print_docstrings(name, module)
+ else:
+ _print_docstrings(str(module.__class__).split('.')[-1], module)
+
+def load_modules():
+ global modules
+ log.debug("Loading modules")
+ #TODO: better way to find modules
+ for f in os.listdir(os.path.abspath('modules')):
+ module_name, ext = os.path.splitext(f)
+ if ext == '.py':
+ exec "from modules import %s as module" % module_name
+ for item in dir(module):
+ obj = getattr(module, item)
+ if item[0] != '_' and isclass(obj):
+ log.debug('%s is subclass of Module: %s' %\
+ (obj, issubclass(obj, Module)))
+ if item[0] != '_' and isclass(obj) and issubclass(obj, Module) \
+ and obj is not Module:
+ modules[item.lower()] = obj
+ log.info(" * %s" % item)
+ del module
+
+def load_module(name, data=[]):
+ top = None
+ try:
+ log.debug("Loading %s.__init__(%s)" % (name, data))
+ top = modules[name](*data)
+ except TypeError, e:
+ log.debug('got type error')
+ log.error("%s: %s" % (name, e))
+ raise ModuleError('probably bad call to __init__' , e)
+ return top
+
+def shell():
+ while True:
+ try:
+ data = raw_input('/'.join(shell.prompt) + '> ')
+ except (EOFError, KeyboardInterrupt):
+ print
+ break
+ if not data: continue
+ if data in ('quit', 'exit'): break
+ keyword = data.split()[0]
+ args = data.split()[1:]
+
+ # Show the docstrings to all methods for all loaded modules
+ if keyword == 'help':
+ print_docstrings()
+
+ # Go up a module in our stack
+ elif keyword in ('up', 'cd..', 'cd ..'):
+ shell.stack = shell.stack[:-1]
+ shell.prompt = shell.prompt[:-1]
+
+ # Show the docstrings for all methods in our current module
+ elif keyword in ('ls', 'help', '?'):
+ if len(shell.stack):
+ print_docstrings(shell.stack[-1])
+ else:
+ print_docstrings()
+
+ # Flush our module stack
+ elif keyword == 'cd':
+ shell.stack = []
+ shell.prompt = prompt
+
+ # iPython. Never leave home without it.
+ elif keyword in ('py', 'python'):
+ os.system("ipython -noconfirm_exit")
+ else:
+ #figure out if there is a top
+ if len(shell.stack):
+ top = shell.stack[-1]
+ else:
+ top = None
+ output, top, params = do_command(data.split(), top)
+ if top:
+ shell.stack += [top]
+ shell.prompt += [top.__class__.__name__] + params
+shell.stack = []
+shell.prompt = prompt
+
+def do_command(data, top=None):
+
+ # Do some intelligent handling of unknown input.
+ # For the given input 'foo bar', we first check if we have the
+ # module 'foo' loaded, then we push it on the top of our module
+ # stack and check if it has the 'bar' attribute. If so, we call
+ # it with any remaining arguments
+ data = deque(data)
+ log.debug(data)
+ params = []
+
+ module = None
+ while len(data):
+ if not top:
+ log.debug('not top')
+ mod = data.popleft()
+ try:
+ module = modules[mod]
+ except KeyError, e:
+ log.error('%s is not a known module' % e.message)
+ return None, None, None
+ log.debug('mod is %s' % mod)
+ params = []
+ while len(data):
+ log.debug('params so far %s' % params)
+ log.debug('inner loop %s' % data)
+ param = data.popleft()
+ if hasattr(module, param):
+ data.appendleft(param)
+ break
+ params += [param]
+ try:
+ top = module = load_module(mod, params)
+ mod_params = params
+ loaded_module = True
+ except ModuleError, e:
+ log.debug(e.reason)
+ break
+ else:
+ log.debug('is top')
+ params = []
+ log.debug('params so far %s' % params)
+ param = data.popleft()
+ if hasattr(top, param):
+ log.debug("next property %s found in %s" % (param, top))
+ top = getattr(top, param)
+ else:
+ log.debug("adding argument: %s" % param)
+ params += [param]
+ output = None
+ if len(params):
+ output = top(*params)
+
+ if module:
+ return output, module, mod_params
+ else:
+ return output, None, None
+
+def setup_options():
+ '''Sets up an options parser for all command line utilities
+
+ Arguements:
+ none: none!
+
+ Return Values:
+ opts: an object containing the options specified
+ args: remaining arguments
+ '''
+ from optparse import OptionParser
+ parser = OptionParser(usage="%prog [options]",
+ version="%s %s" % ('%prog', __version__),
+ description=__description__)
+ parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
+ help='Display verbose debugging output')
+ return parser.parse_args()
+
+def setup_logger(opts):
+ '''Configures the logger system to the environment
+
+ Arguments:
+ opts: options from an OptionParser
+
+ Return Values:
+ none: none!
+ '''
+ global log
+ # Setup our logger
+ sh = logging.StreamHandler()
+ if opts.verbose:
+ log.setLevel(logging.DEBUG)
+ sh.setLevel(logging.DEBUG)
+ format = logging.Formatter("[%(levelname)s] %(message)s")
+ else:
+ log.setLevel(logging.INFO)
+ sh.setLevel(logging.INFO)
+ format = logging.Formatter("%(message)s")
+ sh.setFormatter(format)
+ log.addHandler(sh)
+
+__all__ = ['do_command', 'log', 'setup_options', 'load_module', 'shell',
+ 'print_docstrings', 'modules', 'setup_logger', 'load_modules'] \ No newline at end of file