Merge lp:~ccomb/zcadoc/book-fr into lp:~baijum/zcadoc/book
- book-fr
- Merge into book
Proposed by
Christophe Combelles
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 |
Related bugs: |
Commit message
Description of the change
To post a comment you must log in.
lp:~ccomb/zcadoc/book-fr
updated
- 106. By Christophe Combelles
-
some fixes on the french translation
- 107. By Christophe Combelles
-
small fixes
- 108. By Christophe Combelles
-
fixes
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed file 'TODO-fr-generator.py' | |||
2 | --- TODO-fr-generator.py 2007-12-03 18:27:59 +0000 | |||
3 | +++ TODO-fr-generator.py 1970-01-01 00:00:00 +0000 | |||
4 | @@ -1,178 +0,0 @@ | |||
5 | 1 | from text_table import TextTable | ||
6 | 2 | from enum import Enum | ||
7 | 3 | |||
8 | 4 | TRANSLATED_STATUS = Enum("WIP", "Y", "N") | ||
9 | 5 | REREADED_STATUS = Enum("WIP", "Y", "N") | ||
10 | 6 | DONE_STATUS = Enum("Y", "N") | ||
11 | 7 | NOTE_LEVEL = Enum("-", "1", "2", "3", "4", "5") | ||
12 | 8 | |||
13 | 9 | |||
14 | 10 | heading_content = ("Chapter or section name", "TRANSLATED", "REREADED", "DONE", "NOTE") | ||
15 | 11 | |||
16 | 12 | table_content = ( | ||
17 | 13 | (" * Getting started", TRANSLATED_STATUS.WIP, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
18 | 14 | (" o Introduction", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
19 | 15 | (" o A brief history", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
20 | 16 | (" o Installation", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
21 | 17 | (" o Experimenting with code", TRANSLATED_STATUS.Y, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
22 | 18 | (" * An example", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
23 | 19 | (" o Introduction", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
24 | 20 | (" o Procedural approach", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
25 | 21 | (" o Object oriented approach", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
26 | 22 | (" o The adapter pattern", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
27 | 23 | (" * Interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
28 | 24 | (" o Introduction", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
29 | 25 | (" o Declaring interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
30 | 26 | (" o Implementing interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
31 | 27 | (" o Example revisited", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
32 | 28 | (" o Marker interfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
33 | 29 | (" o Invariants", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
34 | 30 | (" * Adapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
35 | 31 | (" o Implementation", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
36 | 32 | (" o Registration", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
37 | 33 | (" o Querying adapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
38 | 34 | (" o Retrieving adapter using interface", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
39 | 35 | (" o Adapter pattern", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
40 | 36 | (" * Utility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
41 | 37 | (" o Introduction", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
42 | 38 | (" o Simple utility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
43 | 39 | (" o Named utility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
44 | 40 | (" o Factory", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
45 | 41 | (" * Advanced adapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
46 | 42 | (" o Multi adapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
47 | 43 | (" o Subscription adapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
48 | 44 | (" o Handler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
49 | 45 | (" * ZCA usage in Zope", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
50 | 46 | (" o ZCML", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
51 | 47 | (" o Overrides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
52 | 48 | (" o NameChooser", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
53 | 49 | (" o LocationPhysicallyLocatable", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
54 | 50 | (" o DefaultSized", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
55 | 51 | (" o ZopeVersionUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
56 | 52 | (" * Reference", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
57 | 53 | (" o Attribute", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
58 | 54 | (" o Declaration", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
59 | 55 | (" o Interface", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
60 | 56 | (" o adapts", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
61 | 57 | (" o alsoProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
62 | 58 | (" o classImplements", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
63 | 59 | (" o classImplementsOnly", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
64 | 60 | (" o classProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
65 | 61 | (" o ComponentLookupError", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
66 | 62 | (" o createObject", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
67 | 63 | (" o directlyProvidedBy", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
68 | 64 | (" o directlyProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
69 | 65 | (" o getAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
70 | 66 | (" o getAdapterInContext", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
71 | 67 | (" o getAdapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
72 | 68 | (" o getAllUtilitiesRegisteredFor", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
73 | 69 | (" o getFactoriesFor", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
74 | 70 | (" o getFactoryInterfaces", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
75 | 71 | (" o getGlobalSiteManager", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
76 | 72 | (" o getMultiAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
77 | 73 | (" o getSiteManager", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
78 | 74 | (" o getUtilitiesFor", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
79 | 75 | (" o getUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
80 | 76 | (" o handle", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
81 | 77 | (" o implementedBy", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
82 | 78 | (" o implementer", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
83 | 79 | (" o implements", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
84 | 80 | (" o implementsOnly", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
85 | 81 | (" o moduleProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
86 | 82 | (" o noLongerProvides", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
87 | 83 | (" o provideAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
88 | 84 | (" o provideHandler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
89 | 85 | (" o provideSubscriptionAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
90 | 86 | (" o provideUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
91 | 87 | (" o providedBy", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
92 | 88 | (" o queryAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
93 | 89 | (" o queryAdapterInContext", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
94 | 90 | (" o queryMultiAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
95 | 91 | (" o queryUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
96 | 92 | (" o registerAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
97 | 93 | (" o registeredAdapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
98 | 94 | (" o registeredHandlers", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
99 | 95 | (" o registeredSubscriptionAdapters", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
100 | 96 | (" o registeredUtilities", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
101 | 97 | (" o registerHandler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
102 | 98 | (" o registerSubscriptionAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
103 | 99 | (" o registerUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
104 | 100 | (" o subscribers", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
105 | 101 | (" o unregisterAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
106 | 102 | (" o unregisterHandler", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
107 | 103 | (" o unregisterSubscriptionAdapter", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]), | ||
108 | 104 | (" o unregisterUtility", TRANSLATED_STATUS.N, REREADED_STATUS.N, DONE_STATUS.N, NOTE_LEVEL[0]) | ||
109 | 105 | ) | ||
110 | 106 | |||
111 | 107 | column_greater_size_content = [0, 0, 0, 0, 0] | ||
112 | 108 | |||
113 | 109 | #summary_value = { | ||
114 | 110 | # "TRANSLATED" : { "YES" : 0, "WIP": 0 }, | ||
115 | 111 | # "REREADED" : { "YES" : 0 }, | ||
116 | 112 | # "DONE" : { "YES" : 0 } | ||
117 | 113 | #} | ||
118 | 114 | |||
119 | 115 | summary_value = { | ||
120 | 116 | TRANSLATED_STATUS.Y : 0, | ||
121 | 117 | TRANSLATED_STATUS.WIP : 0, | ||
122 | 118 | REREADED_STATUS.Y : 0, | ||
123 | 119 | REREADED_STATUS.WIP : 0, | ||
124 | 120 | DONE_STATUS.Y: 0 | ||
125 | 121 | } | ||
126 | 122 | |||
127 | 123 | for row in (heading_content,) + table_content: | ||
128 | 124 | for col_index in range(0, len(row)): | ||
129 | 125 | if (len(str(row[col_index])) > column_greater_size_content[col_index]): | ||
130 | 126 | column_greater_size_content[col_index] = len(str(row[col_index])) | ||
131 | 127 | |||
132 | 128 | if (summary_value.has_key(row[col_index])): | ||
133 | 129 | summary_value[row[col_index]] = summary_value[row[col_index]] + 1 | ||
134 | 130 | |||
135 | 131 | ascii_table_content = TextTable( | ||
136 | 132 | *tuple([(column_greater_size_content[i], heading_content[i]) for i in range(0, 5)]) | ||
137 | 133 | ) | ||
138 | 134 | |||
139 | 135 | for row in table_content: | ||
140 | 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))]))) | ||
141 | 137 | |||
142 | 138 | |||
143 | 139 | summary_content = ( | ||
144 | 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")), | ||
145 | 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")), | ||
146 | 142 | ("Done", str(str(summary_value[DONE_STATUS.Y]) + " / " + str(len(table_content)) + " (" + str((summary_value[DONE_STATUS.Y] * 100) / len(table_content)) + " %)")) | ||
147 | 143 | ) | ||
148 | 144 | |||
149 | 145 | ascii_summary_content = TextTable((12), (28)) | ||
150 | 146 | for row in summary_content: | ||
151 | 147 | ascii_summary_content.row(*row) | ||
152 | 148 | |||
153 | 149 | print( | ||
154 | 150 | """ | ||
155 | 151 | This file contain some informations about the growth of french | ||
156 | 152 | translation. | ||
157 | 153 | |||
158 | 154 | This file is generate by TODO-fr-generator.py script file. | ||
159 | 155 | |||
160 | 156 | Summary | ||
161 | 157 | ======= | ||
162 | 158 | """) | ||
163 | 159 | |||
164 | 160 | |||
165 | 161 | print(ascii_summary_content.draw()) | ||
166 | 162 | |||
167 | 163 | print(""" | ||
168 | 164 | Detail table | ||
169 | 165 | ============ | ||
170 | 166 | |||
171 | 167 | Fields values : | ||
172 | 168 | |||
173 | 169 | * Translated column can be Yes, No, WIP (Work In Progress) | ||
174 | 170 | * Rereaded column can be Yes, No, WIP (Work In Progress) | ||
175 | 171 | * Done column can be Yes, No | ||
176 | 172 | * Note column can be "-" or 1 to 5, it's quality note | ||
177 | 173 | |||
178 | 174 | """) | ||
179 | 175 | |||
180 | 176 | print ascii_table_content.draw() | ||
181 | 177 | |||
182 | 178 | |||
183 | 179 | 0 | ||
184 | === removed file 'TODO-fr.txt' | |||
185 | --- TODO-fr.txt 2007-12-03 18:27:59 +0000 | |||
186 | +++ TODO-fr.txt 1970-01-01 00:00:00 +0000 | |||
187 | @@ -1,124 +0,0 @@ | |||
188 | 1 | |||
189 | 2 | This file contain some informations about the growth of french | ||
190 | 3 | translation. | ||
191 | 4 | |||
192 | 5 | This file is generate by TODO-fr-generator.py script file. | ||
193 | 6 | |||
194 | 7 | Summary | ||
195 | 8 | ======= | ||
196 | 9 | |||
197 | 10 | .--------------+------------------------------. | ||
198 | 11 | | Translated | 4 / 92 (4 %) , 1 in WIP | | ||
199 | 12 | | Rereaded | 0 / 92 (0 %) , 0 in WIP | | ||
200 | 13 | | Done | 0 / 92 (0 %) | | ||
201 | 14 | '--------------+------------------------------' | ||
202 | 15 | |||
203 | 16 | |||
204 | 17 | Detail table | ||
205 | 18 | ============ | ||
206 | 19 | |||
207 | 20 | Fields values : | ||
208 | 21 | |||
209 | 22 | * Translated column can be Yes, No, WIP (Work In Progress) | ||
210 | 23 | * Rereaded column can be Yes, No, WIP (Work In Progress) | ||
211 | 24 | * Done column can be Yes, No | ||
212 | 25 | * Note column can be "-" or 1 to 5, it's quality note | ||
213 | 26 | |||
214 | 27 | |||
215 | 28 | .---------------------------------------------+------------+----------+------+------. | ||
216 | 29 | | Chapter or section name | TRANSLATED | REREADED | DONE | NOTE | | ||
217 | 30 | +---------------------------------------------+------------+----------+------+------+ | ||
218 | 31 | | * Getting started | WIP | N | N | - | | ||
219 | 32 | | o Introduction | Y | N | N | - | | ||
220 | 33 | | o A brief history | Y | N | N | - | | ||
221 | 34 | | o Installation | Y | N | N | - | | ||
222 | 35 | | o Experimenting with code | Y | N | N | - | | ||
223 | 36 | | * An example | N | N | N | - | | ||
224 | 37 | | o Introduction | N | N | N | - | | ||
225 | 38 | | o Procedural approach | N | N | N | - | | ||
226 | 39 | | o Object oriented approach | N | N | N | - | | ||
227 | 40 | | o The adapter pattern | N | N | N | - | | ||
228 | 41 | | * Interfaces | N | N | N | - | | ||
229 | 42 | | o Introduction | N | N | N | - | | ||
230 | 43 | | o Declaring interfaces | N | N | N | - | | ||
231 | 44 | | o Implementing interfaces | N | N | N | - | | ||
232 | 45 | | o Example revisited | N | N | N | - | | ||
233 | 46 | | o Marker interfaces | N | N | N | - | | ||
234 | 47 | | o Invariants | N | N | N | - | | ||
235 | 48 | | * Adapters | N | N | N | - | | ||
236 | 49 | | o Implementation | N | N | N | - | | ||
237 | 50 | | o Registration | N | N | N | - | | ||
238 | 51 | | o Querying adapter | N | N | N | - | | ||
239 | 52 | | o Retrieving adapter using interface | N | N | N | - | | ||
240 | 53 | | o Adapter pattern | N | N | N | - | | ||
241 | 54 | | * Utility | N | N | N | - | | ||
242 | 55 | | o Introduction | N | N | N | - | | ||
243 | 56 | | o Simple utility | N | N | N | - | | ||
244 | 57 | | o Named utility | N | N | N | - | | ||
245 | 58 | | o Factory | N | N | N | - | | ||
246 | 59 | | * Advanced adapters | N | N | N | - | | ||
247 | 60 | | o Multi adapter | N | N | N | - | | ||
248 | 61 | | o Subscription adapter | N | N | N | - | | ||
249 | 62 | | o Handler | N | N | N | - | | ||
250 | 63 | | * ZCA usage in Zope | N | N | N | - | | ||
251 | 64 | | o ZCML | N | N | N | - | | ||
252 | 65 | | o Overrides | N | N | N | - | | ||
253 | 66 | | o NameChooser | N | N | N | - | | ||
254 | 67 | | o LocationPhysicallyLocatable | N | N | N | - | | ||
255 | 68 | | o DefaultSized | N | N | N | - | | ||
256 | 69 | | o ZopeVersionUtility | N | N | N | - | | ||
257 | 70 | | * Reference | N | N | N | - | | ||
258 | 71 | | o Attribute | N | N | N | - | | ||
259 | 72 | | o Declaration | N | N | N | - | | ||
260 | 73 | | o Interface | N | N | N | - | | ||
261 | 74 | | o adapts | N | N | N | - | | ||
262 | 75 | | o alsoProvides | N | N | N | - | | ||
263 | 76 | | o classImplements | N | N | N | - | | ||
264 | 77 | | o classImplementsOnly | N | N | N | - | | ||
265 | 78 | | o classProvides | N | N | N | - | | ||
266 | 79 | | o ComponentLookupError | N | N | N | - | | ||
267 | 80 | | o createObject | N | N | N | - | | ||
268 | 81 | | o directlyProvidedBy | N | N | N | - | | ||
269 | 82 | | o directlyProvides | N | N | N | - | | ||
270 | 83 | | o getAdapter | N | N | N | - | | ||
271 | 84 | | o getAdapterInContext | N | N | N | - | | ||
272 | 85 | | o getAdapters | N | N | N | - | | ||
273 | 86 | | o getAllUtilitiesRegisteredFor | N | N | N | - | | ||
274 | 87 | | o getFactoriesFor | N | N | N | - | | ||
275 | 88 | | o getFactoryInterfaces | N | N | N | - | | ||
276 | 89 | | o getGlobalSiteManager | N | N | N | - | | ||
277 | 90 | | o getMultiAdapter | N | N | N | - | | ||
278 | 91 | | o getSiteManager | N | N | N | - | | ||
279 | 92 | | o getUtilitiesFor | N | N | N | - | | ||
280 | 93 | | o getUtility | N | N | N | - | | ||
281 | 94 | | o handle | N | N | N | - | | ||
282 | 95 | | o implementedBy | N | N | N | - | | ||
283 | 96 | | o implementer | N | N | N | - | | ||
284 | 97 | | o implements | N | N | N | - | | ||
285 | 98 | | o implementsOnly | N | N | N | - | | ||
286 | 99 | | o moduleProvides | N | N | N | - | | ||
287 | 100 | | o noLongerProvides | N | N | N | - | | ||
288 | 101 | | o provideAdapter | N | N | N | - | | ||
289 | 102 | | o provideHandler | N | N | N | - | | ||
290 | 103 | | o provideSubscriptionAdapter | N | N | N | - | | ||
291 | 104 | | o provideUtility | N | N | N | - | | ||
292 | 105 | | o providedBy | N | N | N | - | | ||
293 | 106 | | o queryAdapter | N | N | N | - | | ||
294 | 107 | | o queryAdapterInContext | N | N | N | - | | ||
295 | 108 | | o queryMultiAdapter | N | N | N | - | | ||
296 | 109 | | o queryUtility | N | N | N | - | | ||
297 | 110 | | o registerAdapter | N | N | N | - | | ||
298 | 111 | | o registeredAdapters | N | N | N | - | | ||
299 | 112 | | o registeredHandlers | N | N | N | - | | ||
300 | 113 | | o registeredSubscriptionAdapters | N | N | N | - | | ||
301 | 114 | | o registeredUtilities | N | N | N | - | | ||
302 | 115 | | o registerHandler | N | N | N | - | | ||
303 | 116 | | o registerSubscriptionAdapter | N | N | N | - | | ||
304 | 117 | | o registerUtility | N | N | N | - | | ||
305 | 118 | | o subscribers | N | N | N | - | | ||
306 | 119 | | o unregisterAdapter | N | N | N | - | | ||
307 | 120 | | o unregisterHandler | N | N | N | - | | ||
308 | 121 | | o unregisterSubscriptionAdapter | N | N | N | - | | ||
309 | 122 | | o unregisterUtility | N | N | N | - | | ||
310 | 123 | '---------------------------------------------+------------+----------+------+------' | ||
311 | 124 | |||
312 | 125 | 0 | ||
313 | === modified file 'izca-fr.txt' | |||
314 | --- izca-fr.txt 2007-12-03 18:27:59 +0000 | |||
315 | +++ izca-fr.txt 2009-12-11 23:53:09 +0000 | |||
316 | @@ -1,246 +1,270 @@ | |||
329 | 1 | =========================== | 1 | ======================================================== |
330 | 2 | Zope Component Architecture | 2 | Le guide complet de l'Architecture de Composants de Zope |
331 | 3 | =========================== | 3 | ======================================================== |
332 | 4 | 4 | ||
333 | 5 | 5 | :Author: Baiju M | |
334 | 6 | :Auteur: Baiju M | 6 | :Version: 0.5.8 |
335 | 7 | :Version: 0.4.1 | 7 | :Printed Book: `http://www.lulu.com/content/1561045 |
336 | 8 | :URL: `http://www.muthukadan.net/docs/zca.pdf | 8 | <http://www.lulu.com/content/1561045>`_ |
337 | 9 | <http://www.muthukadan.net/docs/zca.pdf>`_ | 9 | :Online PDF: `http://www.muthukadan.net/docs/zca.pdf |
338 | 10 | :Traducteur: Stéphane Klein <stephane@harobed.org> | 10 | <http://www.muthukadan.net/docs/zca.pdf>`_ |
339 | 11 | 11 | :Traducteur: Christophe Combelles <ccomb@free.fr>, Stéphane Klein <stephane@harobed.org> | |
340 | 12 | Copyright (C) 2007 Baiju M <baiju.m.mail AT gmail.com>. | 12 | |
341 | 13 | Copyright (C) 2007,2008,2009 Baiju M <baiju.m.mail AT gmail.com>. | ||
342 | 13 | 14 | ||
343 | 14 | Chacun est autorisé à copier, distribuer et/ou modifier ce document | 15 | Chacun est autorisé à copier, distribuer et/ou modifier ce document |
346 | 15 | suivant les termes de la "GNU Free Documentation License", version 1.2 | 16 | suivant les termes de la « GNU Free Documentation License », version 1.3 |
347 | 16 | ou (à votre gré) toute version ultérieur publiée par la Free Software | 17 | ou toute version ultérieure publiée par la Free Software |
348 | 17 | Foundation. | 18 | Foundation. |
349 | 18 | 19 | ||
350 | 19 | Le code source présent dans ce document est soumis aux conditions de | 20 | Le code source présent dans ce document est soumis aux conditions de |
361 | 20 | la licence Zope Public License, Version 2.1 (ZPL). | 21 | la « Zope Public License », Version 2.1 (ZPL). |
362 | 21 | 22 | ||
363 | 22 | LE CODE SOURCE DE CE DOCUMENT EST FOURNI "EN L'ETAT" SANS AUCUNE | 23 | THE SOURCE CODE IN THIS DOCUMENT AND THE DOCUMENT ITSELF IS PROVIDED |
364 | 23 | GARANTIE. | 24 | "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED WARRANTIES ARE DISCLAIMED, |
365 | 24 | 25 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, | |
366 | 25 | .. note:: | 26 | MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS FOR A PARTICULAR |
367 | 26 | 27 | PURPOSE. | |
368 | 27 | Merci à Kent Tenney (Wisconsin, USA) et Brad Allen (Dallas, USA) | 28 | |
369 | 28 | pour leurs suggestions. | 29 | .. sidebar:: Remerciements |
370 | 29 | 30 | ||
371 | 31 | De nombreuses personnes m'ont aidé à écrire ce livre. Le brouillon initial a été | ||
372 | 32 | relu par mon collègue Brad Allen. Quand j'ai annoncé ce livre sur mon blog, j'ai | ||
373 | 33 | reçu de nombreux encouragements pour poursuivre ce travail. Kent Tenney a | ||
374 | 34 | modifié de nombreuses parties du livre et a également réécrit l'application | ||
375 | 35 | servant d'exemple. De nombreuses autres personnes m'ont envoyé des corrections | ||
376 | 36 | et des commentaires, dont Lorenzo Gil Sanchez, Michael Haubenwallner, Nando | ||
377 | 37 | Quintana, Stephane Klein, Tim Cook, Kamal Gill et Thomas Herve. Lorenzo a | ||
378 | 38 | traduit ce travail en espagnol et Stephane initié la traduction en français. Merci à | ||
379 | 39 | toutes ces personnes ! | ||
380 | 30 | 40 | ||
381 | 31 | .. contents:: | 41 | .. contents:: |
382 | 32 | .. .. sectnum:: | 42 | .. .. sectnum:: |
383 | 33 | 43 | ||
384 | 34 | 44 | ||
387 | 35 | Premiers pas | 45 | Mise en route |
388 | 36 | ------------ | 46 | ------------- |
389 | 37 | 47 | ||
390 | 38 | 48 | ||
391 | 39 | Introduction | 49 | Introduction |
392 | 40 | ~~~~~~~~~~~~ | 50 | ~~~~~~~~~~~~ |
393 | 41 | 51 | ||
405 | 42 | Le développement de logiciels de grandes tailles (grande quantité de | 52 | Le développement de grands systèmes logiciels est toujours une tâche ardue |
406 | 43 | lignes de code...) est toujours une tâche très complexe. L'expérience | 53 | L'expérience montre que l'approche orientée objet est bien appropriée à |
407 | 44 | montre que l'utilisation d'une approche orienté objet simplifie | 54 | l'analyse, à la modélisation et à la programmation des systèmes complexes. La |
408 | 45 | l'analyse, la modélisation et l'implémentation de programmes | 55 | conception orientée composants et la programmation basée sur des composants |
409 | 46 | complexes. Les logiciels informatiques basés sur une architecture et | 56 | deviennent actuellement très populaires. L'approche basée composants est d'une |
410 | 47 | une programmation oriénté composant sont de nos jours de plus en plus | 57 | grande aide pour l'écriture et la maintenance de systèmes logiciels et |
411 | 48 | populaire. Une grande partie des langages de programmations disposent | 58 | de leurs tests unitaires. Il existe de nombreux frameworks permettant la |
412 | 49 | de framework qui permettent ou simplifient la programmation orienté | 59 | conception basée sur des composants dans différents langages, certains étant |
413 | 50 | composant. Certain de ces frameworks sont même compatibles avec | 60 | même indépendants du langage. On peut citer comme exemple : COM de Microsoft, ou |
403 | 51 | plusieurs langages. Parmi ces frameworks orientés composants on trouve | ||
404 | 52 | par exemple la technologie COM de Microsoft ou alors la technologie | ||
414 | 53 | XPCOM de Mozilla. | 61 | XPCOM de Mozilla. |
415 | 54 | 62 | ||
428 | 55 | L'architecture composant de Zope (nommé ZCA : Zope Component | 63 | La **Zope Component Architecture (ZCA)** est un framework en Python qui autorise |
429 | 56 | Architecture) est un framework qui permet d'écrire des programmes | 64 | la conception et la programmation basée sur des composants. Elle est très bien |
430 | 57 | orientés composants en langage Python. ZCA est très bien adapté pour | 65 | adaptée au développement de grands systèmes logiciels. La ZCA n'est |
431 | 58 | écrire des programmes Python complexes. Ce framework n'est pas limité | 66 | pas liée au serveur d'application Zope : elle peut être utilisée pour développer |
432 | 59 | au serveur web d'application Zope, il peut être utilisé pour | 67 | n'importe quelle application en Python. Peut-être devrait-elle s'appeler la « |
433 | 60 | l'écriture de tout type d'application Python, peut être même qu'il | 68 | Python Component Architecture ». |
434 | 61 | devrait être nommé `Python Component Architecture` plutôt que Zope | 69 | |
435 | 62 | Component Architecture. | 70 | Le but de la ZCA est d'utiliser des objets Python de manière efficace. Les |
436 | 63 | 71 | composants sont des objets réutilisables fournissant une interface que l'on peut | |
437 | 64 | ZCA dépend principalement de deux paquets: | 72 | introspecter. Une interface est un objet qui décrit comment on peut travailler |
438 | 65 | 73 | avec un composant particulier. Autrement dit, un composant fournit une interface | |
439 | 66 | - ``zope.interface`` utilisé pour définir l'interface des | 74 | implémentée dans une classe ou tout autre objet appelable (*callable*). La façon |
440 | 75 | dont le composant est implémenté n'a pas d'importance : ce qui compte est que | ||
441 | 76 | celui-ci soit en accord avec l'interface. Grâce à la ZCA, vous pouvez éclater la | ||
442 | 77 | complexité d'un système dans plusieurs composants travaillant ensemble. Elle | ||
443 | 78 | vous aide à créer notamment deux types de composants : les « adaptateurs » et les « | ||
444 | 79 | utilitaires ». | ||
445 | 80 | |||
446 | 81 | Trois paquets composent la ZCA : | ||
447 | 82 | |||
448 | 83 | - ``zope.interface`` est utilisé pour la définition d'une interface. | ||
449 | 84 | |||
450 | 85 | - ``zope.event`` fournit un système simple d'événements. | ||
451 | 86 | |||
452 | 87 | - ``zope.component`` sert à la création, l'inscription et la récupération des | ||
453 | 67 | composants. | 88 | composants. |
454 | 68 | 89 | ||
484 | 69 | - ``zope.component`` pour réaliser les opérations d'enregistrements | 90 | Souvenez-vous que la ZCA ne fournit pas de composants par elle-même. Elle n'a |
485 | 70 | et de recherches de composants. | 91 | pour but que de créer, inscrire et récupérer des composants. Gardez également à |
486 | 71 | 92 | l'esprit qu'un adaptateur est une classe Python tout à fait normale (en général | |
487 | 72 | ZCA dispose de tout ce qu'il faut pour utiliser efficacement des | 93 | une fabrique) et qu'un utilitaire est un simple objet Python appelable. |
488 | 73 | objets Python. Les composants sont des objets réutilisables disposant | 94 | |
489 | 74 | d'interface est introspectable. Un composant est un objet disposant | 95 | Le framework ZCA est développé comme une partie du projet Zope 3. Comme |
490 | 75 | d'une interface implémenté par une classe ou tout autre objet | 96 | mentionné plus haut, c'est un framework purement Python et il peut être utilisé |
491 | 76 | exécutable. L'implémentation d'un composant n'est pas l'élément le | 97 | dans n'importe quelle application Python. Actuellement, Zope 3, Zope 2 et Grok |
492 | 77 | plus important, ce qui compte avant tout c'est sa conformité avec le | 98 | l'utilisent abondamment. De nombreux autres projets l'utilisent, y compris des |
493 | 78 | "contrat" défini par son interface. L'utilisation d'une architecture | 99 | applications non liées au web [#projects]_. |
494 | 79 | orienté composant vous permet de diviser la compléxité d'un système à | 100 | |
495 | 80 | travers de multiples composants coopératifs. L'architecture composant | 101 | .. [#projects] http://wiki.zope.org/zope3/ComponentArchitecture |
467 | 81 | de Zope vous aide à créer deux types de composants de base : des | ||
468 | 82 | `adapter` et des `utility`. | ||
469 | 83 | |||
470 | 84 | Notez bien que l'architecture composant de Zope ne vous aide pas à | ||
471 | 85 | écrire les composants eux-mêmes mais elle vous permet la création, | ||
472 | 86 | l'enregistrement et la recherche de composants.Notez aussi qu'un | ||
473 | 87 | composant `adapter` est une classe Python tout à fait normal (ou en | ||
474 | 88 | général une fabrique d'objet (factory)) et qu'un composant `utility` | ||
475 | 89 | est un objet Python exécutable standard. | ||
476 | 90 | |||
477 | 91 | L'architecture composant Zope est développé comme une partie distincte | ||
478 | 92 | du projet Zope 3. ZCA, comme indiqué plus tôt, est un framework | ||
479 | 93 | purement Python, il peut être utilisé pour développer n'importe quel | ||
480 | 94 | type d'application. Actuellement à la fois Zope 3 et Zope 2 utilisent | ||
481 | 95 | très fortement ce framework mais il existe de nombreux autres projets | ||
482 | 96 | et même des applications non orientés Internet qui utilisent | ||
483 | 97 | l'architecture composant de Zope [#projects]_. | ||
496 | 98 | 102 | ||
497 | 99 | 103 | ||
498 | 100 | Petit historique | 104 | Petit historique |
499 | 101 | ~~~~~~~~~~~~~~~~ | 105 | ~~~~~~~~~~~~~~~~ |
500 | 102 | 106 | ||
530 | 103 | Le développement de la ZCA a débuté en 2001 dans le cadre du projet | 107 | Le développement de la ZCA a débuté en 2001 dans le cadre du projet Zope 3. Ce |
531 | 104 | Zope 3. Ce framework est le fruit de l'expérience aquise durant le | 108 | framework est le fruit de l'expérience acquise pendant le développement |
532 | 105 | développement d'application d'envergure en Zope 2. Jim Fulton est le | 109 | d'applications d'envergure avec Zope 2. Jim Fulton est le père de ce projet. De |
533 | 106 | père de ce projet. De nombreuses personnes ont participé à la | 110 | nombreuses personnes ont participé à sa conception et à son implémentation, |
534 | 107 | conception de ce framework, parmit eux on peut citer : Stephan | 111 | notamment Stephan Richter, Philipp von Weitershausen, Guido van Rossum (*aka. |
535 | 108 | Richter, Philipp von Weitershausen, Guido van Rossum (créateur du | 112 | Python BDFL*), Tres Seaver, Phillip J Eby et Martijn Faassen. |
536 | 109 | langage Python), Tres Seaver, Phillip J Eby et Martijn Faassen. | 113 | |
537 | 110 | 114 | À ses débuts, la ZCA définissait des types de composants supplémentaires : les | |
538 | 111 | Par rapport à la version actuel, les premières versions de ZCA | 115 | *services* et les *vues*, mais les développeurs ont fini par réaliser qu'un |
539 | 112 | disposaient de quelques composants supplémentaires : les composants | 116 | *utilitaire* peut remplacer un *service* et qu'un *multi-adaptateur* peut |
540 | 113 | `services` et les composants `views`. Ils ont été supprimé car les | 117 | remplacer une *vue*. Aujourd'hui, la ZCA comporte un nombre très réduit de types |
541 | 114 | développeurs ont réalisé que le composant `utility` pouvait remplacer | 118 | de composants de base : les *utilitaires* (en anglais *utilities*), les *adaptateurs* |
542 | 115 | le composant `service` et le composant `multi-adapter` pouvait | 119 | (*adapters*), les *abonnés* (*subscribers*) et les *gestionnaires* (*handlers*). |
543 | 116 | remplacer le composant `view`. La ZCA comporte actuellement un nombre | 120 | Et encore, les *abonnés* et les *gestionnaires* sont des cas particuliers de |
544 | 117 | réduit de type de type de composant :les `utility`, les `adapter`, les | 121 | l'*adaptateur*. |
545 | 118 | `subscribers` et les `handler`. En fait, les composants `subscriber` | 122 | |
546 | 119 | et `handler` sont tous deux des adaptateurs spécialisés. | 123 | Pendant le cycle de développement de Zope 3.2, Jim Fulton a proposé une |
547 | 120 | 124 | importante simplification de la ZCA [#proposal]_. Grâce à cette simplification, | |
548 | 121 | Pendant le cycle de développement de Zope 3.2, Jim Fulton a proposé | 125 | une nouvelle interface unique (`IComponentRegistry`) a été créée pour |
549 | 122 | une importante simplification de l'achitecture composant de Zope | 126 | l'inscription des composants globaux et locaux. |
550 | 123 | [#proposal]_. Parmit ces simplications, on trouve la possibilité en | 127 | |
551 | 124 | passant par une interface unique de déclarer à la fois des composants | 128 | .. [#proposal] http://wiki.zope.org/zope3/LocalComponentManagementSimplification |
552 | 125 | globaux et locaux. | 129 | |
553 | 126 | 130 | Le paquet ``zope.component`` avait une longue liste de dépendances, dont une | |
554 | 127 | Le paquet ``zope.component`` a une longue liste de dépendances, parmit | 131 | grande partie n'était pas nécessaire pour une application non liée à Zope 3. |
555 | 128 | elles beaucoup ne sont pas nécessaire aux applications non Zope 3. | 132 | Pendant PyCon 2007, Jim Fulton a ajouté la fonctionnalité `extras_require` à |
556 | 129 | Pendant le PyCon 2007, Jim Fulton a ajouté à setuptools une nouvelle | 133 | setuptools pour permettre d'extraire le cœur de la ZCA des fonctionnalités |
528 | 130 | fonctionnalité nommée `extras_require`. Elle permet de séparer les | ||
529 | 131 | fonctionnalités constituant le coeur de ZCA des fonctionnalités | ||
557 | 132 | annexes [#extras]_. | 134 | annexes [#extras]_. |
558 | 133 | 135 | ||
565 | 134 | Maintenant, le projet Zope Component Architecture est un projet | 136 | .. [#extras] http://peak.telecommunity.com/DevCenter/setuptools#declaring-dependencies |
566 | 135 | indépendant avec son propre cycle de version et son propre dépôt | 137 | |
567 | 136 | Subversion. Toutefois, les bugs et problèmes sont encore traités à | 138 | En mars 2009, Tres Seaver a supprimé les dépendances à ``zope.deferredimport`` et |
568 | 137 | l'intérieur du projet Zope 3 [#bugs]_, et la liste de diffusion | 139 | ``zope.proxy``. |
569 | 138 | zope-dev est utilisé pour les discussions liées aux développements | 140 | |
570 | 139 | [#discussions]_. | 141 | Aujourd'hui, le projet ZCA est indépendant et possède son propre cycle de |
571 | 142 | publications et son propre dépôt Subversion. Il est fourni avec le framework | ||
572 | 143 | Zope. [#framework]_. Cependant, les anomalies et les bogues sont toujours pris | ||
573 | 144 | en charge au travers du projet Zope 3 [#bugs]_ et la liste de diffusion | ||
574 | 145 | zope-dev est utilisée pour débattre du développement [#discussions]_. Il existe | ||
575 | 146 | également une liste pour les utilisateurs de Zope 3 (`zope3-users`) qui peut | ||
576 | 147 | être utilisée pour toute demande au sujet de la ZCA [#z3users]_. | ||
577 | 148 | |||
578 | 149 | .. [#framework] http://docs.zope.org/zopeframework/ | ||
579 | 150 | .. [#bugs] https://bugs.launchpad.net/zope3 | ||
580 | 151 | .. [#discussions] http://mail.zope.org/mailman/listinfo/zope-dev | ||
581 | 152 | .. [#z3users] http://mail.zope.org/mailman/listinfo/zope3-users | ||
582 | 140 | 153 | ||
583 | 141 | 154 | ||
584 | 142 | Installation | 155 | Installation |
585 | 143 | ~~~~~~~~~~~~ | 156 | ~~~~~~~~~~~~ |
586 | 144 | 157 | ||
596 | 145 | Les paquets ``zope.component`` et ``zope.interface`` forment | 158 | Les paquets ``zope.component``, ``zope.interface`` et ``zope.event`` constituent |
597 | 146 | ensemble le coeur de l'architecture composant de Zope. Ils fournissent | 159 | le cœur de la *Zope Component Architecture*. Ils fournissent des outils |
598 | 147 | les fonctionnalités permettant de définir, déclarer et retrouver des | 160 | permettant de définir, inscrire et rechercher des composants. Le paquet |
599 | 148 | composants. Le paquet ``zope.component`` et ses dépendances sont | 161 | ``zope.component`` et ses dépendances sont disponibles sous forme d'*egg* dans |
600 | 149 | disponibles sous forme de PythonEggs dans le dépôt PyPI (Python Package | 162 | l'index des paquets Python (PyPI) [#pypi]_. |
601 | 150 | Index) [#pypi]_. | 163 | |
602 | 151 | 164 | .. [#pypi] Dépôt des paquets Python : http://pypi.python.org/pypi | |
603 | 152 | Vous pouvez utiliser `easy_install` [#easyinstall]_ pour installer | 165 | |
604 | 153 | ``zope.component`` et ses dépendances : | 166 | Vous pouvez installer ``zope.component`` et ses dépendances avec `easy_install` |
605 | 167 | [#easyinstall]_ :: | ||
606 | 154 | 168 | ||
607 | 155 | $ easy_install zope.component | 169 | $ easy_install zope.component |
608 | 156 | 170 | ||
617 | 157 | Cette commande télécharge ``zope.component`` et ses depandances depuis | 171 | .. [#easyinstall] http://peak.telecommunity.com/DevCenter/EasyInstall |
618 | 158 | le dépôt PyPI et les installe sur votre système. | 172 | |
619 | 159 | 173 | Cette commande télécharge ``zope.component`` et ses dépendances depuis PyPI et | |
620 | 160 | D'une manière alternative, vous pouvez télécharger manuellement le | 174 | l'installe dans votre *Python path*. |
621 | 161 | paquet ``zope.component`` et ses dépendances depuis PyPi puis les | 175 | |
622 | 162 | installer manuellement. L'ordre d'installation des paquets vous est | 176 | Une autre manière de procéder est de télécharger ``zope.component`` et ses |
623 | 163 | donné ci-dessous. Sous Windows, vous aurais besoin du paquet binaire | 177 | dépendances depuis PyPI et de les installer. Il faut installer les paquets dans |
624 | 164 | de ``zope.interface`` et ``zope.proxy``. | 178 | l'ordre donné ci-dessous. Sous Windows, vous aurez probablement besoin du paquet |
625 | 179 | binaire de ``zope.interface``. | ||
626 | 165 | 180 | ||
627 | 166 | 1. ``zope.interface`` | 181 | 1. ``zope.interface`` |
660 | 167 | 2. ``zope.proxy`` | 182 | 2. ``zope.event`` |
661 | 168 | 3. ``zope.deferredimport`` | 183 | 3. ``zope.component`` |
662 | 169 | 4. ``zope.event`` | 184 | |
663 | 170 | 5. ``zope.deprecation`` | 185 | Pour installer ces paquet, après téléchargement, vous pouvez utiliser la |
664 | 171 | 6. ``zope.component`` | 186 | commande ``easy_install`` avec les eggs comme argument (éventuellement en |
665 | 172 | 187 | fournissant tous les eggs sur la même ligne de commande) :: | |
666 | 173 | Pour installer ces paquets après les avoir téléchagré, vous pouvez | 188 | |
667 | 174 | utiliser la commande ``easy_install`` avec le nom des paquets comme | 189 | $ easy_install /path/to/zope.interface-3.x.x.tar.gz |
668 | 175 | argument (vous pouvez aussi donner la totalité des noms des paquets | 190 | $ easy_install /path/to/zope.event-3.x.x.tar.gz |
669 | 176 | en argument sur la même ligne):: | 191 | $ easy_install /path/to/zope.component-3.x.x.tar.gz |
670 | 177 | 192 | ||
671 | 178 | $ easy_install /path/to/zope.interface-3.4.x.tar.gz | 193 | Vous pouvez aussi installer ces paquets en les décompressant séparément. Par |
672 | 179 | $ easy_install /path/to/zope.proxy-3.4.x.tar.gz | 194 | exemple :: |
673 | 180 | ... | 195 | |
674 | 181 | 196 | $ tar zxvf /path/to/zope.interface-3.x.x.tar.gz | |
675 | 182 | Cette méthode install le framework ZCA dans votre `system Python`, dans | 197 | $ cd zope.interface-3.x.x |
676 | 183 | le répertoire ``site-packages``... ce qui peut poser certain soucis. | 198 | $ python setup.py build |
677 | 184 | Dans un poste présent dans la liste de diffusion Zope 3, Jim Fulton | 199 | $ python setup.py install |
678 | 185 | est défavorable à l'utilisation du `system Python` [#systempython]_ | 200 | |
679 | 186 | (c'est à dire à l'installation dans ``site-packages``). | 201 | Ces méthodes installeront la ZCA dans votre *Python système*, dans le dossier |
680 | 187 | 202 | ``site-packages``, ce qui peut être problématique. Dans un message sur la liste | |
681 | 188 | 203 | de diffusion Zope 3, Jim Fulton déconseille d'utiliser le Python système | |
682 | 189 | Environement d'expérimentation | 204 | [#systempython]_. Vous pouvez utiliser ``virtualenv`` ou ``zc.buildout`` pour |
683 | 190 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 205 | jouer avec n'importe quel paquet Python, et également pour les déploiements. |
684 | 191 | 206 | ||
685 | 192 | ``virtualenv`` et ``zc.buildout`` sont des outils qui permettent | 207 | .. [#systempython] http://article.gmane.org/gmane.comp.web.zope.zope3/21045 |
686 | 193 | l'installation de la ZCA dans un environement isolé. L'utilisation de | 208 | |
687 | 194 | ces outils est conseillé lors l'expérimentation de code. De plus, il | 209 | |
688 | 195 | est bénéfique de se familiariser avec eux car ils sont très pratiques autant | 210 | Méthode pour expérimenter |
689 | 196 | lors de la phase de développement que lors du déploiement d'applications. | 211 | ~~~~~~~~~~~~~~~~~~~~~~~~~ |
690 | 197 | 212 | ||
691 | 198 | Vous pouvez installer``virtualenv`` via ``easy_install``:: | 213 | Il existe deux approches populaires en Python pour construire un environnement |
692 | 214 | de travail isolé. La première est ``virtualenv`` créé par Ian Biking, la | ||
693 | 215 | deuxième est ``zc.buildout`` créé par Jim Fulton. Il est même possible | ||
694 | 216 | d'utiliser ces paquets ensemble. Ils vous aideront à installer | ||
695 | 217 | ``zope.component`` et d'autres dépendances dans un environnement de | ||
696 | 218 | développement isolé. Passer un peu de temps à se familiariser avec ces outils | ||
697 | 219 | vous sera bénéfique lors des développements et des déploiements. | ||
698 | 220 | |||
699 | 221 | **virtualenv** | ||
700 | 222 | |||
701 | 223 | Vous pouvez installer ``virtualenv`` grâce à ``easy_install`` :: | ||
702 | 199 | 224 | ||
703 | 200 | $ easy_install virtualenv | 225 | $ easy_install virtualenv |
704 | 201 | 226 | ||
714 | 202 | Vous pouvez créez ensuite un nouvel environement comme ceci:: | 227 | Puis vous pouvez créer un nouvel environnement de cette façon :: |
715 | 203 | 228 | ||
716 | 204 | $ virtualenv myve | 229 | $ virtualenv --no-site-packages myve |
717 | 205 | 230 | ||
718 | 206 | Cette command a pour effet de créer un nouvel environement virtuel dans le | 231 | Ceci crée un nouvel environnement virtuel dans le dossier ``myve``. |
719 | 207 | dossier ``myve``. Maintenant, à partir du dossier ``myve``, vous | 232 | Maintenant, depuis ce dossier, vous pouvez installer ``zope.component`` et ses |
720 | 208 | pouvez installer ``zope.component`` et ses dépendances en utilisant | 233 | dépendances avec le script ``easy_install`` situé dans ``myve/bin`` :: |
712 | 209 | l'exécutable ``easy_install`` qui se trouve dans le dossier | ||
713 | 210 | ``myve/bin``:: | ||
721 | 211 | 234 | ||
722 | 212 | $ cd myve | 235 | $ cd myve |
723 | 213 | $ ./bin/easy_install zope.component | 236 | $ ./bin/easy_install zope.component |
724 | 214 | 237 | ||
728 | 215 | Vous pouvez maintenant importer les modules ``zope.interface`` et | 238 | Ensuite vous pouvez importer ``zope.interface`` et ``zope.component`` depuis |
729 | 216 | ``zope.component`` a partir de votre nouvel interpréteur ``python`` | 239 | le nouvel interprète ``python`` situé dans ``myve/bin`` :: |
727 | 217 | qui se trouve dans le dossier ``myve/bin||:: | ||
730 | 218 | 240 | ||
731 | 219 | $ ./bin/python | 241 | $ ./bin/python |
732 | 220 | 242 | ||
743 | 221 | Cette commande vous donnera une invite de commande Python que vous | 243 | Cette commande démarre un interprète Python que vous pourrez utiliser pour |
744 | 222 | pouvez utiliser pour exécuter les codes sources de ce livre. | 244 | lancer le code de ce livre. |
745 | 223 | 245 | ||
746 | 224 | L'utilisation de la recette ``zc.recipe.egg`` du paquet | 246 | |
747 | 225 | ``zc.buildout`` vous permet de créer un interpréteur python avec des | 247 | **zc.buildout** |
748 | 226 | PythonEggs spécifique. Premièrement, installez ``zc.buildout`` en | 248 | |
749 | 227 | utilisant la commande ``easy_install`` (Vous pouvez aussi faire cela à | 249 | En combinant ``zc.buildout`` et la recette ``zc.recipe.egg``, vous pouvez créer |
750 | 228 | l'intérieur d'un environement virtuel). Pour créer un nouveau buildout | 250 | un interprète Python ayant accès aux eggs Python spécifiés. Tout d'abord, |
751 | 229 | pour expériement des PythonEggs, commencez par créer un nouveau | 251 | installez ``zc.buildout`` grâce à la commande ``easy_install`` (vous pouvez le |
752 | 230 | dossier et initialisez le en utilisant la command ``buildout init``:: | 252 | faire à l'intérieur de l'environnement virtuel). Pour créer un nouveau |
753 | 253 | *buildout* servant à expérimenter des eggs Python, commencez par créer un | ||
754 | 254 | dossier, puis initialisez-le grâce à la commande ``buildout init`` :: | ||
755 | 231 | 255 | ||
756 | 232 | $ mkdir mybuildout | 256 | $ mkdir mybuildout |
757 | 233 | $ cd mybuildout | 257 | $ cd mybuildout |
758 | 234 | $ buildout init | 258 | $ buildout init |
759 | 235 | 259 | ||
763 | 236 | Maintenant, le nouveau dossier ``mybuildout`` est un buildout. Le | 260 | De cette façon, le dossier ``mybuildout`` devient un « buildout ». Le fichier de |
764 | 237 | fichier de configuration par défaut du buildout est `buildout.cfg`. | 261 | configuration de buildout est par défaut `buildout.cfg`. Après initialisation, |
765 | 238 | Après l'initilisation, il a pour contenu:: | 262 | il doit contenir les lignes suivantes :: |
766 | 239 | 263 | ||
767 | 240 | [buildout] | 264 | [buildout] |
768 | 241 | parts = | 265 | parts = |
769 | 242 | 266 | ||
771 | 243 | Vous pouvez le modifier comme ceci:: | 267 | Vous pouvez le modifier pour qu'il corresponde à ceci :: |
772 | 244 | 268 | ||
773 | 245 | [buildout] | 269 | [buildout] |
774 | 246 | parts = py | 270 | parts = py |
775 | @@ -250,319 +274,314 @@ | |||
776 | 250 | interpreter = python | 274 | interpreter = python |
777 | 251 | eggs = zope.component | 275 | eggs = zope.component |
778 | 252 | 276 | ||
783 | 253 | Maintenant exécutez la commande ``buildout`` disponible dans le | 277 | Si maintenant vous lancez la commande ``buildout`` disponible à l'intérieur du |
784 | 254 | dossier ``mybuildout/bin`` sans aucun argument. Cela a pour effet de | 278 | dossier ``mybuildout/bin``, vous obtiendrez un nouvel interprète Python dans le |
785 | 255 | créer un nouvel interpréteur à l'intérieur du dossier | 279 | dossier ``mybuildout/bin`` :: |
782 | 256 | ``mybuildout/bin``:: | ||
786 | 257 | 280 | ||
787 | 258 | $ ./bin/buildout | 281 | $ ./bin/buildout |
788 | 259 | $ ./bin/python | 282 | $ ./bin/python |
789 | 260 | 283 | ||
804 | 261 | Cette commande vous donnera un invite de commande Python que vous | 284 | Cette commande démarre un interprète Python que vous pourrez utiliser pour |
805 | 262 | pourrez utiliser pour tester le code source de ce livre. | 285 | lancer le code de ce livre. |
806 | 263 | 286 | ||
807 | 264 | .. [#projects] http://wiki.zope.org/zope3/ComponentArchitecture | 287 | |
808 | 265 | .. [#proposal] http://wiki.zope.org/zope3/LocalComponentManagementSimplification | 288 | Un exemple |
795 | 266 | .. [#extras] http://peak.telecommunity.com/DevCenter/setuptools#declaring-dependencies | ||
796 | 267 | .. [#bugs] https://bugs.launchpad.net/zope3 | ||
797 | 268 | .. [#discussions] http://mail.zope.org/mailman/listinfo/zope-dev | ||
798 | 269 | .. [#pypi] Repository of Python packages: http://pypi.python.org/pypi | ||
799 | 270 | .. [#easyinstall] http://peak.telecommunity.com/DevCenter/EasyInstall | ||
800 | 271 | .. [#systempython] http://article.gmane.org/gmane.comp.web.zope.zope3/21045 | ||
801 | 272 | |||
802 | 273 | |||
803 | 274 | An example | ||
809 | 275 | ---------- | 289 | ---------- |
810 | 276 | 290 | ||
811 | 277 | 291 | ||
812 | 278 | Introduction | 292 | Introduction |
813 | 279 | ~~~~~~~~~~~~ | 293 | ~~~~~~~~~~~~ |
814 | 280 | 294 | ||
840 | 281 | Consider a business application for registering guests staying in a | 295 | Imaginez une application servant à enregistrer les clients d'un hôtel. En |
841 | 282 | hotel. Python can implement this in a number of ways. We will start | 296 | Python, il est possible de faire ceci de différentes manières. Nous allons |
842 | 283 | with a brief look at a procedural implementation, and then move to a | 297 | commencer par étudier rapidement la méthode procédurale, puis nous diriger vers |
843 | 284 | basic object oriented approach. As we examine the object oriented | 298 | une approche basique orientée objet. En examinant l'approche orientée objet, |
844 | 285 | approach, we will see how we can benefit from the classic design | 299 | nous verrons comment nous pouvons bénéficier des motifs de conception |
845 | 286 | patterns, `adapter` and `interface`. This will bring us into the | 300 | `adaptateur` et `interface`. Cela nous fera entrer dans le monde de la Zope |
846 | 287 | world of the Zope Component Architecture. | 301 | Component Architecture. |
847 | 288 | 302 | ||
848 | 289 | 303 | ||
849 | 290 | Procedural approach | 304 | Approche procédurale |
850 | 291 | ~~~~~~~~~~~~~~~~~~~ | 305 | ~~~~~~~~~~~~~~~~~~~~ |
851 | 292 | 306 | ||
852 | 293 | In any business application, data storage is very critical. For | 307 | Dans toute application professionnelle, le stockage des données est un point |
853 | 294 | simplicity, this example use a Python dictionary as the storage. Key | 308 | critique. Pour une question de simplicité, cet exemple utilise un simple |
854 | 295 | of the dictionary will be the unique Id for a particular guest. And | 309 | dictionnaire Python comme méthode de stockage. Nous allons générer des |
855 | 296 | value will be another dictionary with key as the property name:: | 310 | identifiants uniques pour le dictionnaire, la valeur associée sera elle-même un |
856 | 297 | 311 | dictionnaire contenant les détails de l'enregistrement. | |
857 | 298 | >>> guests_db = {} #key: unique Id, value: details in a dictionary | 312 | |
858 | 299 | 313 | >>> bookings_db = {} #key: unique ID, value: details in a dictionary | |
859 | 300 | In a simplistic method, a function which accepts details as arguments | 314 | |
860 | 301 | is enough to do the registration. You also required a supporting | 315 | Une implémentation minimaliste nécessite une fonction à laquelle on transmet les |
861 | 302 | function to get the next Id for your data storage. | 316 | détails de l'enregistrement et une fonction annexe qui fournit les |
862 | 303 | 317 | identifiants uniques utilisés comme clés du dictionnaire de stockage. | |
863 | 304 | The supporting function, for getting the next Id can be implemented | 318 | |
864 | 305 | like this:: | 319 | Nous pouvons obtenir un identifiant unique de cette façon :: |
865 | 306 | 320 | ||
866 | 307 | >>> def get_next_id(): | 321 | >>> def get_next_id(): |
868 | 308 | ... db_keys = guests_db.keys() | 322 | ... db_keys = bookings_db.keys() |
869 | 309 | ... if db_keys == []: | 323 | ... if db_keys == []: |
870 | 310 | ... next_id = 1 | 324 | ... next_id = 1 |
871 | 311 | ... else: | 325 | ... else: |
872 | 312 | ... next_id = max(db_keys) + 1 | 326 | ... next_id = max(db_keys) + 1 |
873 | 313 | ... return next_id | 327 | ... return next_id |
874 | 314 | 328 | ||
889 | 315 | As you can see, the `get_next_id` function implementation is very | 329 | Comme vous pouvez voir, l'implémentation de la fonction `get_next_id` est très |
890 | 316 | simple. Well, this is not the ideal way, but it is sufficient to | 330 | simple. La fonction récupère une liste de clés et vérifie si la liste est vide. |
891 | 317 | explain concepts. The function first get all keys of storage as list | 331 | Si c'est le cas, nous savons que nous en sommes au premier enregistrement et |
892 | 318 | and check whether it is empty or not. If the list is empty, so no | 332 | nous renvoyons `1`. Sinon, nous ajoutons `1` à la valeur maximale de la liste et |
893 | 319 | item is stored, it return `1` as the next Id. And if the list is not | 333 | nous renvoyons la nouvelle valeur en résultant. |
894 | 320 | empty, the next Id is calculated by adding `1` to the maximum value of | 334 | |
895 | 321 | list. | 335 | Ensuite, pour créer des enregistrements dans le dictionnaire bookings_db, nous |
896 | 322 | 336 | utilisons la fonction suivante :: | |
897 | 323 | The function to register guest can get next unique Id using | 337 | |
898 | 324 | `get_next_id` function, then assign the details of guest using a | 338 | >>> def book_room(name, place): |
885 | 325 | dictionary. Here is the function to get details and store in the | ||
886 | 326 | database:: | ||
887 | 327 | |||
888 | 328 | >>> def register_guest(name, place): | ||
899 | 329 | ... next_id = get_next_id() | 339 | ... next_id = get_next_id() |
901 | 330 | ... guests_db[next_id] = { | 340 | ... bookings_db[next_id] = { |
902 | 331 | ... 'name': name, | 341 | ... 'name': name, |
904 | 332 | ... 'place': place | 342 | ... 'room': place |
905 | 333 | ... } | 343 | ... } |
906 | 334 | 344 | ||
931 | 335 | We will end our discussion of the procedural approach here. | 345 | Une application de gestion des enregistrements d'hôtel a besoin de données |
932 | 336 | It will be much easier to add required features such as data | 346 | supplémentaires : |
933 | 337 | persistence, design flexibility, and code testability using objects. | 347 | |
934 | 338 | 348 | - les numéros de téléphone | |
935 | 339 | 349 | - les options des chambres | |
936 | 340 | Object oriented approach | 350 | - les méthodes de paiement |
937 | 341 | ~~~~~~~~~~~~~~~~~~~~~~~~ | 351 | - ... |
938 | 342 | 352 | ||
939 | 343 | .. ??? should this paragraph talk about "creating an object for | 353 | Et de code pour gérer les données : |
940 | 344 | handling registration" or "creating a class to handle registration"? | 354 | |
941 | 345 | 355 | - annuler une réservation | |
942 | 346 | In object oriented methodology, you can think of a registrar object | 356 | - Modifier une réservation |
943 | 347 | handling the registration. There are many advantages for creating an | 357 | - payer une chambre |
944 | 348 | object for handling registration. Most importantly, the abstraction | 358 | - stocker les données |
945 | 349 | provided by the registrar object makes the code easier to understand. | 359 | - assurer la sécurité des données |
946 | 350 | It offers a way to group related functionality, and can be extended | 360 | - ... |
947 | 351 | via inheritance. As features are added, such as canceling and updating | 361 | |
948 | 352 | registration, the registrar object can grow to provide them, or | 362 | Si nous devions continuer l'exemple procédural, il faudrait créer plusieurs |
949 | 353 | delegate them to another object. | 363 | fonctions, en renvoyant les données de l'une à l'autre. Au fur à mesure que les |
950 | 354 | 364 | fonctionnalités seraient ajoutées, le code deviendrait de plus en plus difficile | |
951 | 355 | Lets look at the implementation details of a registrar object | 365 | à maintenir et les bogues deviendraient difficiles à trouver et à corriger. |
952 | 356 | implemented as a class:: | 366 | |
953 | 357 | 367 | Nous n'irons pas plus loin dans l'approche procédurale. Il sera beaucoup plus | |
954 | 358 | >>> class guestRegistrar(object): | 368 | facile d'assurer la persistance des données, la flexibilité de la conception et |
955 | 369 | l'écriture de tests unitaires en utilisant des objets. | ||
956 | 370 | |||
957 | 371 | |||
958 | 372 | Approche orientée objet | ||
959 | 373 | ~~~~~~~~~~~~~~~~~~~~~~~ | ||
960 | 374 | |||
961 | 375 | Notre discussion sur la conception orientée objet nous amène à la notion de | ||
962 | 376 | « classe » qui sert à encapsuler les données et le code qui les gère. | ||
963 | 377 | |||
964 | 378 | Notre classe principale sera « FrontDesk ». Le FrontDesk et d'autres classes | ||
965 | 379 | auxquelles il délèguera du traitement, sauront comment gérer les données de | ||
966 | 380 | l'hôtel. Nous allons créer des instances de FrontDesk pour appliquer cette | ||
967 | 381 | connaissance au métier de la gestion d'hôtel. | ||
968 | 382 | |||
969 | 383 | L'expérience a montré qu'en consolidant le code et les contraintes sur les | ||
970 | 384 | données via des objets, on aboutit à un code qui est plus facile à comprendre, à | ||
971 | 385 | tester et à modifier. | ||
972 | 386 | |||
973 | 387 | Observons les détails d'implémentation de la classe FrontDesk :: | ||
974 | 388 | |||
975 | 389 | >>> class FrontDesk(object): | ||
976 | 359 | ... | 390 | ... |
978 | 360 | ... def register(self, name, place): | 391 | ... def book_room(self, name, place): |
979 | 361 | ... next_id = get_next_id() | 392 | ... next_id = get_next_id() |
981 | 362 | ... guests_db[next_id] = { | 393 | ... bookings_db[next_id] = { |
982 | 363 | ... 'name': name, | 394 | ... 'name': name, |
983 | 364 | ... 'place': place | 395 | ... 'place': place |
984 | 365 | ... } | 396 | ... } |
985 | 366 | 397 | ||
1007 | 367 | In this implementation, the registrar object (an instance of | 398 | Dans cette implémentation, l'objet `frontdesk` (une instance de la classe |
1008 | 368 | `GuestRegistrar` class) is handling the registration. With this | 399 | FrontDesk) est capable de prendre en charge les réservations. Nous pouvons |
1009 | 369 | design, a particular registrar object can perform multiple | 400 | l'utiliser de la façon suivante :: |
1010 | 370 | registrations. | 401 | |
1011 | 371 | 402 | >>> frontdesk = FrontDesk() | |
1012 | 372 | This is how you can use the current registrar implementation:: | 403 | >>> frontdesk.book_room("Jack", "Bangalore") |
1013 | 373 | 404 | ||
1014 | 374 | >>> registrar = GuestRegistrar() | 405 | Dans tout projet, on est confronté à des changements de besoins. Dans notre cas, |
1015 | 375 | >>> registrar.register("Jack", "Bangalore") | 406 | la direction a décidé que chaque client devait fournit un numéro de téléphone, |
1016 | 376 | 407 | donc nous devons changer le code. | |
1017 | 377 | Requirement changes are unavoidable in any real world project. | 408 | |
1018 | 378 | Consider this case, after some time, a new requirement is arising: the | 409 | Nous pouvons satisfaire ce nouveau besoin en ajoutant un argument à la méthode |
1019 | 379 | guests also required to provide phone number to admit them. You will | 410 | `book_room` qui sera ajouté au dictionnaire des valeurs :: |
1020 | 380 | be required to change the implementation of registrar object to | 411 | |
1021 | 381 | support it. | 412 | >>> class FrontDesk(object): |
1001 | 382 | |||
1002 | 383 | You can achieve this requirement by adding one argument to `registrar` | ||
1003 | 384 | method and use that argument in the dictionary of values. Here is the | ||
1004 | 385 | new implementation for this requirement:: | ||
1005 | 386 | |||
1006 | 387 | >>> class GuestRegistrar(object): | ||
1022 | 388 | ... | 413 | ... |
1024 | 389 | ... def register(self, name, place, phone): | 414 | ... def book_room(self, name, place, phone): |
1025 | 390 | ... next_id = get_next_id() | 415 | ... next_id = get_next_id() |
1027 | 391 | ... guests_db[next_id] = { | 416 | ... bookings_db[next_id] = { |
1028 | 392 | ... 'name': name, | 417 | ... 'name': name, |
1029 | 393 | ... 'place': place, | 418 | ... 'place': place, |
1030 | 394 | ... 'phone': phone | 419 | ... 'phone': phone |
1031 | 395 | ... } | 420 | ... } |
1032 | 396 | 421 | ||
1041 | 397 | Other than migrating the data to new schema, now you have to change | 422 | En plus de devoir migrer les données vers le nouveau schéma, nous devons changer |
1042 | 398 | the usage of `GuestRegistrar` in all places. If you can abstract the | 423 | tous les appels à la classe ``FrontDesk``. Si nous incorporons les coordonnées |
1043 | 399 | details of guest into an object and use it for registration, the code | 424 | de chaque client dans un objet et que nous utilisons cet objet pour les |
1044 | 400 | changes can be minimized. If you follow this design, you have to pass | 425 | réservations, les modifications de code pourront être minimisées. Nous pouvons |
1045 | 401 | that guest object instead of more arguments to the function. The new | 426 | maintenant changer les détails de l'objet client sans avoir à changer les appels |
1046 | 402 | implementation with guest object will look like this:: | 427 | à FrontDesk. |
1047 | 403 | 428 | ||
1048 | 404 | >>> class GuestRegistrar(object): | 429 | Nous avons donc :: |
1049 | 430 | |||
1050 | 431 | >>> class FrontDesk(object): | ||
1051 | 405 | ... | 432 | ... |
1053 | 406 | ... def register(self, guest): | 433 | ... def book_room(self, guest): |
1054 | 407 | ... next_id = get_next_id() | 434 | ... next_id = get_next_id() |
1056 | 408 | ... guests_db[next_id] = { | 435 | ... bookings_db[next_id] = { |
1057 | 409 | ... 'name': guest.name, | 436 | ... 'name': guest.name, |
1058 | 410 | ... 'place': guest.place, | 437 | ... 'place': guest.place, |
1059 | 411 | ... 'phone': guest.phone | 438 | ... 'phone': guest.phone |
1060 | 412 | ... } | 439 | ... } |
1061 | 413 | 440 | ||
1065 | 414 | Well, even in this implementation you have to change code. Code | 441 | Nous devons toujours modifier le code pour répondre aux nouvelles demandes. |
1066 | 415 | change for requirement is unavoidable, your goal should be to minimize | 442 | C'est inévitable, cependant notre but est de minimiser ces changements et donc |
1067 | 416 | changes and make it maintainable. | 443 | d'améliorer la maintenabilité. |
1068 | 417 | 444 | ||
1069 | 418 | .. note:: | 445 | .. note:: |
1070 | 419 | 446 | ||
1098 | 420 | You should have the courage to make any change, major or minor, at | 447 | Lors du développement il ne faut jamais hésiter à faire des changements sans |
1099 | 421 | any time. Immediate feedback is the only way you can get the | 448 | craindre de casser l'application. L'avertissement nécessaire doit être |
1100 | 422 | courage. Using automated testing, you can get the immediate | 449 | immédiatement obtenu grâce à des tests automatisés. Avec des tests bien écrits |
1101 | 423 | feedback and so the courage to make changes. For more details about | 450 | (et un bon contrôle de versions), vous pouvez faire impunément des changements |
1102 | 424 | this subject, you can read the book called `Extreme Programming | 451 | aussi importants que vous souhaitez. Une bonne source d'informations à propos de |
1103 | 425 | Explained` by Kent Beck. | 452 | cette philosophie de programmation est l'ouvrage `Extreme Programming Explained` |
1104 | 426 | 453 | par Kent Beck. | |
1105 | 427 | By introducing the guest object, you saved some typing. More than | 454 | |
1106 | 428 | that, the abstraction of guest object made the system much simpler and | 455 | En introduisant l'objet guest, vous avez économisé un peu de temps. Mais plus |
1107 | 429 | easy to understand. The better understanding leads to better | 456 | important, l'abstraction apportée par l'objet guest a rendu le système plus |
1108 | 430 | restructuring and hence maintainable code. | 457 | simple et mieux compréhensible. Par conséquent, le code est plus facile à |
1109 | 431 | 458 | restructurer et à maintenir. | |
1110 | 432 | 459 | ||
1111 | 433 | The adapter pattern | 460 | |
1112 | 434 | ~~~~~~~~~~~~~~~~~~~ | 461 | Le motif `adaptateur` |
1113 | 435 | 462 | ~~~~~~~~~~~~~~~~~~~~~ | |
1114 | 436 | In a real application, as you noted earlier, the registrar object may | 463 | |
1115 | 437 | have cancellation and/or updation functionalities. Suppose there are | 464 | Dans une vraie application, l'objet frontdesk devra gérer des fonctionnalités |
1116 | 438 | two more methods like, `cancel_registration` and | 465 | comme les annulations et les modifications. Avec la conception actuelle, nous |
1117 | 439 | `update_registration`. In the new design you will be required to pass | 466 | devons transmettre l'objet `guest` au frontdesk à chaque fois que nous appelons |
1118 | 440 | the guest object for each methods. You can solve this problem by | 467 | les méthodes `cancel_booking` et `update_booking`. |
1119 | 441 | setting guest object as an attribute of registrar object. | 468 | |
1120 | 442 | 469 | Nous pouvons éviter ceci si nous transmettons l'objet `guest` à | |
1121 | 443 | Here is the new implementation of registrar object which set guest | 470 | FrontDesk.__init__() et si nous le stockons en attribut de l'instance. |
1122 | 444 | object as an attribute:: | 471 | |
1123 | 445 | 472 | >>> class FrontDeskNG(object): | |
1097 | 446 | >>> class GuestRegistrarNG(object): | ||
1124 | 447 | ... | 473 | ... |
1125 | 448 | ... def __init__(self, guest): | 474 | ... def __init__(self, guest): |
1126 | 449 | ... self.guest = guest | 475 | ... self.guest = guest |
1127 | 450 | ... | 476 | ... |
1129 | 451 | ... def register(self): | 477 | ... def book_room(self): |
1130 | 452 | ... guest = self.guest | 478 | ... guest = self.guest |
1131 | 453 | ... next_id = get_next_id() | 479 | ... next_id = get_next_id() |
1133 | 454 | ... guests_db[next_id] = { | 480 | ... bookings_db[next_id] = { |
1134 | 455 | ... 'name': guest.name, | 481 | ... 'name': guest.name, |
1135 | 456 | ... 'place': guest.place, | 482 | ... 'place': guest.place, |
1136 | 457 | ... 'phone': guest.phone | 483 | ... 'phone': guest.phone |
1137 | 458 | ... } | 484 | ... } |
1168 | 459 | 485 | ... | |
1169 | 460 | The solution you reached is a common design pattern called, `Adapter`. | 486 | ... def cancel_booking(self): |
1170 | 461 | With this design, now you can add more methods, so more functionality, | 487 | ... guest = self.guest |
1171 | 462 | if required. | 488 | ... #code for cancellations goes here ... |
1172 | 463 | 489 | ... | |
1173 | 464 | In this implementation, while creating the instance you have to pass | 490 | ... def update_booking(self): |
1174 | 465 | the guest object which has the values as attributes. Now you also | 491 | ... guest = self.guest |
1175 | 466 | required to create separate instances of `GuestRegistrarNG` for each | 492 | ... #code for updatiion goes here ... |
1176 | 467 | guest object. | 493 | |
1177 | 468 | 494 | ||
1178 | 469 | Now just step back and think differently. Suppose you are the creator | 495 | La solution que nous avons obtenue est un motif de conception courant appelé |
1179 | 470 | of this software and selling it to many hotel customers. Consider a | 496 | `adaptateur`. Le `Gang of Four` [#patternbook]_ résume ainsi l'*esprit* de |
1180 | 471 | case where your different clients requires different storages. For | 497 | l'adaptateur :: |
1181 | 472 | example, one registrar might store the details in a relational | 498 | |
1182 | 473 | database and another one might store them in Zope Object Database | 499 | « Convertir l'interface d'une classe en une autre interface |
1183 | 474 | (ZODB). It would be better if you can replace the registrar object | 500 | à laquelle le client s'attend. L'adaptateur permet à des |
1184 | 475 | with another one which store guest details in a different way. So, a | 501 | classes de fonctionner ensemble même si elles ont des |
1185 | 476 | mechanism to change implementation based on some configuration would | 502 | interfaces incompatibles. » |
1186 | 477 | be useful. | 503 | |
1187 | 478 | 504 | En général, un objet adaptateur *contient* un objet adapté :: | |
1158 | 479 | Zope component architecture provides a mechanism to replace components | ||
1159 | 480 | based on configuration. Using Zope component architecture you can | ||
1160 | 481 | register components in a registry called component registry. Later, | ||
1161 | 482 | retrieve component based on the configuration. | ||
1162 | 483 | |||
1163 | 484 | The `GuestRegistrarNG` class follows, as you noted, a pattern called | ||
1164 | 485 | `Adapter`. The `GuestRegistrarNG` is the adapter which adapts the | ||
1165 | 486 | guest object (adaptee). As you can see, the adapter should contain | ||
1166 | 487 | the component it adapts (adaptee). This is a typical implementation | ||
1167 | 488 | of adapter:: | ||
1188 | 489 | 505 | ||
1189 | 490 | >>> class Adapter(object): | 506 | >>> class Adapter(object): |
1190 | 491 | ... | 507 | ... |
1191 | 492 | ... def __init__(self, adaptee): | 508 | ... def __init__(self, adaptee): |
1192 | 493 | ... self.adaptee = adaptee | 509 | ... self.adaptee = adaptee |
1193 | 494 | 510 | ||
1229 | 495 | Now the adapter can make use adaptee (call its methods or access | 511 | Ce motif sera utile lorsqu'on sera confronté à des détails d'implémentation qui |
1230 | 496 | attributes). An adapter may adapt more than one component. Zope | 512 | dépendent de considérations telles que: |
1231 | 497 | component architecture provides a mechanism to effectively use these | 513 | |
1232 | 498 | kind of objects. So, which component should be used will become a | 514 | - modification des besoins client |
1233 | 499 | matter of configuration. | 515 | - modification des méthodes de stockage (ZODB, RDBM, XML) |
1234 | 500 | 516 | - modification des méthodes de sortie (HTML, PDF, texte pur) | |
1235 | 501 | This is a common scenario where you want to use different objects | 517 | - modification de la source utilisée (ReST, Markdown, Textile) |
1236 | 502 | doing same things, but the details may change. There are many | 518 | |
1237 | 503 | situations in programming where you want to use different | 519 | La ZCA utilise des adaptateurs et un *registre de composants* pour fournir la |
1238 | 504 | implementations for same type of objects. Here is a small list of | 520 | capacité de changer les détails d'implémentation du code via de la |
1239 | 505 | other common scenarios: | 521 | *configuration*. |
1240 | 506 | 522 | ||
1241 | 507 | - A wiki engine with support for multiple markups (STX, reST, Plain | 523 | Comme nous pouvons le constater dans la section sur les adaptateurs de la ZCA, |
1242 | 508 | text, etc.) | 524 | la capacité de configurer les détails d'implémentation fournit des avantages |
1243 | 509 | 525 | intéressants : | |
1244 | 510 | - An object browser which shows size of different types of objects. | 526 | |
1245 | 511 | 527 | - on peut interchanger les implémentations | |
1246 | 512 | - Different types of output formats for text data (PDF, HTML etc.) | 528 | - on peut ajouter de nouvelles implémentations si besoin |
1247 | 513 | 529 | - on améliore les possibilités de réutilisation, aussi bien d'un code existant que | |
1248 | 514 | - When developing an application for multiple clients, their | 530 | du code utilisant la ZCA. |
1249 | 515 | requirements may change. Maintaining separate code bases of the | 531 | |
1250 | 516 | same application for different clients is difficult. A better | 532 | Ces possibilités mènent à du code qui est flexible, évolutif et réutilisable. Il |
1251 | 517 | approach would be to create reusable components and configure them | 533 | y a un cependant un coût : maintenir le registre de composants ajoute un niveau |
1252 | 518 | based on client-specific requirements. | 534 | de complexité à l'application. Si une application n'a pas besoin de ces |
1253 | 519 | 535 | avantages, la ZCA n'est pas pas nécessaire. | |
1254 | 520 | All these examples points to situations where you want to make | 536 | |
1255 | 521 | applications extensible or pluggable. Do not use `adapter` | 537 | Nous sommes maintenant prêts à étudier la Zope Component Architecture, en |
1256 | 522 | components where you do not want extensibility or pluggability. | 538 | commençant avec les interfaces. |
1222 | 523 | |||
1223 | 524 | Zope component architecture provides `adapter` components to solve | ||
1224 | 525 | these kinds of problems. In fact, `GuestRegistrarNG` is an adapter | ||
1225 | 526 | without explicit interface declaration. This tutorial will discuss | ||
1226 | 527 | adapters after introducing the concept of interfaces. Interfaces are | ||
1227 | 528 | one of the foundations of Zope components, so understanding the | ||
1228 | 529 | concept and usage of interfaces is very important. | ||
1257 | 530 | 539 | ||
1258 | 531 | 540 | ||
1259 | 532 | Interfaces | 541 | Interfaces |
1260 | 533 | ---------- | 542 | ---------- |
1261 | 534 | 543 | ||
1262 | 535 | |||
1263 | 536 | Introduction | 544 | Introduction |
1264 | 537 | ~~~~~~~~~~~~ | 545 | ~~~~~~~~~~~~ |
1265 | 538 | 546 | ||
1293 | 539 | `Design Patterns` is a classic book in software engineering by the | 547 | Le fichier README.txt [#readmes]_ dans chemin/vers/zope/interface définit les |
1294 | 540 | `Gang of Four` [#patternbook]_. In this book they recommend: "Program | 548 | interfaces de cette manière :: |
1295 | 541 | to an interface, not an implementation". Defining formal interfaces | 549 | |
1296 | 542 | helps you better understand system. Moreover interface brings you all | 550 | Les interfaces sont des objets qui spécifient (documentent) le |
1297 | 543 | the benefits of ZCA. | 551 | comportement externe des objets qui les « fournissent ». |
1298 | 544 | 552 | Une interface spécifie un comportement au travers : | |
1299 | 545 | Interface define the behavior and state of objects. An interface | 553 | |
1300 | 546 | describes how you work with the object. If you like metaphor, think | 554 | - de documentation informelle dans une docstring |
1301 | 547 | of interface as a `contract for object`. Another metaphor which may | 555 | |
1302 | 548 | help is `blueprint for objects`. In the code, methods and attributes | 556 | - de définitions d'attributs |
1303 | 549 | are forming the object's interface. | 557 | |
1304 | 550 | 558 | - d'invariants qui sont des conditions posées sur les objets | |
1305 | 551 | The notion of interface is very explicit in modern languages like | 559 | fournissant l'interface. |
1306 | 552 | Java, C#, VB.NET etc. Also these languages provide some syntax for | 560 | |
1307 | 553 | defining interfaces. Python has the notion interfaces, but it is not | 561 | L'ouvrage de référence `Design Patterns` [#patternbook]_ par le `Gang of Four` |
1308 | 554 | very explicit. To simulate a formal definition of interfaces in C++, | 562 | recommande que vous devez « programmer pour une interface, pas pour une |
1309 | 555 | `Gang of Four` used classes with virtual functions in `Design | 563 | implémentation ». Définir une interface formelle est utile dans la compréhension |
1310 | 556 | Patterns` book. In a similar fashion, Zope component architecture use | 564 | d'un système. De plus, les interfaces vous apportent tous les bénéfices de la |
1311 | 557 | ``zope.interface.Interface`` inherited meta-class for defining an | 565 | ZCA. |
1312 | 558 | interface. | 566 | |
1313 | 559 | 567 | .. [#readmes] L'arborescence du code de Zope contient de nombreux fichiers README.txt | |
1314 | 560 | The base of object-orientation is the communication between objects. | 568 | qui offrent une très bonne documentation. |
1315 | 561 | Messages are used for the communication between objects. In Python, | 569 | .. [#patternbook] http://en.wikipedia.org/wiki/Design_Patterns |
1316 | 562 | functions, methods or any other callable can be used to handle | 570 | |
1317 | 563 | messages. | 571 | Une interface spécifie les caractéristiques d'un objet, son comportement et ses |
1318 | 564 | 572 | capacités. Elle décrit le « quoi » d'un objet. Pour apprendre le « comment », | |
1319 | 565 | For example, consider this class:: | 573 | vous devez regarder l'implémentation. |
1320 | 574 | |||
1321 | 575 | Les métaphores couramment utilisées pour les interfaces sont `contrat` ou | ||
1322 | 576 | `plan`, des termes légaux et architecturaux pour représenter un jeu de | ||
1323 | 577 | spécifications. | ||
1324 | 578 | |||
1325 | 579 | Dans certains langages de programmation comme Java, C# ou VB.NET, les | ||
1326 | 580 | interfaces sont un aspect explicite du langage. Étant donné que Python ne | ||
1327 | 581 | possède pas nativement d'interfaces, la ZCA les implémente comme des | ||
1328 | 582 | meta-classes desquelles on hérite. | ||
1329 | 583 | |||
1330 | 584 | Voici un exemple classique de Hello World :: | ||
1331 | 566 | 585 | ||
1332 | 567 | >>> class Host(object): | 586 | >>> class Host(object): |
1333 | 568 | ... | 587 | ... |
1334 | @@ -571,24 +590,23 @@ | |||
1335 | 571 | ... | 590 | ... |
1336 | 572 | ... return "Good morning, %s!" % name | 591 | ... return "Good morning, %s!" % name |
1337 | 573 | 592 | ||
1341 | 574 | In the above class, you defined a `goodmorning` method. If you call | 593 | Dans la classe ci-dessus, on a défini une méthode `goodmorning`. Si vous appelez |
1342 | 575 | the `goodmorning` method from an object created using this class, it | 594 | cette méthode depuis un objet créé en utilisant cette classe, vous obtiendrez un |
1343 | 576 | will return `Good morning, ...!` :: | 595 | `Good morning, ...!` :: |
1344 | 577 | 596 | ||
1345 | 578 | >>> host = Host() | 597 | >>> host = Host() |
1346 | 579 | >>> host.goodmorning('Jack') | 598 | >>> host.goodmorning('Jack') |
1347 | 580 | 'Good morning, Jack!' | 599 | 'Good morning, Jack!' |
1348 | 581 | 600 | ||
1359 | 582 | Here ``host`` is the actual object. The implementation details of | 601 | Ici, ``host`` est l'objet réel que votre code utilise. Si vous voulez |
1360 | 583 | this object is the class ``Host``. Now, how to find how the object | 602 | examiner les détails d'implémentation, vous devez accéder à la classe ``Host``, |
1361 | 584 | looks like, that is, what are the methods and attributes of the | 603 | soit via le code source, soit au travers d'un outil de documentation d'API |
1362 | 585 | object. For this, either you have go through the implementation | 604 | [#api]_. |
1363 | 586 | details (``Host`` class) of the object or a separate API documentation | 605 | |
1364 | 587 | [#api]_ will be required. | 606 | .. [#api] http://en.wikipedia.org/wiki/Application_programming_interface |
1365 | 588 | 607 | ||
1366 | 589 | You can use the ``zope.interface`` package to define the interface of | 608 | Maintenant nous allons commencer à utiliser les interfaces de la ZCA. Pour la |
1367 | 590 | objects. For the class given above you can specify the interface like | 609 | classe ci-dessus, vous pouvez définir l'interface comme suit :: |
1358 | 591 | this:: | ||
1368 | 592 | 610 | ||
1369 | 593 | >>> from zope.interface import Interface | 611 | >>> from zope.interface import Interface |
1370 | 594 | 612 | ||
1371 | @@ -597,21 +615,18 @@ | |||
1372 | 597 | ... def goodmorning(guest): | 615 | ... def goodmorning(guest): |
1373 | 598 | ... """Say good morning to guest""" | 616 | ... """Say good morning to guest""" |
1374 | 599 | 617 | ||
1390 | 600 | As you can see, the interface is defined using Python class statement. | 618 | Vous pouvez constater que l'interface hérite de zope.interface.Interface. C'est |
1391 | 601 | We use (abuse?) Python's class statement to define interfaces. To | 619 | de cette façon (abusive ?) que la ZCA définit des interfaces. Le préfixe « I » |
1392 | 602 | make a class an interface, it must be inherited from | 620 | pour le nom de la classe est une convention utile. |
1393 | 603 | ``zope.interface.Interface`` . The ``I`` prefix for interface name is | 621 | |
1394 | 604 | a convention. | 622 | |
1395 | 605 | 623 | Déclarer des interfaces | |
1396 | 606 | 624 | ~~~~~~~~~~~~~~~~~~~~~~~ | |
1397 | 607 | Declaring interfaces | 625 | |
1398 | 608 | ~~~~~~~~~~~~~~~~~~~~ | 626 | Vous avez déjà vu comment déclarer une interface en utilisant ``zope.interface`` |
1399 | 609 | 627 | dans la section précédente. Cette section va expliquer les concepts en détail. | |
1400 | 610 | You have already seen how to declare an interface using | 628 | |
1401 | 611 | ``zope.interface`` in previous section. This section will explain the | 629 | Prenez cette exemple d'interface :: |
1387 | 612 | concepts in detail. | ||
1388 | 613 | |||
1389 | 614 | Consider this example interface:: | ||
1402 | 615 | 630 | ||
1403 | 616 | >>> from zope.interface import Interface | 631 | >>> from zope.interface import Interface |
1404 | 617 | >>> from zope.interface import Attribute | 632 | >>> from zope.interface import Attribute |
1405 | @@ -624,60 +639,58 @@ | |||
1406 | 624 | ... def goodmorning(guest): | 639 | ... def goodmorning(guest): |
1407 | 625 | ... """Say good morning to guest""" | 640 | ... """Say good morning to guest""" |
1408 | 626 | 641 | ||
1443 | 627 | The interface, ``IHost`` has two attributes, ``name`` and | 642 | L'interface ``IHost`` possède deux attributs, ``name`` et ``goodmorning``. |
1444 | 628 | ``goodmorning``. Recall that, at least in Python, methods are also | 643 | Rappelez-vous qu'en Python les méthodes des classes sont aussi des attributs. |
1445 | 629 | attributes of classes. The ``name`` attribute is defined using | 644 | L'attribut ``name`` est défini en utilisant la classe |
1446 | 630 | ``zope.interface.Attribute`` class. When you add the attribute | 645 | ``zope.interface.Attribute``. Quand vous ajoutez l'attribut ``name`` à |
1447 | 631 | ``name`` to the ``IHost`` interface, you don't set an initial value. | 646 | l'interface ``IHost``, vous ne définissez pas de valeur initiale. La raison de |
1448 | 632 | The purpose of defining the attribute ``name`` here is merely to | 647 | définir l'attribut ``name`` ici est simplement d'indiquer que toute |
1449 | 633 | indicate that any implementation of this interface will feature an | 648 | implémentation de cette interface doit fournir un attribut nommé ``name``. Dans |
1450 | 634 | attribute named ``name``. In this case, you don't even say what type | 649 | ce cas, vous n'indiquez même pas de quel type doit être l'attribut ! Vous pouvez |
1451 | 635 | of attribute it has to be!. You can pass a documentation string as a | 650 | juste fournir une chaîne de documentation comme premier argument à |
1452 | 636 | first argument to ``Attribute``. | 651 | ``Attribute``. |
1453 | 637 | 652 | ||
1454 | 638 | The other attribute, ``goodmorning`` is a method defined using a | 653 | L'autre attribut, ``goodmorning`` est une méthode définie en utilisant une |
1455 | 639 | function definition. Note that `self` is not required in interfaces, | 654 | fonction. Notez bien que ``self`` n'est pas nécessaire dans les interfaces, car |
1456 | 640 | because `self` is an implementation detail of class. For example, a | 655 | ``self`` est un détail d'implémentation de la classe. Il est possible pour un |
1457 | 641 | module can implement this interface. If a module implement this | 656 | module d'implémenter cette interface. Si un module implémente cette interface, |
1458 | 642 | interface, there will be a ``name`` attribute and ``goodmorning`` | 657 | cela signifiera qu'un attribut ``name`` et une fonction ``goodmorning`` seront |
1459 | 643 | function defined. And the ``goodmorning`` function will accept one | 658 | définis. Et la fonction ``goodmorning`` devra accepter un argument. |
1460 | 644 | argument. | 659 | |
1461 | 645 | 660 | Nous allons maintenant voir comment effectuer le lien entre les objets, les | |
1462 | 646 | Now you will see how to connect `interface-class-object`. So object | 661 | classes et les interfaces. Seuls les objets sont vivants : ce sont des instances |
1463 | 647 | is the real living thing, objects are instances of classes. And | 662 | de classes. Et les interfaces représentent la définition des objets, donc les |
1464 | 648 | interface is the actual definition of the object, so classes are just | 663 | classes ne sont qu'un détail d'implémentation. C'est pour cette raison que vous |
1465 | 649 | the implementation details. This is why you should program to an | 664 | devez programmer pour une interface, pas pour une implémentation. |
1466 | 650 | interface and not to an implementation. | 665 | |
1467 | 651 | 666 | Nous devons nous familiariser avec deux termes supplémentaires pour comprendre | |
1468 | 652 | Now you should familiarize two more terms to understand other | 667 | les autres concepts. Le premier est `fournir`, le deuxième est `implémenter`. |
1469 | 653 | concepts. First one is `provide` and the other one is `implement`. | 668 | Les objets fournissent des interfaces, tandis que les classes implémentent des |
1470 | 654 | Object provides interfaces and classes implement interfaces. In other | 669 | interfaces. Autrement dit, les objets fournissent les interfaces que les classes |
1471 | 655 | words, objects provide interfaces that their classes implement. In | 670 | implémentent. Dans l'exemple ci-dessus, l'objet ``host`` fournit l'interface |
1472 | 656 | the above example ``host`` (object) provides ``IHost`` (interface) and | 671 | ``IHost`` et la classe ``Host`` implémente l'interface ``IHost``. Un objet peut |
1473 | 657 | ``Host`` (class) implement ``IHost`` (interface). One object can | 672 | fournir plusieurs interfaces. Les objets peuvent également fournir directement |
1474 | 658 | provide more than one interface also one class can implement more than | 673 | des interfaces, en plus de celles implémentées par leur classe. |
1441 | 659 | one interface. Objects can also provide interfaces directly, in | ||
1442 | 660 | addition to what their classes implement. | ||
1475 | 661 | 674 | ||
1476 | 662 | .. note:: | 675 | .. note:: |
1477 | 663 | 676 | ||
1495 | 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 |
1496 | 665 | classes are callable objects, so why other callable objects can't | 678 | classes sont des objets appelables (`callable`). Pourquoi un autre objet |
1497 | 666 | implement an interface. Yes, it is possible. For any `callable | 679 | appelable ne pourrait-il pas implémenter une interface ? En fait c'est possible. |
1498 | 667 | object` you can declare that it produces objects that provide some | 680 | Pour n'importe quel objet appelable, vous pouvez déclarer qu'il produit des |
1499 | 668 | interfaces by saying that the `callable object` implements the | 681 | objets qui fournissent une interface donnée, en disant simplement que cet objet |
1500 | 669 | interfaces. The `callable objects` are generally called as | 682 | appelable implémente l'interface. Ces objets appelables sont généralement |
1501 | 670 | `factories`. Since functions are callable objects, a function can | 683 | nommés des « fabriques ». Étant donné que les fonctions sont des objets |
1502 | 671 | be an `implementer` of an interface. | 684 | appelables, une fonction peut implémenter une interface. |
1503 | 672 | 685 | ||
1504 | 673 | 686 | ||
1505 | 674 | Implementing interfaces | 687 | Implémentation des interfaces |
1506 | 675 | ~~~~~~~~~~~~~~~~~~~~~~~ | 688 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1507 | 676 | 689 | ||
1508 | 677 | To declare a class implements a particular interface, use the function | 690 | Pour déclarer qu'une classe implémente une interface donnée, utilisez la |
1509 | 678 | ``zope.interface.implements`` in the class statement. | 691 | fonction ``zope.interface.implements`` dans la déclaration de classe. |
1510 | 679 | 692 | ||
1511 | 680 | Consider this example, here ``Host`` implements ``IHost``:: | 693 | Considérons cet exemple. Ici, ``Host`` implémente ``IHost`` :: |
1512 | 681 | 694 | ||
1513 | 682 | >>> from zope.interface import implements | 695 | >>> from zope.interface import implements |
1514 | 683 | 696 | ||
1515 | @@ -694,55 +707,54 @@ | |||
1516 | 694 | 707 | ||
1517 | 695 | .. note:: | 708 | .. note:: |
1518 | 696 | 709 | ||
1521 | 697 | If you wonder how ``implements`` function works, refer the blog post | 710 | Si vous vous demandez comment ``implements`` fonctionne, faites un tour sur |
1522 | 698 | by James Henstridge | 711 | l'article de blog de James Henstridge |
1523 | 699 | (http://blogs.gnome.org/jamesh/2005/09/08/python-class-advisors/) . | 712 | (http://blogs.gnome.org/jamesh/2005/09/08/python-class-advisors/) . |
1526 | 700 | In the adapter section, you will see an ``adapts`` function, it is | 713 | Dans la section sur les adaptateurs, vous allez voir une fonction ``adapts``, |
1527 | 701 | also working similarly. | 714 | celle-ci fonctionne de manière similaire. |
1528 | 702 | 715 | ||
1534 | 703 | Since ``Host`` implements ``IHost``, instances of ``Host`` provides | 716 | Comme ``Host`` implémente ``IHost``, les instances de ``Host`` fournissent |
1535 | 704 | ``IHost``. There are some utility methods to introspect the | 717 | ``IHost``. Il existe des méthodes permettant d'introspecter les déclarations. La |
1536 | 705 | declarations. The declaration can write outside the class also. If | 718 | déclaration peut également s'écrire en dehors de la classe. Au lieu d'écrire |
1537 | 706 | you don't write ``interface.implements(IHost)`` in the above example, | 719 | ``interface.implements(IHost)`` comme dans l'exemple ci-dessus, vous pouvez |
1538 | 707 | then after defining the class statement, you can write like this:: | 720 | écrire la chose suivante après la déclaration de classe :: |
1539 | 708 | 721 | ||
1540 | 709 | >>> from zope.interface import classImplements | 722 | >>> from zope.interface import classImplements |
1541 | 710 | >>> classImplements(Host, IHost) | 723 | >>> classImplements(Host, IHost) |
1542 | 711 | 724 | ||
1543 | 712 | 725 | ||
1546 | 713 | Example revisited | 726 | L'exemple revisité |
1547 | 714 | ~~~~~~~~~~~~~~~~~ | 727 | ~~~~~~~~~~~~~~~~~~ |
1548 | 715 | 728 | ||
1551 | 716 | Now, return to the example application. Here you will see how to | 729 | Maintenant retournons à notre application exemple. Voici comment définir |
1552 | 717 | define the interface of the registrar object:: | 730 | l'interface de l'objet frontdesk :: |
1553 | 718 | 731 | ||
1554 | 719 | >>> from zope.interface import Interface | 732 | >>> from zope.interface import Interface |
1555 | 720 | 733 | ||
1558 | 721 | >>> class IRegistrar(Interface): | 734 | >>> class IDesk(Interface): |
1559 | 722 | ... """A registrar will register object's details""" | 735 | ... """A frontdesk will register object's details""" |
1560 | 723 | ... | 736 | ... |
1561 | 724 | ... def register(): | 737 | ... def register(): |
1562 | 725 | ... """Register object's details""" | 738 | ... """Register object's details""" |
1563 | 726 | ... | 739 | ... |
1564 | 727 | 740 | ||
1583 | 728 | Here, first you imported ``Interface`` class from ``zope.interface`` | 741 | Nous avons d'abord importé la classe ``Interface`` depuis le module |
1584 | 729 | module. If you define a subclass of this ``Interface`` class, it will | 742 | ``zope.interface``. Si vous définissez une sous-classe de cette classe |
1585 | 730 | be an interface from Zope component architecture point of view. An | 743 | ``Interface``, ce sera considéré comme une interface, du point de vue de |
1586 | 731 | interface can be implemented, as you already noted, in a class or any | 744 | l'Architecture de Composants. Une interface peut être implémentée, comme nous |
1587 | 732 | other callable object. | 745 | l'avons vu, dans une classe ou tout autre objet appelable. |
1588 | 733 | 746 | ||
1589 | 734 | The registrar interface defined here is ``IRegistrar``. The | 747 | L'interface de frontdesk ici définie est ``IDesk``. La chaîne de documentation |
1590 | 735 | documentation string for interface gives an idea about the object. By | 748 | de l'interface donne une idée sur la nature de l'objet. En définissant une |
1591 | 736 | defining a method in the interface, you made a contract for the | 749 | méthode dans l'interface, vous avez passé un contrat avec le composant, imposant |
1592 | 737 | component, that there will be a method with same name available. For | 750 | la présence d'une méthode du même nom. Dans la déclaration de la méthode côté |
1593 | 738 | the method definition interface, the first argument should not be | 751 | interface, le premier argument ne doit pas être `self`, car une interface ne |
1594 | 739 | `self`, because an interface will never be instantiated nor will its | 752 | sera jamais instanciée et ses méthodes ne seront jamais appelées. Le rôle d'une |
1595 | 740 | methods ever be called. Instead, the interface class merely documents | 753 | interface est simplement de documenter quels arguments et quelles méthodes |
1596 | 741 | what methods and attributes should appear in any normal class that | 754 | doivent apparaître dans une classe qui l'implémente, et le paramètre `self` |
1597 | 742 | claims to implement it, and the `self` parameter is an implementation | 755 | n'est qu'un détail d'implémentation qui n'a pas besoin d'être documenté. |
1598 | 743 | detail which doesn't need to be documented. | 756 | |
1599 | 744 | 757 | Comme vous le savez, une interface peut aussi spécifier des attributs normaux :: | |
1582 | 745 | As you know, an interface can also specify normal attributes:: | ||
1600 | 746 | 758 | ||
1601 | 747 | >>> from zope.interface import Interface | 759 | >>> from zope.interface import Interface |
1602 | 748 | >>> from zope.interface import Attribute | 760 | >>> from zope.interface import Attribute |
1603 | @@ -752,26 +764,25 @@ | |||
1604 | 752 | ... name = Attribute("Name of guest") | 764 | ... name = Attribute("Name of guest") |
1605 | 753 | ... place = Attribute("Place of guest") | 765 | ... place = Attribute("Place of guest") |
1606 | 754 | 766 | ||
1627 | 755 | In this interface, guest object has two attributes specified with | 767 | Dans cette interface, l'objet guest a deux attributs contenant de la |
1628 | 756 | documentation. An interface can also specify both attributes and | 768 | documentation. Une interface peut spécifier à la fois des méthodes et des |
1629 | 757 | methods together. An interface can be implemented in a class, module | 769 | attributs. Une interface peut être implémentée dans une classe, un module ou |
1630 | 758 | or any other objects. For example a function can dynamically create | 770 | tout autre objet. Par exemple une fonction peut créer dynamiquement le composant |
1631 | 759 | the component and return, in this case the function is an implementer | 771 | et le renvoyer, auquel cas on dit que la fonction implémente l'interface. |
1632 | 760 | for the interface. | 772 | |
1633 | 761 | 773 | Vous savez maintenant ce qu'est une interface, comment la créer et l'utiliser. | |
1634 | 762 | Now you know what is an interface and how to define and use it. In | 774 | Dans le chapitre suivant nous allons voir comment une interface peut être |
1635 | 763 | the next chapter you can see how an interface is used to define an | 775 | utilisée pour définir un composant adaptateur. |
1636 | 764 | adapter component. | 776 | |
1637 | 765 | 777 | ||
1638 | 766 | 778 | Interfaces marqueurs | |
1639 | 767 | Marker interfaces | 779 | ~~~~~~~~~~~~~~~~~~~~ |
1640 | 768 | ~~~~~~~~~~~~~~~~~ | 780 | |
1641 | 769 | 781 | Une interface peut être utilisée pour déclarer qu'un objet appartient à un | |
1642 | 770 | An interface can be used to declare that a particular object belongs | 782 | type donné. Une interface sans aucun attribut ni aucune méthode est appelée une |
1643 | 771 | to a special type. An interface without any attribute or method is | 783 | « interface marqueur ». |
1644 | 772 | called `marker interface`. | 784 | |
1645 | 773 | 785 | Voici une `interface marqueur` :: | |
1626 | 774 | Here is a `marker interface`:: | ||
1646 | 775 | 786 | ||
1647 | 776 | >>> from zope.interface import Interface | 787 | >>> from zope.interface import Interface |
1648 | 777 | 788 | ||
1649 | @@ -779,24 +790,25 @@ | |||
1650 | 779 | ... """A special guest""" | 790 | ... """A special guest""" |
1651 | 780 | 791 | ||
1652 | 781 | 792 | ||
1654 | 782 | This interface can be used to declare an object is a special guest. | 793 | Cette interface peut être utilisée pour déclarer qu'un objet est un client |
1655 | 794 | spécial. | ||
1656 | 783 | 795 | ||
1657 | 784 | 796 | ||
1658 | 785 | Invariants | 797 | Invariants |
1659 | 786 | ~~~~~~~~~~ | 798 | ~~~~~~~~~~ |
1660 | 787 | 799 | ||
1673 | 788 | Sometimes you will be required to use some rule for your component | 800 | Parfois vous aurez besoin de définir des règles ou des contraintes sur les |
1674 | 789 | which involve one or more normal attributes. These kind of rule is | 801 | attributs de vos composants. Ces types de règles sont appelés des `invariants`. |
1675 | 790 | called `invariants`. You can use ``zope.interface.invariant`` for | 802 | Vous pouvez utiliser ``zope.interface.invariant`` pour définir des |
1676 | 791 | setting `invariants` for your objects in their interface. | 803 | ``invariants`` sur vos objets dans leur interface. |
1677 | 792 | 804 | ||
1678 | 793 | Consider a simple example, there is a `person` object. A person | 805 | Considérons un exemple simple, avec un objet `person`. Une objet `person` a un |
1679 | 794 | object has `name`, `email` and `phone` attributes. How do you | 806 | attribut `nom`, un attribut `email` et un attribut `phone`. Comment peut-on |
1680 | 795 | implement a validation rule that says either email or phone have to | 807 | implémenter une règle de validation qui oblige à définir au choix le `phone` ou |
1681 | 796 | exist, but not necessarily both. | 808 | l'`email` mais pas forcément les deux ? |
1682 | 797 | 809 | ||
1683 | 798 | First you have to make a callable object, either a simple function or | 810 | Créez tout d'abord un objet appelable, soit une simple fonction soit une |
1684 | 799 | callable instance of a class like this:: | 811 | instance appelable d'une classe de la façon suivante :: |
1685 | 800 | 812 | ||
1686 | 801 | >>> def contacts_invariant(obj): | 813 | >>> def contacts_invariant(obj): |
1687 | 802 | ... | 814 | ... |
1688 | @@ -804,8 +816,8 @@ | |||
1689 | 804 | ... raise Exception( | 816 | ... raise Exception( |
1690 | 805 | ... "At least one contact info is required") | 817 | ... "At least one contact info is required") |
1691 | 806 | 818 | ||
1694 | 807 | Then define the `person` object's interface like this. Use the | 819 | Ensuite définissez l'interface de l'objet `person` en utilisant la fonction |
1695 | 808 | ``zope.interface.invariant`` function to set the invariant:: | 820 | ``zope.interface.invariant`` pour définir l'invariant :: |
1696 | 809 | 821 | ||
1697 | 810 | >>> from zope.interface import Interface | 822 | >>> from zope.interface import Interface |
1698 | 811 | >>> from zope.interface import Attribute | 823 | >>> from zope.interface import Attribute |
1699 | @@ -819,7 +831,8 @@ | |||
1700 | 819 | ... | 831 | ... |
1701 | 820 | ... invariant(contacts_invariant) | 832 | ... invariant(contacts_invariant) |
1702 | 821 | 833 | ||
1704 | 822 | Now use `validateInvariants` method of the interface to validate:: | 834 | Maintenant, utilisez la méthode `validateInvariants` de l'interface pour |
1705 | 835 | effectuer la validation :: | ||
1706 | 823 | 836 | ||
1707 | 824 | >>> from zope.interface import implements | 837 | >>> from zope.interface import implements |
1708 | 825 | 838 | ||
1709 | @@ -839,37 +852,34 @@ | |||
1710 | 839 | ... | 852 | ... |
1711 | 840 | Exception: At least one contact info is required | 853 | Exception: At least one contact info is required |
1712 | 841 | 854 | ||
1726 | 842 | As you can see `jack` object validated without raising any | 855 | Vous constatez que l'ojet `jack` est validé sans erreur. Mais l'objet `jill` n'a |
1727 | 843 | exception. But `jill` object didn't validated the invariant | 856 | pas pu valider la contrainte de l'invariant, il a donc levé une exception. |
1728 | 844 | constraint, so it raised exception. | 857 | |
1729 | 845 | 858 | ||
1730 | 846 | .. [#patternbook] http://en.wikipedia.org/wiki/Design_Patterns | 859 | Adaptateurs |
1731 | 847 | .. [#api] http://en.wikipedia.org/wiki/Application_programming_interface | 860 | ----------- |
1732 | 848 | 861 | ||
1733 | 849 | 862 | ||
1734 | 850 | Adapters | 863 | Implémentation |
1722 | 851 | -------- | ||
1723 | 852 | |||
1724 | 853 | |||
1725 | 854 | Implementation | ||
1735 | 855 | ~~~~~~~~~~~~~~ | 864 | ~~~~~~~~~~~~~~ |
1736 | 856 | 865 | ||
1742 | 857 | This section will describe adapters in detail. Zope component | 866 | Cette section décrit les adaptateurs en détail. L'Architecture de Composants, |
1743 | 858 | architecture, as you noted, helps to effectively use Python objects. | 867 | comme vous l'avez remarqué, fournit une aide dans l'utilisation efficace des objets |
1744 | 859 | Adapter components are one of the basic components used by Zope | 868 | Python. Les composants adaptateurs sont l'un des composants basiques utilisés |
1745 | 860 | component architecture for effectively using Python objects. Adapter | 869 | par l'Architecture de Composants de Zope pour utiliser efficacement des objets |
1746 | 861 | components are Python objects, but with well defined interface. | 870 | Python. Les adaptateurs sont aussi des objets Python, mais avec une interface bien |
1747 | 871 | définie. | ||
1748 | 862 | 872 | ||
1752 | 863 | To declare a class is an adapter use `adapts` function defined in | 873 | Pour déclarer qu'une classe est un adaptateur, utilisez la fonction `adapts` |
1753 | 864 | ``zope.component`` package. Here is a new `GuestRegistrarNG` adapter | 874 | définie dans le paquet ``zope.component``. Voici un nouvel adaptateur |
1754 | 865 | with explicit interface declaration:: | 875 | `FrontDeskNG` avec une déclaration explicite d'interface :: |
1755 | 866 | 876 | ||
1756 | 867 | >>> from zope.interface import implements | 877 | >>> from zope.interface import implements |
1757 | 868 | >>> from zope.component import adapts | 878 | >>> from zope.component import adapts |
1758 | 869 | 879 | ||
1760 | 870 | >>> class GuestRegistrarNG(object): | 880 | >>> class FrontDeskNG(object): |
1761 | 871 | ... | 881 | ... |
1763 | 872 | ... implements(IRegistrar) | 882 | ... implements(IDesk) |
1764 | 873 | ... adapts(IGuest) | 883 | ... adapts(IGuest) |
1765 | 874 | ... | 884 | ... |
1766 | 875 | ... def __init__(self, guest): | 885 | ... def __init__(self, guest): |
1767 | @@ -878,17 +888,16 @@ | |||
1768 | 878 | ... def register(self): | 888 | ... def register(self): |
1769 | 879 | ... guest = self.guest | 889 | ... guest = self.guest |
1770 | 880 | ... next_id = get_next_id() | 890 | ... next_id = get_next_id() |
1772 | 881 | ... guests_db[next_id] = { | 891 | ... bookings_db[next_id] = { |
1773 | 882 | ... 'name': guest.name, | 892 | ... 'name': guest.name, |
1774 | 883 | ... 'place': guest.place, | 893 | ... 'place': guest.place, |
1775 | 884 | ... 'phone': guest.phone | 894 | ... 'phone': guest.phone |
1776 | 885 | ... } | 895 | ... } |
1777 | 886 | 896 | ||
1778 | 887 | 897 | ||
1783 | 888 | What you defined here is an `adapter` for `IRegistrar`, which adapts | 898 | Ce que nous avons défini ici est un `adaptateur` pour `IDesk`, qui s'adapte à |
1784 | 889 | `IGuest` object. The `IRegistrar` interface is implemented by | 899 | l'objet `IGuest`. L'interface `IDesk` est implémentée par la classe |
1785 | 890 | `GuestRegistrarNG` class. So, an instance of this class will provide | 900 | `FrontDeskNG`. Donc une instance de cette classe fournira l'interface `IDesk`. |
1782 | 891 | `IRegistrar` interface. | ||
1786 | 892 | 901 | ||
1787 | 893 | :: | 902 | :: |
1788 | 894 | 903 | ||
1789 | @@ -901,252 +910,254 @@ | |||
1790 | 901 | ... self.place = place | 910 | ... self.place = place |
1791 | 902 | 911 | ||
1792 | 903 | >>> jack = Guest("Jack", "Bangalore") | 912 | >>> jack = Guest("Jack", "Bangalore") |
1794 | 904 | >>> jack_registrar = GuestRegistrarNG(jack) | 913 | >>> jack_frontdesk = FrontDeskNG(jack) |
1795 | 905 | 914 | ||
1797 | 906 | >>> IRegistrar.providedBy(jack_registrar) | 915 | >>> IDesk.providedBy(jack_frontdesk) |
1798 | 907 | True | 916 | True |
1799 | 908 | 917 | ||
1816 | 909 | The `GuestRegistrarNG` is just one adapter you created, you can also | 918 | `FrontDeskNG` est juste un adaptateur que nous avons créé. Vous pouvez créer |
1817 | 910 | create other adapters which handles guest registration differently. | 919 | d'autres adaptateurs qui prendront en charge le bureau d'enregistrement différemment. |
1818 | 911 | 920 | ||
1819 | 912 | 921 | ||
1820 | 913 | Registration | 922 | Inscription |
1821 | 914 | ~~~~~~~~~~~~ | 923 | ~~~~~~~~~~~ |
1822 | 915 | 924 | ||
1823 | 916 | To use this adapter component, you have to register this in a | 925 | Pour utiliser ce composant adaptateur, vous devez l'inscrire dans un registre de |
1824 | 917 | component registry also known as site manager. A site manager | 926 | composants (appelé également « gestionnaire de site »). Un gestionnaire de site |
1825 | 918 | normally resides in a site. A site and site manager will be more | 927 | réside normalement à l'intérieur d'un site. Le site et le gestionnaire de site |
1826 | 919 | important when developing a Zope 3 application. For now you only | 928 | prendront leur importance lors du développement d'une application Zope 3. Pour |
1827 | 920 | required to bother about global site and global site manager ( or | 929 | l'instant vous avez juste besoin de connaître les notions de site global et de |
1828 | 921 | component registry). A global site manager will be in memory, but a | 930 | gestionnaire global de site (ou registre de composant). Un gestionnaire global |
1829 | 922 | local site manager is persistent. | 931 | de site est situé en mémoire, alors qu'un gestionnaire de site local est |
1830 | 923 | 932 | persistant. | |
1831 | 924 | To register your component, first get the global site manager:: | 933 | |
1832 | 934 | Pour inscrire votre composant, commencez par récupérer le gestionnaire global de | ||
1833 | 935 | site :: | ||
1834 | 925 | 936 | ||
1835 | 926 | >>> from zope.component import getGlobalSiteManager | 937 | >>> from zope.component import getGlobalSiteManager |
1836 | 927 | >>> gsm = getGlobalSiteManager() | 938 | >>> gsm = getGlobalSiteManager() |
1873 | 928 | >>> gsm.registerAdapter(GuestRegistrarNG, | 939 | >>> gsm.registerAdapter(FrontDeskNG, |
1874 | 929 | ... (IGuest,), IRegistrar, 'ng') | 940 | ... (IGuest,), IDesk, 'ng') |
1875 | 930 | 941 | ||
1876 | 931 | To get the global site manager, you have to call | 942 | Pour récupérer le gestionnaire global de site, vous devez appeler la fonction |
1877 | 932 | ``getGlobalSiteManager`` function available in ``zope.component`` | 943 | ``getGlobalSiteManager` disponible dans le paquet ``zope.component``. |
1878 | 933 | package. In fact, the global site manager is available as an | 944 | En fait, le gestionnaire global de site est disponible dans un attribut |
1879 | 934 | attribute (``globalSiteManager``) of ``zope.component`` package. So, | 945 | (``globalSiteManager``) du paquet ``zope.component``. Vous pouvez donc utiliser |
1880 | 935 | you can directly use ``zope.component.globalSiteManager`` attribute. | 946 | directement l'attribut ``zope.component.globalSiteManager``. |
1881 | 936 | To register the adapter in component, as you can see above, use | 947 | Pour inscrire l'adaptateur comme un composant, utilisez la méthode |
1882 | 937 | ``registerAdapter`` method of component registry. The first argument | 948 | ``registerAdapter`` du registre de composants. Le premier argument doit être |
1883 | 938 | should be your adapter class/factory. The second argument is a tuple | 949 | votre classe ou fabrique d'adaptateur. Le deuxième argument est un tuple d'objets |
1884 | 939 | of `adaptee` objects, i.e, the object which you are adapting. In this | 950 | adaptés, c'est à dire les objets sur lesquels vous vous adaptez. Dans cet |
1885 | 940 | example, you are adapting only `IGuest` object. The third argument is | 951 | exemple, vous vous adaptez seulement à l'objet `IGuest`. Le troisième argument |
1886 | 941 | the interface provided by the adapter component. The fourth argument | 952 | est l'interface implémentée par le composant adaptateur. Le quatrième argument |
1887 | 942 | is optional, that is the name of the particular adapter. Since you | 953 | est optionnel, il s'agit du nom de cet adaptateur particulier. Si vous donnez un |
1888 | 943 | gave a name for this adapter, this is a `named adapter`. If name is | 954 | nom à l'adaptateur, celui devient un `adaptateur nommé`. Si aucun nom n'est |
1889 | 944 | not given, it will default to an empty string (''). | 955 | donné, la valeur transmise par défaut est une chaîne vide (''). |
1890 | 945 | 956 | ||
1891 | 946 | In the above registration, you have given the adaptee interface and | 957 | Dans l'inscription ci-dessus, vous avez donné l'interface de l'objet adapté et |
1892 | 947 | interface to be provided by the adapter. Since you have already given | 958 | l'interface fournie par l'adaptateur. Comme vous avez déjà donné ces |
1893 | 948 | these details in adapter implementation, it is not required to specify | 959 | informations dans l'implémentation de l'adaptateur, il est inutile de les |
1894 | 949 | again. In fact, you could have done the registration like this:: | 960 | spécifier à nouveau. En réalité, vous pouvez effectuer l'inscription de la |
1895 | 950 | 961 | manière suivante :: | |
1896 | 951 | >>> gsm.registerAdapter(GuestRegistrarNG, name='ng') | 962 | |
1897 | 952 | 963 | >>> gsm.registerAdapter(FrontDeskNG, name='ng') | |
1898 | 953 | There are some old API to do the registration, which you should avoid. | 964 | |
1899 | 954 | The old API functions starts with `provide`, eg: ``provideAdapter``, | 965 | Pour effectuer l'inscription, il existe d'anciennes API que vous devriez |
1900 | 955 | ``provideUtility`` etc. While developing a Zope 3 application you can | 966 | éviter. Les fonctions de l'ancienne API commencent par `provide`, par exemple : |
1901 | 956 | use Zope configuration markup language (ZCML) for registration of | 967 | ``provideAdapter``, ``provideUtility``, etc. Si vous développez une application |
1902 | 957 | components. In Zope 3, local components (persistent components) can | 968 | Zope 3, vous pouvez utiliser le langage ZCML (Zope Configuration Markup |
1903 | 958 | be registered from Zope Management Interface (ZMI) or you can do it | 969 | Language) pour effectuer les inscriptions des composants. Avec Zope 3, les |
1904 | 959 | programmatically also. | 970 | composants locaux (persistants) peut être inscrits depuis la ZMI (Zope |
1905 | 960 | 971 | Management Interface), ou bien par programmation. | |
1906 | 961 | You registered `GuestRegistrarNG` with a name `ng`. Similarly you can | 972 | |
1907 | 962 | register other adapters with different names. If a component is | 973 | Vous avez inscrit `FrontDeskNG` avec le nom `ng`. De la même manière, vous |
1908 | 963 | registered without name, it will default to an empty string. | 974 | pouvez inscrire d'autre adaptateurs avec différents noms. Si un composant est |
1909 | 975 | inscrit sans nom, son nom sera la chaîne vide par défaut. | ||
1910 | 964 | 976 | ||
1911 | 965 | .. note:: | 977 | .. note:: |
1912 | 966 | 978 | ||
1930 | 967 | Local components are persistent components but global components are | 979 | Les composants locaux sont persistants mais les composants globaux sont en |
1931 | 968 | in memory. Global components will be registered based on the | 980 | mémoire. Les composants globaux sont inscrits en fonction de la configuration de |
1932 | 969 | configuration of application. Local components are taken to memory | 981 | l'application. Les composants locaux sont récupérés dans la base de données au |
1933 | 970 | from database while starting the application. | 982 | démarrage de l'application. |
1934 | 971 | 983 | ||
1935 | 972 | 984 | ||
1936 | 973 | Querying adapter | 985 | récupération d'un adaptateur |
1937 | 974 | ~~~~~~~~~~~~~~~~ | 986 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1938 | 975 | 987 | ||
1939 | 976 | Retrieving registered components from component registry is achieved | 988 | La récupération des composants inscrits dans le registre est effectuée grâce à |
1940 | 977 | through two functions available in ``zope.component`` package. One of | 989 | deux fonctions disponibles dans le paquet ``zope.component``. La première est |
1941 | 978 | them is ``getAdapter`` and the other is ``queryAdapter`` . Both | 990 | ``getAdapter``, la deuxième ``queryAdapter``. Les deux fonctions prennent les |
1942 | 979 | functions accepts same arguments. The ``getAdapter`` will raise | 991 | mêmes arguments. ``getAdapter`` lève une exception ``ComponentLookupError`` si |
1943 | 980 | ``ComponentLookupError`` if component lookup fails on the other hand | 992 | la recherche de composant échoue, tandis que ``queryAdapter`` renvoie `None`. |
1944 | 981 | ``queryAdapter`` will return `None`. | 993 | |
1945 | 982 | 994 | Vous pouvez importer ces fonctions comme ceci :: | |
1929 | 983 | You can import the methods like this:: | ||
1946 | 984 | 995 | ||
1947 | 985 | >>> from zope.component import getAdapter | 996 | >>> from zope.component import getAdapter |
1948 | 986 | >>> from zope.component import queryAdapter | 997 | >>> from zope.component import queryAdapter |
1949 | 987 | 998 | ||
1974 | 988 | In the previous section you have registered a component for guest | 999 | Dans la section précédente, nous avons inscrit un composant qui fournit |
1975 | 989 | object (adaptee) which provides `IRegistrar` interface with name as | 1000 | l'interface `IDesk` avec un nom `ng`, et qui s'adapte à l'objet guest. |
1976 | 990 | 'ng'. In the first section of this chapter, you have created a guest | 1001 | Dans la première section nous avons créé un objet nommé `jack`. |
1977 | 991 | object named `jack` . | 1002 | |
1978 | 992 | 1003 | Voici maintenant comment récupérer un composant qui s'adapte à l'interface de l'objet | |
1979 | 993 | This is how you can retrieve a component which adapts the interface of | 1004 | `jack` (`IGuest`) et qui fournit l'interface `IDesk` également avec le nom `ng`. |
1980 | 994 | `jack` object (`IGuest`) and provides `IRegistrar` interface also with | 1005 | Ici, ``getAdapter`` et ``queryAdapter`` fonctionnent de la même manière :: |
1981 | 995 | name as 'ng'. Here both ``getAdapter`` and ``queryAdapter`` works | 1006 | |
1982 | 996 | similarly:: | 1007 | >>> getAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS |
1983 | 997 | 1008 | <FrontDeskNG object at ...> | |
1984 | 998 | >>> getAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS | 1009 | >>> queryAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS |
1985 | 999 | <GuestRegistrarNG object at ...> | 1010 | <FrontDeskNG object at ...> |
1986 | 1000 | >>> queryAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS | 1011 | |
1987 | 1001 | <GuestRegistrarNG object at ...> | 1012 | Vous pouvez constater que le premier argument doit être l'objet adapté, puis |
1988 | 1002 | 1013 | l'interface qui doit être fournie par le composant et finalement le nom du | |
1989 | 1003 | As you can see, the first argument should be adaptee then, the | 1014 | composant adaptateur. |
1990 | 1004 | interface which should be provided by component and last the name of | 1015 | |
1991 | 1005 | adapter component. | 1016 | Si vous essayez de récupérer le composant grâce à un nom inutilisé pour |
1992 | 1006 | 1017 | l'inscription mais pour le même objet adapté et la même interface, la recherche | |
1993 | 1007 | If you try to lookup the component with an name not used for | 1018 | échouera. Voici dans ce cas comment fonctionnent les deux méthodes :: |
1994 | 1008 | registration but for same adaptee and interface, the lookup will fail. | 1019 | |
1995 | 1009 | Here is how the two methods works in such a case:: | 1020 | >>> getAdapter(jack, IDesk, 'not-exists') #doctest: +ELLIPSIS |
1972 | 1010 | |||
1973 | 1011 | >>> getAdapter(jack, IRegistrar, 'not-exists') #doctest: +ELLIPSIS | ||
1996 | 1012 | Traceback (most recent call last): | 1021 | Traceback (most recent call last): |
1997 | 1013 | ... | 1022 | ... |
1998 | 1014 | ComponentLookupError: ... | 1023 | ComponentLookupError: ... |
1999 | 1015 | >>> reg = queryAdapter(jack, | 1024 | >>> reg = queryAdapter(jack, |
2001 | 1016 | ... IRegistrar, 'not-exists') #doctest: +ELLIPSIS | 1025 | ... IDesk, 'not-exists') #doctest: +ELLIPSIS |
2002 | 1017 | >>> reg is None | 1026 | >>> reg is None |
2003 | 1018 | True | 1027 | True |
2004 | 1019 | 1028 | ||
2015 | 1020 | As you can see above, ``getAdapter`` raised a ``ComponentLookupError`` | 1029 | ``getAdapter`` a levé une exception ``ComponentLookupError`` mais |
2016 | 1021 | exception, but ``queryAdapter`` returned `None` when lookup failed. | 1030 | ``queryAdapter`` a renvoyé `None`. |
2017 | 1022 | 1031 | ||
2018 | 1023 | The third argument, the name of registration, is optional. If the | 1032 | Le troisième argument, le nom d'inscription, est optionnel. Si le troisième |
2019 | 1024 | third argument is not given it will default to empty string (''). | 1033 | argument n'est pas fourni, sa valeur par défaut est la chaîne vide (''). Comme |
2020 | 1025 | Since there is no component registered with an empty string, | 1034 | il n'y a aucun composant inscrit avec la chaîne vide comme nom, ``getAdapter`` |
2021 | 1026 | ``getAdapter`` will raise ``ComponentLookupError`` . Similarly | 1035 | lève l'exception ``ComponentLookupError``. De la même manière, ``queryAdapter`` |
2022 | 1027 | ``queryAdapter`` will return `None`, see yourself how it works:: | 1036 | renvoie `None`. Voyez vous-même comment cela fonctionne :: |
2023 | 1028 | 1037 | ||
2024 | 1029 | >>> getAdapter(jack, IRegistrar) #doctest: +ELLIPSIS | 1038 | >>> getAdapter(jack, IDesk) #doctest: +ELLIPSIS |
2025 | 1030 | Traceback (most recent call last): | 1039 | Traceback (most recent call last): |
2026 | 1031 | ... | 1040 | ... |
2027 | 1032 | ComponentLookupError: ... | 1041 | ComponentLookupError: ... |
2029 | 1033 | >>> reg = queryAdapter(jack, IRegistrar) #doctest: +ELLIPSIS | 1042 | >>> reg = queryAdapter(jack, IDesk) #doctest: +ELLIPSIS |
2030 | 1034 | >>> reg is None | 1043 | >>> reg is None |
2031 | 1035 | True | 1044 | True |
2032 | 1036 | 1045 | ||
2059 | 1037 | In this section you have learned how to register a simple adapter and | 1046 | Dans cette section, vous avez appris à inscrire un simple adaptateur et à le |
2060 | 1038 | how to retrieve it from component registry. These kind of adapters is | 1047 | récupérer depuis le registre de composants. Ce type d'adaptateurs est appelé un |
2061 | 1039 | called single adapter, because it adapts only one adaptee. If an | 1048 | adaptateur simple, car il ne s'adapte qu'à un seul objet. Si un adaptateur |
2062 | 1040 | adapter adapts more that one adaptee, then it is called multi | 1049 | s'adapte à plusieurs objets, on l'appelle un multi-adaptateur. |
2063 | 1041 | adapter. | 1050 | |
2064 | 1042 | 1051 | ||
2065 | 1043 | 1052 | Récupérer un adaptateur en utilisant l'interface | |
2066 | 1044 | Retrieving adapter using interface | 1053 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
2067 | 1045 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1054 | |
2068 | 1046 | 1055 | Les adaptateurs peuvent être récupérés directement en utilisant les interfaces, | |
2069 | 1047 | Adapters can be directly retrieved using interfaces, but it will only | 1056 | mais cela ne fonctionne qu'avec les adaptateurs simples. Le premier argument est |
2070 | 1048 | work for non-named single adapters. The first argument is the adaptee | 1057 | l'objet adapté, le deuxième argument est un argument mot-clé. Si la recheche |
2071 | 1049 | and the second argument is a keyword argument. If adapter lookup | 1058 | d'adaptateur échoue, le deuxième argument est renvoyé. |
2072 | 1050 | fails, second argument will be returned. | 1059 | |
2073 | 1051 | 1060 | >>> IDesk(jack, alternate='default-output') | |
2074 | 1052 | >>> IRegistrar(jack, alternate='default-output') | 1061 | 'default-output' |
2075 | 1053 | 'default-output' | 1062 | |
2076 | 1054 | 1063 | Le mot-clé peut être omis : | |
2077 | 1055 | Keyword name can be omitted: | 1064 | |
2078 | 1056 | 1065 | >>> IDesk(jack, 'default-output') | |
2079 | 1057 | >>> IRegistrar(jack, 'default-output') | 1066 | 'default-output' |
2080 | 1058 | 'default-output' | 1067 | |
2081 | 1059 | 1068 | Si le deuxième argument n'est pas fourni, une erreur `TypeError` est levée : | |
2082 | 1060 | If second argument is not given, it will raise `TypeError`: | 1069 | |
2083 | 1061 | 1070 | >>> IDesk(jack) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS | |
2058 | 1062 | >>> IRegistrar(jack) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS | ||
2084 | 1063 | Traceback (most recent call last): | 1071 | Traceback (most recent call last): |
2085 | 1064 | ... | 1072 | ... |
2086 | 1065 | TypeError: ('Could not adapt', | 1073 | TypeError: ('Could not adapt', |
2087 | 1066 | <Guest object at ...>, | 1074 | <Guest object at ...>, |
2137 | 1067 | <InterfaceClass __builtin__.IRegistrar>) | 1075 | <InterfaceClass __builtin__.IDesk>) |
2138 | 1068 | 1076 | ||
2139 | 1069 | Here `GuestRegistrarNG` is registered without name: | 1077 | Ici, `FrontDeskNG` est inscrit sans nom : |
2140 | 1070 | 1078 | ||
2141 | 1071 | >>> gsm.registerAdapter(GuestRegistrarNG) | 1079 | >>> gsm.registerAdapter(FrontDeskNG) |
2142 | 1072 | 1080 | ||
2143 | 1073 | Now the adapter lookup should succeed: | 1081 | Maintenant la récupération de l'adaptateur doit réussir : |
2144 | 1074 | 1082 | ||
2145 | 1075 | >>> IRegistrar(jack, 'default-output') #doctest: +ELLIPSIS | 1083 | >>> IDesk(jack, 'default-output') #doctest: +ELLIPSIS |
2146 | 1076 | <GuestRegistrarNG object at ...> | 1084 | <FrontDeskNG object at ...> |
2147 | 1077 | 1085 | ||
2148 | 1078 | For simple cases, you may use interface to get adapter components. | 1086 | Pour les cas simples, vous pouvez utiliser l'interface pour récupérer des |
2149 | 1079 | 1087 | adaptateurs. | |
2150 | 1080 | 1088 | ||
2151 | 1081 | Adapter pattern | 1089 | |
2152 | 1082 | ~~~~~~~~~~~~~~~ | 1090 | Motif adaptateur |
2153 | 1083 | 1091 | ~~~~~~~~~~~~~~~~ | |
2154 | 1084 | The adapter concept in Zope Component Architecture and the classic | 1092 | |
2155 | 1085 | `adapter pattern` as described in Design Patterns book are very | 1093 | Le principe de l'adaptateur dans l'Architecture de Composants de Zope est très |
2156 | 1086 | similar. But the intent of ZCA adapter usage is more wider than the | 1094 | similaire au `motif adaptateur` classique, tel que décrit dans le livre « Design |
2157 | 1087 | `adapter pattern` itself. The intent of `adapter pattern` is to | 1095 | Patterns ». Mais l'objectif visé par l'utilisation des adaptateurs dans la ZCA |
2158 | 1088 | convert the interface of a class into another interface clients | 1096 | est plus large que le principe de l'adaptateur lui-même. Le but de l'adaptateur |
2159 | 1089 | expect. This allows classes work together that couldn't otherwise | 1097 | est de convertir l'interface d'une classe en une autre interface attendue par le |
2160 | 1090 | because of incompatible interfaces. But in the `motivation` section | 1098 | client. Ceci permet de faire fonctionner des classes ensemble même si elles ont |
2161 | 1091 | of Degisgn Patterns book, GoF says: "Often the adapter is responsible | 1099 | des interfaces incompatibles entre elles. Mais dans la section `motivations` du |
2162 | 1092 | for functionality the adapted class doesn't provide". ZCA adapter has | 1100 | livre « Design Patterns », le GoF dit : « souvent, l'adaptateur est responsable |
2163 | 1093 | more focus on adding functionalities than creating a new interface for | 1101 | d'une fonctionnalité que la classe adaptée ne fournit pas ». Un adaptateur de la |
2164 | 1094 | an adapted object (adaptee). ZCA adapter lets adapter classes extend | 1102 | ZCA se concentre effectivement plus sur l'ajout de fonctionnalités que sur la |
2165 | 1095 | functionality by adding methods. (It would be interesting to note | 1103 | création d'une nouvelle interface pour un objet adapté. L'adaptateur de la ZCA |
2166 | 1096 | that `Adapter` was known as `Feature` in earlier stage of ZCA | 1104 | permet aux classes adaptateurs d'étendre des fonctionnalités par ajout de |
2167 | 1097 | design. ) [#feature]_ | 1105 | méthodes. (Il peut être intéressant de remarquer que l'adaptateur était appelé |
2168 | 1098 | 1106 | `Fonctionnalité` (`feature`) dans les premières étapes de conception de la ZCA.) [#feature]_ | |
2120 | 1099 | The above paragraph has a quote from Gang of Four book, it ends like | ||
2121 | 1100 | this: " ...adapted class doesn't provide". But in the next sentence I | ||
2122 | 1101 | used "adapted object" instead of "adapted class", because GoF | ||
2123 | 1102 | describes about two variants of adapters based on implementations. | ||
2124 | 1103 | The first one is called `class adapter` and the other one is called | ||
2125 | 1104 | `object adapter`. A class adapter uses multiple inheritance to adapt | ||
2126 | 1105 | one interface to another, on the other hand an object adapter relies | ||
2127 | 1106 | on object composition. ZCA adapter is following object adapter | ||
2128 | 1107 | pattern, which use delegation as a mechanism for composition. GoF's | ||
2129 | 1108 | second principle of object-oriented design goes like this: "Favor | ||
2130 | 1109 | object composition over class inheritance". For more details about | ||
2131 | 1110 | this subject please read Design Patterns book. | ||
2132 | 1111 | |||
2133 | 1112 | The major attraction of ZCA adapter are the explicit interface for | ||
2134 | 1113 | components and the component registry. ZCA adapter components are | ||
2135 | 1114 | registered in component registry and looked up by client objects using | ||
2136 | 1115 | interface and name when required. | ||
2169 | 1116 | 1107 | ||
2170 | 1117 | .. [#feature] Thread discussing renaming of `Feature` to `Adapter`: | 1108 | .. [#feature] Thread discussing renaming of `Feature` to `Adapter`: |
2171 | 1118 | http://mail.zope.org/pipermail/zope3-dev/2001-December/000008.html | 1109 | http://mail.zope.org/pipermail/zope3-dev/2001-December/000008.html |
2172 | 1119 | 1110 | ||
2176 | 1120 | 1111 | La citation du Gang of Four dans le paragraphe ci-dessus se termine de la façon | |
2177 | 1121 | Utility | 1112 | suivante : « ... que la classe adaptée ne fournit pas ». Mais dans la phrase |
2178 | 1122 | ------- | 1113 | suivante nous avons utilisé « objet adapté » plutôt que « classe adaptée », car |
2179 | 1114 | le GoF décrit deux variantes d'adaptateurs selon les implémentations. | ||
2180 | 1115 | Le premier est appelé `adaptateur de classe`, le deuxième `adaptateur d'objet`. | ||
2181 | 1116 | Un adaptateur de classe utilise l'héritage multiple pour adapter une interface à | ||
2182 | 1117 | une autre, alors que l'adaptateur d'objet se base sur la composition d'objet. | ||
2183 | 1118 | L'adaptateur de la ZCA utilise le principe de l'adaptateur d'objet, qui utilise | ||
2184 | 1119 | la délégation comme mécanisme de composition. Le second principe du GoF à propos | ||
2185 | 1120 | de la conception orientée objets est la suivante : « favorisez la composition | ||
2186 | 1121 | d'objets plutôt que l'héritage de classes ». Pour approfondir le sujet, | ||
2187 | 1122 | reportez-vous au livre « Design Patterns ». | ||
2188 | 1123 | |||
2189 | 1124 | Les principaux atouts des adaptateurs de la ZCA sont les interfaces explicites | ||
2190 | 1125 | et les registres de composants. Les composants adaptateurs de la ZCA sont inscrits | ||
2191 | 1126 | dans le registre de composants et sont récupérés par les objets clients via leur | ||
2192 | 1127 | interface et leur nom si besoin. | ||
2193 | 1128 | |||
2194 | 1129 | |||
2195 | 1130 | Utilitaires | ||
2196 | 1131 | ----------- | ||
2197 | 1123 | 1132 | ||
2198 | 1124 | 1133 | ||
2199 | 1125 | Introduction | 1134 | Introduction |
2200 | 1126 | ~~~~~~~~~~~~ | 1135 | ~~~~~~~~~~~~ |
2201 | 1127 | 1136 | ||
2224 | 1128 | Now you know the concept of interface, adapter and component registry. | 1137 | Vous connaissez maintenant le principe des interfaces, des adaptateurs et du |
2225 | 1129 | Sometimes it would be useful to register an object which is not | 1138 | registre de composants. Parfois, il peut être utile d'inscrire un objet qui ne |
2226 | 1130 | adapting anything. Database connection, XML parser, object returning | 1139 | s'adapte à rien du tout, par exemple une connexion à une base de données, un analyseur XML |
2227 | 1131 | unique Ids etc. are examples of these kinds of objects. These kind of | 1140 | ou un objet retournant des identifiants uniques. Ce type de composant |
2228 | 1132 | components provided by Zope component architecture are called | 1141 | fourni par la ZCA est appelé un « utilitaire » (*utility*). |
2229 | 1133 | ``utility`` components. | 1142 | |
2230 | 1134 | 1143 | Les utilitaires sont simplement des objets qui fournissent une interface et qui sont | |
2231 | 1135 | Utilities are just objects that provide an interface and that are | 1144 | récupérés à partir de cette interface et d'un nom. Cette approche permet de créer |
2232 | 1136 | looked up by an interface and a name. This approach creates a global | 1145 | un registre global dans lequel des instances peuvent être inscrites et |
2233 | 1137 | registry by which instances can be registered and accessed by | 1146 | récupérées à différents endroits de votre application, sans avoir besoin de |
2234 | 1138 | different parts of your application, with no need to pass the | 1147 | transmettre les instances comme paramètres. |
2235 | 1139 | instances around as parameters. | 1148 | |
2236 | 1140 | 1149 | Vous n'avez pas besoin d'inscrire toutes les instances de composants de cette | |
2237 | 1141 | You need not to register all component instances like this. Only | 1150 | façon. Inscrivez seulement les composants que vous voulez rendre |
2238 | 1142 | register components which you want to make replaceable. | 1151 | interchangeables. |
2239 | 1143 | 1152 | ||
2240 | 1144 | 1153 | ||
2241 | 1145 | Simple utility | 1154 | Utilitaire simple |
2242 | 1146 | ~~~~~~~~~~~~~~ | 1155 | ~~~~~~~~~~~~~~~~~ |
2243 | 1147 | 1156 | ||
2244 | 1148 | Before implementing the utility, as usual, define its interface. Here | 1157 | Un utilitaire peut être inscrit avec ou sans nom. Un utilitaire inscrit avec un nom |
2245 | 1149 | is a `greeter` interface:: | 1158 | est appelé un `utilitaire nommé`. Vous le verrez dans la prochaine section. |
2246 | 1159 | Avant d'implémenter l'utilitaire, comme d'habitude, définissez son interface. | ||
2247 | 1160 | Voici une interface qui dit bonjour :: | ||
2248 | 1150 | 1161 | ||
2249 | 1151 | >>> from zope.interface import Interface | 1162 | >>> from zope.interface import Interface |
2250 | 1152 | >>> from zope.interface import implements | 1163 | >>> from zope.interface import implements |
2251 | @@ -1154,9 +1165,10 @@ | |||
2252 | 1154 | >>> class IGreeter(Interface): | 1165 | >>> class IGreeter(Interface): |
2253 | 1155 | ... | 1166 | ... |
2254 | 1156 | ... def greet(name): | 1167 | ... def greet(name): |
2256 | 1157 | ... "say hello" | 1168 | ... """Say hello""" |
2257 | 1158 | 1169 | ||
2259 | 1159 | Here is a possible implementation of the above interface:: | 1170 | Comme un adaptateur, un utilitaire peut avoir plusieurs implémentations. Voici |
2260 | 1171 | une implémentation possible de l'interface ci-dessus :: | ||
2261 | 1160 | 1172 | ||
2262 | 1161 | >>> class Greeter(object): | 1173 | >>> class Greeter(object): |
2263 | 1162 | ... | 1174 | ... |
2264 | @@ -1165,7 +1177,10 @@ | |||
2265 | 1165 | ... def greet(self, name): | 1177 | ... def greet(self, name): |
2266 | 1166 | ... return "Hello " + name | 1178 | ... return "Hello " + name |
2267 | 1167 | 1179 | ||
2269 | 1168 | You can register an instance of this class using ``registerUtility``:: | 1180 | L'utilitaire réel sera une instance de cette classe. Pour utiliser cet |
2270 | 1181 | utilitaire, vous devez l'inscrire, puis vous pourrez la récupérer en | ||
2271 | 1182 | utilisant l'API de la ZCA. Vous pouvez inscrire une instance de cette classe | ||
2272 | 1183 | (`utilitaire`) grâce à ``registerUtility`` :: | ||
2273 | 1169 | 1184 | ||
2274 | 1170 | >>> from zope.component import getGlobalSiteManager | 1185 | >>> from zope.component import getGlobalSiteManager |
2275 | 1171 | >>> gsm = getGlobalSiteManager() | 1186 | >>> gsm = getGlobalSiteManager() |
2276 | @@ -1173,9 +1188,9 @@ | |||
2277 | 1173 | >>> greet = Greeter() | 1188 | >>> greet = Greeter() |
2278 | 1174 | >>> gsm.registerUtility(greet, IGreeter) | 1189 | >>> gsm.registerUtility(greet, IGreeter) |
2279 | 1175 | 1190 | ||
2283 | 1176 | In this example you registered the utility as providing the `IGreeter` | 1191 | Dans cet exemple, vous avez inscrit l'utilitaire en fournissant l'interface |
2284 | 1177 | interface. You can look the interface up with either `queryUtility` | 1192 | `IGreeter`. Vous pouvez récupérer l'utilitaire avec `queryUtility` ou |
2285 | 1178 | or `getUtility`:: | 1193 | `getUtility` :: |
2286 | 1179 | 1194 | ||
2287 | 1180 | >>> from zope.component import queryUtility | 1195 | >>> from zope.component import queryUtility |
2288 | 1181 | >>> from zope.component import getUtility | 1196 | >>> from zope.component import getUtility |
2289 | @@ -1186,24 +1201,27 @@ | |||
2290 | 1186 | >>> getUtility(IGreeter).greet('Jack') | 1201 | >>> getUtility(IGreeter).greet('Jack') |
2291 | 1187 | 'Hello Jack' | 1202 | 'Hello Jack' |
2292 | 1188 | 1203 | ||
2304 | 1189 | As you can see, adapters are normally classes, but utilities are | 1204 | Comme vous pouvez le constater, alors que les adaptateurs sont habituellement |
2305 | 1190 | normally instances of classes. | 1205 | des classes, les utilitaires sont habituellement des instances de classes. vous |
2306 | 1191 | 1206 | ne créez une instance d'utilitaire qu'une fois, alors que les instances | |
2307 | 1192 | 1207 | d'adaptateurs sont créées à chaque fois que vous les récupérez. | |
2308 | 1193 | Named utility | 1208 | |
2309 | 1194 | ~~~~~~~~~~~~~ | 1209 | |
2310 | 1195 | 1210 | Utilitaire nommé | |
2311 | 1196 | When registering a utility component, like adapter, you can use a | 1211 | ~~~~~~~~~~~~~~~~ |
2312 | 1197 | name. | 1212 | |
2313 | 1198 | 1213 | Lorsque vous inscrivez un composant utilitaire, de la même manière que pour les | |
2314 | 1199 | For example consider this: | 1214 | adaptateurs, vous pouvez utiliser un nom. Comme mentionné dans la section |
2315 | 1215 | précédente, un utilitaire inscrit avec un nom est appelé un `utilitaire nommé`. | ||
2316 | 1216 | |||
2317 | 1217 | Voici comment inscrire l'utilitaire `greeter` avec un nom :: | ||
2318 | 1200 | 1218 | ||
2319 | 1201 | >>> greet = Greeter() | 1219 | >>> greet = Greeter() |
2320 | 1202 | >>> gsm.registerUtility(greet, IGreeter, 'new') | 1220 | >>> gsm.registerUtility(greet, IGreeter, 'new') |
2321 | 1203 | 1221 | ||
2325 | 1204 | In this example you registered the utility with a name as providing | 1222 | Dans cet exemple, nous avons inscrit l'utilitaire avec un nom en fournissant |
2326 | 1205 | the `IGreeter` interface. You can look the interface up with either | 1223 | l'interface `IGreeter`. Vous pouvez récupérer l'utilitaire avec `queryUtility` |
2327 | 1206 | `queryUtility` or `getUtility`:: | 1224 | ou `getUtility` :: |
2328 | 1207 | 1225 | ||
2329 | 1208 | >>> from zope.component import queryUtility | 1226 | >>> from zope.component import queryUtility |
2330 | 1209 | >>> from zope.component import getUtility | 1227 | >>> from zope.component import getUtility |
2331 | @@ -1214,28 +1232,25 @@ | |||
2332 | 1214 | >>> getUtility(IGreeter, 'new').greet('Jill') | 1232 | >>> getUtility(IGreeter, 'new').greet('Jill') |
2333 | 1215 | 'Hello Jill' | 1233 | 'Hello Jill' |
2334 | 1216 | 1234 | ||
2357 | 1217 | As you can see here, while querying you have to use the `name` as | 1235 | Remarquez que vous devez utiliser le nom de l'utilitaire comme second argument |
2358 | 1218 | second argument. | 1236 | pour que la récupération fonctionne. |
2359 | 1219 | 1237 | ||
2360 | 1220 | .. note:: | 1238 | Appeler `getUtility` sans nom (comme second argument) est équivalent à l'appeler |
2361 | 1221 | 1239 | avec un nom vide (''), car la valeur par défaut pour ce second argument est | |
2362 | 1222 | Calling `getUtility` function without a name (second argument) is | 1240 | justement la chaîne vide. Donc le mécanisme de recherche de composant essaiera |
2363 | 1223 | equivalent to calling with an empty string ('') as the name. | 1241 | de trouver le composant ayant une chaîne vide comme nom et il échouera. |
2364 | 1224 | Because, the default value for second (keyword) argument is an empty | 1242 | Lorsqu'une recherche de composant échoue, le résultat est une exception |
2365 | 1225 | string. Then, component lookup mechanism will try to find the | 1243 | ``ComponentLookupError``. Souvenez-vous qu'aucun composant aléatoire avec un |
2366 | 1226 | component with name as empty string (''), and it will fail. When | 1244 | autre nom ne sera renvoyé. Les fonctions de récupération d'adaptateurs, |
2367 | 1227 | component lookup fails it will raise `ComponentLookupError` | 1245 | `getAdapter` et `queryUtility` fonctionnent de manière similaire. |
2368 | 1228 | exception. Remember, it will not return some random component | 1246 | |
2369 | 1229 | registered with some other name. | 1247 | |
2370 | 1230 | 1248 | Fabrique | |
2371 | 1231 | 1249 | ~~~~~~~~ | |
2372 | 1232 | Factory | 1250 | |
2373 | 1233 | ~~~~~~~ | 1251 | Une ``fabrique`` est un composant utilitaire qui fournit l'interface ``IFactory``. |
2374 | 1234 | 1252 | ||
2375 | 1235 | A ``Factory`` is a utility component which provides ``IFactory`` | 1253 | Pour créer une fabrique, commencez par définir l'interface de l'objet :: |
2354 | 1236 | interface. | ||
2355 | 1237 | |||
2356 | 1238 | To create a factory, first define the interface of the object:: | ||
2376 | 1239 | 1254 | ||
2377 | 1240 | >>> from zope.interface import Attribute | 1255 | >>> from zope.interface import Attribute |
2378 | 1241 | >>> from zope.interface import Interface | 1256 | >>> from zope.interface import Interface |
2379 | @@ -1246,7 +1261,7 @@ | |||
2380 | 1246 | ... def getConnection(): | 1261 | ... def getConnection(): |
2381 | 1247 | ... """Return connection object""" | 1262 | ... """Return connection object""" |
2382 | 1248 | 1263 | ||
2384 | 1249 | Here is fake implementation of `IDatabase` interface:: | 1264 | Voici une implémentation factice de l'interface `IDatabase` :: |
2385 | 1250 | 1265 | ||
2386 | 1251 | >>> class FakeDb(object): | 1266 | >>> class FakeDb(object): |
2387 | 1252 | ... | 1267 | ... |
2388 | @@ -1255,13 +1270,13 @@ | |||
2389 | 1255 | ... def getConnection(self): | 1270 | ... def getConnection(self): |
2390 | 1256 | ... return "connection" | 1271 | ... return "connection" |
2391 | 1257 | 1272 | ||
2393 | 1258 | You can create a factory using ``zope.component.factory.Factory``:: | 1273 | Vous pouvez créer une fabrique en utilisant ``zope.component.factory.Factory`` :: |
2394 | 1259 | 1274 | ||
2395 | 1260 | >>> from zope.component.factory import Factory | 1275 | >>> from zope.component.factory import Factory |
2396 | 1261 | 1276 | ||
2397 | 1262 | >>> factory = Factory(FakeDb, 'FakeDb') | 1277 | >>> factory = Factory(FakeDb, 'FakeDb') |
2398 | 1263 | 1278 | ||
2400 | 1264 | Now you can register it like this:: | 1279 | Maintenant vous pouvez l'inscrire de cette façon :: |
2401 | 1265 | 1280 | ||
2402 | 1266 | >>> from zope.component import getGlobalSiteManager | 1281 | >>> from zope.component import getGlobalSiteManager |
2403 | 1267 | >>> gsm = getGlobalSiteManager() | 1282 | >>> gsm = getGlobalSiteManager() |
2404 | @@ -1269,29 +1284,32 @@ | |||
2405 | 1269 | >>> from zope.component.interfaces import IFactory | 1284 | >>> from zope.component.interfaces import IFactory |
2406 | 1270 | >>> gsm.registerUtility(factory, IFactory, 'fakedb') | 1285 | >>> gsm.registerUtility(factory, IFactory, 'fakedb') |
2407 | 1271 | 1286 | ||
2409 | 1272 | To use the factory, you may do it like this:: | 1287 | Pour utiliser la fabrique, vous pouvez faire comme ceci :: |
2410 | 1273 | 1288 | ||
2411 | 1274 | >>> from zope.component import queryUtility | 1289 | >>> from zope.component import queryUtility |
2412 | 1275 | >>> queryUtility(IFactory, 'fakedb')() #doctest: +ELLIPSIS | 1290 | >>> queryUtility(IFactory, 'fakedb')() #doctest: +ELLIPSIS |
2413 | 1276 | <FakeDb object at ...> | 1291 | <FakeDb object at ...> |
2414 | 1277 | 1292 | ||
2416 | 1278 | There is a shortcut to use factory:: | 1293 | Voici l'écriture simplifiée pour utiliser une fabrique :: |
2417 | 1279 | 1294 | ||
2418 | 1280 | >>> from zope.component import createObject | 1295 | >>> from zope.component import createObject |
2419 | 1281 | >>> createObject('fakedb') #doctest: +ELLIPSIS | 1296 | >>> createObject('fakedb') #doctest: +ELLIPSIS |
2420 | 1282 | <FakeDb object at ...> | 1297 | <FakeDb object at ...> |
2421 | 1283 | 1298 | ||
2422 | 1284 | 1299 | ||
2433 | 1285 | Advanced adapters | 1300 | Adaptateurs avancés |
2434 | 1286 | ----------------- | 1301 | ------------------- |
2435 | 1287 | 1302 | ||
2436 | 1288 | 1303 | Ce chapître traite de concepts avancés comme les multi-adaptateurs, les | |
2437 | 1289 | Multi adapter | 1304 | abonnés (subscribers) et les gestionnaires (handles). |
2438 | 1290 | ~~~~~~~~~~~~~ | 1305 | |
2439 | 1291 | 1306 | ||
2440 | 1292 | A simple adapter normally adapts only one object, but an adapter can | 1307 | Multi-adaptateur |
2441 | 1293 | adapt more than one object. If an adapter adapts more than one | 1308 | ~~~~~~~~~~~~~~~~ |
2442 | 1294 | objects, it is called as multi-adapter. | 1309 | |
2443 | 1310 | Un adaptateur simple s'adapte normalement à un seul objet, mais un adaptateur | ||
2444 | 1311 | peut s'adapter à plusieurs objets. Si un adaptateur s'adapte à plus d'un objet, | ||
2445 | 1312 | il s'appelle un multi-adaptateur. | ||
2446 | 1295 | 1313 | ||
2447 | 1296 | :: | 1314 | :: |
2448 | 1297 | 1315 | ||
2449 | @@ -1342,16 +1360,16 @@ | |||
2450 | 1342 | <Two object at ...> | 1360 | <Two object at ...> |
2451 | 1343 | 1361 | ||
2452 | 1344 | 1362 | ||
2463 | 1345 | Subscription adapter | 1363 | Adaptateur d'abonnement |
2464 | 1346 | ~~~~~~~~~~~~~~~~~~~~ | 1364 | ~~~~~~~~~~~~~~~~~~~~~~~ |
2465 | 1347 | 1365 | ||
2466 | 1348 | Unlike regular adapters, subscription adapters are used when we want | 1366 | À la différence des adaptateurs habituels, les adaptateurs d'abonnement sont |
2467 | 1349 | all of the adapters that adapt an object to a particular adapter. | 1367 | utilisés quand on veut récupérer tous les adaptateurs qui adaptent un objet à |
2468 | 1350 | Subscription adapter is also known as `subscriber` . | 1368 | une interface donnée. Un adaptateur d'abonnement est également appelé `abonné`. |
2469 | 1351 | 1369 | ||
2470 | 1352 | Consider a validation problem. We have objects and we want to assess | 1370 | Considérons un problème de validation. Nous avons des objets et nous voulons |
2471 | 1353 | whether they meet some sort of standards. We define a validation | 1371 | vérifier s'ils satisfont à un certain critère. Nous définissons une interface |
2472 | 1354 | interface:: | 1372 | de validation :: |
2473 | 1355 | 1373 | ||
2474 | 1356 | >>> from zope.interface import Interface | 1374 | >>> from zope.interface import Interface |
2475 | 1357 | >>> from zope.interface import Attribute | 1375 | >>> from zope.interface import Attribute |
2476 | @@ -1367,7 +1385,7 @@ | |||
2477 | 1367 | ... object is valid. | 1385 | ... object is valid. |
2478 | 1368 | ... """ | 1386 | ... """ |
2479 | 1369 | 1387 | ||
2481 | 1370 | Perhaps we have documents:: | 1388 | Nous avons également des documents :: |
2482 | 1371 | 1389 | ||
2483 | 1372 | >>> class IDocument(Interface): | 1390 | >>> class IDocument(Interface): |
2484 | 1373 | ... | 1391 | ... |
2485 | @@ -1381,9 +1399,9 @@ | |||
2486 | 1381 | ... def __init__(self, summary, body): | 1399 | ... def __init__(self, summary, body): |
2487 | 1382 | ... self.summary, self.body = summary, body | 1400 | ... self.summary, self.body = summary, body |
2488 | 1383 | 1401 | ||
2492 | 1384 | Now, we may want to specify various validation rules for | 1402 | Maintenant, nous pouvons avoir besoin de préciser différentes règles de |
2493 | 1385 | documents. For example, we might require that the summary be a single | 1403 | validation pour les documents. Par exemple, nous voulons que le résumé tienne |
2494 | 1386 | line: | 1404 | sur une seule ligne :: |
2495 | 1387 | 1405 | ||
2496 | 1388 | >>> from zope.component import adapts | 1406 | >>> from zope.component import adapts |
2497 | 1389 | 1407 | ||
2498 | @@ -1401,7 +1419,7 @@ | |||
2499 | 1401 | ... else: | 1419 | ... else: |
2500 | 1402 | ... return '' | 1420 | ... return '' |
2501 | 1403 | 1421 | ||
2503 | 1404 | Or we might require the body to be at least 1000 characters in length: | 1422 | Ou bien nous voulons que le corps du document fasse au moins 1000 caractères :: |
2504 | 1405 | 1423 | ||
2505 | 1406 | >>> class AdequateLength(object): | 1424 | >>> class AdequateLength(object): |
2506 | 1407 | ... | 1425 | ... |
2507 | @@ -1417,7 +1435,7 @@ | |||
2508 | 1417 | ... else: | 1435 | ... else: |
2509 | 1418 | ... return '' | 1436 | ... return '' |
2510 | 1419 | 1437 | ||
2512 | 1420 | We can register these as subscription adapters: | 1438 | Nous pouvons inscrire ces deux composants comme des adaptateurs d'abonnement :: |
2513 | 1421 | 1439 | ||
2514 | 1422 | >>> from zope.component import getGlobalSiteManager | 1440 | >>> from zope.component import getGlobalSiteManager |
2515 | 1423 | >>> gsm = getGlobalSiteManager() | 1441 | >>> gsm = getGlobalSiteManager() |
2516 | @@ -1425,7 +1443,7 @@ | |||
2517 | 1425 | >>> gsm.registerSubscriptionAdapter(SingleLineSummary) | 1443 | >>> gsm.registerSubscriptionAdapter(SingleLineSummary) |
2518 | 1426 | >>> gsm.registerSubscriptionAdapter(AdequateLength) | 1444 | >>> gsm.registerSubscriptionAdapter(AdequateLength) |
2519 | 1427 | 1445 | ||
2521 | 1428 | We can then use the subscribers to validate objects: | 1446 | Nous pouvons ensuite utiliser ces abonnés pour valider les objets :: |
2522 | 1429 | 1447 | ||
2523 | 1430 | >>> from zope.component import subscribers | 1448 | >>> from zope.component import subscribers |
2524 | 1431 | 1449 | ||
2525 | @@ -1448,36 +1466,37 @@ | |||
2526 | 1448 | ['too short'] | 1466 | ['too short'] |
2527 | 1449 | 1467 | ||
2528 | 1450 | 1468 | ||
2545 | 1451 | Handler | 1469 | Gestionnaire |
2546 | 1452 | ~~~~~~~ | 1470 | ~~~~~~~~~~~~ |
2547 | 1453 | 1471 | ||
2548 | 1454 | Handlers are subscription adapter factories that don't produce | 1472 | Les gestionnaires sont des fabriques d'abonnés qui ne |
2549 | 1455 | anything. They do all of their work when called. Handlers are | 1473 | produisent rien du tout. Ils font la totalité de leur travail lorsqu'ils sont |
2550 | 1456 | typically used to handle events. Handlers are also known as event | 1474 | appelés. Les gestionnaires sont typiquement utilisés pour gérer des événements. |
2551 | 1457 | subscribers or event subscription adapters. | 1475 | Les gestionnaires sont aussi connus sous le nom d'``abonnés |
2552 | 1458 | 1476 | à des événements`` ou ``adaptateurs d'abonnement à des événements``. | |
2553 | 1459 | Event subscribers are different from other subscription adapters in | 1477 | |
2554 | 1460 | that the caller of event subscribers doesn't expect to interact with | 1478 | Les abonnés à des événements sont différents des autres abonnés car l'objet qui |
2555 | 1461 | them in any direct way. For example, an event publisher doesn't | 1479 | appelle les abonnés ne s'attend pas à interagir avec eux d'une quelconque façon. |
2556 | 1462 | expect to get any return value. Because subscribers don't need to | 1480 | Par exemple, un publicateur d'événements ne s'attend pas à récupérer une valeur |
2557 | 1463 | provide an API to their callers, it is more natural to define them | 1481 | de retour. Comme les abonnés n'ont pas besoin de fournir une API aux objets qui |
2558 | 1464 | with functions, rather than classes. For example, in a | 1482 | les appellent, il est plus naturel de les définir avec des fonctions, plutôt |
2559 | 1465 | document-management system, we might want to record creation times for | 1483 | qu'avec des classes. Par exemple, dans un système de gestion de documents, nous |
2560 | 1466 | documents:: | 1484 | pouvons avoir besoin de gérer les heures de création des documents :: |
2561 | 1467 | 1485 | ||
2562 | 1468 | >>> import datetime | 1486 | >>> import datetime |
2563 | 1469 | 1487 | ||
2564 | 1470 | >>> def documentCreated(event): | 1488 | >>> def documentCreated(event): |
2565 | 1471 | ... event.doc.created = datetime.datetime.utcnow() | 1489 | ... event.doc.created = datetime.datetime.utcnow() |
2566 | 1472 | 1490 | ||
2573 | 1473 | In this example, we have a function that takes an event and performs | 1491 | Dans cet exemple, nous avons une fonction qui prend un événement et effectue un |
2574 | 1474 | some processing. It doesn't actually return anything. This is a | 1492 | traitement. La fonction ne retourne en fait rien du tout. C'est un cas |
2575 | 1475 | special case of a subscription adapter that adapts an event to | 1493 | particulier de l'adaptateur d'abonnement qui s'adapte à un événement et ne |
2576 | 1476 | nothing. All of the work is done when the adapter "factory" is | 1494 | fournit rien. Tout le travail est effectué lorsque la fabrique de l'adaptateur |
2577 | 1477 | called. We call subscribers that don't actually create anything | 1495 | est appelée. Nous appelons les abonnés qui ne fabriquent rien des « gestionnaires ». |
2578 | 1478 | "handlers". There are special APIs for registering and calling them. | 1496 | Il existe des APIs spécialisées dans leur inscription et leur récupération. |
2579 | 1479 | 1497 | ||
2581 | 1480 | To register the subscriber above, we define a document-created event:: | 1498 | Pour inscrire l'abonné ci-dessus, nous définissons un événement « document créé |
2582 | 1499 | » :: | ||
2583 | 1481 | 1500 | ||
2584 | 1482 | >>> from zope.interface import Interface | 1501 | >>> from zope.interface import Interface |
2585 | 1483 | >>> from zope.interface import Attribute | 1502 | >>> from zope.interface import Attribute |
2586 | @@ -1494,7 +1513,7 @@ | |||
2587 | 1494 | ... def __init__(self, doc): | 1513 | ... def __init__(self, doc): |
2588 | 1495 | ... self.doc = doc | 1514 | ... self.doc = doc |
2589 | 1496 | 1515 | ||
2591 | 1497 | We'll also change our handler definition to: | 1516 | Nous modifions également notre définition du gestionnaire :: |
2592 | 1498 | 1517 | ||
2593 | 1499 | >>> def documentCreated(event): | 1518 | >>> def documentCreated(event): |
2594 | 1500 | ... event.doc.created = datetime.datetime.utcnow() | 1519 | ... event.doc.created = datetime.datetime.utcnow() |
2595 | @@ -1505,17 +1524,18 @@ | |||
2596 | 1505 | ... def documentCreated(event): | 1524 | ... def documentCreated(event): |
2597 | 1506 | ... event.doc.created = datetime.datetime.utcnow() | 1525 | ... event.doc.created = datetime.datetime.utcnow() |
2598 | 1507 | 1526 | ||
2600 | 1508 | This marks the handler as an adapter of `IDocumentCreated` events. | 1527 | Ceci marque le gestionnaire comme étant un adaptateur des événements |
2601 | 1528 | `IDocumentCreated`. | ||
2602 | 1509 | 1529 | ||
2604 | 1510 | Now we'll register the handler:: | 1530 | Nous inscrivons le gestionnaire :: |
2605 | 1511 | 1531 | ||
2606 | 1512 | >>> from zope.component import getGlobalSiteManager | 1532 | >>> from zope.component import getGlobalSiteManager |
2607 | 1513 | >>> gsm = getGlobalSiteManager() | 1533 | >>> gsm = getGlobalSiteManager() |
2608 | 1514 | 1534 | ||
2609 | 1515 | >>> gsm.registerHandler(documentCreated) | 1535 | >>> gsm.registerHandler(documentCreated) |
2610 | 1516 | 1536 | ||
2613 | 1517 | Now, if we can create an event and use the `handle` function to call | 1537 | Il est maintenant possible de créer un événement et d'utiliser la fonction |
2614 | 1518 | handlers registered for the event:: | 1538 | `handle` pour appeler les gestionnaires inscrits à l'événement :: |
2615 | 1519 | 1539 | ||
2616 | 1520 | >>> from zope.component import handle | 1540 | >>> from zope.component import handle |
2617 | 1521 | 1541 | ||
2618 | @@ -1524,29 +1544,34 @@ | |||
2619 | 1524 | 'datetime' | 1544 | 'datetime' |
2620 | 1525 | 1545 | ||
2621 | 1526 | 1546 | ||
2624 | 1527 | ZCA usage in Zope | 1547 | Usage de la ZCA dans Zope |
2625 | 1528 | ----------------- | 1548 | ------------------------- |
2626 | 1529 | 1549 | ||
2629 | 1530 | Zope Component Architecture is used in both Zope 3 and Zope 2. This | 1550 | L'Architecture de Composants de Zope est utilisée dans Zope 2 et dans Zope 3. Ce |
2630 | 1531 | chapter go through ZCA usage in Zope. | 1551 | chapitre traite de l'usage de la ZCA dans Zope. |
2631 | 1532 | 1552 | ||
2632 | 1533 | 1553 | ||
2633 | 1534 | ZCML | 1554 | ZCML |
2634 | 1535 | ~~~~ | 1555 | ~~~~ |
2635 | 1536 | 1556 | ||
2641 | 1537 | The Zope Configuration Markup Language (ZCML) is an XML based | 1557 | Le **Zope Configuration Markup Language (ZCML)** est un système de configuration |
2642 | 1538 | configuration system for registration of components. So, instead of | 1558 | pour l'inscription des composants. Au lieu d'utiliser l'API Python pour les |
2643 | 1539 | using Python API for registration, you can use ZCML. But to use ZCML, | 1559 | inscriptions, vous pouvez utiliser le ZCML. Pour pouvoir utiliser le ZCML, |
2644 | 1540 | unfortunately, you will be required to install more dependency | 1560 | vous devez installer des paquets supplémentaires. |
2640 | 1541 | packages. | ||
2645 | 1542 | 1561 | ||
2647 | 1543 | To install these packages:: | 1562 | Vous pouvez installer ``zope.component`` avec la prise en charge du ZCML en |
2648 | 1563 | utilisant easy_install comme ceci :: | ||
2649 | 1544 | 1564 | ||
2650 | 1545 | $ easy_install "zope.component [zcml]" | 1565 | $ easy_install "zope.component [zcml]" |
2651 | 1546 | 1566 | ||
2653 | 1547 | To register an adapter:: | 1567 | Un fichier ZCML doit commencer par une directive ``configure`` avec la |
2654 | 1568 | déclaration d'espace de nom appropriée :: | ||
2655 | 1548 | 1569 | ||
2656 | 1549 | <configure xmlns="http://namespaces.zope.org/zope"> | 1570 | <configure xmlns="http://namespaces.zope.org/zope"> |
2657 | 1571 | ... | ||
2658 | 1572 | </configure> | ||
2659 | 1573 | |||
2660 | 1574 | La directive `adapter` peut être utilisée pour inscrire des adaptateurs :: | ||
2661 | 1550 | 1575 | ||
2662 | 1551 | <adapter | 1576 | <adapter |
2663 | 1552 | factory=".company.EmployeeSalary" | 1577 | factory=".company.EmployeeSalary" |
2664 | @@ -1554,73 +1579,59 @@ | |||
2665 | 1554 | for=".interfaces.IEmployee" | 1579 | for=".interfaces.IEmployee" |
2666 | 1555 | /> | 1580 | /> |
2667 | 1556 | 1581 | ||
2672 | 1557 | The `provides` and `for` attributes are optional, provided you have | 1582 | Les attributs `provides` et `for` sont optionnels, à condition que vous ayez |
2673 | 1558 | declared it in the implementation:: | 1583 | fait les déclaration correspondantes dans l'implémentation :: |
2670 | 1559 | |||
2671 | 1560 | <configure xmlns="http://namespaces.zope.org/zope"> | ||
2674 | 1561 | 1584 | ||
2675 | 1562 | <adapter | 1585 | <adapter |
2676 | 1563 | factory=".company.EmployeeSalary" | 1586 | factory=".company.EmployeeSalary" |
2677 | 1564 | /> | 1587 | /> |
2678 | 1565 | 1588 | ||
2684 | 1566 | If you want to register the component as named adapter, you can give a | 1589 | Si vous voulez inscrire le composant comme un adaptateur nommé, vous pouvez |
2685 | 1567 | `name` attribute:: | 1590 | utiliser l'attribut `name` :: |
2681 | 1568 | |||
2682 | 1569 | |||
2683 | 1570 | <configure xmlns="http://namespaces.zope.org/zope"> | ||
2686 | 1571 | 1591 | ||
2687 | 1572 | <adapter | 1592 | <adapter |
2688 | 1573 | factory=".company.EmployeeSalary" | 1593 | factory=".company.EmployeeSalary" |
2689 | 1574 | name="salary" | 1594 | name="salary" |
2690 | 1575 | /> | 1595 | /> |
2691 | 1576 | 1596 | ||
2697 | 1577 | Utilities are also registered similarly. | 1597 | Un utilitaire peut être inscrit avec la directive `utility` :: |
2693 | 1578 | |||
2694 | 1579 | To register an utility:: | ||
2695 | 1580 | |||
2696 | 1581 | <configure xmlns="http://namespaces.zope.org/zope"> | ||
2698 | 1582 | 1598 | ||
2699 | 1583 | <utility | 1599 | <utility |
2700 | 1584 | component=".database.connection" | 1600 | component=".database.connection" |
2701 | 1585 | provides=".interfaces.IConnection" | 1601 | provides=".interfaces.IConnection" |
2702 | 1586 | /> | 1602 | /> |
2703 | 1587 | 1603 | ||
2727 | 1588 | The `provides` attribute is optional, provided you have declared it in | 1604 | L'attribut `provides` est optionnel, à condition que vous ayez fait la |
2728 | 1589 | the implementation:: | 1605 | déclaration correspondante dans l'implémentation :: |
2729 | 1590 | 1606 | ||
2730 | 1591 | <configure xmlns="http://namespaces.zope.org/zope"> | 1607 | <configure xmlns="http://namespaces.zope.org/zope"> |
2731 | 1592 | 1608 | ||
2732 | 1593 | <utility | 1609 | <utility |
2733 | 1594 | component=".database.connection" | 1610 | component=".database.connection" |
2734 | 1595 | /> | 1611 | /> |
2735 | 1596 | 1612 | ||
2736 | 1597 | If you want to register the component as named adapter, you can give a | 1613 | Si vous voulez inscrire le composant comme un utilitaire nommé, vous pouvez |
2737 | 1598 | `name` attribute:: | 1614 | utiliser l'attribut `name` :: |
2738 | 1599 | 1615 | ||
2739 | 1600 | 1616 | <utility | |
2740 | 1601 | <configure xmlns="http://namespaces.zope.org/zope"> | 1617 | component=".database.connection" |
2741 | 1602 | 1618 | name="db_connection" | |
2742 | 1603 | <utility | 1619 | /> |
2743 | 1604 | component=".database.connection" | 1620 | |
2744 | 1605 | name="Database Connection" | 1621 | Plutôt que d'utiliser directement le composant, vous pouvez aussi fournir une |
2745 | 1606 | /> | 1622 | fabrique :: |
2723 | 1607 | |||
2724 | 1608 | Instead of directly using the component, you can also give a factory:: | ||
2725 | 1609 | |||
2726 | 1610 | <configure xmlns="http://namespaces.zope.org/zope"> | ||
2746 | 1611 | 1623 | ||
2747 | 1612 | <utility | 1624 | <utility |
2748 | 1613 | factory=".database.Connection" | 1625 | factory=".database.Connection" |
2749 | 1614 | /> | 1626 | /> |
2750 | 1615 | 1627 | ||
2751 | 1616 | 1628 | ||
2754 | 1617 | Overrides | 1629 | Surchargements |
2755 | 1618 | ~~~~~~~~~ | 1630 | ~~~~~~~~~~~~~~ |
2756 | 1619 | 1631 | ||
2761 | 1620 | When you register components using Python API (``register*`` methods), | 1632 | Lorsque vous inscrivez des composants avec l'API Python (méthodes |
2762 | 1621 | the last registered component will replace previously registered | 1633 | ``register*``), le dernier composant inscrit remplace le précédent, si les deux |
2763 | 1622 | component, if both are registered with same type of arguments. For | 1634 | sont inscrits avec les mêmes arguments. Considérons l'exemple suivant :: |
2760 | 1623 | example, consider this example:: | ||
2764 | 1624 | 1635 | ||
2765 | 1625 | >>> from zope.interface import Attribute | 1636 | >>> from zope.interface import Attribute |
2766 | 1626 | >>> from zope.interface import Interface | 1637 | >>> from zope.interface import Interface |
2767 | @@ -1665,22 +1676,21 @@ | |||
2768 | 1665 | >>> getAdapter(a, IP) #doctest: +ELLIPSIS | 1676 | >>> getAdapter(a, IP) #doctest: +ELLIPSIS |
2769 | 1666 | <AP object at ...> | 1677 | <AP object at ...> |
2770 | 1667 | 1678 | ||
2772 | 1668 | If you register another adapter, the existing one will be replaced: | 1679 | Si vous inscrivez un autre adaptateur, celui existant sera surchargé :: |
2773 | 1669 | 1680 | ||
2774 | 1670 | >>> gsm.registerAdapter(AP2) | 1681 | >>> gsm.registerAdapter(AP2) |
2775 | 1671 | 1682 | ||
2776 | 1672 | >>> getAdapter(a, IP) #doctest: +ELLIPSIS | 1683 | >>> getAdapter(a, IP) #doctest: +ELLIPSIS |
2777 | 1673 | <AP2 object at ...> | 1684 | <AP2 object at ...> |
2778 | 1674 | 1685 | ||
2784 | 1675 | But when registering components using ZCML, the second registration | 1686 | Mais lorsque vous inscrivez des composants en ZCML, la deuxième inscription |
2785 | 1676 | will raise a conflict error. This is a hint for you, otherwise there | 1687 | provoquera un conflit. Ceci est fait pour éviter les surchargements accidentels |
2786 | 1677 | is a chance for overriding registration by mistake. This may lead to | 1688 | d'inscriptions, qui sont difficiles à retrouver et corriger. |
2787 | 1678 | hard to track bugs in your system. So, using ZCML is a win for the | 1689 | L'utilisation de ZCML est donc un avantage pour votre application. |
2783 | 1679 | application. | ||
2788 | 1680 | 1690 | ||
2792 | 1681 | Sometimes you will be required to override existing registration. | 1691 | Parfois vous aurez besoin de surcharger une inscription existante. ZCML fournit |
2793 | 1682 | ZCML provides ``includeOverrides`` directive for this. Using this, | 1692 | une directive ``includeOverrides`` à cet effet. Avec la directive ci-dessous, |
2794 | 1683 | you can write your overrides in a separate file:: | 1693 | vous pouvez écrire vos surcharges dans un fichier séparé :: |
2795 | 1684 | 1694 | ||
2796 | 1685 | <includeOverrides file="overrides.zcml" /> | 1695 | <includeOverrides file="overrides.zcml" /> |
2797 | 1686 | 1696 | ||
2798 | @@ -1688,12 +1698,11 @@ | |||
2799 | 1688 | NameChooser | 1698 | NameChooser |
2800 | 1689 | ~~~~~~~~~~~ | 1699 | ~~~~~~~~~~~ |
2801 | 1690 | 1700 | ||
2808 | 1691 | Location: `zope.app.container.contained.NameChooser` | 1701 | Emplacement : `zope.app.container.contained.NameChooser` |
2809 | 1692 | 1702 | ||
2810 | 1693 | This is an adapter for choosing a unique name for an object inside a | 1703 | C'est un adaptateur qui choisit un nom unique pour un objet dans un conteneur. |
2811 | 1694 | container. | 1704 | |
2812 | 1695 | 1705 | L'inscription de l'adaptateur ressemble à ceci :: | |
2807 | 1696 | The registration of adapter is like this:: | ||
2813 | 1697 | 1706 | ||
2814 | 1698 | <adapter | 1707 | <adapter |
2815 | 1699 | provides=".interfaces.INameChooser" | 1708 | provides=".interfaces.INameChooser" |
2816 | @@ -1701,40 +1710,37 @@ | |||
2817 | 1701 | factory=".contained.NameChooser" | 1710 | factory=".contained.NameChooser" |
2818 | 1702 | /> | 1711 | /> |
2819 | 1703 | 1712 | ||
2822 | 1704 | From the registration, you can see that the adaptee is a | 1713 | Dans cette inscription, vous pouvez observer qu'on s'adapte à un |
2823 | 1705 | ``IWriteContainer`` and the adapter provides ``INameChooser``. | 1714 | ``IWriteContainer`` et que l'adaptateur fournit ``INameChooser``. |
2824 | 1706 | 1715 | ||
2833 | 1707 | This adapter provides a very convenient functionality for Zope | 1716 | Cet adaptateur fournit une fonctionnalité très pratique pour les développeurs |
2834 | 1708 | programmers. The main implementations of ``IWriteContainer`` in | 1717 | Zope. Les implémentations principales de ``IWriteContainer`` dans Zope 3 sont |
2835 | 1709 | Zope 3 are ``zope.app.container.BTreeContainer`` and | 1718 | `zope.app.container.BTreeContainer`` et ``zope.app.folder.Folder``. Normalement |
2836 | 1710 | ``zope.app.folder.Folder``. Normally you will be inheriting from | 1719 | vous hériterez de ces implémentations pour créer vos propres classes de |
2837 | 1711 | these implementations for creating your own container classes. | 1720 | conteneurs. Supposez qu'il n'y ait pas d'interface ``INameChooser`` ni |
2838 | 1712 | Suppose there is no interface called ``INameChooser`` and | 1721 | d'adaptateur : vous seriez obligé de recréer cette fonctionnalité séparément |
2839 | 1713 | adapter, then you will be required to implement this functionality | 1722 | pour chaque implémentation. |
2832 | 1714 | for every implementations separately. | ||
2840 | 1715 | 1723 | ||
2841 | 1716 | 1724 | ||
2842 | 1717 | LocationPhysicallyLocatable | 1725 | LocationPhysicallyLocatable |
2843 | 1718 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1726 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
2844 | 1719 | 1727 | ||
2846 | 1720 | Location: | 1728 | Emplacement : |
2847 | 1721 | ``zope.location.traversing.LocationPhysicallyLocatable`` | 1729 | ``zope.location.traversing.LocationPhysicallyLocatable`` |
2848 | 1722 | 1730 | ||
2853 | 1723 | This adapter is frequently used in Zope 3 applications, but | 1731 | Cet adaptateur est fréquemment utilisé dans les applications Zope 3, mais |
2854 | 1724 | normally it is called through an API in ``zope.traversing.api``. | 1732 | habituellement il est appelé au travers d'une API dans ``zope.traversing.api``. |
2855 | 1725 | (Some old code even use ``zope.app.zapi`` functions, which is | 1733 | (Certains vieux codes utilisent même les fonctions ``zope.app.zapi`` qui ne sont |
2856 | 1726 | again one more indirection) | 1734 | qu'une indirection supplémentaire). |
2857 | 1727 | 1735 | ||
2859 | 1728 | The registration of adapter is like this:: | 1736 | L'inscription de l'adaptateur ressemble à ceci :: |
2860 | 1729 | 1737 | ||
2861 | 1730 | <adapter | 1738 | <adapter |
2862 | 1731 | factory="zope.location.traversing.LocationPhysicallyLocatable" | 1739 | factory="zope.location.traversing.LocationPhysicallyLocatable" |
2863 | 1732 | /> | 1740 | /> |
2864 | 1733 | 1741 | ||
2869 | 1734 | The interface provided and adaptee interface is given in the | 1742 | L'interface fournie et l'interface adaptée sont données dans l'implémentation, |
2870 | 1735 | implementation. | 1743 | dont voici le début :: |
2867 | 1736 | |||
2868 | 1737 | Here is the beginning of implementation:: | ||
2871 | 1738 | 1744 | ||
2872 | 1739 | class LocationPhysicallyLocatable(object): | 1745 | class LocationPhysicallyLocatable(object): |
2873 | 1740 | """Provide location information for location objects | 1746 | """Provide location information for location objects |
2874 | @@ -1743,43 +1749,41 @@ | |||
2875 | 1743 | zope.interface.implements(IPhysicallyLocatable) | 1749 | zope.interface.implements(IPhysicallyLocatable) |
2876 | 1744 | ... | 1750 | ... |
2877 | 1745 | 1751 | ||
2902 | 1746 | Normally, almost all persistent objects in Zope 3 application | 1752 | Normalement, presque tous les objets persistants d'une application Zope 3 |
2903 | 1747 | will be providing the ``ILocation`` interface. This interface | 1753 | fournissent l'interface ``ILocation``. Cette interface n'a que deux attributs, |
2904 | 1748 | has only two attribute, ``__parent__`` and ``__name__``. The | 1754 | ``__parent__`` et ``__name__``. ``__parent__`` est le parent dans la hiérarchie |
2905 | 1749 | ``__parent__`` is the parent in the location hierarchy. And | 1755 | des objets et ``__name__`` est le nom, vu depuis le parent. |
2906 | 1750 | ``__name__`` is the name within the parent. | 1756 | |
2907 | 1751 | 1757 | L'interface ``IPhysicallyLocatable`` a quatre méthodes: | |
2908 | 1752 | The ``IPhysicallyLocatable`` interface has four methods: | 1758 | ``getRoot``, ``getPath``, ``getName``, et ``getNearestSite``. |
2909 | 1753 | ``getRoot``, ``getPath``, ``getName``, and ``getNearestSite``. | 1759 | |
2910 | 1754 | 1760 | - ``getRoot`` renvoie l'objet racine physique. | |
2911 | 1755 | - ``getRoot`` function will return the physical root object. | 1761 | |
2912 | 1756 | 1762 | - ``getPath`` renvoie une chaîne donnant le chemin physique vers l'objet. | |
2913 | 1757 | - ``getPath`` return the physical path to the object as a | 1763 | |
2914 | 1758 | string. | 1764 | - ``getName`` renvoie le dernier segment du chemin physique. |
2915 | 1759 | 1765 | ||
2916 | 1760 | - ``getName`` return the last segment of the physical path. | 1766 | - ``getNearestSite`` renvoie le site dans lequel l'objet est contenu. Si |
2917 | 1761 | 1767 | l'objet est lui-même un site, il est renvoyé. | |
2918 | 1762 | - ``getNearestSite`` return the site the object is contained | 1768 | |
2919 | 1763 | in. If the object is a site, the object itself is returned. | 1769 | Si vous apprenez Zope 3, ce sont des choses importantes dont vous aurez besoin |
2920 | 1764 | 1770 | très souvent. Pour comprendre la beauté de ce système, vous devriez regarder | |
2921 | 1765 | If you learn Zope 3, you can see that these are the important | 1771 | comment Zope 2 récupère l'objet racine physique et comment ceci est implémenté. |
2922 | 1766 | things which you required very often. To understand the beauty | 1772 | Il existe une méthode ``getPhysicalRoot`` virtuellement pour tous les objets |
2923 | 1767 | of this system, you must see how Zope 2 actually get the physical | 1773 | conteneurs. |
2900 | 1768 | root object and how it is implemented. There is a method called | ||
2901 | 1769 | ``getPhysicalRoot`` virtually for all container objects. | ||
2924 | 1770 | 1774 | ||
2925 | 1771 | 1775 | ||
2926 | 1772 | DefaultSized | 1776 | DefaultSized |
2927 | 1773 | ~~~~~~~~~~~~ | 1777 | ~~~~~~~~~~~~ |
2928 | 1774 | 1778 | ||
2937 | 1775 | Location: ``zope.size.DefaultSized`` | 1779 | Emplacement : ``zope.size.DefaultSized`` |
2938 | 1776 | 1780 | ||
2939 | 1777 | This adapter is just a default implementation of ``ISized`` interface. | 1781 | Cet adaptateur n'est qu'une implémentation par défaut de l'interface ``ISized``. |
2940 | 1778 | This adapter is registered for all kind of objects. If you want to | 1782 | Il est inscrit pour tous les types d'objets. Si vous voulez inscrire cet |
2941 | 1779 | register this adapter for a particular interface, then you have to | 1783 | adaptateur pour une interface particulière, vous devez surcharger cette |
2942 | 1780 | override this registration for your implementation. | 1784 | inscription avec votre implémentation. |
2943 | 1781 | 1785 | ||
2944 | 1782 | The registration of adapter is like this:: | 1786 | L'inscription de l'adaptateur ressemble à ceci :: |
2945 | 1783 | 1787 | ||
2946 | 1784 | <adapter | 1788 | <adapter |
2947 | 1785 | for="*" | 1789 | for="*" |
2948 | @@ -1788,10 +1792,10 @@ | |||
2949 | 1788 | permission="zope.View" | 1792 | permission="zope.View" |
2950 | 1789 | /> | 1793 | /> |
2951 | 1790 | 1794 | ||
2954 | 1791 | As you can see, the adaptee interface is `*`, so it can adapt any kind | 1795 | Comme vous pouvez voir, l'interface adaptée est « * », pour pouvoir s'adapter à |
2955 | 1792 | of objects. | 1796 | tous les types d'objets. |
2956 | 1793 | 1797 | ||
2958 | 1794 | The ``ISized`` is a simple interface with two method contracts:: | 1798 | ``ISized`` est une interface simple possédant deux méthodes :: |
2959 | 1795 | 1799 | ||
2960 | 1796 | class ISized(Interface): | 1800 | class ISized(Interface): |
2961 | 1797 | 1801 | ||
2962 | @@ -1806,112 +1810,793 @@ | |||
2963 | 1806 | """Returns a string giving the size. | 1810 | """Returns a string giving the size. |
2964 | 1807 | """ | 1811 | """ |
2965 | 1808 | 1812 | ||
2968 | 1809 | You can see another ``ISized`` adapter registered for ``IZPTPage`` in | 1813 | Vous pouvez trouver un autre adaptateur ``ISized`` pour ``IZPTPage`` dans le |
2969 | 1810 | ``zope.app.zptpage`` package. | 1814 | paquet ``zope.app.zptpage``. |
2970 | 1811 | 1815 | ||
2971 | 1812 | 1816 | ||
2972 | 1813 | ZopeVersionUtility | 1817 | ZopeVersionUtility |
2973 | 1814 | ~~~~~~~~~~~~~~~~~~ | 1818 | ~~~~~~~~~~~~~~~~~~ |
2974 | 1815 | 1819 | ||
2980 | 1816 | Location: ``zope.app.applicationcontrol.ZopeVersionUtility`` | 1820 | Emplacement : ``zope.app.applicationcontrol.ZopeVersionUtility`` |
2981 | 1817 | 1821 | ||
2982 | 1818 | This utility gives version of the running Zope. | 1822 | Cet utilitaire donne la version de Zope en fonctionnement. |
2983 | 1819 | 1823 | ||
2984 | 1820 | The registration goes like this:: | 1824 | L'inscription est la suivante :: |
2985 | 1821 | 1825 | ||
2986 | 1822 | <utility | 1826 | <utility |
2987 | 1823 | component=".zopeversion.ZopeVersionUtility" | 1827 | component=".zopeversion.ZopeVersionUtility" |
2988 | 1824 | provides=".interfaces.IZopeVersion" /> | 1828 | provides=".interfaces.IZopeVersion" /> |
2989 | 1825 | 1829 | ||
3000 | 1826 | The interface provided, ``IZopeVersion``, has only one method named | 1830 | L'interface fournie, ``IZopeVersion``, n'a qu'une méthode nommée |
3001 | 1827 | ``getZopeVersion``. This method return a string containing the Zope | 1831 | ``getZopeVersion``. Cette méthode renvoie une chaîne contenant la version de |
3002 | 1828 | version (possibly including SVN information). | 1832 | Zope (avec éventuellement un changeset SVN). |
3003 | 1829 | 1833 | ||
3004 | 1830 | The default implementation, ``ZopeVersionUtility``, get version info | 1834 | L'implémentation par défaut, ``ZopeVersionUtility``, récupère le numéro de |
3005 | 1831 | from a file ``version.txt`` in `zope/app` directory. If Zope is | 1835 | version dans un fichier ``version.txt`` du répertoire `zope/app`. Si Zope |
3006 | 1832 | running from subversion checkout, it will show the latest revision | 1836 | fonctionne depuis un espace de travail Subversion, il montre le dernier numéro |
3007 | 1833 | number. If none of the above works it will set it to: | 1837 | de révision. Si aucun des deux ne fonctionne il renvoie `DevCenter/Unknown`. |
3008 | 1834 | `Development/Unknown`. | 1838 | |
3009 | 1835 | 1839 | ||
3010 | 1840 | Étude de cas | ||
3011 | 1841 | ------------ | ||
3012 | 1842 | |||
3013 | 1843 | .. note:: | ||
3014 | 1844 | |||
3015 | 1845 | Ce chapitre n'est pas terminé. Merci d'envoyer vos suggestions ! | ||
3016 | 1846 | |||
3017 | 1847 | Introduction | ||
3018 | 1848 | ~~~~~~~~~~~~ | ||
3019 | 1849 | |||
3020 | 1850 | Ce chapitre est un exemple de création d'une application lourde avec la | ||
3021 | 1851 | bibliothèque d'interface graphique PyGTK et la ZCA. Cette application utilise | ||
3022 | 1852 | également deux types différents de mécanismes de persistance des données : le | ||
3023 | 1853 | premier est une base de données objet (ZODB), l'autre est une base de données | ||
3024 | 1854 | relationnelle (SQLite). Cependant, en pratique, un seul des deux mécanismes peut | ||
3025 | 1855 | être utilisé dans une installation donnée. L'utilisation de deux types de | ||
3026 | 1856 | persistance est là pour démontrer comment utiliser la ZCA pour brancher des | ||
3027 | 1857 | composants entre eux. La majorité de code de cette application est lié à PyGTK. | ||
3028 | 1858 | |||
3029 | 1859 | Lorsque l'application grossit, vous pouvez utiliser les composants de la ZCA aux | ||
3030 | 1860 | endroits où vous souhaitez fournir de la modularité ou de l'extensibilité. | ||
3031 | 1861 | Utilisez des objets Python classiques quand vous n'avez pas besoin de ces | ||
3032 | 1862 | propriétés. | ||
3033 | 1863 | |||
3034 | 1864 | Il n'y a pas de différence entre l'utilisation de la ZCA pour une application | ||
3035 | 1865 | web, pour une application graphique lourde, ou pour toute autre application ou | ||
3036 | 1866 | framework. Il est préférable de suivre une convention pour l'emplacement où vous | ||
3037 | 1867 | allez inscrire les composants. Cette application utilise une convention qui peut | ||
3038 | 1868 | être étendue en plaçant des inscriptions ou des composants similaires dans des | ||
3039 | 1869 | modules séparés et en les important plus tard depuis le module principal | ||
3040 | 1870 | d'inscription. Dans cette application, le module principal pour l'inscription | ||
3041 | 1871 | est `register.py`. | ||
3042 | 1872 | |||
3043 | 1873 | Le code source de cette application peut être téléchargé sur : | ||
3044 | 1874 | http://www.muthukadan.net/downloads/zcalib.tar.bz2 | ||
3045 | 1875 | |||
3046 | 1876 | |||
3047 | 1877 | Cas d'utilisation | ||
3048 | 1878 | ~~~~~~~~~~~~~~~~~ | ||
3049 | 1879 | |||
3050 | 1880 | L'application que nous allons créer ici est un système de gestion de | ||
3051 | 1881 | bibliothèque avec des fonctionnalités minimales. Les besoins peuvent être | ||
3052 | 1882 | résumés comme ceci: | ||
3053 | 1883 | |||
3054 | 1884 | - Ajouter des membres avec un numéro et un nom uniques. | ||
3055 | 1885 | |||
3056 | 1886 | - Ajouter des livres avec un code barre, un auteur et un titre. | ||
3057 | 1887 | |||
3058 | 1888 | - Prêter des livres | ||
3059 | 1889 | |||
3060 | 1890 | - Récupérer des livres | ||
3061 | 1891 | |||
3062 | 1892 | |||
3063 | 1893 | L'application peut être conçue de telle façon que les grandes fonctionnalités | ||
3064 | 1894 | seront utilisées dans une fenêtre unique. La fenêtre principale peut être conçue | ||
3065 | 1895 | de cette façon : | ||
3066 | 1896 | |||
3067 | 1897 | .. image:: mainwindow.png | ||
3068 | 1898 | :align: center | ||
3069 | 1899 | |||
3070 | 1900 | Depuis la fenêtre des membres, l'utilisateur devrait être capable de gérer des | ||
3071 | 1901 | membres. Donc il devrait être possible d'*ajouter*, *modifier* et *effacer* des | ||
3072 | 1902 | membres comme dans l'image ci-dessous : | ||
3073 | 1903 | |||
3074 | 1904 | .. image:: memberwindow.png | ||
3075 | 1905 | :align: center | ||
3076 | 1906 | |||
3077 | 1907 | Similaire à la fenêtre des membres, la fenêtre du catalogue permet aux | ||
3078 | 1908 | utilisateurs d'*ajouter*, *modifier* et *effacer* des livres : | ||
3079 | 1909 | |||
3080 | 1910 | .. image:: catalogwindow.png | ||
3081 | 1911 | :align: center | ||
3082 | 1912 | |||
3083 | 1913 | La fenêtre de circulation doit avoir ce qu'il faut pour prêter et récupérer des | ||
3084 | 1914 | livres : | ||
3085 | 1915 | |||
3086 | 1916 | .. image:: circulationwindow.png | ||
3087 | 1917 | :align: center | ||
3088 | 1918 | |||
3089 | 1919 | |||
3090 | 1920 | Survol du code PyGTK | ||
3091 | 1921 | ~~~~~~~~~~~~~~~~~~~~ | ||
3092 | 1922 | |||
3093 | 1923 | Vous pouvez constater que la majorité du code est en rapport avec PyGTK. | ||
3094 | 1924 | Sa structure est très similaire pour les différentes fenêtres. Les écrans | ||
3095 | 1925 | de cette application sont conçus avec le créateur d'interface graphiques Glade. | ||
3096 | 1926 | Vous devriez donner des noms appropriés aux widgets que vous allez utiliser dans | ||
3097 | 1927 | votre code. Dans la fenêtre principale, tous les éléments de menu ont des noms | ||
3098 | 1928 | du type : circulation, catalog, member, quit et about. | ||
3099 | 1929 | |||
3100 | 1930 | La classe ``gtk.glade.XML`` est utilisée pour analyser le fichier Glade, et donc | ||
3101 | 1931 | pour créer les objets widgets de l'interface graphique. Voici comment faire :: | ||
3102 | 1932 | |||
3103 | 1933 | import gtk.glade | ||
3104 | 1934 | xmlobj = gtk.glade.XML('/path/to/file.glade') | ||
3105 | 1935 | widget = xmlobj.get_widget('widget_name') | ||
3106 | 1936 | |||
3107 | 1937 | Dans mainwindow.py, vous pouvez voir le code suivant :: | ||
3108 | 1938 | |||
3109 | 1939 | curdir = os.path.abspath(os.path.dirname(__file__)) | ||
3110 | 1940 | xml = os.path.join(curdir, 'glade', 'mainwindow.glade') | ||
3111 | 1941 | xmlobj = gtk.glade.XML(xml) | ||
3112 | 1942 | |||
3113 | 1943 | self.mainwindow = xmlobj.get_widget('mainwindow') | ||
3114 | 1944 | |||
3115 | 1945 | Le nom du widget fenêtre principal est `mainwindow`. Les autres widgets sont | ||
3116 | 1946 | créés de la même manière :: | ||
3117 | 1947 | |||
3118 | 1948 | circulation = xmlobj.get_widget('circulation') | ||
3119 | 1949 | member = xmlobj.get_widget('member') | ||
3120 | 1950 | quit = xmlobj.get_widget('quit') | ||
3121 | 1951 | catalog = xmlobj.get_widget('catalog') | ||
3122 | 1952 | about = xmlobj.get_widget('about') | ||
3123 | 1953 | |||
3124 | 1954 | Ensuite ces widgets sont connectés à certains événements :: | ||
3125 | 1955 | |||
3126 | 1956 | self.mainwindow.connect('delete_event', self.delete_event) | ||
3127 | 1957 | quit.connect('activate', self.delete_event) | ||
3128 | 1958 | circulation.connect('activate', self.on_circulation_activate) | ||
3129 | 1959 | member.connect('activate', self.on_member_activate) | ||
3130 | 1960 | catalog.connect('activate', self.on_catalog_activate) | ||
3131 | 1961 | about.connect('activate', self.on_about_activate) | ||
3132 | 1962 | |||
3133 | 1963 | L'événement `delete_event` est celui correspondant à la fermeture de la fenêtre lors | ||
3134 | 1964 | de l'appui sur le bouton de fermeture. L'événement `activate` est émis lorsque | ||
3135 | 1965 | le menu est sélectionné. Les widgets sont connectés à des fonctions de rappel | ||
3136 | 1966 | pour certains événements. | ||
3137 | 1967 | |||
3138 | 1968 | Vous pouvez voir dans le code ci-dessus que la fenêtre principale est connectée | ||
3139 | 1969 | à la méthode `on_delete_event` pour l'événement `delete_event`. Le widget `quit` | ||
3140 | 1970 | est aussi connecté aux mêmes méthodes pour l'événement `activate` :: | ||
3141 | 1971 | |||
3142 | 1972 | def on_delete_event(self, *args): | ||
3143 | 1973 | gtk.main_quit() | ||
3144 | 1974 | |||
3145 | 1975 | La fonction de rappel lance juste la fonction `main_quit`. | ||
3146 | 1976 | |||
3147 | 1977 | |||
3148 | 1978 | Le code | ||
3149 | 1979 | ~~~~~~~ | ||
3150 | 1980 | |||
3151 | 1981 | Voici `zcalib.py` :: | ||
3152 | 1982 | |||
3153 | 1983 | import registry | ||
3154 | 1984 | import mainwindow | ||
3155 | 1985 | |||
3156 | 1986 | if __name__ == '__main__': | ||
3157 | 1987 | registry.initialize() | ||
3158 | 1988 | try: | ||
3159 | 1989 | mainwindow.main() | ||
3160 | 1990 | except KeyboardInterrupt: | ||
3161 | 1991 | import sys | ||
3162 | 1992 | sys.exit(1) | ||
3163 | 1993 | |||
3164 | 1994 | Ici, deux modules sont importés : `registry` et `mainwindow`. | ||
3165 | 1995 | Ensuite le registre est initialisé et la fonction `main` de la fenêtre | ||
3166 | 1996 | principale est appelée. Si l'utilisateur essaye de fermer l'application en | ||
3167 | 1997 | appuyant sur `Ctrl-C`, celle-ci s'arrête normalement car nous avons intercepté | ||
3168 | 1998 | l'exception `KeyboardInterrupt`. | ||
3169 | 1999 | |||
3170 | 2000 | Voici `registry.py` :: | ||
3171 | 2001 | |||
3172 | 2002 | import sys | ||
3173 | 2003 | from zope.component import getGlobalSiteManager | ||
3174 | 2004 | |||
3175 | 2005 | from interfaces import IMember | ||
3176 | 2006 | from interfaces import IBook | ||
3177 | 2007 | from interfaces import ICirculation | ||
3178 | 2008 | from interfaces import IDbOperation | ||
3179 | 2009 | |||
3180 | 2010 | |||
3181 | 2011 | def initialize_rdb(): | ||
3182 | 2012 | from interfaces import IRelationalDatabase | ||
3183 | 2013 | from relationaldatabase import RelationalDatabase | ||
3184 | 2014 | from member import MemberRDbOperation | ||
3185 | 2015 | from catalog import BookRDbOperation | ||
3186 | 2016 | from circulation import CirculationRDbOperation | ||
3187 | 2017 | |||
3188 | 2018 | gsm = getGlobalSiteManager() | ||
3189 | 2019 | db = RelationalDatabase() | ||
3190 | 2020 | gsm.registerUtility(db, IRelationalDatabase) | ||
3191 | 2021 | |||
3192 | 2022 | gsm.registerAdapter(MemberRDbOperation, | ||
3193 | 2023 | (IMember,), | ||
3194 | 2024 | IDbOperation) | ||
3195 | 2025 | |||
3196 | 2026 | gsm.registerAdapter(BookRDbOperation, | ||
3197 | 2027 | (IBook,), | ||
3198 | 2028 | IDbOperation) | ||
3199 | 2029 | |||
3200 | 2030 | gsm.registerAdapter(CirculationRDbOperation, | ||
3201 | 2031 | (ICirculation,), | ||
3202 | 2032 | IDbOperation) | ||
3203 | 2033 | |||
3204 | 2034 | def initialize_odb(): | ||
3205 | 2035 | from interfaces import IObjectDatabase | ||
3206 | 2036 | from objectdatabase import ObjectDatabase | ||
3207 | 2037 | from member import MemberODbOperation | ||
3208 | 2038 | from catalog import BookODbOperation | ||
3209 | 2039 | from circulation import CirculationODbOperation | ||
3210 | 2040 | |||
3211 | 2041 | gsm = getGlobalSiteManager() | ||
3212 | 2042 | db = ObjectDatabase() | ||
3213 | 2043 | gsm.registerUtility(db, IObjectDatabase) | ||
3214 | 2044 | |||
3215 | 2045 | gsm.registerAdapter(MemberODbOperation, | ||
3216 | 2046 | (IMember,), | ||
3217 | 2047 | IDbOperation) | ||
3218 | 2048 | |||
3219 | 2049 | gsm.registerAdapter(BookODbOperation, | ||
3220 | 2050 | (IBook,), | ||
3221 | 2051 | IDbOperation) | ||
3222 | 2052 | |||
3223 | 2053 | gsm.registerAdapter(CirculationODbOperation, | ||
3224 | 2054 | (ICirculation,), | ||
3225 | 2055 | IDbOperation) | ||
3226 | 2056 | |||
3227 | 2057 | def check_use_relational_db(): | ||
3228 | 2058 | use_rdb = False | ||
3229 | 2059 | try: | ||
3230 | 2060 | arg = sys.argv[1] | ||
3231 | 2061 | if arg == '-r': | ||
3232 | 2062 | return True | ||
3233 | 2063 | except IndexError: | ||
3234 | 2064 | pass | ||
3235 | 2065 | return use_rdb | ||
3236 | 2066 | |||
3237 | 2067 | def initialize(): | ||
3238 | 2068 | use_rdb = check_use_relational_db() | ||
3239 | 2069 | if use_rdb: | ||
3240 | 2070 | initialize_rdb() | ||
3241 | 2071 | else: | ||
3242 | 2072 | initialize_odb() | ||
3243 | 2073 | |||
3244 | 2074 | Observez la fonction `initialize` que nous appelons depuis le module principal | ||
3245 | 2075 | `zcalib.py`. Cette fonction commence par vérifier quelle base de données | ||
3246 | 2076 | utiliser : une base relationnelle (RDB) ou une base objet (ODB). Cette | ||
3247 | 2077 | vérification est effectuée dans la fonction `check_use_relational_db`. Si | ||
3248 | 2078 | l'option `-r` est passé dans la ligne de commandes, elle appelera la fonction | ||
3249 | 2079 | `initialize_rdb`, sinon `initialize_odb`. Si la fonction RDB est appelée, elle | ||
3250 | 2080 | configure tous les composants liés à la base relationnelle. Si la fonction ODB est appelée, | ||
3251 | 2081 | elle configure tous les composants liés à la base objet. | ||
3252 | 2082 | |||
3253 | 2083 | Voici `mainwindow.py` :: | ||
3254 | 2084 | |||
3255 | 2085 | import os | ||
3256 | 2086 | import gtk | ||
3257 | 2087 | import gtk.glade | ||
3258 | 2088 | |||
3259 | 2089 | from circulationwindow import circulationwindow | ||
3260 | 2090 | from catalogwindow import catalogwindow | ||
3261 | 2091 | from memberwindow import memberwindow | ||
3262 | 2092 | |||
3263 | 2093 | class MainWindow(object): | ||
3264 | 2094 | |||
3265 | 2095 | def __init__(self): | ||
3266 | 2096 | curdir = os.path.abspath(os.path.dirname(__file__)) | ||
3267 | 2097 | xml = os.path.join(curdir, 'glade', 'mainwindow.glade') | ||
3268 | 2098 | xmlobj = gtk.glade.XML(xml) | ||
3269 | 2099 | |||
3270 | 2100 | self.mainwindow = xmlobj.get_widget('mainwindow') | ||
3271 | 2101 | circulation = xmlobj.get_widget('circulation') | ||
3272 | 2102 | member = xmlobj.get_widget('member') | ||
3273 | 2103 | quit = xmlobj.get_widget('quit') | ||
3274 | 2104 | catalog = xmlobj.get_widget('catalog') | ||
3275 | 2105 | about = xmlobj.get_widget('about') | ||
3276 | 2106 | |||
3277 | 2107 | self.mainwindow.connect('delete_event', self.delete_event) | ||
3278 | 2108 | quit.connect('activate', self.delete_event) | ||
3279 | 2109 | |||
3280 | 2110 | circulation.connect('activate', self.on_circulation_activate) | ||
3281 | 2111 | member.connect('activate', self.on_member_activate) | ||
3282 | 2112 | catalog.connect('activate', self.on_catalog_activate) | ||
3283 | 2113 | about.connect('activate', self.on_about_activate) | ||
3284 | 2114 | |||
3285 | 2115 | def delete_event(self, *args): | ||
3286 | 2116 | gtk.main_quit() | ||
3287 | 2117 | |||
3288 | 2118 | def on_circulation_activate(self, *args): | ||
3289 | 2119 | circulationwindow.show_all() | ||
3290 | 2120 | |||
3291 | 2121 | def on_member_activate(self, *args): | ||
3292 | 2122 | memberwindow.show_all() | ||
3293 | 2123 | |||
3294 | 2124 | def on_catalog_activate(self, *args): | ||
3295 | 2125 | catalogwindow.show_all() | ||
3296 | 2126 | |||
3297 | 2127 | def on_about_activate(self, *args): | ||
3298 | 2128 | pass | ||
3299 | 2129 | |||
3300 | 2130 | def run(self): | ||
3301 | 2131 | self.mainwindow.show_all() | ||
3302 | 2132 | |||
3303 | 2133 | def main(): | ||
3304 | 2134 | mainwindow = MainWindow() | ||
3305 | 2135 | mainwindow.run() | ||
3306 | 2136 | gtk.main() | ||
3307 | 2137 | |||
3308 | 2138 | |||
3309 | 2139 | La fonction `main` crée une instance de la classe `MainWindow` qui initialise | ||
3310 | 2140 | tous les widgets. | ||
3311 | 2141 | |||
3312 | 2142 | Voici `memberwindow.py` :: | ||
3313 | 2143 | |||
3314 | 2144 | import os | ||
3315 | 2145 | import gtk | ||
3316 | 2146 | import gtk.glade | ||
3317 | 2147 | |||
3318 | 2148 | from zope.component import getAdapter | ||
3319 | 2149 | |||
3320 | 2150 | from components import Member | ||
3321 | 2151 | from interfaces import IDbOperation | ||
3322 | 2152 | |||
3323 | 2153 | |||
3324 | 2154 | class MemberWindow(object): | ||
3325 | 2155 | |||
3326 | 2156 | def __init__(self): | ||
3327 | 2157 | curdir = os.path.abspath(os.path.dirname(__file__)) | ||
3328 | 2158 | xml = os.path.join(curdir, 'glade', 'memberwindow.glade') | ||
3329 | 2159 | xmlobj = gtk.glade.XML(xml) | ||
3330 | 2160 | |||
3331 | 2161 | self.memberwindow = xmlobj.get_widget('memberwindow') | ||
3332 | 2162 | self.number = xmlobj.get_widget('number') | ||
3333 | 2163 | self.name = xmlobj.get_widget('name') | ||
3334 | 2164 | add = xmlobj.get_widget('add') | ||
3335 | 2165 | update = xmlobj.get_widget('update') | ||
3336 | 2166 | delete = xmlobj.get_widget('delete') | ||
3337 | 2167 | close = xmlobj.get_widget('close') | ||
3338 | 2168 | self.treeview = xmlobj.get_widget('treeview') | ||
3339 | 2169 | |||
3340 | 2170 | self.memberwindow.connect('delete_event', self.on_delete_event) | ||
3341 | 2171 | add.connect('clicked', self.on_add_clicked) | ||
3342 | 2172 | update.connect('clicked', self.on_update_clicked) | ||
3343 | 2173 | delete.connect('clicked', self.on_delete_clicked) | ||
3344 | 2174 | close.connect('clicked', self.on_delete_event) | ||
3345 | 2175 | |||
3346 | 2176 | self.initialize_list() | ||
3347 | 2177 | |||
3348 | 2178 | def show_all(self): | ||
3349 | 2179 | self.populate_list_store() | ||
3350 | 2180 | self.memberwindow.show_all() | ||
3351 | 2181 | |||
3352 | 2182 | def populate_list_store(self): | ||
3353 | 2183 | self.list_store.clear() | ||
3354 | 2184 | member = Member() | ||
3355 | 2185 | memberdboperation = getAdapter(member, IDbOperation) | ||
3356 | 2186 | members = memberdboperation.get() | ||
3357 | 2187 | for member in members: | ||
3358 | 2188 | number = member.number | ||
3359 | 2189 | name = member.name | ||
3360 | 2190 | self.list_store.append((member, number, name,)) | ||
3361 | 2191 | |||
3362 | 2192 | def on_delete_event(self, *args): | ||
3363 | 2193 | self.memberwindow.hide() | ||
3364 | 2194 | return True | ||
3365 | 2195 | |||
3366 | 2196 | def initialize_list(self): | ||
3367 | 2197 | self.list_store = gtk.ListStore(object, str, str) | ||
3368 | 2198 | self.treeview.set_model(self.list_store) | ||
3369 | 2199 | tvcolumn = gtk.TreeViewColumn('Member Number') | ||
3370 | 2200 | self.treeview.append_column(tvcolumn) | ||
3371 | 2201 | |||
3372 | 2202 | cell = gtk.CellRendererText() | ||
3373 | 2203 | tvcolumn.pack_start(cell, True) | ||
3374 | 2204 | tvcolumn.add_attribute(cell, 'text', 1) | ||
3375 | 2205 | |||
3376 | 2206 | tvcolumn = gtk.TreeViewColumn('Member Name') | ||
3377 | 2207 | self.treeview.append_column(tvcolumn) | ||
3378 | 2208 | |||
3379 | 2209 | cell = gtk.CellRendererText() | ||
3380 | 2210 | tvcolumn.pack_start(cell, True) | ||
3381 | 2211 | tvcolumn.add_attribute(cell, 'text', 2) | ||
3382 | 2212 | |||
3383 | 2213 | def on_add_clicked(self, *args): | ||
3384 | 2214 | number = self.number.get_text() | ||
3385 | 2215 | name = self.name.get_text() | ||
3386 | 2216 | member = Member() | ||
3387 | 2217 | member.number = number | ||
3388 | 2218 | member.name = name | ||
3389 | 2219 | self.add(member) | ||
3390 | 2220 | self.list_store.append((member, number, name,)) | ||
3391 | 2221 | |||
3392 | 2222 | def add(self, member): | ||
3393 | 2223 | memberdboperation = getAdapter(member, IDbOperation) | ||
3394 | 2224 | memberdboperation.add() | ||
3395 | 2225 | |||
3396 | 2226 | def on_update_clicked(self, *args): | ||
3397 | 2227 | number = self.number.get_text() | ||
3398 | 2228 | name = self.name.get_text() | ||
3399 | 2229 | treeselection = self.treeview.get_selection() | ||
3400 | 2230 | model, iter = treeselection.get_selected() | ||
3401 | 2231 | if not iter: | ||
3402 | 2232 | return | ||
3403 | 2233 | member = self.list_store.get_value(iter, 0) | ||
3404 | 2234 | member.number = number | ||
3405 | 2235 | member.name = name | ||
3406 | 2236 | self.update(member) | ||
3407 | 2237 | self.list_store.set(iter, 1, number, 2, name) | ||
3408 | 2238 | |||
3409 | 2239 | def update(self, member): | ||
3410 | 2240 | memberdboperation = getAdapter(member, IDbOperation) | ||
3411 | 2241 | memberdboperation.update() | ||
3412 | 2242 | |||
3413 | 2243 | def on_delete_clicked(self, *args): | ||
3414 | 2244 | treeselection = self.treeview.get_selection() | ||
3415 | 2245 | model, iter = treeselection.get_selected() | ||
3416 | 2246 | if not iter: | ||
3417 | 2247 | return | ||
3418 | 2248 | member = self.list_store.get_value(iter, 0) | ||
3419 | 2249 | self.delete(member) | ||
3420 | 2250 | self.list_store.remove(iter) | ||
3421 | 2251 | |||
3422 | 2252 | def delete(self, member): | ||
3423 | 2253 | memberdboperation = getAdapter(member, IDbOperation) | ||
3424 | 2254 | memberdboperation.delete() | ||
3425 | 2255 | |||
3426 | 2256 | memberwindow = MemberWindow() | ||
3427 | 2257 | |||
3428 | 2258 | Voici `components.py` :: | ||
3429 | 2259 | |||
3430 | 2260 | from zope.interface import implements | ||
3431 | 2261 | |||
3432 | 2262 | from interfaces import IBook | ||
3433 | 2263 | from interfaces import IMember | ||
3434 | 2264 | from interfaces import ICirculation | ||
3435 | 2265 | |||
3436 | 2266 | class Book(object): | ||
3437 | 2267 | |||
3438 | 2268 | implements(IBook) | ||
3439 | 2269 | |||
3440 | 2270 | barcode = "" | ||
3441 | 2271 | title = "" | ||
3442 | 2272 | author = "" | ||
3443 | 2273 | |||
3444 | 2274 | class Member(object): | ||
3445 | 2275 | |||
3446 | 2276 | implements(IMember) | ||
3447 | 2277 | |||
3448 | 2278 | number = "" | ||
3449 | 2279 | name = "" | ||
3450 | 2280 | |||
3451 | 2281 | class Circulation(object): | ||
3452 | 2282 | |||
3453 | 2283 | implements(ICirculation) | ||
3454 | 2284 | |||
3455 | 2285 | book = Book() | ||
3456 | 2286 | member = Member() | ||
3457 | 2287 | |||
3458 | 2288 | Voici `interfaces.py` :: | ||
3459 | 2289 | |||
3460 | 2290 | from zope.interface import Interface | ||
3461 | 2291 | from zope.interface import Attribute | ||
3462 | 2292 | |||
3463 | 2293 | |||
3464 | 2294 | class IBook(Interface): | ||
3465 | 2295 | |||
3466 | 2296 | barcode = Attribute("Barcode") | ||
3467 | 2297 | author = Attribute("Author of book") | ||
3468 | 2298 | title = Attribute("Title of book") | ||
3469 | 2299 | |||
3470 | 2300 | |||
3471 | 2301 | class IMember(Interface): | ||
3472 | 2302 | |||
3473 | 2303 | number = Attribute("ID number") | ||
3474 | 2304 | name = Attribute("Name of member") | ||
3475 | 2305 | |||
3476 | 2306 | |||
3477 | 2307 | class ICirculation(Interface): | ||
3478 | 2308 | |||
3479 | 2309 | book = Attribute("A book") | ||
3480 | 2310 | member = Attribute("A member") | ||
3481 | 2311 | |||
3482 | 2312 | |||
3483 | 2313 | class IRelationalDatabase(Interface): | ||
3484 | 2314 | |||
3485 | 2315 | def commit(): | ||
3486 | 2316 | pass | ||
3487 | 2317 | |||
3488 | 2318 | def rollback(): | ||
3489 | 2319 | pass | ||
3490 | 2320 | |||
3491 | 2321 | def cursor(): | ||
3492 | 2322 | pass | ||
3493 | 2323 | |||
3494 | 2324 | def get_next_id(): | ||
3495 | 2325 | pass | ||
3496 | 2326 | |||
3497 | 2327 | |||
3498 | 2328 | class IObjectDatabase(Interface): | ||
3499 | 2329 | |||
3500 | 2330 | def commit(): | ||
3501 | 2331 | pass | ||
3502 | 2332 | |||
3503 | 2333 | def rollback(): | ||
3504 | 2334 | pass | ||
3505 | 2335 | |||
3506 | 2336 | def container(): | ||
3507 | 2337 | pass | ||
3508 | 2338 | |||
3509 | 2339 | def get_next_id(): | ||
3510 | 2340 | pass | ||
3511 | 2341 | |||
3512 | 2342 | |||
3513 | 2343 | class IDbOperation(Interface): | ||
3514 | 2344 | |||
3515 | 2345 | def get(): | ||
3516 | 2346 | pass | ||
3517 | 2347 | |||
3518 | 2348 | def add(): | ||
3519 | 2349 | pass | ||
3520 | 2350 | |||
3521 | 2351 | def update(): | ||
3522 | 2352 | pass | ||
3523 | 2353 | |||
3524 | 2354 | def delete(): | ||
3525 | 2355 | pass | ||
3526 | 2356 | |||
3527 | 2357 | Here is the `member.py` :: | ||
3528 | 2358 | |||
3529 | 2359 | from zope.interface import implements | ||
3530 | 2360 | from zope.component import getUtility | ||
3531 | 2361 | from zope.component import adapts | ||
3532 | 2362 | |||
3533 | 2363 | from components import Member | ||
3534 | 2364 | |||
3535 | 2365 | from interfaces import IRelationalDatabase | ||
3536 | 2366 | from interfaces import IObjectDatabase | ||
3537 | 2367 | from interfaces import IMember | ||
3538 | 2368 | from interfaces import IDbOperation | ||
3539 | 2369 | |||
3540 | 2370 | |||
3541 | 2371 | class MemberRDbOperation(object): | ||
3542 | 2372 | |||
3543 | 2373 | implements(IDbOperation) | ||
3544 | 2374 | adapts(IMember) | ||
3545 | 2375 | |||
3546 | 2376 | def __init__(self, member): | ||
3547 | 2377 | self.member = member | ||
3548 | 2378 | |||
3549 | 2379 | def get(self): | ||
3550 | 2380 | db = getUtility(IRelationalDatabase) | ||
3551 | 2381 | cr = db.cursor() | ||
3552 | 2382 | number = self.member.number | ||
3553 | 2383 | if number: | ||
3554 | 2384 | cr.execute("""SELECT | ||
3555 | 2385 | id, | ||
3556 | 2386 | number, | ||
3557 | 2387 | name | ||
3558 | 2388 | FROM members | ||
3559 | 2389 | WHERE number = ?""", | ||
3560 | 2390 | (number,)) | ||
3561 | 2391 | else: | ||
3562 | 2392 | cr.execute("""SELECT | ||
3563 | 2393 | id, | ||
3564 | 2394 | number, | ||
3565 | 2395 | name | ||
3566 | 2396 | FROM members""") | ||
3567 | 2397 | rst = cr.fetchall() | ||
3568 | 2398 | cr.close() | ||
3569 | 2399 | members = [] | ||
3570 | 2400 | for record in rst: | ||
3571 | 2401 | id = record['id'] | ||
3572 | 2402 | number = record['number'] | ||
3573 | 2403 | name = record['name'] | ||
3574 | 2404 | member = Member() | ||
3575 | 2405 | member.id = id | ||
3576 | 2406 | member.number = number | ||
3577 | 2407 | member.name = name | ||
3578 | 2408 | members.append(member) | ||
3579 | 2409 | return members | ||
3580 | 2410 | |||
3581 | 2411 | def add(self): | ||
3582 | 2412 | db = getUtility(IRelationalDatabase) | ||
3583 | 2413 | cr = db.cursor() | ||
3584 | 2414 | next_id = db.get_next_id("members") | ||
3585 | 2415 | number = self.member.number | ||
3586 | 2416 | name = self.member.name | ||
3587 | 2417 | cr.execute("""INSERT INTO members | ||
3588 | 2418 | (id, number, name) | ||
3589 | 2419 | VALUES (?, ?, ?)""", | ||
3590 | 2420 | (next_id, number, name)) | ||
3591 | 2421 | cr.close() | ||
3592 | 2422 | db.commit() | ||
3593 | 2423 | self.member.id = next_id | ||
3594 | 2424 | |||
3595 | 2425 | def update(self): | ||
3596 | 2426 | db = getUtility(IRelationalDatabase) | ||
3597 | 2427 | cr = db.cursor() | ||
3598 | 2428 | number = self.member.number | ||
3599 | 2429 | name = self.member.name | ||
3600 | 2430 | id = self.member.id | ||
3601 | 2431 | cr.execute("""UPDATE members | ||
3602 | 2432 | SET | ||
3603 | 2433 | number = ?, | ||
3604 | 2434 | name = ? | ||
3605 | 2435 | WHERE id = ?""", | ||
3606 | 2436 | (number, name, id)) | ||
3607 | 2437 | cr.close() | ||
3608 | 2438 | db.commit() | ||
3609 | 2439 | |||
3610 | 2440 | def delete(self): | ||
3611 | 2441 | db = getUtility(IRelationalDatabase) | ||
3612 | 2442 | cr = db.cursor() | ||
3613 | 2443 | id = self.member.id | ||
3614 | 2444 | cr.execute("""DELETE FROM members | ||
3615 | 2445 | WHERE id = ?""", | ||
3616 | 2446 | (id,)) | ||
3617 | 2447 | cr.close() | ||
3618 | 2448 | db.commit() | ||
3619 | 2449 | |||
3620 | 2450 | |||
3621 | 2451 | class MemberODbOperation(object): | ||
3622 | 2452 | |||
3623 | 2453 | implements(IDbOperation) | ||
3624 | 2454 | adapts(IMember) | ||
3625 | 2455 | |||
3626 | 2456 | def __init__(self, member): | ||
3627 | 2457 | self.member = member | ||
3628 | 2458 | |||
3629 | 2459 | def get(self): | ||
3630 | 2460 | db = getUtility(IObjectDatabase) | ||
3631 | 2461 | zcalibdb = db.container() | ||
3632 | 2462 | members = zcalibdb['members'] | ||
3633 | 2463 | return members.values() | ||
3634 | 2464 | |||
3635 | 2465 | def add(self): | ||
3636 | 2466 | db = getUtility(IObjectDatabase) | ||
3637 | 2467 | zcalibdb = db.container() | ||
3638 | 2468 | members = zcalibdb['members'] | ||
3639 | 2469 | number = self.member.number | ||
3640 | 2470 | if number in [x.number for x in members.values()]: | ||
3641 | 2471 | db.rollback() | ||
3642 | 2472 | raise Exception("Duplicate key") | ||
3643 | 2473 | next_id = db.get_next_id('members') | ||
3644 | 2474 | self.member.id = next_id | ||
3645 | 2475 | members[next_id] = self.member | ||
3646 | 2476 | db.commit() | ||
3647 | 2477 | |||
3648 | 2478 | def update(self): | ||
3649 | 2479 | db = getUtility(IObjectDatabase) | ||
3650 | 2480 | zcalibdb = db.container() | ||
3651 | 2481 | members = zcalibdb['members'] | ||
3652 | 2482 | id = self.member.id | ||
3653 | 2483 | members[id] = self.member | ||
3654 | 2484 | db.commit() | ||
3655 | 2485 | |||
3656 | 2486 | def delete(self): | ||
3657 | 2487 | db = getUtility(IObjectDatabase) | ||
3658 | 2488 | zcalibdb = db.container() | ||
3659 | 2489 | members = zcalibdb['members'] | ||
3660 | 2490 | id = self.member.id | ||
3661 | 2491 | del members[id] | ||
3662 | 2492 | db.commit() | ||
3663 | 2493 | |||
3664 | 2494 | |||
3665 | 2495 | PySQLite | ||
3666 | 2496 | ~~~~~~~~ | ||
3667 | 2497 | |||
3668 | 2498 | ZODB | ||
3669 | 2499 | ~~~~ | ||
3670 | 2500 | |||
3671 | 2501 | Conclusions | ||
3672 | 2502 | ~~~~~~~~~~~ | ||
3673 | 1836 | 2503 | ||
3674 | 1837 | Reference | 2504 | Reference |
3675 | 1838 | --------- | 2505 | --------- |
3676 | 1839 | 2506 | ||
3677 | 1840 | 2507 | ||
3733 | 1841 | Attribute | 2508 | adaptedBy |
3734 | 1842 | ~~~~~~~~~ | 2509 | ~~~~~~~~~ |
3735 | 1843 | 2510 | ||
3736 | 1844 | Using this class, you can define normal attribute in an interface. | 2511 | Cette fonction permet de trouver les interfaces adaptées. |
3737 | 1845 | 2512 | ||
3738 | 1846 | - Location: ``zope.interface`` | 2513 | - Emplacement : ``zope.component`` |
3739 | 1847 | 2514 | ||
3740 | 1848 | - Signature: `Attribute(name, doc='')` | 2515 | - Signature : `adaptedBy(object)` |
3741 | 1849 | 2516 | ||
3742 | 1850 | Example:: | 2517 | Exemple :: |
3743 | 1851 | 2518 | ||
3744 | 1852 | >>> from zope.interface import Attribute | 2519 | >>> from zope.interface import implements |
3745 | 1853 | >>> from zope.interface import Interface | 2520 | >>> from zope.component import adapts |
3746 | 1854 | 2521 | >>> from zope.component import adaptedBy | |
3747 | 1855 | >>> class IPerson(Interface): | 2522 | |
3748 | 1856 | ... | 2523 | >>> class FrontDeskNG(object): |
3749 | 1857 | ... name = Attribute("Name of person") | 2524 | ... |
3750 | 1858 | ... email = Attribute("Email Address") | 2525 | ... implements(IDesk) |
3751 | 1859 | 2526 | ... adapts(IGuest) | |
3752 | 1860 | 2527 | ... | |
3753 | 1861 | Declaration | 2528 | ... def __init__(self, guest): |
3754 | 1862 | ~~~~~~~~~~~ | 2529 | ... self.guest = guest |
3755 | 1863 | 2530 | ||
3756 | 1864 | Need not to use directly. | 2531 | >>> adaptedBy(FrontDeskNG) |
3757 | 1865 | 2532 | (<InterfaceClass __builtin__.IGuest>,) | |
3758 | 1866 | 2533 | ||
3759 | 1867 | Interface | 2534 | |
3760 | 1868 | ~~~~~~~~~ | 2535 | adapter |
3761 | 1869 | 2536 | ~~~~~~~ | |
3762 | 1870 | Using this class, you can define an interface. To define an | 2537 | |
3763 | 1871 | interface, just inherit from ``Interface`` class. | 2538 | Un adaptateur peut être n'importe quel objet appelable. Vous pouvez |
3764 | 1872 | 2539 | utiliser le décorateur `adapter` pour déclarer qu'un objet appelable s'adapte à | |
3765 | 1873 | - Location: ``zope.interface`` | 2540 | des interfaces (ou des classes). |
3766 | 1874 | 2541 | ||
3767 | 1875 | - Signature: `Interface(name, doc='')` | 2542 | - Emplacement : ``zope.component`` |
3768 | 1876 | 2543 | ||
3769 | 1877 | Example 1:: | 2544 | - Signature : `adapter(*interfaces)` |
3770 | 1878 | 2545 | ||
3771 | 1879 | >>> from zope.interface import Attribute | 2546 | Exemple :: |
3772 | 1880 | >>> from zope.interface import Interface | 2547 | |
3773 | 1881 | 2548 | >>> from zope.interface import Attribute | |
3774 | 1882 | >>> class IPerson(Interface): | 2549 | >>> from zope.interface import Interface |
3775 | 1883 | ... | 2550 | >>> from zope.interface import implementer |
3776 | 1884 | ... name = Attribute("Name of person") | 2551 | >>> from zope.component import adapter |
3777 | 1885 | ... email = Attribute("Email Address") | 2552 | >>> from zope.interface import implements |
3778 | 1886 | 2553 | ||
3779 | 1887 | 2554 | >>> class IJob(Interface): | |
3780 | 1888 | Example 2:: | 2555 | ... """A job""" |
3781 | 1889 | 2556 | ||
3782 | 1890 | >>> from zope.interface import Interface | 2557 | >>> class Job(object): |
3783 | 1891 | 2558 | ... implements(IJob) | |
3784 | 1892 | >>> class IHost(Interface): | 2559 | |
3785 | 1893 | ... | 2560 | >>> class IPerson(Interface): |
3786 | 1894 | ... def goodmorning(guest): | 2561 | ... |
3787 | 1895 | ... """Say good morning to guest""" | 2562 | ... name = Attribute("Name") |
3788 | 2563 | ... job = Attribute("Job") | ||
3789 | 2564 | |||
3790 | 2565 | >>> class Person(object): | ||
3791 | 2566 | ... implements(IPerson) | ||
3792 | 2567 | ... | ||
3793 | 2568 | ... name = None | ||
3794 | 2569 | ... job = None | ||
3795 | 2570 | |||
3796 | 2571 | >>> @implementer(IJob) | ||
3797 | 2572 | ... @adapter(IPerson) | ||
3798 | 2573 | ... def personJob(person): | ||
3799 | 2574 | ... return person.job | ||
3800 | 2575 | |||
3801 | 2576 | >>> jack = Person() | ||
3802 | 2577 | >>> jack.name = "Jack" | ||
3803 | 2578 | >>> jack.job = Job() | ||
3804 | 2579 | >>> personJob(jack) #doctest: +ELLIPSIS | ||
3805 | 2580 | <Job object at ...> | ||
3806 | 1896 | 2581 | ||
3807 | 1897 | 2582 | ||
3808 | 1898 | adapts | 2583 | adapts |
3809 | 1899 | ~~~~~~ | 2584 | ~~~~~~ |
3810 | 1900 | 2585 | ||
3818 | 1901 | This function helps to declare adapter classes. | 2586 | Cette fonction permet de déclarer les classes adaptateurs. |
3819 | 1902 | 2587 | ||
3820 | 1903 | - Location: ``zope.component`` | 2588 | - Emplacement : ``zope.component`` |
3821 | 1904 | 2589 | ||
3822 | 1905 | - Signature: `adapts(*interfaces)` | 2590 | - Signature : `adapts(*interfaces)` |
3823 | 1906 | 2591 | ||
3824 | 1907 | Example:: | 2592 | Exemple :: |
3825 | 1908 | 2593 | ||
3826 | 1909 | >>> from zope.interface import implements | 2594 | >>> from zope.interface import implements |
3827 | 1910 | >>> from zope.component import adapts | 2595 | >>> from zope.component import adapts |
3828 | 1911 | 2596 | ||
3830 | 1912 | >>> class GuestRegistrarNG(object): | 2597 | >>> class FrontDeskNG(object): |
3831 | 1913 | ... | 2598 | ... |
3833 | 1914 | ... implements(IRegistrar) | 2599 | ... implements(IDesk) |
3834 | 1915 | ... adapts(IGuest) | 2600 | ... adapts(IGuest) |
3835 | 1916 | ... | 2601 | ... |
3836 | 1917 | ... def __init__(self, guest): | 2602 | ... def __init__(self, guest): |
3837 | @@ -1919,7 +2604,7 @@ | |||
3838 | 1919 | ... | 2604 | ... |
3839 | 1920 | ... def register(self): | 2605 | ... def register(self): |
3840 | 1921 | ... next_id = get_next_id() | 2606 | ... next_id = get_next_id() |
3842 | 1922 | ... guests_db[next_id] = { | 2607 | ... bookings_db[next_id] = { |
3843 | 1923 | ... 'name': guest.name, | 2608 | ... 'name': guest.name, |
3844 | 1924 | ... 'place': guest.place, | 2609 | ... 'place': guest.place, |
3845 | 1925 | ... 'phone': guest.phone | 2610 | ... 'phone': guest.phone |
3846 | @@ -1929,15 +2614,15 @@ | |||
3847 | 1929 | alsoProvides | 2614 | alsoProvides |
3848 | 1930 | ~~~~~~~~~~~~ | 2615 | ~~~~~~~~~~~~ |
3849 | 1931 | 2616 | ||
3859 | 1932 | Declare interfaces declared directly for an object. The arguments | 2617 | Déclare des interfaces additionnelles fournies par un objet. Les arguments après |
3860 | 1933 | after the object are one or more interfaces. The interfaces given are | 2618 | l'objet sont une ou plusieurs interfaces. Les interfaces données sont ajoutées |
3861 | 1934 | added to the interfaces previously declared for the object. | 2619 | aux interfaces précédemment déclarées pour l'objet. |
3862 | 1935 | 2620 | ||
3863 | 1936 | - Location: ``zope.interface`` | 2621 | - Emplacement : ``zope.interface`` |
3864 | 1937 | 2622 | ||
3865 | 1938 | - Signature: `alsoProvides(object, *interfaces)` | 2623 | - Signature : `alsoProvides(object, *interfaces)` |
3866 | 1939 | 2624 | ||
3867 | 1940 | Example:: | 2625 | Exemple :: |
3868 | 1941 | 2626 | ||
3869 | 1942 | >>> from zope.interface import Attribute | 2627 | >>> from zope.interface import Attribute |
3870 | 1943 | >>> from zope.interface import Interface | 2628 | >>> from zope.interface import Interface |
3871 | @@ -1954,7 +2639,7 @@ | |||
3872 | 1954 | 2639 | ||
3873 | 1955 | >>> class Person(object): | 2640 | >>> class Person(object): |
3874 | 1956 | ... | 2641 | ... |
3876 | 1957 | ... implements(IRegistrar) | 2642 | ... implements(IDesk) |
3877 | 1958 | ... name = u"" | 2643 | ... name = u"" |
3878 | 1959 | 2644 | ||
3879 | 1960 | >>> jack = Person() | 2645 | >>> jack = Person() |
3880 | @@ -1962,25 +2647,48 @@ | |||
3881 | 1962 | >>> jack.college = "New College" | 2647 | >>> jack.college = "New College" |
3882 | 1963 | >>> alsoProvides(jack, IStudent) | 2648 | >>> alsoProvides(jack, IStudent) |
3883 | 1964 | 2649 | ||
3885 | 1965 | You can test it like this: | 2650 | Vous pouvez tester de cette façon: |
3886 | 1966 | 2651 | ||
3887 | 1967 | >>> from zope.interface import providedBy | 2652 | >>> from zope.interface import providedBy |
3888 | 1968 | >>> IStudent in providedBy(jack) | 2653 | >>> IStudent in providedBy(jack) |
3889 | 1969 | True | 2654 | True |
3890 | 1970 | 2655 | ||
3891 | 1971 | 2656 | ||
3892 | 2657 | Attribute | ||
3893 | 2658 | ~~~~~~~~~ | ||
3894 | 2659 | |||
3895 | 2660 | En utilisant cette classe, vous pouvez définir des attributs dans une interface. | ||
3896 | 2661 | |||
3897 | 2662 | - Emplacement : ``zope.interface`` | ||
3898 | 2663 | |||
3899 | 2664 | - Signature : `Attribute(name, doc='')` | ||
3900 | 2665 | |||
3901 | 2666 | - Voir aussi : `Interface`_ | ||
3902 | 2667 | |||
3903 | 2668 | Exemple :: | ||
3904 | 2669 | |||
3905 | 2670 | >>> from zope.interface import Attribute | ||
3906 | 2671 | >>> from zope.interface import Interface | ||
3907 | 2672 | |||
3908 | 2673 | >>> class IPerson(Interface): | ||
3909 | 2674 | ... | ||
3910 | 2675 | ... name = Attribute("Name of person") | ||
3911 | 2676 | ... email = Attribute("Email Address") | ||
3912 | 2677 | |||
3913 | 2678 | |||
3914 | 1972 | classImplements | 2679 | classImplements |
3915 | 1973 | ~~~~~~~~~~~~~~~ | 2680 | ~~~~~~~~~~~~~~~ |
3916 | 1974 | 2681 | ||
3926 | 1975 | Declare additional interfaces implemented for instances of a class. | 2682 | Déclare des interfaces additionnelles qui doivent être fournies par les |
3927 | 1976 | The arguments after the class are one or more interfaces. The | 2683 | instances d'une classe. Les arguments après la classe sont une ou plusieurs |
3928 | 1977 | interfaces given are added to any interfaces previously declared. | 2684 | interfaces. Les interfaces données sont ajoutées aux interfaces précédemment |
3929 | 1978 | 2685 | déclarées. | |
3930 | 1979 | - Location: ``zope.interface`` | 2686 | |
3931 | 1980 | 2687 | - Emplacement : ``zope.interface`` | |
3932 | 1981 | - Signature: `classImplements(cls, *interfaces)` | 2688 | |
3933 | 1982 | 2689 | - Signature : `classImplements(cls, *interfaces)` | |
3934 | 1983 | Example:: | 2690 | |
3935 | 2691 | Exemple :: | ||
3936 | 1984 | 2692 | ||
3937 | 1985 | >>> from zope.interface import Attribute | 2693 | >>> from zope.interface import Attribute |
3938 | 1986 | >>> from zope.interface import Interface | 2694 | >>> from zope.interface import Interface |
3939 | @@ -1997,7 +2705,7 @@ | |||
3940 | 1997 | 2705 | ||
3941 | 1998 | >>> class Person(object): | 2706 | >>> class Person(object): |
3942 | 1999 | ... | 2707 | ... |
3944 | 2000 | ... implements(IRegistrar) | 2708 | ... implements(IDesk) |
3945 | 2001 | ... name = u"" | 2709 | ... name = u"" |
3946 | 2002 | ... college = u"" | 2710 | ... college = u"" |
3947 | 2003 | 2711 | ||
3948 | @@ -2006,7 +2714,7 @@ | |||
3949 | 2006 | >>> jack.name = "Jack" | 2714 | >>> jack.name = "Jack" |
3950 | 2007 | >>> jack.college = "New College" | 2715 | >>> jack.college = "New College" |
3951 | 2008 | 2716 | ||
3953 | 2009 | You can test it like this: | 2717 | Vous pouvez tester de cette façon : |
3954 | 2010 | 2718 | ||
3955 | 2011 | >>> from zope.interface import providedBy | 2719 | >>> from zope.interface import providedBy |
3956 | 2012 | >>> IStudent in providedBy(jack) | 2720 | >>> IStudent in providedBy(jack) |
3957 | @@ -2016,15 +2724,16 @@ | |||
3958 | 2016 | classImplementsOnly | 2724 | classImplementsOnly |
3959 | 2017 | ~~~~~~~~~~~~~~~~~~~ | 2725 | ~~~~~~~~~~~~~~~~~~~ |
3960 | 2018 | 2726 | ||
3970 | 2019 | Declare the only interfaces implemented by instances of a class. The | 2727 | Déclare les seules interfaces qui devront être fournies par les instances d'une |
3971 | 2020 | arguments after the class are one or more interfaces. The interfaces | 2728 | classe. Les arguments après la classe sont une ou plusieurs interfaces. Les |
3972 | 2021 | given replace any previous declarations. | 2729 | interfaces fournies vont remplacer toutes les interfaces des déclarations |
3973 | 2022 | 2730 | précédentes. | |
3974 | 2023 | - Location: ``zope.interface`` | 2731 | |
3975 | 2024 | 2732 | - Emplacement : ``zope.interface`` | |
3976 | 2025 | - Signature: `classImplementsOnly(cls, *interfaces)` | 2733 | |
3977 | 2026 | 2734 | - Signature : `classImplementsOnly(cls, *interfaces)` | |
3978 | 2027 | Example:: | 2735 | |
3979 | 2736 | Exemple :: | ||
3980 | 2028 | 2737 | ||
3981 | 2029 | >>> from zope.interface import Attribute | 2738 | >>> from zope.interface import Attribute |
3982 | 2030 | >>> from zope.interface import Interface | 2739 | >>> from zope.interface import Interface |
3983 | @@ -2048,7 +2757,7 @@ | |||
3984 | 2048 | >>> jack = Person() | 2757 | >>> jack = Person() |
3985 | 2049 | >>> jack.college = "New College" | 2758 | >>> jack.college = "New College" |
3986 | 2050 | 2759 | ||
3988 | 2051 | You can test it like this: | 2760 | Vous pouvez tester de cette façon : |
3989 | 2052 | 2761 | ||
3990 | 2053 | >>> from zope.interface import providedBy | 2762 | >>> from zope.interface import providedBy |
3991 | 2054 | >>> IPerson in providedBy(jack) | 2763 | >>> IPerson in providedBy(jack) |
3992 | @@ -2060,16 +2769,16 @@ | |||
3993 | 2060 | classProvides | 2769 | classProvides |
3994 | 2061 | ~~~~~~~~~~~~~ | 2770 | ~~~~~~~~~~~~~ |
3995 | 2062 | 2771 | ||
4006 | 2063 | Normally if a class implements a particular interface, the instance of | 2772 | Normalement si une classe implémente une interface particulière, les instances |
4007 | 2064 | that class will provide the interface implemented by that class. But | 2773 | de cette classe fourniront l'interface implémentée par la classe. Mais si vous |
4008 | 2065 | if you want a class to be provided by an interface, you can declare it | 2774 | voulez qu'une classe fournisse une interface, vous pouvez le déclarer grâce à la |
4009 | 2066 | using ``classProvides`` function. | 2775 | fonction ``classProvides``. |
4010 | 2067 | 2776 | ||
4011 | 2068 | - Location: ``zope.interface`` | 2777 | - Emplacement : ``zope.interface`` |
4012 | 2069 | 2778 | ||
4013 | 2070 | - Signature: `classProvides(*interfaces)` | 2779 | - Signature : `classProvides(*interfaces)` |
4014 | 2071 | 2780 | ||
4015 | 2072 | Example:: | 2781 | Exemple :: |
4016 | 2073 | 2782 | ||
4017 | 2074 | >>> from zope.interface import Attribute | 2783 | >>> from zope.interface import Attribute |
4018 | 2075 | >>> from zope.interface import Interface | 2784 | >>> from zope.interface import Interface |
4019 | @@ -2084,7 +2793,7 @@ | |||
4020 | 2084 | ... classProvides(IPerson) | 2793 | ... classProvides(IPerson) |
4021 | 2085 | ... name = u"Jack" | 2794 | ... name = u"Jack" |
4022 | 2086 | 2795 | ||
4024 | 2087 | You can test it like this: | 2796 | Vous pouvez tester de cette façon : |
4025 | 2088 | 2797 | ||
4026 | 2089 | >>> from zope.interface import providedBy | 2798 | >>> from zope.interface import providedBy |
4027 | 2090 | >>> IPerson in providedBy(Person) | 2799 | >>> IPerson in providedBy(Person) |
4028 | @@ -2094,26 +2803,39 @@ | |||
4029 | 2094 | ComponentLookupError | 2803 | ComponentLookupError |
4030 | 2095 | ~~~~~~~~~~~~~~~~~~~~ | 2804 | ~~~~~~~~~~~~~~~~~~~~ |
4031 | 2096 | 2805 | ||
4032 | 2806 | C'est l'exception levée quand une recherche de composant échoue. | ||
4033 | 2807 | |||
4034 | 2808 | Exemple :: | ||
4035 | 2809 | |||
4036 | 2810 | >>> class IPerson(Interface): | ||
4037 | 2811 | ... | ||
4038 | 2812 | ... name = Attribute("Name of person") | ||
4039 | 2813 | |||
4040 | 2814 | >>> person = object() | ||
4041 | 2815 | >>> getAdapter(person, IPerson, 'not-exists') #doctest: +ELLIPSIS | ||
4042 | 2816 | Traceback (most recent call last): | ||
4043 | 2817 | ... | ||
4044 | 2818 | ComponentLookupError: ... | ||
4045 | 2819 | |||
4046 | 2097 | 2820 | ||
4047 | 2098 | createObject | 2821 | createObject |
4048 | 2099 | ~~~~~~~~~~~~ | 2822 | ~~~~~~~~~~~~ |
4049 | 2100 | 2823 | ||
4066 | 2101 | Create an object using a factory. | 2824 | Crée un objet en utilisant une fabrique. |
4067 | 2102 | 2825 | ||
4068 | 2103 | Finds the named factory in the current site and calls it with the | 2826 | Cette fonction trouve une fabrique nommée dans le site courant et l'appelle avec |
4069 | 2104 | given arguments. If a matching factory cannot be found raises | 2827 | les arguments donnés. Si la bonne fabrique ne peut pas être trouvée, une erreur |
4070 | 2105 | ComponentLookupError. Returns the created object. | 2828 | ``ComponentLookupError`` est déclenchée. Sinon l'objet créé est renvoyé. |
4071 | 2106 | 2829 | ||
4072 | 2107 | A context keyword argument can be provided to cause the factory to be | 2830 | Un argument mot-clé contextuel peut être fourni pour rechercher une fabrique |
4073 | 2108 | looked up in a location other than the current site. (Of course, this | 2831 | dans un emplacement différent du site courant. (Bien sûr, cela signifie qu'il |
4074 | 2109 | means that it is impossible to pass a keyword argument named "context" | 2832 | est impossible de transmettre à la fabrique un argument mot-clé nommé « context ». |
4075 | 2110 | to the factory. | 2833 | |
4076 | 2111 | 2834 | - Emplacement : ``zope.component`` | |
4077 | 2112 | - Location: ``zope.component`` | 2835 | |
4078 | 2113 | 2836 | - Signature : `createObject(factory_name, *args, **kwargs)` | |
4079 | 2114 | - Signature: `createObject(factory_name, *args, **kwargs)` | 2837 | |
4080 | 2115 | 2838 | Exemple :: | |
4065 | 2116 | Example:: | ||
4081 | 2117 | 2839 | ||
4082 | 2118 | >>> from zope.interface import Attribute | 2840 | >>> from zope.interface import Attribute |
4083 | 2119 | >>> from zope.interface import Interface | 2841 | >>> from zope.interface import Interface |
4084 | @@ -2146,17 +2868,22 @@ | |||
4085 | 2146 | <FakeDb object at ...> | 2868 | <FakeDb object at ...> |
4086 | 2147 | 2869 | ||
4087 | 2148 | 2870 | ||
4088 | 2871 | Declaration | ||
4089 | 2872 | ~~~~~~~~~~~ | ||
4090 | 2873 | |||
4091 | 2874 | N'a pas besoin d'être utilisé directement. | ||
4092 | 2875 | |||
4093 | 2876 | |||
4094 | 2149 | directlyProvidedBy | 2877 | directlyProvidedBy |
4095 | 2150 | ~~~~~~~~~~~~~~~~~~ | 2878 | ~~~~~~~~~~~~~~~~~~ |
4096 | 2151 | 2879 | ||
4105 | 2152 | This function will return the interfaces directly provided by the | 2880 | Cette fonction renvoie les interfaces fournies directement par un objet donné. |
4106 | 2153 | given object. | 2881 | |
4107 | 2154 | 2882 | - Emplacement : ``zope.interface`` | |
4108 | 2155 | - Location: ``zope.interface`` | 2883 | |
4109 | 2156 | 2884 | - Signature : `directlyProvidedBy(object)` | |
4110 | 2157 | - Signature: `directlyProvidedBy(object)` | 2885 | |
4111 | 2158 | 2886 | Exemple :: | |
4104 | 2159 | Example:: | ||
4112 | 2160 | 2887 | ||
4113 | 2161 | >>> from zope.interface import Attribute | 2888 | >>> from zope.interface import Attribute |
4114 | 2162 | >>> from zope.interface import Interface | 2889 | >>> from zope.interface import Interface |
4115 | @@ -2196,15 +2923,15 @@ | |||
4116 | 2196 | directlyProvides | 2923 | directlyProvides |
4117 | 2197 | ~~~~~~~~~~~~~~~~ | 2924 | ~~~~~~~~~~~~~~~~ |
4118 | 2198 | 2925 | ||
4128 | 2199 | Declare interfaces declared directly for an object. The arguments | 2926 | Déclare que des interfaces sont fournies directement par un objet. Les arguments |
4129 | 2200 | after the object are one or more interfaces. The interfaces given | 2927 | après l'objet sont une ou plusieurs interfaces. Les interfaces données |
4130 | 2201 | replace interfaces previously declared for the object. | 2928 | remplacent celles précédemment déclarées pour l'objet. |
4131 | 2202 | 2929 | ||
4132 | 2203 | - Location: ``zope.interface`` | 2930 | - Emplacement : ``zope.interface`` |
4133 | 2204 | 2931 | ||
4134 | 2205 | - Signature: `directlyProvides(object, *interfaces)` | 2932 | - Signature : `directlyProvides(object, *interfaces)` |
4135 | 2206 | 2933 | ||
4136 | 2207 | Example:: | 2934 | Exemple :: |
4137 | 2208 | 2935 | ||
4138 | 2209 | >>> from zope.interface import Attribute | 2936 | >>> from zope.interface import Attribute |
4139 | 2210 | >>> from zope.interface import Interface | 2937 | >>> from zope.interface import Interface |
4140 | @@ -2262,21 +2989,22 @@ | |||
4141 | 2262 | getAdapter | 2989 | getAdapter |
4142 | 2263 | ~~~~~~~~~~ | 2990 | ~~~~~~~~~~ |
4143 | 2264 | 2991 | ||
4153 | 2265 | Get a named adapter to an interface for an object. Returns an adapter | 2992 | Cette fonction récupère un adaptateur (nommé) vers une interface, pour un objet |
4154 | 2266 | that can adapt object to interface. If a matching adapter cannot be | 2993 | donné. Elle renvoie un adaptateur qui peut adapter les objets à l'interface |
4155 | 2267 | found, raises ``ComponentLookupError`` . | 2994 | voulue. Si aucun adaptateur ne peut être trouvé, une erreur |
4156 | 2268 | 2995 | ``ComponentLookupError`` est émise. | |
4157 | 2269 | - Location: ``zope.interface`` | 2996 | |
4158 | 2270 | 2997 | - Emplacement : ``zope.interface`` | |
4159 | 2271 | - Signature: `getAdapter(object, interface=Interface, name=u'', context=None)` | 2998 | |
4160 | 2272 | 2999 | - Signature : `getAdapter(object, interface=Interface, name=u'', context=None)` | |
4161 | 2273 | Example:: | 3000 | |
4162 | 3001 | Exemple :: | ||
4163 | 2274 | 3002 | ||
4164 | 2275 | >>> from zope.interface import Attribute | 3003 | >>> from zope.interface import Attribute |
4165 | 2276 | >>> from zope.interface import Interface | 3004 | >>> from zope.interface import Interface |
4166 | 2277 | 3005 | ||
4169 | 2278 | >>> class IRegistrar(Interface): | 3006 | >>> class IDesk(Interface): |
4170 | 2279 | ... """A registrar will register object's details""" | 3007 | ... """A frontdesk will register object's details""" |
4171 | 2280 | ... | 3008 | ... |
4172 | 2281 | ... def register(): | 3009 | ... def register(): |
4173 | 2282 | ... """Register object's details""" | 3010 | ... """Register object's details""" |
4174 | @@ -2285,9 +3013,9 @@ | |||
4175 | 2285 | >>> from zope.interface import implements | 3013 | >>> from zope.interface import implements |
4176 | 2286 | >>> from zope.component import adapts | 3014 | >>> from zope.component import adapts |
4177 | 2287 | 3015 | ||
4179 | 2288 | >>> class GuestRegistrarNG(object): | 3016 | >>> class FrontDeskNG(object): |
4180 | 2289 | ... | 3017 | ... |
4182 | 2290 | ... implements(IRegistrar) | 3018 | ... implements(IDesk) |
4183 | 2291 | ... adapts(IGuest) | 3019 | ... adapts(IGuest) |
4184 | 2292 | ... | 3020 | ... |
4185 | 2293 | ... def __init__(self, guest): | 3021 | ... def __init__(self, guest): |
4186 | @@ -2295,7 +3023,7 @@ | |||
4187 | 2295 | ... | 3023 | ... |
4188 | 2296 | ... def register(self): | 3024 | ... def register(self): |
4189 | 2297 | ... next_id = get_next_id() | 3025 | ... next_id = get_next_id() |
4191 | 2298 | ... guests_db[next_id] = { | 3026 | ... bookings_db[next_id] = { |
4192 | 2299 | ... 'name': guest.name, | 3027 | ... 'name': guest.name, |
4193 | 2300 | ... 'place': guest.place, | 3028 | ... 'place': guest.place, |
4194 | 2301 | ... 'phone': guest.phone | 3029 | ... 'phone': guest.phone |
4195 | @@ -2310,31 +3038,33 @@ | |||
4196 | 2310 | ... self.place = place | 3038 | ... self.place = place |
4197 | 2311 | 3039 | ||
4198 | 2312 | >>> jack = Guest("Jack", "Bangalore") | 3040 | >>> jack = Guest("Jack", "Bangalore") |
4200 | 2313 | >>> jack_registrar = GuestRegistrarNG(jack) | 3041 | >>> jack_frontdesk = FrontDeskNG(jack) |
4201 | 2314 | 3042 | ||
4203 | 2315 | >>> IRegistrar.providedBy(jack_registrar) | 3043 | >>> IDesk.providedBy(jack_frontdesk) |
4204 | 2316 | True | 3044 | True |
4205 | 2317 | 3045 | ||
4206 | 2318 | >>> from zope.component import getGlobalSiteManager | 3046 | >>> from zope.component import getGlobalSiteManager |
4207 | 2319 | >>> gsm = getGlobalSiteManager() | 3047 | >>> gsm = getGlobalSiteManager() |
4210 | 2320 | >>> gsm.registerAdapter(GuestRegistrarNG, | 3048 | >>> gsm.registerAdapter(FrontDeskNG, |
4211 | 2321 | ... (IGuest,), IRegistrar, 'ng') | 3049 | ... (IGuest,), IDesk, 'ng') |
4212 | 2322 | 3050 | ||
4215 | 2323 | >>> getAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS | 3051 | >>> getAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS |
4216 | 2324 | <GuestRegistrarNG object at ...> | 3052 | <FrontDeskNG object at ...> |
4217 | 2325 | 3053 | ||
4218 | 2326 | 3054 | ||
4219 | 2327 | getAdapterInContext | 3055 | getAdapterInContext |
4220 | 2328 | ~~~~~~~~~~~~~~~~~~~ | 3056 | ~~~~~~~~~~~~~~~~~~~ |
4221 | 2329 | 3057 | ||
4230 | 2330 | Instead of this function, use `context` argument of `getAdapter`_ | 3058 | Au lieu d'utiliser cette fonction, utilisez `getAdapter`_ avec un argument |
4231 | 2331 | function. | 3059 | `context`. |
4232 | 2332 | 3060 | ||
4233 | 2333 | - Location: ``zope.component`` | 3061 | - Emplacement : ``zope.component`` |
4234 | 2334 | 3062 | ||
4235 | 2335 | - Signature: `getAdapterInContext(object, interface, context)` | 3063 | - Signature : `getAdapterInContext(object, interface, context)` |
4236 | 2336 | 3064 | ||
4237 | 2337 | Example:: | 3065 | - Voir aussi : `queryAdapterInContext`_ |
4238 | 3066 | |||
4239 | 3067 | Exemple :: | ||
4240 | 2338 | 3068 | ||
4241 | 2339 | >>> from zope.component.globalregistry import BaseGlobalComponents | 3069 | >>> from zope.component.globalregistry import BaseGlobalComponents |
4242 | 2340 | >>> from zope.component import IComponentLookup | 3070 | >>> from zope.component import IComponentLookup |
4243 | @@ -2352,8 +3082,8 @@ | |||
4244 | 2352 | >>> from zope.interface import Attribute | 3082 | >>> from zope.interface import Attribute |
4245 | 2353 | >>> from zope.interface import Interface | 3083 | >>> from zope.interface import Interface |
4246 | 2354 | 3084 | ||
4249 | 2355 | >>> class IRegistrar(Interface): | 3085 | >>> class IDesk(Interface): |
4250 | 2356 | ... """A registrar will register object's details""" | 3086 | ... """A frontdesk will register object's details""" |
4251 | 2357 | ... | 3087 | ... |
4252 | 2358 | ... def register(): | 3088 | ... def register(): |
4253 | 2359 | ... """Register object's details""" | 3089 | ... """Register object's details""" |
4254 | @@ -2362,9 +3092,9 @@ | |||
4255 | 2362 | >>> from zope.interface import implements | 3092 | >>> from zope.interface import implements |
4256 | 2363 | >>> from zope.component import adapts | 3093 | >>> from zope.component import adapts |
4257 | 2364 | 3094 | ||
4259 | 2365 | >>> class GuestRegistrarNG(object): | 3095 | >>> class FrontDeskNG(object): |
4260 | 2366 | ... | 3096 | ... |
4262 | 2367 | ... implements(IRegistrar) | 3097 | ... implements(IDesk) |
4263 | 2368 | ... adapts(IGuest) | 3098 | ... adapts(IGuest) |
4264 | 2369 | ... | 3099 | ... |
4265 | 2370 | ... def __init__(self, guest): | 3100 | ... def __init__(self, guest): |
4266 | @@ -2372,7 +3102,7 @@ | |||
4267 | 2372 | ... | 3102 | ... |
4268 | 2373 | ... def register(self): | 3103 | ... def register(self): |
4269 | 2374 | ... next_id = get_next_id() | 3104 | ... next_id = get_next_id() |
4271 | 2375 | ... guests_db[next_id] = { | 3105 | ... bookings_db[next_id] = { |
4272 | 2376 | ... 'name': guest.name, | 3106 | ... 'name': guest.name, |
4273 | 2377 | ... 'place': guest.place, | 3107 | ... 'place': guest.place, |
4274 | 2378 | ... 'phone': guest.phone | 3108 | ... 'phone': guest.phone |
4275 | @@ -2387,42 +3117,41 @@ | |||
4276 | 2387 | ... self.place = place | 3117 | ... self.place = place |
4277 | 2388 | 3118 | ||
4278 | 2389 | >>> jack = Guest("Jack", "Bangalore") | 3119 | >>> jack = Guest("Jack", "Bangalore") |
4280 | 2390 | >>> jack_registrar = GuestRegistrarNG(jack) | 3120 | >>> jack_frontdesk = FrontDeskNG(jack) |
4281 | 2391 | 3121 | ||
4283 | 2392 | >>> IRegistrar.providedBy(jack_registrar) | 3122 | >>> IDesk.providedBy(jack_frontdesk) |
4284 | 2393 | True | 3123 | True |
4285 | 2394 | 3124 | ||
4286 | 2395 | >>> from zope.component import getGlobalSiteManager | 3125 | >>> from zope.component import getGlobalSiteManager |
4287 | 2396 | >>> gsm = getGlobalSiteManager() | 3126 | >>> gsm = getGlobalSiteManager() |
4290 | 2397 | >>> sm.registerAdapter(GuestRegistrarNG, | 3127 | >>> sm.registerAdapter(FrontDeskNG, |
4291 | 2398 | ... (IGuest,), IRegistrar) | 3128 | ... (IGuest,), IDesk) |
4292 | 2399 | 3129 | ||
4293 | 2400 | >>> from zope.component import getAdapterInContext | 3130 | >>> from zope.component import getAdapterInContext |
4294 | 2401 | >>> from zope.component import queryAdapterInContext | ||
4295 | 2402 | 3131 | ||
4298 | 2403 | >>> getAdapterInContext(jack, IRegistrar, sm) #doctest: +ELLIPSIS | 3132 | >>> getAdapterInContext(jack, IDesk, sm) #doctest: +ELLIPSIS |
4299 | 2404 | <GuestRegistrarNG object at ...> | 3133 | <FrontDeskNG object at ...> |
4300 | 2405 | 3134 | ||
4301 | 2406 | 3135 | ||
4302 | 2407 | getAdapters | 3136 | getAdapters |
4303 | 2408 | ~~~~~~~~~~~ | 3137 | ~~~~~~~~~~~ |
4304 | 2409 | 3138 | ||
4314 | 2410 | Look for all matching adapters to a provided interface for objects. | 3139 | Recherche pour des objets tous les adaptateurs fournissant une interface donnée. |
4315 | 2411 | Return a list of adapters that match. If an adapter is named, only the | 3140 | Une liste d'adaptateurs est renvoyée. Si un adaptateur est nommé, seul |
4316 | 2412 | most specific adapter of a given name is returned. | 3141 | l'adaptateur le plus spécifique pour un nom donné est renvoyé. |
4317 | 2413 | 3142 | ||
4318 | 2414 | - Location: ``zope.component`` | 3143 | - Emplacement : ``zope.component`` |
4319 | 2415 | 3144 | ||
4320 | 2416 | - Signature: `getAdapters(objects, provided, context=None)` | 3145 | - Signature : `getAdapters(objects, provided, context=None)` |
4321 | 2417 | 3146 | ||
4322 | 2418 | Example:: | 3147 | Exemple :: |
4323 | 2419 | 3148 | ||
4324 | 2420 | >>> from zope.interface import implements | 3149 | >>> from zope.interface import implements |
4325 | 2421 | >>> from zope.component import adapts | 3150 | >>> from zope.component import adapts |
4326 | 2422 | 3151 | ||
4328 | 2423 | >>> class GuestRegistrarNG(object): | 3152 | >>> class FrontDeskNG(object): |
4329 | 2424 | ... | 3153 | ... |
4331 | 2425 | ... implements(IRegistrar) | 3154 | ... implements(IDesk) |
4332 | 2426 | ... adapts(IGuest) | 3155 | ... adapts(IGuest) |
4333 | 2427 | ... | 3156 | ... |
4334 | 2428 | ... def __init__(self, guest): | 3157 | ... def __init__(self, guest): |
4335 | @@ -2430,37 +3159,37 @@ | |||
4336 | 2430 | ... | 3159 | ... |
4337 | 2431 | ... def register(self): | 3160 | ... def register(self): |
4338 | 2432 | ... next_id = get_next_id() | 3161 | ... next_id = get_next_id() |
4340 | 2433 | ... guests_db[next_id] = { | 3162 | ... bookings_db[next_id] = { |
4341 | 2434 | ... 'name': guest.name, | 3163 | ... 'name': guest.name, |
4342 | 2435 | ... 'place': guest.place, | 3164 | ... 'place': guest.place, |
4343 | 2436 | ... 'phone': guest.phone | 3165 | ... 'phone': guest.phone |
4344 | 2437 | ... } | 3166 | ... } |
4345 | 2438 | 3167 | ||
4346 | 2439 | >>> jack = Guest("Jack", "Bangalore") | 3168 | >>> jack = Guest("Jack", "Bangalore") |
4348 | 2440 | >>> jack_registrar = GuestRegistrarNG(jack) | 3169 | >>> jack_frontdesk = FrontDeskNG(jack) |
4349 | 2441 | 3170 | ||
4350 | 2442 | >>> from zope.component import getGlobalSiteManager | 3171 | >>> from zope.component import getGlobalSiteManager |
4351 | 2443 | >>> gsm = getGlobalSiteManager() | 3172 | >>> gsm = getGlobalSiteManager() |
4352 | 2444 | 3173 | ||
4354 | 2445 | >>> gsm.registerAdapter(GuestRegistrarNG, name='ng') | 3174 | >>> gsm.registerAdapter(FrontDeskNG, name='ng') |
4355 | 2446 | 3175 | ||
4356 | 2447 | >>> from zope.component import getAdapters | 3176 | >>> from zope.component import getAdapters |
4359 | 2448 | >>> list(getAdapters((jack,), IRegistrar)) #doctest: +ELLIPSIS | 3177 | >>> list(getAdapters((jack,), IDesk)) #doctest: +ELLIPSIS |
4360 | 2449 | [(u'ng', <GuestRegistrarNG object at ...>)] | 3178 | [(u'ng', <FrontDeskNG object at ...>)] |
4361 | 2450 | 3179 | ||
4362 | 2451 | 3180 | ||
4363 | 2452 | getAllUtilitiesRegisteredFor | 3181 | getAllUtilitiesRegisteredFor |
4364 | 2453 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 3182 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4365 | 2454 | 3183 | ||
4375 | 2455 | Return all registered utilities for an interface. This includes | 3184 | Renvoie tous les utilitaires inscrits pour une interface. Ceci inclut les |
4376 | 2456 | overridden utilities. The returned value is an iterable of utility | 3185 | utilitaires surchargés. La valeur renvoyée est un objet iterable listant les |
4377 | 2457 | instances. | 3186 | instances d'utilitaires correspondants. |
4378 | 2458 | 3187 | ||
4379 | 2459 | - Location: ``zope.component`` | 3188 | - Emplacement : ``zope.component`` |
4380 | 2460 | 3189 | ||
4381 | 2461 | - Signature: `getAllUtilitiesRegisteredFor(interface)` | 3190 | - Signature : `getAllUtilitiesRegisteredFor(interface)` |
4382 | 2462 | 3191 | ||
4383 | 2463 | Example:: | 3192 | Exemple :: |
4384 | 2464 | 3193 | ||
4385 | 2465 | >>> from zope.interface import Interface | 3194 | >>> from zope.interface import Interface |
4386 | 2466 | >>> from zope.interface import implements | 3195 | >>> from zope.interface import implements |
4387 | @@ -2491,14 +3220,14 @@ | |||
4388 | 2491 | getFactoriesFor | 3220 | getFactoriesFor |
4389 | 2492 | ~~~~~~~~~~~~~~~ | 3221 | ~~~~~~~~~~~~~~~ |
4390 | 2493 | 3222 | ||
4399 | 2494 | Return a tuple (name, factory) of registered factories that create | 3223 | Renvoie un tuple (nom, fabrique) de fabriques inscrites capables de créer des |
4400 | 2495 | objects which implement the given interface. | 3224 | objets qui fournissent une interface donnée. |
4401 | 2496 | 3225 | ||
4402 | 2497 | - Location: ``zope.component`` | 3226 | - Emplacement : ``zope.component`` |
4403 | 2498 | 3227 | ||
4404 | 2499 | - Signature: `getFactoriesFor(interface, context=None)` | 3228 | - Signature : `getFactoriesFor(interface, context=None)` |
4405 | 2500 | 3229 | ||
4406 | 2501 | Example:: | 3230 | Exemple :: |
4407 | 2502 | 3231 | ||
4408 | 2503 | >>> from zope.interface import Attribute | 3232 | >>> from zope.interface import Attribute |
4409 | 2504 | >>> from zope.interface import Interface | 3233 | >>> from zope.interface import Interface |
4410 | @@ -2535,16 +3264,16 @@ | |||
4411 | 2535 | getFactoryInterfaces | 3264 | getFactoryInterfaces |
4412 | 2536 | ~~~~~~~~~~~~~~~~~~~~ | 3265 | ~~~~~~~~~~~~~~~~~~~~ |
4413 | 2537 | 3266 | ||
4424 | 2538 | Get interfaces implemented by a factory. Finds the factory of the | 3267 | Récupère les interfaces implémentées par une fabrique. Cette fonction trouve la |
4425 | 2539 | given name that is nearest to the context, and returns the interface | 3268 | fabrique possédant le nom donné la plus proche du contexte, puis renvoie |
4426 | 2540 | or interface tuple that object instances created by the named factory | 3269 | l'interface ou le tuple d'interfaces que les instances créées par la fabrique |
4427 | 2541 | will implement. | 3270 | vont fournir. |
4428 | 2542 | 3271 | ||
4429 | 2543 | - Location: ``zope.component`` | 3272 | - Emplacement : ``zope.component`` |
4430 | 2544 | 3273 | ||
4431 | 2545 | - Signature: `getFactoryInterfaces(name, context=None)` | 3274 | - Signature : `getFactoryInterfaces(name, context=None)` |
4432 | 2546 | 3275 | ||
4433 | 2547 | Example:: | 3276 | Exemple :: |
4434 | 2548 | 3277 | ||
4435 | 2549 | >>> from zope.interface import Attribute | 3278 | >>> from zope.interface import Attribute |
4436 | 2550 | >>> from zope.interface import Interface | 3279 | >>> from zope.interface import Interface |
4437 | @@ -2581,14 +3310,14 @@ | |||
4438 | 2581 | getGlobalSiteManager | 3310 | getGlobalSiteManager |
4439 | 2582 | ~~~~~~~~~~~~~~~~~~~~ | 3311 | ~~~~~~~~~~~~~~~~~~~~ |
4440 | 2583 | 3312 | ||
4449 | 2584 | Return the global site manager. This function should never fail and | 3313 | Renvoie le gestionnaire global de site. Cette fonction ne doit jamais échouer |
4450 | 2585 | always return an object that provides `IGlobalSiteManager` | 3314 | et doit toujours renvoyer un objet qui fournit `IGlobalSiteManager`. |
4451 | 2586 | 3315 | ||
4452 | 2587 | - Location: ``zope.component`` | 3316 | - Emplacement : ``zope.component`` |
4453 | 2588 | 3317 | ||
4454 | 2589 | - Signature: `getGlobalSiteManager()` | 3318 | - Signature : `getGlobalSiteManager()` |
4455 | 2590 | 3319 | ||
4456 | 2591 | Example:: | 3320 | Exemple :: |
4457 | 2592 | 3321 | ||
4458 | 2593 | >>> from zope.component import getGlobalSiteManager | 3322 | >>> from zope.component import getGlobalSiteManager |
4459 | 2594 | >>> from zope.component import globalSiteManager | 3323 | >>> from zope.component import globalSiteManager |
4460 | @@ -2600,19 +3329,21 @@ | |||
4461 | 2600 | getMultiAdapter | 3329 | getMultiAdapter |
4462 | 2601 | ~~~~~~~~~~~~~~~ | 3330 | ~~~~~~~~~~~~~~~ |
4463 | 2602 | 3331 | ||
4474 | 2603 | Look for a multi-adapter to an interface for an objects. Returns a | 3332 | Cette fonction recherche pour des objets un multi-adaptateur vers une interface |
4475 | 2604 | multi-adapter that can adapt objects to interface. If a matching | 3333 | donnée. Elle renvoie un multi-adaptateur qui peut s'adapter aux objets donnés et |
4476 | 2605 | adapter cannot be found, raises ComponentLookupError. The name | 3334 | fournir l'interface voulue. Si aucun adaptateur ne peut être trouvé, une erreur |
4477 | 2606 | consisting of an empty string is reserved for unnamed adapters. The | 3335 | `ComponentLookupError` est émise. Le nom constitué de la chaîne vide est réservé |
4478 | 2607 | unnamed adapter methods will often call the named adapter methods with | 3336 | aux adaptateur sans nom. Les méthodes des adaptateurs sans nom appellent souvent |
4479 | 2608 | an empty string for a name. | 3337 | les méthodes des adaptateurs nommés en fournissant un nom vide (''). |
4480 | 2609 | 3338 | ||
4481 | 2610 | - Location: ``zope.component`` | 3339 | - Emplacement : ``zope.component`` |
4482 | 2611 | 3340 | ||
4483 | 2612 | - Signature: `getMultiAdapter(objects, interface=Interface, name='', | 3341 | - Signature : `getMultiAdapter(objects, interface=Interface, name='', |
4484 | 2613 | context=None)` | 3342 | context=None)` |
4485 | 2614 | 3343 | ||
4487 | 2615 | Example:: | 3344 | - Voir aussi : `queryMultiAdapter`_ |
4488 | 3345 | |||
4489 | 3346 | Exemple :: | ||
4490 | 2616 | 3347 | ||
4491 | 2617 | >>> from zope.interface import Interface | 3348 | >>> from zope.interface import Interface |
4492 | 2618 | >>> from zope.interface import implements | 3349 | >>> from zope.interface import implements |
4493 | @@ -2664,17 +3395,17 @@ | |||
4494 | 2664 | getSiteManager | 3395 | getSiteManager |
4495 | 2665 | ~~~~~~~~~~~~~~ | 3396 | ~~~~~~~~~~~~~~ |
4496 | 2666 | 3397 | ||
4508 | 2667 | Get the nearest site manager in the given context. If `context` is | 3398 | Récupère le gestionnaire de site le plus proche du contexte donné. Si `context` |
4509 | 2668 | `None`, return the global site manager. If the `context` is not | 3399 | est `None`, cette fonction renvoie le gestionnaire global de site. Si le |
4510 | 2669 | `None`, it is expected that an adapter from the `context` to | 3400 | `context` n'est pas `None`, on s'attend à ce qu'un adaptateur sur le contexte |
4511 | 2670 | `IComponentLookup` can be found. If no adapter is found, a | 3401 | vers `IComponentLookup` soit trouvé. Si aucun adaptateur n'est trouvé, une |
4512 | 2671 | `ComponentLookupError` is raised. | 3402 | erreur `ComponentLookupError` est émise. |
4513 | 2672 | 3403 | ||
4514 | 2673 | - Location: ``zope.component`` | 3404 | - Emplacement : ``zope.component`` |
4515 | 2674 | 3405 | ||
4516 | 2675 | - Signature: `getSiteManager(context=None)` | 3406 | - Signature : `getSiteManager(context=None)` |
4517 | 2676 | 3407 | ||
4518 | 2677 | Example 1:: | 3408 | Exemple 1 :: |
4519 | 2678 | 3409 | ||
4520 | 2679 | >>> from zope.component.globalregistry import BaseGlobalComponents | 3410 | >>> from zope.component.globalregistry import BaseGlobalComponents |
4521 | 2680 | >>> from zope.component import IComponentLookup | 3411 | >>> from zope.component import IComponentLookup |
4522 | @@ -2695,7 +3426,7 @@ | |||
4523 | 2695 | >>> lsm is sm | 3426 | >>> lsm is sm |
4524 | 2696 | True | 3427 | True |
4525 | 2697 | 3428 | ||
4527 | 2698 | Example 2:: | 3429 | Exemple 2 :: |
4528 | 2699 | 3430 | ||
4529 | 2700 | >>> from zope.component import getGlobalSiteManager | 3431 | >>> from zope.component import getGlobalSiteManager |
4530 | 2701 | >>> gsm = getGlobalSiteManager() | 3432 | >>> gsm = getGlobalSiteManager() |
4531 | @@ -2708,14 +3439,14 @@ | |||
4532 | 2708 | getUtilitiesFor | 3439 | getUtilitiesFor |
4533 | 2709 | ~~~~~~~~~~~~~~~ | 3440 | ~~~~~~~~~~~~~~~ |
4534 | 2710 | 3441 | ||
4543 | 2711 | Look up the registered utilities that provide an interface. Returns | 3442 | Récupère les utilitaires inscrits pour une interface particulière. Renvoie un |
4544 | 2712 | an iterable of name-utility pairs. | 3443 | objet iterable listant les paires nom/utilitaire. |
4545 | 2713 | 3444 | ||
4546 | 2714 | - Location: ``zope.component`` | 3445 | - Emplacement : ``zope.component`` |
4547 | 2715 | 3446 | ||
4548 | 2716 | - Signature: `getUtilitiesFor(interface)` | 3447 | - Signature : `getUtilitiesFor(interface)` |
4549 | 2717 | 3448 | ||
4550 | 2718 | Example:: | 3449 | Exemple :: |
4551 | 2719 | 3450 | ||
4552 | 2720 | >>> from zope.interface import Interface | 3451 | >>> from zope.interface import Interface |
4553 | 2721 | >>> from zope.interface import implements | 3452 | >>> from zope.interface import implements |
4554 | @@ -2746,15 +3477,15 @@ | |||
4555 | 2746 | getUtility | 3477 | getUtility |
4556 | 2747 | ~~~~~~~~~~ | 3478 | ~~~~~~~~~~ |
4557 | 2748 | 3479 | ||
4567 | 2749 | Get the utility that provides interface. Returns the nearest utility | 3480 | Récupère l'utilitaire qui fournit une interface donnée. Cette fonction renvoie |
4568 | 2750 | to the context that implements the specified interface. If one is not | 3481 | l'utilitaire le plus proche du contexte et qui fournit l'interface donnée. Si |
4569 | 2751 | found, raises ComponentLookupError. | 3482 | aucun n'est trouvé, une erreur ``ComponentLookupError`` est levée. |
4570 | 2752 | 3483 | ||
4571 | 2753 | - Location: ``zope.component`` | 3484 | - Emplacement : ``zope.component`` |
4572 | 2754 | 3485 | ||
4573 | 2755 | - Signature: `getUtility(interface, name='', context=None)` | 3486 | - Signature : `getUtility(interface, name='', context=None)` |
4574 | 2756 | 3487 | ||
4575 | 2757 | Example:: | 3488 | Exemple :: |
4576 | 2758 | 3489 | ||
4577 | 2759 | >>> from zope.interface import Interface | 3490 | >>> from zope.interface import Interface |
4578 | 2760 | >>> from zope.interface import implements | 3491 | >>> from zope.interface import implements |
4579 | @@ -2785,16 +3516,15 @@ | |||
4580 | 2785 | handle | 3516 | handle |
4581 | 2786 | ~~~~~~ | 3517 | ~~~~~~ |
4582 | 2787 | 3518 | ||
4593 | 2788 | Call all of the handlers for the given objects. Handlers are | 3519 | Appelle tous les gestionnaires pour un objet donné. Les gestionnaires sont des |
4594 | 2789 | subscription adapter factories that don't produce anything. They do | 3520 | fabriques d'abonnés qui ne produisent rien. Ils font tout leur travail lors de |
4595 | 2790 | all of their work when called. Handlers are typically used to handle | 3521 | l'appel. Ils sont typiquement utilisés pour gérer des événements. |
4596 | 2791 | events. | 3522 | |
4597 | 2792 | 3523 | - Emplacement : ``zope.component`` | |
4598 | 2793 | - Location: ``zope.component`` | 3524 | |
4599 | 2794 | 3525 | - Signature : `handle(*objects)` | |
4600 | 2795 | - Signature: `handle(*objects)` | 3526 | |
4601 | 2796 | 3527 | Exemple :: | |
4592 | 2797 | Example:: | ||
4602 | 2798 | 3528 | ||
4603 | 2799 | >>> import datetime | 3529 | >>> import datetime |
4604 | 2800 | 3530 | ||
4605 | @@ -2840,13 +3570,13 @@ | |||
4606 | 2840 | implementedBy | 3570 | implementedBy |
4607 | 2841 | ~~~~~~~~~~~~~ | 3571 | ~~~~~~~~~~~~~ |
4608 | 2842 | 3572 | ||
4616 | 2843 | Return the interfaces implemented for a class' instances. | 3573 | Renvoie les interfaces implémentées par une classe. |
4617 | 2844 | 3574 | ||
4618 | 2845 | - Location: ``zope.interface`` | 3575 | - Emplacement : ``zope.interface`` |
4619 | 2846 | 3576 | ||
4620 | 2847 | - Signature: `implementedBy(class_)` | 3577 | - Signature : `implementedBy(class_)` |
4621 | 2848 | 3578 | ||
4622 | 2849 | Example 1:: | 3579 | Exemple 1 :: |
4623 | 2850 | 3580 | ||
4624 | 2851 | >>> from zope.interface import Interface | 3581 | >>> from zope.interface import Interface |
4625 | 2852 | >>> from zope.interface import implements | 3582 | >>> from zope.interface import implements |
4626 | @@ -2866,7 +3596,7 @@ | |||
4627 | 2866 | >>> implementedBy(Greeter) | 3596 | >>> implementedBy(Greeter) |
4628 | 2867 | <implementedBy __builtin__.Greeter> | 3597 | <implementedBy __builtin__.Greeter> |
4629 | 2868 | 3598 | ||
4631 | 2869 | Example 2:: | 3599 | Exemple 2 :: |
4632 | 2870 | 3600 | ||
4633 | 2871 | >>> from zope.interface import Attribute | 3601 | >>> from zope.interface import Attribute |
4634 | 2872 | >>> from zope.interface import Interface | 3602 | >>> from zope.interface import Interface |
4635 | @@ -2887,7 +3617,8 @@ | |||
4636 | 2887 | 3617 | ||
4637 | 2888 | >>> from zope.interface import implementedBy | 3618 | >>> from zope.interface import implementedBy |
4638 | 2889 | 3619 | ||
4640 | 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 |
4641 | 3621 | classe :: | ||
4642 | 2891 | 3622 | ||
4643 | 2892 | >>> [x.__name__ for x in implementedBy(Person)] | 3623 | >>> [x.__name__ for x in implementedBy(Person)] |
4644 | 2893 | ['IPerson', 'ISpecial'] | 3624 | ['IPerson', 'ISpecial'] |
4645 | @@ -2896,15 +3627,15 @@ | |||
4646 | 2896 | implementer | 3627 | implementer |
4647 | 2897 | ~~~~~~~~~~~ | 3628 | ~~~~~~~~~~~ |
4648 | 2898 | 3629 | ||
4658 | 2899 | Create a decorator for declaring interfaces implemented by a factory. | 3630 | Créer un décorateur permettant de déclarer des interfaces implémentées par une |
4659 | 2900 | A callable is returned that makes an implements declaration on objects | 3631 | fabrique. Un objet appelable est renvoyé, qui fait une déclaration |
4660 | 2901 | passed to it. | 3632 | d'implémentation sur les objets qui lui sont transmis. |
4661 | 2902 | 3633 | ||
4662 | 2903 | - Location: ``zope.interface`` | 3634 | - Emplacement : ``zope.interface`` |
4663 | 2904 | 3635 | ||
4664 | 2905 | - Signature: `implementer(*interfaces)` | 3636 | - Signature : `implementer(*interfaces)` |
4665 | 2906 | 3637 | ||
4666 | 2907 | Example:: | 3638 | Exemple :: |
4667 | 2908 | 3639 | ||
4668 | 2909 | >>> from zope.interface import implementer | 3640 | >>> from zope.interface import implementer |
4669 | 2910 | >>> class IFoo(Interface): | 3641 | >>> class IFoo(Interface): |
4670 | @@ -2923,17 +3654,17 @@ | |||
4671 | 2923 | implements | 3654 | implements |
4672 | 2924 | ~~~~~~~~~~ | 3655 | ~~~~~~~~~~ |
4673 | 2925 | 3656 | ||
4685 | 2926 | Declare interfaces implemented by instances of a class This function | 3657 | Déclare que des interfaces seront fournies par une classe. Cette fonction est |
4686 | 2927 | is called in a class definition. The arguments are one or more | 3658 | appelée dans une définition de classe. Les arguments sont une ou plusieurs |
4687 | 2928 | interfaces. The interfaces given are added to any interfaces | 3659 | interfaces. Les interfaces données sont ajoutées aux interfaces précédemment |
4688 | 2929 | previously declared. Previous declarations include declarations for | 3660 | déclarées. Les déclarations précédentes incluent les déclarations des classes |
4689 | 2930 | base classes unless implementsOnly was used. | 3661 | debase, à moins que `implementsOnly` ne soit utilisé. |
4690 | 2931 | 3662 | ||
4691 | 2932 | - Location: ``zope.interface`` | 3663 | - Emplacement : ``zope.interface`` |
4692 | 2933 | 3664 | ||
4693 | 2934 | - Signature: `implements(*interfaces)` | 3665 | - Signature : `implements(*interfaces)` |
4694 | 2935 | 3666 | ||
4695 | 2936 | Example:: | 3667 | Exemple :: |
4696 | 2937 | 3668 | ||
4697 | 2938 | >>> from zope.interface import Attribute | 3669 | >>> from zope.interface import Attribute |
4698 | 2939 | >>> from zope.interface import Interface | 3670 | >>> from zope.interface import Interface |
4699 | @@ -2957,19 +3688,20 @@ | |||
4700 | 2957 | >>> IPerson in providedBy(jack) | 3688 | >>> IPerson in providedBy(jack) |
4701 | 2958 | True | 3689 | True |
4702 | 2959 | 3690 | ||
4703 | 3691 | |||
4704 | 2960 | implementsOnly | 3692 | implementsOnly |
4705 | 2961 | ~~~~~~~~~~~~~~ | 3693 | ~~~~~~~~~~~~~~ |
4706 | 2962 | 3694 | ||
4717 | 2963 | Declare the only interfaces implemented by instances of a class. This | 3695 | Déclare les seules interfaces qui doivent être implémentées par une classe. |
4718 | 2964 | function is called in a class definition. The arguments are one or | 3696 | Cette fonction est appelée dans la définition de classe. Les arguments sont une |
4719 | 2965 | more interfaces. Previous declarations including declarations for | 3697 | ou plusieurs interfaces. Les déclarations précédentes, y compris celles des |
4720 | 2966 | base classes are overridden. | 3698 | classes de base, sont remplacées. |
4721 | 2967 | 3699 | ||
4722 | 2968 | - Location: ``zope.interface`` | 3700 | - Emplacement : ``zope.interface`` |
4723 | 2969 | 3701 | ||
4724 | 2970 | - Signature: `implementsOnly(*interfaces)` | 3702 | - Signature : `implementsOnly(*interfaces)` |
4725 | 2971 | 3703 | ||
4726 | 2972 | Example:: | 3704 | Exemple :: |
4727 | 2973 | 3705 | ||
4728 | 2974 | >>> from zope.interface import Attribute | 3706 | >>> from zope.interface import Attribute |
4729 | 2975 | >>> from zope.interface import Interface | 3707 | >>> from zope.interface import Interface |
4730 | @@ -3005,35 +3737,78 @@ | |||
4731 | 3005 | True | 3737 | True |
4732 | 3006 | 3738 | ||
4733 | 3007 | 3739 | ||
4734 | 3740 | Interface | ||
4735 | 3741 | ~~~~~~~~~ | ||
4736 | 3742 | |||
4737 | 3743 | Grâce à cette classe, vous pouvez définir une interface. Pour définir une | ||
4738 | 3744 | interface, contentez-vous d'hériter de cette classe. | ||
4739 | 3745 | |||
4740 | 3746 | - Emplacement : ``zope.interface`` | ||
4741 | 3747 | |||
4742 | 3748 | - Signature : `Interface(name, doc='')` | ||
4743 | 3749 | |||
4744 | 3750 | Exemple 1 :: | ||
4745 | 3751 | |||
4746 | 3752 | >>> from zope.interface import Attribute | ||
4747 | 3753 | >>> from zope.interface import Interface | ||
4748 | 3754 | |||
4749 | 3755 | >>> class IPerson(Interface): | ||
4750 | 3756 | ... | ||
4751 | 3757 | ... name = Attribute("Name of person") | ||
4752 | 3758 | ... email = Attribute("Email Address") | ||
4753 | 3759 | |||
4754 | 3760 | |||
4755 | 3761 | Exemple 2 :: | ||
4756 | 3762 | |||
4757 | 3763 | >>> from zope.interface import Interface | ||
4758 | 3764 | |||
4759 | 3765 | >>> class IHost(Interface): | ||
4760 | 3766 | ... | ||
4761 | 3767 | ... def goodmorning(guest): | ||
4762 | 3768 | ... """Say good morning to guest""" | ||
4763 | 3769 | |||
4764 | 3770 | |||
4765 | 3008 | moduleProvides | 3771 | moduleProvides |
4766 | 3009 | ~~~~~~~~~~~~~~ | 3772 | ~~~~~~~~~~~~~~ |
4767 | 3010 | 3773 | ||
4781 | 3011 | Declare interfaces provided by a module. This function is used in a | 3774 | Déclare les interfaces fournies par un module. Cette fonction est utilisée dans |
4782 | 3012 | module definition. The arguments are one or more interfaces. The | 3775 | une définition de module. Les arguments sont une ou plusieurs interfaces. Les |
4783 | 3013 | given interfaces are used to create the module's direct-object | 3776 | interfaces fournies sont utilisées pour créer la spécification d'interface objet |
4784 | 3014 | interface specification. An error will be raised if the module | 3777 | du module. Une erreur est levée si le module a déjà une spécification |
4785 | 3015 | already has an interface specification. In other words, it is an | 3778 | d'interface. Autrement dit, c'est une erreur d'appeler cette fonction plus d'une |
4786 | 3016 | error to call this function more than once in a module definition. | 3779 | fois dans une définition de module. |
4787 | 3017 | 3780 | ||
4788 | 3018 | This function is provided for convenience. It provides a more | 3781 | Cette fonction est fournie pour des raisons pratiques. Elle fournit une manière |
4789 | 3019 | convenient way to call directlyProvides for a module. | 3782 | plus pratique d'appeler ``directlyProvides`` pour un module. |
4790 | 3020 | 3783 | ||
4791 | 3021 | - Location: ``zope.interface`` | 3784 | - Emplacement : ``zope.interface`` |
4792 | 3022 | 3785 | ||
4793 | 3023 | - Signature: `moduleProvides(*interfaces)` | 3786 | - Signature : `moduleProvides(*interfaces)` |
4794 | 3787 | |||
4795 | 3788 | - Voir aussi : `directlyProvides`_ | ||
4796 | 3789 | |||
4797 | 3790 | Vous pouvez consulter un exemple d'utilisation dans le code source de | ||
4798 | 3791 | `zope.component` lui-même. Le fichier `__init__.py` possède celle | ||
4799 | 3792 | instruction :: | ||
4800 | 3793 | |||
4801 | 3794 | moduleProvides(IComponentArchitecture, | ||
4802 | 3795 | IComponentRegistrationConvenience) | ||
4803 | 3796 | |||
4804 | 3797 | Ainsi, le paquet `zope.component` fournit deux interfaces : | ||
4805 | 3798 | `IComponentArchitecture` et `IComponentRegistrationConvenience`. | ||
4806 | 3024 | 3799 | ||
4807 | 3025 | 3800 | ||
4808 | 3026 | noLongerProvides | 3801 | noLongerProvides |
4809 | 3027 | ~~~~~~~~~~~~~~~~ | 3802 | ~~~~~~~~~~~~~~~~ |
4810 | 3028 | 3803 | ||
4819 | 3029 | Remove an interface from the list of an object's directly provided | 3804 | Retire une interface de la liste des interfaces directements fournies par un |
4820 | 3030 | interfaces. | 3805 | objet. |
4821 | 3031 | 3806 | ||
4822 | 3032 | - Location: ``zope.interface`` | 3807 | - Emplacement : ``zope.interface`` |
4823 | 3033 | 3808 | ||
4824 | 3034 | - Signature: `noLongerProvides(object, interface)` | 3809 | - Signature : `noLongerProvides(object, interface)` |
4825 | 3035 | 3810 | ||
4826 | 3036 | Example:: | 3811 | Exemple :: |
4827 | 3037 | 3812 | ||
4828 | 3038 | >>> from zope.interface import Attribute | 3813 | >>> from zope.interface import Attribute |
4829 | 3039 | >>> from zope.interface import Interface | 3814 | >>> from zope.interface import Interface |
4830 | @@ -3076,39 +3851,38 @@ | |||
4831 | 3076 | provideAdapter | 3851 | provideAdapter |
4832 | 3077 | ~~~~~~~~~~~~~~ | 3852 | ~~~~~~~~~~~~~~ |
4833 | 3078 | 3853 | ||
4835 | 3079 | It is recommend to use `registerAdapter`_ . | 3854 | Il est recommandé d'utilier `registerAdapter`_ . |
4836 | 3080 | 3855 | ||
4837 | 3081 | 3856 | ||
4838 | 3082 | provideHandler | 3857 | provideHandler |
4839 | 3083 | ~~~~~~~~~~~~~~ | 3858 | ~~~~~~~~~~~~~~ |
4840 | 3084 | 3859 | ||
4842 | 3085 | It is recommend to use `registerHandler`_ . | 3860 | Il est recommandé d'utiliser `registerHandler`_ . |
4843 | 3086 | 3861 | ||
4844 | 3087 | 3862 | ||
4845 | 3088 | provideSubscriptionAdapter | 3863 | provideSubscriptionAdapter |
4846 | 3089 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 3864 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4847 | 3090 | 3865 | ||
4849 | 3091 | It is recommend to use `registerSubscriptionAdapter`_ . | 3866 | Il est recommandé d'utiliser `registerSubscriptionAdapter`_ . |
4850 | 3092 | 3867 | ||
4851 | 3093 | 3868 | ||
4852 | 3094 | provideUtility | 3869 | provideUtility |
4853 | 3095 | ~~~~~~~~~~~~~~ | 3870 | ~~~~~~~~~~~~~~ |
4854 | 3096 | 3871 | ||
4856 | 3097 | It is recommend to use `registerUtility`_ . | 3872 | Il est recommandé d'utiliser `registerUtility`_ . |
4857 | 3098 | 3873 | ||
4858 | 3099 | 3874 | ||
4859 | 3100 | providedBy | 3875 | providedBy |
4860 | 3101 | ~~~~~~~~~~ | 3876 | ~~~~~~~~~~ |
4861 | 3102 | 3877 | ||
4871 | 3103 | Test whether the interface is implemented by the object. Return true | 3878 | Teste si l'interface est implémentée par l'objet. Renvoie True si l'objet |
4872 | 3104 | if the object asserts that it implements the interface, including | 3879 | affirme qu'il implémente l'interface, y compris les interfaces étendues. |
4873 | 3105 | asserting that it implements an extended interface. | 3880 | |
4874 | 3106 | 3881 | - Emplacement : ``zope.interface`` | |
4875 | 3107 | - Location: ``zope.interface`` | 3882 | |
4876 | 3108 | 3883 | - Signature : `providedBy(object)` | |
4877 | 3109 | - Signature: `providedBy(object)` | 3884 | |
4878 | 3110 | 3885 | Exemple 1 :: | |
4870 | 3111 | Example 1:: | ||
4879 | 3112 | 3886 | ||
4880 | 3113 | >>> from zope.interface import Attribute | 3887 | >>> from zope.interface import Attribute |
4881 | 3114 | >>> from zope.interface import Interface | 3888 | >>> from zope.interface import Interface |
4882 | @@ -3132,7 +3906,7 @@ | |||
4883 | 3132 | >>> IPerson in providedBy(jack) | 3906 | >>> IPerson in providedBy(jack) |
4884 | 3133 | True | 3907 | True |
4885 | 3134 | 3908 | ||
4887 | 3135 | Example 2:: | 3909 | Exemple 2 :: |
4888 | 3136 | 3910 | ||
4889 | 3137 | >>> from zope.interface import Attribute | 3911 | >>> from zope.interface import Attribute |
4890 | 3138 | >>> from zope.interface import Interface | 3912 | >>> from zope.interface import Interface |
4891 | @@ -3154,7 +3928,7 @@ | |||
4892 | 3154 | >>> jack = Person() | 3928 | >>> jack = Person() |
4893 | 3155 | >>> jack.name = "Jack" | 3929 | >>> jack.name = "Jack" |
4894 | 3156 | 3930 | ||
4896 | 3157 | To get a list of all interfaces provided by that object:: | 3931 | Pour obtenir une liste de toutes les interfaces fournies par cet objet :: |
4897 | 3158 | 3932 | ||
4898 | 3159 | >>> [x.__name__ for x in providedBy(jack)] | 3933 | >>> [x.__name__ for x in providedBy(jack)] |
4899 | 3160 | ['IPerson', 'ISpecial'] | 3934 | ['IPerson', 'ISpecial'] |
4900 | @@ -3163,22 +3937,22 @@ | |||
4901 | 3163 | queryAdapter | 3937 | queryAdapter |
4902 | 3164 | ~~~~~~~~~~~~ | 3938 | ~~~~~~~~~~~~ |
4903 | 3165 | 3939 | ||
4911 | 3166 | Look for a named adapter to an interface for an object. Returns an | 3940 | Recherche pour un objet un adaptateur nommé vers une interface. Renvoie un |
4912 | 3167 | adapter that can adapt object to interface. If a matching adapter | 3941 | adaptateur qui peut s'adapter à un objet et fournir une interface. Si aucun |
4913 | 3168 | cannot be found, returns the default. | 3942 | adaptateur ne peut être trouvé, la valeur par défaut est renvoyée. |
4914 | 3169 | 3943 | ||
4915 | 3170 | - Location: ``zope.component`` | 3944 | - Emplacement : ``zope.component`` |
4916 | 3171 | 3945 | ||
4917 | 3172 | - Signature: `queryAdapter(object, interface=Interface, name=u'', | 3946 | - Signature : `queryAdapter(object, interface=Interface, name=u'', |
4918 | 3173 | default=None, context=None)` | 3947 | default=None, context=None)` |
4919 | 3174 | 3948 | ||
4921 | 3175 | Example:: | 3949 | Exemple :: |
4922 | 3176 | 3950 | ||
4923 | 3177 | >>> from zope.interface import Attribute | 3951 | >>> from zope.interface import Attribute |
4924 | 3178 | >>> from zope.interface import Interface | 3952 | >>> from zope.interface import Interface |
4925 | 3179 | 3953 | ||
4928 | 3180 | >>> class IRegistrar(Interface): | 3954 | >>> class IDesk(Interface): |
4929 | 3181 | ... """A registrar will register object's details""" | 3955 | ... """A frontdesk will register object's details""" |
4930 | 3182 | ... | 3956 | ... |
4931 | 3183 | ... def register(): | 3957 | ... def register(): |
4932 | 3184 | ... """Register object's details""" | 3958 | ... """Register object's details""" |
4933 | @@ -3187,9 +3961,9 @@ | |||
4934 | 3187 | >>> from zope.interface import implements | 3961 | >>> from zope.interface import implements |
4935 | 3188 | >>> from zope.component import adapts | 3962 | >>> from zope.component import adapts |
4936 | 3189 | 3963 | ||
4938 | 3190 | >>> class GuestRegistrarNG(object): | 3964 | >>> class FrontDeskNG(object): |
4939 | 3191 | ... | 3965 | ... |
4941 | 3192 | ... implements(IRegistrar) | 3966 | ... implements(IDesk) |
4942 | 3193 | ... adapts(IGuest) | 3967 | ... adapts(IGuest) |
4943 | 3194 | ... | 3968 | ... |
4944 | 3195 | ... def __init__(self, guest): | 3969 | ... def __init__(self, guest): |
4945 | @@ -3197,7 +3971,7 @@ | |||
4946 | 3197 | ... | 3971 | ... |
4947 | 3198 | ... def register(self): | 3972 | ... def register(self): |
4948 | 3199 | ... next_id = get_next_id() | 3973 | ... next_id = get_next_id() |
4950 | 3200 | ... guests_db[next_id] = { | 3974 | ... bookings_db[next_id] = { |
4951 | 3201 | ... 'name': guest.name, | 3975 | ... 'name': guest.name, |
4952 | 3202 | ... 'place': guest.place, | 3976 | ... 'place': guest.place, |
4953 | 3203 | ... 'phone': guest.phone | 3977 | ... 'phone': guest.phone |
4954 | @@ -3212,32 +3986,50 @@ | |||
4955 | 3212 | ... self.place = place | 3986 | ... self.place = place |
4956 | 3213 | 3987 | ||
4957 | 3214 | >>> jack = Guest("Jack", "Bangalore") | 3988 | >>> jack = Guest("Jack", "Bangalore") |
4959 | 3215 | >>> jack_registrar = GuestRegistrarNG(jack) | 3989 | >>> jack_frontdesk = FrontDeskNG(jack) |
4960 | 3216 | 3990 | ||
4962 | 3217 | >>> IRegistrar.providedBy(jack_registrar) | 3991 | >>> IDesk.providedBy(jack_frontdesk) |
4963 | 3218 | True | 3992 | True |
4964 | 3219 | 3993 | ||
4965 | 3220 | >>> from zope.component import getGlobalSiteManager | 3994 | >>> from zope.component import getGlobalSiteManager |
4966 | 3221 | >>> gsm = getGlobalSiteManager() | 3995 | >>> gsm = getGlobalSiteManager() |
4969 | 3222 | >>> gsm.registerAdapter(GuestRegistrarNG, | 3996 | >>> gsm.registerAdapter(FrontDeskNG, |
4970 | 3223 | ... (IGuest,), IRegistrar, 'ng') | 3997 | ... (IGuest,), IDesk, 'ng') |
4971 | 3224 | 3998 | ||
4974 | 3225 | >>> queryAdapter(jack, IRegistrar, 'ng') #doctest: +ELLIPSIS | 3999 | >>> queryAdapter(jack, IDesk, 'ng') #doctest: +ELLIPSIS |
4975 | 3226 | <GuestRegistrarNG object at ...> | 4000 | <FrontDeskNG object at ...> |
4976 | 3227 | 4001 | ||
4977 | 3228 | 4002 | ||
4978 | 3229 | queryAdapterInContext | 4003 | queryAdapterInContext |
4979 | 3230 | ~~~~~~~~~~~~~~~~~~~~~ | 4004 | ~~~~~~~~~~~~~~~~~~~~~ |
4980 | 3231 | 4005 | ||
4987 | 3232 | Instead of this function, use `context` argument of `queryAdapter`_ | 4006 | Recherche pour un objet un adaptateur spécial vers une interface. |
4988 | 3233 | function. | 4007 | |
4989 | 3234 | 4008 | NOTE : cette méthode ne doit être utilisée que si un contexte personnalisé doit | |
4990 | 3235 | - Location: ``zope.component`` | 4009 | être fourni lors d'une recherche de composant personnalisée. Sinon, appelez |
4991 | 3236 | 4010 | l'interface comme ci-dessous :: | |
4992 | 3237 | - Signature: `queryAdapterInContext(object, interface, context, | 4011 | |
4993 | 4012 | interface(object, default) | ||
4994 | 4013 | |||
4995 | 4014 | Renvoie un adaptateur qui peut s'adapter à l'objet et fournir l'interface. Si | ||
4996 | 4015 | aucun adaptateur n'est fourni, la valeur par défaut est renvoyée. | ||
4997 | 4016 | |||
4998 | 4017 | Le contexte est adapté à IServiceService, et ce service d'adaptateurs, fourni par | ||
4999 | 4018 | l'adaptateur, est utilisé. | ||
5000 | 4019 |
The diff has been truncated for viewing.