From 1eb861e0f046397715a92ed7ad7b85a2baa22b29 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 2 Jul 2009 07:15:44 +0000 Subject: - Allow a Paste config file (``configure_zcml``) value or an environment variable (``BFG_CONFIGURE_ZCML``) to name a ZCML file that will be used to bootstrap the application. Previously, the integrator could not influence which ZCML file was used to do the boostrapping (only the original application developer could do so). --- CHANGES.txt | 12 +++ repoze/bfg/router.py | 29 ++++-- repoze/bfg/settings.py | 3 + repoze/bfg/tests/fixtureapp/another.zcml | 2 + repoze/bfg/tests/fixtureapp/configure.zcml | 5 + repoze/bfg/tests/fixtureapp/models.py | 3 + repoze/bfg/tests/test_router.py | 147 ++++++++++++++++++----------- repoze/bfg/tests/test_settings.py | 11 +++ 8 files changed, 149 insertions(+), 63 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d87c2749e..d601f3199 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,15 @@ +Next release +============ + +Features +-------- + +- Allow a Paste config file (``configure_zcml``) value or an + environment variable (``BFG_CONFIGURE_ZCML``) to name a ZCML file + that will be used to bootstrap the application. Previously, the + integrator could not influence which ZCML file was used to do the + boostrapping (only the original application developer). + 1.0a9 (2009-07-01) ================== diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index 4eb0fed81..3b9b12cb7 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -210,8 +210,9 @@ def default_notfound_view(context, request): def make_app(root_factory, package=None, filename='configure.zcml', authentication_policy=None, authorization_policy=None, - options=None, registry=None, debug_logger=None): - # registry and debug_logger *only* for unittests + options=None, registry=None, debug_logger=None, + manager=manager): + # registry, debug_logger and manager *only* for unittests """ Return a Router object, representing a fully configured ``repoze.bfg`` WSGI application. @@ -223,13 +224,18 @@ def make_app(root_factory, package=None, filename='configure.zcml', used. ``package`` is a Python module representing the application's - package. It is optional, defaulting to ``None``. If ``package`` - is ``None``, the ``filename`` passed must be an absolute pathname - to a ZCML file that represents the application's configuration. + package. It is optional, defaulting to ``None``. ``package`` may + be ``None``. If ``package`` is ``None``, either the ``filename`` + passed or the value in the ``options`` dictionary named + ``configure_zcml`` must be an absolute pathname to a ZCML file + that represents the application's configuration. ``filename`` is the filesystem path to a ZCML file (optionally relative to the package path) that should be parsed to create the - application registry. It defaults to ``configure.zcml``. + application registry. It defaults to ``configure.zcml``. Note + that if any value for ``configure_zcml`` is passed within the + ``options`` dictionary, the value passed as ``filename`` will be + ignored, replaced with the ``configure_zcml`` value. ``authentication_policy`` should be an object that implements the ``repoze.bfg.interfaces.IAuthenticationPolicy`` interface (e.g. @@ -265,19 +271,24 @@ def make_app(root_factory, package=None, filename='configure.zcml', if options is None: options = {} + if not 'configure_zcml' in options: + options['configure_zcml'] = filename + + settings = Settings(get_options(options)) + filename = settings['configure_zcml'] + if registry is None: regname = filename if package: regname = package.__name__ registry = Registry(regname) + registry.registerUtility(settings, ISettings) + if debug_logger is None: debug_logger = make_stream_logger('repoze.bfg.debug', sys.stderr) registry.registerUtility(debug_logger, ILogger, 'repoze.bfg.debug') - settings = Settings(get_options(options)) - registry.registerUtility(settings, ISettings) - if root_factory is None: root_factory = DefaultRootFactory diff --git a/repoze/bfg/settings.py b/repoze/bfg/settings.py index 08607f756..57295fcdc 100644 --- a/repoze/bfg/settings.py +++ b/repoze/bfg/settings.py @@ -55,11 +55,14 @@ def get_options(kw, environ=os.environ): config_reload_resources = kw.get('reload_resources', '') effective_reload_resources = asbool(eget('BFG_RELOAD_RESOURCES', config_reload_resources)) + configure_zcml = kw.get('configure_zcml', '') + effective_configure_zcml = eget('BFG_CONFIGURE_ZCML', configure_zcml) update = { 'debug_authorization': effective_debug_all or effective_debug_auth, 'debug_notfound': effective_debug_all or effective_debug_notfound, 'reload_templates': effective_reload_all or effective_reload_templates, 'reload_resources':effective_reload_all or effective_reload_resources, + 'configure_zcml':effective_configure_zcml, } kw.update(update) diff --git a/repoze/bfg/tests/fixtureapp/another.zcml b/repoze/bfg/tests/fixtureapp/another.zcml index c01245656..0ed8cff1b 100644 --- a/repoze/bfg/tests/fixtureapp/another.zcml +++ b/repoze/bfg/tests/fixtureapp/another.zcml @@ -1,5 +1,7 @@ + + + + diff --git a/repoze/bfg/tests/fixtureapp/models.py b/repoze/bfg/tests/fixtureapp/models.py index a57b06308..d80d14bb3 100644 --- a/repoze/bfg/tests/fixtureapp/models.py +++ b/repoze/bfg/tests/fixtureapp/models.py @@ -3,3 +3,6 @@ from zope.interface import Interface class IFixture(Interface): pass +def fixture(): + """ """ + diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index b0f75d899..cd88f8971 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -97,7 +97,7 @@ class RouterTests(unittest.TestCase): return L def _registerRootFactory(self, val): - rootfactory = make_rootfactory(val) + rootfactory = DummyRootFactory(val) from repoze.bfg.interfaces import IRootFactory self.registry.registerUtility(rootfactory, IRootFactory) return rootfactory @@ -221,7 +221,7 @@ class RouterTests(unittest.TestCase): context = DummyContext() self._registerTraverserFactory(context) environ = self._makeEnviron() - view = make_view('abc') + view = DummyView('abc') self._registerView(view, '', None, None) router = self._makeOne() start_response = DummyStartResponse() @@ -251,7 +251,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) self._registerAuthenticationPolicy() response = DummyResponse() - view = make_view(response) + view = DummyView(response) from repoze.bfg.security import ACLDenied denied = ACLDenied('ace', 'acl', 'permission', ['principals'], context) environ = self._makeEnviron() @@ -269,7 +269,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', None, None) rootfactory = self._registerRootFactory(context) @@ -289,7 +289,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, _deprecation_warning='abc') response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', None, None) router = self._makeOne() @@ -308,7 +308,7 @@ class RouterTests(unittest.TestCase): rootfactory = self._registerRootFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, 'foo', None, None) router = self._makeOne() @@ -334,7 +334,7 @@ class RouterTests(unittest.TestCase): rootfactory = self._registerRootFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) router = self._makeOne() @@ -360,7 +360,7 @@ class RouterTests(unittest.TestCase): directlyProvides(context, INotContext) self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) router = self._makeOne() @@ -379,7 +379,7 @@ class RouterTests(unittest.TestCase): directlyProvides(context, IContext) self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) router = self._makeOne() @@ -398,7 +398,7 @@ class RouterTests(unittest.TestCase): directlyProvides(context, IContext) self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) router = self._makeOne() @@ -421,7 +421,7 @@ class RouterTests(unittest.TestCase): directlyProvides(context, IContext) self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) router = self._makeOne() @@ -444,7 +444,7 @@ class RouterTests(unittest.TestCase): directlyProvides(context, IContext) self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) router = self._makeOne() @@ -465,7 +465,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) self._registerAuthenticationPolicy() response = DummyResponse() - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) checker = self._registerViewPermission('', True) @@ -486,7 +486,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) self._registerAuthenticationPolicy() response = DummyResponse() - view = make_view(response) + view = DummyView(response) from repoze.bfg.security import ACLDenied denied = ACLDenied('ace', 'acl', 'permission', ['principals'], context) environ = self._makeEnviron() @@ -511,7 +511,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) self._registerAuthenticationPolicy() response = DummyResponse() - view = make_view(response) + view = DummyView(response) from repoze.bfg.security import ACLDenied denied = ACLDenied('ace', 'acl', 'permission', ['principals'], context) environ = self._makeEnviron() @@ -537,7 +537,7 @@ class RouterTests(unittest.TestCase): self._registerAuthenticationPolicy() self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() - view = make_view(response) + view = DummyView(response) from repoze.bfg.security import ACLDenied environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) @@ -571,7 +571,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', None, None) from repoze.bfg.interfaces import INewRequest @@ -591,7 +591,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron() self._registerView(view, '', None, None) router = self._makeOne() @@ -610,7 +610,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron(REQUEST_METHOD='POST') self._registerView(view, '', None, None) router = self._makeOne() @@ -631,7 +631,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron(REQUEST_METHOD='PUT') self._registerView(view, '', None, None) router = self._makeOne() @@ -650,7 +650,7 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) response = DummyResponse() response.app_iter = ['Hello world'] - view = make_view(response) + view = DummyView(response) environ = self._makeEnviron(REQUEST_METHOD='UNKNOWN') self._registerView(view, '', None, None) router = self._makeOne() @@ -663,27 +663,49 @@ class RouterTests(unittest.TestCase): class MakeAppTests(unittest.TestCase): def setUp(self): cleanUp() - import repoze.bfg.router - self.old_tl_manager = repoze.bfg.router.manager - self.regmgr = DummyRegistryManager() - repoze.bfg.router.manager = self.regmgr def tearDown(self): cleanUp() - import repoze.bfg.router - repoze.bfg.router.threadlocal_manager = self.old_tl_manager def _callFUT(self, *arg, **kw): from repoze.bfg.router import make_app return make_app(*arg, **kw) - def test_fixtureapp(self): + def test_fixtureapp_default_filename_withpackage(self): + manager = DummyRegistryManager() from repoze.bfg.tests import fixtureapp - rootpolicy = make_rootfactory(None) - app = self._callFUT(rootpolicy, fixtureapp) + rootpolicy = DummyRootFactory(None) + app = self._callFUT(rootpolicy, fixtureapp, manager=manager) self.assertEqual(app.registry.__name__, 'repoze.bfg.tests.fixtureapp') + from repoze.bfg.tests.fixtureapp.models import IFixture + self.failUnless(app.registry.queryUtility(IFixture)) # only in c.zcml + def test_fixtureapp_explicit_filename(self): + manager = DummyRegistryManager() + from repoze.bfg.tests import fixtureapp + rootpolicy = DummyRootFactory(None) + app = self._callFUT(rootpolicy, fixtureapp, filename='another.zcml', + manager=manager) + self.assertEqual(app.registry.__name__, 'repoze.bfg.tests.fixtureapp') + from repoze.bfg.tests.fixtureapp.models import IFixture + self.failIf(app.registry.queryUtility(IFixture)) # only in c.zcml + + def test_fixtureapp_explicit_filename_in_options(self): + import os + manager = DummyRegistryManager() + rootpolicy = DummyRootFactory(None) + from repoze.bfg.tests import fixtureapp + zcmlfile = os.path.join(os.path.dirname(fixtureapp.__file__), + 'another.zcml') + app = self._callFUT(rootpolicy, fixtureapp, filename='configure.zcml', + options={'configure_zcml':zcmlfile}, + manager=manager) + self.assertEqual(app.registry.__name__, 'repoze.bfg.tests.fixtureapp') + from repoze.bfg.tests.fixtureapp.models import IFixture + self.failIf(app.registry.queryUtility(IFixture)) # only in c.zcml + def test_event(self): + manager = DummyRegistryManager() def subscriber(event): event.app.created = True from repoze.bfg.interfaces import IWSGIApplicationCreatedEvent @@ -693,15 +715,17 @@ class MakeAppTests(unittest.TestCase): (IWSGIApplicationCreatedEvent,) ) from repoze.bfg.tests import fixtureapp - rootpolicy = make_rootfactory(None) - app = self._callFUT(rootpolicy, fixtureapp) + rootpolicy = DummyRootFactory(None) + app = self._callFUT(rootpolicy, fixtureapp, manager=manager) assert app.created is True def test_custom_settings(self): + manager = DummyRegistryManager() options= {'mysetting':True} from repoze.bfg.tests import fixtureapp - rootpolicy = make_rootfactory(None) - app = self._callFUT(rootpolicy, fixtureapp, options=options) + rootpolicy = DummyRootFactory(None) + app = self._callFUT(rootpolicy, fixtureapp, options=options, + manager=manager) from repoze.bfg.interfaces import ISettings settings = app.registry.getUtility(ISettings) self.assertEqual(settings.reload_templates, False) @@ -709,11 +733,13 @@ class MakeAppTests(unittest.TestCase): self.assertEqual(settings.mysetting, True) def test_registrations(self): + manager = DummyRegistryManager() options= {'reload_templates':True, 'debug_authorization':True} from repoze.bfg.tests import fixtureapp - rootpolicy = make_rootfactory(None) - app = self._callFUT(rootpolicy, fixtureapp, options=options) + rootpolicy = DummyRootFactory(None) + app = self._callFUT(rootpolicy, fixtureapp, options=options, + manager=manager) from repoze.bfg.interfaces import ISettings from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import IRootFactory @@ -724,15 +750,17 @@ class MakeAppTests(unittest.TestCase): self.assertEqual(settings.reload_templates, True) self.assertEqual(settings.debug_authorization, True) self.assertEqual(rootfactory, rootpolicy) - self.failUnless(self.regmgr.pushed and self.regmgr.popped) + self.failUnless(manager.pushed and manager.popped) def test_routes_in_config_with_rootpolicy(self): + manager = DummyRegistryManager() options= {'reload_templates':True, 'debug_authorization':True} from repoze.bfg.urldispatch import RoutesRootFactory from repoze.bfg.tests import routesapp - rootpolicy = make_rootfactory(None) - app = self._callFUT(rootpolicy, routesapp, options=options) + rootpolicy = DummyRootFactory(None) + app = self._callFUT(rootpolicy, routesapp, options=options, + manager=manager) from repoze.bfg.interfaces import ISettings from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import IRootFactory @@ -744,15 +772,17 @@ class MakeAppTests(unittest.TestCase): self.assertEqual(settings.debug_authorization, True) self.failUnless(isinstance(rootfactory, RoutesRootFactory)) self.assertEqual(rootfactory.default_root_factory, rootpolicy) - self.failUnless(self.regmgr.pushed and self.regmgr.popped) + self.failUnless(manager.pushed and manager.popped) def test_routes_in_config_no_rootpolicy(self): + manager = DummyRegistryManager() options= {'reload_templates':True, 'debug_authorization':True} from repoze.bfg.urldispatch import RoutesRootFactory from repoze.bfg.router import DefaultRootFactory from repoze.bfg.tests import routesapp - app = self._callFUT(None, routesapp, options=options) + app = self._callFUT(None, routesapp, options=options, + manager=manager) from repoze.bfg.interfaces import ISettings from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import IRootFactory @@ -764,29 +794,33 @@ class MakeAppTests(unittest.TestCase): self.assertEqual(settings.debug_authorization, True) self.failUnless(isinstance(rootfactory, RoutesRootFactory)) self.assertEqual(rootfactory.default_root_factory, DefaultRootFactory) - self.failUnless(self.regmgr.pushed and self.regmgr.popped) + self.failUnless(manager.pushed and manager.popped) def test_no_routes_in_config_no_rootpolicy(self): + manager = DummyRegistryManager() from repoze.bfg.router import DefaultRootFactory from repoze.bfg.interfaces import IRootFactory options= {'reload_templates':True, 'debug_authorization':True} from repoze.bfg.tests import fixtureapp - app = self._callFUT(None, fixtureapp, options=options) + app = self._callFUT(None, fixtureapp, options=options, + manager=manager) rootfactory = app.registry.getUtility(IRootFactory) self.assertEqual(rootfactory, DefaultRootFactory) def test_authorization_policy_no_authentication_policy(self): + manager = DummyRegistryManager() from repoze.bfg.interfaces import IAuthorizationPolicy authzpolicy = DummyContext() from repoze.bfg.tests import routesapp logger = DummyLogger() app = self._callFUT(None, routesapp, authorization_policy=authzpolicy, - debug_logger=logger) + debug_logger=logger, manager=manager) self.failIf(app.registry.queryUtility(IAuthorizationPolicy)) self.assertEqual(logger.messages, []) def test_authentication_policy_no_authorization_policy(self): + manager = DummyRegistryManager() from repoze.bfg.interfaces import IAuthorizationPolicy from repoze.bfg.interfaces import IAuthenticationPolicy from repoze.bfg.authorization import ACLAuthorizationPolicy @@ -794,7 +828,7 @@ class MakeAppTests(unittest.TestCase): from repoze.bfg.tests import routesapp logger = DummyLogger() app = self._callFUT(None, routesapp, authentication_policy=authnpolicy, - debug_logger=logger) + debug_logger=logger, manager=manager) self.assertEqual(app.registry.getUtility(IAuthenticationPolicy), authnpolicy) self.assertEqual( @@ -803,6 +837,7 @@ class MakeAppTests(unittest.TestCase): self.assertEqual(len(logger.messages), 1) # deprecation warning def test_authentication_policy_and_authorization_policy(self): + manager = DummyRegistryManager() from repoze.bfg.interfaces import IAuthorizationPolicy from repoze.bfg.interfaces import IAuthenticationPolicy authnpolicy = DummyContext() @@ -811,7 +846,7 @@ class MakeAppTests(unittest.TestCase): logger = DummyLogger() app = self._callFUT(None, routesapp, authentication_policy=authnpolicy, authorization_policy = authzpolicy, - debug_logger=logger) + debug_logger=logger, manager=manager) self.assertEqual(app.registry.getUtility(IAuthenticationPolicy), authnpolicy) self.assertEqual(app.registry.getUtility(IAuthorizationPolicy), @@ -866,15 +901,19 @@ class DummyRegistryManager: class DummyContext: pass -def make_view(response): - def view(context, request): - return response - return view +class DummyView: + def __init__(self, response): + self.response = response + + def __call__(self, context, request): + return self.response + +class DummyRootFactory: + def __init__(self, root): + self.root = root -def make_rootfactory(root): - def rootpolicy(environ): - return root - return rootpolicy + def __call__(self, environ): + return self.root class DummyStartResponse: status = () diff --git a/repoze/bfg/tests/test_settings.py b/repoze/bfg/tests/test_settings.py index 8319a302d..bef8297bf 100644 --- a/repoze/bfg/tests/test_settings.py +++ b/repoze/bfg/tests/test_settings.py @@ -148,6 +148,17 @@ class TestGetOptions(unittest.TestCase): self.assertEqual(result['debug_notfound'], True) self.assertEqual(result['debug_authorization'], True) + def test_configure_zcml(self): + result = self._callFUT({}) + self.assertEqual(result['configure_zcml'], '') + result = self._callFUT({'configure_zcml':'abc'}) + self.assertEqual(result['configure_zcml'], 'abc') + result = self._callFUT({}, {'BFG_CONFIGURE_ZCML':'abc'}) + self.assertEqual(result['configure_zcml'], 'abc') + result = self._callFUT({'configure_zcml':'def'}, + {'BFG_CONFIGURE_ZCML':'abc'}) + self.assertEqual(result['configure_zcml'], 'abc') + def test_originals_kept(self): result = self._callFUT({'a':'i am so a'}) self.assertEqual(result['a'], 'i am so a') -- cgit v1.2.3