summaryrefslogtreecommitdiff
path: root/repoze/bfg/router.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-10-15 15:44:33 +0000
committerChris McDonough <chrism@agendaless.com>2009-10-15 15:44:33 +0000
commit17b8bc69b783be4b81a6c42818c6227845b16683 (patch)
treefa481f95e2508b6cf57185cec3e687372fa8ad18 /repoze/bfg/router.py
parent083422c0c66c1aa53f9d96c6fd185e238bc51708 (diff)
downloadpyramid-17b8bc69b783be4b81a6c42818c6227845b16683.tar.gz
pyramid-17b8bc69b783be4b81a6c42818c6227845b16683.tar.bz2
pyramid-17b8bc69b783be4b81a6c42818c6227845b16683.zip
Features
-------- - Add ``setUp`` and ``tearDown`` functions to the ``repoze.bfg.testing`` module. Using ``setUp`` in a test setup and ``tearDown`` in a test teardown is now the recommended way to do component registry setup and teardown. Previously, it was recommended that a single function named ``repoze.bfg.testing.cleanUp`` be called in both the test setup and tear down. ``repoze.bfg.testing.cleanUp`` still exists (and will exist "forever" due to its widespread use); it is now just an alias for ``repoze.bfg.testing.setUp`` and is nominally deprecated. - The BFG component registry is now available in view and event subscriber code as an attribute of the request ie. ``request.registry``. This fact is currently undocumented except for this note, because BFG developers never need to interact with the registry directly anywhere else. - The BFG component registry now inherits from ``dict``, meaning that it can optionally be used as a simple dictionary. *Component* registrations performed against it via e.g. ``registerUtility``, ``registerAdapter``, and similar API methods are kept in a completely separate namespace than its dict members, so using the its component API methods won't effect the keys and values in the dictionary namespace. Likewise, though the component registry "happens to be" a dictionary, use of mutating dictionary methods such as ``__setitem__`` will have no influence on any component registrations made against it. In other words, the registry object you obtain via e.g. ``repoze.bfg.threadlocal.get_current_registry`` or ``request.registry`` happens to be both a component registry and a dictionary, but using its component-registry API won't impact data added to it via its dictionary API and vice versa. This is a forward compatibility move based on the goals of "marco". Documentation ------------- - Various tutorial test modules updated to use ``repoze.bfg.testing.setUp`` and ``repoze.bfg.testing.tearDown`` methods in order to encourage this as best practice going forward. Backwards Incompatibilities --------------------------- - Importing ``getSiteManager`` and ``get_registry`` from ``repoze.bfg.registry`` is no longer supported. These imports were deprecated in repoze.bfg 1.0. Import of ``getSiteManager`` should be done as ``from zope.component import getSiteManager``. Import of ``get_registry`` should be done as ``from repoze.bfg.threadlocal import get_current_registry``. This was done to prevent a circular import dependency. - Code bases which alternately invoke both ``zope.testing.cleanup.cleanUp`` and ``repoze.bfg.testing.cleanUp`` (treating them equivalently, using them interchangeably) in the setUp/tearDown of unit tests will begin to experience test failures due to lack of test isolation. The "right" mechanism is ``repoze.bfg.testing.cleanUp`` (or the combination of ``repoze.bfg.testing.setUp`` and ``repoze.bfg.testing.tearDown``). but a good number of legacy codebases will use ``zope.testing.cleanup.cleanUp`` instead. We support ``zope.testing.cleanup.cleanUp`` but not in combination with ``repoze.bfg.testing.cleanUp`` in the same codebase. You should use one or the other test cleanup function in a single codebase, but not both. Internal -------- - Created new ``repoze.bfg.configuration`` module which assumes responsibilities previously held by the ``repoze.bfg.registry`` and ``repoze.bfg.router`` modules (avoid a circular import dependency). - The result of the ``zope.component.getSiteManager`` function in unit tests set up with ``repoze.bfg.testing.cleanUp`` or ``repoze.bfg.testing.setUp`` will be an instance of ``repoze.bfg.registry.Registry`` instead of the global ``zope.component.globalregistry.base`` registry. This also means that the threadlocal ZCA API functions such as ``getAdapter`` and ``getUtility`` as well as internal BFG machinery (such as ``model_url`` and ``route_url``) will consult this registry within unit tests. This is a forward compatibility move based on the goals of "marco". - Removed ``repoze.bfg.testing.addCleanUp`` function and associated module-scope globals. This was never an API.
Diffstat (limited to 'repoze/bfg/router.py')
-rw-r--r--repoze/bfg/router.py121
1 files changed, 17 insertions, 104 deletions
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index e2b2b6830..1b894129b 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -1,40 +1,28 @@
-import os
-import sys
+from zope.component.event import dispatch
from zope.interface import implements
from zope.interface import providedBy
-from zope.component.event import dispatch
-
-from repoze.bfg.interfaces import IAuthenticationPolicy
-from repoze.bfg.interfaces import IAuthorizationPolicy
-from repoze.bfg.interfaces import IDefaultRootFactory
from repoze.bfg.interfaces import IForbiddenView
from repoze.bfg.interfaces import ILogger
from repoze.bfg.interfaces import INotFoundView
from repoze.bfg.interfaces import IRootFactory
from repoze.bfg.interfaces import IRouter
-from repoze.bfg.interfaces import IRoutesMapper
from repoze.bfg.interfaces import ISettings
from repoze.bfg.interfaces import ITraverserFactory
from repoze.bfg.interfaces import IView
-from repoze.bfg.authorization import ACLAuthorizationPolicy
+from repoze.bfg.configuration import make_registry
+from repoze.bfg.configuration import DefaultRootFactory
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.log import make_stream_logger
-from repoze.bfg.registry import Registry
-from repoze.bfg.registry import populateRegistry
from repoze.bfg.request import request_factory
-from repoze.bfg.settings import Settings
-from repoze.bfg.settings import get_options
from repoze.bfg.threadlocal import manager
from repoze.bfg.traversal import ModelGraphTraverser
from repoze.bfg.traversal import _traverse
-from repoze.bfg.urldispatch import RoutesRootFactory
from repoze.bfg.view import default_forbidden_view
from repoze.bfg.view import default_notfound_view
@@ -76,6 +64,14 @@ class Router(object):
try:
root = self.root_factory(environ)
request = request_factory(environ)
+
+ # webob.Request's __setattr__ (as of 0.9.5 and lower) is a
+ # bottleneck; since we're sure we're using a
+ # webob.Request, we can go around its back and set stuff
+ # into the environ directly
+ attrs = environ.setdefault('webob.adhoc_attrs', {})
+ attrs['registry'] = registry
+
threadlocals['request'] = request
registry.has_listeners and registry.notify(NewRequest(request))
traverser = registry.queryAdapter(root, ITraverserFactory)
@@ -86,16 +82,7 @@ class Router(object):
tdict['context'], tdict['view_name'], tdict['subpath'],
tdict['traversed'], tdict['virtual_root'],
tdict['virtual_root_path'])
-
- # webob.Request's __setattr__ (as of 0.9.5 and lower) is a
- # bottleneck; since we're sure we're using a
- # webob.Request, we can go around its back and set stuff
- # into the environ directly
- if 'webob.adhoc_attrs' in environ:
- attrs = environ.setdefault('webob.adhoc_attrs', {})
- attrs.update(tdict)
- else:
- environ['webob.adhoc_attrs'] = tdict
+ attrs.update(tdict)
provides = map(providedBy, (context, request))
view_callable = registry.adapters.lookup(
@@ -142,11 +129,10 @@ class Router(object):
finally:
manager.pop()
+# make_registry kw arg for unit testing only
def make_app(root_factory, package=None, filename='configure.zcml',
authentication_policy=None, authorization_policy=None,
- options=None, registry=None, debug_logger=None,
- manager=manager, os=os):
- # registry, debug_logger, manager and os *only* for unittests
+ options=None, manager=manager, make_registry=make_registry):
""" Return a Router object, representing a fully configured
``repoze.bfg`` WSGI application.
@@ -180,72 +166,10 @@ def make_app(root_factory, package=None, filename='configure.zcml',
PasteDeploy file), with each key representing the option and the
key's value representing the specific option value,
e.g. ``{'reload_templates':True}``"""
- if options is None:
- options = {}
-
- if not 'configure_zcml' in options:
- options['configure_zcml'] = filename
-
- settings = Settings(get_options(options))
- filename = settings['configure_zcml']
-
- # not os.path.isabs below for windows systems
- if (':' in filename) and (not os.path.isabs(filename)):
- package, filename = filename.split(':', 1)
- __import__(package)
- package = sys.modules[package]
-
- 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')
-
- if root_factory is None:
- root_factory = DefaultRootFactory
-
- # register the *default* root factory so apps can find it later
- registry.registerUtility(root_factory, IDefaultRootFactory)
-
- mapper = RoutesRootFactory(root_factory)
- registry.registerUtility(mapper, IRoutesMapper)
-
- if authentication_policy:
- debug_logger.warn(
- 'The "authentication_policy" and "authorization_policy" '
- 'arguments to repoze.bfg.router.make_app have been deprecated '
- 'in repoze.bfg version 1.0. Instead of using these arguments to '
- 'configure an authorization/authentication policy pair, use '
- 'a pair of ZCML directives (such as "authtktauthenticationpolicy" '
- 'and "aclauthorizationpolicy" documented within the Security '
- 'chapter in the BFG documentation. If you need to use a custom '
- 'authentication or authorization policy, you should make a ZCML '
- 'directive for it and use that directive within your '
- 'application\'s ZCML')
- registry.registerUtility(authentication_policy, IAuthenticationPolicy)
- if authorization_policy is None:
- authorization_policy = ACLAuthorizationPolicy()
- registry.registerUtility(authorization_policy, IAuthorizationPolicy)
-
- populateRegistry(registry, filename, package)
-
- if mapper.has_routes():
- # if the user had any <route/> statements in his configuration,
- # use the RoutesRootFactory as the IRootFactory; otherwise use the
- # default root factory (optimization; we don't want to go through
- # the Routes logic if we know there are no routes to match)
- root_factory = mapper
-
- registry.registerUtility(root_factory, IRootFactory)
-
+ registry = make_registry(root_factory, package, filename,
+ authentication_policy, authorization_policy,
+ options)
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.
@@ -256,16 +180,5 @@ def make_app(root_factory, package=None, filename='configure.zcml',
dispatch(WSGIApplicationCreatedEvent(app))
finally:
manager.pop()
-
return app
-class DefaultRootFactory:
- __parent__ = None
- __name__ = None
- def __init__(self, environ):
- if 'bfg.routes.matchdict' in environ:
- # 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(environ['bfg.routes.matchdict'])
-