Merge lp:~ccomb/zcadoc/book-fr into lp:~baijum/zcadoc/book

Proposed by Christophe Combelles on 2009-12-08
Status: Merged
Merged at revision: not available
Proposed branch: lp:~ccomb/zcadoc/book-fr
Merge into: lp:~baijum/zcadoc/book
Diff against target: 5672 lines (+2429/-1926)
3 files modified
TODO-fr-generator.py (+0/-178)
TODO-fr.txt (+0/-124)
izca-fr.txt (+2429/-1624)
To merge this branch: bzr merge lp:~ccomb/zcadoc/book-fr
To post a comment you must log in.
lp:~ccomb/zcadoc/book-fr updated on 2009-12-11
106. By Christophe Combelles on 2009-12-09

some fixes on the french translation

107. By Christophe Combelles on 2009-12-09

small fixes

108. By Christophe Combelles on 2009-12-11

fixes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file 'TODO-fr-generator.py'
--- TODO-fr-generator.py 2007-12-03 18:27:59 +0000
+++ TODO-fr-generator.py 1970-01-01 00:00:00 +0000
@@ -1,178 +0,0 @@
1from text_table import TextTable
2from enum import Enum
3
4TRANSLATED_STATUS = Enum("WIP", "Y", "N")
5REREADED_STATUS = Enum("WIP", "Y", "N")
6DONE_STATUS = Enum("Y", "N")
7NOTE_LEVEL = Enum("-", "1", "2", "3", "4", "5")
8
9
10heading_content = ("Chapter or section name", "TRANSLATED", "REREADED", "DONE", "NOTE")
11
12table_content = (
13 (" * Getting started", TRANSLATED_STATUS.WIP, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
14 (" o Introduction", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
15 (" o A brief history", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
16 (" o Installation", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
17 (" o Experimenting with code", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
18 (" * An example", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
19 (" o Introduction", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
20 (" o Procedural approach", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
21 (" o Object oriented approach", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
22 (" o The adapter pattern", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
23 (" * Interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
24 (" o Introduction", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
25 (" o Declaring interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
26 (" o Implementing interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
27 (" o Example revisited", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
28 (" o Marker interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
29 (" o Invariants", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
30 (" * Adapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
31 (" o Implementation", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
32 (" o Registration", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
33 (" o Querying adapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
34 (" o Retrieving adapter using interface", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
35 (" o Adapter pattern", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
36 (" * Utility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
37 (" o Introduction", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
38 (" o Simple utility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
39 (" o Named utility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
40 (" o Factory", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
41 (" * Advanced adapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
42 (" o Multi adapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
43 (" o Subscription adapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
44 (" o Handler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
45 (" * ZCA usage in Zope", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
46 (" o ZCML", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
47 (" o Overrides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
48 (" o NameChooser", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
49 (" o LocationPhysicallyLocatable", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
50 (" o DefaultSized", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
51 (" o ZopeVersionUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
52 (" * Reference", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
53 (" o Attribute", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
54 (" o Declaration", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
55 (" o Interface", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
56 (" o adapts", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
57 (" o alsoProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
58 (" o classImplements", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
59 (" o classImplementsOnly", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
60 (" o classProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
61 (" o ComponentLookupError", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
62 (" o createObject", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
63 (" o directlyProvidedBy", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
64 (" o directlyProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
65 (" o getAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
66 (" o getAdapterInContext", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
67 (" o getAdapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
68 (" o getAllUtilitiesRegisteredFor", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
69 (" o getFactoriesFor", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
70 (" o getFactoryInterfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
71 (" o getGlobalSiteManager", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
72 (" o getMultiAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
73 (" o getSiteManager", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
74 (" o getUtilitiesFor", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
75 (" o getUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
76 (" o handle", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
77 (" o implementedBy", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
78 (" o implementer", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
79 (" o implements", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
80 (" o implementsOnly", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
81 (" o moduleProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
82 (" o noLongerProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
83 (" o provideAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
84 (" o provideHandler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
85 (" o provideSubscriptionAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
86 (" o provideUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
87 (" o providedBy", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
88 (" o queryAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
89 (" o queryAdapterInContext", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
90 (" o queryMultiAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
91 (" o queryUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
92 (" o registerAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
93 (" o registeredAdapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
94 (" o registeredHandlers", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
95 (" o registeredSubscriptionAdapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
96 (" o registeredUtilities", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
97 (" o registerHandler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
98 (" o registerSubscriptionAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
99 (" o registerUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
100 (" o subscribers", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
101 (" o unregisterAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
102 (" o unregisterHandler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
103 (" o unregisterSubscriptionAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]),
104 (" o unregisterUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0])
105)
106
107column_greater_size_content = [0, 0, 0, 0, 0]
108
109#summary_value = {
110# "TRANSLATED" : { "YES" : 0, "WIP": 0 },
111# "REREADED" : { "YES" : 0 },
112# "DONE" : { "YES" : 0 }
113#}
114
115summary_value = {
116 TRANSLATED_STATUS.Y : 0,
117 TRANSLATED_STATUS.WIP : 0,
118 REREADED_STATUS.Y : 0,
119 REREADED_STATUS.WIP : 0,
120 DONE_STATUS.Y: 0
121}
122
123for row in (heading_content,) + table_content:
124 for col_index in range(0, len(row)):
125 if (len(str(row[col_index])) > column_greater_size_content[col_index]):
126 column_greater_size_content[col_index] = len(str(row[col_index]))
127
128 if (summary_value.has_key(row[col_index])):
129 summary_value[row[col_index]] = summary_value[row[col_index]] + 1
130
131ascii_table_content = TextTable(
132 *tuple([(column_greater_size_content[i], heading_content[i]) for i in range(0, 5)])
133)
134
135for row in table_content:
136 ascii_table_content.row(*(((row[0]),) + tuple([str(row[col_index]).center(column_greater_size_content[col_index]) for col_index in range(1, len(row))])))
137
138
139summary_content = (
140 ("Translated", str(str(summary_value[TRANSLATED_STATUS.Y]) + " / " + str(len(table_content)) + " (" + str((summary_value[TRANSLATED_STATUS.Y] * 100) / len(table_content)) + " %) , " + str(summary_value[TRANSLATED_STATUS.WIP]) + " in WIP")),
141 ("Rereaded", str(str(summary_value[REREADED_STATUS.Y]) + " / " + str(len(table_content)) + " (" + str((summary_value[REREADED_STATUS.Y] * 100) / len(table_content)) + " %) , " + str(summary_value[REREADED_STATUS.WIP]) + " in WIP")),
142 ("Done", str(str(summary_value[DONE_STATUS.Y]) + " / " + str(len(table_content)) + " (" + str((summary_value[DONE_STATUS.Y] * 100) / len(table_content)) + " %)"))
143)
144
145ascii_summary_content = TextTable((12), (28))
146for row in summary_content:
147 ascii_summary_content.row(*row)
148
149print(
150"""
151This file contain some informations about the growth of french
152translation.
153
154This file is generate by TODO-fr-generator.py script file.
155
156Summary
157=======
158""")
159
160
161print(ascii_summary_content.draw())
162
163print("""
164Detail table
165============
166
167Fields values :
168
169 * Translated column can be Yes, No, WIP (Work In Progress)
170 * Rereaded column can be Yes, No, WIP (Work In Progress)
171 * Done column can be Yes, No
172 * Note column can be "-" or 1 to 5, it's quality note
173
174""")
175
176print ascii_table_content.draw()
177
178
1790
=== removed file 'TODO-fr.txt'
--- TODO-fr.txt 2007-12-03 18:27:59 +0000
+++ TODO-fr.txt 1970-01-01 00:00:00 +0000
@@ -1,124 +0,0 @@
1
2This file contain some informations about the growth of french
3translation.
4
5This file is generate by TODO-fr-generator.py script file.
6
7Summary
8=======
9
10.--------------+------------------------------.
11| Translated | 4 / 92 (4 %) , 1 in WIP |
12| Rereaded | 0 / 92 (0 %) , 0 in WIP |
13| Done | 0 / 92 (0 %) |
14'--------------+------------------------------'
15
16
17Detail table
18============
19
20Fields values :
21
22 * Translated column can be Yes, No, WIP (Work In Progress)
23 * Rereaded column can be Yes, No, WIP (Work In Progress)
24 * Done column can be Yes, No
25 * Note column can be "-" or 1 to 5, it's quality note
26
27
28.---------------------------------------------+------------+----------+------+------.
29| Chapter or section name | TRANSLATED | REREADED | DONE | NOTE |
30+---------------------------------------------+------------+----------+------+------+
31| * Getting started | WIP | N | N | - |
32| o Introduction | Y | N | N | - |
33| o A brief history | Y | N | N | - |
34| o Installation | Y | N | N | - |
35| o Experimenting with code | Y | N | N | - |
36| * An example | N | N | N | - |
37| o Introduction | N | N | N | - |
38| o Procedural approach | N | N | N | - |
39| o Object oriented approach | N | N | N | - |
40| o The adapter pattern | N | N | N | - |
41| * Interfaces | N | N | N | - |
42| o Introduction | N | N | N | - |
43| o Declaring interfaces | N | N | N | - |
44| o Implementing interfaces | N | N | N | - |
45| o Example revisited | N | N | N | - |
46| o Marker interfaces | N | N | N | - |
47| o Invariants | N | N | N | - |
48| * Adapters | N | N | N | - |
49| o Implementation | N | N | N | - |
50| o Registration | N | N | N | - |
51| o Querying adapter | N | N | N | - |
52| o Retrieving adapter using interface | N | N | N | - |
53| o Adapter pattern | N | N | N | - |
54| * Utility | N | N | N | - |
55| o Introduction | N | N | N | - |
56| o Simple utility | N | N | N | - |
57| o Named utility | N | N | N | - |
58| o Factory | N | N | N | - |
59| * Advanced adapters | N | N | N | - |
60| o Multi adapter | N | N | N | - |
61| o Subscription adapter | N | N | N | - |
62| o Handler | N | N | N | - |
63| * ZCA usage in Zope | N | N | N | - |
64| o ZCML | N | N | N | - |
65| o Overrides | N | N | N | - |
66| o NameChooser | N | N | N | - |
67| o LocationPhysicallyLocatable | N | N | N | - |
68| o DefaultSized | N | N | N | - |
69| o ZopeVersionUtility | N | N | N | - |
70| * Reference | N | N | N | - |
71| o Attribute | N | N | N | - |
72| o Declaration | N | N | N | - |
73| o Interface | N | N | N | - |
74| o adapts | N | N | N | - |
75| o alsoProvides | N | N | N | - |
76| o classImplements | N | N | N | - |
77| o classImplementsOnly | N | N | N | - |
78| o classProvides | N | N | N | - |
79| o ComponentLookupError | N | N | N | - |
80| o createObject | N | N | N | - |
81| o directlyProvidedBy | N | N | N | - |
82| o directlyProvides | N | N | N | - |
83| o getAdapter | N | N | N | - |
84| o getAdapterInContext | N | N | N | - |
85| o getAdapters | N | N | N | - |
86| o getAllUtilitiesRegisteredFor | N | N | N | - |
87| o getFactoriesFor | N | N | N | - |
88| o getFactoryInterfaces | N | N | N | - |
89| o getGlobalSiteManager | N | N | N | - |
90| o getMultiAdapter | N | N | N | - |
91| o getSiteManager | N | N | N | - |
92| o getUtilitiesFor | N | N | N | - |
93| o getUtility | N | N | N | - |
94| o handle | N | N | N | - |
95| o implementedBy | N | N | N | - |
96| o implementer | N | N | N | - |
97| o implements | N | N | N | - |
98| o implementsOnly | N | N | N | - |
99| o moduleProvides | N | N | N | - |
100| o noLongerProvides | N | N | N | - |
101| o provideAdapter | N | N | N | - |
102| o provideHandler | N | N | N | - |
103| o provideSubscriptionAdapter | N | N | N | - |
104| o provideUtility | N | N | N | - |
105| o providedBy | N | N | N | - |
106| o queryAdapter | N | N | N | - |
107| o queryAdapterInContext | N | N | N | - |
108| o queryMultiAdapter | N | N | N | - |
109| o queryUtility | N | N | N | - |
110| o registerAdapter | N | N | N | - |
111| o registeredAdapters | N | N | N | - |
112| o registeredHandlers | N | N | N | - |
113| o registeredSubscriptionAdapters | N | N | N | - |
114| o registeredUtilities | N | N | N | - |
115| o registerHandler | N | N | N | - |
116| o registerSubscriptionAdapter | N | N | N | - |
117| o registerUtility | N | N | N | - |
118| o subscribers | N | N | N | - |
119| o unregisterAdapter | N | N | N | - |
120| o unregisterHandler | N | N | N | - |
121| o unregisterSubscriptionAdapter | N | N | N | - |
122| o unregisterUtility | N | N | N | - |
123'---------------------------------------------+------------+----------+------+------'
124
1250
=== modified file 'izca-fr.txt'
--- izca-fr.txt 2007-12-03 18:27:59 +0000
+++ izca-fr.txt 2009-12-11 23:53:09 +0000
@@ -1,246 +1,270 @@
1===========================1========================================================
2Zope Component Architecture2Le guide complet de l'Architecture de Composants de Zope
3===========================3========================================================
44
55:Author: Baiju M
6:Auteur: Baiju M6:Version: 0.5.8
7:Version: 0.4.17:Printed Book: `http://www.lulu.com/content/1561045
8:URL: `http://www.muthukadan.net/docs/zca.pdf8 <http://www.lulu.com/content/1561045>`_
9 <http://www.muthukadan.net/docs/zca.pdf>`_9:Online PDF: `http://www.muthukadan.net/docs/zca.pdf
10:Traducteur: Stéphane Klein <stephane@harobed.org>10 <http://www.muthukadan.net/docs/zca.pdf>`_
1111:Traducteur: Christophe Combelles <ccomb@free.fr>, Stéphane Klein <stephane@harobed.org>
12Copyright (C) 2007 Baiju M <baiju.m.mail AT gmail.com>.12
13Copyright (C) 2007,2008,2009 Baiju M <baiju.m.mail AT gmail.com>.
1314
14Chacun est autorisé à copier, distribuer et/ou modifier ce document15Chacun est autorisé à copier, distribuer et/ou modifier ce document
15suivant les termes de la "GNU Free Documentation License", version 1.216suivant les termes de la « GNU Free Documentation License », version 1.3
16ou (à votre gré) toute version ultérieur publiée par la Free Software17ou toute version ultérieure publiée par la Free Software
17Foundation.18Foundation.
1819
19Le code source présent dans ce document est soumis aux conditions de20Le code source présent dans ce document est soumis aux conditions de
20la licence Zope Public License, Version 2.1 (ZPL).21la « Zope Public License », Version 2.1 (ZPL).
2122
22LE CODE SOURCE DE CE DOCUMENT EST FOURNI "EN L'ETAT" SANS AUCUNE23THE SOURCE CODE IN THIS DOCUMENT AND THE DOCUMENT ITSELF IS PROVIDED
23GARANTIE.24"AS IS" AND ANY AND ALL EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED,
2425INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE,
25.. note::26MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS FOR A PARTICULAR
2627PURPOSE.
27 Merci à Kent Tenney (Wisconsin, USA) et Brad Allen (Dallas, USA)28
28 pour leurs suggestions.29.. sidebar:: Remerciements
2930
31 De nombreuses personnes m'ont aidé à écrire ce livre. Le brouillon initial a été
32 relu par mon collègue Brad Allen. Quand j'ai annoncé ce livre sur mon blog, j'ai
33 reçu de nombreux encouragements pour poursuivre ce travail. Kent Tenney a
34 modifié de nombreuses parties du livre et a également réécrit l'application
35 servant d'exemple. De nombreuses autres personnes m'ont envoyé des corrections
36 et des commentaires, dont Lorenzo Gil Sanchez, Michael Haubenwallner, Nando
37 Quintana, Stephane Klein, Tim Cook, Kamal Gill et Thomas Herve. Lorenzo a
38 traduit ce travail en espagnol et Stephane initié la traduction en français. Merci à
39 toutes ces personnes !
3040
31.. contents::41.. contents::
32.. .. sectnum::42.. .. sectnum::
3343
3444
35Premiers pas45Mise en route
36------------46-------------
3747
3848
39Introduction49Introduction
40~~~~~~~~~~~~50~~~~~~~~~~~~
4151
42Le développement de logiciels de grandes tailles (grande quantité de52Le développement de grands systèmes logiciels est toujours une tâche ardue
43lignes de code...) est toujours une tâche très complexe. L'expérience53L'expérience montre que l'approche orientée objet est bien appropriée à
44montre que l'utilisation d'une approche orienté objet simplifie54l'analyse, à la modélisation et à la programmation des systèmes complexes. La
45l'analyse, la modélisation et l'implémentation de programmes55conception orientée composants et la programmation basée sur des composants
46complexes. Les logiciels informatiques basés sur une architecture et56deviennent actuellement très populaires. L'approche basée composants est d'une
47une programmation oriénté composant sont de nos jours de plus en plus57grande aide pour l'écriture et la maintenance de systèmes logiciels et
48populaire. Une grande partie des langages de programmations disposent58de leurs tests unitaires. Il existe de nombreux frameworks permettant la
49de framework qui permettent ou simplifient la programmation orienté59conception basée sur des composants dans différents langages, certains étant
50composant. Certain de ces frameworks sont même compatibles avec60même indépendants du langage. On peut citer comme exemple : COM de Microsoft, ou
51plusieurs langages. Parmi ces frameworks orientés composants on trouve
52par exemple la technologie COM de Microsoft ou alors la technologie
53XPCOM de Mozilla.61XPCOM de Mozilla.
5462
55L'architecture composant de Zope (nommé ZCA : Zope Component63La **Zope Component Architecture (ZCA)** est un framework en Python qui autorise
56Architecture) est un framework qui permet d'écrire des programmes64la conception et la programmation basée sur des composants. Elle est très bien
57orientés composants en langage Python. ZCA est très bien adapté pour65adaptée au développement de grands systèmes logiciels. La ZCA n'est
58écrire des programmes Python complexes. Ce framework n'est pas limité66pas liée au serveur d'application Zope : elle peut être utilisée pour développer
59au serveur web d'application Zope, il peut être utilisé pour67n'importe quelle application en Python. Peut-être devrait-elle s'appeler la «
60l'écriture de tout type d'application Python, peut être même qu'il68Python Component Architecture ».
61devrait être nommé `Python Component Architecture` plutôt que Zope69
62Component Architecture.70Le but de la ZCA est d'utiliser des objets Python de manière efficace. Les
6371composants sont des objets réutilisables fournissant une interface que l'on peut
64ZCA dépend principalement de deux paquets:72introspecter. Une interface est un objet qui décrit comment on peut travailler
6573avec un composant particulier. Autrement dit, un composant fournit une interface
66 - ``zope.interface`` utilisé pour définir l'interface des74implémentée dans une classe ou tout autre objet appelable (*callable*). La façon
75dont le composant est implémenté n'a pas d'importance : ce qui compte est que
76celui-ci soit en accord avec l'interface. Grâce à la ZCA, vous pouvez éclater la
77complexité d'un système dans plusieurs composants travaillant ensemble. Elle
78vous aide à créer notamment deux types de composants : les « adaptateurs » et les «
79utilitaires ».
80
81Trois paquets composent la ZCA :
82
83 - ``zope.interface`` est utilisé pour la définition d'une interface.
84
85 - ``zope.event`` fournit un système simple d'événements.
86
87 - ``zope.component`` sert à la création, l'inscription et la récupération des
67 composants.88 composants.
6889
69 - ``zope.component`` pour réaliser les opérations d'enregistrements90Souvenez-vous que la ZCA ne fournit pas de composants par elle-même. Elle n'a
70 et de recherches de composants.91pour but que de créer, inscrire et récupérer des composants. Gardez également à
7192l'esprit qu'un adaptateur est une classe Python tout à fait normale (en général
72ZCA dispose de tout ce qu'il faut pour utiliser efficacement des93une fabrique) et qu'un utilitaire est un simple objet Python appelable.
73objets Python. Les composants sont des objets réutilisables disposant94
74d'interface est introspectable. Un composant est un objet disposant95Le framework ZCA est développé comme une partie du projet Zope 3. Comme
75d'une interface implémenté par une classe ou tout autre objet96mentionné plus haut, c'est un framework purement Python et il peut être utilisé
76exécutable. L'implémentation d'un composant n'est pas l'élément le97dans n'importe quelle application Python. Actuellement, Zope 3, Zope 2 et Grok
77plus important, ce qui compte avant tout c'est sa conformité avec le98l'utilisent abondamment. De nombreux autres projets l'utilisent, y compris des
78"contrat" défini par son interface. L'utilisation d'une architecture99applications non liées au web [#projects]_.
79orienté composant vous permet de diviser la compléxité d'un système à100
80travers de multiples composants coopératifs. L'architecture composant101.. [#projects] http://wiki.zope.org/zope3/ComponentArchitecture
81de Zope vous aide à créer deux types de composants de base : des
82`adapter` et des `utility`.
83
84Notez bien que l'architecture composant de Zope ne vous aide pas à
85écrire les composants eux-mêmes mais elle vous permet la création,
86l'enregistrement et la recherche de composants.Notez aussi qu'un
87composant `adapter` est une classe Python tout à fait normal (ou en
88général une fabrique d'objet (factory)) et qu'un composant `utility`
89est un objet Python exécutable standard.
90
91L'architecture composant Zope est développé comme une partie distincte
92du projet Zope 3. ZCA, comme indiqué plus tôt, est un framework
93purement Python, il peut être utilisé pour développer n'importe quel
94type d'application. Actuellement à la fois Zope 3 et Zope 2 utilisent
95très fortement ce framework mais il existe de nombreux autres projets
96et même des applications non orientés Internet qui utilisent
97l'architecture composant de Zope [#projects]_.
98102
99103
100Petit historique104Petit historique
101~~~~~~~~~~~~~~~~105~~~~~~~~~~~~~~~~
102106
103Le développement de la ZCA a débuté en 2001 dans le cadre du projet107Le développement de la ZCA a débuté en 2001 dans le cadre du projet Zope 3. Ce
104Zope 3. Ce framework est le fruit de l'expérience aquise durant le108framework est le fruit de l'expérience acquise pendant le développement
105développement d'application d'envergure en Zope 2. Jim Fulton est le109d'applications d'envergure avec Zope 2. Jim Fulton est le père de ce projet. De
106père de ce projet. De nombreuses personnes ont participé à la110nombreuses personnes ont participé à sa conception et à son implémentation,
107conception de ce framework, parmit eux on peut citer : Stephan111notamment Stephan Richter, Philipp von Weitershausen, Guido van Rossum (*aka.
108Richter, Philipp von Weitershausen, Guido van Rossum (créateur du112Python BDFL*), Tres Seaver, Phillip J Eby et Martijn Faassen.
109langage Python), Tres Seaver, Phillip J Eby et Martijn Faassen.113
110114À ses débuts, la ZCA définissait des types de composants supplémentaires : les
111Par rapport à la version actuel, les premières versions de ZCA115*services* et les *vues*, mais les développeurs ont fini par réaliser qu'un
112disposaient de quelques composants supplémentaires : les composants116*utilitaire* peut remplacer un *service* et qu'un *multi-adaptateur* peut
113`services` et les composants `views`. Ils ont été supprimé car les117remplacer une *vue*. Aujourd'hui, la ZCA comporte un nombre très réduit de types
114développeurs ont réalisé que le composant `utility` pouvait remplacer118de composants de base : les *utilitaires* (en anglais *utilities*), les *adaptateurs*
115le composant `service` et le composant `multi-adapter` pouvait119(*adapters*), les *abonnés* (*subscribers*) et les *gestionnaires* (*handlers*).
116remplacer le composant `view`. La ZCA comporte actuellement un nombre120Et encore, les *abonnés* et les *gestionnaires* sont des cas particuliers de
117réduit de type de type de composant :les `utility`, les `adapter`, les121l'*adaptateur*.
118`subscribers` et les `handler`. En fait, les composants `subscriber`122
119et `handler` sont tous deux des adaptateurs spécialisés.123Pendant le cycle de développement de Zope 3.2, Jim Fulton a proposé une
120124importante simplification de la ZCA [#proposal]_. Grâce à cette simplification,
121Pendant le cycle de développement de Zope 3.2, Jim Fulton a proposé125une nouvelle interface unique (`IComponentRegistry`) a été créée pour
122une importante simplification de l'achitecture composant de Zope126l'inscription des composants globaux et locaux.
123[#proposal]_. Parmit ces simplications, on trouve la possibilité en127
124passant par une interface unique de déclarer à la fois des composants128.. [#proposal] http://wiki.zope.org/zope3/LocalComponentManagementSimplification
125globaux et locaux.129
126130Le paquet ``zope.component`` avait une longue liste de dépendances, dont une
127Le paquet ``zope.component`` a une longue liste de dépendances, parmit131grande partie n'était pas nécessaire pour une application non liée à Zope 3.
128elles beaucoup ne sont pas nécessaire aux applications non Zope 3.132Pendant PyCon 2007, Jim Fulton a ajouté la fonctionnalité `extras_require` à
129Pendant le PyCon 2007, Jim Fulton a ajouté à setuptools une nouvelle133setuptools pour permettre d'extraire le cœur de la ZCA des fonctionnalités
130fonctionnalité nommée `extras_require`. Elle permet de séparer les
131fonctionnalités constituant le coeur de ZCA des fonctionnalités
132annexes [#extras]_.134annexes [#extras]_.
133135
134Maintenant, le projet Zope Component Architecture est un projet136.. [#extras] http://peak.telecommunity.com/DevCenter/setuptools#declaring-dependencies
135indépendant avec son propre cycle de version et son propre dépôt137
136Subversion. Toutefois, les bugs et problèmes sont encore traités à138En mars 2009, Tres Seaver a supprimé les dépendances à ``zope.deferredimport`` et
137l'intérieur du projet Zope 3 [#bugs]_, et la liste de diffusion139``zope.proxy``.
138zope-dev est utilisé pour les discussions liées aux développements140
139[#discussions]_.141Aujourd'hui, le projet ZCA est indépendant et possède son propre cycle de
142publications et son propre dépôt Subversion. Il est fourni avec le framework
143Zope. [#framework]_. Cependant, les anomalies et les bogues sont toujours pris
144en charge au travers du projet Zope 3 [#bugs]_ et la liste de diffusion
145zope-dev est utilisée pour débattre du développement [#discussions]_. Il existe
146également une liste pour les utilisateurs de Zope 3 (`zope3-users`) qui peut
147être utilisée pour toute demande au sujet de la ZCA [#z3users]_.
148
149.. [#framework] http://docs.zope.org/zopeframework/
150.. [#bugs] https://bugs.launchpad.net/zope3
151.. [#discussions] http://mail.zope.org/mailman/listinfo/zope-dev
152.. [#z3users] http://mail.zope.org/mailman/listinfo/zope3-users
140153
141154
142Installation155Installation
143~~~~~~~~~~~~156~~~~~~~~~~~~
144157
145Les paquets ``zope.component`` et ``zope.interface`` forment158Les paquets ``zope.component``, ``zope.interface`` et ``zope.event`` constituent
146ensemble le coeur de l'architecture composant de Zope. Ils fournissent159le cœur de la *Zope Component Architecture*. Ils fournissent des outils
147les fonctionnalités permettant de définir, déclarer et retrouver des160permettant de définir, inscrire et rechercher des composants. Le paquet
148composants. Le paquet ``zope.component`` et ses dépendances sont161``zope.component`` et ses dépendances sont disponibles sous forme d'*egg* dans
149disponibles sous forme de PythonEggs dans le dépôt PyPI (Python Package162l'index des paquets Python (PyPI) [#pypi]_.
150Index) [#pypi]_.163
151164.. [#pypi] Dépôt des paquets Python : http://pypi.python.org/pypi
152Vous pouvez utiliser `easy_install` [#easyinstall]_ pour installer165
153``zope.component`` et ses dépendances :166Vous pouvez installer ``zope.component`` et ses dépendances avec `easy_install`
167[#easyinstall]_ ::
154168
155 $ easy_install zope.component169 $ easy_install zope.component
156170
157Cette commande télécharge ``zope.component`` et ses depandances depuis171.. [#easyinstall] http://peak.telecommunity.com/DevCenter/EasyInstall
158le dépôt PyPI et les installe sur votre système.172
159173Cette commande télécharge ``zope.component`` et ses dépendances depuis PyPI et
160D'une manière alternative, vous pouvez télécharger manuellement le174l'installe dans votre *Python path*.
161paquet ``zope.component`` et ses dépendances depuis PyPi puis les175
162installer manuellement. L'ordre d'installation des paquets vous est176Une autre manière de procéder est de télécharger ``zope.component`` et ses
163donné ci-dessous. Sous Windows, vous aurais besoin du paquet binaire177dépendances depuis PyPI et de les installer. Il faut installer les paquets dans
164de ``zope.interface`` et ``zope.proxy``.178l'ordre donné ci-dessous. Sous Windows, vous aurez probablement besoin du paquet
179binaire de ``zope.interface``.
165180
166 1. ``zope.interface``181 1. ``zope.interface``
167 2. ``zope.proxy``182 2. ``zope.event``
168 3. ``zope.deferredimport``183 3. ``zope.component``
169 4. ``zope.event``184
170 5. ``zope.deprecation``185Pour installer ces paquet, après téléchargement, vous pouvez utiliser la
171 6. ``zope.component``186commande ``easy_install`` avec les eggs comme argument (éventuellement en
172187fournissant tous les eggs sur la même ligne de commande) ::
173Pour installer ces paquets après les avoir téléchagré, vous pouvez188
174utiliser la commande ``easy_install`` avec le nom des paquets comme189 $ easy_install /path/to/zope.interface-3.x.x.tar.gz
175argument (vous pouvez aussi donner la totalité des noms des paquets190 $ easy_install /path/to/zope.event-3.x.x.tar.gz
176en argument sur la même ligne)::191 $ easy_install /path/to/zope.component-3.x.x.tar.gz
177192
178 $ easy_install /path/to/zope.interface-3.4.x.tar.gz193Vous pouvez aussi installer ces paquets en les décompressant séparément. Par
179 $ easy_install /path/to/zope.proxy-3.4.x.tar.gz194exemple ::
180 ...195
181196 $ tar zxvf /path/to/zope.interface-3.x.x.tar.gz
182Cette méthode install le framework ZCA dans votre `system Python`, dans197 $ cd zope.interface-3.x.x
183le répertoire ``site-packages``... ce qui peut poser certain soucis.198 $ python setup.py build
184Dans un poste présent dans la liste de diffusion Zope 3, Jim Fulton199 $ python setup.py install
185est défavorable à l'utilisation du `system Python` [#systempython]_200
186(c'est à dire à l'installation dans ``site-packages``).201Ces méthodes installeront la ZCA dans votre *Python système*, dans le dossier
187202``site-packages``, ce qui peut être problématique. Dans un message sur la liste
188203de diffusion Zope 3, Jim Fulton déconseille d'utiliser le Python système
189Environement d'expérimentation204[#systempython]_. Vous pouvez utiliser ``virtualenv`` ou ``zc.buildout`` pour
190~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~205jouer avec n'importe quel paquet Python, et également pour les déploiements.
191206
192``virtualenv`` et ``zc.buildout`` sont des outils qui permettent207.. [#systempython] http://article.gmane.org/gmane.comp.web.zope.zope3/21045
193l'installation de la ZCA dans un environement isolé. L'utilisation de208
194ces outils est conseillé lors l'expérimentation de code. De plus, il209
195est bénéfique de se familiariser avec eux car ils sont très pratiques autant210Méthode pour expérimenter
196lors de la phase de développement que lors du déploiement d'applications.211~~~~~~~~~~~~~~~~~~~~~~~~~
197212
198Vous pouvez installer``virtualenv`` via ``easy_install``:: 213Il existe deux approches populaires en Python pour construire un environnement
214de travail isolé. La première est ``virtualenv`` créé par Ian Biking, la
215deuxième est ``zc.buildout`` créé par Jim Fulton. Il est même possible
216d'utiliser ces paquets ensemble. Ils vous aideront à installer
217``zope.component`` et d'autres dépendances dans un environnement de
218développement isolé. Passer un peu de temps à se familiariser avec ces outils
219vous sera bénéfique lors des développements et des déploiements.
220
221**virtualenv**
222
223Vous pouvez installer ``virtualenv`` grâce à ``easy_install`` ::
199224
200 $ easy_install virtualenv225 $ easy_install virtualenv
201226
202Vous pouvez créez ensuite un nouvel environement comme ceci::227Puis vous pouvez créer un nouvel environnement de cette façon ::
203228
204 $ virtualenv myve229 $ virtualenv --no-site-packages myve
205230
206Cette command a pour effet de créer un nouvel environement virtuel dans le231Ceci crée un nouvel environnement virtuel dans le dossier ``myve``.
207dossier ``myve``. Maintenant, à partir du dossier ``myve``, vous232Maintenant, depuis ce dossier, vous pouvez installer ``zope.component`` et ses
208pouvez installer ``zope.component`` et ses dépendances en utilisant233dépendances avec le script ``easy_install`` situé dans ``myve/bin`` ::
209l'exécutable ``easy_install`` qui se trouve dans le dossier
210``myve/bin``::
211234
212 $ cd myve235 $ cd myve
213 $ ./bin/easy_install zope.component236 $ ./bin/easy_install zope.component
214237
215Vous pouvez maintenant importer les modules ``zope.interface`` et238Ensuite vous pouvez importer ``zope.interface`` et ``zope.component`` depuis
216``zope.component`` a partir de votre nouvel interpréteur ``python``239le nouvel interprète ``python`` situé dans ``myve/bin`` ::
217qui se trouve dans le dossier ``myve/bin||::
218240
219 $ ./bin/python241 $ ./bin/python
220242
221Cette commande vous donnera une invite de commande Python que vous243Cette commande démarre un interprète Python que vous pourrez utiliser pour
222pouvez utiliser pour exécuter les codes sources de ce livre.244lancer le code de ce livre.
223245
224L'utilisation de la recette ``zc.recipe.egg`` du paquet246
225``zc.buildout`` vous permet de créer un interpréteur python avec des247**zc.buildout**
226PythonEggs spécifique. Premièrement, installez ``zc.buildout`` en248
227utilisant la commande ``easy_install`` (Vous pouvez aussi faire cela à249En combinant ``zc.buildout`` et la recette ``zc.recipe.egg``, vous pouvez créer
228l'intérieur d'un environement virtuel). Pour créer un nouveau buildout250un interprète Python ayant accès aux eggs Python spécifiés. Tout d'abord,
229pour expériement des PythonEggs, commencez par créer un nouveau251installez ``zc.buildout`` grâce à la commande ``easy_install`` (vous pouvez le
230dossier et initialisez le en utilisant la command ``buildout init``::252faire à l'intérieur de l'environnement virtuel). Pour créer un nouveau
253*buildout* servant à expérimenter des eggs Python, commencez par créer un
254dossier, puis initialisez-le grâce à la commande ``buildout init`` ::
231255
232 $ mkdir mybuildout256 $ mkdir mybuildout
233 $ cd mybuildout257 $ cd mybuildout
234 $ buildout init258 $ buildout init
235259
236Maintenant, le nouveau dossier ``mybuildout`` est un buildout. Le260De cette façon, le dossier ``mybuildout`` devient un « buildout ». Le fichier de
237fichier de configuration par défaut du buildout est `buildout.cfg`.261configuration de buildout est par défaut `buildout.cfg`. Après initialisation,
238Après l'initilisation, il a pour contenu::262il doit contenir les lignes suivantes ::
239263
240 [buildout]264 [buildout]
241 parts =265 parts =
242266
243Vous pouvez le modifier comme ceci::267Vous pouvez le modifier pour qu'il corresponde à ceci ::
244268
245 [buildout]269 [buildout]
246 parts = py270 parts = py
@@ -250,319 +274,314 @@
250 interpreter = python274 interpreter = python
251 eggs = zope.component275 eggs = zope.component
252276
253Maintenant exécutez la commande ``buildout`` disponible dans le277Si maintenant vous lancez la commande ``buildout`` disponible à l'intérieur du
254dossier ``mybuildout/bin`` sans aucun argument. Cela a pour effet de278dossier ``mybuildout/bin``, vous obtiendrez un nouvel interprète Python dans le
255créer un nouvel interpréteur à l'intérieur du dossier279dossier ``mybuildout/bin`` ::
256``mybuildout/bin``::
257280
258 $ ./bin/buildout281 $ ./bin/buildout
259 $ ./bin/python282 $ ./bin/python
260283
261Cette commande vous donnera un invite de commande Python que vous284Cette commande démarre un interprète Python que vous pourrez utiliser pour
262pourrez utiliser pour tester le code source de ce livre.285lancer le code de ce livre.
263286
264.. [#projects] http://wiki.zope.org/zope3/ComponentArchitecture287
265.. [#proposal] http://wiki.zope.org/zope3/LocalComponentManagementSimplification288Un exemple
266.. [#extras] http://peak.telecommunity.com/DevCenter/setuptools#declaring-dependencies
267.. [#bugs] https://bugs.launchpad.net/zope3
268.. [#discussions] http://mail.zope.org/mailman/listinfo/zope-dev
269.. [#pypi] Repository of Python packages: http://pypi.python.org/pypi
270.. [#easyinstall] http://peak.telecommunity.com/DevCenter/EasyInstall
271.. [#systempython] http://article.gmane.org/gmane.comp.web.zope.zope3/21045
272
273
274An example
275----------289----------
276290
277291
278Introduction292Introduction
279~~~~~~~~~~~~293~~~~~~~~~~~~
280294
281Consider a business application for registering guests staying in a295Imaginez une application servant à enregistrer les clients d'un hôtel. En
282hotel. Python can implement this in a number of ways. We will start296Python, il est possible de faire ceci de différentes manières. Nous allons
283with a brief look at a procedural implementation, and then move to a297commencer par étudier rapidement la méthode procédurale, puis nous diriger vers
284basic object oriented approach. As we examine the object oriented298une approche basique orientée objet. En examinant l'approche orientée objet,
285approach, we will see how we can benefit from the classic design299nous verrons comment nous pouvons bénéficier des motifs de conception
286patterns, `adapter` and `interface`. This will bring us into the300`adaptateur` et `interface`. Cela nous fera entrer dans le monde de la Zope
287world of the Zope Component Architecture.301Component Architecture.
288302
289303
290Procedural approach304Approche procédurale
291~~~~~~~~~~~~~~~~~~~305~~~~~~~~~~~~~~~~~~~~
292306
293In any business application, data storage is very critical. For307Dans toute application professionnelle, le stockage des données est un point
294simplicity, this example use a Python dictionary as the storage. Key308critique. Pour une question de simplicité, cet exemple utilise un simple
295of the dictionary will be the unique Id for a particular guest. And309dictionnaire Python comme méthode de stockage. Nous allons générer des
296value will be another dictionary with key as the property name::310identifiants uniques pour le dictionnaire, la valeur associée sera elle-même un
297311dictionnaire contenant les détails de l'enregistrement.
298 >>> guests_db = {} #key: unique Id, value: details in a dictionary312
299313 >>> bookings_db = {} #key: unique ID, value: details in a dictionary
300In a simplistic method, a function which accepts details as arguments314
301is enough to do the registration. You also required a supporting315Une implémentation minimaliste nécessite une fonction à laquelle on transmet les
302function to get the next Id for your data storage.316détails de l'enregistrement et une fonction annexe qui fournit les
303317identifiants uniques utilisés comme clés du dictionnaire de stockage.
304The supporting function, for getting the next Id can be implemented318
305like this::319Nous pouvons obtenir un identifiant unique de cette façon ::
306320
307 >>> def get_next_id():321 >>> def get_next_id():
308 ... db_keys = guests_db.keys()322 ... db_keys = bookings_db.keys()
309 ... if db_keys == []:323 ... if db_keys == []:
310 ... next_id = 1324 ... next_id = 1
311 ... else:325 ... else:
312 ... next_id = max(db_keys) + 1326 ... next_id = max(db_keys) + 1
313 ... return next_id327 ... return next_id
314328
315As you can see, the `get_next_id` function implementation is very329Comme vous pouvez voir, l'implémentation de la fonction `get_next_id` est très
316simple. Well, this is not the ideal way, but it is sufficient to330simple. La fonction récupère une liste de clés et vérifie si la liste est vide.
317explain concepts. The function first get all keys of storage as list331Si c'est le cas, nous savons que nous en sommes au premier enregistrement et
318and check whether it is empty or not. If the list is empty, so no332nous renvoyons `1`. Sinon, nous ajoutons `1` à la valeur maximale de la liste et
319item is stored, it return `1` as the next Id. And if the list is not333nous renvoyons la nouvelle valeur en résultant.
320empty, the next Id is calculated by adding `1` to the maximum value of334
321list.335Ensuite, pour créer des enregistrements dans le dictionnaire bookings_db, nous
322336utilisons la fonction suivante ::
323The function to register guest can get next unique Id using337
324`get_next_id` function, then assign the details of guest using a338 >>> def book_room(name, place):
325dictionary. Here is the function to get details and store in the
326database::
327
328 >>> def register_guest(name, place):
329 ... next_id = get_next_id()339 ... next_id = get_next_id()
330 ... guests_db[next_id] = {340 ... bookings_db[next_id] = {
331 ... 'name': name,341 ... 'name': name,
332 ... 'place': place342 ... 'room': place
333 ... }343 ... }
334344
335We will end our discussion of the procedural approach here.345Une application de gestion des enregistrements d'hôtel a besoin de données
336It will be much easier to add required features such as data346supplémentaires :
337persistence, design flexibility, and code testability using objects.347
338348 - les numéros de téléphone
339349 - les options des chambres
340Object oriented approach350 - les méthodes de paiement
341~~~~~~~~~~~~~~~~~~~~~~~~351 - ...
342352
343.. ??? should this paragraph talk about "creating an object for353Et de code pour gérer les données :
344 handling registration" or "creating a class to handle registration"?354
345355 - annuler une réservation
346In object oriented methodology, you can think of a registrar object356 - Modifier une réservation
347handling the registration. There are many advantages for creating an357 - payer une chambre
348object for handling registration. Most importantly, the abstraction358 - stocker les données
349provided by the registrar object makes the code easier to understand.359 - assurer la sécurité des données
350It offers a way to group related functionality, and can be extended360 - ...
351via inheritance. As features are added, such as canceling and updating361
352registration, the registrar object can grow to provide them, or362Si nous devions continuer l'exemple procédural, il faudrait créer plusieurs
353delegate them to another object.363fonctions, en renvoyant les données de l'une à l'autre. Au fur à mesure que les
354364fonctionnalités seraient ajoutées, le code deviendrait de plus en plus difficile
355Lets look at the implementation details of a registrar object365à maintenir et les bogues deviendraient difficiles à trouver et à corriger.
356implemented as a class::366
357367Nous n'irons pas plus loin dans l'approche procédurale. Il sera beaucoup plus
358 >>> class guestRegistrar(object):368facile d'assurer la persistance des données, la flexibilité de la conception et
369l'écriture de tests unitaires en utilisant des objets.
370
371
372Approche orientée objet
373~~~~~~~~~~~~~~~~~~~~~~~
374
375Notre discussion sur la conception orientée objet nous amène à la notion de
376« classe » qui sert à encapsuler les données et le code qui les gère.
377
378Notre classe principale sera « FrontDesk ». Le FrontDesk et d'autres classes
379auxquelles il délèguera du traitement, sauront comment gérer les données de
380l'hôtel. Nous allons créer des instances de FrontDesk pour appliquer cette
381connaissance au métier de la gestion d'hôtel.
382
383L'expérience a montré qu'en consolidant le code et les contraintes sur les
384données via des objets, on aboutit à un code qui est plus facile à comprendre, à
385tester et à modifier.
386
387Observons les détails d'implémentation de la classe FrontDesk ::
388
389 >>> class FrontDesk(object):
359 ...390 ...
360 ... def register(self, name, place):391 ... def book_room(self, name, place):
361 ... next_id = get_next_id()392 ... next_id = get_next_id()
362 ... guests_db[next_id] = {393 ... bookings_db[next_id] = {
363 ... 'name': name,394 ... 'name': name,
364 ... 'place': place395 ... 'place': place
365 ... }396 ... }
366397
367In this implementation, the registrar object (an instance of398Dans cette implémentation, l'objet `frontdesk` (une instance de la classe
368`GuestRegistrar` class) is handling the registration. With this399FrontDesk) est capable de prendre en charge les réservations. Nous pouvons
369design, a particular registrar object can perform multiple400l'utiliser de la façon suivante ::
370registrations.401
371402 >>> frontdesk = FrontDesk()
372This is how you can use the current registrar implementation::403 >>> frontdesk.book_room("Jack", "Bangalore")
373404
374 >>> registrar = GuestRegistrar()405Dans tout projet, on est confronté à des changements de besoins. Dans notre cas,
375 >>> registrar.register("Jack", "Bangalore")406la direction a décidé que chaque client devait fournit un numéro de téléphone,
376407donc nous devons changer le code.
377Requirement changes are unavoidable in any real world project.408
378Consider this case, after some time, a new requirement is arising: the409Nous pouvons satisfaire ce nouveau besoin en ajoutant un argument à la méthode
379guests also required to provide phone number to admit them. You will410`book_room` qui sera ajouté au dictionnaire des valeurs ::
380be required to change the implementation of registrar object to411
381support it.412 >>> class FrontDesk(object):
382
383You can achieve this requirement by adding one argument to `registrar`
384method and use that argument in the dictionary of values. Here is the
385new implementation for this requirement::
386
387 >>> class GuestRegistrar(object):
388 ...413 ...
389 ... def register(self, name, place, phone):414 ... def book_room(self, name, place, phone):
390 ... next_id = get_next_id()415 ... next_id = get_next_id()
391 ... guests_db[next_id] = {416 ... bookings_db[next_id] = {
392 ... 'name': name,417 ... 'name': name,
393 ... 'place': place,418 ... 'place': place,
394 ... 'phone': phone419 ... 'phone': phone
395 ... }420 ... }
396421
397Other than migrating the data to new schema, now you have to change422En plus de devoir migrer les données vers le nouveau schéma, nous devons changer
398the usage of `GuestRegistrar` in all places. If you can abstract the423tous les appels à la classe ``FrontDesk``. Si nous incorporons les coordonnées
399details of guest into an object and use it for registration, the code424de chaque client dans un objet et que nous utilisons cet objet pour les
400changes can be minimized. If you follow this design, you have to pass425réservations, les modifications de code pourront être minimisées. Nous pouvons
401that guest object instead of more arguments to the function. The new426maintenant changer les détails de l'objet client sans avoir à changer les appels
402implementation with guest object will look like this::427à FrontDesk.
403428
404 >>> class GuestRegistrar(object):429Nous avons donc ::
430
431 >>> class FrontDesk(object):
405 ...432 ...
406 ... def register(self, guest):433 ... def book_room(self, guest):
407 ... next_id = get_next_id()434 ... next_id = get_next_id()
408 ... guests_db[next_id] = {435 ... bookings_db[next_id] = {
409 ... 'name': guest.name,436 ... 'name': guest.name,
410 ... 'place': guest.place,437 ... 'place': guest.place,
411 ... 'phone': guest.phone438 ... 'phone': guest.phone
412 ... }439 ... }
413440
414Well, even in this implementation you have to change code. Code441Nous devons toujours modifier le code pour répondre aux nouvelles demandes.
415change for requirement is unavoidable, your goal should be to minimize442C'est inévitable, cependant notre but est de minimiser ces changements et donc
416changes and make it maintainable.443d'améliorer la maintenabilité.
417444
418.. note::445.. note::
419446
420 You should have the courage to make any change, major or minor, at447 Lors du développement il ne faut jamais hésiter à faire des changements sans
421 any time. Immediate feedback is the only way you can get the448 craindre de casser l'application. L'avertissement nécessaire doit être
422 courage. Using automated testing, you can get the immediate449 immédiatement obtenu grâce à des tests automatisés. Avec des tests bien écrits
423 feedback and so the courage to make changes. For more details about450 (et un bon contrôle de versions), vous pouvez faire impunément des changements
424 this subject, you can read the book called `Extreme Programming451 aussi importants que vous souhaitez. Une bonne source d'informations à propos de
425 Explained` by Kent Beck.452 cette philosophie de programmation est l'ouvrage `Extreme Programming Explained`
426453 par Kent Beck.
427By introducing the guest object, you saved some typing. More than454
428that, the abstraction of guest object made the system much simpler and455En introduisant l'objet guest, vous avez économisé un peu de temps. Mais plus
429easy to understand. The better understanding leads to better456important, l'abstraction apportée par l'objet guest a rendu le système plus
430restructuring and hence maintainable code.457simple et mieux compréhensible. Par conséquent, le code est plus facile à
431458restructurer et à maintenir.
432459
433The adapter pattern460
434~~~~~~~~~~~~~~~~~~~461Le motif `adaptateur`
435462~~~~~~~~~~~~~~~~~~~~~
436In a real application, as you noted earlier, the registrar object may463
437have cancellation and/or updation functionalities. Suppose there are464Dans une vraie application, l'objet frontdesk devra gérer des fonctionnalités
438two more methods like, `cancel_registration` and465comme les annulations et les modifications. Avec la conception actuelle, nous
439`update_registration`. In the new design you will be required to pass466devons transmettre l'objet `guest` au frontdesk à chaque fois que nous appelons
440the guest object for each methods. You can solve this problem by467les méthodes `cancel_booking` et `update_booking`.
441setting guest object as an attribute of registrar object.468
442469Nous pouvons éviter ceci si nous transmettons l'objet `guest` à
443Here is the new implementation of registrar object which set guest470FrontDesk.__init__() et si nous le stockons en attribut de l'instance.
444object as an attribute::471
445472 >>> class FrontDeskNG(object):
446 >>> class GuestRegistrarNG(object):
447 ...473 ...
448 ... def __init__(self, guest):474 ... def __init__(self, guest):
449 ... self.guest = guest475 ... self.guest = guest
450 ...476 ...
451 ... def register(self):477 ... def book_room(self):
452 ... guest = self.guest478 ... guest = self.guest
453 ... next_id = get_next_id()479 ... next_id = get_next_id()
454 ... guests_db[next_id] = {480 ... bookings_db[next_id] = {
455 ... 'name': guest.name,481 ... 'name': guest.name,
456 ... 'place': guest.place,482 ... 'place': guest.place,
457 ... 'phone': guest.phone483 ... 'phone': guest.phone
458 ... }484 ... }
459485 ...
460The solution you reached is a common design pattern called, `Adapter`.486 ... def cancel_booking(self):
461With this design, now you can add more methods, so more functionality,487 ... guest = self.guest
462if required.488 ... #code for cancellations goes here ...
463489 ...
464In this implementation, while creating the instance you have to pass490 ... def update_booking(self):
465the guest object which has the values as attributes. Now you also491 ... guest = self.guest
466required to create separate instances of `GuestRegistrarNG` for each492 ... #code for updatiion goes here ...
467guest object.493
468494
469Now just step back and think differently. Suppose you are the creator495 La solution que nous avons obtenue est un motif de conception courant appelé
470of this software and selling it to many hotel customers. Consider a496 `adaptateur`. Le `Gang of Four` [#patternbook]_ résume ainsi l'*esprit* de
471case where your different clients requires different storages. For497 l'adaptateur ::
472example, one registrar might store the details in a relational498
473database and another one might store them in Zope Object Database499 « Convertir l'interface d'une classe en une autre interface
474(ZODB). It would be better if you can replace the registrar object500 à laquelle le client s'attend. L'adaptateur permet à des
475with another one which store guest details in a different way. So, a501 classes de fonctionner ensemble même si elles ont des
476mechanism to change implementation based on some configuration would502 interfaces incompatibles. »
477be useful.503
478504En général, un objet adaptateur *contient* un objet adapté ::
479Zope component architecture provides a mechanism to replace components
480based on configuration. Using Zope component architecture you can
481register components in a registry called component registry. Later,
482retrieve component based on the configuration.
483
484The `GuestRegistrarNG` class follows, as you noted, a pattern called
485`Adapter`. The `GuestRegistrarNG` is the adapter which adapts the
486guest object (adaptee). As you can see, the adapter should contain
487the component it adapts (adaptee). This is a typical implementation
488of adapter::
489505
490 >>> class Adapter(object):506 >>> class Adapter(object):
491 ...507 ...
492 ... def __init__(self, adaptee):508 ... def __init__(self, adaptee):
493 ... self.adaptee = adaptee509 ... self.adaptee = adaptee
494510
495Now the adapter can make use adaptee (call its methods or access511Ce motif sera utile lorsqu'on sera confronté à des détails d'implémentation qui
496attributes). An adapter may adapt more than one component. Zope512dépendent de considérations telles que:
497component architecture provides a mechanism to effectively use these513
498kind of objects. So, which component should be used will become a514- modification des besoins client
499matter of configuration.515- modification des méthodes de stockage (ZODB, RDBM, XML)
500516- modification des méthodes de sortie (HTML, PDF, texte pur)
501This is a common scenario where you want to use different objects517- modification de la source utilisée (ReST, Markdown, Textile)
502doing same things, but the details may change. There are many518
503situations in programming where you want to use different519La ZCA utilise des adaptateurs et un *registre de composants* pour fournir la
504implementations for same type of objects. Here is a small list of520capacité de changer les détails d'implémentation du code via de la
505other common scenarios:521*configuration*.
506522
507 - A wiki engine with support for multiple markups (STX, reST, Plain523Comme nous pouvons le constater dans la section sur les adaptateurs de la ZCA,
508 text, etc.)524la capacité de configurer les détails d'implémentation fournit des avantages
509525intéressants :
510 - An object browser which shows size of different types of objects.526
511527- on peut interchanger les implémentations
512 - Different types of output formats for text data (PDF, HTML etc.)528- on peut ajouter de nouvelles implémentations si besoin
513529- on améliore les possibilités de réutilisation, aussi bien d'un code existant que
514 - When developing an application for multiple clients, their530 du code utilisant la ZCA.
515 requirements may change. Maintaining separate code bases of the531
516 same application for different clients is difficult. A better532Ces possibilités mènent à du code qui est flexible, évolutif et réutilisable. Il
517 approach would be to create reusable components and configure them533y a un cependant un coût : maintenir le registre de composants ajoute un niveau
518 based on client-specific requirements.534de complexité à l'application. Si une application n'a pas besoin de ces
519535avantages, la ZCA n'est pas pas nécessaire.
520All these examples points to situations where you want to make536
521applications extensible or pluggable. Do not use `adapter`537Nous sommes maintenant prêts à étudier la Zope Component Architecture, en
522components where you do not want extensibility or pluggability.538commençant avec les interfaces.
523
524Zope component architecture provides `adapter` components to solve
525these kinds of problems. In fact, `GuestRegistrarNG` is an adapter
526without explicit interface declaration. This tutorial will discuss
527adapters after introducing the concept of interfaces. Interfaces are
528one of the foundations of Zope components, so understanding the
529concept and usage of interfaces is very important.
530539
531540
532Interfaces541Interfaces
533----------542----------
534543
535
536Introduction544Introduction
537~~~~~~~~~~~~545~~~~~~~~~~~~
538546
539`Design Patterns` is a classic book in software engineering by the547Le fichier README.txt [#readmes]_ dans chemin/vers/zope/interface définit les
540`Gang of Four` [#patternbook]_. In this book they recommend: "Program548interfaces de cette manière ::
541to an interface, not an implementation". Defining formal interfaces549
542helps you better understand system. Moreover interface brings you all550 Les interfaces sont des objets qui spécifient (documentent) le
543the benefits of ZCA.551 comportement externe des objets qui les « fournissent ».
544552 Une interface spécifie un comportement au travers :
545Interface define the behavior and state of objects. An interface553
546describes how you work with the object. If you like metaphor, think554 - de documentation informelle dans une docstring
547of interface as a `contract for object`. Another metaphor which may555
548help is `blueprint for objects`. In the code, methods and attributes556 - de définitions d'attributs
549are forming the object's interface.557
550558 - d'invariants qui sont des conditions posées sur les objets
551The notion of interface is very explicit in modern languages like559 fournissant l'interface.
552Java, C#, VB.NET etc. Also these languages provide some syntax for560
553defining interfaces. Python has the notion interfaces, but it is not561L'ouvrage de référence `Design Patterns` [#patternbook]_ par le `Gang of Four`
554very explicit. To simulate a formal definition of interfaces in C++,562recommande que vous devez « programmer pour une interface, pas pour une
555`Gang of Four` used classes with virtual functions in `Design563implémentation ». Définir une interface formelle est utile dans la compréhension
556Patterns` book. In a similar fashion, Zope component architecture use564d'un système. De plus, les interfaces vous apportent tous les bénéfices de la
557``zope.interface.Interface`` inherited meta-class for defining an565ZCA.
558interface.566
559567.. [#readmes] L'arborescence du code de Zope contient de nombreux fichiers README.txt
560The base of object-orientation is the communication between objects.568 qui offrent une très bonne documentation.
561Messages are used for the communication between objects. In Python,569.. [#patternbook] http://en.wikipedia.org/wiki/Design_Patterns
562functions, methods or any other callable can be used to handle570
563messages.571Une interface spécifie les caractéristiques d'un objet, son comportement et ses
564572capacités. Elle décrit le « quoi » d'un objet. Pour apprendre le « comment »,
565For example, consider this class::573vous devez regarder l'implémentation.
574
575Les métaphores couramment utilisées pour les interfaces sont `contrat` ou
576`plan`, des termes légaux et architecturaux pour représenter un jeu de
577spécifications.
578
579Dans certains langages de programmation comme Java, C# ou VB.NET, les
580interfaces sont un aspect explicite du langage. Étant donné que Python ne
581possède pas nativement d'interfaces, la ZCA les implémente comme des
582meta-classes desquelles on hérite.
583
584Voici un exemple classique de Hello World ::
566585
567 >>> class Host(object):586 >>> class Host(object):
568 ...587 ...
@@ -571,24 +590,23 @@
571 ...590 ...
572 ... return "Good morning, %s!" % name591 ... return "Good morning, %s!" % name
573592
574In the above class, you defined a `goodmorning` method. If you call593Dans la classe ci-dessus, on a défini une méthode `goodmorning`. Si vous appelez
575the `goodmorning` method from an object created using this class, it594cette méthode depuis un objet créé en utilisant cette classe, vous obtiendrez un
576will return `Good morning, ...!` ::595`Good morning, ...!` ::
577596
578 >>> host = Host()597 >>> host = Host()
579 >>> host.goodmorning('Jack')598 >>> host.goodmorning('Jack')
580 'Good morning, Jack!'599 'Good morning, Jack!'
581600
582Here ``host`` is the actual object. The implementation details of601Ici, ``host`` est l'objet réel que votre code utilise. Si vous voulez
583this object is the class ``Host``. Now, how to find how the object602examiner les détails d'implémentation, vous devez accéder à la classe ``Host``,
584looks like, that is, what are the methods and attributes of the603soit via le code source, soit au travers d'un outil de documentation d'API
585object. For this, either you have go through the implementation604[#api]_.
586details (``Host`` class) of the object or a separate API documentation605
587[#api]_ will be required.606.. [#api] http://en.wikipedia.org/wiki/Application_programming_interface
588607
589You can use the ``zope.interface`` package to define the interface of608Maintenant nous allons commencer à utiliser les interfaces de la ZCA. Pour la
590objects. For the class given above you can specify the interface like609classe ci-dessus, vous pouvez définir l'interface comme suit ::
591this::
592610
593 >>> from zope.interface import Interface611 >>> from zope.interface import Interface
594612
@@ -597,21 +615,18 @@
597 ... def goodmorning(guest):615 ... def goodmorning(guest):
598 ... """Say good morning to guest"""616 ... """Say good morning to guest"""
599617
600As you can see, the interface is defined using Python class statement.618Vous pouvez constater que l'interface hérite de zope.interface.Interface. C'est
601We use (abuse?) Python's class statement to define interfaces. To619de cette façon (abusive ?) que la ZCA définit des interfaces. Le préfixe « I »
602make a class an interface, it must be inherited from620pour le nom de la classe est une convention utile.
603``zope.interface.Interface`` . The ``I`` prefix for interface name is621
604a convention.622
605623Déclarer des interfaces
606624~~~~~~~~~~~~~~~~~~~~~~~
607Declaring interfaces625
608~~~~~~~~~~~~~~~~~~~~626Vous avez déjà vu comment déclarer une interface en utilisant ``zope.interface``
609627dans la section précédente. Cette section va expliquer les concepts en détail.
610You have already seen how to declare an interface using628
611``zope.interface`` in previous section. This section will explain the629Prenez cette exemple d'interface ::
612concepts in detail.
613
614Consider this example interface::
615630
616 >>> from zope.interface import Interface631 >>> from zope.interface import Interface
617 >>> from zope.interface import Attribute632 >>> from zope.interface import Attribute
@@ -624,60 +639,58 @@
624 ... def goodmorning(guest):639 ... def goodmorning(guest):
625 ... """Say good morning to guest"""640 ... """Say good morning to guest"""
626641
627The interface, ``IHost`` has two attributes, ``name`` and642L'interface ``IHost`` possède deux attributs, ``name`` et ``goodmorning``.
628``goodmorning``. Recall that, at least in Python, methods are also643Rappelez-vous qu'en Python les méthodes des classes sont aussi des attributs.
629attributes of classes. The ``name`` attribute is defined using644L'attribut ``name`` est défini en utilisant la classe
630``zope.interface.Attribute`` class. When you add the attribute645``zope.interface.Attribute``. Quand vous ajoutez l'attribut ``name`` à
631``name`` to the ``IHost`` interface, you don't set an initial value.646l'interface ``IHost``, vous ne définissez pas de valeur initiale. La raison de
632The purpose of defining the attribute ``name`` here is merely to647définir l'attribut ``name`` ici est simplement d'indiquer que toute
633indicate that any implementation of this interface will feature an648implémentation de cette interface doit fournir un attribut nommé ``name``. Dans
634attribute named ``name``. In this case, you don't even say what type649ce cas, vous n'indiquez même pas de quel type doit être l'attribut ! Vous pouvez
635of attribute it has to be!. You can pass a documentation string as a650juste fournir une chaîne de documentation comme premier argument à
636first argument to ``Attribute``.651``Attribute``.
637652
638The other attribute, ``goodmorning`` is a method defined using a653L'autre attribut, ``goodmorning`` est une méthode définie en utilisant une
639function definition. Note that `self` is not required in interfaces,654fonction. Notez bien que ``self`` n'est pas nécessaire dans les interfaces, car
640because `self` is an implementation detail of class. For example, a655``self`` est un détail d'implémentation de la classe. Il est possible pour un
641module can implement this interface. If a module implement this656module d'implémenter cette interface. Si un module implémente cette interface,
642interface, there will be a ``name`` attribute and ``goodmorning``657cela signifiera qu'un attribut ``name`` et une fonction ``goodmorning`` seront
643function defined. And the ``goodmorning`` function will accept one658définis. Et la fonction ``goodmorning`` devra accepter un argument.
644argument.659
645660Nous allons maintenant voir comment effectuer le lien entre les objets, les
646Now you will see how to connect `interface-class-object`. So object661classes et les interfaces. Seuls les objets sont vivants : ce sont des instances
647is the real living thing, objects are instances of classes. And662de classes. Et les interfaces représentent la définition des objets, donc les
648interface is the actual definition of the object, so classes are just663classes ne sont qu'un détail d'implémentation. C'est pour cette raison que vous
649the implementation details. This is why you should program to an664devez programmer pour une interface, pas pour une implémentation.
650interface and not to an implementation.665
651666Nous devons nous familiariser avec deux termes supplémentaires pour comprendre
652Now you should familiarize two more terms to understand other667les autres concepts. Le premier est `fournir`, le deuxième est `implémenter`.
653concepts. First one is `provide` and the other one is `implement`.668Les objets fournissent des interfaces, tandis que les classes implémentent des
654Object provides interfaces and classes implement interfaces. In other669interfaces. Autrement dit, les objets fournissent les interfaces que les classes
655words, objects provide interfaces that their classes implement. In670implémentent. Dans l'exemple ci-dessus, l'objet ``host`` fournit l'interface
656the above example ``host`` (object) provides ``IHost`` (interface) and671``IHost`` et la classe ``Host`` implémente l'interface ``IHost``. Un objet peut
657``Host`` (class) implement ``IHost`` (interface). One object can672fournir plusieurs interfaces. Les objets peuvent également fournir directement
658provide more than one interface also one class can implement more than673des interfaces, en plus de celles implémentées par leur classe.
659one interface. Objects can also provide interfaces directly, in
660addition to what their classes implement.
661674
662.. note::675.. note::
663676
664 Classes are the implementation details of objects. In Python,677 Les classes sont les détails d'implémentation des objets. En Python, les
665 classes are callable objects, so why other callable objects can't678 classes sont des objets appelables (`callable`). Pourquoi un autre objet
666 implement an interface. Yes, it is possible. For any `callable679 appelable ne pourrait-il pas implémenter une interface ? En fait c'est possible.
667 object` you can declare that it produces objects that provide some680 Pour n'importe quel objet appelable, vous pouvez déclarer qu'il produit des
668 interfaces by saying that the `callable object` implements the681 objets qui fournissent une interface donnée, en disant simplement que cet objet
669 interfaces. The `callable objects` are generally called as682 appelable implémente l'interface. Ces objets appelables sont généralement
670 `factories`. Since functions are callable objects, a function can683 nommés des « fabriques ». Étant donné que les fonctions sont des objets
671 be an `implementer` of an interface.684 appelables, une fonction peut implémenter une interface.
672685
673686
674Implementing interfaces687Implémentation des interfaces
675~~~~~~~~~~~~~~~~~~~~~~~688~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
676689
677To declare a class implements a particular interface, use the function690Pour déclarer qu'une classe implémente une interface donnée, utilisez la
678``zope.interface.implements`` in the class statement.691fonction ``zope.interface.implements`` dans la déclaration de classe.
679692
680Consider this example, here ``Host`` implements ``IHost``::693Considérons cet exemple. Ici, ``Host`` implémente ``IHost`` ::
681694
682 >>> from zope.interface import implements695 >>> from zope.interface import implements
683696
@@ -694,55 +707,54 @@
694707
695.. note::708.. note::
696709
697 If you wonder how ``implements`` function works, refer the blog post710 Si vous vous demandez comment ``implements`` fonctionne, faites un tour sur
698 by James Henstridge711 l'article de blog de James Henstridge
699 (http://blogs.gnome.org/jamesh/2005/09/08/python-class-advisors/) .712 (http://blogs.gnome.org/jamesh/2005/09/08/python-class-advisors/) .
700 In the adapter section, you will see an ``adapts`` function, it is713 Dans la section sur les adaptateurs, vous allez voir une fonction ``adapts``,
701 also working similarly.714 celle-ci fonctionne de manière similaire.
702715
703Since ``Host`` implements ``IHost``, instances of ``Host`` provides716Comme ``Host`` implémente ``IHost``, les instances de ``Host`` fournissent
704``IHost``. There are some utility methods to introspect the717``IHost``. Il existe des méthodes permettant d'introspecter les déclarations. La
705declarations. The declaration can write outside the class also. If718déclaration peut également s'écrire en dehors de la classe. Au lieu d'écrire
706you don't write ``interface.implements(IHost)`` in the above example,719``interface.implements(IHost)`` comme dans l'exemple ci-dessus, vous pouvez
707then after defining the class statement, you can write like this::720écrire la chose suivante après la déclaration de classe ::
708721
709 >>> from zope.interface import classImplements722 >>> from zope.interface import classImplements
710 >>> classImplements(Host, IHost)723 >>> classImplements(Host, IHost)
711724
712725
713Example revisited726L'exemple revisité
714~~~~~~~~~~~~~~~~~727~~~~~~~~~~~~~~~~~~
715728
716Now, return to the example application. Here you will see how to729Maintenant retournons à notre application exemple. Voici comment définir
717define the interface of the registrar object::730l'interface de l'objet frontdesk ::
718731
719 >>> from zope.interface import Interface732 >>> from zope.interface import Interface
720733
721 >>> class IRegistrar(Interface):734 >>> class IDesk(Interface):
722 ... """A registrar will register object's details"""735 ... """A frontdesk will register object's details"""
723 ...736 ...
724 ... def register():737 ... def register():
725 ... """Register object's details"""738 ... """Register object's details"""
726 ...739 ...
727740
728Here, first you imported ``Interface`` class from ``zope.interface``741Nous avons d'abord importé la classe ``Interface`` depuis le module
729module. If you define a subclass of this ``Interface`` class, it will742``zope.interface``. Si vous définissez une sous-classe de cette classe
730be an interface from Zope component architecture point of view. An743``Interface``, ce sera considéré comme une interface, du point de vue de
731interface can be implemented, as you already noted, in a class or any744l'Architecture de Composants. Une interface peut être implémentée, comme nous
732other callable object.745l'avons vu, dans une classe ou tout autre objet appelable.
733746
734The registrar interface defined here is ``IRegistrar``. The747L'interface de frontdesk ici définie est ``IDesk``. La chaîne de documentation
735documentation string for interface gives an idea about the object. By748de l'interface donne une idée sur la nature de l'objet. En définissant une
736defining a method in the interface, you made a contract for the749méthode dans l'interface, vous avez passé un contrat avec le composant, imposant
737component, that there will be a method with same name available. For750la présence d'une méthode du même nom. Dans la déclaration de la méthode côté
738the method definition interface, the first argument should not be751interface, le premier argument ne doit pas être `self`, car une interface ne
739`self`, because an interface will never be instantiated nor will its752sera jamais instanciée et ses méthodes ne seront jamais appelées. Le rôle d'une
740methods ever be called. Instead, the interface class merely documents753interface est simplement de documenter quels arguments et quelles méthodes
741what methods and attributes should appear in any normal class that754doivent apparaître dans une classe qui l'implémente, et le paramètre `self`
742claims to implement it, and the `self` parameter is an implementation755n'est qu'un détail d'implémentation qui n'a pas besoin d'être documenté.
743detail which doesn't need to be documented.756
744757Comme vous le savez, une interface peut aussi spécifier des attributs normaux ::
745As you know, an interface can also specify normal attributes::
746758
747 >>> from zope.interface import Interface759 >>> from zope.interface import Interface
748 >>> from zope.interface import Attribute760 >>> from zope.interface import Attribute
@@ -752,26 +764,25 @@
752 ... name = Attribute("Name of guest")764 ... name = Attribute("Name of guest")
753 ... place = Attribute("Place of guest")765 ... place = Attribute("Place of guest")
754766
755In this interface, guest object has two attributes specified with767Dans cette interface, l'objet guest a deux attributs contenant de la
756documentation. An interface can also specify both attributes and768documentation. Une interface peut spécifier à la fois des méthodes et des
757methods together. An interface can be implemented in a class, module769attributs. Une interface peut être implémentée dans une classe, un module ou
758or any other objects. For example a function can dynamically create770tout autre objet. Par exemple une fonction peut créer dynamiquement le composant
759the component and return, in this case the function is an implementer771et le renvoyer, auquel cas on dit que la fonction implémente l'interface.
760for the interface.772
761773Vous savez maintenant ce qu'est une interface, comment la créer et l'utiliser.
762Now you know what is an interface and how to define and use it. In774Dans le chapitre suivant nous allons voir comment une interface peut être
763the next chapter you can see how an interface is used to define an775utilisée pour définir un composant adaptateur.
764adapter component.776
765777
766778Interfaces marqueurs
767Marker interfaces779~~~~~~~~~~~~~~~~~~~~
768~~~~~~~~~~~~~~~~~780
769781Une interface peut être utilisée pour déclarer qu'un objet appartient à un
770An interface can be used to declare that a particular object belongs782type donné. Une interface sans aucun attribut ni aucune méthode est appelée une
771to a special type. An interface without any attribute or method is783« interface marqueur ».
772called `marker interface`.784
773785Voici une `interface marqueur` ::
774Here is a `marker interface`::
775786
776 >>> from zope.interface import Interface787 >>> from zope.interface import Interface
777788
@@ -779,24 +790,25 @@
779 ... """A special guest"""790 ... """A special guest"""
780791
781792
782This interface can be used to declare an object is a special guest.793Cette interface peut être utilisée pour déclarer qu'un objet est un client
794spécial.
783795
784796
785Invariants797Invariants
786~~~~~~~~~~798~~~~~~~~~~
787799
788Sometimes you will be required to use some rule for your component800Parfois vous aurez besoin de définir des règles ou des contraintes sur les
789which involve one or more normal attributes. These kind of rule is801attributs de vos composants. Ces types de règles sont appelés des `invariants`.
790called `invariants`. You can use ``zope.interface.invariant`` for802Vous pouvez utiliser ``zope.interface.invariant`` pour définir des
791setting `invariants` for your objects in their interface.803``invariants`` sur vos objets dans leur interface.
792804
793Consider a simple example, there is a `person` object. A person805Considérons un exemple simple, avec un objet `person`. Une objet `person` a un
794object has `name`, `email` and `phone` attributes. How do you806attribut `nom`, un attribut `email` et un attribut `phone`. Comment peut-on
795implement a validation rule that says either email or phone have to807implémenter une règle de validation qui oblige à définir au choix le `phone` ou
796exist, but not necessarily both.808l'`email` mais pas forcément les deux ?
797809
798First you have to make a callable object, either a simple function or810Créez tout d'abord un objet appelable, soit une simple fonction soit une
799callable instance of a class like this::811instance appelable d'une classe de la façon suivante ::
800812
801 >>> def contacts_invariant(obj):813 >>> def contacts_invariant(obj):
802 ...814 ...
@@ -804,8 +816,8 @@
804 ... raise Exception(816 ... raise Exception(
805 ... "At least one contact info is required")817 ... "At least one contact info is required")
806818
807Then define the `person` object's interface like this. Use the819Ensuite définissez l'interface de l'objet `person` en utilisant la fonction
808``zope.interface.invariant`` function to set the invariant::820``zope.interface.invariant`` pour définir l'invariant ::
809821
810 >>> from zope.interface import Interface822 >>> from zope.interface import Interface
811 >>> from zope.interface import Attribute823 >>> from zope.interface import Attribute
@@ -819,7 +831,8 @@
819 ...831 ...
820 ... invariant(contacts_invariant)832 ... invariant(contacts_invariant)
821833
822Now use `validateInvariants` method of the interface to validate::834Maintenant, utilisez la méthode `validateInvariants` de l'interface pour
835effectuer la validation ::
823836
824 >>> from zope.interface import implements837 >>> from zope.interface import implements
825838
@@ -839,37 +852,34 @@
839 ...852 ...
840 Exception: At least one contact info is required853 Exception: At least one contact info is required
841854
842As you can see `jack` object validated without raising any855Vous constatez que l'ojet `jack` est validé sans erreur. Mais l'objet `jill` n'a
843exception. But `jill` object didn't validated the invariant856pas pu valider la contrainte de l'invariant, il a donc levé une exception.
844constraint, so it raised exception.857
845858
846.. [#patternbook] http://en.wikipedia.org/wiki/Design_Patterns859Adaptateurs
847.. [#api] http://en.wikipedia.org/wiki/Application_programming_interface860-----------
848861
849862
850Adapters863Implémentation
851--------
852
853
854Implementation
855~~~~~~~~~~~~~~864~~~~~~~~~~~~~~
856865
857This section will describe adapters in detail. Zope component866Cette section décrit les adaptateurs en détail. L'Architecture de Composants,
858architecture, as you noted, helps to effectively use Python objects.867comme vous l'avez remarqué, fournit une aide dans l'utilisation efficace des objets
859Adapter components are one of the basic components used by Zope868Python. Les composants adaptateurs sont l'un des composants basiques utilisés
860component architecture for effectively using Python objects. Adapter869par l'Architecture de Composants de Zope pour utiliser efficacement des objets
861components are Python objects, but with well defined interface.870Python. Les adaptateurs sont aussi des objets Python, mais avec une interface bien
871définie.
862872
863To declare a class is an adapter use `adapts` function defined in873Pour déclarer qu'une classe est un adaptateur, utilisez la fonction `adapts`
864``zope.component`` package. Here is a new `GuestRegistrarNG` adapter874définie dans le paquet ``zope.component``. Voici un nouvel adaptateur
865with explicit interface declaration::875`FrontDeskNG` avec une déclaration explicite d'interface ::
866876
867 >>> from zope.interface import implements877 >>> from zope.interface import implements
868 >>> from zope.component import adapts878 >>> from zope.component import adapts
869879
870 >>> class GuestRegistrarNG(object):880 >>> class FrontDeskNG(object):
871 ...881 ...
872 ... implements(IRegistrar)882 ... implements(IDesk)
873 ... adapts(IGuest)883 ... adapts(IGuest)
874 ...884 ...
875 ... def __init__(self, guest):885 ... def __init__(self, guest):
@@ -878,17 +888,16 @@
878 ... def register(self):888 ... def register(self):
879 ... guest = self.guest889 ... guest = self.guest
880 ... next_id = get_next_id()890 ... next_id = get_next_id()
881 ... guests_db[next_id] = {891 ... bookings_db[next_id] = {
882 ... 'name': guest.name,892 ... 'name': guest.name,
883 ... 'place': guest.place,893 ... 'place': guest.place,
884 ... 'phone': guest.phone894 ... 'phone': guest.phone
885 ... }895 ... }
886896
887897
888What you defined here is an `adapter` for `IRegistrar`, which adapts898Ce que nous avons défini ici est un `adaptateur` pour `IDesk`, qui s'adapte à
889`IGuest` object. The `IRegistrar` interface is implemented by899l'objet `IGuest`. L'interface `IDesk` est implémentée par la classe
890`GuestRegistrarNG` class. So, an instance of this class will provide900`FrontDeskNG`. Donc une instance de cette classe fournira l'interface `IDesk`.
891`IRegistrar` interface.
892901
893::902::
894903
@@ -901,252 +910,254 @@
901 ... self.place = place910 ... self.place = place
902911
903 >>> jack = Guest("Jack", "Bangalore")912 >>> jack = Guest("Jack", "Bangalore")
904 >>> jack_registrar = GuestRegistrarNG(jack)913 >>> jack_frontdesk = FrontDeskNG(jack)
905914
906 >>> IRegistrar.providedBy(jack_registrar)915 >>> IDesk.providedBy(jack_frontdesk)
907 True916 True
908917
909The `GuestRegistrarNG` is just one adapter you created, you can also918`FrontDeskNG` est juste un adaptateur que nous avons créé. Vous pouvez créer
910create other adapters which handles guest registration differently.919d'autres adaptateurs qui prendront en charge le bureau d'enregistrement différemment.
911920
912921
913Registration922Inscription
914~~~~~~~~~~~~923~~~~~~~~~~~
915924
916To use this adapter component, you have to register this in a925Pour utiliser ce composant adaptateur, vous devez l'inscrire dans un registre de
917component registry also known as site manager. A site manager926composants (appelé également « gestionnaire de site »). Un gestionnaire de site
918normally resides in a site. A site and site manager will be more927réside normalement à l'intérieur d'un site. Le site et le gestionnaire de site
919important when developing a Zope 3 application. For now you only928prendront leur importance lors du développement d'une application Zope 3. Pour
920required to bother about global site and global site manager ( or929l'instant vous avez juste besoin de connaître les notions de site global et de
921component registry). A global site manager will be in memory, but a930gestionnaire global de site (ou registre de composant). Un gestionnaire global
922local site manager is persistent.931de site est situé en mémoire, alors qu'un gestionnaire de site local est
923932persistant.
924To register your component, first get the global site manager::933
934Pour inscrire votre composant, commencez par récupérer le gestionnaire global de
935site ::
925936
926 >>> from zope.component import getGlobalSiteManager937 >>> from zope.component import getGlobalSiteManager
927 >>> gsm = getGlobalSiteManager()938 >>> gsm = getGlobalSiteManager()
928 >>> gsm.registerAdapter(GuestRegistrarNG,939 >>> gsm.registerAdapter(FrontDeskNG,
929 ... (IGuest,), IRegistrar, 'ng')940 ... (IGuest,), IDesk, 'ng')
930941
931To get the global site manager, you have to call942Pour récupérer le gestionnaire global de site, vous devez appeler la fonction
932``getGlobalSiteManager`` function available in ``zope.component``943``getGlobalSiteManager` disponible dans le paquet ``zope.component``.
933package. In fact, the global site manager is available as an944En fait, le gestionnaire global de site est disponible dans un attribut
934attribute (``globalSiteManager``) of ``zope.component`` package. So,945(``globalSiteManager``) du paquet ``zope.component``. Vous pouvez donc utiliser
935you can directly use ``zope.component.globalSiteManager`` attribute.946directement l'attribut ``zope.component.globalSiteManager``.
936To register the adapter in component, as you can see above, use947Pour inscrire l'adaptateur comme un composant, utilisez la méthode
937``registerAdapter`` method of component registry. The first argument948``registerAdapter`` du registre de composants. Le premier argument doit être
938should be your adapter class/factory. The second argument is a tuple949votre classe ou fabrique d'adaptateur. Le deuxième argument est un tuple d'objets
939of `adaptee` objects, i.e, the object which you are adapting. In this950adaptés, c'est à dire les objets sur lesquels vous vous adaptez. Dans cet
940example, you are adapting only `IGuest` object. The third argument is951exemple, vous vous adaptez seulement à l'objet `IGuest`. Le troisième argument
941the interface provided by the adapter component. The fourth argument952est l'interface implémentée par le composant adaptateur. Le quatrième argument
942is optional, that is the name of the particular adapter. Since you953est optionnel, il s'agit du nom de cet adaptateur particulier. Si vous donnez un
943gave a name for this adapter, this is a `named adapter`. If name is954nom à l'adaptateur, celui devient un `adaptateur nommé`. Si aucun nom n'est
944not given, it will default to an empty string ('').955donné, la valeur transmise par défaut est une chaîne vide ('').
945956
946In the above registration, you have given the adaptee interface and957Dans l'inscription ci-dessus, vous avez donné l'interface de l'objet adapté et
947interface to be provided by the adapter. Since you have already given958l'interface fournie par l'adaptateur. Comme vous avez déjà donné ces
948these details in adapter implementation, it is not required to specify959informations dans l'implémentation de l'adaptateur, il est inutile de les
949again. In fact, you could have done the registration like this::960spécifier à nouveau. En réalité, vous pouvez effectuer l'inscription de la
950961manière suivante ::
951 >>> gsm.registerAdapter(GuestRegistrarNG, name='ng')962
952963 >>> gsm.registerAdapter(FrontDeskNG, name='ng')
953There are some old API to do the registration, which you should avoid.964
954The old API functions starts with `provide`, eg: ``provideAdapter``,965Pour effectuer l'inscription, il existe d'anciennes API que vous devriez
955``provideUtility`` etc. While developing a Zope 3 application you can966éviter. Les fonctions de l'ancienne API commencent par `provide`, par exemple :
956use Zope configuration markup language (ZCML) for registration of967``provideAdapter``, ``provideUtility``, etc. Si vous développez une application
957components. In Zope 3, local components (persistent components) can968Zope 3, vous pouvez utiliser le langage ZCML (Zope Configuration Markup
958be registered from Zope Management Interface (ZMI) or you can do it969Language) pour effectuer les inscriptions des composants. Avec Zope 3, les
959programmatically also.970composants locaux (persistants) peut être inscrits depuis la ZMI (Zope
960971Management Interface), ou bien par programmation.
961You registered `GuestRegistrarNG` with a name `ng`. Similarly you can972
962register other adapters with different names. If a component is973Vous avez inscrit `FrontDeskNG` avec le nom `ng`. De la même manière, vous
963registered without name, it will default to an empty string.974pouvez inscrire d'autre adaptateurs avec différents noms. Si un composant est
975inscrit sans nom, son nom sera la chaîne vide par défaut.
964976
965.. note::977.. note::
966978
967 Local components are persistent components but global components are979 Les composants locaux sont persistants mais les composants globaux sont en
968 in memory. Global components will be registered based on the980 mémoire. Les composants globaux sont inscrits en fonction de la configuration de
969 configuration of application. Local components are taken to memory981 l'application. Les composants locaux sont récupérés dans la base de données au
970 from database while starting the application.982 démarrage de l'application.
971983
972984
973Querying adapter985récupération d'un adaptateur
974~~~~~~~~~~~~~~~~986~~~~~~~~~~~~~~~~~~~~~~~~~~~~
975987
976Retrieving registered components from component registry is achieved988La récupération des composants inscrits dans le registre est effectuée grâce à
977through two functions available in ``zope.component`` package. One of989deux fonctions disponibles dans le paquet ``zope.component``. La première est
978them is ``getAdapter`` and the other is ``queryAdapter`` . Both990``getAdapter``, la deuxième ``queryAdapter``. Les deux fonctions prennent les
979functions accepts same arguments. The ``getAdapter`` will raise991mêmes arguments. ``getAdapter`` lève une exception ``ComponentLookupError`` si
980``ComponentLookupError`` if component lookup fails on the other hand992la recherche de composant échoue, tandis que ``queryAdapter`` renvoie `None`.
981``queryAdapter`` will return `None`.993
982994Vous pouvez importer ces fonctions comme ceci ::
983You can import the methods like this::
984995
985 >>> from zope.component import getAdapter996 >>> from zope.component import getAdapter
986 >>> from zope.component import queryAdapter997 >>> from zope.component import queryAdapter
987998
988In the previous section you have registered a component for guest999Dans la section précédente, nous avons inscrit un composant qui fournit
989object (adaptee) which provides `IRegistrar` interface with name as1000l'interface `IDesk` avec un nom `ng`, et qui s'adapte à l'objet guest.
990'ng'. In the first section of this chapter, you have created a guest1001Dans la première section nous avons créé un objet nommé `jack`.
991object named `jack` .1002
9921003Voici maintenant comment récupérer un composant qui s'adapte à l'interface de l'objet
993This is how you can retrieve a component which adapts the interface of1004`jack` (`IGuest`) et qui fournit l'interface `IDesk` également avec le nom `ng`.
994`jack` object (`IGuest`) and provides `IRegistrar` interface also with1005Ici, ``getAdapter`` et ``queryAdapter`` fonctionnent de la même manière ::
995name as 'ng'. Here both ``getAdapter`` and ``queryAdapter`` works1006
996similarly::1007 >>> getAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS
9971008 <FrontDeskNG object at ...>
998 >>> getAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS1009 >>> queryAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS
999 <GuestRegistrarNG object at ...>1010 <FrontDeskNG object at ...>
1000 >>> queryAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS1011
1001 <GuestRegistrarNG object at ...>1012Vous pouvez constater que le premier argument doit être l'objet adapté, puis
10021013l'interface qui doit être fournie par le composant et finalement le nom du
1003As you can see, the first argument should be adaptee then, the1014composant adaptateur.
1004interface which should be provided by component and last the name of1015
1005adapter component.1016Si vous essayez de récupérer le composant grâce à un nom inutilisé pour
10061017l'inscription mais pour le même objet adapté et la même interface, la recherche
1007If you try to lookup the component with an name not used for1018échouera. Voici dans ce cas comment fonctionnent les deux méthodes ::
1008registration but for same adaptee and interface, the lookup will fail.1019
1009Here is how the two methods works in such a case::1020 >>> getAdapter(jack, IDesk, 'not-exists') #doctest: +ELLIPSIS
1010
1011 >>> getAdapter(jack, IRegistrar, 'not-exists') #doctest: +ELLIPSIS
1012 Traceback (most recent call last):1021 Traceback (most recent call last):
1013 ...1022 ...
1014 ComponentLookupError: ...1023 ComponentLookupError: ...
1015 >>> reg = queryAdapter(jack,1024 >>> reg = queryAdapter(jack,
1016 ... IRegistrar, 'not-exists') #doctest: +ELLIPSIS1025 ... IDesk, 'not-exists') #doctest: +ELLIPSIS
1017 >>> reg is None1026 >>> reg is None
1018 True1027 True
10191028
1020As you can see above, ``getAdapter`` raised a ``ComponentLookupError``1029``getAdapter`` a levé une exception ``ComponentLookupError`` mais
1021exception, but ``queryAdapter`` returned `None` when lookup failed.1030``queryAdapter`` a renvoyé `None`.
10221031
1023The third argument, the name of registration, is optional. If the1032Le troisième argument, le nom d'inscription, est optionnel. Si le troisième
1024third argument is not given it will default to empty string ('').1033argument n'est pas fourni, sa valeur par défaut est la chaîne vide (''). Comme
1025Since there is no component registered with an empty string,1034il n'y a aucun composant inscrit avec la chaîne vide comme nom, ``getAdapter``
1026``getAdapter`` will raise ``ComponentLookupError`` . Similarly1035lève l'exception ``ComponentLookupError``. De la même manière, ``queryAdapter``
1027``queryAdapter`` will return `None`, see yourself how it works::1036renvoie `None`. Voyez vous-même comment cela fonctionne ::
10281037
1029 >>> getAdapter(jack, IRegistrar) #doctest: +ELLIPSIS1038 >>> getAdapter(jack, IDesk) #doctest: +ELLIPSIS
1030 Traceback (most recent call last):1039 Traceback (most recent call last):
1031 ...1040 ...
1032 ComponentLookupError: ...1041 ComponentLookupError: ...
1033 >>> reg = queryAdapter(jack, IRegistrar) #doctest: +ELLIPSIS1042 >>> reg = queryAdapter(jack, IDesk) #doctest: +ELLIPSIS
1034 >>> reg is None1043 >>> reg is None
1035 True1044 True
10361045
1037In this section you have learned how to register a simple adapter and1046Dans cette section, vous avez appris à inscrire un simple adaptateur et à le
1038how to retrieve it from component registry. These kind of adapters is1047récupérer depuis le registre de composants. Ce type d'adaptateurs est appelé un
1039called single adapter, because it adapts only one adaptee. If an1048adaptateur simple, car il ne s'adapte qu'à un seul objet. Si un adaptateur
1040adapter adapts more that one adaptee, then it is called multi1049s'adapte à plusieurs objets, on l'appelle un multi-adaptateur.
1041adapter.1050
10421051
10431052Récupérer un adaptateur en utilisant l'interface
1044Retrieving adapter using interface1053~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1045~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1054
10461055Les adaptateurs peuvent être récupérés directement en utilisant les interfaces,
1047Adapters can be directly retrieved using interfaces, but it will only1056mais cela ne fonctionne qu'avec les adaptateurs simples. Le premier argument est
1048work for non-named single adapters. The first argument is the adaptee1057l'objet adapté, le deuxième argument est un argument mot-clé. Si la recheche
1049and the second argument is a keyword argument. If adapter lookup1058d'adaptateur échoue, le deuxième argument est renvoyé.
1050fails, second argument will be returned.1059
10511060 >>> IDesk(jack, alternate='default-output')
1052 >>> IRegistrar(jack, alternate='default-output')1061 'default-output'
1053 'default-output'1062
10541063 Le mot-clé peut être omis :
1055 Keyword name can be omitted:1064
10561065 >>> IDesk(jack, 'default-output')
1057 >>> IRegistrar(jack, 'default-output')1066 'default-output'
1058 'default-output'1067
10591068 Si le deuxième argument n'est pas fourni, une erreur `TypeError` est levée :
1060 If second argument is not given, it will raise `TypeError`:1069
10611070 >>> IDesk(jack) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
1062 >>> IRegistrar(jack) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
1063 Traceback (most recent call last):1071 Traceback (most recent call last):
1064 ...1072 ...
1065 TypeError: ('Could not adapt',1073 TypeError: ('Could not adapt',
1066 <Guest object at ...>,1074 <Guest object at ...>,
1067 <InterfaceClass __builtin__.IRegistrar>)1075 <InterfaceClass __builtin__.IDesk>)
10681076
1069 Here `GuestRegistrarNG` is registered without name:1077 Ici, `FrontDeskNG` est inscrit sans nom :
10701078
1071 >>> gsm.registerAdapter(GuestRegistrarNG)1079 >>> gsm.registerAdapter(FrontDeskNG)
10721080
1073 Now the adapter lookup should succeed:1081 Maintenant la récupération de l'adaptateur doit réussir :
10741082
1075 >>> IRegistrar(jack, 'default-output') #doctest: +ELLIPSIS1083 >>> IDesk(jack, 'default-output') #doctest: +ELLIPSIS
1076 <GuestRegistrarNG object at ...>1084 <FrontDeskNG object at ...>
10771085
1078For simple cases, you may use interface to get adapter components.1086Pour les cas simples, vous pouvez utiliser l'interface pour récupérer des
10791087adaptateurs.
10801088
1081Adapter pattern1089
1082~~~~~~~~~~~~~~~1090Motif adaptateur
10831091~~~~~~~~~~~~~~~~
1084The adapter concept in Zope Component Architecture and the classic1092
1085`adapter pattern` as described in Design Patterns book are very1093Le principe de l'adaptateur dans l'Architecture de Composants de Zope est très
1086similar. But the intent of ZCA adapter usage is more wider than the1094similaire au `motif adaptateur` classique, tel que décrit dans le livre « Design
1087`adapter pattern` itself. The intent of `adapter pattern` is to1095Patterns ». Mais l'objectif visé par l'utilisation des adaptateurs dans la ZCA
1088convert the interface of a class into another interface clients1096est plus large que le principe de l'adaptateur lui-même. Le but de l'adaptateur
1089expect. This allows classes work together that couldn't otherwise1097est de convertir l'interface d'une classe en une autre interface attendue par le
1090because of incompatible interfaces. But in the `motivation` section1098client. Ceci permet de faire fonctionner des classes ensemble même si elles ont
1091of Degisgn Patterns book, GoF says: "Often the adapter is responsible1099des interfaces incompatibles entre elles. Mais dans la section `motivations` du
1092for functionality the adapted class doesn't provide". ZCA adapter has1100livre « Design Patterns », le GoF dit : « souvent, l'adaptateur est responsable
1093more focus on adding functionalities than creating a new interface for1101d'une fonctionnalité que la classe adaptée ne fournit pas ». Un adaptateur de la
1094an adapted object (adaptee). ZCA adapter lets adapter classes extend1102ZCA se concentre effectivement plus sur l'ajout de fonctionnalités que sur la
1095functionality by adding methods. (It would be interesting to note1103création d'une nouvelle interface pour un objet adapté. L'adaptateur de la ZCA
1096that `Adapter` was known as `Feature` in earlier stage of ZCA1104permet aux classes adaptateurs d'étendre des fonctionnalités par ajout de
1097design. ) [#feature]_1105méthodes. (Il peut être intéressant de remarquer que l'adaptateur était appelé
10981106`Fonctionnalité` (`feature`) dans les premières étapes de conception de la ZCA.) [#feature]_
1099The above paragraph has a quote from Gang of Four book, it ends like
1100this: " ...adapted class doesn't provide". But in the next sentence I
1101used "adapted object" instead of "adapted class", because GoF
1102describes about two variants of adapters based on implementations.
1103The first one is called `class adapter` and the other one is called
1104`object adapter`. A class adapter uses multiple inheritance to adapt
1105one interface to another, on the other hand an object adapter relies
1106on object composition. ZCA adapter is following object adapter
1107pattern, which use delegation as a mechanism for composition. GoF's
1108second principle of object-oriented design goes like this: "Favor
1109object composition over class inheritance". For more details about
1110this subject please read Design Patterns book.
1111
1112The major attraction of ZCA adapter are the explicit interface for
1113components and the component registry. ZCA adapter components are
1114registered in component registry and looked up by client objects using
1115interface and name when required.
11161107
1117.. [#feature] Thread discussing renaming of `Feature` to `Adapter`:1108.. [#feature] Thread discussing renaming of `Feature` to `Adapter`:
1118 http://mail.zope.org/pipermail/zope3-dev/2001-December/000008.html1109 http://mail.zope.org/pipermail/zope3-dev/2001-December/000008.html
11191110
11201111La citation du Gang of Four dans le paragraphe ci-dessus se termine de la façon
1121Utility1112suivante : « ... que la classe adaptée ne fournit pas ». Mais dans la phrase
1122-------1113suivante nous avons utilisé « objet adapté » plutôt que « classe adaptée », car
1114le GoF décrit deux variantes d'adaptateurs selon les implémentations.
1115Le premier est appelé `adaptateur de classe`, le deuxième `adaptateur d'objet`.
1116Un adaptateur de classe utilise l'héritage multiple pour adapter une interface à
1117une autre, alors que l'adaptateur d'objet se base sur la composition d'objet.
1118L'adaptateur de la ZCA utilise le principe de l'adaptateur d'objet, qui utilise
1119la délégation comme mécanisme de composition. Le second principe du GoF à propos
1120de la conception orientée objets est la suivante : « favorisez la composition
1121d'objets plutôt que l'héritage de classes ». Pour approfondir le sujet,
1122reportez-vous au livre « Design Patterns ».
1123
1124Les principaux atouts des adaptateurs de la ZCA sont les interfaces explicites
1125et les registres de composants. Les composants adaptateurs de la ZCA sont inscrits
1126dans le registre de composants et sont récupérés par les objets clients via leur
1127interface et leur nom si besoin.
1128
1129
1130Utilitaires
1131-----------
11231132
11241133
1125Introduction1134Introduction
1126~~~~~~~~~~~~1135~~~~~~~~~~~~
11271136
1128Now you know the concept of interface, adapter and component registry.1137Vous connaissez maintenant le principe des interfaces, des adaptateurs et du
1129Sometimes it would be useful to register an object which is not1138registre de composants. Parfois, il peut être utile d'inscrire un objet qui ne
1130adapting anything. Database connection, XML parser, object returning1139s'adapte à rien du tout, par exemple une connexion à une base de données, un analyseur XML
1131unique Ids etc. are examples of these kinds of objects. These kind of1140ou un objet retournant des identifiants uniques. Ce type de composant
1132components provided by Zope component architecture are called1141fourni par la ZCA est appelé un « utilitaire » (*utility*).
1133``utility`` components.1142
11341143Les utilitaires sont simplement des objets qui fournissent une interface et qui sont
1135Utilities are just objects that provide an interface and that are1144récupérés à partir de cette interface et d'un nom. Cette approche permet de créer
1136looked up by an interface and a name. This approach creates a global1145un registre global dans lequel des instances peuvent être inscrites et
1137registry by which instances can be registered and accessed by1146récupérées à différents endroits de votre application, sans avoir besoin de
1138different parts of your application, with no need to pass the1147transmettre les instances comme paramètres.
1139instances around as parameters.1148
11401149Vous n'avez pas besoin d'inscrire toutes les instances de composants de cette
1141You need not to register all component instances like this. Only1150façon. Inscrivez seulement les composants que vous voulez rendre
1142register components which you want to make replaceable.1151interchangeables.
11431152
11441153
1145Simple utility1154Utilitaire simple
1146~~~~~~~~~~~~~~1155~~~~~~~~~~~~~~~~~
11471156
1148Before implementing the utility, as usual, define its interface. Here1157Un utilitaire peut être inscrit avec ou sans nom. Un utilitaire inscrit avec un nom
1149is a `greeter` interface::1158est appelé un `utilitaire nommé`. Vous le verrez dans la prochaine section.
1159Avant d'implémenter l'utilitaire, comme d'habitude, définissez son interface.
1160Voici une interface qui dit bonjour ::
11501161
1151 >>> from zope.interface import Interface1162 >>> from zope.interface import Interface
1152 >>> from zope.interface import implements1163 >>> from zope.interface import implements
@@ -1154,9 +1165,10 @@
1154 >>> class IGreeter(Interface):1165 >>> class IGreeter(Interface):
1155 ...1166 ...
1156 ... def greet(name):1167 ... def greet(name):
1157 ... "say hello"1168 ... """Say hello"""
11581169
1159Here is a possible implementation of the above interface::1170Comme un adaptateur, un utilitaire peut avoir plusieurs implémentations. Voici
1171une implémentation possible de l'interface ci-dessus ::
11601172
1161 >>> class Greeter(object):1173 >>> class Greeter(object):
1162 ...1174 ...
@@ -1165,7 +1177,10 @@
1165 ... def greet(self, name):1177 ... def greet(self, name):
1166 ... return "Hello " + name1178 ... return "Hello " + name
11671179
1168You can register an instance of this class using ``registerUtility``::1180L'utilitaire réel sera une instance de cette classe. Pour utiliser cet
1181utilitaire, vous devez l'inscrire, puis vous pourrez la récupérer en
1182utilisant l'API de la ZCA. Vous pouvez inscrire une instance de cette classe
1183(`utilitaire`) grâce à ``registerUtility`` ::
11691184
1170 >>> from zope.component import getGlobalSiteManager1185 >>> from zope.component import getGlobalSiteManager
1171 >>> gsm = getGlobalSiteManager()1186 >>> gsm = getGlobalSiteManager()
@@ -1173,9 +1188,9 @@
1173 >>> greet = Greeter()1188 >>> greet = Greeter()
1174 >>> gsm.registerUtility(greet, IGreeter)1189 >>> gsm.registerUtility(greet, IGreeter)
11751190
1176In this example you registered the utility as providing the `IGreeter`1191Dans cet exemple, vous avez inscrit l'utilitaire en fournissant l'interface
1177interface. You can look the interface up with either `queryUtility`1192`IGreeter`. Vous pouvez récupérer l'utilitaire avec `queryUtility` ou
1178or `getUtility`::1193`getUtility` ::
11791194
1180 >>> from zope.component import queryUtility1195 >>> from zope.component import queryUtility
1181 >>> from zope.component import getUtility1196 >>> from zope.component import getUtility
@@ -1186,24 +1201,27 @@
1186 >>> getUtility(IGreeter).greet('Jack')1201 >>> getUtility(IGreeter).greet('Jack')
1187 'Hello Jack'1202 'Hello Jack'
11881203
1189As you can see, adapters are normally classes, but utilities are1204Comme vous pouvez le constater, alors que les adaptateurs sont habituellement
1190normally instances of classes.1205des classes, les utilitaires sont habituellement des instances de classes. vous
11911206ne créez une instance d'utilitaire qu'une fois, alors que les instances
11921207d'adaptateurs sont créées à chaque fois que vous les récupérez.
1193Named utility1208
1194~~~~~~~~~~~~~1209
11951210Utilitaire nommé
1196When registering a utility component, like adapter, you can use a1211~~~~~~~~~~~~~~~~
1197name.1212
11981213Lorsque vous inscrivez un composant utilitaire, de la même manière que pour les
1199For example consider this:1214adaptateurs, vous pouvez utiliser un nom. Comme mentionné dans la section
1215précédente, un utilitaire inscrit avec un nom est appelé un `utilitaire nommé`.
1216
1217Voici comment inscrire l'utilitaire `greeter` avec un nom ::
12001218
1201 >>> greet = Greeter()1219 >>> greet = Greeter()
1202 >>> gsm.registerUtility(greet, IGreeter, 'new')1220 >>> gsm.registerUtility(greet, IGreeter, 'new')
12031221
1204In this example you registered the utility with a name as providing1222Dans cet exemple, nous avons inscrit l'utilitaire avec un nom en fournissant
1205the `IGreeter` interface. You can look the interface up with either1223l'interface `IGreeter`. Vous pouvez récupérer l'utilitaire avec `queryUtility`
1206`queryUtility` or `getUtility`::1224ou `getUtility` ::
12071225
1208 >>> from zope.component import queryUtility1226 >>> from zope.component import queryUtility
1209 >>> from zope.component import getUtility1227 >>> from zope.component import getUtility
@@ -1214,28 +1232,25 @@
1214 >>> getUtility(IGreeter, 'new').greet('Jill')1232 >>> getUtility(IGreeter, 'new').greet('Jill')
1215 'Hello Jill'1233 'Hello Jill'
12161234
1217As you can see here, while querying you have to use the `name` as1235Remarquez que vous devez utiliser le nom de l'utilitaire comme second argument
1218second argument.1236pour que la récupération fonctionne.
12191237
1220.. note::1238Appeler `getUtility` sans nom (comme second argument) est équivalent à l'appeler
12211239avec un nom vide (''), car la valeur par défaut pour ce second argument est
1222 Calling `getUtility` function without a name (second argument) is1240justement la chaîne vide. Donc le mécanisme de recherche de composant essaiera
1223 equivalent to calling with an empty string ('') as the name.1241de trouver le composant ayant une chaîne vide comme nom et il échouera.
1224 Because, the default value for second (keyword) argument is an empty1242Lorsqu'une recherche de composant échoue, le résultat est une exception
1225 string. Then, component lookup mechanism will try to find the1243``ComponentLookupError``. Souvenez-vous qu'aucun composant aléatoire avec un
1226 component with name as empty string (''), and it will fail. When1244autre nom ne sera renvoyé. Les fonctions de récupération d'adaptateurs,
1227 component lookup fails it will raise `ComponentLookupError`1245`getAdapter` et `queryUtility` fonctionnent de manière similaire.
1228 exception. Remember, it will not return some random component1246
1229 registered with some other name.1247
12301248Fabrique
12311249~~~~~~~~
1232Factory1250
1233~~~~~~~1251Une ``fabrique`` est un composant utilitaire qui fournit l'interface ``IFactory``.
12341252
1235A ``Factory`` is a utility component which provides ``IFactory``1253Pour créer une fabrique, commencez par définir l'interface de l'objet ::
1236interface.
1237
1238To create a factory, first define the interface of the object::
12391254
1240 >>> from zope.interface import Attribute1255 >>> from zope.interface import Attribute
1241 >>> from zope.interface import Interface1256 >>> from zope.interface import Interface
@@ -1246,7 +1261,7 @@
1246 ... def getConnection():1261 ... def getConnection():
1247 ... """Return connection object"""1262 ... """Return connection object"""
12481263
1249Here is fake implementation of `IDatabase` interface::1264Voici une implémentation factice de l'interface `IDatabase` ::
12501265
1251 >>> class FakeDb(object):1266 >>> class FakeDb(object):
1252 ...1267 ...
@@ -1255,13 +1270,13 @@
1255 ... def getConnection(self):1270 ... def getConnection(self):
1256 ... return "connection"1271 ... return "connection"
12571272
1258You can create a factory using ``zope.component.factory.Factory``::1273Vous pouvez créer une fabrique en utilisant ``zope.component.factory.Factory`` ::
12591274
1260 >>> from zope.component.factory import Factory1275 >>> from zope.component.factory import Factory
12611276
1262 >>> factory = Factory(FakeDb, 'FakeDb')1277 >>> factory = Factory(FakeDb, 'FakeDb')
12631278
1264Now you can register it like this::1279Maintenant vous pouvez l'inscrire de cette façon ::
12651280
1266 >>> from zope.component import getGlobalSiteManager1281 >>> from zope.component import getGlobalSiteManager
1267 >>> gsm = getGlobalSiteManager()1282 >>> gsm = getGlobalSiteManager()
@@ -1269,29 +1284,32 @@
1269 >>> from zope.component.interfaces import IFactory1284 >>> from zope.component.interfaces import IFactory
1270 >>> gsm.registerUtility(factory, IFactory, 'fakedb')1285 >>> gsm.registerUtility(factory, IFactory, 'fakedb')
12711286
1272To use the factory, you may do it like this::1287Pour utiliser la fabrique, vous pouvez faire comme ceci ::
12731288
1274 >>> from zope.component import queryUtility1289 >>> from zope.component import queryUtility
1275 >>> queryUtility(IFactory, 'fakedb')() #doctest: +ELLIPSIS1290 >>> queryUtility(IFactory, 'fakedb')() #doctest: +ELLIPSIS
1276 <FakeDb object at ...>1291 <FakeDb object at ...>
12771292
1278There is a shortcut to use factory::1293Voici l'écriture simplifiée pour utiliser une fabrique ::
12791294
1280 >>> from zope.component import createObject1295 >>> from zope.component import createObject
1281 >>> createObject('fakedb') #doctest: +ELLIPSIS1296 >>> createObject('fakedb') #doctest: +ELLIPSIS
1282 <FakeDb object at ...>1297 <FakeDb object at ...>
12831298
12841299
1285Advanced adapters1300Adaptateurs avancés
1286-----------------1301-------------------
12871302
12881303Ce chapître traite de concepts avancés comme les multi-adaptateurs, les
1289Multi adapter1304abonnés (subscribers) et les gestionnaires (handles).
1290~~~~~~~~~~~~~1305
12911306
1292A simple adapter normally adapts only one object, but an adapter can1307Multi-adaptateur
1293adapt more than one object. If an adapter adapts more than one1308~~~~~~~~~~~~~~~~
1294objects, it is called as multi-adapter.1309
1310Un adaptateur simple s'adapte normalement à un seul objet, mais un adaptateur
1311peut s'adapter à plusieurs objets. Si un adaptateur s'adapte à plus d'un objet,
1312il s'appelle un multi-adaptateur.
12951313
1296::1314::
12971315
@@ -1342,16 +1360,16 @@
1342 <Two object at ...>1360 <Two object at ...>
13431361
13441362
1345Subscription adapter1363Adaptateur d'abonnement
1346~~~~~~~~~~~~~~~~~~~~1364~~~~~~~~~~~~~~~~~~~~~~~
13471365
1348Unlike regular adapters, subscription adapters are used when we want1366À la différence des adaptateurs habituels, les adaptateurs d'abonnement sont
1349all of the adapters that adapt an object to a particular adapter.1367utilisés quand on veut récupérer tous les adaptateurs qui adaptent un objet à
1350Subscription adapter is also known as `subscriber` .1368une interface donnée. Un adaptateur d'abonnement est également appelé `abonné`.
13511369
1352Consider a validation problem. We have objects and we want to assess1370Considérons un problème de validation. Nous avons des objets et nous voulons
1353whether they meet some sort of standards. We define a validation1371vérifier s'ils satisfont à un certain critère. Nous définissons une interface
1354interface::1372de validation ::
13551373
1356 >>> from zope.interface import Interface1374 >>> from zope.interface import Interface
1357 >>> from zope.interface import Attribute1375 >>> from zope.interface import Attribute
@@ -1367,7 +1385,7 @@
1367 ... object is valid.1385 ... object is valid.
1368 ... """1386 ... """
13691387
1370Perhaps we have documents::1388Nous avons également des documents ::
13711389
1372 >>> class IDocument(Interface):1390 >>> class IDocument(Interface):
1373 ...1391 ...
@@ -1381,9 +1399,9 @@
1381 ... def __init__(self, summary, body):1399 ... def __init__(self, summary, body):
1382 ... self.summary, self.body = summary, body1400 ... self.summary, self.body = summary, body
13831401
1384Now, we may want to specify various validation rules for1402Maintenant, nous pouvons avoir besoin de préciser différentes règles de
1385documents. For example, we might require that the summary be a single1403validation pour les documents. Par exemple, nous voulons que le résumé tienne
1386line:1404sur une seule ligne ::
13871405
1388 >>> from zope.component import adapts1406 >>> from zope.component import adapts
13891407
@@ -1401,7 +1419,7 @@
1401 ... else:1419 ... else:
1402 ... return ''1420 ... return ''
14031421
1404Or we might require the body to be at least 1000 characters in length:1422Ou bien nous voulons que le corps du document fasse au moins 1000 caractères ::
14051423
1406 >>> class AdequateLength(object):1424 >>> class AdequateLength(object):
1407 ...1425 ...
@@ -1417,7 +1435,7 @@
1417 ... else:1435 ... else:
1418 ... return ''1436 ... return ''
14191437
1420We can register these as subscription adapters:1438Nous pouvons inscrire ces deux composants comme des adaptateurs d'abonnement ::
14211439
1422 >>> from zope.component import getGlobalSiteManager1440 >>> from zope.component import getGlobalSiteManager
1423 >>> gsm = getGlobalSiteManager()1441 >>> gsm = getGlobalSiteManager()
@@ -1425,7 +1443,7 @@
1425 >>> gsm.registerSubscriptionAdapter(SingleLineSummary)1443 >>> gsm.registerSubscriptionAdapter(SingleLineSummary)
1426 >>> gsm.registerSubscriptionAdapter(AdequateLength)1444 >>> gsm.registerSubscriptionAdapter(AdequateLength)
14271445
1428We can then use the subscribers to validate objects:1446Nous pouvons ensuite utiliser ces abonnés pour valider les objets ::
14291447
1430 >>> from zope.component import subscribers1448 >>> from zope.component import subscribers
14311449
@@ -1448,36 +1466,37 @@
1448 ['too short']1466 ['too short']
14491467
14501468
1451Handler1469Gestionnaire
1452~~~~~~~1470~~~~~~~~~~~~
14531471
1454Handlers are subscription adapter factories that don't produce1472Les gestionnaires sont des fabriques d'abonnés qui ne
1455anything. They do all of their work when called. Handlers are1473produisent rien du tout. Ils font la totalité de leur travail lorsqu'ils sont
1456typically used to handle events. Handlers are also known as event1474appelés. Les gestionnaires sont typiquement utilisés pour gérer des événements.
1457subscribers or event subscription adapters.1475Les gestionnaires sont aussi connus sous le nom d'``abonnés
14581476à des événements`` ou ``adaptateurs d'abonnement à des événements``.
1459Event subscribers are different from other subscription adapters in1477
1460that the caller of event subscribers doesn't expect to interact with1478Les abonnés à des événements sont différents des autres abonnés car l'objet qui
1461them in any direct way. For example, an event publisher doesn't1479appelle les abonnés ne s'attend pas à interagir avec eux d'une quelconque façon.
1462expect to get any return value. Because subscribers don't need to1480Par exemple, un publicateur d'événements ne s'attend pas à récupérer une valeur
1463provide an API to their callers, it is more natural to define them1481de retour. Comme les abonnés n'ont pas besoin de fournir une API aux objets qui
1464with functions, rather than classes. For example, in a1482les appellent, il est plus naturel de les définir avec des fonctions, plutôt
1465document-management system, we might want to record creation times for1483qu'avec des classes. Par exemple, dans un système de gestion de documents, nous
1466documents::1484pouvons avoir besoin de gérer les heures de création des documents ::
14671485
1468 >>> import datetime1486 >>> import datetime
14691487
1470 >>> def documentCreated(event):1488 >>> def documentCreated(event):
1471 ... event.doc.created = datetime.datetime.utcnow()1489 ... event.doc.created = datetime.datetime.utcnow()
14721490
1473In this example, we have a function that takes an event and performs1491Dans cet exemple, nous avons une fonction qui prend un événement et effectue un
1474some processing. It doesn't actually return anything. This is a1492traitement. La fonction ne retourne en fait rien du tout. C'est un cas
1475special case of a subscription adapter that adapts an event to1493particulier de l'adaptateur d'abonnement qui s'adapte à un événement et ne
1476nothing. All of the work is done when the adapter "factory" is1494fournit rien. Tout le travail est effectué lorsque la fabrique de l'adaptateur
1477called. We call subscribers that don't actually create anything1495est appelée. Nous appelons les abonnés qui ne fabriquent rien des « gestionnaires ».
1478"handlers". There are special APIs for registering and calling them.1496Il existe des APIs spécialisées dans leur inscription et leur récupération.
14791497
1480To register the subscriber above, we define a document-created event::1498Pour inscrire l'abonné ci-dessus, nous définissons un événement « document créé
1499» ::
14811500
1482 >>> from zope.interface import Interface1501 >>> from zope.interface import Interface
1483 >>> from zope.interface import Attribute1502 >>> from zope.interface import Attribute
@@ -1494,7 +1513,7 @@
1494 ... def __init__(self, doc):1513 ... def __init__(self, doc):
1495 ... self.doc = doc1514 ... self.doc = doc
14961515
1497We'll also change our handler definition to:1516Nous modifions également notre définition du gestionnaire ::
14981517
1499 >>> def documentCreated(event):1518 >>> def documentCreated(event):
1500 ... event.doc.created = datetime.datetime.utcnow()1519 ... event.doc.created = datetime.datetime.utcnow()
@@ -1505,17 +1524,18 @@
1505 ... def documentCreated(event):1524 ... def documentCreated(event):
1506 ... event.doc.created = datetime.datetime.utcnow()1525 ... event.doc.created = datetime.datetime.utcnow()
15071526
1508This marks the handler as an adapter of `IDocumentCreated` events.1527Ceci marque le gestionnaire comme étant un adaptateur des événements
1528`IDocumentCreated`.
15091529
1510Now we'll register the handler::1530Nous inscrivons le gestionnaire ::
15111531
1512 >>> from zope.component import getGlobalSiteManager1532 >>> from zope.component import getGlobalSiteManager
1513 >>> gsm = getGlobalSiteManager()1533 >>> gsm = getGlobalSiteManager()
15141534
1515 >>> gsm.registerHandler(documentCreated)1535 >>> gsm.registerHandler(documentCreated)
15161536
1517Now, if we can create an event and use the `handle` function to call1537Il est maintenant possible de créer un événement et d'utiliser la fonction
1518handlers registered for the event::1538`handle` pour appeler les gestionnaires inscrits à l'événement ::
15191539
1520 >>> from zope.component import handle1540 >>> from zope.component import handle
15211541
@@ -1524,29 +1544,34 @@
1524 'datetime'1544 'datetime'
15251545
15261546
1527ZCA usage in Zope1547Usage de la ZCA dans Zope
1528-----------------1548-------------------------
15291549
1530Zope Component Architecture is used in both Zope 3 and Zope 2. This1550L'Architecture de Composants de Zope est utilisée dans Zope 2 et dans Zope 3. Ce
1531chapter go through ZCA usage in Zope.1551chapitre traite de l'usage de la ZCA dans Zope.
15321552
15331553
1534ZCML1554ZCML
1535~~~~1555~~~~
15361556
1537The Zope Configuration Markup Language (ZCML) is an XML based1557Le **Zope Configuration Markup Language (ZCML)** est un système de configuration
1538configuration system for registration of components. So, instead of1558pour l'inscription des composants. Au lieu d'utiliser l'API Python pour les
1539using Python API for registration, you can use ZCML. But to use ZCML,1559inscriptions, vous pouvez utiliser le ZCML. Pour pouvoir utiliser le ZCML,
1540unfortunately, you will be required to install more dependency1560vous devez installer des paquets supplémentaires.
1541packages.
15421561
1543To install these packages::1562Vous pouvez installer ``zope.component`` avec la prise en charge du ZCML en
1563utilisant easy_install comme ceci ::
15441564
1545 $ easy_install "zope.component [zcml]"1565 $ easy_install "zope.component [zcml]"
15461566
1547To register an adapter::1567Un fichier ZCML doit commencer par une directive ``configure`` avec la
1568déclaration d'espace de nom appropriée ::
15481569
1549 <configure xmlns="http://namespaces.zope.org/zope">1570 <configure xmlns="http://namespaces.zope.org/zope">
1571 ...
1572 </configure>
1573
1574La directive `adapter` peut être utilisée pour inscrire des adaptateurs ::
15501575
1551 <adapter1576 <adapter
1552 factory=".company.EmployeeSalary"1577 factory=".company.EmployeeSalary"
@@ -1554,73 +1579,59 @@
1554 for=".interfaces.IEmployee"1579 for=".interfaces.IEmployee"
1555 />1580 />
15561581
1557The `provides` and `for` attributes are optional, provided you have1582Les attributs `provides` et `for` sont optionnels, à condition que vous ayez
1558declared it in the implementation::1583fait les déclaration correspondantes dans l'implémentation ::
1559
1560 <configure xmlns="http://namespaces.zope.org/zope">
15611584
1562 <adapter1585 <adapter
1563 factory=".company.EmployeeSalary"1586 factory=".company.EmployeeSalary"
1564 />1587 />
15651588
1566If you want to register the component as named adapter, you can give a1589Si vous voulez inscrire le composant comme un adaptateur nommé, vous pouvez
1567`name` attribute::1590utiliser l'attribut `name` ::
1568
1569
1570 <configure xmlns="http://namespaces.zope.org/zope">
15711591
1572 <adapter1592 <adapter
1573 factory=".company.EmployeeSalary"1593 factory=".company.EmployeeSalary"
1574 name="salary"1594 name="salary"
1575 />1595 />
15761596
1577Utilities are also registered similarly.1597Un utilitaire peut être inscrit avec la directive `utility` ::
1578
1579To register an utility::
1580
1581 <configure xmlns="http://namespaces.zope.org/zope">
15821598
1583 <utility1599 <utility
1584 component=".database.connection"1600 component=".database.connection"
1585 provides=".interfaces.IConnection"1601 provides=".interfaces.IConnection"
1586 />1602 />
15871603
1588The `provides` attribute is optional, provided you have declared it in1604L'attribut `provides` est optionnel, à condition que vous ayez fait la
1589the implementation::1605déclaration correspondante dans l'implémentation ::
15901606
1591 <configure xmlns="http://namespaces.zope.org/zope">1607 <configure xmlns="http://namespaces.zope.org/zope">
15921608
1593 <utility1609 <utility
1594 component=".database.connection"1610 component=".database.connection"
1595 />1611 />
15961612
1597If you want to register the component as named adapter, you can give a1613Si vous voulez inscrire le composant comme un utilitaire nommé, vous pouvez
1598`name` attribute::1614utiliser l'attribut `name` ::
15991615
16001616 <utility
1601 <configure xmlns="http://namespaces.zope.org/zope">1617 component=".database.connection"
16021618 name="db_connection"
1603 <utility1619 />
1604 component=".database.connection"1620
1605 name="Database Connection"1621Plutôt que d'utiliser directement le composant, vous pouvez aussi fournir une
1606 />1622fabrique ::
1607
1608Instead of directly using the component, you can also give a factory::
1609
1610 <configure xmlns="http://namespaces.zope.org/zope">
16111623
1612 <utility1624 <utility
1613 factory=".database.Connection"1625 factory=".database.Connection"
1614 />1626 />
16151627
16161628
1617Overrides1629Surchargements
1618~~~~~~~~~1630~~~~~~~~~~~~~~
16191631
1620When you register components using Python API (``register*`` methods),1632Lorsque vous inscrivez des composants avec l'API Python (méthodes
1621the last registered component will replace previously registered1633``register*``), le dernier composant inscrit remplace le précédent, si les deux
1622component, if both are registered with same type of arguments. For1634sont inscrits avec les mêmes arguments. Considérons l'exemple suivant ::
1623example, consider this example::
16241635
1625 >>> from zope.interface import Attribute1636 >>> from zope.interface import Attribute
1626 >>> from zope.interface import Interface1637 >>> from zope.interface import Interface
@@ -1665,22 +1676,21 @@
1665 >>> getAdapter(a, IP) #doctest: +ELLIPSIS1676 >>> getAdapter(a, IP) #doctest: +ELLIPSIS
1666 <AP object at ...>1677 <AP object at ...>
16671678
1668 If you register another adapter, the existing one will be replaced:1679Si vous inscrivez un autre adaptateur, celui existant sera surchargé ::
16691680
1670 >>> gsm.registerAdapter(AP2)1681 >>> gsm.registerAdapter(AP2)
16711682
1672 >>> getAdapter(a, IP) #doctest: +ELLIPSIS1683 >>> getAdapter(a, IP) #doctest: +ELLIPSIS
1673 <AP2 object at ...>1684 <AP2 object at ...>
16741685
1675But when registering components using ZCML, the second registration1686Mais lorsque vous inscrivez des composants en ZCML, la deuxième inscription
1676will raise a conflict error. This is a hint for you, otherwise there1687provoquera un conflit. Ceci est fait pour éviter les surchargements accidentels
1677is a chance for overriding registration by mistake. This may lead to1688d'inscriptions, qui sont difficiles à retrouver et corriger.
1678hard to track bugs in your system. So, using ZCML is a win for the1689L'utilisation de ZCML est donc un avantage pour votre application.
1679application.
16801690
1681Sometimes you will be required to override existing registration.1691Parfois vous aurez besoin de surcharger une inscription existante. ZCML fournit
1682ZCML provides ``includeOverrides`` directive for this. Using this,1692une directive ``includeOverrides`` à cet effet. Avec la directive ci-dessous,
1683you can write your overrides in a separate file::1693vous pouvez écrire vos surcharges dans un fichier séparé ::
16841694
1685 <includeOverrides file="overrides.zcml" />1695 <includeOverrides file="overrides.zcml" />
16861696
@@ -1688,12 +1698,11 @@
1688NameChooser1698NameChooser
1689~~~~~~~~~~~1699~~~~~~~~~~~
16901700
1691Location: `zope.app.container.contained.NameChooser`1701Emplacement : `zope.app.container.contained.NameChooser`
16921702
1693This is an adapter for choosing a unique name for an object inside a1703C'est un adaptateur qui choisit un nom unique pour un objet dans un conteneur.
1694container.1704
16951705L'inscription de l'adaptateur ressemble à ceci ::
1696The registration of adapter is like this::
16971706
1698 <adapter1707 <adapter
1699 provides=".interfaces.INameChooser"1708 provides=".interfaces.INameChooser"
@@ -1701,40 +1710,37 @@
1701 factory=".contained.NameChooser"1710 factory=".contained.NameChooser"
1702 />1711 />
17031712
1704From the registration, you can see that the adaptee is a1713Dans cette inscription, vous pouvez observer qu'on s'adapte à un
1705``IWriteContainer`` and the adapter provides ``INameChooser``.1714``IWriteContainer`` et que l'adaptateur fournit ``INameChooser``.
17061715
1707This adapter provides a very convenient functionality for Zope1716Cet adaptateur fournit une fonctionnalité très pratique pour les développeurs
1708programmers. The main implementations of ``IWriteContainer`` in1717Zope. Les implémentations principales de ``IWriteContainer`` dans Zope 3 sont
1709Zope 3 are ``zope.app.container.BTreeContainer`` and1718`zope.app.container.BTreeContainer`` et ``zope.app.folder.Folder``. Normalement
1710``zope.app.folder.Folder``. Normally you will be inheriting from1719vous hériterez de ces implémentations pour créer vos propres classes de
1711these implementations for creating your own container classes.1720conteneurs. Supposez qu'il n'y ait pas d'interface ``INameChooser`` ni
1712Suppose there is no interface called ``INameChooser`` and1721d'adaptateur : vous seriez obligé de recréer cette fonctionnalité séparément
1713adapter, then you will be required to implement this functionality1722pour chaque implémentation.
1714for every implementations separately.
17151723
17161724
1717LocationPhysicallyLocatable1725LocationPhysicallyLocatable
1718~~~~~~~~~~~~~~~~~~~~~~~~~~~1726~~~~~~~~~~~~~~~~~~~~~~~~~~~
17191727
1720Location:1728Emplacement :
1721``zope.location.traversing.LocationPhysicallyLocatable``1729``zope.location.traversing.LocationPhysicallyLocatable``
17221730
1723This adapter is frequently used in Zope 3 applications, but1731Cet adaptateur est fréquemment utilisé dans les applications Zope 3, mais
1724normally it is called through an API in ``zope.traversing.api``.1732habituellement il est appelé au travers d'une API dans ``zope.traversing.api``.
1725(Some old code even use ``zope.app.zapi`` functions, which is1733(Certains vieux codes utilisent même les fonctions ``zope.app.zapi`` qui ne sont
1726again one more indirection)1734qu'une indirection supplémentaire).
17271735
1728The registration of adapter is like this::1736L'inscription de l'adaptateur ressemble à ceci ::
17291737
1730 <adapter1738 <adapter
1731 factory="zope.location.traversing.LocationPhysicallyLocatable"1739 factory="zope.location.traversing.LocationPhysicallyLocatable"
1732 />1740 />
17331741
1734The interface provided and adaptee interface is given in the1742L'interface fournie et l'interface adaptée sont données dans l'implémentation,
1735implementation.1743dont voici le début ::
1736
1737Here is the beginning of implementation::
17381744
1739 class LocationPhysicallyLocatable(object):1745 class LocationPhysicallyLocatable(object):
1740 """Provide location information for location objects1746 """Provide location information for location objects
@@ -1743,43 +1749,41 @@
1743 zope.interface.implements(IPhysicallyLocatable)1749 zope.interface.implements(IPhysicallyLocatable)
1744 ...1750 ...
17451751
1746Normally, almost all persistent objects in Zope 3 application1752Normalement, presque tous les objets persistants d'une application Zope 3
1747will be providing the ``ILocation`` interface. This interface1753fournissent l'interface ``ILocation``. Cette interface n'a que deux attributs,
1748has only two attribute, ``__parent__`` and ``__name__``. The1754``__parent__`` et ``__name__``. ``__parent__`` est le parent dans la hiérarchie
1749``__parent__`` is the parent in the location hierarchy. And1755des objets et ``__name__`` est le nom, vu depuis le parent.
1750``__name__`` is the name within the parent.1756
17511757L'interface ``IPhysicallyLocatable`` a quatre méthodes:
1752The ``IPhysicallyLocatable`` interface has four methods:1758``getRoot``, ``getPath``, ``getName``, et ``getNearestSite``.
1753``getRoot``, ``getPath``, ``getName``, and ``getNearestSite``.1759
17541760 - ``getRoot`` renvoie l'objet racine physique.
1755 - ``getRoot`` function will return the physical root object.1761
17561762 - ``getPath`` renvoie une chaîne donnant le chemin physique vers l'objet.
1757 - ``getPath`` return the physical path to the object as a1763
1758 string.1764 - ``getName`` renvoie le dernier segment du chemin physique.
17591765
1760 - ``getName`` return the last segment of the physical path.1766 - ``getNearestSite`` renvoie le site dans lequel l'objet est contenu. Si
17611767 l'objet est lui-même un site, il est renvoyé.
1762 - ``getNearestSite`` return the site the object is contained1768
1763 in. If the object is a site, the object itself is returned.1769Si vous apprenez Zope 3, ce sont des choses importantes dont vous aurez besoin
17641770très souvent. Pour comprendre la beauté de ce système, vous devriez regarder
1765If you learn Zope 3, you can see that these are the important1771comment Zope 2 récupère l'objet racine physique et comment ceci est implémenté.
1766things which you required very often. To understand the beauty1772Il existe une méthode ``getPhysicalRoot`` virtuellement pour tous les objets
1767of this system, you must see how Zope 2 actually get the physical1773conteneurs.
1768root object and how it is implemented. There is a method called
1769``getPhysicalRoot`` virtually for all container objects.
17701774
17711775
1772DefaultSized1776DefaultSized
1773~~~~~~~~~~~~1777~~~~~~~~~~~~
17741778
1775Location: ``zope.size.DefaultSized``1779Emplacement : ``zope.size.DefaultSized``
17761780
1777This adapter is just a default implementation of ``ISized`` interface.1781Cet adaptateur n'est qu'une implémentation par défaut de l'interface ``ISized``.
1778This adapter is registered for all kind of objects. If you want to1782Il est inscrit pour tous les types d'objets. Si vous voulez inscrire cet
1779register this adapter for a particular interface, then you have to1783adaptateur pour une interface particulière, vous devez surcharger cette
1780override this registration for your implementation.1784inscription avec votre implémentation.
17811785
1782The registration of adapter is like this::1786L'inscription de l'adaptateur ressemble à ceci ::
17831787
1784 <adapter1788 <adapter
1785 for="*"1789 for="*"
@@ -1788,10 +1792,10 @@
1788 permission="zope.View"1792 permission="zope.View"
1789 />1793 />
17901794
1791As you can see, the adaptee interface is `*`, so it can adapt any kind1795Comme vous pouvez voir, l'interface adaptée est « * », pour pouvoir s'adapter à
1792of objects.1796tous les types d'objets.
17931797
1794The ``ISized`` is a simple interface with two method contracts::1798``ISized`` est une interface simple possédant deux méthodes ::
17951799
1796 class ISized(Interface):1800 class ISized(Interface):
17971801
@@ -1806,112 +1810,793 @@
1806 """Returns a string giving the size.1810 """Returns a string giving the size.
1807 """1811 """
18081812
1809You can see another ``ISized`` adapter registered for ``IZPTPage`` in1813Vous pouvez trouver un autre adaptateur ``ISized`` pour ``IZPTPage`` dans le
1810``zope.app.zptpage`` package.1814paquet ``zope.app.zptpage``.
18111815
18121816
1813ZopeVersionUtility1817ZopeVersionUtility
1814~~~~~~~~~~~~~~~~~~1818~~~~~~~~~~~~~~~~~~
18151819
1816Location: ``zope.app.applicationcontrol.ZopeVersionUtility``1820Emplacement : ``zope.app.applicationcontrol.ZopeVersionUtility``
18171821
1818This utility gives version of the running Zope.1822Cet utilitaire donne la version de Zope en fonctionnement.
18191823
1820The registration goes like this::1824L'inscription est la suivante ::
18211825
1822 <utility1826 <utility
1823 component=".zopeversion.ZopeVersionUtility"1827 component=".zopeversion.ZopeVersionUtility"
1824 provides=".interfaces.IZopeVersion" />1828 provides=".interfaces.IZopeVersion" />
18251829
1826The interface provided, ``IZopeVersion``, has only one method named1830L'interface fournie, ``IZopeVersion``, n'a qu'une méthode nommée
1827``getZopeVersion``. This method return a string containing the Zope1831``getZopeVersion``. Cette méthode renvoie une chaîne contenant la version de
1828version (possibly including SVN information).1832Zope (avec éventuellement un changeset SVN).
18291833
1830The default implementation, ``ZopeVersionUtility``, get version info1834L'implémentation par défaut, ``ZopeVersionUtility``, récupère le numéro de
1831from a file ``version.txt`` in `zope/app` directory. If Zope is1835version dans un fichier ``version.txt`` du répertoire `zope/app`. Si Zope
1832running from subversion checkout, it will show the latest revision1836fonctionne depuis un espace de travail Subversion, il montre le dernier numéro
1833number. If none of the above works it will set it to:1837de révision. Si aucun des deux ne fonctionne il renvoie `DevCenter/Unknown`.
1834`Development/Unknown`.1838
18351839
1840Étude de cas
1841------------
1842
1843.. note::
1844
1845 Ce chapitre n'est pas terminé. Merci d'envoyer vos suggestions !
1846
1847Introduction
1848~~~~~~~~~~~~
1849
1850Ce chapitre est un exemple de création d'une application lourde avec la
1851bibliothèque d'interface graphique PyGTK et la ZCA. Cette application utilise
1852également deux types différents de mécanismes de persistance des données : le
1853premier est une base de données objet (ZODB), l'autre est une base de données
1854relationnelle (SQLite). Cependant, en pratique, un seul des deux mécanismes peut
1855être utilisé dans une installation donnée. L'utilisation de deux types de
1856persistance est là pour démontrer comment utiliser la ZCA pour brancher des
1857composants entre eux. La majorité de code de cette application est lié à PyGTK.
1858
1859Lorsque l'application grossit, vous pouvez utiliser les composants de la ZCA aux
1860endroits où vous souhaitez fournir de la modularité ou de l'extensibilité.
1861Utilisez des objets Python classiques quand vous n'avez pas besoin de ces
1862propriétés.
1863
1864Il n'y a pas de différence entre l'utilisation de la ZCA pour une application
1865web, pour une application graphique lourde, ou pour toute autre application ou
1866framework. Il est préférable de suivre une convention pour l'emplacement où vous
1867allez inscrire les composants. Cette application utilise une convention qui peut
1868être étendue en plaçant des inscriptions ou des composants similaires dans des
1869modules séparés et en les important plus tard depuis le module principal
1870d'inscription. Dans cette application, le module principal pour l'inscription
1871est `register.py`.
1872
1873Le code source de cette application peut être téléchargé sur :
1874http://www.muthukadan.net/downloads/zcalib.tar.bz2
1875
1876
1877Cas d'utilisation
1878~~~~~~~~~~~~~~~~~
1879
1880L'application que nous allons créer ici est un système de gestion de
1881bibliothèque avec des fonctionnalités minimales. Les besoins peuvent être
1882résumés comme ceci:
1883
1884- Ajouter des membres avec un numéro et un nom uniques.
1885
1886- Ajouter des livres avec un code barre, un auteur et un titre.
1887
1888- Prêter des livres
1889
1890- Récupérer des livres
1891
1892
1893L'application peut être conçue de telle façon que les grandes fonctionnalités
1894seront utilisées dans une fenêtre unique. La fenêtre principale peut être conçue
1895de cette façon :
1896
1897.. image:: mainwindow.png
1898 :align: center
1899
1900Depuis la fenêtre des membres, l'utilisateur devrait être capable de gérer des
1901membres. Donc il devrait être possible d'*ajouter*, *modifier* et *effacer* des
1902membres comme dans l'image ci-dessous :
1903
1904.. image:: memberwindow.png
1905 :align: center
1906
1907Similaire à la fenêtre des membres, la fenêtre du catalogue permet aux
1908utilisateurs d'*ajouter*, *modifier* et *effacer* des livres :
1909
1910.. image:: catalogwindow.png
1911 :align: center
1912
1913La fenêtre de circulation doit avoir ce qu'il faut pour prêter et récupérer des
1914livres :
1915
1916.. image:: circulationwindow.png
1917 :align: center
1918
1919
1920Survol du code PyGTK
1921~~~~~~~~~~~~~~~~~~~~
1922
1923Vous pouvez constater que la majorité du code est en rapport avec PyGTK.
1924Sa structure est très similaire pour les différentes fenêtres. Les écrans
1925de cette application sont conçus avec le créateur d'interface graphiques Glade.
1926Vous devriez donner des noms appropriés aux widgets que vous allez utiliser dans
1927votre code. Dans la fenêtre principale, tous les éléments de menu ont des noms
1928du type : circulation, catalog, member, quit et about.
1929
1930La classe ``gtk.glade.XML`` est utilisée pour analyser le fichier Glade, et donc
1931pour créer les objets widgets de l'interface graphique. Voici comment faire ::
1932
1933 import gtk.glade
1934 xmlobj = gtk.glade.XML('/path/to/file.glade')
1935 widget = xmlobj.get_widget('widget_name')
1936
1937Dans mainwindow.py, vous pouvez voir le code suivant ::
1938
1939 curdir = os.path.abspath(os.path.dirname(__file__))
1940 xml = os.path.join(curdir, 'glade', 'mainwindow.glade')
1941 xmlobj = gtk.glade.XML(xml)
1942
1943 self.mainwindow = xmlobj.get_widget('mainwindow')
1944
1945Le nom du widget fenêtre principal est `mainwindow`. Les autres widgets sont
1946créés de la même manière ::
1947
1948 circulation = xmlobj.get_widget('circulation')
1949 member = xmlobj.get_widget('member')
1950 quit = xmlobj.get_widget('quit')
1951 catalog = xmlobj.get_widget('catalog')
1952 about = xmlobj.get_widget('about')
1953
1954Ensuite ces widgets sont connectés à certains événements ::
1955
1956 self.mainwindow.connect('delete_event', self.delete_event)
1957 quit.connect('activate', self.delete_event)
1958 circulation.connect('activate', self.on_circulation_activate)
1959 member.connect('activate', self.on_member_activate)
1960 catalog.connect('activate', self.on_catalog_activate)
1961 about.connect('activate', self.on_about_activate)
1962
1963L'événement `delete_event` est celui correspondant à la fermeture de la fenêtre lors
1964de l'appui sur le bouton de fermeture. L'événement `activate` est émis lorsque
1965le menu est sélectionné. Les widgets sont connectés à des fonctions de rappel
1966pour certains événements.
1967
1968Vous pouvez voir dans le code ci-dessus que la fenêtre principale est connectée
1969à la méthode `on_delete_event` pour l'événement `delete_event`. Le widget `quit`
1970est aussi connecté aux mêmes méthodes pour l'événement `activate` ::
1971
1972 def on_delete_event(self, *args):
1973 gtk.main_quit()
1974
1975La fonction de rappel lance juste la fonction `main_quit`.
1976
1977
1978Le code
1979~~~~~~~
1980
1981Voici `zcalib.py` ::
1982
1983 import registry
1984 import mainwindow
1985
1986 if __name__ == '__main__':
1987 registry.initialize()
1988 try:
1989 mainwindow.main()
1990 except KeyboardInterrupt:
1991 import sys
1992 sys.exit(1)
1993
1994Ici, deux modules sont importés : `registry` et `mainwindow`.
1995Ensuite le registre est initialisé et la fonction `main` de la fenêtre
1996principale est appelée. Si l'utilisateur essaye de fermer l'application en
1997appuyant sur `Ctrl-C`, celle-ci s'arrête normalement car nous avons intercepté
1998l'exception `KeyboardInterrupt`.
1999
2000Voici `registry.py` ::
2001
2002 import sys
2003 from zope.component import getGlobalSiteManager
2004
2005 from interfaces import IMember
2006 from interfaces import IBook
2007 from interfaces import ICirculation
2008 from interfaces import IDbOperation
2009
2010
2011 def initialize_rdb():
2012 from interfaces import IRelationalDatabase
2013 from relationaldatabase import RelationalDatabase
2014 from member import MemberRDbOperation
2015 from catalog import BookRDbOperation
2016 from circulation import CirculationRDbOperation
2017
2018 gsm = getGlobalSiteManager()
2019 db = RelationalDatabase()
2020 gsm.registerUtility(db, IRelationalDatabase)
2021
2022 gsm.registerAdapter(MemberRDbOperation,
2023 (IMember,),
2024 IDbOperation)
2025
2026 gsm.registerAdapter(BookRDbOperation,
2027 (IBook,),
2028 IDbOperation)
2029
2030 gsm.registerAdapter(CirculationRDbOperation,
2031 (ICirculation,),
2032 IDbOperation)
2033
2034 def initialize_odb():
2035 from interfaces import IObjectDatabase
2036 from objectdatabase import ObjectDatabase
2037 from member import MemberODbOperation
2038 from catalog import BookODbOperation
2039 from circulation import CirculationODbOperation
2040
2041 gsm = getGlobalSiteManager()
2042 db = ObjectDatabase()
2043 gsm.registerUtility(db, IObjectDatabase)
2044
2045 gsm.registerAdapter(MemberODbOperation,
2046 (IMember,),
2047 IDbOperation)
2048
2049 gsm.registerAdapter(BookODbOperation,
2050 (IBook,),
2051 IDbOperation)
2052
2053 gsm.registerAdapter(CirculationODbOperation,
2054 (ICirculation,),
2055 IDbOperation)
2056
2057 def check_use_relational_db():
2058 use_rdb = False
2059 try:
2060 arg = sys.argv[1]
2061 if arg == '-r':
2062 return True
2063 except IndexError:
2064 pass
2065 return use_rdb
2066
2067 def initialize():
2068 use_rdb = check_use_relational_db()
2069 if use_rdb:
2070 initialize_rdb()
2071 else:
2072 initialize_odb()
2073
2074Observez la fonction `initialize` que nous appelons depuis le module principal
2075`zcalib.py`. Cette fonction commence par vérifier quelle base de données
2076utiliser : une base relationnelle (RDB) ou une base objet (ODB). Cette
2077vérification est effectuée dans la fonction `check_use_relational_db`. Si
2078l'option `-r` est passé dans la ligne de commandes, elle appelera la fonction
2079`initialize_rdb`, sinon `initialize_odb`. Si la fonction RDB est appelée, elle
2080configure tous les composants liés à la base relationnelle. Si la fonction ODB est appelée,
2081elle configure tous les composants liés à la base objet.
2082
2083Voici `mainwindow.py` ::
2084
2085 import os
2086 import gtk
2087 import gtk.glade
2088
2089 from circulationwindow import circulationwindow
2090 from catalogwindow import catalogwindow
2091 from memberwindow import memberwindow
2092
2093 class MainWindow(object):
2094
2095 def __init__(self):
2096 curdir = os.path.abspath(os.path.dirname(__file__))
2097 xml = os.path.join(curdir, 'glade', 'mainwindow.glade')
2098 xmlobj = gtk.glade.XML(xml)
2099
2100 self.mainwindow = xmlobj.get_widget('mainwindow')
2101 circulation = xmlobj.get_widget('circulation')
2102 member = xmlobj.get_widget('member')
2103 quit = xmlobj.get_widget('quit')
2104 catalog = xmlobj.get_widget('catalog')
2105 about = xmlobj.get_widget('about')
2106
2107 self.mainwindow.connect('delete_event', self.delete_event)
2108 quit.connect('activate', self.delete_event)
2109
2110 circulation.connect('activate', self.on_circulation_activate)
2111 member.connect('activate', self.on_member_activate)
2112 catalog.connect('activate', self.on_catalog_activate)
2113 about.connect('activate', self.on_about_activate)
2114
2115 def delete_event(self, *args):
2116 gtk.main_quit()
2117
2118 def on_circulation_activate(self, *args):
2119 circulationwindow.show_all()
2120
2121 def on_member_activate(self, *args):
2122 memberwindow.show_all()
2123
2124 def on_catalog_activate(self, *args):
2125 catalogwindow.show_all()
2126
2127 def on_about_activate(self, *args):
2128 pass
2129
2130 def run(self):
2131 self.mainwindow.show_all()
2132
2133 def main():
2134 mainwindow = MainWindow()
2135 mainwindow.run()
2136 gtk.main()
2137
2138
2139La fonction `main` crée une instance de la classe `MainWindow` qui initialise
2140tous les widgets.
2141
2142Voici `memberwindow.py` ::
2143
2144 import os
2145 import gtk
2146 import gtk.glade
2147
2148 from zope.component import getAdapter
2149
2150 from components import Member
2151 from interfaces import IDbOperation
2152
2153
2154 class MemberWindow(object):
2155
2156 def __init__(self):
2157 curdir = os.path.abspath(os.path.dirname(__file__))
2158 xml = os.path.join(curdir, 'glade', 'memberwindow.glade')
2159 xmlobj = gtk.glade.XML(xml)
2160
2161 self.memberwindow = xmlobj.get_widget('memberwindow')
2162 self.number = xmlobj.get_widget('number')
2163 self.name = xmlobj.get_widget('name')
2164 add = xmlobj.get_widget('add')
2165 update = xmlobj.get_widget('update')
2166 delete = xmlobj.get_widget('delete')
2167 close = xmlobj.get_widget('close')
2168 self.treeview = xmlobj.get_widget('treeview')
2169
2170 self.memberwindow.connect('delete_event', self.on_delete_event)
2171 add.connect('clicked', self.on_add_clicked)
2172 update.connect('clicked', self.on_update_clicked)
2173 delete.connect('clicked', self.on_delete_clicked)
2174 close.connect('clicked', self.on_delete_event)
2175
2176 self.initialize_list()
2177
2178 def show_all(self):
2179 self.populate_list_store()
2180 self.memberwindow.show_all()
2181
2182 def populate_list_store(self):
2183 self.list_store.clear()
2184 member = Member()
2185 memberdboperation = getAdapter(member, IDbOperation)
2186 members = memberdboperation.get()
2187 for member in members:
2188 number = member.number
2189 name = member.name
2190 self.list_store.append((member, number, name,))
2191
2192 def on_delete_event(self, *args):
2193 self.memberwindow.hide()
2194 return True
2195
2196 def initialize_list(self):
2197 self.list_store = gtk.ListStore(object, str, str)
2198 self.treeview.set_model(self.list_store)
2199 tvcolumn = gtk.TreeViewColumn('Member Number')
2200 self.treeview.append_column(tvcolumn)
2201
2202 cell = gtk.CellRendererText()
2203 tvcolumn.pack_start(cell, True)
2204 tvcolumn.add_attribute(cell, 'text', 1)
2205
2206 tvcolumn = gtk.TreeViewColumn('Member Name')
2207 self.treeview.append_column(tvcolumn)
2208
2209 cell = gtk.CellRendererText()
2210 tvcolumn.pack_start(cell, True)
2211 tvcolumn.add_attribute(cell, 'text', 2)
2212
2213 def on_add_clicked(self, *args):
2214 number = self.number.get_text()
2215 name = self.name.get_text()
2216 member = Member()
2217 member.number = number
2218 member.name = name
2219 self.add(member)
2220 self.list_store.append((member, number, name,))
2221
2222 def add(self, member):
2223 memberdboperation = getAdapter(member, IDbOperation)
2224 memberdboperation.add()
2225
2226 def on_update_clicked(self, *args):
2227 number = self.number.get_text()
2228 name = self.name.get_text()
2229 treeselection = self.treeview.get_selection()
2230 model, iter = treeselection.get_selected()
2231 if not iter:
2232 return
2233 member = self.list_store.get_value(iter, 0)
2234 member.number = number
2235 member.name = name
2236 self.update(member)
2237 self.list_store.set(iter, 1, number, 2, name)
2238
2239 def update(self, member):
2240 memberdboperation = getAdapter(member, IDbOperation)
2241 memberdboperation.update()
2242
2243 def on_delete_clicked(self, *args):
2244 treeselection = self.treeview.get_selection()
2245 model, iter = treeselection.get_selected()
2246 if not iter:
2247 return
2248 member = self.list_store.get_value(iter, 0)
2249 self.delete(member)
2250 self.list_store.remove(iter)
2251
2252 def delete(self, member):
2253 memberdboperation = getAdapter(member, IDbOperation)
2254 memberdboperation.delete()
2255
2256 memberwindow = MemberWindow()
2257
2258Voici `components.py` ::
2259
2260 from zope.interface import implements
2261
2262 from interfaces import IBook
2263 from interfaces import IMember
2264 from interfaces import ICirculation
2265
2266 class Book(object):
2267
2268 implements(IBook)
2269
2270 barcode = ""
2271 title = ""
2272 author = ""
2273
2274 class Member(object):
2275
2276 implements(IMember)
2277
2278 number = ""
2279 name = ""
2280
2281 class Circulation(object):
2282
2283 implements(ICirculation)
2284
2285 book = Book()
2286 member = Member()
2287
2288Voici `interfaces.py` ::
2289
2290 from zope.interface import Interface
2291 from zope.interface import Attribute
2292
2293
2294 class IBook(Interface):
2295
2296 barcode = Attribute("Barcode")
2297 author = Attribute("Author of book")
2298 title = Attribute("Title of book")
2299
2300
2301 class IMember(Interface):
2302
2303 number = Attribute("ID number")
2304 name = Attribute("Name of member")
2305
2306
2307 class ICirculation(Interface):
2308
2309 book = Attribute("A book")
2310 member = Attribute("A member")
2311
2312
2313 class IRelationalDatabase(Interface):
2314
2315 def commit():
2316 pass
2317
2318 def rollback():
2319 pass
2320
2321 def cursor():
2322 pass
2323
2324 def get_next_id():
2325 pass
2326
2327
2328 class IObjectDatabase(Interface):
2329
2330 def commit():
2331 pass
2332
2333 def rollback():
2334 pass
2335
2336 def container():
2337 pass
2338
2339 def get_next_id():
2340 pass
2341
2342
2343 class IDbOperation(Interface):
2344
2345 def get():
2346 pass
2347
2348 def add():
2349 pass
2350
2351 def update():
2352 pass
2353
2354 def delete():
2355 pass
2356
2357Here is the `member.py` ::
2358
2359 from zope.interface import implements
2360 from zope.component import getUtility
2361 from zope.component import adapts
2362
2363 from components import Member
2364
2365 from interfaces import IRelationalDatabase
2366 from interfaces import IObjectDatabase
2367 from interfaces import IMember
2368 from interfaces import IDbOperation
2369
2370
2371 class MemberRDbOperation(object):
2372
2373 implements(IDbOperation)
2374 adapts(IMember)
2375
2376 def __init__(self, member):
2377 self.member = member
2378
2379 def get(self):
2380 db = getUtility(IRelationalDatabase)
2381 cr = db.cursor()
2382 number = self.member.number
2383 if number:
2384 cr.execute("""SELECT
2385 id,
2386 number,
2387 name
2388 FROM members
2389 WHERE number = ?""",
2390 (number,))
2391 else:
2392 cr.execute("""SELECT
2393 id,
2394 number,
2395 name
2396 FROM members""")
2397 rst = cr.fetchall()
2398 cr.close()
2399 members = []
2400 for record in rst:
2401 id = record['id']
2402 number = record['number']
2403 name = record['name']
2404 member = Member()
2405 member.id = id
2406 member.number = number
2407 member.name = name
2408 members.append(member)
2409 return members
2410
2411 def add(self):
2412 db = getUtility(IRelationalDatabase)
2413 cr = db.cursor()
2414 next_id = db.get_next_id("members")
2415 number = self.member.number
2416 name = self.member.name
2417 cr.execute("""INSERT INTO members
2418 (id, number, name)
2419 VALUES (?, ?, ?)""",
2420 (next_id, number, name))
2421 cr.close()
2422 db.commit()
2423 self.member.id = next_id
2424
2425 def update(self):
2426 db = getUtility(IRelationalDatabase)
2427 cr = db.cursor()
2428 number = self.member.number
2429 name = self.member.name
2430 id = self.member.id
2431 cr.execute("""UPDATE members
2432 SET
2433 number = ?,
2434 name = ?
2435 WHERE id = ?""",
2436 (number, name, id))
2437 cr.close()
2438 db.commit()
2439
2440 def delete(self):
2441 db = getUtility(IRelationalDatabase)
2442 cr = db.cursor()
2443 id = self.member.id
2444 cr.execute("""DELETE FROM members
2445 WHERE id = ?""",
2446 (id,))
2447 cr.close()
2448 db.commit()
2449
2450
2451 class MemberODbOperation(object):
2452
2453 implements(IDbOperation)
2454 adapts(IMember)
2455
2456 def __init__(self, member):
2457 self.member = member
2458
2459 def get(self):
2460 db = getUtility(IObjectDatabase)
2461 zcalibdb = db.container()
2462 members = zcalibdb['members']
2463 return members.values()
2464
2465 def add(self):
2466 db = getUtility(IObjectDatabase)
2467 zcalibdb = db.container()
2468 members = zcalibdb['members']
2469 number = self.member.number
2470 if number in [x.number for x in members.values()]:
2471 db.rollback()
2472 raise Exception("Duplicate key")
2473 next_id = db.get_next_id('members')
2474 self.member.id = next_id
2475 members[next_id] = self.member
2476 db.commit()
2477
2478 def update(self):
2479 db = getUtility(IObjectDatabase)
2480 zcalibdb = db.container()
2481 members = zcalibdb['members']
2482 id = self.member.id
2483 members[id] = self.member
2484 db.commit()
2485
2486 def delete(self):
2487 db = getUtility(IObjectDatabase)
2488 zcalibdb = db.container()
2489 members = zcalibdb['members']
2490 id = self.member.id
2491 del members[id]
2492 db.commit()
2493
2494
2495PySQLite
2496~~~~~~~~
2497
2498ZODB
2499~~~~
2500
2501Conclusions
2502~~~~~~~~~~~
18362503
1837Reference2504Reference
1838---------2505---------
18392506
18402507
1841Attribute2508adaptedBy
1842~~~~~~~~~2509~~~~~~~~~
18432510
1844Using this class, you can define normal attribute in an interface.2511Cette fonction permet de trouver les interfaces adaptées.
18452512
1846 - Location: ``zope.interface``2513 - Emplacement : ``zope.component``
18472514
1848 - Signature: `Attribute(name, doc='')`2515 - Signature : `adaptedBy(object)`
18492516
1850Example::2517Exemple ::
18512518
1852 >>> from zope.interface import Attribute2519 >>> from zope.interface import implements
1853 >>> from zope.interface import Interface2520 >>> from zope.component import adapts
18542521 >>> from zope.component import adaptedBy
1855 >>> class IPerson(Interface):2522
1856 ...2523 >>> class FrontDeskNG(object):
1857 ... name = Attribute("Name of person")2524 ...
1858 ... email = Attribute("Email Address")2525 ... implements(IDesk)
18592526 ... adapts(IGuest)
18602527 ...
1861Declaration2528 ... def __init__(self, guest):
1862~~~~~~~~~~~2529 ... self.guest = guest
18632530
1864Need not to use directly.2531 >>> adaptedBy(FrontDeskNG)
18652532 (<InterfaceClass __builtin__.IGuest>,)
18662533
1867Interface2534
1868~~~~~~~~~2535adapter
18692536~~~~~~~
1870Using this class, you can define an interface. To define an2537
1871interface, just inherit from ``Interface`` class.2538Un adaptateur peut être n'importe quel objet appelable. Vous pouvez
18722539utiliser le décorateur `adapter` pour déclarer qu'un objet appelable s'adapte à
1873 - Location: ``zope.interface``2540des interfaces (ou des classes).
18742541
1875 - Signature: `Interface(name, doc='')`2542 - Emplacement : ``zope.component``
18762543
1877Example 1::2544 - Signature : `adapter(*interfaces)`
18782545
1879 >>> from zope.interface import Attribute2546Exemple ::
1880 >>> from zope.interface import Interface2547
18812548 >>> from zope.interface import Attribute
1882 >>> class IPerson(Interface):2549 >>> from zope.interface import Interface
1883 ...2550 >>> from zope.interface import implementer
1884 ... name = Attribute("Name of person")2551 >>> from zope.component import adapter
1885 ... email = Attribute("Email Address")2552 >>> from zope.interface import implements
18862553
18872554 >>> class IJob(Interface):
1888Example 2::2555 ... """A job"""
18892556
1890 >>> from zope.interface import Interface2557 >>> class Job(object):
18912558 ... implements(IJob)
1892 >>> class IHost(Interface):2559
1893 ...2560 >>> class IPerson(Interface):
1894 ... def goodmorning(guest):2561 ...
1895 ... """Say good morning to guest"""2562 ... name = Attribute("Name")
2563 ... job = Attribute("Job")
2564
2565 >>> class Person(object):
2566 ... implements(IPerson)
2567 ...
2568 ... name = None
2569 ... job = None
2570
2571 >>> @implementer(IJob)
2572 ... @adapter(IPerson)
2573 ... def personJob(person):
2574 ... return person.job
2575
2576 >>> jack = Person()
2577 >>> jack.name = "Jack"
2578 >>> jack.job = Job()
2579 >>> personJob(jack) #doctest: +ELLIPSIS
2580 <Job object at ...>
18962581
18972582
1898adapts2583adapts
1899~~~~~~2584~~~~~~
19002585
1901This function helps to declare adapter classes.2586Cette fonction permet de déclarer les classes adaptateurs.
19022587
1903 - Location: ``zope.component``2588 - Emplacement : ``zope.component``
19042589
1905 - Signature: `adapts(*interfaces)`2590 - Signature : `adapts(*interfaces)`
19062591
1907Example::2592Exemple ::
19082593
1909 >>> from zope.interface import implements2594 >>> from zope.interface import implements
1910 >>> from zope.component import adapts2595 >>> from zope.component import adapts
19112596
1912 >>> class GuestRegistrarNG(object):2597 >>> class FrontDeskNG(object):
1913 ...2598 ...
1914 ... implements(IRegistrar)2599 ... implements(IDesk)
1915 ... adapts(IGuest)2600 ... adapts(IGuest)
1916 ...2601 ...
1917 ... def __init__(self, guest):2602 ... def __init__(self, guest):
@@ -1919,7 +2604,7 @@
1919 ...2604 ...
1920 ... def register(self):2605 ... def register(self):
1921 ... next_id = get_next_id()2606 ... next_id = get_next_id()
1922 ... guests_db[next_id] = {2607 ... bookings_db[next_id] = {
1923 ... 'name': guest.name,2608 ... 'name': guest.name,
1924 ... 'place': guest.place,2609 ... 'place': guest.place,
1925 ... 'phone': guest.phone2610 ... 'phone': guest.phone
@@ -1929,15 +2614,15 @@
1929alsoProvides2614alsoProvides
1930~~~~~~~~~~~~2615~~~~~~~~~~~~
19312616
1932Declare interfaces declared directly for an object. The arguments2617Déclare des interfaces additionnelles fournies par un objet. Les arguments après
1933after the object are one or more interfaces. The interfaces given are2618l'objet sont une ou plusieurs interfaces. Les interfaces données sont ajoutées
1934added to the interfaces previously declared for the object.2619aux interfaces précédemment déclarées pour l'objet.
19352620
1936 - Location: ``zope.interface``2621 - Emplacement : ``zope.interface``
19372622
1938 - Signature: `alsoProvides(object, *interfaces)`2623 - Signature : `alsoProvides(object, *interfaces)`
19392624
1940Example::2625Exemple ::
19412626
1942 >>> from zope.interface import Attribute2627 >>> from zope.interface import Attribute
1943 >>> from zope.interface import Interface2628 >>> from zope.interface import Interface
@@ -1954,7 +2639,7 @@
19542639
1955 >>> class Person(object):2640 >>> class Person(object):
1956 ...2641 ...
1957 ... implements(IRegistrar)2642 ... implements(IDesk)
1958 ... name = u""2643 ... name = u""
19592644
1960 >>> jack = Person()2645 >>> jack = Person()
@@ -1962,25 +2647,48 @@
1962 >>> jack.college = "New College"2647 >>> jack.college = "New College"
1963 >>> alsoProvides(jack, IStudent)2648 >>> alsoProvides(jack, IStudent)
19642649
1965 You can test it like this:2650 Vous pouvez tester de cette façon:
19662651
1967 >>> from zope.interface import providedBy2652 >>> from zope.interface import providedBy
1968 >>> IStudent in providedBy(jack)2653 >>> IStudent in providedBy(jack)
1969 True2654 True
19702655
19712656
2657Attribute
2658~~~~~~~~~
2659
2660En utilisant cette classe, vous pouvez définir des attributs dans une interface.
2661
2662 - Emplacement : ``zope.interface``
2663
2664 - Signature : `Attribute(name, doc='')`
2665
2666 - Voir aussi : `Interface`_
2667
2668Exemple ::
2669
2670 >>> from zope.interface import Attribute
2671 >>> from zope.interface import Interface
2672
2673 >>> class IPerson(Interface):
2674 ...
2675 ... name = Attribute("Name of person")
2676 ... email = Attribute("Email Address")
2677
2678
1972classImplements2679classImplements
1973~~~~~~~~~~~~~~~2680~~~~~~~~~~~~~~~
19742681
1975Declare additional interfaces implemented for instances of a class.2682Déclare des interfaces additionnelles qui doivent être fournies par les
1976The arguments after the class are one or more interfaces. The2683instances d'une classe. Les arguments après la classe sont une ou plusieurs
1977interfaces given are added to any interfaces previously declared.2684interfaces. Les interfaces données sont ajoutées aux interfaces précédemment
19782685déclarées.
1979 - Location: ``zope.interface``2686
19802687 - Emplacement : ``zope.interface``
1981 - Signature: `classImplements(cls, *interfaces)`2688
19822689 - Signature : `classImplements(cls, *interfaces)`
1983Example::2690
2691Exemple ::
19842692
1985 >>> from zope.interface import Attribute2693 >>> from zope.interface import Attribute
1986 >>> from zope.interface import Interface2694 >>> from zope.interface import Interface
@@ -1997,7 +2705,7 @@
19972705
1998 >>> class Person(object):2706 >>> class Person(object):
1999 ...2707 ...
2000 ... implements(IRegistrar)2708 ... implements(IDesk)
2001 ... name = u""2709 ... name = u""
2002 ... college = u""2710 ... college = u""
20032711
@@ -2006,7 +2714,7 @@
2006 >>> jack.name = "Jack"2714 >>> jack.name = "Jack"
2007 >>> jack.college = "New College"2715 >>> jack.college = "New College"
20082716
2009 You can test it like this:2717 Vous pouvez tester de cette façon :
20102718
2011 >>> from zope.interface import providedBy2719 >>> from zope.interface import providedBy
2012 >>> IStudent in providedBy(jack)2720 >>> IStudent in providedBy(jack)
@@ -2016,15 +2724,16 @@
2016classImplementsOnly2724classImplementsOnly
2017~~~~~~~~~~~~~~~~~~~2725~~~~~~~~~~~~~~~~~~~
20182726
2019Declare the only interfaces implemented by instances of a class. The2727Déclare les seules interfaces qui devront être fournies par les instances d'une
2020arguments after the class are one or more interfaces. The interfaces2728classe. Les arguments après la classe sont une ou plusieurs interfaces. Les
2021given replace any previous declarations.2729interfaces fournies vont remplacer toutes les interfaces des déclarations
20222730précédentes.
2023 - Location: ``zope.interface``2731
20242732 - Emplacement : ``zope.interface``
2025 - Signature: `classImplementsOnly(cls, *interfaces)`2733
20262734 - Signature : `classImplementsOnly(cls, *interfaces)`
2027Example::2735
2736Exemple ::
20282737
2029 >>> from zope.interface import Attribute2738 >>> from zope.interface import Attribute
2030 >>> from zope.interface import Interface2739 >>> from zope.interface import Interface
@@ -2048,7 +2757,7 @@
2048 >>> jack = Person()2757 >>> jack = Person()
2049 >>> jack.college = "New College"2758 >>> jack.college = "New College"
20502759
2051 You can test it like this:2760 Vous pouvez tester de cette façon :
20522761
2053 >>> from zope.interface import providedBy2762 >>> from zope.interface import providedBy
2054 >>> IPerson in providedBy(jack)2763 >>> IPerson in providedBy(jack)
@@ -2060,16 +2769,16 @@
2060classProvides2769classProvides
2061~~~~~~~~~~~~~2770~~~~~~~~~~~~~
20622771
2063Normally if a class implements a particular interface, the instance of2772Normalement si une classe implémente une interface particulière, les instances
2064that class will provide the interface implemented by that class. But2773de cette classe fourniront l'interface implémentée par la classe. Mais si vous
2065if you want a class to be provided by an interface, you can declare it2774voulez qu'une classe fournisse une interface, vous pouvez le déclarer grâce à la
2066using ``classProvides`` function.2775fonction ``classProvides``.
20672776
2068 - Location: ``zope.interface``2777 - Emplacement : ``zope.interface``
20692778
2070 - Signature: `classProvides(*interfaces)`2779 - Signature : `classProvides(*interfaces)`
20712780
2072Example::2781Exemple ::
20732782
2074 >>> from zope.interface import Attribute2783 >>> from zope.interface import Attribute
2075 >>> from zope.interface import Interface2784 >>> from zope.interface import Interface
@@ -2084,7 +2793,7 @@
2084 ... classProvides(IPerson)2793 ... classProvides(IPerson)
2085 ... name = u"Jack"2794 ... name = u"Jack"
20862795
2087 You can test it like this:2796 Vous pouvez tester de cette façon :
20882797
2089 >>> from zope.interface import providedBy2798 >>> from zope.interface import providedBy
2090 >>> IPerson in providedBy(Person)2799 >>> IPerson in providedBy(Person)
@@ -2094,26 +2803,39 @@
2094ComponentLookupError2803ComponentLookupError
2095~~~~~~~~~~~~~~~~~~~~2804~~~~~~~~~~~~~~~~~~~~
20962805
2806C'est l'exception levée quand une recherche de composant échoue.
2807
2808Exemple ::
2809
2810 >>> class IPerson(Interface):
2811 ...
2812 ... name = Attribute("Name of person")
2813
2814 >>> person = object()
2815 >>> getAdapter(person, IPerson, 'not-exists') #doctest: +ELLIPSIS
2816 Traceback (most recent call last):
2817 ...
2818 ComponentLookupError: ...
2819
20972820
2098createObject2821createObject
2099~~~~~~~~~~~~2822~~~~~~~~~~~~
21002823
2101Create an object using a factory.2824Crée un objet en utilisant une fabrique.
21022825
2103Finds the named factory in the current site and calls it with the2826Cette fonction trouve une fabrique nommée dans le site courant et l'appelle avec
2104given arguments. If a matching factory cannot be found raises2827les arguments donnés. Si la bonne fabrique ne peut pas être trouvée, une erreur
2105ComponentLookupError. Returns the created object.2828``ComponentLookupError`` est déclenchée. Sinon l'objet créé est renvoyé.
21062829
2107A context keyword argument can be provided to cause the factory to be2830Un argument mot-clé contextuel peut être fourni pour rechercher une fabrique
2108looked up in a location other than the current site. (Of course, this2831dans un emplacement différent du site courant. (Bien sûr, cela signifie qu'il
2109means that it is impossible to pass a keyword argument named "context"2832est impossible de transmettre à la fabrique un argument mot-clé nommé « context ».
2110to the factory.2833
21112834 - Emplacement : ``zope.component``
2112 - Location: ``zope.component``2835
21132836 - Signature : `createObject(factory_name, *args, **kwargs)`
2114 - Signature: `createObject(factory_name, *args, **kwargs)`2837
21152838Exemple ::
2116Example::
21172839
2118 >>> from zope.interface import Attribute2840 >>> from zope.interface import Attribute
2119 >>> from zope.interface import Interface2841 >>> from zope.interface import Interface
@@ -2146,17 +2868,22 @@
2146 <FakeDb object at ...>2868 <FakeDb object at ...>
21472869
21482870
2871Declaration
2872~~~~~~~~~~~
2873
2874N'a pas besoin d'être utilisé directement.
2875
2876
2149directlyProvidedBy2877directlyProvidedBy
2150~~~~~~~~~~~~~~~~~~2878~~~~~~~~~~~~~~~~~~
21512879
2152This function will return the interfaces directly provided by the2880Cette fonction renvoie les interfaces fournies directement par un objet donné.
2153given object.2881
21542882 - Emplacement : ``zope.interface``
2155 - Location: ``zope.interface``2883
21562884 - Signature : `directlyProvidedBy(object)`
2157 - Signature: `directlyProvidedBy(object)`2885
21582886Exemple ::
2159Example::
21602887
2161 >>> from zope.interface import Attribute2888 >>> from zope.interface import Attribute
2162 >>> from zope.interface import Interface2889 >>> from zope.interface import Interface
@@ -2196,15 +2923,15 @@
2196directlyProvides2923directlyProvides
2197~~~~~~~~~~~~~~~~2924~~~~~~~~~~~~~~~~
21982925
2199Declare interfaces declared directly for an object. The arguments2926Déclare que des interfaces sont fournies directement par un objet. Les arguments
2200after the object are one or more interfaces. The interfaces given2927après l'objet sont une ou plusieurs interfaces. Les interfaces données
2201replace interfaces previously declared for the object.2928remplacent celles précédemment déclarées pour l'objet.
22022929
2203 - Location: ``zope.interface``2930 - Emplacement : ``zope.interface``
22042931
2205 - Signature: `directlyProvides(object, *interfaces)`2932 - Signature : `directlyProvides(object, *interfaces)`
22062933
2207Example::2934Exemple ::
22082935
2209 >>> from zope.interface import Attribute2936 >>> from zope.interface import Attribute
2210 >>> from zope.interface import Interface2937 >>> from zope.interface import Interface
@@ -2262,21 +2989,22 @@
2262getAdapter2989getAdapter
2263~~~~~~~~~~2990~~~~~~~~~~
22642991
2265Get a named adapter to an interface for an object. Returns an adapter2992Cette fonction récupère un adaptateur (nommé) vers une interface, pour un objet
2266that can adapt object to interface. If a matching adapter cannot be2993donné. Elle renvoie un adaptateur qui peut adapter les objets à l'interface
2267found, raises ``ComponentLookupError`` .2994voulue. Si aucun adaptateur ne peut être trouvé, une erreur
22682995``ComponentLookupError`` est émise.
2269 - Location: ``zope.interface``2996
22702997 - Emplacement : ``zope.interface``
2271 - Signature: `getAdapter(object, interface=Interface, name=u'', context=None)`2998
22722999 - Signature : `getAdapter(object, interface=Interface, name=u'', context=None)`
2273Example::3000
3001Exemple ::
22743002
2275 >>> from zope.interface import Attribute3003 >>> from zope.interface import Attribute
2276 >>> from zope.interface import Interface3004 >>> from zope.interface import Interface
22773005
2278 >>> class IRegistrar(Interface):3006 >>> class IDesk(Interface):
2279 ... """A registrar will register object's details"""3007 ... """A frontdesk will register object's details"""
2280 ...3008 ...
2281 ... def register():3009 ... def register():
2282 ... """Register object's details"""3010 ... """Register object's details"""
@@ -2285,9 +3013,9 @@
2285 >>> from zope.interface import implements3013 >>> from zope.interface import implements
2286 >>> from zope.component import adapts3014 >>> from zope.component import adapts
22873015
2288 >>> class GuestRegistrarNG(object):3016 >>> class FrontDeskNG(object):
2289 ...3017 ...
2290 ... implements(IRegistrar)3018 ... implements(IDesk)
2291 ... adapts(IGuest)3019 ... adapts(IGuest)
2292 ...3020 ...
2293 ... def __init__(self, guest):3021 ... def __init__(self, guest):
@@ -2295,7 +3023,7 @@
2295 ...3023 ...
2296 ... def register(self):3024 ... def register(self):
2297 ... next_id = get_next_id()3025 ... next_id = get_next_id()
2298 ... guests_db[next_id] = {3026 ... bookings_db[next_id] = {
2299 ... 'name': guest.name,3027 ... 'name': guest.name,
2300 ... 'place': guest.place,3028 ... 'place': guest.place,
2301 ... 'phone': guest.phone3029 ... 'phone': guest.phone
@@ -2310,31 +3038,33 @@
2310 ... self.place = place3038 ... self.place = place
23113039
2312 >>> jack = Guest("Jack", "Bangalore")3040 >>> jack = Guest("Jack", "Bangalore")
2313 >>> jack_registrar = GuestRegistrarNG(jack)3041 >>> jack_frontdesk = FrontDeskNG(jack)
23143042
2315 >>> IRegistrar.providedBy(jack_registrar)3043 >>> IDesk.providedBy(jack_frontdesk)
2316 True3044 True
23173045
2318 >>> from zope.component import getGlobalSiteManager3046 >>> from zope.component import getGlobalSiteManager
2319 >>> gsm = getGlobalSiteManager()3047 >>> gsm = getGlobalSiteManager()
2320 >>> gsm.registerAdapter(GuestRegistrarNG,3048 >>> gsm.registerAdapter(FrontDeskNG,
2321 ... (IGuest,), IRegistrar, 'ng')3049 ... (IGuest,), IDesk, 'ng')
23223050
2323 >>> getAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS3051 >>> getAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS
2324 <GuestRegistrarNG object at ...>3052 <FrontDeskNG object at ...>
23253053
23263054
2327getAdapterInContext3055getAdapterInContext
2328~~~~~~~~~~~~~~~~~~~3056~~~~~~~~~~~~~~~~~~~
23293057
2330Instead of this function, use `context` argument of `getAdapter`_3058Au lieu d'utiliser cette fonction, utilisez `getAdapter`_ avec un argument
2331function.3059`context`.
23323060
2333 - Location: ``zope.component``3061 - Emplacement : ``zope.component``
23343062
2335 - Signature: `getAdapterInContext(object, interface, context)`3063 - Signature : `getAdapterInContext(object, interface, context)`
23363064
2337Example::3065 - Voir aussi : `queryAdapterInContext`_
3066
3067Exemple ::
23383068
2339 >>> from zope.component.globalregistry import BaseGlobalComponents3069 >>> from zope.component.globalregistry import BaseGlobalComponents
2340 >>> from zope.component import IComponentLookup3070 >>> from zope.component import IComponentLookup
@@ -2352,8 +3082,8 @@
2352 >>> from zope.interface import Attribute3082 >>> from zope.interface import Attribute
2353 >>> from zope.interface import Interface3083 >>> from zope.interface import Interface
23543084
2355 >>> class IRegistrar(Interface):3085 >>> class IDesk(Interface):
2356 ... """A registrar will register object's details"""3086 ... """A frontdesk will register object's details"""
2357 ...3087 ...
2358 ... def register():3088 ... def register():
2359 ... """Register object's details"""3089 ... """Register object's details"""
@@ -2362,9 +3092,9 @@
2362 >>> from zope.interface import implements3092 >>> from zope.interface import implements
2363 >>> from zope.component import adapts3093 >>> from zope.component import adapts
23643094
2365 >>> class GuestRegistrarNG(object):3095 >>> class FrontDeskNG(object):
2366 ...3096 ...
2367 ... implements(IRegistrar)3097 ... implements(IDesk)
2368 ... adapts(IGuest)3098 ... adapts(IGuest)
2369 ...3099 ...
2370 ... def __init__(self, guest):3100 ... def __init__(self, guest):
@@ -2372,7 +3102,7 @@
2372 ...3102 ...
2373 ... def register(self):3103 ... def register(self):
2374 ... next_id = get_next_id()3104 ... next_id = get_next_id()
2375 ... guests_db[next_id] = {3105 ... bookings_db[next_id] = {
2376 ... 'name': guest.name,3106 ... 'name': guest.name,
2377 ... 'place': guest.place,3107 ... 'place': guest.place,
2378 ... 'phone': guest.phone3108 ... 'phone': guest.phone
@@ -2387,42 +3117,41 @@
2387 ... self.place = place3117 ... self.place = place
23883118
2389 >>> jack = Guest("Jack", "Bangalore")3119 >>> jack = Guest("Jack", "Bangalore")
2390 >>> jack_registrar = GuestRegistrarNG(jack)3120 >>> jack_frontdesk = FrontDeskNG(jack)
23913121
2392 >>> IRegistrar.providedBy(jack_registrar)3122 >>> IDesk.providedBy(jack_frontdesk)
2393 True3123 True
23943124
2395 >>> from zope.component import getGlobalSiteManager3125 >>> from zope.component import getGlobalSiteManager
2396 >>> gsm = getGlobalSiteManager()3126 >>> gsm = getGlobalSiteManager()
2397 >>> sm.registerAdapter(GuestRegistrarNG,3127 >>> sm.registerAdapter(FrontDeskNG,
2398 ... (IGuest,), IRegistrar)3128 ... (IGuest,), IDesk)
23993129
2400 >>> from zope.component import getAdapterInContext3130 >>> from zope.component import getAdapterInContext
2401 >>> from zope.component import queryAdapterInContext
24023131
2403 >>> getAdapterInContext(jack, IRegistrar, sm) #doctest: +ELLIPSIS3132 >>> getAdapterInContext(jack, IDesk, sm) #doctest: +ELLIPSIS
2404 <GuestRegistrarNG object at ...>3133 <FrontDeskNG object at ...>
24053134
24063135
2407getAdapters3136getAdapters
2408~~~~~~~~~~~3137~~~~~~~~~~~
24093138
2410Look for all matching adapters to a provided interface for objects.3139Recherche pour des objets tous les adaptateurs fournissant une interface donnée.
2411Return a list of adapters that match. If an adapter is named, only the3140Une liste d'adaptateurs est renvoyée. Si un adaptateur est nommé, seul
2412most specific adapter of a given name is returned.3141l'adaptateur le plus spécifique pour un nom donné est renvoyé.
24133142
2414 - Location: ``zope.component``3143 - Emplacement : ``zope.component``
24153144
2416 - Signature: `getAdapters(objects, provided, context=None)`3145 - Signature : `getAdapters(objects, provided, context=None)`
24173146
2418Example::3147Exemple ::
24193148
2420 >>> from zope.interface import implements3149 >>> from zope.interface import implements
2421 >>> from zope.component import adapts3150 >>> from zope.component import adapts
24223151
2423 >>> class GuestRegistrarNG(object):3152 >>> class FrontDeskNG(object):
2424 ...3153 ...
2425 ... implements(IRegistrar)3154 ... implements(IDesk)
2426 ... adapts(IGuest)3155 ... adapts(IGuest)
2427 ...3156 ...
2428 ... def __init__(self, guest):3157 ... def __init__(self, guest):
@@ -2430,37 +3159,37 @@
2430 ...3159 ...
2431 ... def register(self):3160 ... def register(self):
2432 ... next_id = get_next_id()3161 ... next_id = get_next_id()
2433 ... guests_db[next_id] = {3162 ... bookings_db[next_id] = {
2434 ... 'name': guest.name,3163 ... 'name': guest.name,
2435 ... 'place': guest.place,3164 ... 'place': guest.place,
2436 ... 'phone': guest.phone3165 ... 'phone': guest.phone
2437 ... }3166 ... }
24383167
2439 >>> jack = Guest("Jack", "Bangalore")3168 >>> jack = Guest("Jack", "Bangalore")
2440 >>> jack_registrar = GuestRegistrarNG(jack)3169 >>> jack_frontdesk = FrontDeskNG(jack)
24413170
2442 >>> from zope.component import getGlobalSiteManager3171 >>> from zope.component import getGlobalSiteManager
2443 >>> gsm = getGlobalSiteManager()3172 >>> gsm = getGlobalSiteManager()
24443173
2445 >>> gsm.registerAdapter(GuestRegistrarNG, name='ng')3174 >>> gsm.registerAdapter(FrontDeskNG, name='ng')
24463175
2447 >>> from zope.component import getAdapters3176 >>> from zope.component import getAdapters
2448 >>> list(getAdapters((jack,), IRegistrar)) #doctest: +ELLIPSIS3177 >>> list(getAdapters((jack,), IDesk)) #doctest: +ELLIPSIS
2449 [(u'ng', <GuestRegistrarNG object at ...>)]3178 [(u'ng', <FrontDeskNG object at ...>)]
24503179
24513180
2452getAllUtilitiesRegisteredFor3181getAllUtilitiesRegisteredFor
2453~~~~~~~~~~~~~~~~~~~~~~~~~~~~3182~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24543183
2455Return all registered utilities for an interface. This includes3184Renvoie tous les utilitaires inscrits pour une interface. Ceci inclut les
2456overridden utilities. The returned value is an iterable of utility3185utilitaires surchargés. La valeur renvoyée est un objet iterable listant les
2457instances.3186instances d'utilitaires correspondants.
24583187
2459 - Location: ``zope.component``3188 - Emplacement : ``zope.component``
24603189
2461 - Signature: `getAllUtilitiesRegisteredFor(interface)`3190 - Signature : `getAllUtilitiesRegisteredFor(interface)`
24623191
2463Example::3192Exemple ::
24643193
2465 >>> from zope.interface import Interface3194 >>> from zope.interface import Interface
2466 >>> from zope.interface import implements3195 >>> from zope.interface import implements
@@ -2491,14 +3220,14 @@
2491getFactoriesFor3220getFactoriesFor
2492~~~~~~~~~~~~~~~3221~~~~~~~~~~~~~~~
24933222
2494Return a tuple (name, factory) of registered factories that create3223Renvoie un tuple (nom, fabrique) de fabriques inscrites capables de créer des
2495objects which implement the given interface.3224objets qui fournissent une interface donnée.
24963225
2497 - Location: ``zope.component``3226 - Emplacement : ``zope.component``
24983227
2499 - Signature: `getFactoriesFor(interface, context=None)`3228 - Signature : `getFactoriesFor(interface, context=None)`
25003229
2501Example::3230Exemple ::
25023231
2503 >>> from zope.interface import Attribute3232 >>> from zope.interface import Attribute
2504 >>> from zope.interface import Interface3233 >>> from zope.interface import Interface
@@ -2535,16 +3264,16 @@
2535getFactoryInterfaces3264getFactoryInterfaces
2536~~~~~~~~~~~~~~~~~~~~3265~~~~~~~~~~~~~~~~~~~~
25373266
2538Get interfaces implemented by a factory. Finds the factory of the3267Récupère les interfaces implémentées par une fabrique. Cette fonction trouve la
2539given name that is nearest to the context, and returns the interface3268fabrique possédant le nom donné la plus proche du contexte, puis renvoie
2540or interface tuple that object instances created by the named factory3269l'interface ou le tuple d'interfaces que les instances créées par la fabrique
2541will implement.3270vont fournir.
25423271
2543 - Location: ``zope.component``3272 - Emplacement : ``zope.component``
25443273
2545 - Signature: `getFactoryInterfaces(name, context=None)`3274 - Signature : `getFactoryInterfaces(name, context=None)`
25463275
2547Example::3276Exemple ::
25483277
2549 >>> from zope.interface import Attribute3278 >>> from zope.interface import Attribute
2550 >>> from zope.interface import Interface3279 >>> from zope.interface import Interface
@@ -2581,14 +3310,14 @@
2581getGlobalSiteManager3310getGlobalSiteManager
2582~~~~~~~~~~~~~~~~~~~~3311~~~~~~~~~~~~~~~~~~~~
25833312
2584Return the global site manager. This function should never fail and3313Renvoie le gestionnaire global de site. Cette fonction ne doit jamais échouer
2585always return an object that provides `IGlobalSiteManager`3314et doit toujours renvoyer un objet qui fournit `IGlobalSiteManager`.
25863315
2587 - Location: ``zope.component``3316 - Emplacement : ``zope.component``
25883317
2589 - Signature: `getGlobalSiteManager()`3318 - Signature : `getGlobalSiteManager()`
25903319
2591Example::3320Exemple ::
25923321
2593 >>> from zope.component import getGlobalSiteManager3322 >>> from zope.component import getGlobalSiteManager
2594 >>> from zope.component import globalSiteManager3323 >>> from zope.component import globalSiteManager
@@ -2600,19 +3329,21 @@
2600getMultiAdapter3329getMultiAdapter
2601~~~~~~~~~~~~~~~3330~~~~~~~~~~~~~~~
26023331
2603Look for a multi-adapter to an interface for an objects. Returns a3332Cette fonction recherche pour des objets un multi-adaptateur vers une interface
2604multi-adapter that can adapt objects to interface. If a matching3333donnée. Elle renvoie un multi-adaptateur qui peut s'adapter aux objets donnés et
2605adapter cannot be found, raises ComponentLookupError. The name3334fournir l'interface voulue. Si aucun adaptateur ne peut être trouvé, une erreur
2606consisting of an empty string is reserved for unnamed adapters. The3335`ComponentLookupError` est émise. Le nom constitué de la chaîne vide est réservé
2607unnamed adapter methods will often call the named adapter methods with3336aux adaptateur sans nom. Les méthodes des adaptateurs sans nom appellent souvent
2608an empty string for a name.3337les méthodes des adaptateurs nommés en fournissant un nom vide ('').
26093338
2610 - Location: ``zope.component``3339 - Emplacement : ``zope.component``
26113340
2612 - Signature: `getMultiAdapter(objects, interface=Interface, name='',3341 - Signature : `getMultiAdapter(objects, interface=Interface, name='',
2613 context=None)`3342 context=None)`
26143343
2615Example::3344 - Voir aussi : `queryMultiAdapter`_
3345
3346Exemple ::
26163347
2617 >>> from zope.interface import Interface3348 >>> from zope.interface import Interface
2618 >>> from zope.interface import implements3349 >>> from zope.interface import implements
@@ -2664,17 +3395,17 @@
2664getSiteManager3395getSiteManager
2665~~~~~~~~~~~~~~3396~~~~~~~~~~~~~~
26663397
2667Get the nearest site manager in the given context. If `context` is3398Récupère le gestionnaire de site le plus proche du contexte donné. Si `context`
2668`None`, return the global site manager. If the `context` is not3399est `None`, cette fonction renvoie le gestionnaire global de site. Si le
2669`None`, it is expected that an adapter from the `context` to3400`context` n'est pas `None`, on s'attend à ce qu'un adaptateur sur le contexte
2670`IComponentLookup` can be found. If no adapter is found, a3401vers `IComponentLookup` soit trouvé. Si aucun adaptateur n'est trouvé, une
2671`ComponentLookupError` is raised.3402erreur `ComponentLookupError` est émise.
26723403
2673 - Location: ``zope.component``3404 - Emplacement : ``zope.component``
26743405
2675 - Signature: `getSiteManager(context=None)`3406 - Signature : `getSiteManager(context=None)`
26763407
2677Example 1::3408Exemple 1 ::
26783409
2679 >>> from zope.component.globalregistry import BaseGlobalComponents3410 >>> from zope.component.globalregistry import BaseGlobalComponents
2680 >>> from zope.component import IComponentLookup3411 >>> from zope.component import IComponentLookup
@@ -2695,7 +3426,7 @@
2695 >>> lsm is sm3426 >>> lsm is sm
2696 True3427 True
26973428
2698Example 2::3429Exemple 2 ::
26993430
2700 >>> from zope.component import getGlobalSiteManager3431 >>> from zope.component import getGlobalSiteManager
2701 >>> gsm = getGlobalSiteManager()3432 >>> gsm = getGlobalSiteManager()
@@ -2708,14 +3439,14 @@
2708getUtilitiesFor3439getUtilitiesFor
2709~~~~~~~~~~~~~~~3440~~~~~~~~~~~~~~~
27103441
2711Look up the registered utilities that provide an interface. Returns3442Récupère les utilitaires inscrits pour une interface particulière. Renvoie un
2712an iterable of name-utility pairs.3443objet iterable listant les paires nom/utilitaire.
27133444
2714 - Location: ``zope.component``3445 - Emplacement : ``zope.component``
27153446
2716 - Signature: `getUtilitiesFor(interface)`3447 - Signature : `getUtilitiesFor(interface)`
27173448
2718Example::3449Exemple ::
27193450
2720 >>> from zope.interface import Interface3451 >>> from zope.interface import Interface
2721 >>> from zope.interface import implements3452 >>> from zope.interface import implements
@@ -2746,15 +3477,15 @@
2746getUtility3477getUtility
2747~~~~~~~~~~3478~~~~~~~~~~
27483479
2749Get the utility that provides interface. Returns the nearest utility3480Récupère l'utilitaire qui fournit une interface donnée. Cette fonction renvoie
2750to the context that implements the specified interface. If one is not3481l'utilitaire le plus proche du contexte et qui fournit l'interface donnée. Si
2751found, raises ComponentLookupError.3482aucun n'est trouvé, une erreur ``ComponentLookupError`` est levée.
27523483
2753 - Location: ``zope.component``3484 - Emplacement : ``zope.component``
27543485
2755 - Signature: `getUtility(interface, name='', context=None)`3486 - Signature : `getUtility(interface, name='', context=None)`
27563487
2757Example::3488Exemple ::
27583489
2759 >>> from zope.interface import Interface3490 >>> from zope.interface import Interface
2760 >>> from zope.interface import implements3491 >>> from zope.interface import implements
@@ -2785,16 +3516,15 @@
2785handle3516handle
2786~~~~~~3517~~~~~~
27873518
2788Call all of the handlers for the given objects. Handlers are3519Appelle tous les gestionnaires pour un objet donné. Les gestionnaires sont des
2789subscription adapter factories that don't produce anything. They do3520fabriques d'abonnés qui ne produisent rien. Ils font tout leur travail lors de
2790all of their work when called. Handlers are typically used to handle3521l'appel. Ils sont typiquement utilisés pour gérer des événements.
2791events.3522
27923523 - Emplacement : ``zope.component``
2793 - Location: ``zope.component``3524
27943525 - Signature : `handle(*objects)`
2795 - Signature: `handle(*objects)`3526
27963527Exemple ::
2797Example::
27983528
2799 >>> import datetime3529 >>> import datetime
28003530
@@ -2840,13 +3570,13 @@
2840implementedBy3570implementedBy
2841~~~~~~~~~~~~~3571~~~~~~~~~~~~~
28423572
2843Return the interfaces implemented for a class' instances.3573Renvoie les interfaces implémentées par une classe.
28443574
2845 - Location: ``zope.interface``3575 - Emplacement : ``zope.interface``
28463576
2847 - Signature: `implementedBy(class_)`3577 - Signature : `implementedBy(class_)`
28483578
2849Example 1::3579Exemple 1 ::
28503580
2851 >>> from zope.interface import Interface3581 >>> from zope.interface import Interface
2852 >>> from zope.interface import implements3582 >>> from zope.interface import implements
@@ -2866,7 +3596,7 @@
2866 >>> implementedBy(Greeter)3596 >>> implementedBy(Greeter)
2867 <implementedBy __builtin__.Greeter>3597 <implementedBy __builtin__.Greeter>
28683598
2869Example 2::3599Exemple 2 ::
28703600
2871 >>> from zope.interface import Attribute3601 >>> from zope.interface import Attribute
2872 >>> from zope.interface import Interface3602 >>> from zope.interface import Interface
@@ -2887,7 +3617,8 @@
28873617
2888 >>> from zope.interface import implementedBy3618 >>> from zope.interface import implementedBy
28893619
2890 To get a list of all interfaces implemented by that class::3620 Pour récupérer une liste de toutes les interfaces implémentées par cette
3621 classe ::
28913622
2892 >>> [x.__name__ for x in implementedBy(Person)]3623 >>> [x.__name__ for x in implementedBy(Person)]
2893 ['IPerson', 'ISpecial']3624 ['IPerson', 'ISpecial']
@@ -2896,15 +3627,15 @@
2896implementer3627implementer
2897~~~~~~~~~~~3628~~~~~~~~~~~
28983629
2899Create a decorator for declaring interfaces implemented by a factory.3630Créer un décorateur permettant de déclarer des interfaces implémentées par une
2900A callable is returned that makes an implements declaration on objects3631fabrique. Un objet appelable est renvoyé, qui fait une déclaration
2901passed to it.3632d'implémentation sur les objets qui lui sont transmis.
29023633
2903 - Location: ``zope.interface``3634 - Emplacement : ``zope.interface``
29043635
2905 - Signature: `implementer(*interfaces)`3636 - Signature : `implementer(*interfaces)`
29063637
2907Example::3638Exemple ::
29083639
2909 >>> from zope.interface import implementer3640 >>> from zope.interface import implementer
2910 >>> class IFoo(Interface):3641 >>> class IFoo(Interface):
@@ -2923,17 +3654,17 @@
2923implements3654implements
2924~~~~~~~~~~3655~~~~~~~~~~
29253656
2926Declare interfaces implemented by instances of a class This function3657Déclare que des interfaces seront fournies par une classe. Cette fonction est
2927is called in a class definition. The arguments are one or more3658appelée dans une définition de classe. Les arguments sont une ou plusieurs
2928interfaces. The interfaces given are added to any interfaces3659interfaces. Les interfaces données sont ajoutées aux interfaces précédemment
2929previously declared. Previous declarations include declarations for3660déclarées. Les déclarations précédentes incluent les déclarations des classes
2930base classes unless implementsOnly was used.3661debase, à moins que `implementsOnly` ne soit utilisé.
29313662
2932 - Location: ``zope.interface``3663 - Emplacement : ``zope.interface``
29333664
2934 - Signature: `implements(*interfaces)`3665 - Signature : `implements(*interfaces)`
29353666
2936Example::3667Exemple ::
29373668
2938 >>> from zope.interface import Attribute3669 >>> from zope.interface import Attribute
2939 >>> from zope.interface import Interface3670 >>> from zope.interface import Interface
@@ -2957,19 +3688,20 @@
2957 >>> IPerson in providedBy(jack)3688 >>> IPerson in providedBy(jack)
2958 True3689 True
29593690