""" This module is responsible for instantiating a typical glim framework app. It registers glim framework components, extensions and wsgi app. """ # application initiation script import os import sys import traceback from glim import Config, Log, GlimLog from glim.utils import import_module, empty import glim.paths as paths from termcolor import colored from bottle import Bottle, route, request, response class Glim(object): """ This class is responsible for registering the components of a typical glim framework app Attributes ---------- commandadapter (glim.command.CommandAdapter): The commandadapter object which is responsible for dispatching commands env (string): application environment variable passed from command line mconfig (module): The configuration module imported from app.config.<env> config (dict): The configuration dictionary by environment which resides in app.config.<env> before (method): The before hook function for registering a function before app starts """ def __init__(self, commandadapter, mconfig=None, mroutes=None, mcontrollers=None, env='default', before=None): # register app self.commandadapter = commandadapter self.config = mconfig.config self.urls = mroutes.urls self.mcontrollers = mcontrollers; self.wsgi = Bottle() self.register_config() self.register_log() self.register_extensions() self.register_ssl_context() self.register_routes() self.before = before self.before() def register_config(self): """ Function registers the Config facade using Config(Registry). """ Config.register(self.config) def register_routes(self): """ Function creates instances of controllers, adds into bottle routes """ routes = self.flatten_urls(self.urls) self.controllers = {} controller_names = set() for route in routes: cname = route['endpoint'].split('.')[0] controller_names.add(cname) for cname in controller_names: attr = getattr(self.mcontrollers, cname) instance = attr(request, response) self.controllers[cname] = instance for route in routes: cname, aname = route['endpoint'].split('.') action = getattr(self.controllers[cname], aname) self.wsgi.route(route['url'], route['methods'], action) def register_extensions(self): """ Function registers extensions given extensions list Args ---- extensions (list) : the extensions dict on app.config.<env> Raises ------ Exception: Raises exception when extension can't be loaded properly. """ try: for extension, config in self.config['extensions'].items(): extension_bstr = '' # gather package name if exists extension_pieces = extension.split('.') # if the extensions is not in glim_extensions package if len(extension_pieces) > 1: extension_bstr = '.'.join(extension_pieces) else: # if the extension is in glim_extensions package extension_bstr = 'glim_extensions.%s' % extension_pieces[0] extension_module = import_module(extension_bstr) if extension_module: extension_startstr = '%s.%s' % (extension_bstr, 'start') extension_start = import_module(extension_startstr, pass_errors=True) extension_cmdsstr = '%s.%s' % (extension_bstr, 'commands') extension_cmds = import_module(extension_cmdsstr, pass_errors=True) if extension_start is not None: before = extension_start.before before(config) if extension_cmds is not None: if self.commandadapter is not None: self.commandadapter.register_extension(extension_cmds, extension_pieces[0]) else: GlimLog.error('Extension %s could not be loaded' % extension) except Exception as e: GlimLog.error(traceback.format_exc()) def register_log(self): """ Function registers Log facade using configuration in app.config.<env>. Note: The Log facade will be registered using default configuration if there isn't any 'log' key in app.config.<env>. """ if not empty('log', self.config): if not empty('glim', self.config['log']): GlimLog.boot(name='glim', config=self.config['log']['glim']) else: GlimLog.boot(name='glim') if not empty('app', self.config['log']): Log.boot(name='app', config=self.config['log']['app']) else: Log.boot(name='app') else: Log.boot(name='app') GlimLog.boot(name='glim') def register_ssl_context(self): """ Function detects ssl context """ if not empty('ssl', self.config['app']): self.ssl_context = self.config['app']['ssl'] else: self.ssl_context = None def flatten_urls(self, urls): """ Function flatten urls for route grouping feature of glim. Args ---- urls (dict): a dict of url definitions. current_key (unknown type): a dict or a string marking the current key that is used for recursive calls. ruleset (dict): the ruleset that is eventually returned to dispatcher. Returns ------- ruleset (list): a list of ruleset dict with endpoint, url and method functions """ available_methods = ['POST', 'PUT', 'OPTIONS', 'GET', 'DELETE', 'TRACE', 'COPY'] ruleset = [] for route, endpoint in urls.items(): route_pieces = route.split(' ') try: methods = url = None if len(route_pieces) > 1: methods = [route_pieces[0]] url = route_pieces[1] else: methods = available_methods url = route_pieces[0] endpoint_pieces = endpoint.split('.') if len(endpoint_pieces) > 1: rule = {'url': url, 'endpoint': endpoint, 'methods': methods} ruleset.append(rule) else: for method in available_methods: rule = { 'url': url, 'endpoint': '%s.%s' % (endpoint, method.lower()), 'methods': [method] } ruleset.append(rule) except Exception as e: raise InvalidRouteDefinitionError() return ruleset