summaryrefslogtreecommitdiff
path: root/docs/hooks.rst
blob: 382e69bf7141a1cc17ae2d8521a2be3160dd0232 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
==========================================================
 ``zope.component.hooks``: The current component registry
==========================================================

.. currentmodule:: zope.component.hooks

There can be any number of component registries in an application. One of them
is the global component registry, and there is also the concept of a currently
used component registry. Component registries other than the global one are
associated with objects called sites. The :mod:`zope.component.hooks` module
provides an API to set and access the current site as well as manipulate the
adapter hook associated with it.

.. autofunction:: getSite

As long as we haven't set a site, none is being considered current:

.. doctest::

   >>> from zope.component.hooks import getSite
   >>> print(getSite())
   None

We can also ask for the current component registry (aka site manager
historically); it will return the global one if no current site is set:

.. autofunction:: getSiteManager

.. doctest::

   >>> from zope.component.hooks import getSiteManager
   >>> getSiteManager()
   <BaseGlobalComponents base>

Let's set a site now. A site has to be an object that provides the
``getSiteManager`` method, which is specified by
`zope.component.interfaces.IPossibleSite`:

.. autofunction:: setSite

.. doctest::

   >>> from zope.interface.registry import Components
   >>> class Site(object):
   ...     def __init__(self):
   ...         self.registry = Components('components')
   ...     def getSiteManager(self):
   ...         return self.registry

   >>> from zope.component.hooks import setSite
   >>> site1 = Site()
   >>> setSite(site1)

After this, the newly set site is considered the currently active one:

.. doctest::

   >>> getSite() is site1
   True
   >>> getSiteManager() is site1.registry
   True

If we set another site, that one will be considered current:

.. doctest::

   >>> site2 = Site()
   >>> site2.registry is not site1.registry
   True
   >>> setSite(site2)

   >>> getSite() is site2
   True
   >>> getSiteManager() is site2.registry
   True

However, the default `zope.component.getSiteManager` function isn't
yet aware of this:

.. doctest::

   >>> from zope.component import getSiteManager as global_getSiteManager
   >>> global_getSiteManager()
   <BaseGlobalComponents base>

To integrate that with the notion of the current site, we need to call ``setHooks``:

.. autofunction:: setHooks

.. doctest::

   >>> from zope.component.hooks import setHooks
   >>> setHooks()
   >>> getSiteManager() is site2.registry
   True
   >>> global_getSiteManager() is site2.registry
   True

This can be reversed using ``resetHooks``:

.. autofunction:: resetHooks

.. doctest::

   >>> from zope.component.hooks import resetHooks
   >>> resetHooks()
   >>> global_getSiteManager()
   <BaseGlobalComponents base>

Finally we can unset the site and the global component registry is used again:

.. doctest::

   >>> setSite()
   >>> print(getSite())
   None
   >>> getSiteManager()
   <BaseGlobalComponents base>


Context manager
===============

There also is a context manager for setting the site, which is especially
useful when writing tests:

.. autofunction:: site

.. doctest::

   >>> import zope.component.hooks
   >>> print(getSite())
   None
   >>> with zope.component.hooks.site(site2):
   ...     getSite() is site2
   True
   >>> print(getSite())
   None

The site is properly restored even if the body of the with statement
raises an exception:

.. doctest::

   >>> print(getSite())
   None
   >>> with zope.component.hooks.site(site2):
   ...    getSite() is site2
   ...    raise ValueError('An error in the body')
   Traceback (most recent call last):
      ...
   ValueError: An error in the body
   >>> print(getSite())
   None