1. Ian Bicking
  2. PasteDeploy

Commits

Jason Stitt  committed 643ebda

Added a new loader using the call: protocol that uses an object path and not an egg

  • Participants
  • Parent commits 6c1607a
  • Branches default

Comments (0)

Files changed (3)

File paste/deploy/loadwsgi.py

View file
 
 _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
 ############################################################
             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,
                 % (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,

File tests/sample_configs/test_func.ini

View file
+[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

File tests/test_func_loader.py

View file
+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