A bunch of cleanup, and the removal of a few features:
* Consolidating a considerable amount of duplicate (for loading a Pecan app and its environment) into `pecan.core.load_app`. * Removing support for module-based configurations. * Wrote a simple utility for loading a test environment, `pecan.testing.load_test_app`.
This commit is contained in:
@@ -9,7 +9,7 @@ from paste.urlparser import StaticURLParser
|
||||
from weberror.errormiddleware import ErrorMiddleware
|
||||
from weberror.evalexception import EvalException
|
||||
|
||||
from core import abort, error_for, override_template, Pecan, redirect, render, request, response, ValidationException
|
||||
from core import abort, error_for, override_template, Pecan, load_app, redirect, render, request, response, ValidationException
|
||||
from decorators import expose
|
||||
from hooks import RequestViewerHook
|
||||
from templating import error_formatters
|
||||
@@ -18,7 +18,7 @@ from configuration import set_config
|
||||
from configuration import _runtime_conf as conf
|
||||
|
||||
__all__ = [
|
||||
'make_app', 'Pecan', 'request', 'response', 'override_template', 'expose', 'conf', 'set_config'
|
||||
'make_app', 'load_app', 'Pecan', 'request', 'response', 'override_template', 'expose', 'conf', 'set_config'
|
||||
]
|
||||
|
||||
def make_app(root, static_root=None, debug=False, errorcfg={}, wrap_app=None, logging=False, **kw):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
PasteScript base command for Pecan.
|
||||
"""
|
||||
from pecan import load_app
|
||||
from pecan.configuration import _runtime_conf, set_config
|
||||
from paste.script import command as paste_command
|
||||
|
||||
@@ -31,37 +32,18 @@ class Command(paste_command.Command):
|
||||
except paste_command.BadCommand, ex:
|
||||
ex.args[0] = self.parser.error(ex.args[0])
|
||||
raise
|
||||
|
||||
def get_package_names(self, config):
|
||||
if not hasattr(config.app, 'modules'):
|
||||
return []
|
||||
return config.app.modules
|
||||
|
||||
def import_module(self, package, name):
|
||||
parent = __import__(package, fromlist=[name])
|
||||
return getattr(parent, name, None)
|
||||
|
||||
def load_configuration(self, name):
|
||||
set_config(name)
|
||||
return _runtime_conf
|
||||
|
||||
def load_app(self, config):
|
||||
for package_name in self.get_package_names(config):
|
||||
module = self.import_module(package_name, 'app')
|
||||
if hasattr(module, 'setup_app'):
|
||||
return module.setup_app(config)
|
||||
raise paste_command.BadCommand('No app.setup_app found in any app modules')
|
||||
|
||||
def load_model(self, config):
|
||||
for package_name in self.get_package_names(config):
|
||||
module = self.import_module(package_name, 'model')
|
||||
if module:
|
||||
return module
|
||||
return None
|
||||
|
||||
def load_app(self):
|
||||
return load_app(self.validate_file(self.args))
|
||||
|
||||
def logging_file_config(self, config_file):
|
||||
if os.path.splitext(config_file)[1].lower() == '.ini':
|
||||
paste_command.Command.logging_file_config(self, config_file)
|
||||
|
||||
def validate_file(self, argv):
|
||||
if not argv or not os.path.isfile(argv[0]):
|
||||
raise paste_command.BadCommand('This command needs a valid config file.')
|
||||
return argv[0]
|
||||
|
||||
def command(self):
|
||||
pass
|
||||
|
||||
@@ -45,25 +45,11 @@ class ServeCommand(_ServeCommand, Command):
|
||||
setattr(self.options, 'server', None)
|
||||
setattr(self.options, 'server_name', None)
|
||||
|
||||
config_file = self.validate_file(self.args)
|
||||
|
||||
# for file-watching to work, we need a filename, not a module
|
||||
if self.requires_config_file and self.args:
|
||||
self.config = self.load_configuration(config_file)
|
||||
self.args[0] = self.config.__file__
|
||||
if self.options.reload is None:
|
||||
self.options.reload = getattr(self.config.app, 'reload', False)
|
||||
|
||||
# run the base command
|
||||
_ServeCommand.command(self)
|
||||
|
||||
def loadserver(self, server_spec, name, relative_to, **kw):
|
||||
return (lambda app: httpserver.serve(app, self.config.server.host, self.config.server.port))
|
||||
return (lambda app: httpserver.serve(app, app.config.server.host, app.config.server.port))
|
||||
|
||||
def loadapp(self, app_spec, name, relative_to, **kw):
|
||||
return self.load_app(self.config)
|
||||
|
||||
def validate_file(self, argv):
|
||||
if not argv or not os.path.isfile(argv[0]):
|
||||
raise paste_command.BadCommand('This command needs a valid config file.')
|
||||
return argv[0]
|
||||
return self.load_app()
|
||||
|
||||
@@ -24,9 +24,7 @@ class ShellCommand(Command):
|
||||
def command(self):
|
||||
|
||||
# load the application
|
||||
config = self.load_configuration(self.args[0])
|
||||
setattr(config.app, 'reload', False)
|
||||
app = self.load_app(config)
|
||||
app = self.load_app()
|
||||
|
||||
# prepare the locals
|
||||
locs = dict(__name__='pecan-admin')
|
||||
@@ -34,7 +32,7 @@ class ShellCommand(Command):
|
||||
locs['app'] = TestApp(app)
|
||||
|
||||
# find the model for the app
|
||||
model = self.load_model(config)
|
||||
model = getattr(app, 'model', None)
|
||||
if model:
|
||||
locs['model'] = model
|
||||
|
||||
|
||||
@@ -5,6 +5,27 @@ import os
|
||||
|
||||
IDENTIFIER = re.compile(r'[a-z_](\w)*$', re.IGNORECASE)
|
||||
|
||||
DEFAULT = {
|
||||
# Server Specific Configurations
|
||||
'server' : {
|
||||
'port' : '8080',
|
||||
'host' : '0.0.0.0'
|
||||
},
|
||||
|
||||
# Pecan Application Configurations
|
||||
'app' : {
|
||||
'root' : None,
|
||||
'modules' : [],
|
||||
'static_root' : 'public',
|
||||
'template_path' : '',
|
||||
'debug' : False,
|
||||
'force_canonical' : True,
|
||||
'errors' : {
|
||||
'__force_dict__' : True
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigDict(dict):
|
||||
pass
|
||||
|
||||
@@ -80,15 +101,6 @@ class Config(object):
|
||||
conf_obj = dict(self)
|
||||
return self.__dictify__(conf_obj, prefix)
|
||||
|
||||
def update_with_module(self, module):
|
||||
'''
|
||||
Updates this configuration with a module.
|
||||
|
||||
:param module: The module to update this configuration with. Either a string or the module itself.
|
||||
'''
|
||||
|
||||
self.update(conf_from_module(module))
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self.__values__[name]
|
||||
@@ -123,20 +135,6 @@ class Config(object):
|
||||
def __repr__(self):
|
||||
return 'Config(%s)' % str(self.__values__)
|
||||
|
||||
def conf_from_module(module):
|
||||
'''
|
||||
Creates a configuration dictionary from a module.
|
||||
|
||||
:param module: The module, either as a string or the module itself.
|
||||
'''
|
||||
|
||||
if isinstance(module, str):
|
||||
module = import_module(module)
|
||||
|
||||
module_dict = dict(inspect.getmembers(module))
|
||||
|
||||
return conf_from_dict(module_dict)
|
||||
|
||||
|
||||
def conf_from_file(filepath):
|
||||
'''
|
||||
@@ -173,48 +171,23 @@ def conf_from_dict(conf_dict):
|
||||
return conf
|
||||
|
||||
|
||||
def import_module(conf):
|
||||
'''
|
||||
Imports the a configuration as a module.
|
||||
|
||||
:param conf: The string to the configuration. Automatically strips off ".py" file extensions.
|
||||
'''
|
||||
|
||||
if '.' in conf:
|
||||
parts = conf.split('.')
|
||||
name = '.'.join(parts[:-1])
|
||||
fromlist = parts[-1:]
|
||||
|
||||
try:
|
||||
module = __import__(name, fromlist=fromlist)
|
||||
conf_mod = getattr(module, parts[-1])
|
||||
except AttributeError, e:
|
||||
raise ImportError('No module named %s' % conf)
|
||||
else:
|
||||
conf_mod = __import__(conf)
|
||||
|
||||
return conf_mod
|
||||
|
||||
|
||||
def initconf():
|
||||
'''
|
||||
Initializes the default configuration and exposes it at ``pecan.configuration.conf``,
|
||||
which is also exposed at ``pecan.conf``.
|
||||
'''
|
||||
|
||||
import default_config
|
||||
conf = conf_from_module(default_config)
|
||||
return conf
|
||||
return conf_from_dict(DEFAULT)
|
||||
|
||||
|
||||
def set_config(name):
|
||||
def set_config(name, overwrite=False):
|
||||
'''
|
||||
Updates the global configuration a filename.
|
||||
|
||||
:param name: filename, as a string.
|
||||
'''
|
||||
|
||||
_runtime_conf.update(conf_from_file(name))
|
||||
conf = conf_from_file(name)
|
||||
_runtime_conf.update(conf)
|
||||
|
||||
|
||||
_runtime_conf = initconf()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from configuration import _runtime_conf, set_config
|
||||
from templating import RendererFactory
|
||||
from routing import lookup_controller, NonCanonicalPath
|
||||
from util import _cfg, splitext, encode_if_needed
|
||||
@@ -171,6 +172,26 @@ class ValidationException(ForwardRequestException):
|
||||
ForwardRequestException.__init__(self, location)
|
||||
|
||||
|
||||
def load_app(config):
|
||||
'''
|
||||
Used to load a ``Pecan`` application and its environment based on passed
|
||||
configuration.
|
||||
|
||||
:param config: Can be a dictionary containing configuration, or a string which
|
||||
represents a (relative) configuration filename.
|
||||
:returns a pecan.Pecan object
|
||||
'''
|
||||
set_config(config, overwrite=True)
|
||||
|
||||
for package_name in getattr(_runtime_conf.app, 'modules', []):
|
||||
module = __import__(package_name, fromlist=['app'])
|
||||
if hasattr(module, 'app') and hasattr(module.app, 'setup_app'):
|
||||
app = module.app.setup_app(_runtime_conf)
|
||||
app.config = _runtime_conf
|
||||
return app
|
||||
raise RuntimeError('No app.setup_app found in any of the configured app.modules')
|
||||
|
||||
|
||||
class Pecan(object):
|
||||
'''
|
||||
Base Pecan application object. Generally created using ``pecan.make_app``,
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# Server Specific Configurations
|
||||
server = {
|
||||
'port' : '8080',
|
||||
'host' : '0.0.0.0'
|
||||
}
|
||||
|
||||
# Pecan Application Configurations
|
||||
app = {
|
||||
'root' : None,
|
||||
'modules' : [],
|
||||
'static_root' : 'public',
|
||||
'template_path' : '',
|
||||
'debug' : False,
|
||||
'force_canonical' : True,
|
||||
'errors' : {
|
||||
'__force_dict__' : True
|
||||
}
|
||||
}
|
||||
|
||||
# Custom Configurations must be in Python dictionary format in user config
|
||||
#
|
||||
# foo = {'bar':'baz'}
|
||||
#
|
||||
# All configurations are accessible at::
|
||||
# pecan.conf
|
||||
@@ -1,14 +1,4 @@
|
||||
from configuration import set_config, import_module, _runtime_conf as conf
|
||||
|
||||
def deploy(config_module_or_path):
|
||||
set_config(config_module_or_path)
|
||||
for module in getattr(conf.app, 'modules'):
|
||||
try:
|
||||
module_app = import_module('%s.app' % module)
|
||||
if hasattr(module_app, 'setup_app'):
|
||||
return module_app.setup_app(conf)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
raise Exception, 'No app.setup_app found in any of the configured app.modules'
|
||||
from core import load_app
|
||||
|
||||
def deploy(config):
|
||||
return load_app(config)
|
||||
|
||||
5
pecan/testing.py
Normal file
5
pecan/testing.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from pecan import load_app
|
||||
from webtest import TestApp
|
||||
|
||||
def load_test_app(config):
|
||||
return TestApp(load_app(config))
|
||||
Reference in New Issue
Block a user