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.errormiddleware import ErrorMiddleware
|
||||||
from weberror.evalexception import EvalException
|
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 decorators import expose
|
||||||
from hooks import RequestViewerHook
|
from hooks import RequestViewerHook
|
||||||
from templating import error_formatters
|
from templating import error_formatters
|
||||||
@@ -18,7 +18,7 @@ from configuration import set_config
|
|||||||
from configuration import _runtime_conf as conf
|
from configuration import _runtime_conf as conf
|
||||||
|
|
||||||
__all__ = [
|
__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):
|
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.
|
PasteScript base command for Pecan.
|
||||||
"""
|
"""
|
||||||
|
from pecan import load_app
|
||||||
from pecan.configuration import _runtime_conf, set_config
|
from pecan.configuration import _runtime_conf, set_config
|
||||||
from paste.script import command as paste_command
|
from paste.script import command as paste_command
|
||||||
|
|
||||||
@@ -31,37 +32,18 @@ class Command(paste_command.Command):
|
|||||||
except paste_command.BadCommand, ex:
|
except paste_command.BadCommand, ex:
|
||||||
ex.args[0] = self.parser.error(ex.args[0])
|
ex.args[0] = self.parser.error(ex.args[0])
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_package_names(self, config):
|
def load_app(self):
|
||||||
if not hasattr(config.app, 'modules'):
|
return load_app(self.validate_file(self.args))
|
||||||
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 logging_file_config(self, config_file):
|
def logging_file_config(self, config_file):
|
||||||
if os.path.splitext(config_file)[1].lower() == '.ini':
|
if os.path.splitext(config_file)[1].lower() == '.ini':
|
||||||
paste_command.Command.logging_file_config(self, config_file)
|
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):
|
def command(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -45,25 +45,11 @@ class ServeCommand(_ServeCommand, Command):
|
|||||||
setattr(self.options, 'server', None)
|
setattr(self.options, 'server', None)
|
||||||
setattr(self.options, 'server_name', 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
|
# run the base command
|
||||||
_ServeCommand.command(self)
|
_ServeCommand.command(self)
|
||||||
|
|
||||||
def loadserver(self, server_spec, name, relative_to, **kw):
|
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):
|
def loadapp(self, app_spec, name, relative_to, **kw):
|
||||||
return self.load_app(self.config)
|
return self.load_app()
|
||||||
|
|
||||||
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]
|
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ class ShellCommand(Command):
|
|||||||
def command(self):
|
def command(self):
|
||||||
|
|
||||||
# load the application
|
# load the application
|
||||||
config = self.load_configuration(self.args[0])
|
app = self.load_app()
|
||||||
setattr(config.app, 'reload', False)
|
|
||||||
app = self.load_app(config)
|
|
||||||
|
|
||||||
# prepare the locals
|
# prepare the locals
|
||||||
locs = dict(__name__='pecan-admin')
|
locs = dict(__name__='pecan-admin')
|
||||||
@@ -34,7 +32,7 @@ class ShellCommand(Command):
|
|||||||
locs['app'] = TestApp(app)
|
locs['app'] = TestApp(app)
|
||||||
|
|
||||||
# find the model for the app
|
# find the model for the app
|
||||||
model = self.load_model(config)
|
model = getattr(app, 'model', None)
|
||||||
if model:
|
if model:
|
||||||
locs['model'] = model
|
locs['model'] = model
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,27 @@ import os
|
|||||||
|
|
||||||
IDENTIFIER = re.compile(r'[a-z_](\w)*$', re.IGNORECASE)
|
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):
|
class ConfigDict(dict):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -80,15 +101,6 @@ class Config(object):
|
|||||||
conf_obj = dict(self)
|
conf_obj = dict(self)
|
||||||
return self.__dictify__(conf_obj, prefix)
|
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):
|
def __getattr__(self, name):
|
||||||
try:
|
try:
|
||||||
return self.__values__[name]
|
return self.__values__[name]
|
||||||
@@ -123,20 +135,6 @@ class Config(object):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Config(%s)' % str(self.__values__)
|
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):
|
def conf_from_file(filepath):
|
||||||
'''
|
'''
|
||||||
@@ -173,48 +171,23 @@ def conf_from_dict(conf_dict):
|
|||||||
return conf
|
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():
|
def initconf():
|
||||||
'''
|
'''
|
||||||
Initializes the default configuration and exposes it at ``pecan.configuration.conf``,
|
Initializes the default configuration and exposes it at ``pecan.configuration.conf``,
|
||||||
which is also exposed at ``pecan.conf``.
|
which is also exposed at ``pecan.conf``.
|
||||||
'''
|
'''
|
||||||
|
return conf_from_dict(DEFAULT)
|
||||||
import default_config
|
|
||||||
conf = conf_from_module(default_config)
|
|
||||||
return conf
|
|
||||||
|
|
||||||
|
|
||||||
def set_config(name):
|
def set_config(name, overwrite=False):
|
||||||
'''
|
'''
|
||||||
Updates the global configuration a filename.
|
Updates the global configuration a filename.
|
||||||
|
|
||||||
:param name: filename, as a string.
|
: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()
|
_runtime_conf = initconf()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from configuration import _runtime_conf, set_config
|
||||||
from templating import RendererFactory
|
from templating import RendererFactory
|
||||||
from routing import lookup_controller, NonCanonicalPath
|
from routing import lookup_controller, NonCanonicalPath
|
||||||
from util import _cfg, splitext, encode_if_needed
|
from util import _cfg, splitext, encode_if_needed
|
||||||
@@ -171,6 +172,26 @@ class ValidationException(ForwardRequestException):
|
|||||||
ForwardRequestException.__init__(self, location)
|
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):
|
class Pecan(object):
|
||||||
'''
|
'''
|
||||||
Base Pecan application object. Generally created using ``pecan.make_app``,
|
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
|
from core import load_app
|
||||||
|
|
||||||
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'
|
|
||||||
|
|
||||||
|
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