1 .. _zca: |
1 .. _zca: |
2 |
2 |
3 Zope Component Architecture with PyAMS |
3 Zope Component Architecture with PyAMS |
4 ====================================== |
4 ++++++++++++++++++++++++++++++++++++++ |
5 |
5 |
6 The **Zope Component Architecture** (aka **ZCA**) is used by the Pyramid framework "under the hood" to handle interfaces, |
6 The **Zope Component Architecture** (aka **ZCA**) is used by the Pyramid framework "under the hood" to handle interfaces, |
7 adapters and utilities. You don't **have to** use it in your own applications. But you can. |
7 adapters and utilities. You don't **have to** use it in your own applications. But you can. |
8 |
8 |
9 The ZCA is mainly adding elements like **interfaces**, **adapters** and **utilities** to the Python language. It |
9 The ZCA is mainly adding elements like **interfaces**, **adapters** and **utilities** to the Python language. It |
10 allows you to write a framework or an application by using **components** which can be extended easily. |
10 allows you to write a framework or an application by using **components** which can be extended easily. |
11 |
11 |
|
12 Interfaces |
|
13 Interfaces are objects that specify (document) the external behavior |
|
14 of objects that "provide" them. An interface specifies behavior through, a documentation in a doc string, |
|
15 attribute definitions and conditions of attribute values. |
|
16 |
|
17 Components |
|
18 Components are objects that are associated with interfaces. |
|
19 |
|
20 Utilities |
|
21 Utilities are just components that provide an interface and that are looked up by an interface and a name |
|
22 |
|
23 Adapters |
|
24 Adapters are components that are computed from other components to adapt them to some interface. |
|
25 Because they are computed from other objects, they are provided as factories, usually classes. |
|
26 |
|
27 |
12 You will find several useful resources about ZCA concepts on the internet. |
28 You will find several useful resources about ZCA concepts on the internet. |
13 |
|
14 |
29 |
15 .. seealso:: |
30 .. seealso:: |
16 Zope Documentations: |
31 Zope Documentations: |
17 - `Components and Interfaces <http://zope.readthedocs.io/en/latest/zdgbook/ComponentsAndInterfaces.html>`_ |
32 - `Components and Interfaces <http://zope.readthedocs.io/en/latest/zdgbook/ComponentsAndInterfaces.html>`_ |
18 - `Zope component <http://zopecomponent.readthedocs.io/en/latest/narr.html>`_ |
33 - `Zope component <http://zopecomponent.readthedocs.io/en/latest/narr.html>`_ |
19 - `Zope interface <https://docs.zope.org/zope.interface/README.html>`_ |
34 - `Zope interface <https://docs.zope.org/zope.interface/README.html>`_ |
20 |
35 |
|
36 |
|
37 Utilities |
|
38 --------- |
21 |
39 |
22 Local utilities |
40 Local utilities |
23 --------------- |
41 ''''''''''''''' |
24 |
42 |
25 In ZCA, a **utility** is a **registered** component which provides an **interface**. This interface is the |
43 In ZCA, a **utility** is a **registered** component which provides an **interface**. This interface is the |
26 **contract** which defines features (list of attributes and methods) provided by the component which implements it. |
44 **contract** which defines features (list of attributes and methods) provided by the component which implements it. |
27 |
45 |
28 When a Pyramid application starts, a **global registry** is created to register a whole set of utilities and |
46 When a Pyramid application starts, a **global registry** is created to register a whole set of utilities and |
29 adapters; this registration can be done via ZCML directives or via native Python code. |
47 adapters; this registration can be done via ZCML directives or via native Python code. |
30 In addition, PyAMS allows you to define **local utilities**, which are stored and registered in the ZODB via a **site |
48 In addition, PyAMS allows you to define **local utilities**, which are stored and registered in the ZODB via a |
31 manager**. |
49 **site manager**. |
32 |
|
33 |
|
34 Defining site root |
|
35 ------------------ |
|
36 |
|
37 One of PyAMS pre-requisites is to use the ZODB, at least to store the site root application, it's configuration and a |
|
38 set of local utilities. :ref:`site` describes application startup and **local site manager** initialization process. |
|
39 |
|
40 This site can be used to store **local utilities** whose configuration, which is easily available to site |
|
41 administrators through management interface, is stored in the ZODB. |
|
42 |
|
43 |
|
44 Registering global utilities |
|
45 ---------------------------- |
|
46 |
|
47 **Global utilities** are components providing an interface which are registered in the global registry. |
|
48 PyAMS_utils package provides custom annotations to register global utilities without using ZCML. For example, a skin |
|
49 is nothing more than a simple utility providing the *ISkin* interface: |
|
50 |
|
51 .. code-block:: python |
|
52 |
|
53 from pyams_default_theme.layer import IPyAMSDefaultLayer |
|
54 from pyams_skin.interfaces import ISkin |
|
55 from pyams_utils.registry import utility_config |
|
56 |
|
57 @utility_config(name='PyAMS default skin', provides=ISkin) |
|
58 class PyAMSDefaultSkin(object): |
|
59 """PyAMS default skin""" |
|
60 |
|
61 label = _("PyAMS default skin") |
|
62 layer = IPyAMSDefaultLayer |
|
63 |
|
64 This annotation registers a utility, named *PyAMS default skin*, providing the *ISkin* interface. It's the developer |
|
65 responsibility to provide all attributes and methods required by the provided interface. |
|
66 |
50 |
67 |
51 |
68 Registering local utilities |
52 Registering local utilities |
69 --------------------------- |
53 ''''''''''''''''''''''''''' |
|
54 |
|
55 |
|
56 .. tip:: |
|
57 |
|
58 :ref:`site` can be used to store **local utilities** whose configuration, which is easily |
|
59 available to site administrators through management interface, is stored in the ZODB. |
|
60 |
70 |
61 |
71 A local utility is a persistent object, registered in a *local site manager*, and providing a specific interface (if |
62 A local utility is a persistent object, registered in a *local site manager*, and providing a specific interface (if |
72 a component provides several interfaces, it can be registered several times). |
63 a component provides several interfaces, it can be registered several times). |
73 |
64 |
74 Some components can be required by a given package, and created automatically via the *pyams_upgrade* command line |
65 Some components can be required by a given package, and created automatically via the *pyams_upgrade* command line |
148 |
139 |
149 *context_selector* is a custom subscriber predicate, so that subscriber event is activated only if object concerned |
140 *context_selector* is a custom subscriber predicate, so that subscriber event is activated only if object concerned |
150 by an event is providing given interface. |
141 by an event is providing given interface. |
151 |
142 |
152 |
143 |
|
144 Registering global utilities |
|
145 '''''''''''''''''''''''''''' |
|
146 |
|
147 **Global utilities** are components providing an interface which are registered in the global registry. |
|
148 PyAMS_utils package provides custom annotations to register global utilities without using ZCML. For example, a skin |
|
149 is nothing more than a simple utility providing the *ISkin* interface: |
|
150 |
|
151 .. code-block:: python |
|
152 |
|
153 from pyams_default_theme.layer import IPyAMSDefaultLayer |
|
154 from pyams_skin.interfaces import ISkin |
|
155 from pyams_utils.registry import utility_config |
|
156 |
|
157 @utility_config(name='PyAMS default skin', provides=ISkin) |
|
158 class PyAMSDefaultSkin(object): |
|
159 """PyAMS default skin""" |
|
160 |
|
161 label = _("PyAMS default skin") |
|
162 layer = IPyAMSDefaultLayer |
|
163 |
|
164 This annotation registers a utility, named *PyAMS default skin*, providing the *ISkin* interface. It's the developer |
|
165 responsibility to provide all attributes and methods required by the provided interface. |
|
166 |
|
167 |
153 Looking for utilities |
168 Looking for utilities |
154 --------------------- |
169 ''''''''''''''''''''' |
155 |
170 |
156 ZCA provides the *getUtility* and *queryUtility* functions to look for a utility. But these methods only applies to |
171 ZCA provides the *getUtility* and *queryUtility* functions to look for a utility. But these methods only applies to |
157 global registry. |
172 global registry. |
158 |
173 |
159 PyAMS package provides equivalent functions, which are looking for components into local registry before looking into |
174 PyAMS package provides equivalent functions, which are looking for components into local registry before looking into |
171 All ZCA utility functions have been ported to use local registry: *registered_utilities*, *query_utility*, |
186 All ZCA utility functions have been ported to use local registry: *registered_utilities*, *query_utility*, |
172 *get_utility*, *get_utilities_for*, *get_all_utilities_registered_for* functions all follow the equivalent ZCA |
187 *get_utility*, *get_utilities_for*, *get_all_utilities_registered_for* functions all follow the equivalent ZCA |
173 functions API, but are looking for utilities in the local registry before looking in the global registry. |
188 functions API, but are looking for utilities in the local registry before looking in the global registry. |
174 |
189 |
175 |
190 |
|
191 Adapters |
|
192 -------- |
|
193 |
176 Registering adapters |
194 Registering adapters |
177 -------------------- |
195 '''''''''''''''''''' |
178 |
196 |
179 An adapter is also a kind of utility. But instead of *just* providing an interface, it adapts an input object, |
197 An adapter is also a kind of utility. But instead of *just* providing an interface, it adapts an input object, |
180 providing a given interface, to provide another interface. An adapter can also be named, so that you can choose which |
198 providing a given interface, to provide another interface. An adapter can also be named, so that you can choose which |
181 adapter to use at a given time. |
199 adapter to use at a given time. |
182 |
200 |