diff options
-rw-r--r-- | paste/deploy/loadwsgi.py | 54 | ||||
-rw-r--r-- | tests/sample_configs/test_func.ini | 13 | ||||
-rw-r--r-- | tests/test_func_loader.py | 32 |
3 files changed, 99 insertions, 0 deletions
diff --git a/paste/deploy/loadwsgi.py b/paste/deploy/loadwsgi.py index bae77ae..6b373d0 100644 --- a/paste/deploy/loadwsgi.py +++ b/paste/deploy/loadwsgi.py @@ -278,6 +278,14 @@ def _loadegg(object_type, uri, spec, name, relative_to, _loaders['egg'] = _loadegg +def _loadfunc(object_type, uri, spec, name, relative_to, + global_conf): + + loader = FuncLoader(spec) + return loader.get_context(object_type, name, global_conf) + +_loaders['call'] = _loadfunc + ############################################################ ## Loaders ############################################################ @@ -428,6 +436,20 @@ class ConfigLoader(_Loader): context.global_conf['__file__'] = global_conf['__file__'] # @@: Should loader be overwritten? context.loader = self + + if context.protocol is None: + # Determine protocol from section type + section_protocol = section.split(':', 1)[0] + if section_protocol in ('application','app'): + context.protocol = 'paste.app_factory' + elif section_protocol in ('composit','composite'): + context.protocol = 'paste.composit_factory' + else: + # This will work with 'server' and 'filter', otherwise it + # could fail but there is an error message already for + # bad protocols + context.protocol = 'paste.%s_factory' % context_protocol + return context def _context_from_explicit(self, object_type, local_conf, global_conf, @@ -596,6 +618,38 @@ class EggLoader(_Loader): % (name, self.spec, ', '.join(_flatten(protocol_options)))) return possible[0] + +class FuncLoader(_Loader): + """ Loader that supports specifying functions inside modules, without + using eggs at all. Configuration should be in the format: + use = call:my.module.path:function_name + + Dot notation is supported in both the module and function name, e.g.: + use = call:my.module.path:object.method + """ + def __init__(self, spec): + self.spec = spec + try: + self.module_path, self.func_name = self.spec.split(':') + except ValueError: + raise LookupError("Configuration not in format module:function") + self.module_name = self.module_path.split('.', 1)[-1] + + def get_context(self, object_type, name=None, global_conf=None): + module = __import__(self.module_path, {}, {}, [self.module_name], 0) + obj = module + for part in self.func_name.split('.'): + obj = getattr(obj, part) + return LoaderContext( + obj, + object_type, + None, # determine protocol from section type + global_conf or {}, + {}, + self, + ) + + class LoaderContext(object): def __init__(self, obj, object_type, protocol, diff --git a/tests/sample_configs/test_func.ini b/tests/sample_configs/test_func.ini new file mode 100644 index 0000000..a0d28c4 --- /dev/null +++ b/tests/sample_configs/test_func.ini @@ -0,0 +1,13 @@ +[application:main] +use = call:fakeapp.apps:make_basic_app + +[application:other] +use = call:fakeapp.apps:make_basic_app2 + +[composit:remote_addr] +use = call:fakeapp.apps:make_remote_addr +app.1 = main +addr.1 = 127.0.0.1 + +app.2 = other +addr.2 = 0.0.0.0
\ No newline at end of file diff --git a/tests/test_func_loader.py b/tests/test_func_loader.py new file mode 100644 index 0000000..a04632d --- /dev/null +++ b/tests/test_func_loader.py @@ -0,0 +1,32 @@ +from paste.deploy import loadapp, loadfilter, appconfig +from fixture import * +import fakeapp.apps + +here = os.path.abspath(os.path.dirname(__file__)) + +def test_main(): + app = loadapp('config:sample_configs/test_func.ini', + relative_to=here) + assert app is fakeapp.apps.basic_app + app = loadapp('config:sample_configs/test_func.ini#main', + relative_to=here) + assert app is fakeapp.apps.basic_app + app = loadapp('config:sample_configs/test_func.ini', + relative_to=here, name='main') + assert app is fakeapp.apps.basic_app + app = loadapp('config:sample_configs/test_func.ini#ignored', + relative_to=here, name='main') + assert app is fakeapp.apps.basic_app + +def test_other(): + app = loadapp('config:sample_configs/test_func.ini#other', + relative_to=here) + assert app is fakeapp.apps.basic_app2 + + +def test_composit(): + app = loadapp('config:sample_configs/test_func.ini#remote_addr', + relative_to=here) + assert isinstance(app, fakeapp.apps.RemoteAddrDispatch) + assert app.map['127.0.0.1'] is fakeapp.apps.basic_app + assert app.map['0.0.0.0'] is fakeapp.apps.basic_app2 |