| | |
| | | .. _zca_chapter: |
| | | |
| | | Using the Zope Component Architecture in :app:`Pyramid` |
| | | ========================================================== |
| | | ======================================================= |
| | | |
| | | Under the hood, :app:`Pyramid` uses a :term:`Zope Component |
| | | Architecture` component registry as its :term:`application registry`. |
| | | The Zope Component Architecture is referred to colloquially as the |
| | | "ZCA." |
| | | Under the hood, :app:`Pyramid` 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: |
| | | 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: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | 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. |
| | | 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 :app:`Pyramid`, it is not always the best tool with which |
| | | to build an *application* due to the opacity of the ``zope.component`` |
| | | APIs. Accordingly, :app:`Pyramid` tends to hide the presence of the |
| | | ZCA from application developers. You needn't understand the ZCA to |
| | | create a :app:`Pyramid` application; its use is effectively only a |
| | | framework implementation detail. |
| | | While the ZCA is an excellent tool with which to build a *framework* such as |
| | | :app:`Pyramid`, it is not always the best tool with which to build an |
| | | *application* due to the opacity of the ``zope.component`` APIs. Accordingly, |
| | | :app:`Pyramid` tends to hide the presence of the ZCA from application |
| | | developers. You needn't understand the ZCA to create a :app:`Pyramid` |
| | | application; its use is effectively only a framework implementation detail. |
| | | |
| | | However, developers who are already used to writing :term:`Zope` |
| | | applications often still wish to use the ZCA while building a |
| | | :app:`Pyramid` application; :app:`Pyramid` makes this possible. |
| | | However, developers who are already used to writing :term:`Zope` applications |
| | | often still wish to use the ZCA while building a :app:`Pyramid` application. |
| | | :app:`Pyramid` makes this possible. |
| | | |
| | | .. index:: |
| | | single: get_current_registry |
| | |
| | | single: getSiteManager |
| | | single: ZCA global API |
| | | |
| | | Using the ZCA Global API in a :app:`Pyramid` Application |
| | | ----------------------------------------------------------- |
| | | Using the ZCA global API in a :app:`Pyramid` application |
| | | -------------------------------------------------------- |
| | | |
| | | :term:`Zope` uses a single ZCA registry -- the "global" ZCA registry |
| | | -- for all Zope applications that run in the same Python process, |
| | | effectively making it impossible to run more than one Zope application |
| | | in a single process. |
| | | :term:`Zope` uses a single ZCA registry—the "global" ZCA registry—for all Zope |
| | | applications that 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:`PasteDeploy` "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 :app:`Pyramid` application at ``/pyramid``, both |
| | | served up using the same :term:`WSGI` server within a single Python 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:`PasteDeploy` |
| | | "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 |
| | | :app:`Pyramid` application at ``/pyramid``, 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 :app:`Pyramid` application |
| | | may be very small and consume very little memory, so it's a reasonable |
| | | goal to be able to run more than one :app:`Pyramid` application per |
| | | 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 :app:`Pyramid` application may be very small and consume |
| | | very little memory, so it's a reasonable goal to be able to run more than one |
| | | :app:`Pyramid` application per process. |
| | | |
| | | In order to make it possible to run more than one :app:`Pyramid` |
| | | application in a single process, :app:`Pyramid` defaults to using a |
| | | separate ZCA registry *per application*. |
| | | In order to make it possible to run more than one :app:`Pyramid` application in |
| | | a single process, :app:`Pyramid` 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 :app:`Pyramid` application. |
| | | Without special help, ZCA "global" APIs such as |
| | | :func:`zope.component.getUtility` and :func:`zope.component.getSiteManager` |
| | | will use the ZCA "global" registry. Therefore, these APIs |
| | | will appear to fail when used in a :app:`Pyramid` application, |
| | | because they'll be consulting the ZCA global registry rather than the |
| | | component registry associated with your :app:`Pyramid` 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 :app:`Pyramid` application. Without special help, ZCA "global" APIs |
| | | such as :func:`zope.component.getUtility` and |
| | | :func:`zope.component.getSiteManager` will use the ZCA "global" registry. |
| | | Therefore, these APIs will appear to fail when used in a :app:`Pyramid` |
| | | application, because they'll be consulting the ZCA global registry rather than |
| | | the component registry associated with your :app:`Pyramid` application. |
| | | |
| | | There are three ways to fix this: by disusing the ZCA global API |
| | | entirely, by using |
| | | :meth:`pyramid.config.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. |
| | | There are three ways to fix this: by disusing the ZCA global API entirely, by |
| | | using :meth:`pyramid.config.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 |
| | | Disusing the global ZCA API |
| | | +++++++++++++++++++++++++++ |
| | | |
| | | ZCA "global" API functions such as ``zope.component.getSiteManager``, |
| | | ``zope.component.getUtility``, :func:`zope.component.getAdapter`, and |
| | | :func:`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 following bit of code is equivalent to |
| | | ``zope.component.getUtility(IFoo)``: |
| | | 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 following 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. |
| | | 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 |
| | | :app:`Pyramid` component registry. |
| | | 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 :app:`Pyramid` |
| | | component registry. |
| | | |
| | | There are two ways of doing so: |
| | | |
| | | - use the :func:`pyramid.threadlocal.get_current_registry` |
| | | function within :app:`Pyramid` view or resource code. This will |
| | | always return the "current" :app:`Pyramid` application registry. |
| | | - use the :func:`pyramid.threadlocal.get_current_registry` function within |
| | | :app:`Pyramid` view or resource code. This will always return the "current" |
| | | :app:`Pyramid` application registry. |
| | | |
| | | - use the attribute of the :term:`request` object named ``registry`` |
| | | in your :app:`Pyramid` view code, eg. ``request.registry``. This |
| | | is the ZCA component registry related to the running |
| | | :app:`Pyramid` application. |
| | | - use the attribute of the :term:`request` object named ``registry`` in your |
| | | :app:`Pyramid` view code, e.g., ``request.registry``. This is the ZCA |
| | | component registry related to the running :app:`Pyramid` application. |
| | | |
| | | See :ref:`threadlocals_chapter` for more information about |
| | | :func:`pyramid.threadlocal.get_current_registry`. |
| | |
| | | |
| | | .. _hook_zca: |
| | | |
| | | Enabling the ZCA Global API by Using ``hook_zca`` |
| | | Enabling the ZCA global API by using ``hook_zca`` |
| | | +++++++++++++++++++++++++++++++++++++++++++++++++ |
| | | |
| | | Consider the following bit of idiomatic :app:`Pyramid` startup code: |
| | |
| | | config.include('some.other.package') |
| | | 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. |
| | | 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:`~pyramid.threadlocal.get_current_registry` in the thread |
| | | handling the request will return the component registry associated |
| | | with the application. |
| | | During a request, the application registry created by the Configurator is "made |
| | | current". This means calls to |
| | | :func:`~pyramid.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``). |
| | | 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" |
| | | :app:`Pyramid` registry, you need to call |
| | | :meth:`~pyramid.config.Configurator.hook_zca` within your setup code. |
| | | For example: |
| | | To "fix" this and make the ZCA global APIs use the "current" :app:`Pyramid` |
| | | registry, you need to call :meth:`~pyramid.config.Configurator.hook_zca` within |
| | | your setup code. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | :emphasize-lines: 5 |
| | | |
| | | from pyramid.config import Configurator |
| | | |
| | |
| | | config.include('some.other.application') |
| | | 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: |
| | | We've added a line to our original startup code, line number 5, 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 pyramid.threadlocal import get_current_registry |
| | | getSiteManager.sethook(get_current_registry) |
| | | |
| | | This causes the ZCA global API to start using the :app:`Pyramid` |
| | | application registry in threads which are running a :app:`Pyramid` |
| | | request. |
| | | This causes the ZCA global API to start using the :app:`Pyramid` application |
| | | registry in threads which are running a :app:`Pyramid` request. |
| | | |
| | | Calling ``hook_zca`` is usually sufficient to "fix" the problem of |
| | | being able to use the global ZCA API within a :app:`Pyramid` |
| | | application. However, it also means that a Zope application that is |
| | | running in the same process may start using the :app:`Pyramid` |
| | | 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`. |
| | | Calling ``hook_zca`` is usually sufficient to "fix" the problem of being able |
| | | to use the global ZCA API within a :app:`Pyramid` application. However, it |
| | | also means that a Zope application that is running in the same process may |
| | | start using the :app:`Pyramid` 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 |
| | |
| | | |
| | | .. _using_the_zca_global_registry: |
| | | |
| | | Enabling the ZCA Global API by Using The ZCA Global Registry |
| | | Enabling the ZCA global API by using the ZCA global registry |
| | | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| | | |
| | | You can tell your :app:`Pyramid` application to use the ZCA global |
| | | registry at startup time instead of constructing a new one: |
| | | You can tell your :app:`Pyramid` application to use the ZCA global registry at |
| | | startup time instead of constructing a new one: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | :emphasize-lines: 5-7 |
| | | |
| | | from zope.component import getGlobalSiteManager |
| | | from pyramid.config import Configurator |
| | |
| | | config.include('some.other.application') |
| | | 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 Pyramid-specific registrations; this is code that is |
| | | normally executed when a registry is constructed rather than created, |
| | | 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 Pyramid-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, :app:`Pyramid` 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. |
| | | |
| | | At this point, :app:`Pyramid` 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 in a Zope app |
| | | when you use the global ZCA API. |