diff options
| -rw-r--r-- | paste/default_config.conf | 8 | ||||
| -rw-r--r-- | paste/errormiddleware.py (renamed from paste/error_middleware.py) | 0 | ||||
| -rw-r--r-- | paste/makeapp.py | 37 | ||||
| -rw-r--r-- | paste/pyconfig.py | 187 | ||||
| -rwxr-xr-x | paste/server.py | 48 | ||||
| -rw-r--r-- | paste/tests/fixture.py | 72 | ||||
| -rw-r--r-- | paste/tests/test_error_middleware.py | 2 | ||||
| -rw-r--r-- | paste/webkit/conf_setup.py | 24 |
8 files changed, 176 insertions, 202 deletions
diff --git a/paste/default_config.conf b/paste/default_config.conf index bf9ad00..d92dcff 100644 --- a/paste/default_config.conf +++ b/paste/default_config.conf @@ -3,3 +3,11 @@ index_names = ['index', 'Index', 'main', 'Main'] sys_path = [] framework = 'default' +# The first middleware in this list is wrapped most closely around +# the application: +middleware = [] +port = 8080 +host = 'localhost' +verbose = False +quiet = False +reload = False diff --git a/paste/error_middleware.py b/paste/errormiddleware.py index d5c2b02..d5c2b02 100644 --- a/paste/error_middleware.py +++ b/paste/errormiddleware.py diff --git a/paste/makeapp.py b/paste/makeapp.py new file mode 100644 index 0000000..34d1e1c --- /dev/null +++ b/paste/makeapp.py @@ -0,0 +1,37 @@ +""" +Helper functions for framework build_application functions. +""" + +from paste.util import import_string +from paste import lint +from paste import errormiddleware +from paste import configmiddleware + +def apply_conf_middleware(app, conf, first_middleware=()): + """ + Applies any middleware that the configuration specifies, + returning the wrapped configuration. + + If first_middleware is given, this middleware is applied most + closely to the application (before configuration middleware). + """ + all_middleware = list(first_middleware) + all_middleware.extend(conf.get('middleware', [])) + for middleware in all_middleware: + # @@: Should this use plugins too? + if isinstance(middleware, (str, unicode)): + middleware = import_string.eval_import(middleware) + app = middleware(app) + if conf.get('lint', False): + app = lint.middleware(app) + return app + +def apply_default_middleware(app, conf): + """ + Applies middleware that is generally always used. + """ + app = errormiddleware.ErrorMiddleware(app) + if conf.get('lint', False): + app = lint.middleware(app) + app = configmiddleware.config_middleware(app, conf) + return app diff --git a/paste/pyconfig.py b/paste/pyconfig.py index 2f408f9..d798f6e 100644 --- a/paste/pyconfig.py +++ b/paste/pyconfig.py @@ -139,88 +139,23 @@ class Config(UserDict.DictMixin): self.namespaces.insert(default, d) else: self.namespaces.insert(0, d) - - def load_commandline(self, items, bool_options, aliases={}, default=False): - """ - Loads options from the command line. bool_options take no arguments, - everything else is supposed to take arguments. aliases is a mapping - of arguments to other arguments. All -'s are turned to _, like - --config-file=... becomes config_file. Any extra arguments are - returned as a list. - """ - options = {} - args = [] - while items: - if items[0] == '--': - args.extend(items[1:]) - break - elif items[0].startswith('--'): - name = items[0][2:] - value = None - if '=' in name: - name, value = name.split('=', 1) - name = aliases.get(name, name) - if (name in bool_options - or name.replace('-', '_') in bool_options): - if value is not None: - raise BadCommandLine( - "%s does not take any arguments" - % items[0]) - options[name] = True - items.pop(0) - continue - if value is None: - if len(items) <= 1: - raise BadCommandLine( - "%s takes an argument, but no argument given" - % items[0]) - value = items[1] - items.pop(0) - items.pop(0) - value = self.convert_commandline(value) - options[name] = value - elif items[0].startswith('-'): - orig = items[0] - name = items[0][1:] - items.pop(0) - if '=' in name: - raise BadCommandLine( - "Single-character options may not have arguments (%r)" - % orig) - for i in range(len(name)): - op_name = aliases.get(name[i], name[i]) - if op_name in bool_options: - options[op_name] = True - else: - if i != len(name)-1: - raise BadCommandLine( - "-%s takes an argument, it cannot be followed " - "by other options (in %s)" - % (name[i], orig)) - if not items: - raise BadCommandLine( - "-%s takes an argument, but no argument given" - % name[i]) - value = self.convert_commandline(items[0]) - items.pop(0) - options[op_name] = value - break - else: - args.append(items[0]) - items.pop(0) - for key in options.keys(): - options[key.replace('-', '_')] = options[key] - self.load_dict(options, default) + + def load_commandline(self, *args, **kw): + options, args = parse_commandline(*args, **kw) + self.load_dict(options) return args - def convert_commandline(self, value): - try: - return int(value) - except ValueError: - pass - return value + def update_sys_path(self): + update_sys_path(self.get('sys_path'), self.get('verbose')) + +def setup_config(filename, add_config=None, conf=None): + """ + Load the configuration with all default configs also applied, + and, apply sys_path. -def setup_config(filename, add_config=None): + If add_config is given, this configuration (a dictionary or + filename) is loaded before the filename is loaded. + """ conf = Config(with_default=True) if add_config: if isinstance(add_config, (str, unicode)): @@ -235,6 +170,8 @@ def setup_config(filename, add_config=None): return conf def update_sys_path(paths, verbose): + if paths is None: + return if isinstance(paths, (str, unicode)): paths = [paths] for path in paths: @@ -243,7 +180,97 @@ def update_sys_path(paths, verbose): if verbose: print 'Adding %s to path' % path sys.path.insert(0, path) - + +def parse_commandline(items, bool_options, aliases={}, default=False): + """ + Parses options from the command line. bool_options take no + arguments, everything else is supposed to take arguments. aliases + is a mapping of arguments to other arguments. All -'s are turned + to _, like --config-file=... becomes config_file. Any extra + arguments are returned as a list. + """ + options = {} + args = [] + while items: + if items[0] == '--': + args.extend(items[1:]) + break + elif items[0].startswith('--'): + name = items[0][2:] + value = None + if '=' in name: + name, value = name.split('=', 1) + name = aliases.get(name, name) + if (name in bool_options + or name.replace('-', '_') in bool_options): + if value is not None: + raise BadCommandLine( + "%s does not take any arguments" + % items[0]) + # For things like -vv (extra verbose) + if options.get(name): + options[name] += 1 + else: + options[name] = True + items.pop(0) + continue + if value is None: + if len(items) <= 1: + raise BadCommandLine( + "%s takes an argument, but no argument given" + % items[0]) + value = items[1] + items.pop(0) + items.pop(0) + value = convert_commandline(value) + options[name] = value + elif items[0].startswith('-'): + orig = items[0] + name = items[0][1:] + items.pop(0) + if '=' in name: + raise BadCommandLine( + "Single-character options may not have arguments (%r)" + % orig) + for i in range(len(name)): + op_name = aliases.get(name[i], name[i]) + if op_name in bool_options: + options[op_name] = True + else: + if i != len(name)-1: + raise BadCommandLine( + "-%s takes an argument, it cannot be followed " + "by other options (in %s)" + % (name[i], orig)) + if not items: + raise BadCommandLine( + "-%s takes an argument, but no argument given" + % name[i]) + value = convert_commandline(items[0]) + items.pop(0) + options[op_name] = value + break + else: + args.append(items[0]) + items.pop(0) + for key in options.keys(): + options[key.replace('-', '_')] = options[key] + return options, args + +def convert_commandline(value): + """ + Converts command-line strings to Python objects; just converting + integer strings to integers now. + """ + # @@: In most cases we should anticipate string options and parse + # them appropriately, instead of this conversion which cannot be + # context-sensitive + try: + return int(value) + except ValueError: + pass + return value + class DispatchingConfig(object): """ diff --git a/paste/server.py b/paste/server.py index 4b6c49c..a910cdd 100755 --- a/paste/server.py +++ b/paste/server.py @@ -29,10 +29,6 @@ OPTIONS import sys import os -from paste import reloader -from paste import wsgilib -from paste import CONFIG -from paste.util import plugin # This way you can run this out of a checkout, and we'll fix up # the path... @@ -53,18 +49,11 @@ if os.path.dirname(here) != paste_path: 'Warning: server.py is running out of %s, but paste is loaded ' 'out of %s\n' % (here, paste_path)) -from paste.pyconfig import Config -from paste.configmiddleware import config_middleware -from paste.webkit import wsgiwebkit -from paste.util import thirdparty - -default_ops = { - 'port': 8080, - 'host': 'localhost', - 'verbose': False, - 'quiet': False, - 'reload': False, - } +from paste import reloader +from paste import wsgilib +from paste import CONFIG +from paste.util import plugin +from paste import pyconfig reloader_environ_key = 'WSGI_RELOADER_SHOULD_RUN' @@ -72,10 +61,8 @@ default_config_fn = os.path.join(os.path.dirname(__file__), 'default_config.conf') def load_commandline(args, allow_reload=True): - conf = Config() - # We use conf.verbose early, so we set it now: - conf.load_dict(default_ops, default=True) - args = conf.load_commandline( + conf = pyconfig.Config(with_default=True) + conf.load_commandline( args, bool_options=['help', 'verbose', 'reload', 'debug', 'quiet', 'no_verbose'], aliases={'h': 'help', 'v': 'verbose', 'f': 'config_file', @@ -85,14 +72,10 @@ def load_commandline(args, allow_reload=True): return None, 0 if conf.get('no_verbose'): conf['verbose'] = False - load_conf(conf, default_config_fn, True) - reloader.watch_file(default_config_fn) if not conf.get('no_server_conf') and os.path.exists('server.conf'): load_conf(conf, 'server.conf', True) - reloader.watch_file('server.conf') if conf.get('config_file'): load_conf(conf, conf['config_file'], True) - reloader.watch_file(conf['config_file']) if conf['quiet']: conf['verbose'] = False server = conf.get('server') @@ -111,8 +94,7 @@ def load_commandline(args, allow_reload=True): return restart_with_reloader(conf) except KeyboardInterrupt: return None, 0 - if conf.get('sys_path'): - update_sys_path(conf['sys_path'], conf['verbose']) + conf.update_sys_path() app = make_app(conf) return conf, app @@ -154,16 +136,6 @@ def load_conf(conf, filename, default=False): if conf['verbose']: print 'Loading configuration from %s' % filename conf.load(filename, default=default) - -def update_sys_path(paths, verbose): - if isinstance(paths, (str, unicode)): - paths = [paths] - for path in paths: - path = os.path.abspath(path) - if path not in sys.path: - if verbose: - print 'Adding %s to path' % path - sys.path.insert(0, path) def help(): program = sys.argv[0] @@ -177,10 +149,6 @@ def make_app(conf): framework_name, '_framework') app = framework.build_application(conf) - if conf.get('lint'): - import lint - app = lint.middleware(app) - app = config_middleware(app, conf) return app def restart_with_reloader(conf): diff --git a/paste/tests/fixture.py b/paste/tests/fixture.py index a312a52..a6245e2 100644 --- a/paste/tests/fixture.py +++ b/paste/tests/fixture.py @@ -50,68 +50,6 @@ class DummyMethod(object): def __call__(self, *args, **kw): return self.return_value - -# These have to be rewritten, since py.test has changed; -# but we're not using them now anyway. - -# class ParamCollector(PyCollector): - -# def collect_function(self, extpy): -# if not extpy.check(func=1, basestarts='test_'): -# return -# func = extpy.resolve() -# if hasattr(func, 'params'): -# params = func.params -# for i, param in enumerate(params): -# item = self.Item(extpy, *param) -# item.name = item.name + '.%i' % i -# yield item -# else: -# yield self.Item(extpy) - -# class DoctestCollector(PyCollector): - -# def __init__(self, extpy_or_module): -# if isinstance(extpy_or_module, types.ModuleType): -# self.module = extpy_or_module -# self.extpy = None -# else: -# self.extpy = extpy_or_module -# self.module = self.extpy.getpymodule() - -# def __call__(self, extpy): -# # we throw it away, because this has been set up to explicitly -# # check another module; maybe this isn't clean -# if self.extpy is None: -# self.extpy = extpy -# return self - -# def __iter__(self): -# finder = doctest.DocTestFinder() -# tests = finder.find(self.module) -# for t in tests: -# yield DoctestItem(self.extpy, t) - -# class DoctestItem(DoctestCollector.Item): - -# def __init__(self, extpy, doctestitem, *args): -# self.extpy = extpy -# self.doctestitem = doctestitem -# self.name = extpy.basename -# self.args = args - -# def execute(self, driver): -# runner = doctest.DocTestRunner() -# driver.setup_path(self.extpy) -# target, teardown = driver.setup_method(self.extpy) -# try: -# (failed, tried), run_output = capture_stdout(runner.run, self.doctestitem) -# if failed: -# raise self.Failed(msg=run_output, tbindex=-2) - -# finally: -# if teardown: -# teardown(target) def capture_stdout(func, *args, **kw): newstdout = StringIO() @@ -154,7 +92,6 @@ def sorted(l): l.sort() return l - def fake_request(application, path_info='', use_lint=True, **environ): """ Runs the application in a fake environment, returning a response object @@ -332,6 +269,9 @@ class AppError(Exception): class TestApp(object): + # for py.test + disabled = True + def __init__(self, app, config={}, namespace=None): self.app = app self.config = config @@ -486,6 +426,9 @@ class TestApp(object): class TestResponse(object): + # for py.test + disabled = True + def __init__(self, test_app, status, headers, body, errors, total_time): self.test_app = test_app @@ -600,6 +543,9 @@ class TestResponse(object): class TestRequest(object): + # for py.test + disabled = True + def __init__(self, url, environ): self.url = url self.environ = environ diff --git a/paste/tests/test_error_middleware.py b/paste/tests/test_error_middleware.py index f7731ae..603e724 100644 --- a/paste/tests/test_error_middleware.py +++ b/paste/tests/test_error_middleware.py @@ -1,5 +1,5 @@ from fixture import * -from paste.error_middleware import ErrorMiddleware +from paste.errormiddleware import ErrorMiddleware from paste import lint def do_request(app, expect_status=500): diff --git a/paste/webkit/conf_setup.py b/paste/webkit/conf_setup.py index 1599997..656bea6 100644 --- a/paste/webkit/conf_setup.py +++ b/paste/webkit/conf_setup.py @@ -1,11 +1,10 @@ import sys import os +from paste import makeapp from paste import urlparser from paste import session from paste import recursive from paste import httpexceptions -from paste import lint -from paste import error_middleware def build_application(conf): if not 'publish_dir' in conf: @@ -13,25 +12,14 @@ def build_application(conf): sys.exit(2) directory = conf['publish_dir'] install_fake_webware = conf.get('install_fake_webware', True) - use_lint = conf.get('lint', False) if install_fake_webware: _install_fake_webware() app = urlparser.URLParser(directory, os.path.basename(directory)) - if use_lint: - app = lint.middleware(app) - app = httpexceptions.middleware(app) - if use_lint: - app = lint.middleware(app) - print session - app = session.SessionMiddleware(app) - if use_lint: - app = lint.middleware(app) - app = recursive.RecursiveMiddleware(app) - if use_lint: - app = lint.middleware(app) - app = error_middleware.ErrorMiddleware(app) - # I'll skip the use of lint on recursive, because it doesn't modify - # its output much at all + app = makeapp.apply_conf_middleware( + app, conf, + [httpexceptions.middleware, session.SessionMiddleware, + recursive.RecursiveMiddleware]) + app = makeapp.apply_default_middleware(app, conf) return app def install_fake_webware(): |
