text: #!/usr/bin/env python
  # encoding: utf-8
  # __init__.py
  '''
  Pybald
  ======
  
  An MVC-like framework using many best-of-breed components (i.e. webob,
  sqlalchemy).
  
  (c) 2015 Michael Kowalchik
  MIT License, see LICENSE file
  '''
  import imp
  import sys
  import os
  from pybald.util.context import AppContext
  import logging
  from .default import default_config
  from collections import namedtuple
  log = logging.getLogger(__name__)
  
  __version__ = '0.5.2'
  
  
  def read_config_module(root_path='.', filename='project.py'):
      '''Read a configuration module and append it's path to sys.path'''
      # since the config module may have relative imports
      # add the _config files_ path to root before executing the config
      if root_path not in sys.path:
          sys.path.insert(1, root_path)
      filename = os.path.join(root_path, filename)
      config_module = imp.new_module("config")
      config_module.__dict__['__file__'] = filename
      config_module.__dict__['path'] = root_path
      with open(filename) as config_file:
          exec(compile(config_file.read(), filename, 'exec'),
               config_module.__dict__)
      return config_module
  
  
  class Unconfigured(object):
      def __getattr__(self, key):
          raise RuntimeError("Pybald is not configured, you must run "
                             "pybald.configure() before context.{0} can"
                             " be used".format(key))
  
  
  class DefaultApp(dict):
      def __init__(self, *pargs, **kargs):
          self.register('config', {})
          self.register('controller_registry', [])
          # self.register('model_registry', [])
          self.unconfigured = True
          super(DefaultApp, self).__init__(*pargs, **kargs)
  
      # def __getattr__(self, key):
      #     if key in ('models', 'engine', 'metdata'):
      #         raise RuntimeError("Pybald is not configured, you must run "
      #                            "pybald.configure() before context.{0} can"
      #                            " be used".format(key))
      #     else:
      #         return super(DefaultApp, self).__getattr__(key)
  
      def register(self, key, value):
          self[key] = value
          setattr(self, key, self[key])
  
  # unconfigured application stack context
  context = AppContext()
  # register the context as a module
  sys.modules['pybald.context'] = context
  # push the default placeholder app onto the context stack
  # the default allows for temporary storage of elements required
  # for bootstrapping (and eliminates some sequencing requirements
  # for configuration)
  context._push(DefaultApp())
  
  # the template engine and database session are built at config time
  context_template = '''
  from pybald.core.templates import TemplateEngine
  from pybald.util.command_line import start
  from pybald.core.models import ContextBoundModels
  from pybald.db.db_engine import create_dump_engine
  
  render = TemplateEngine()
  dump_engine = create_dump_engine()
  if config.database_engine_uri:
      models = ContextBoundModels()
      db = models.db
  else:
      models = Unconfigured()
      db = Unconfigured()
  
  def register(key, value):
      globals()[key] = value
  
  '''
  
  
  def create_config_dict_from_module(module):
      '''Converts a module into a dictionary filtering out common module
      level attributes'''
      return {key: getattr(module, key) for key in module.__dict__.keys() if
              not key.startswith('_') and key not in ('sys', 'os')}
  
  
  def create_config_object(config_object):
      '''Convert a config dictionary to a config object named tuple
      and combines it with the default configuration dictionary.'''
      keys = set(default_config.keys()) | set(config_object.keys())
      ConfigObject = namedtuple("ConfigObject", keys)
      return ConfigObject(**dict(list(default_config.items()) +
                                 list(config_object.items())))
  
  
  def bootstrap(bootstrap_file=None):
      '''Execute the python file passed in. It's assumed that the bootstrap
      python module file will execute configure() before returning although
      not strictly necessary
  
      This is intended for complicated projects that need to do a lot of
      dynamic stuff before configuring the project. It's primarily a convenience
      hook that sets the sys.path to the current working directory before
      executing the module import.
  
      Use of this method should be rare, ask yourself if you really need it :)
      '''
      # since bootstrap can be anywhere, add bootstrap to sys.path as well
      if os.getcwd() not in sys.path:
          sys.path.insert(1, os.getcwd())
      possible_root_path = os.getcwd()
      root_path, filename = os.path.split(os.path.join(possible_root_path,
                                                       bootstrap_file))
      if root_path not in sys.path:
          sys.path.insert(1, root_path)
      filename = os.path.join(root_path, filename)
      bootstrap_module = imp.new_module("bootstrap")
      bootstrap_module.__dict__['__file__'] = filename
      with open(filename) as bootstrap_file:
          exec(compile(bootstrap_file.read(), filename, 'exec'),
               bootstrap_module.__dict__)
      return bootstrap_module
  
  
  def configure(name=None, config_file=None, config_object=None, **kargs):
      '''
      Generate a dynamic context module that's pushed / popped on
      the application context stack.
      '''
      script_name = sys.argv[0]
      # always add current working directory to the path regardless
      # was trying to avoid this but too much path munging happening
      if os.getcwd() not in sys.path:
          sys.path.insert(1, os.getcwd())
  
      if config_object:
          if 'project_name' not in config_object:
              config_object['project_name'] = script_name
          # create a named tuple that's the combo of default plus input dict
          root_path = config_object['path'] = config_object.get('path',
                                                                os.getcwd())
          config = create_config_object(config_object)
          # add root path to config?
      elif config_file:
          # possible root path if relative filename specified
          possible_root_path = os.getcwd()
          root_path, filename = os.path.split(os.path.join(possible_root_path,
                                                           config_file))
          try:
              config_module = read_config_module(root_path=root_path,
                                                 filename=filename)
          except IOError:
              log.exception("Config Error:\n"
                            "File Error or File not "
                            "found\n{0}".format(config_file))
              sys.exit(1)
          config = create_config_object(create_config_dict_from_module(config_module))
      elif kargs:
          if 'project_name' not in kargs:
              kargs['project_name'] = script_name
  
          root_path = kargs['path'] = kargs.get('path',
                                                os.getcwd())
          config = create_config_object(kargs)
      else:
          root_path = os.getcwd()
          log.warning("Warning: Using current path for the config "
                      "file {0}".format(root_path))
          if root_path not in sys.path:
              sys.path.insert(1, root_path)
          try:
              config_module = read_config_module(root_path=root_path,
                                                 filename='project.py')
              log.warning("Found project.py in default path, "
                          "using for the config file")
          except IOError:
              config = create_config_object(default_config)
              log.warning("No config file, using default pybald configuration")
          else:
              config = create_config_object(create_config_dict_from_module(config_module))
  
      # if the discovered root_path is not in sys.path, add it in the least ugly
      # way possible
      if root_path not in sys.path:
          sys.path.insert(1, root_path)
  
      if config.debug:
          from pybald.core.logs import default_debug_log
          default_debug_log()
  
      new_context = imp.new_module("context")
  
      if context._proxied() and hasattr(context._proxied(), 'unconfigured'):
          # if we're at the root, consume any placeholder values
          placeholder = context._pop()
          new_context.__dict__.update(placeholder)
      else:
          new_context.__dict__['controller_registry'] = []
      # always set the runtime config
      new_context.__dict__['path'] = root_path
      new_context.__dict__['config'] = config
      new_context.__dict__['name'] = name
      new_context.__dict__['__file__'] = None
      new_context.__dict__['Unconfigured'] = Unconfigured
      # new_context.__dict__['__path__'] = None
      # now execute the app context with this config
      context._push(new_context)
      exec(compile(context_template, '<string>', 'exec'), new_context.__dict__)
      return new_context
  