From 37bcb77a86b73151c781d8b0b8c2d3d4e14f5fe7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 19 Jan 2010 02:08:12 +0000 Subject: Bug Fixes --------- - When the ``Configurator`` is passed an instance of ``zope.component.registry.Components`` as a ``registry`` constructor argument, fix the instance up to have the attributes we expect of an instance of ``repoze.bfg.registry.Registry`` when ``setup_registry`` is called. This makes it possible to use the global Zope component registry as a BFG application registry. Documentation ------------- - Change renderings of ZCML directive documentation. - Add a narrative documentation chapter: "Using the Zope Component Architecture in ``repoze.bfg``" --- CHANGES.txt | 23 +- docs/authorintro.rst | 9 +- docs/copyright.rst | 7 + docs/index.rst | 1 + docs/latexindex.rst | 1 + docs/narr/webob.rst | 36 +-- docs/narr/zca.rst | 302 ++++++++++++++++++++++++++ docs/zcml/adapter.rst | 4 - docs/zcml/authtktauthenticationpolicy.rst | 8 - docs/zcml/configure.rst | 1 - docs/zcml/forbidden.rst | 4 - docs/zcml/include.rst | 2 - docs/zcml/notfound.rst | 4 - docs/zcml/remoteuserauthenticationpolicy.rst | 2 - docs/zcml/renderer.rst | 2 - docs/zcml/repozewho1authenticatiohnpolicy.rst | 2 - docs/zcml/resource.rst | 2 - docs/zcml/route.rst | 17 -- docs/zcml/scan.rst | 1 - docs/zcml/static.rst | 3 - docs/zcml/subscriber.rst | 2 - docs/zcml/utility.rst | 4 - docs/zcml/view.rst | 17 -- repoze/bfg/configuration.py | 14 ++ repoze/bfg/tests/test_configuration.py | 14 ++ 25 files changed, 387 insertions(+), 95 deletions(-) create mode 100644 docs/narr/zca.rst diff --git a/CHANGES.txt b/CHANGES.txt index 42a5c2cd3..98ab464b7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,24 @@ +Next release +============ + +Bug Fixes +--------- + +- When the ``Configurator`` is passed an instance of + ``zope.component.registry.Components`` as a ``registry`` constructor + argument, fix the instance up to have the attributes we expect of an + instance of ``repoze.bfg.registry.Registry`` when ``setup_registry`` + is called. This makes it possible to use the global Zope component + registry as a BFG application registry. + +Documentation +------------- + +- Change renderings of ZCML directive documentation. + +- Add a narrative documentation chapter: "Using the Zope Component + Architecture in ``repoze.bfg``" + 1.2b1 (2010-01-18) ================== @@ -7,7 +28,7 @@ Bug Fixes - In ``bfg_routesalchemy``, ``bfg_alchemy`` paster templates and the ``bfgwiki2`` tutorial, clean up the SQLAlchemy connection by registering a ``repoze.tm.after_end`` callback instead of relying on - a ``__del__`` method of a ``Cleanup`` class added to the WSFI + a ``__del__`` method of a ``Cleanup`` class added to the WSGI environment. The ``__del__`` strategy was fragile and caused problems in the wild. Thanks to Daniel Holth for testing. diff --git a/docs/authorintro.rst b/docs/authorintro.rst index 356a26fb8..eb8dbec24 100644 --- a/docs/authorintro.rst +++ b/docs/authorintro.rst @@ -153,6 +153,7 @@ and well-documented. single: Koym, Todd single: van Rossum, Guido single: Peters, Tim + single: Rossi, Chris Thanks ====== @@ -164,10 +165,10 @@ typewriter (a Royal), and my mother, who bought me my first computer Thanks to the following people for providing expertise, resources, and software. Without the help of these folks, neither this book nor the software which it details would exist: Paul Everitt, Tres Seaver, -Andrew Sawyers, Malthe Borch, Carlos de la Guardia, Georg Brandl, -Simon Oram and Nat Hardwick of Electrosoup, Ian Bicking of the Open -Planning Project, Jim Fulton of Zope Corporation, Tom Moroz of the -Open Society Institute, and Todd Koym of Environmental Health +Andrew Sawyers, Malthe Borch, Carlos de la Guardia, Chris Rossi, Georg +Brandl, Simon Oram and Nat Hardwick of Electrosoup, Ian Bicking of the +Open Planning Project, Jim Fulton of Zope Corporation, Tom Moroz of +the Open Society Institute, and Todd Koym of Environmental Health Sciences. Thanks to Guido van Rossum and Tim Peters for Python. diff --git a/docs/copyright.rst b/docs/copyright.rst index 6ecd5af0f..28b6a4089 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -61,6 +61,13 @@ Used with permission: The :ref:`webob_chapter` chapter is adapted, with permission, from documentation originally written by Ian Bicking. +Print Production +---------------- + +The print version of this book was produced using the `Sphinx +`_ documentation generation system and the +`LaTeX `_ typesetting system. + Contacting The Publisher ------------------------ diff --git a/docs/index.rst b/docs/index.rst index 9e64f9d29..590c8708e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -63,6 +63,7 @@ Narrative documentation in chapter form explaining how to use narr/resources narr/router narr/threadlocals + narr/zca Tutorials ========= diff --git a/docs/latexindex.rst b/docs/latexindex.rst index 4220aff35..bfdfb3899 100644 --- a/docs/latexindex.rst +++ b/docs/latexindex.rst @@ -52,6 +52,7 @@ Narrative Documentation narr/router narr/startup narr/threadlocals + narr/zca .. _tutorials: diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index ba710d54d..d931e41a2 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -118,17 +118,17 @@ In addition to the standard :term:`WebOb` attributes, :mod:`repoze.bfg` adds the following special attributes to every request. -``req.subpath`` - The traversal :term:`subpath` will be available as the ``subpath`` - attribute of the :term:`request` object. It will be a sequence - containing zero or more elements (which will be Unicode objects). - See :ref:`traversal_chapter` for information about the subpath. +``req.context`` + The :term:`context` will be available as the ``context`` attribute + of the :term:`request` object. It will be the context object + implied by the current request. See :ref:`traversal_chapter` for + information about context objects. -``req.view_name`` - The :term:`view name` will be available as the ``view_name`` - attribute of the :term:`request` object. It will be a single string - (possibly the empty string if we're rendering a default view). - See :ref:`traversal_chapter` for information about view names. +``req.registry`` + The :term:`application registry` will be available as + the ``registry`` attribute of the :term:`request` object. See + :ref:`zca_chapter` for more information about the application + registry. ``req.root`` The :term:`root` object will be available as the ``root`` attribute @@ -136,11 +136,11 @@ request. traversal started (the root). See :ref:`traversal_chapter` for information about root objects. -``req.context`` - The :term:`context` will be available as the ``context`` attribute - of the :term:`request` object. It will be the context object - implied by the current request. See :ref:`traversal_chapter` for - information about context objects. +``req.subpath`` + The traversal :term:`subpath` will be available as the ``subpath`` + attribute of the :term:`request` object. It will be a sequence + containing zero or more elements (which will be Unicode objects). + See :ref:`traversal_chapter` for information about the subpath. ``req.traversed`` The "traversal path" will be as the ``traversed`` attribute of the @@ -151,6 +151,12 @@ request. included within the traversal path. See :ref:`traversal_chapter` for more information. +``req.view_name`` + The :term:`view name` will be available as the ``view_name`` + attribute of the :term:`request` object. It will be a single string + (possibly the empty string if we're rendering a default view). + See :ref:`traversal_chapter` for information about view names. + ``req.virtual_root`` The :term:`virtual root` will be available as the ``virtual_root`` attribute of the :term:`request` object. It will be the virtual diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst new file mode 100644 index 000000000..2fe6109d7 --- /dev/null +++ b/docs/narr/zca.rst @@ -0,0 +1,302 @@ +.. index:: + single: ZCA + single: Zope Component Architecture + single: zope.component + single: application registry + single: getSiteManager + single: getUtility + +.. _zca_chapter: + +Using the Zope Component Architecture in :mod:`repoze.bfg` +========================================================== + +Under the hood, :mod:`repoze.bfg` uses a :term:`Zope Component +Architecture` component registry as its :term:`application registry`. +The Zope Component Architecture is referred to colloquially as the +"ZCA." + +The ``zope.component`` API used to access data in a traditional Zope +application can be opaque. For example, here is a typical "unnamed +utility" lookup using the :func:`zope.component.getUtility` global API +as it might appear in a traditional Zope application: + +.. ignore-next-block +.. code-block:: python + :linenos: + + from repoze.bfg.interfaces import ISettings + from zope.component import getUtility + settings = getUtility(ISettings) + +After this code runs, ``settings`` will be a Python dictionary. But +it's unlikely that any "civilian" will be able to figure this out just +by reading the code casually. When the ``zope.component.getUtility`` +API is used by a developer, the conceptual load on a casual reader of +code is high. + +While the ZCA is an excellent tool with which to build a *framework* +such as :mod:`repoze.bfg`, it is not always the best tool with which +to build an *application* due to the opacity of the ``zope.component`` +APIs. Accordingly, :mod:`repoze.bfg` tends to hide the the presence +of the ZCA from application developers. You needn't understand the +ZCA to create a :mod:`repoze.bfg` application; the use of the ZCA is +effectively only a framework implementation detail. + +However, developers whom are already used to writing :term:`Zope` +applications often still wish to use the ZCA while building a +:mod:`repoze.bfg` application; :mod:`repoze.bfg` makes this possible. + +.. index:: + single: get_current_registry + single: getUtility + single: getSiteManager + single: ZCA global API + +Using the ZCA Global API in a :mod:`repoze.bfg` Application +----------------------------------------------------------- + +:term:`Zope` uses a single ZCA registry -- the "global" ZCA registry +-- for all Zope applications run in the same Python process, +effectively making it impossible to run more than one Zope application +in a single process. + +However, for ease of deployment, it's often useful to be able to run +more than a single application per process. For example, use of a +:term:`Paste` "composite" allows you to run separate individual WSGI +applications in the same process, each answering requests for some URL +prefix. This makes it possible to run, for example, a TurboGears +application at ``/turbogears`` and a BFG application at ``/bfg``, both +served up using the same :term:`WSGI` server within a single Python +process. + +Most production Zope applications are relatively large, making it +impractical due to memory constraints to run more than one Zope +application per Python process. However, a :mod:`repoze.bfg` +application may be very small and consume very little memory, so it's +a reasonable goal to be able to want to run more than one BFG +application per process. + +In order to make it possible to run more than one :mod:`repoze.bfg` +application in a single process, :mod:`repoze.bfg` defaults to using a +separate ZCA registry *per application*. + +While this services a reasonable goal, it causes some issues when +trying to use patterns which you might use to build a typical +:term:`Zope` application to build a :mod:`repoze.bfg` application. +Without special help, ZCA "global" APIs such as +``zope.component.getUtility`` and ``zope.component.getSiteManager`` +will use the ZCA "global" registry. Therefore, these APIs application +will appear to fail when used in a :mod:`repoze.bfg` application, +because they'll be consulting the ZCA global registry rather than the +component registry associated with your :mod:`repoze.bfg` application. + +There are three ways to fix this: by disusing the ZCA global registry +entirely, by using +:meth:`repoze.bfg.configuration.Configurator.hook_zca` or by passing +the ZCA global registry to the :term:`Configurator` constructor at +startup time. We'll describe all three methods in this section. + +.. index:: + single: request.registry + +.. _disusing_the_global_zca_api: + +Disusing the Global ZCA API ++++++++++++++++++++++++++++ + +ZCA "global" API functions such as ``zope.component.getSiteManager``, +``zope.component.getUtility``, ``zope.component.getAdapter``, and +``zope.component.getMultiAdapter`` aren't strictly necessary. Every +component registry has a method API that offers the same +functionality; it can be used instead. For example, presuming the +``registry`` value below is a Zope Component Architecture component +registry, the folllowing bit of code is equivalent to +``zope.component.getUtility(IFoo)``: + +.. code-block:: python + + registry.getUtility(IFoo) + +The full method API is documented in the ``zope.component`` package, +but it largely mirrors the "global" API almost exactly. + +If you are willing to disuse the "global" ZCA APIs and use the method +interface of a registry instead, you need only know how to obtain the +:mod:`repoze.bfg` component registry. + +There are two ways of doing so: + +- use the :func:`repoze.bfg.threadlocal.get_current_registry`` + function within :mod:`repoze.bfg` view or model code. This will + always return the "current" :mod:`repoze.bfg` application registry. + +- use the attribute of the :term:`request` object named ``registry`` + in your :mod:`repoze.bfg` view code, eg. ``request.registry``. This + is the application registry related to the running :mod:`repoze.bfg` + application. + +See :ref:`threadlocals_chapter` for more information about +:func:`repoze.bfg.threadlocal.get_current_registry`. + +.. index:: + single: hook_zca (configurator method) + +.. _hook_zca: + +Enabling the ZCA Global API by Using ``hook_zca`` ++++++++++++++++++++++++++++++++++++++++++++++++++ + +Consider the following bit of idiomatic :mod:`repoze.bfg` startup code: + +.. code-block:: python + :linenos: + + from zope.component import getGlobalSiteManager + from repoze.bfg.configuration import Configurator + + def app(global_settings, **settings): + config = Configurator(settings=settings) + config.begin() + config.load_zcml('configure.zcml') + config.end() + return config.make_wsgi_app() + +When the ``app`` function above is run, a :term:`Configurator` is +constructed. When the configurator is created, it creates a *new* +:term:`application registry` (a ZCA component registry). A new +registry is constructed whenever the ``registry`` argument is omitted +when a :term:`Configurator` constructor is called, or when a +``registry`` argument with a value of ``None`` is passed to a +:term:`Configurator` constructor. + +During a request, the application registry created by the Configurator +is "made current". This means calls to +:func:`repoze.bfg.threadlocal.get_current_registry` in the thread +handling the request will return the component registry associated +with the application. + +As a result, application developers can use ``get_current_registry`` +to get the registry and thus get access to utilities and such, as per +:ref:`disusing_the_global_zca_api`. But they still cannot use the +global ZCA API. Without special treatment, the ZCA global APIs will +always return the global ZCA registry (the one in +``zope.component.globalregistry.base``). + +To "fix" this and make the ZCA global APIs use the "current" BFG +registry, you need to call +:meth:`repoze.bfg.configuration.Configurator.hook_zca` within your +setup code. For example: + +.. code-block:: python + :linenos: + + from zope.component import getGlobalSiteManager + from repoze.bfg.configuration import Configurator + + def app(global_settings, **settings): + config = Configurator(settings=settings) + config.hook_zca() + config.begin() + config.load_zcml('configure.zcml') + config.end() + return config.make_wsgi_app() + +We've added a line to our original startup code, line number 6, which +calls ``config.hook_zca()``. The effect of this line under the hood +is that an analogue of the following code is executed: + +.. code-block:: python + :linenos: + + from zope.component import getSiteManager + from repoze.bfg.threadlocal import get_current_registry + getSiteManager.sethook(get_current_registry) + +This causes the ZCA global API to start using the :mod:`repoze.bfg` +application registry in threads which are running a :mod:`repoze.bfg` +request. + +Calling ``hook_zca`` is usually sufficient to "fix" the problem of +being able to use the global ZCA API within a :mod:`repoze.bfg` +application. However, it also means that a Zope application that is +running in the same process may start using the :mod:`repoze.bfg` +global registry instead of the Zope global registry, effectively +inverting the original problem. In such a case, follow the steps in +the next section, :ref:`using_the_zca_global_registry`. + +.. index:: + single: get_current_registry + single: getGlobalSiteManager + single: ZCA global registry + +.. _using_the_zca_global_registry: + +Enabling the ZCA Global API by Using The ZCA Global Registry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +You can tell your :mod:`repoze.bfg` application to use the ZCA global +registry at startup time instead of constructing a new one: + +.. code-block:: python + :linenos: + + from zope.component import getGlobalSiteManager + from repoze.bfg.configuration import Configurator + + def app(global_settings, **settings): + globalreg = getGlobalSiteManager() + config = Configurator(registry=globalreg) + config.setup_registry(settings=settings) + config.hook_zca() + config.begin() + config.load_zcml('configure.zcml') + config.end() + return config.make_wsgi_app() + +Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves +the global ZCA component registry. Line 6 creates a +:term:`Configurator`, passing the global ZCA registry into its +constructor as the ``registry`` argument. Line 7 "sets up" the global +registry with BFG-specific registrations; this is code that is +normally executed when a registry is constructed rather than created, +but we must call it "by hand" when we pass an explicit registry. + +At this point, :mod:`repoze.bfg` will use the ZCA global registry +rather than creating a new application-specific registry; since by +default the ZCA global API will use this registry, things will work as +you might expect a Zope app to when you use the global ZCA API. + +.. index:: + single: Zope ZCML directives + single: getGlobalSiteManager + single: getSiteManager + +Using Broken ZCML Directives +---------------------------- + +Some :term:`Zope` and third-party :term:`ZCML` directives use the +``zope.component.getGlobalSiteManager`` API to get "the registry" when +they should actually be calling ``zope.component.getSiteManager``. + +``zope.component.getSiteManager`` can be overridden by +:mod:`repoze.bfg` via +:meth:`repoze.bfg.configuration.Configurator.hook_zca`, while +``zope.component.getGlobalSiteManager`` cannot. Directives that use +``zope.component.getGlobalSiteManager`` are effectively broken; no +ZCML directive should be using this function to find a registry to +populate. + +You cannot use ZCML directives which use +``zope.component.getGlobalSiteManager`` within a :mod:`repoze.bfg` +application without passing the ZCA global registry to the +:term:`Configurator` constructor at application startup, as per +:ref:`using_the_zca_global_registry`. + +One alternative exists: fix the ZCML directive to use +``getSiteManager`` rather than ``getGlobalSiteManager``. If a +directive disuses ``getGlobalSiteManager``, the ``hook_zca`` method of +using a component registry as documented in :ref:`hook_zca` will begin +to work, allowing you to make use of the ZCML directive without +also using the ZCA global registry. + diff --git a/docs/zcml/adapter.rst b/docs/zcml/adapter.rst index 48ed49f6c..83cce0c39 100644 --- a/docs/zcml/adapter.rst +++ b/docs/zcml/adapter.rst @@ -9,21 +9,17 @@ Attributes ~~~~~~~~~~ ``factory`` - The adapter factory (often a class). ``provides`` - The :term:`interface` that an adapter instance resulting from a lookup will provide. ``for`` - Interfaces or classes to be adapted, separated by spaces, e.g. ``interfaces.IFoo interfaces.IBar``. ``name`` - The adapter name. Example diff --git a/docs/zcml/authtktauthenticationpolicy.rst b/docs/zcml/authtktauthenticationpolicy.rst index de1bcdcd6..e779fc9a8 100644 --- a/docs/zcml/authtktauthenticationpolicy.rst +++ b/docs/zcml/authtktauthenticationpolicy.rst @@ -11,12 +11,10 @@ Attributes ~~~~~~~~~~ ``secret`` - The ``secret`` is a string that will be used to encrypt the data stored by the cookie. It is required and has no default. ``callback`` - The ``callback`` is a Python dotted name to a function passed the string representing the userid stored in the cookie and the request as positional arguments. The callback is expected to @@ -26,18 +24,15 @@ Attributes exist with no groups. It defaults to ``None``. ``cookie_name`` - The ``cookie_name`` is the name used for the cookie that contains the user information. It defaults to ``repoze.bfg.auth_tkt``. ``secure`` - ``secure`` is a boolean value. If it's set to "true", the cookie will only be sent back by the browser over a secure (HTTPS) connection. It defaults to "false". ``include_ip`` - ``include_ip`` is a boolean value. If it's set to true, the requesting IP address is made part of the authentication data in the cookie; if the IP encoded in the cookie differs from the IP of @@ -45,7 +40,6 @@ Attributes defaults to "false". ``timeout`` - ``timeout`` is an integer value. It represents the maximum age in seconds which the auth_tkt ticket will be considered valid. If ``timeout`` is specified, and ``reissue_time`` is also specified, @@ -54,7 +48,6 @@ Attributes valid forever. ``reissue_time`` - ``reissue_time`` is an integer value. If ``reissue_time`` is specified, when we encounter a cookie that is older than the reissue time (in seconds), but younger that the ``timeout``, a new @@ -64,7 +57,6 @@ Attributes authentication. ``max_age`` - ``max_age`` is the maximum age of the auth_tkt *cookie*, in seconds. This differs from ``timeout`` inasmuch as ``timeout`` represents the lifetime of the ticket contained in the cookie, diff --git a/docs/zcml/configure.rst b/docs/zcml/configure.rst index 20c0ed76a..7b479b2c0 100644 --- a/docs/zcml/configure.rst +++ b/docs/zcml/configure.rst @@ -13,7 +13,6 @@ Attributes ~~~~~~~~~~ ``xmlns`` - The default XML namespace used for subdirectives. Example diff --git a/docs/zcml/forbidden.rst b/docs/zcml/forbidden.rst index 7540c28cb..bd2235ccf 100644 --- a/docs/zcml/forbidden.rst +++ b/docs/zcml/forbidden.rst @@ -13,7 +13,6 @@ Attributes ~~~~~~~~~~ ``view`` - The :term:`dotted Python name` to a :term:`view callable`. This attribute is required unless a ``renderer`` attribute also exists. If a ``renderer`` attribute exists on the directive, this attribute @@ -21,7 +20,6 @@ Attributes :ref:`views_which_use_a_renderer`). ``attr`` - The attribute of the view callable to use if ``__call__`` is not correct (has the same meaning as in the context of :ref:`view_directive`; see the description of ``attr`` @@ -30,7 +28,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``renderer`` - This is either a single string term (e.g. ``json``) or a string implying a path or :term:`resource specification` (e.g. ``templates/views.pt``) used when the view returns a @@ -41,7 +38,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``wrapper`` - The :term:`view name` (*not* an object dotted name) of another view declared elsewhere in ZCML (or via the ``@bfg_view`` decorator) which will receive the response body of this view as the diff --git a/docs/zcml/include.rst b/docs/zcml/include.rst index 5e22f584a..149ddb67a 100644 --- a/docs/zcml/include.rst +++ b/docs/zcml/include.rst @@ -13,11 +13,9 @@ Attributes ~~~~~~~~~~ ``package`` - A :term:`dotted Python name` which references a Python :term:`package`. ``filename`` - An absolute or relative filename which references a ZCML file. The ``package`` and ``filename`` attributes can be used together or diff --git a/docs/zcml/notfound.rst b/docs/zcml/notfound.rst index 76846d770..141cac6f9 100644 --- a/docs/zcml/notfound.rst +++ b/docs/zcml/notfound.rst @@ -12,7 +12,6 @@ Attributes ~~~~~~~~~~ ``view`` - The :term:`dotted Python name` to a :term:`view callable`. This attribute is required unless a ``renderer`` attribute also exists. If a ``renderer`` attribute exists on the directive, this attribute @@ -20,7 +19,6 @@ Attributes :ref:`views_which_use_a_renderer`). ``attr`` - The attribute of the view callable to use if ``__call__`` is not correct (has the same meaning as in the context of :ref:`view_directive`; see the description of ``attr`` @@ -29,7 +27,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``renderer`` - This is either a single string term (e.g. ``json``) or a string implying a path or :term:`resource specification` (e.g. ``templates/views.pt``) used when the view returns a @@ -40,7 +37,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``wrapper`` - The :term:`view name` (*not* an object dotted name) of another view declared elsewhere in ZCML (or via the ``@bfg_view`` decorator) which will receive the response body of this view as the diff --git a/docs/zcml/remoteuserauthenticationpolicy.rst b/docs/zcml/remoteuserauthenticationpolicy.rst index 61f519e4c..0435bfbdb 100644 --- a/docs/zcml/remoteuserauthenticationpolicy.rst +++ b/docs/zcml/remoteuserauthenticationpolicy.rst @@ -11,13 +11,11 @@ Attributes ~~~~~~~~~~ ``environ_key`` - The ``environ_key`` is the name that will be used to obtain the remote user value from the WSGI environment. It defaults to ``REMOTE_USER``. ``callback`` - The ``callback`` is a Python dotted name to a function passed the string representing the remote user and the request as positional arguments. The callback is expected to return None if the user diff --git a/docs/zcml/renderer.rst b/docs/zcml/renderer.rst index 1a3942ede..5eb4f03f8 100644 --- a/docs/zcml/renderer.rst +++ b/docs/zcml/renderer.rst @@ -10,12 +10,10 @@ Attributes ~~~~~~~~~~ ``factory`` - A :term:`dotted Python name` referencing a callable object that accepts a renderer name and returns a :term:`renderer` object. ``name`` - The renderer name, which is a string. Examples diff --git a/docs/zcml/repozewho1authenticatiohnpolicy.rst b/docs/zcml/repozewho1authenticatiohnpolicy.rst index a41ae08e0..62713e822 100644 --- a/docs/zcml/repozewho1authenticatiohnpolicy.rst +++ b/docs/zcml/repozewho1authenticatiohnpolicy.rst @@ -11,7 +11,6 @@ Attributes ~~~~~~~~~~ ``identifier_name`` - The ``identifier_name`` controls the name used to look up the :term:`repoze.who` "identifier" plugin within ``request.environ['repoze.who.plugins']`` which is used by this @@ -19,7 +18,6 @@ Attributes ``auth_tkt``. ``callback`` - The ``callback`` is a Python dotted name to a function passed the repoze.who identity and the request as positional arguments. The callback is expected to return None if the user represented by the diff --git a/docs/zcml/resource.rst b/docs/zcml/resource.rst index 45aa1ce53..80a5e6722 100644 --- a/docs/zcml/resource.rst +++ b/docs/zcml/resource.rst @@ -10,12 +10,10 @@ Attributes ~~~~~~~~~~ ``to_override`` - A :term:`resource specification` specifying the resource to be overridden. ``override_with`` - A :term:`resource specification` specifying the resource which is used as the override. diff --git a/docs/zcml/route.rst b/docs/zcml/route.rst index d3181bdf6..bb842819d 100644 --- a/docs/zcml/route.rst +++ b/docs/zcml/route.rst @@ -10,32 +10,27 @@ Attributes ~~~~~~~~~~ ``path`` - The path of the route e.g. ``ideas/:idea``. This attribute is required. See :ref:`route_path_pattern_syntax` for information about the syntax of route paths. ``name`` - The name of the route, e.g. ``myroute``. This attribute is required. It must be unique among all defined routes in a given configuration. ``factory`` - The :term:`dotted Python name` to a function that will generate a :mod:`repoze.bfg` context object when this route matches. e.g. ``mypackage.models.MyFactoryClass``. If this argument is not specified, a default root factory will be used. ``view`` - The :term:`dotted Python name` to a function that will be used as a view callable when this route matches. e.g. ``mypackage.views.my_view``. ``xhr`` - This value should be either ``True`` or ``False``. If this value is specified and is ``True``, the :term:`request` must possess an ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header for this @@ -46,7 +41,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``request_method`` - A string representing an HTTP method name, e.g. ``GET``, ``POST``, ``HEAD``, ``DELETE``, ``PUT``. If this argument is not specified, this route will match if the request has *any* request method. If @@ -55,7 +49,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``path_info`` - The value of this attribute represents a regular expression pattern that will be tested against the ``PATH_INFO`` WSGI environment variable. If the regex matches, this predicate will be true. If @@ -64,7 +57,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``request_param`` - This value can be any string. A view declaration with this attribute ensures that the associated route will only match when the request has a key in the ``request.params`` dictionary (an HTTP @@ -79,7 +71,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``header`` - The value of this attribute represents an HTTP header name or a header name/value pair. If the value contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` @@ -100,7 +91,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``accept`` - The value of this attribute represents a match query for one or more mimetypes in the ``Accept`` HTTP request header. If this value is specified, it must be in one of the following forms: a mimetype @@ -113,7 +103,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``custom_predicates`` - This value should be a sequence of references to custom predicate callables. Use custom predicates when no set of predefined predicates does what you need. Custom predicates can be combined @@ -129,7 +118,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.2. ``view_context`` - The :term:`dotted Python name` to a class or an interface that the :term:`context` of the view should match for the view named by the route to be used. This attribute is only useful if the ``view`` @@ -143,7 +131,6 @@ Attributes these are valid older spellings. ``view_permission`` - The permission name required to invoke the view associated with this route. e.g. ``edit``. (see :ref:`using_security_with_urldispatch` for more information about permissions). @@ -154,7 +141,6 @@ Attributes This attribute can also be spelled as ``permission``. ``view_renderer`` - This is either a single string term (e.g. ``json``) or a string implying a path or :term:`resource specification` (e.g. ``templates/views.pt``). If the renderer value is a single @@ -177,7 +163,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``view_request_type`` - A :term:`dotted Python name` to an interface representing a :term:`request type`. If this argument is not specified, any request type will be considered a match for the view associated with @@ -189,7 +174,6 @@ Attributes This attribute can also be spelled as ``request_type``. ``view_containment`` - This value should be a :term:`dotted Python name` string representing the class that a graph traversal parent object of the :term:`context` must be an instance of (or :term:`interface` that a @@ -204,7 +188,6 @@ Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``view_attr`` - The view machinery defaults to using the ``__call__`` method of the view callable (or the function itself, if the view callable is a function) to obtain a response dictionary. The ``attr`` value allows diff --git a/docs/zcml/scan.rst b/docs/zcml/scan.rst index d48cf66b4..679f035e2 100644 --- a/docs/zcml/scan.rst +++ b/docs/zcml/scan.rst @@ -11,7 +11,6 @@ Attributes ~~~~~~~~~~ ``package`` - The package to scan or the single dot (``.``), meaning the "current" package (the package in which the ZCML file lives). diff --git a/docs/zcml/static.rst b/docs/zcml/static.rst index 23cd57538..1a11f222c 100644 --- a/docs/zcml/static.rst +++ b/docs/zcml/static.rst @@ -12,13 +12,11 @@ Attributes ~~~~~~~~~~ ``name`` - The (application-root-relative) URL prefix of the static directory. For example, to serve static files from ``/static`` in most applications, you would provide a ``name`` of ``static``. ``path`` - A path to a directory on disk where the static files live. This path may either be 1) absolute (e.g. ``/foo/bar/baz``) 2) Python-package-relative (e.g. (``packagename:foo/bar/baz``) or 3) @@ -26,7 +24,6 @@ Attributes contains the directive (e.g. ``foo/bar/baz``). ``cache_max_age`` - The number of seconds that the static resource can be cached, as represented in the returned response's ``Expires`` and/or ``Cache-Control`` headers, when any static file is served from this diff --git a/docs/zcml/subscriber.rst b/docs/zcml/subscriber.rst index ef56d2b1c..371ec0752 100644 --- a/docs/zcml/subscriber.rst +++ b/docs/zcml/subscriber.rst @@ -11,7 +11,6 @@ Attributes ~~~~~~~~~~ ``for`` - The class or :term:`interface` that you are subscribing the listener for, e.g. :class:`repoze.bfg.interfaces.INewRequest`. Registering a subscriber for a specific class or interface limits @@ -20,7 +19,6 @@ Attributes (implying *any* event type). ``handler`` - A :term:`dotted Python name` which references an event handler callable. The callable should accept a single argument: ``event``. The return value of the callable is ignored. diff --git a/docs/zcml/utility.rst b/docs/zcml/utility.rst index 88198eaa0..1341dfb83 100644 --- a/docs/zcml/utility.rst +++ b/docs/zcml/utility.rst @@ -9,22 +9,18 @@ Attributes ~~~~~~~~~~ ``component`` - The utility component (cannot be specified if ``factory`` is specified). ``factory`` - A factory that creates a component (cannot be specified if ``component`` is specified). ``provides`` - The :term:`interface` that an utility instance resulting from a lookup will provide. ``name`` - The utility name. Example diff --git a/docs/zcml/view.rst b/docs/zcml/view.rst index ea55352a8..d33a9a9a5 100644 --- a/docs/zcml/view.rst +++ b/docs/zcml/view.rst @@ -27,7 +27,6 @@ Non-Predicate Attributes ######################## ``view`` - The :term:`dotted Python name` to a :term:`view callable`. This attribute is required unless a ``renderer`` attribute also exists. If a ``renderer`` attribute exists on the directive, this attribute @@ -35,13 +34,11 @@ Non-Predicate Attributes :ref:`views_which_use_a_renderer`). ``permission`` - The name of a *permission* that the user must possess in order to call the view. See :ref:`view_security_section` for more information about view security and permissions. ``attr`` - The view machinery defaults to using the ``__call__`` method of the view callable (or the function itself, if the view callable is a function) to obtain a response dictionary. The ``attr`` value @@ -55,7 +52,6 @@ Non-Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``renderer`` - This is either a single string term (e.g. ``json``) or a string implying a path or :term:`resource specification` (e.g. ``templates/views.pt``). If the renderer value is a single @@ -90,7 +86,6 @@ Non-Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``wrapper`` - The :term:`view name` (*not* an object dotted name) of another view declared elsewhere in ZCML (or via the ``@bfg_view`` decorator) which will receive the response body of this view as the @@ -113,12 +108,10 @@ Predicate Attributes #################### ``name`` - The *view name*. Read the :ref:`traversal_chapter` to understand the concept of a view name. ``context`` - A :term:`dotted Python name` representing the Python class that the :term:`context` must be an instance of, *or* the :term:`interface` that the :term:`context` must provide in order for this view to be @@ -129,7 +122,6 @@ Predicate Attributes spelling). ``route_name`` - *This attribute services an advanced feature that isn't often used unless you want to perform traversal after a route has matched.* This value must match the ``name`` of a ```` declaration (see @@ -142,7 +134,6 @@ Predicate Attributes advanced feature. ``request_type`` - This value should be a :term:`dotted Python name` string representing the :term:`interface` that the :term:`request` must have in order for this view to be found and called. The presence of @@ -154,7 +145,6 @@ Predicate Attributes attribute instead for maximum forward compatibility. ``request_method`` - This value can either be one of the strings 'GET', 'POST', 'PUT', 'DELETE', or 'HEAD' representing an HTTP ``REQUEST_METHOD``. A view declaration with this attribute ensures that the view will only be @@ -164,7 +154,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``request_param`` - This value can be any string. A view declaration with this attribute ensures that the view will only be called when the request has a key in the ``request.params`` dictionary (an HTTP ``GET`` or @@ -178,7 +167,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``containment`` - This value should be a :term:`dotted Python name` string representing the class that a graph traversal parent object of the :term:`context` must be an instance of (or :term:`interface` that a @@ -190,7 +178,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``xhr`` - This value should be either ``True`` or ``False``. If this value is specified and is ``True``, the :term:`request` must possess an ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has @@ -201,7 +188,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``accept`` - The value of this attribute represents a match query for one or more mimetypes in the ``Accept`` HTTP request header. If this value is specified, it must be in one of the following forms: a mimetype @@ -213,7 +199,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``header`` - The value of this attribute represents an HTTP header name or a header name/value pair. If the value contains a ``:`` (colon), it will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*`` @@ -233,7 +218,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``path_info`` - The value of this attribute represents a regular expression pattern that will be tested against the ``PATH_INFO`` WSGI environment variable. If the regex matches, this predicate will be true. @@ -241,7 +225,6 @@ Predicate Attributes .. note:: This feature is new as of :mod:`repoze.bfg` 1.1. ``custom_predicates`` - This value should be a sequence of references to custom predicate callables (e.g. ``dotted.name.one dotted.name.two``, if used in ZCML; a :term:`dotted Python name` to each callable separated by a diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py index f9c70e02d..08fc0da0a 100644 --- a/repoze/bfg/configuration.py +++ b/repoze/bfg/configuration.py @@ -261,6 +261,19 @@ class Configurator(object): self._set_authentication_policy(authentication) self._set_authorization_policy(authorization) + def _fix_registry(self): + """ Fix up a ZCA component registry that is not a + repoze.bfg.registry.Registry by adding analogues of + ``has_listeners`` and ``notify`` through monkey-patching.""" + + if not hasattr(self.registry, 'notify'): + def notify(*events): + [ _ for _ in self.registry.subscribers(events, None) ] + self.registry.notify = notify + + if not hasattr(self.registry, 'has_listeners'): + self.registry.has_listeners = True + # API def setup_registry(self, settings=None, root_factory=None, @@ -283,6 +296,7 @@ class Configurator(object): security policies, renderers, and a debug logger using the configurator's current registry, as per the descriptions in the Configurator constructor.""" + self._fix_registry() self._set_settings(settings) self._set_root_factory(root_factory) if debug_logger is None: diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py index ba306f26b..db960e2e9 100644 --- a/repoze/bfg/tests/test_configuration.py +++ b/repoze/bfg/tests/test_configuration.py @@ -173,6 +173,20 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(config.registry.getUtility(IRendererFactory, 'yeah'), renderer) + def test_setup_registry_fixed(self): + class DummyRegistry(object): + def subscribers(self, events, name): + self.events = events + return events + def registerUtility(self, impl, iface, name=None, info=None): + pass + reg = DummyRegistry() + config = self._makeOne(reg) + config.setup_registry() + self.assertEqual(reg.has_listeners, True) + self.assertEqual(reg.notify(1), None) + self.assertEqual(reg.events, (1,)) + def test_setup_registry_custom_settings(self): from repoze.bfg.registry import Registry from repoze.bfg.interfaces import ISettings -- cgit v1.2.3