Merge pull request #45 from ryanpetrello/next
A bunch of cleanup, and the removal of a few featuresPulling after review from Jon and Mark.
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
[run]
|
||||
omit = pecan/commands/*.py, pecan/templates/__init__.py, pecan/testing.py
|
||||
@@ -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,17 +24,14 @@ 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')
|
||||
locs['wsgiapp'] = app
|
||||
locs['app'] = TestApp(app)
|
||||
|
||||
# find the model for the app
|
||||
model = self.load_model(config)
|
||||
model = self.load_model(app.config)
|
||||
if model:
|
||||
locs['model'] = model
|
||||
|
||||
@@ -67,3 +64,10 @@ class ShellCommand(Command):
|
||||
except ImportError:
|
||||
pass
|
||||
shell.interact(shell_banner + banner)
|
||||
|
||||
def load_model(self, config):
|
||||
for package_name in getattr(config.app, 'modules', []):
|
||||
module = __import__(package_name, fromlist=['model'])
|
||||
if hasattr(module, 'model'):
|
||||
return module.model
|
||||
return None
|
||||
|
||||
@@ -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,31 @@ 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(config, overwrite=False):
|
||||
'''
|
||||
Updates the global configuration a filename.
|
||||
|
||||
:param name: filename, as a string.
|
||||
:param config: Can be a dictionary containing configuration, or a string which
|
||||
represents a (relative) configuration filename.
|
||||
'''
|
||||
|
||||
_runtime_conf.update(conf_from_file(name))
|
||||
if overwrite is True:
|
||||
_runtime_conf.__values__ == {}
|
||||
|
||||
if isinstance(config, basestring):
|
||||
_runtime_conf.update(conf_from_file(config))
|
||||
elif isinstance(config, dict):
|
||||
_runtime_conf.update(conf_from_dict(config))
|
||||
else:
|
||||
raise TypeError('%s is neither a dictionary of a string.' % config)
|
||||
|
||||
|
||||
_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``,
|
||||
@@ -438,11 +459,14 @@ class Pecan(object):
|
||||
elif cfg.get('content_type') is not None and \
|
||||
request.pecan['content_type'] not in cfg.get('content_types', {}):
|
||||
|
||||
print "Controller '%s' defined does not support content_type '%s'. Supported type(s): %s" % (
|
||||
import warnings
|
||||
warnings.warn("Controller '%s' defined does not support content_type '%s'. Supported type(s): %s" % (
|
||||
controller.__name__,
|
||||
request.pecan['content_type'],
|
||||
cfg.get('content_types', {}).keys()
|
||||
)
|
||||
),
|
||||
RuntimeWarning
|
||||
)
|
||||
raise exc.HTTPNotFound
|
||||
|
||||
# get a sorted list of hooks, by priority
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
"""
|
||||
Plugin for py.test that sets up the app.
|
||||
|
||||
App configuration inspired by the Pylons nose equivalent:
|
||||
https://github.com/Pylons/pylons/blob/master/pylons/test.py
|
||||
|
||||
Handling of multiprocessing inspired by pytest-cov.
|
||||
"""
|
||||
from configuration import set_config, _runtime_conf as conf
|
||||
from tempfile import mkdtemp
|
||||
|
||||
import py
|
||||
import py.test
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import sys
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
"""
|
||||
Adds the custom "with-config" option to take in the config file.
|
||||
"""
|
||||
group = parser.getgroup('pecan')
|
||||
group._addoption('--with-config',
|
||||
dest='config_file',
|
||||
metavar='path',
|
||||
default='./test.py',
|
||||
action='store',
|
||||
type='string',
|
||||
help='configuration file for pecan tests')
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
"""
|
||||
Loads the Pecan plugin if using a configuration file.
|
||||
"""
|
||||
if config.getvalue('config_file'):
|
||||
config.pluginmanager.register(PecanPlugin(config), '_pecan')
|
||||
|
||||
|
||||
class PecanPlugin(object):
|
||||
"""
|
||||
Plugin for a Pecan application. Sets up and tears down the
|
||||
WSGI application based on the configuration and session type.
|
||||
"""
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.impl = None
|
||||
|
||||
def pytest_namespace(self):
|
||||
"""
|
||||
Add the session variables to the namespace.
|
||||
"""
|
||||
return {
|
||||
'temp_dir': None,
|
||||
'wsgi_app': None
|
||||
}
|
||||
|
||||
def pytest_sessionstart(self, session):
|
||||
"""
|
||||
Set up the testing session.
|
||||
"""
|
||||
self.impl = PecanPluginImpl.create_from_session(session)
|
||||
self.impl.sessionstart(session)
|
||||
|
||||
def pytest_configure_node(self, node):
|
||||
"""
|
||||
Configures a new slave node.
|
||||
"""
|
||||
if self.impl:
|
||||
self.impl.configure_node(node)
|
||||
|
||||
def pytest_runtest_setup(self, item):
|
||||
if self.impl:
|
||||
self.impl.ensure_config_loaded()
|
||||
|
||||
def pytest_testnodedown(self, node, error):
|
||||
"""
|
||||
Tears down an exiting node.
|
||||
"""
|
||||
if self.impl:
|
||||
self.impl.testnodedown(node, error)
|
||||
|
||||
def pytest_sessionfinish(self, session, exitstatus):
|
||||
"""
|
||||
Cleans up the testing session.
|
||||
"""
|
||||
if self.impl:
|
||||
self.impl.sessionfinish(session, exitstatus)
|
||||
|
||||
|
||||
class PecanPluginImpl(object):
|
||||
"""
|
||||
Actual implementation of the Pecan plugin. This ensures the proper
|
||||
environment is configured for each session type.
|
||||
"""
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.log = py.log.Producer('pecan-%s' % self.name)
|
||||
if not config.option.debug:
|
||||
py.log.setconsumer(self.log._keywords, None)
|
||||
self.log('Created %s instance' % self.__class__.__name__)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return 'main'
|
||||
|
||||
def _setup_app(self):
|
||||
self.log('Invoking setup_app')
|
||||
path = os.getcwd()
|
||||
if path not in sys.path:
|
||||
sys.path.insert(0, path)
|
||||
set_config(self.config.getvalue('config_file'))
|
||||
py.test.wsgi_app = self._load_app(conf)
|
||||
|
||||
def _get_package_names(self, config):
|
||||
if not hasattr(config.app, 'modules'):
|
||||
return []
|
||||
return [module.__name__ for module in config.app.modules if hasattr(module, '__name__')]
|
||||
|
||||
def _can_import(self, name):
|
||||
try:
|
||||
__import__(name)
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
def _load_app(self, config):
|
||||
for package_name in self._get_package_names(config):
|
||||
module_name = '%s.app' % package_name
|
||||
if self._can_import(module_name):
|
||||
module = sys.modules[module_name]
|
||||
if hasattr(module, 'setup_app'):
|
||||
return module.setup_app(config)
|
||||
raise RuntimeError('No app.setup_app found in any of the configured app.modules')
|
||||
|
||||
def _create_temp_directory(self):
|
||||
temp_dir = mkdtemp()
|
||||
self.log('Created temporary directory %s' % temp_dir)
|
||||
py.test.temp_dir = temp_dir
|
||||
|
||||
def _delete_temp_directory(self):
|
||||
if py.test.temp_dir and os.path.exists(py.test.temp_dir):
|
||||
self.log('Removing temporary directory %s' % py.test.temp_dir)
|
||||
shutil.rmtree(py.test.temp_dir)
|
||||
|
||||
def sessionstart(self, session):
|
||||
self.log('Starting session')
|
||||
self._create_temp_directory()
|
||||
|
||||
def ensure_config_loaded(self):
|
||||
if not hasattr(py.test, 'wsgi_app') or py.test.wsgi_app is None:
|
||||
self._setup_app()
|
||||
|
||||
def configure_node(self, node):
|
||||
pass
|
||||
|
||||
def testnodedown(self, node, error):
|
||||
pass
|
||||
|
||||
def sessionfinish(self, session, exitstatus):
|
||||
self.log('Stopping session')
|
||||
self._delete_temp_directory()
|
||||
|
||||
@staticmethod
|
||||
def create_from_session(session):
|
||||
if session.config.option.dist != 'no':
|
||||
impl_cls = MasterPecanPluginImpl
|
||||
elif getattr(session.config, 'slaveinput', {}).get('slaveid'):
|
||||
impl_cls = SlavePecanPluginImpl
|
||||
else:
|
||||
impl_cls = PecanPluginImpl
|
||||
return impl_cls(session.config)
|
||||
|
||||
|
||||
class MasterPecanPluginImpl(PecanPluginImpl):
|
||||
"""
|
||||
Plugin implementation for distributed master.
|
||||
"""
|
||||
|
||||
def sessionstart(self, session):
|
||||
self.log('Starting master session')
|
||||
self._create_temp_directory()
|
||||
self._setup_app()
|
||||
|
||||
def configure_node(self, node):
|
||||
self.log('Configuring slave node %s' % node.gateway.id)
|
||||
node.slaveinput['pecan_master_host'] = socket.gethostname()
|
||||
node.slaveinput['pecan_temp_dir'] = py.test.temp_dir
|
||||
|
||||
def sessionfinish(self, session, exitstatus):
|
||||
self.log('Stopping master session')
|
||||
self._delete_temp_directory()
|
||||
|
||||
|
||||
class SlavePecanPluginImpl(PecanPluginImpl):
|
||||
"""
|
||||
Plugin implementation for distributed slaves.
|
||||
"""
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.config.slaveinput['slaveid']
|
||||
|
||||
def _is_collocated(self, session):
|
||||
return (socket.gethostname() == session.config.slaveinput['pecan_master_host'])
|
||||
|
||||
def _set_temp_directory(self, session):
|
||||
self.log('Setting temporary directory to %s' % session.config.slaveinput['pecan_temp_dir'])
|
||||
py.test.temp_dir = session.config.slaveinput['pecan_temp_dir']
|
||||
|
||||
def sessionstart(self, session):
|
||||
self.log('Starting slave session')
|
||||
if self._is_collocated(session):
|
||||
self._set_temp_directory(session)
|
||||
else:
|
||||
self._create_temp_directory()
|
||||
self._setup_app()
|
||||
|
||||
def sessionfinish(self, session, exitstatus):
|
||||
self.log('Stopping slave session')
|
||||
if not self._is_collocated(session):
|
||||
self._delete_temp_directory()
|
||||
@@ -39,7 +39,11 @@ def lookup_controller(obj, url_path):
|
||||
cross_boundary(prev_obj, obj)
|
||||
break
|
||||
except TypeError, te:
|
||||
print 'Got exception calling lookup(): %s (%s)' % (te, te.args)
|
||||
import warnings
|
||||
warnings.warn(
|
||||
'Got exception calling lookup(): %s (%s)' % (te, te.args),
|
||||
RuntimeWarning
|
||||
)
|
||||
else:
|
||||
raise exc.HTTPNotFound
|
||||
|
||||
|
||||
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))
|
||||
@@ -943,7 +943,7 @@ class TestLogging(TestCase):
|
||||
assert len(writes) == 1
|
||||
|
||||
|
||||
class TestEngines(object):
|
||||
class TestEngines(TestCase):
|
||||
|
||||
template_path = os.path.join(os.path.dirname(__file__), 'templates')
|
||||
|
||||
|
||||
@@ -4,14 +4,10 @@ from unittest import TestCase
|
||||
from pecan import configuration
|
||||
from pecan import conf as _runtime_conf
|
||||
|
||||
__here__ = os.path.dirname(__file__)
|
||||
|
||||
class TestConf(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
test_config_d = os.path.join(os.path.dirname(__file__), 'test_config')
|
||||
|
||||
if test_config_d not in sys.path:
|
||||
sys.path.append(test_config_d)
|
||||
|
||||
def test_update_config_fail_identifier(self):
|
||||
"""Fail when naming does not pass correctness"""
|
||||
bad_dict = {'bad name':'value'}
|
||||
@@ -21,7 +17,10 @@ class TestConf(TestCase):
|
||||
"""Update an empty configuration with the default values"""
|
||||
|
||||
conf = configuration.initconf()
|
||||
conf.update_with_module('config')
|
||||
conf.update(configuration.conf_from_file(os.path.join(
|
||||
__here__,
|
||||
'test_config/config.py'
|
||||
)))
|
||||
|
||||
self.assertTrue(conf.app.debug)
|
||||
self.assertEqual(conf.app.root, None)
|
||||
@@ -35,7 +34,10 @@ class TestConf(TestCase):
|
||||
"""Update an empty configuration with the default values"""
|
||||
|
||||
conf = configuration.initconf()
|
||||
conf.update_with_module('empty')
|
||||
conf.update(configuration.conf_from_file(os.path.join(
|
||||
__here__,
|
||||
'test_config/empty.py'
|
||||
)))
|
||||
|
||||
self.assertFalse(conf.app.debug)
|
||||
self.assertEqual(conf.app.root, None)
|
||||
@@ -48,7 +50,10 @@ class TestConf(TestCase):
|
||||
def test_update_force_dict(self):
|
||||
"""Update an empty configuration with the default values"""
|
||||
conf = configuration.initconf()
|
||||
conf.update_with_module('forcedict')
|
||||
conf.update(configuration.conf_from_file(os.path.join(
|
||||
__here__,
|
||||
'test_config/forcedict.py'
|
||||
)))
|
||||
|
||||
self.assertFalse(conf.app.debug)
|
||||
self.assertEqual(conf.app.root, None)
|
||||
@@ -70,12 +75,6 @@ class TestConf(TestCase):
|
||||
conf['attr'] = d
|
||||
self.assertTrue(conf.attr.attr)
|
||||
|
||||
def test_config_dirname(self):
|
||||
from pecan import default_config
|
||||
conf = configuration.initconf()
|
||||
conf['path'] = '%(confdir)s'
|
||||
self.assertEqual(conf.path, os.path.dirname(default_config.__file__))
|
||||
|
||||
def test_config_repr(self):
|
||||
conf = configuration.Config({'a':1})
|
||||
self.assertEqual(repr(conf),"Config({'a': 1})")
|
||||
@@ -92,16 +91,50 @@ class TestConf(TestCase):
|
||||
|
||||
def test_config_illegal_ids(self):
|
||||
conf = configuration.Config({})
|
||||
conf.update_with_module('bad.module_and_underscore')
|
||||
conf.update(configuration.conf_from_file(os.path.join(
|
||||
__here__,
|
||||
'test_config/bad/module_and_underscore.py'
|
||||
)))
|
||||
self.assertEqual([], list(conf))
|
||||
|
||||
def test_config_bad_module(self):
|
||||
def test_config_missing_file(self):
|
||||
path = ('doesnotexist.py',)
|
||||
conf = configuration.Config({})
|
||||
self.assertRaises(ImportError, conf.update_with_module, 'doesnotexist')
|
||||
self.assertRaises(ImportError, conf.update_with_module, 'bad.doesnotexists')
|
||||
self.assertRaises(ImportError, conf.update_with_module, 'bad.bad.doesnotexist')
|
||||
self.assertRaises(SyntaxError, conf.update_with_module, 'bad.syntaxerror')
|
||||
self.assertRaises(ImportError, conf.update_with_module, 'bad.importerror')
|
||||
self.assertRaises(IOError, configuration.conf_from_file, os.path.join(
|
||||
__here__,
|
||||
'test_config',
|
||||
*path
|
||||
))
|
||||
|
||||
def test_config_missing_file_on_path(self):
|
||||
path = ('bad', 'bad', 'doesnotexist.py',)
|
||||
conf = configuration.Config({})
|
||||
|
||||
self.assertRaises(IOError, configuration.conf_from_file, os.path.join(
|
||||
__here__,
|
||||
'test_config',
|
||||
*path
|
||||
))
|
||||
|
||||
def test_config_with_syntax_error(self):
|
||||
path = ('bad', 'syntaxerror.py')
|
||||
conf = configuration.Config({})
|
||||
|
||||
self.assertRaises(SyntaxError, configuration.conf_from_file, os.path.join(
|
||||
__here__,
|
||||
'test_config',
|
||||
*path
|
||||
))
|
||||
|
||||
def test_config_with_bad_import(self):
|
||||
path = ('bad', 'importerror.py')
|
||||
conf = configuration.Config({})
|
||||
|
||||
self.assertRaises(ImportError, configuration.conf_from_file, os.path.join(
|
||||
__here__,
|
||||
'test_config',
|
||||
*path
|
||||
))
|
||||
|
||||
def test_config_set_from_file(self):
|
||||
path = os.path.join(os.path.dirname(__file__), 'test_config', 'empty.py')
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
from pecan.deploy import deploy
|
||||
from unittest import TestCase
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
class TestDeploy(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
test_config_d = os.path.join(os.path.dirname(__file__), 'test_config', 'sample_apps')
|
||||
|
||||
if test_config_d not in sys.path:
|
||||
sys.path.append(test_config_d)
|
||||
|
||||
def test_module_lookup(self):
|
||||
"""
|
||||
1. A config file has:
|
||||
app { 'modules': ['valid_module'] }
|
||||
2. The module, `valid_module` has an app.py that defines a `def setup.py`
|
||||
"""
|
||||
test_config_file = os.path.join(os.path.dirname(__file__), 'test_config', 'sample_apps', 'sample_app_config.py')
|
||||
assert deploy(test_config_file) == 'DEPLOYED!'
|
||||
|
||||
def test_module_lookup_find_best_match(self):
|
||||
"""
|
||||
1. A config file has:
|
||||
app { 'modules': ['invalid_module', 'valid_module'] }
|
||||
2. The module, `valid_module` has an app.py that defines a `def setup_app`
|
||||
"""
|
||||
test_config_file = os.path.join(os.path.dirname(__file__), 'test_config', 'sample_apps', 'sample_app_config.py')
|
||||
assert deploy(test_config_file) == 'DEPLOYED!'
|
||||
|
||||
def test_missing_app_file_lookup(self):
|
||||
"""
|
||||
1. A config file has:
|
||||
app { 'modules': ['valid_module'] }
|
||||
2. The module has no `app.py` file.
|
||||
"""
|
||||
test_config_file = os.path.join(os.path.dirname(__file__), 'test_config', 'sample_apps', 'sample_app_config_missing.py')
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
deploy,
|
||||
test_config_file
|
||||
)
|
||||
|
||||
def test_missing_setup_app(self):
|
||||
"""
|
||||
1. A config file has:
|
||||
app { 'modules': ['valid_module'] }
|
||||
2. The module, `valid_module` has an `app.py` that contains no `def setup_app`
|
||||
"""
|
||||
test_config_file = os.path.join(os.path.dirname(__file__), 'test_config', 'sample_apps', 'sample_app_config_missing_app.py')
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
deploy,
|
||||
test_config_file
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
from pecan import Pecan, expose, request, response, redirect
|
||||
from unittest import TestCase
|
||||
from webtest import TestApp
|
||||
try:
|
||||
from simplejson import dumps
|
||||
@@ -6,7 +7,7 @@ except:
|
||||
from json import dumps
|
||||
|
||||
|
||||
class TestGeneric(object):
|
||||
class TestGeneric(TestCase):
|
||||
|
||||
def test_simple_generic(self):
|
||||
class RootController(object):
|
||||
|
||||
@@ -5,11 +5,12 @@ from pecan.hooks import PecanHook, TransactionHook, HookController, Requ
|
||||
from pecan.configuration import Config
|
||||
from pecan.decorators import transactional, after_commit, after_rollback
|
||||
from copy import copy
|
||||
from unittest import TestCase
|
||||
from formencode import Schema, validators
|
||||
from webtest import TestApp
|
||||
|
||||
|
||||
class TestHooks(object):
|
||||
class TestHooks(TestCase):
|
||||
|
||||
def test_basic_single_hook(self):
|
||||
run_hook = []
|
||||
@@ -446,7 +447,7 @@ class TestHooks(object):
|
||||
assert run_hook[5] == 'inside'
|
||||
assert run_hook[6] == 'after'
|
||||
|
||||
class TestTransactionHook(object):
|
||||
class TestTransactionHook(TestCase):
|
||||
def test_transaction_hook(self):
|
||||
run_hook = []
|
||||
|
||||
@@ -1109,7 +1110,7 @@ class TestTransactionHook(object):
|
||||
assert run_hook[3] == 'clear'
|
||||
|
||||
|
||||
class TestRequestViewerHook(object):
|
||||
class TestRequestViewerHook(TestCase):
|
||||
|
||||
def test_hook_from_config(self):
|
||||
from pecan.configuration import _runtime_conf as conf
|
||||
|
||||
@@ -48,7 +48,7 @@ def test_simple_rule():
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
class TestJsonify(object):
|
||||
class TestJsonify(TestCase):
|
||||
|
||||
def test_simple_jsonify(self):
|
||||
Person = make_person()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from pecan import abort, expose, make_app, request, response
|
||||
from pecan.rest import RestController
|
||||
from unittest import TestCase
|
||||
from webtest import TestApp
|
||||
try:
|
||||
from simplejson import dumps, loads
|
||||
@@ -9,7 +10,7 @@ except:
|
||||
import formencode
|
||||
|
||||
|
||||
class TestRestController(object):
|
||||
class TestRestController(TestCase):
|
||||
|
||||
def test_basic_rest(self):
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ try:
|
||||
except:
|
||||
from sets import Set as set
|
||||
|
||||
class TestSecure(object):
|
||||
class TestSecure(TestCase):
|
||||
def test_simple_secure(self):
|
||||
authorized = False
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import os
|
||||
from pecan import expose, make_app
|
||||
from unittest import TestCase
|
||||
from webtest import TestApp
|
||||
|
||||
class TestStatic(object):
|
||||
class TestStatic(TestCase):
|
||||
|
||||
def test_simple_static(self):
|
||||
class RootController(object):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from formencode import ForEach, Schema, validators
|
||||
from webtest import TestApp
|
||||
from unittest import TestCase
|
||||
|
||||
import os.path
|
||||
|
||||
@@ -12,7 +13,7 @@ except ImportError:
|
||||
from json import dumps
|
||||
|
||||
|
||||
class TestValidation(object):
|
||||
class TestValidation(TestCase):
|
||||
|
||||
template_path = os.path.join(os.path.dirname(__file__), 'templates')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user