diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-11-19 10:44:55 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-11-19 10:44:55 +0000 |
| commit | eac7c470021b647d63c2e2af8acd6cebd738f2a4 (patch) | |
| tree | 6d04102c9442c0dd67a26d002ff89ae51b454993 | |
| parent | 4dd55a50a7ed559748661f369313030773d13e75 (diff) | |
| download | pyramid-eac7c470021b647d63c2e2af8acd6cebd738f2a4.tar.gz pyramid-eac7c470021b647d63c2e2af8acd6cebd738f2a4.tar.bz2 pyramid-eac7c470021b647d63c2e2af8acd6cebd738f2a4.zip | |
Rearrange things to try to avoid circular import deps.
| -rw-r--r-- | repoze/bfg/configuration.py | 71 | ||||
| -rw-r--r-- | repoze/bfg/router.py | 43 | ||||
| -rw-r--r-- | repoze/bfg/testing.py | 5 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_configuration.py | 63 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_router.py | 70 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_traversal.py | 24 | ||||
| -rw-r--r-- | repoze/bfg/traversal.py | 9 | ||||
| -rw-r--r-- | repoze/bfg/zcml.py | 17 |
8 files changed, 135 insertions, 167 deletions
diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py index 74c848946..447cb5963 100644 --- a/repoze/bfg/configuration.py +++ b/repoze/bfg/configuration.py @@ -5,10 +5,10 @@ import threading import inspect import zope.component +from zope.component.event import dispatch -from zope.configuration import xmlconfig from zope.configuration.exceptions import ConfigurationError -from zope.configuration.config import ConfigurationMachine +from zope.configuration import xmlconfig from zope.component import getGlobalSiteManager from zope.component import getSiteManager @@ -39,6 +39,7 @@ from repoze.bfg import chameleon_zpt from repoze.bfg import chameleon_text from repoze.bfg import renderers from repoze.bfg.compat import all +from repoze.bfg.events import WSGIApplicationCreatedEvent from repoze.bfg.exceptions import Forbidden from repoze.bfg.exceptions import NotFound from repoze.bfg.log import make_stream_logger @@ -51,6 +52,7 @@ from repoze.bfg.static import StaticRootFactory from repoze.bfg.threadlocal import get_current_registry from repoze.bfg.threadlocal import manager from repoze.bfg.traversal import find_interface +from repoze.bfg.traversal import DefaultRootFactory from repoze.bfg.urldispatch import RoutesMapper from repoze.bfg.view import MultiView from repoze.bfg.view import decorate_view @@ -61,26 +63,13 @@ from repoze.bfg.view import static as static_view import martian -def zcml_configure(name, package): - """ Given a ZCML filename as ``name`` and a Python package as - ``package`` which the filename should be relative to, load the - ZCML into the current ZCML registry. - - .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. - """ - context = ConfigurationMachine() - xmlconfig.registerCommonDirectives(context) - context.package = package - xmlconfig.include(context, name, package) - context.execute_actions(clear=False) - return context.actions - class Configurator(object): """ A wrapper around the registry that performs configuration tasks """ def __init__(self, registry=None): if registry is None: - registry = self.make_default_registry() - self.reg = registry + self.make_default_registry() + else: + self.reg = registry def make_default_registry(self): self.reg = Registry() @@ -94,14 +83,31 @@ class Configurator(object): self.debug_logger(None) return self.reg - def default_configuration(self, root_factory, package=None, - filename='configure.zcml', settings=None, - debug_logger=None, manager=manager, os=os, - lock=threading.Lock()): + def make_wsgi_app(self, manager=manager, getSiteManager=getSiteManager): + from repoze.bfg.router import Router # avoid circdep + app = Router(self.reg) + # executing sethook means we're taking over getSiteManager for + # the lifetime of this process + getSiteManager.sethook(get_current_registry) + # We push the registry on to the stack here in case any ZCA API is + # used in listeners subscribed to the WSGIApplicationCreatedEvent + # we send. + manager.push({'registry':self.reg, 'request':None}) + try: + # use dispatch here instead of registry.notify to make unit + # tests possible + dispatch(WSGIApplicationCreatedEvent(app)) + finally: + manager.pop() + return app + + def declarative(self, root_factory, package=None, + filename='configure.zcml', settings=None, + debug_logger=None, os=os, lock=threading.Lock()): self.make_default_registry() - # registry, debug_logger, manager, os and lock *only* for unittests + # debug_logger, os and lock *only* for unittests if settings is None: settings = {} @@ -120,7 +126,9 @@ class Configurator(object): self.settings(settings) self.debug_logger(debug_logger) self.root_factory(root_factory or DefaultRootFactory) + self.load_zcml(filename, package, lock=lock) + def load_zcml(self, filename, package=None, lock=threading.Lock()): # We push our ZCML-defined configuration into an app-local # component registry in order to allow more than one bfg app to live # in the same process space without one unnecessarily stomping on @@ -134,13 +142,12 @@ class Configurator(object): # site manager API directly in a different thread while we hold the # lock. Those registrations will end up in our application's # registry. - lock.acquire() manager.push({'registry':self.reg, 'request':None}) try: getSiteManager.sethook(get_current_registry) zope.component.getGlobalSiteManager = get_current_registry - zcml_configure(filename, package) + xmlconfig.file(filename, package, execute=True) finally: zope.component.getGlobalSiteManager = getGlobalSiteManager lock.release() @@ -567,8 +574,8 @@ class Configurator(object): def view(context, request): return {} else: - raise ConfigurationError('"view" attribute was not specified and ' - 'no renderer specified') + raise ConfigurationError('"view" attribute was not specified ' + 'and no renderer specified') derived_view = self.derive_view(view, attr=attr, renderer_name=renderer, wrapper_viewname=wrapper) @@ -709,13 +716,3 @@ class BFGViewGrokker(martian.InstanceGrokker): config.view(view=obj, _info=info, **settings) return bool(config) -class DefaultRootFactory: - __parent__ = None - __name__ = None - def __init__(self, request): - matchdict = getattr(request, 'matchdict', {}) - # provide backwards compatibility for applications which - # used routes (at least apps without any custom "context - # factory") in BFG 0.9.X and before - self.__dict__.update(matchdict) - diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index b317c9b35..7edf40620 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -1,11 +1,7 @@ -from zope.component.event import dispatch - from zope.interface import implements from zope.interface import providedBy from zope.interface import alsoProvides -from zope.component import getSiteManager - from repoze.bfg.interfaces import IForbiddenView from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import INotFoundView @@ -17,24 +13,18 @@ from repoze.bfg.interfaces import ISettings from repoze.bfg.interfaces import ITraverser from repoze.bfg.interfaces import IView -from repoze.bfg.configuration import DefaultRootFactory -from repoze.bfg.configuration import Configurator from repoze.bfg.events import AfterTraversal from repoze.bfg.events import NewRequest from repoze.bfg.events import NewResponse -from repoze.bfg.events import WSGIApplicationCreatedEvent from repoze.bfg.exceptions import Forbidden from repoze.bfg.exceptions import NotFound -from repoze.bfg.registry import Registry from repoze.bfg.request import Request from repoze.bfg.threadlocal import manager -from repoze.bfg.threadlocal import get_current_registry +from repoze.bfg.traversal import DefaultRootFactory from repoze.bfg.traversal import ModelGraphTraverser from repoze.bfg.view import default_forbidden_view from repoze.bfg.view import default_notfound_view -_marker = object() - class Router(object): """ The main repoze.bfg WSGI application. """ implements(IRouter) @@ -43,9 +33,6 @@ class Router(object): threadlocal_manager = manager def __init__(self, registry): - # executing sethook means we're taking over getSiteManager for - # the lifetime of this process - getSiteManager.sethook(get_current_registry) q = registry.queryUtility self.logger = q(ILogger, 'repoze.bfg.debug') self.notfound_view = q(INotFoundView, default=default_notfound_view) @@ -162,10 +149,10 @@ class Router(object): finally: manager.pop() -# note that ``options`` is a b/w compat alias for ``settings`` +# note that ``options`` is a b/w compat alias for ``settings`` and +# ``Configurator`` is a testing dep inj def make_app(root_factory, package=None, filename='configure.zcml', - settings=None, options=None, Configurator=Configurator, - Router=Router, Registry=Registry, manager=manager): + settings=None, options=None, Configurator=None): """ Return a Router object, representing a fully configured ``repoze.bfg`` WSGI application. @@ -202,20 +189,12 @@ def make_app(root_factory, package=None, filename='configure.zcml', parameter ``options`` is a backwards compatibility alias for the ``settings`` keyword parameter. """ + if Configurator is None: + from repoze.bfg.configuration import Configurator settings = settings or options - registry = Registry('make_app') - config = Configurator(registry) - config.default_configuration(root_factory, package=package, - filename=filename, settings=settings) - app = Router(registry) - # We push the registry on to the stack here in case any ZCA API is - # used in listeners subscribed to the WSGIApplicationCreatedEvent - # we send. - manager.push({'registry':registry, 'request':None}) - try: - # use dispatch here instead of registry.notify to make unit - # tests possible - dispatch(WSGIApplicationCreatedEvent(app)) - finally: - manager.pop() + config = Configurator() + config.declarative(root_factory, package=package, + filename=filename, settings=settings) + app = config.make_wsgi_app() return app + diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py index af659aca6..128e5cf32 100644 --- a/repoze/bfg/testing.py +++ b/repoze/bfg/testing.py @@ -1,6 +1,7 @@ import copy from zope.configuration.xmlconfig import _clearContext + from zope.component import getSiteManager from zope.deprecation import deprecated from zope.interface import implements @@ -8,10 +9,9 @@ from zope.interface import Interface from repoze.bfg.interfaces import IRequest -from repoze.bfg.configuration import zcml_configure # API import alias -from repoze.bfg.registry import Registry from repoze.bfg.threadlocal import manager from repoze.bfg.threadlocal import get_current_registry +from repoze.bfg.zcml import zcml_configure # API _marker = object() @@ -535,6 +535,7 @@ def setUp(): .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. """ + from repoze.bfg.registry import Registry registry = Registry('testing') manager.clear() manager.push({'registry':registry, 'request':None}) diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py index 1916fe11d..a1f60a91f 100644 --- a/repoze/bfg/tests/test_configuration.py +++ b/repoze/bfg/tests/test_configuration.py @@ -38,7 +38,7 @@ class ConfiguratorTests(unittest.TestCase): def _callDefaultConfiguration(self, *arg, **kw): inst = self._makeOne() - inst.default_configuration(*arg, **kw) + inst.declarative(*arg, **kw) return inst.reg def _getRouteRequestIface(self, config, name): @@ -292,7 +292,7 @@ class ConfiguratorTests(unittest.TestCase): request.params = {'param':'1'} self.assertEqual(wrapper(ctx, request), 'view8') - def test_view_with_relative_template_renderer(self): + def test_view_with_template_renderer(self): class view(object): def __init__(self, context, request): self.request = request @@ -302,24 +302,24 @@ class ConfiguratorTests(unittest.TestCase): return {'a':'1'} config = self._makeOne() renderer = self._registerRenderer(config) - fixture = 'fixtures/minimal.txt' + fixture = 'repoze.bfg.tests:fixtures/minimal.txt' config.view(view=view, renderer=fixture) wrapper = self._getViewCallable(config) request = DummyRequest() result = wrapper(None, request) self.assertEqual(result.body, 'Hello!') - self.assertEqual(renderer.path, 'fixtures/minimal.txt') + self.assertEqual(renderer.path, 'repoze.bfg.tests:fixtures/minimal.txt') - def test_view_with_relative_template_renderer_no_callable(self): + def test_view_with_template_renderer_no_callable(self): config = self._makeOne() renderer = self._registerRenderer(config) - fixture = 'fixtures/minimal.txt' + fixture = 'repoze.bfg.tests:fixtures/minimal.txt' config.view(view=None, renderer=fixture) wrapper = self._getViewCallable(config) request = DummyRequest() result = wrapper(None, request) self.assertEqual(result.body, 'Hello!') - self.assertEqual(renderer.path, 'fixtures/minimal.txt') + self.assertEqual(renderer.path, 'repoze.bfg.tests:fixtures/minimal.txt') def test_view_with_request_type_as_iface(self): def view(context, request): @@ -1162,43 +1162,36 @@ class ConfiguratorTests(unittest.TestCase): self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml def test_default_config_fixtureapp_explicit_filename(self): - manager = DummyRegistryManager() from repoze.bfg.tests import fixtureapp rootfactory = DummyRootFactory(None) registry = self._callDefaultConfiguration( - rootfactory, fixtureapp, filename='another.zcml', - manager=manager) + rootfactory, fixtureapp, filename='another.zcml') from repoze.bfg.tests.fixtureapp.models import IFixture self.failIf(registry.queryUtility(IFixture)) # only in c.zcml def test_default_config_fixtureapp_explicit_filename_in_settings(self): import os - manager = DummyRegistryManager() rootfactory = DummyRootFactory(None) from repoze.bfg.tests import fixtureapp zcmlfile = os.path.join(os.path.dirname(fixtureapp.__file__), 'another.zcml') registry = self._callDefaultConfiguration( rootfactory, fixtureapp, filename='configure.zcml', - settings={'configure_zcml':zcmlfile}, - manager=manager) + settings={'configure_zcml':zcmlfile}) from repoze.bfg.tests.fixtureapp.models import IFixture self.failIf(registry.queryUtility(IFixture)) # only in c.zcml def test_default_config_fixtureapp_explicit_specification_in_settings(self): - manager = DummyRegistryManager() rootfactory = DummyRootFactory(None) from repoze.bfg.tests import fixtureapp zcmlfile = 'repoze.bfg.tests.fixtureapp.subpackage:yetanother.zcml' registry = self._callDefaultConfiguration( rootfactory, fixtureapp, filename='configure.zcml', - settings={'configure_zcml':zcmlfile}, - manager=manager) + settings={'configure_zcml':zcmlfile}) from repoze.bfg.tests.fixtureapp.models import IFixture self.failIf(registry.queryUtility(IFixture)) # only in c.zcml def test_default_config_fixtureapp_filename_hascolon_isabs(self): - manager = DummyRegistryManager() rootfactory = DummyRootFactory(None) from repoze.bfg.tests import fixtureapp zcmlfile = 'repoze.bfg.tests.fixtureapp.subpackage:yetanother.zcml' @@ -1212,32 +1205,28 @@ class ConfiguratorTests(unittest.TestCase): fixtureapp, filename='configure.zcml', settings={'configure_zcml':zcmlfile}, - manager=manager, os=os) def test_default_config_custom_settings(self): - manager = DummyRegistryManager() settings = {'mysetting':True} from repoze.bfg.tests import fixtureapp rootfactory = DummyRootFactory(None) registry = self._callDefaultConfiguration( - rootfactory, fixtureapp, settings=settings, - manager=manager) + rootfactory, fixtureapp, settings=settings) from repoze.bfg.interfaces import ISettings settings = registry.getUtility(ISettings) self.assertEqual(settings.reload_templates, False) self.assertEqual(settings.debug_authorization, False) self.assertEqual(settings.mysetting, True) - def test_default_config_registrations(self): + def test_declarative_registrations(self): manager = DummyRegistryManager() settings = {'reload_templates':True, 'debug_authorization':True} from repoze.bfg.tests import fixtureapp rootfactory = DummyRootFactory(None) registry = self._callDefaultConfiguration( - rootfactory, fixtureapp, settings=settings, - manager=manager) + rootfactory, fixtureapp, settings=settings) from repoze.bfg.interfaces import ISettings from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import IRootFactory @@ -1248,7 +1237,6 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(settings.reload_templates, True) self.assertEqual(settings.debug_authorization, True) self.assertEqual(rootfactory, rootfactory) - self.failUnless(manager.pushed and manager.popped) def test_default_config_routes_in_config(self): from repoze.bfg.interfaces import ISettings @@ -1325,31 +1313,6 @@ class TestBFGViewGrokker(unittest.TestCase): result = grokker.grok('name', obj) self.assertEqual(result, False) -class TestDefaultRootFactory(unittest.TestCase): - def _getTargetClass(self): - from repoze.bfg.configuration import DefaultRootFactory - return DefaultRootFactory - - def _makeOne(self, environ): - return self._getTargetClass()(environ) - - def test_no_matchdict(self): - environ = {} - root = self._makeOne(environ) - self.assertEqual(root.__parent__, None) - self.assertEqual(root.__name__, None) - - def test_matchdict(self): - class DummyRequest: - pass - request = DummyRequest() - request.matchdict = {'a':1, 'b':2} - root = self._makeOne(request) - self.assertEqual(root.a, 1) - self.assertEqual(root.b, 2) - - - class DummyRequest: pass diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index 3321af938..f3fe6dd70 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -528,46 +528,26 @@ class TestMakeApp(unittest.TestCase): return make_app(*arg, **kw) def test_it(self): - from repoze.bfg.interfaces import IWSGIApplicationCreatedEvent - from repoze.bfg.tests import fixtureapp - from zope.component import getSiteManager - sm = getSiteManager() - def subscriber(event): - event.app.created = True - manager = DummyRegistryManager() - sm.registerHandler(subscriber, (IWSGIApplicationCreatedEvent,)) - rootfactory = DummyRootFactory(None) settings = {'a':1} - app = self._callFUT(rootfactory, fixtureapp, settings=settings, - Configurator=DummyConfigurator, manager=manager) - self.failUnless(app.created) - self.failUnless(manager.pushed) - self.failUnless(manager.popped) - self.assertEqual(app.registry.root_factory, rootfactory) - self.assertEqual(app.registry.settings, settings) - self.assertEqual(app.registry.package, fixtureapp) - self.assertEqual(app.registry.filename, 'configure.zcml') + package = object() + rootfactory = object() + app = self._callFUT(rootfactory, package, settings=settings, + Configurator=DummyConfigurator) + self.assertEqual(app.root_factory, rootfactory) + self.assertEqual(app.settings, settings) + self.assertEqual(app.package, package) + self.assertEqual(app.filename, 'configure.zcml') def test_it_options_means_settings(self): - from repoze.bfg.interfaces import IWSGIApplicationCreatedEvent - from repoze.bfg.tests import fixtureapp - from zope.component import getSiteManager - sm = getSiteManager() - def subscriber(event): - event.app.created = True - manager = DummyRegistryManager() - sm.registerHandler(subscriber, (IWSGIApplicationCreatedEvent,)) - rootfactory = DummyRootFactory(None) settings = {'a':1} - app = self._callFUT(rootfactory, fixtureapp, options=settings, - Configurator=DummyConfigurator, manager=manager) - self.failUnless(app.created) - self.failUnless(manager.pushed) - self.failUnless(manager.popped) - self.assertEqual(app.registry.root_factory, rootfactory) - self.assertEqual(app.registry.settings, settings) - self.assertEqual(app.registry.package, fixtureapp) - self.assertEqual(app.registry.filename, 'configure.zcml') + package = object() + rootfactory = object() + app = self._callFUT(rootfactory, package, options=settings, + Configurator=DummyConfigurator) + self.assertEqual(app.root_factory, rootfactory) + self.assertEqual(app.settings, settings) + self.assertEqual(app.package, package) + self.assertEqual(app.filename, 'configure.zcml') class DummyContext: pass @@ -640,13 +620,13 @@ class DummyRegistryManager: self.popped = True class DummyConfigurator(object): - def __init__(self, registry): - self.registry = registry - - def default_configuration(self, root_factory=None, package=None, - filename=None, settings=None): - self.registry.root_factory = root_factory - self.registry.package = package - self.registry.filename = filename - self.registry.settings = settings + def make_wsgi_app(self): + return self + + def declarative(self, root_factory=None, package=None, + filename=None, settings=None): + self.root_factory = root_factory + self.package = package + self.filename = filename + self.settings = settings diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py index aceed1076..a15716d4c 100644 --- a/repoze/bfg/tests/test_traversal.py +++ b/repoze/bfg/tests/test_traversal.py @@ -970,6 +970,30 @@ class TraverseTests(unittest.TestCase): self.assertEqual(result['view_name'], '') self.assertEqual(result['context'], model) +class TestDefaultRootFactory(unittest.TestCase): + def _getTargetClass(self): + from repoze.bfg.traversal import DefaultRootFactory + return DefaultRootFactory + + def _makeOne(self, environ): + return self._getTargetClass()(environ) + + def test_no_matchdict(self): + environ = {} + root = self._makeOne(environ) + self.assertEqual(root.__parent__, None) + self.assertEqual(root.__name__, None) + + def test_matchdict(self): + class DummyRequest: + pass + request = DummyRequest() + request.matchdict = {'a':1, 'b':2} + root = self._makeOne(request) + self.assertEqual(root.a, 1) + self.assertEqual(root.b, 2) + + def make_traverser(result): class DummyTraverser(object): def __init__(self, context): diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py index 325e41e4b..b46fb83c7 100644 --- a/repoze/bfg/traversal.py +++ b/repoze/bfg/traversal.py @@ -632,3 +632,12 @@ class TraversalContextURL(object): def _join_path_tuple(tuple): return tuple and '/'.join([quote_path_segment(x) for x in tuple]) or '/' +class DefaultRootFactory: + __parent__ = None + __name__ = None + def __init__(self, request): + matchdict = getattr(request, 'matchdict', {}) + # provide backwards compatibility for applications which + # used routes (at least apps without any custom "context + # factory") in BFG 0.9.X and before + self.__dict__.update(matchdict) diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index a7c5f2660..eae53c337 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -1,5 +1,7 @@ from zope.configuration.exceptions import ConfigurationError from zope.configuration.fields import GlobalObject +from zope.configuration.config import ConfigurationMachine +from zope.configuration import xmlconfig from zope.interface import Interface @@ -22,7 +24,6 @@ from repoze.bfg.authentication import RepozeWho1AuthenticationPolicy from repoze.bfg.authentication import RemoteUserAuthenticationPolicy from repoze.bfg.authentication import AuthTktAuthenticationPolicy from repoze.bfg.authorization import ACLAuthorizationPolicy -from repoze.bfg.configuration import zcml_configure from repoze.bfg.configuration import Configurator from repoze.bfg.path import package_name from repoze.bfg.request import route_request_iface @@ -536,5 +537,19 @@ class Uncacheable(object): """ Include in discriminators of actions which are not cacheable; this class only exists for backwards compatibility (<0.8.1)""" +def zcml_configure(name, package): + """ Given a ZCML filename as ``name`` and a Python package as + ``package`` which the filename should be relative to, load the + ZCML into the current ZCML registry. + + .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. + """ + context = ConfigurationMachine() + xmlconfig.registerCommonDirectives(context) + context.package = package + xmlconfig.include(context, name, package) + context.execute_actions(clear=False) # the raison d'etre + return context.actions + file_configure = zcml_configure # backwards compat (>0.8.1) |
