Merge lp:~kissiel/checkbox/validation-rework into lp:checkbox
- validation-rework
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Sylvain Pineau |
Approved revision: | 4514 |
Merged at revision: | 4511 |
Proposed branch: | lp:~kissiel/checkbox/validation-rework |
Merge into: | lp:checkbox |
Diff against target: |
969 lines (+222/-242) 12 files modified
plainbox/plainbox/impl/unit/category.py (+6/-22) plainbox/plainbox/impl/unit/concrete_validators.py (+57/-0) plainbox/plainbox/impl/unit/exporter.py (+12/-22) plainbox/plainbox/impl/unit/file.py (+2/-7) plainbox/plainbox/impl/unit/job.py (+48/-72) plainbox/plainbox/impl/unit/manifest.py (+11/-14) plainbox/plainbox/impl/unit/packaging.py (+6/-6) plainbox/plainbox/impl/unit/template.py (+8/-8) plainbox/plainbox/impl/unit/testplan.py (+21/-32) plainbox/plainbox/impl/unit/unit.py (+14/-47) plainbox/plainbox/impl/unit/unit_with_id.py (+7/-12) plainbox/plainbox/impl/unit/validators.py (+30/-0) |
To merge this branch: | bzr merge lp:~kissiel/checkbox/validation-rework |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sylvain Pineau | Approve | ||
Review via email: mp+307082@code.launchpad.net |
Commit message
Description of the change
This MR refactors validation a bit. Three goals achieved here:
1) readability improvements (my opinion)
2) better performance (every plainbox invocation runs validation, the code on this branch runs a few percent faster)
3) less code!
4) more in line with zen of python
Important change here is what field_validators are. Previously this could have been an instance of a validator, a type of a validator or list of any of the above. This branch makes it instance-only.
In terms of testing, there should be no tangible changes in how *boxes work.
Sylvain Pineau (sylvain-pineau) wrote : | # |
Maciej Kisielewski (kissiel) wrote : | # |
This way present() would have to be a function yielding a concrete_validator (a constructor, really), so I wanted to stick to explicit and very oop-clear rules.
Right?
Sylvain Pineau (sylvain-pineau) wrote : | # |
It's ok and I like the new syntax a lot. It's finally good to have the old way in a few places in case we want to change severity (as a example). But getting rid of all those lambdas is a bug win.
+1
Sylvain Pineau (sylvain-pineau) wrote : | # |
s/bug/big hehe
Preview Diff
1 | === modified file 'plainbox/plainbox/impl/unit/category.py' |
2 | --- plainbox/plainbox/impl/unit/category.py 2016-05-11 14:36:13 +0000 |
3 | +++ plainbox/plainbox/impl/unit/category.py 2016-09-28 20:21:08 +0000 |
4 | @@ -30,16 +30,10 @@ |
5 | |
6 | import logging |
7 | |
8 | -from plainbox.i18n import gettext as _ |
9 | from plainbox.i18n import gettext_noop as N_ |
10 | from plainbox.impl.symbol import SymbolDef |
11 | +from plainbox.impl.unit import concrete_validators |
12 | from plainbox.impl.unit.unit_with_id import UnitWithId |
13 | -from plainbox.impl.unit.validators import CorrectFieldValueValidator |
14 | -from plainbox.impl.unit.validators import PresentFieldValidator |
15 | -from plainbox.impl.unit.validators import TemplateVariantFieldValidator |
16 | -from plainbox.impl.unit.validators import TranslatableFieldValidator |
17 | -from plainbox.impl.validation import Problem |
18 | -from plainbox.impl.validation import Severity |
19 | |
20 | __all__ = ['CategoryUnit'] |
21 | |
22 | @@ -108,20 +102,10 @@ |
23 | |
24 | field_validators = { |
25 | fields.name: [ |
26 | - TranslatableFieldValidator, |
27 | - TemplateVariantFieldValidator, |
28 | - PresentFieldValidator, |
29 | - # We want the name to be a single line |
30 | - CorrectFieldValueValidator( |
31 | - lambda name: name.count("\n") == 0, |
32 | - Problem.wrong, Severity.warning, |
33 | - message=_("please use only one line"), |
34 | - onlyif=lambda unit: unit.name is not None), |
35 | - # We want the name to be relatively short |
36 | - CorrectFieldValueValidator( |
37 | - lambda name: len(name) <= 80, |
38 | - Problem.wrong, Severity.warning, |
39 | - message=_("please stay under 80 characters"), |
40 | - onlyif=lambda unit: unit.name is not None), |
41 | + concrete_validators.translatable, |
42 | + concrete_validators.templateVariant, |
43 | + concrete_validators.present, |
44 | + concrete_validators.oneLine, |
45 | + concrete_validators.shortValue, |
46 | ] |
47 | } |
48 | |
49 | === added file 'plainbox/plainbox/impl/unit/concrete_validators.py' |
50 | --- plainbox/plainbox/impl/unit/concrete_validators.py 1970-01-01 00:00:00 +0000 |
51 | +++ plainbox/plainbox/impl/unit/concrete_validators.py 2016-09-28 20:21:08 +0000 |
52 | @@ -0,0 +1,57 @@ |
53 | +# This file is part of Checkbox. |
54 | +# |
55 | +# Copyright 2016 Canonical Ltd. |
56 | +# Written by: |
57 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
58 | +# |
59 | +# Checkbox is free software: you can redistribute it and/or modify |
60 | +# it under the terms of the GNU General Public License version 3, |
61 | +# as published by the Free Software Foundation. |
62 | +# |
63 | +# Checkbox is distributed in the hope that it will be useful, |
64 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
65 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
66 | +# GNU General Public License for more details. |
67 | +# |
68 | +# You should have received a copy of the GNU General Public License |
69 | +# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
70 | +""" |
71 | +:mod:`plainbox.impl.unit.concrete_validators` -- common validator instances |
72 | +=========================================================================== |
73 | + |
74 | +This module gathers common validator instances that can be shared among |
75 | +multiple unit types as their field_validators. |
76 | +""" |
77 | + |
78 | +from plainbox.i18n import gettext as _ |
79 | +from plainbox.impl.unit.validators import CorrectFieldValueValidator |
80 | +from plainbox.impl.validation import Problem |
81 | +from plainbox.impl.validation import Severity |
82 | + |
83 | +from plainbox.impl.unit.validators import PresentFieldValidator |
84 | +from plainbox.impl.unit.validators import TemplateInvariantFieldValidator |
85 | +from plainbox.impl.unit.validators import TemplateVariantFieldValidator |
86 | +from plainbox.impl.unit.validators import TranslatableFieldValidator |
87 | +from plainbox.impl.unit.validators import UntranslatableFieldValidator |
88 | + |
89 | + |
90 | +translatable = TranslatableFieldValidator() |
91 | +templateVariant = TemplateVariantFieldValidator() |
92 | +templateInvariant = TemplateInvariantFieldValidator() |
93 | +untranslatable = UntranslatableFieldValidator() |
94 | +present = PresentFieldValidator() |
95 | + |
96 | +localDeprecated = CorrectFieldValueValidator( |
97 | + lambda plugin: plugin != 'local', Problem.deprecated, Severity.advice, |
98 | + message=_("please migrate to job templates, see plainbox-template-unit(7)" |
99 | + " for details")) |
100 | + |
101 | +oneLine = CorrectFieldValueValidator( |
102 | + lambda field: field is not None and field.count("\n") == 0, |
103 | + Problem.wrong, Severity.warning, |
104 | + message=_("please use only one line")) |
105 | + |
106 | +shortValue = CorrectFieldValueValidator( |
107 | + lambda field: field is not None and len(field) <= 80, |
108 | + Problem.wrong, Severity.warning, |
109 | + message=_("please stay under 80 characters")) |
110 | |
111 | === modified file 'plainbox/plainbox/impl/unit/exporter.py' |
112 | --- plainbox/plainbox/impl/unit/exporter.py 2015-06-25 11:52:05 +0000 |
113 | +++ plainbox/plainbox/impl/unit/exporter.py 2016-09-28 20:21:08 +0000 |
114 | @@ -1,8 +1,9 @@ |
115 | # This file is part of Checkbox. |
116 | # |
117 | -# Copyright 2015 Canonical Ltd. |
118 | +# Copyright 2015-2016 Canonical Ltd. |
119 | # Written by: |
120 | # Sylvain Pineau <sylvain.pineau@canonical.com> |
121 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
122 | # |
123 | # Checkbox is free software: you can redistribute it and/or modify |
124 | # it under the terms of the GNU General Public License version 3, |
125 | @@ -26,11 +27,10 @@ |
126 | |
127 | from plainbox.i18n import gettext as _ |
128 | from plainbox.impl.symbol import SymbolDef |
129 | +from plainbox.impl.unit import concrete_validators |
130 | from plainbox.impl.unit.unit_with_id import UnitWithId |
131 | from plainbox.impl.unit.validators import CorrectFieldValueValidator |
132 | from plainbox.impl.unit.validators import PresentFieldValidator |
133 | -from plainbox.impl.unit.validators import TranslatableFieldValidator |
134 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
135 | from plainbox.impl.validation import Problem |
136 | from plainbox.impl.validation import Severity |
137 | |
138 | @@ -115,40 +115,30 @@ |
139 | field_validators = { |
140 | fields.summary: [ |
141 | PresentFieldValidator(severity=Severity.advice), |
142 | - TranslatableFieldValidator, |
143 | - # We want the summary to be a single line |
144 | - CorrectFieldValueValidator( |
145 | - lambda summary: summary.count("\n") == 0, |
146 | - Problem.wrong, Severity.warning, |
147 | - message=_("please use only one line"), |
148 | - onlyif=lambda unit: unit.summary is not None), |
149 | - # We want the summary to be relatively short |
150 | - CorrectFieldValueValidator( |
151 | - lambda summary: len(summary) <= 80, |
152 | - Problem.wrong, Severity.warning, |
153 | - message=_("please stay under 80 characters"), |
154 | - onlyif=lambda unit: unit.summary is not None), |
155 | + concrete_validators.translatable, |
156 | + concrete_validators.oneLine, |
157 | + concrete_validators.shortValue, |
158 | ], |
159 | fields.entry_point: [ |
160 | - PresentFieldValidator, |
161 | - UntranslatableFieldValidator, |
162 | + concrete_validators.present, |
163 | + concrete_validators.untranslatable, |
164 | CorrectFieldValueValidator( |
165 | lambda entry_point: pkg_resources.load_entry_point( |
166 | 'plainbox', 'plainbox.exporter', entry_point), |
167 | Problem.wrong, Severity.error), |
168 | ], |
169 | fields.file_extension: [ |
170 | - PresentFieldValidator, |
171 | - UntranslatableFieldValidator, |
172 | + concrete_validators.present, |
173 | + concrete_validators.untranslatable, |
174 | CorrectFieldValueValidator( |
175 | lambda extension: re.search("^[\w\.\-]+$", extension), |
176 | Problem.syntax_error, Severity.error), |
177 | ], |
178 | fields.options: [ |
179 | - UntranslatableFieldValidator, |
180 | + concrete_validators.untranslatable, |
181 | ], |
182 | fields.data: [ |
183 | - UntranslatableFieldValidator, |
184 | + concrete_validators.untranslatable, |
185 | CorrectFieldValueValidator( |
186 | lambda value, unit: json.loads(value), |
187 | Problem.syntax_error, Severity.error, |
188 | |
189 | === modified file 'plainbox/plainbox/impl/unit/file.py' |
190 | --- plainbox/plainbox/impl/unit/file.py 2015-02-06 15:30:54 +0000 |
191 | +++ plainbox/plainbox/impl/unit/file.py 2016-09-28 20:21:08 +0000 |
192 | @@ -30,6 +30,7 @@ |
193 | from plainbox.impl.unit.job import propertywithsymbols |
194 | from plainbox.impl.unit.unit import Unit, UnitValidator |
195 | from plainbox.impl.unit.validators import CorrectFieldValueValidator |
196 | +from plainbox.impl.unit.validators import MemberOfFieldValidator |
197 | from plainbox.impl.validation import Problem |
198 | from plainbox.impl.validation import Severity |
199 | |
200 | @@ -146,11 +147,5 @@ |
201 | 'faq.html#faq-1' |
202 | )), |
203 | ], |
204 | - fields.role: [ |
205 | - CorrectFieldValueValidator( |
206 | - lambda value: value in FileRole.get_all_symbols(), |
207 | - message=_('valid values are: {}').format( |
208 | - ', '.join(str(sym) for sym in sorted( |
209 | - FileRole.get_all_symbols())))), |
210 | - ] |
211 | + fields.role: [MemberOfFieldValidator(FileRole.get_all_symbols())] |
212 | } |
213 | |
214 | === modified file 'plainbox/plainbox/impl/unit/job.py' |
215 | --- plainbox/plainbox/impl/unit/job.py 2016-09-22 18:53:53 +0000 |
216 | +++ plainbox/plainbox/impl/unit/job.py 2016-09-28 20:21:08 +0000 |
217 | @@ -1,9 +1,10 @@ |
218 | # This file is part of Checkbox. |
219 | # |
220 | -# Copyright 2012-2014 Canonical Ltd. |
221 | +# Copyright 2012-2016 Canonical Ltd. |
222 | # Written by: |
223 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
224 | # Sylvain Pineau <sylvain.pineau@canonical.com> |
225 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
226 | # |
227 | # Checkbox is free software: you can redistribute it and/or modify |
228 | # it under the terms of the GNU General Public License version 3, |
229 | @@ -34,18 +35,17 @@ |
230 | from plainbox.impl.secure.origin import JobOutputTextSource |
231 | from plainbox.impl.secure.origin import Origin |
232 | from plainbox.impl.symbol import SymbolDef |
233 | +from plainbox.impl.unit import concrete_validators |
234 | from plainbox.impl.unit.unit_with_id import UnitWithId |
235 | from plainbox.impl.unit.validators import CorrectFieldValueValidator |
236 | from plainbox.impl.unit.validators import DeprecatedFieldValidator |
237 | +from plainbox.impl.unit.validators import MemberOfFieldValidator |
238 | from plainbox.impl.unit.validators import PresentFieldValidator |
239 | from plainbox.impl.unit.validators import ReferenceConstraint |
240 | from plainbox.impl.unit.validators import ShellProgramValidator |
241 | -from plainbox.impl.unit.validators import TemplateInvariantFieldValidator |
242 | -from plainbox.impl.unit.validators import TemplateVariantFieldValidator |
243 | -from plainbox.impl.unit.validators import TranslatableFieldValidator |
244 | from plainbox.impl.unit.validators import UnitReferenceValidator |
245 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
246 | from plainbox.impl.unit.validators import UselessFieldValidator |
247 | + |
248 | from plainbox.impl.validation import Problem |
249 | from plainbox.impl.validation import Severity |
250 | from plainbox.impl.xparsers import Error |
251 | @@ -700,51 +700,32 @@ |
252 | |
253 | field_validators = { |
254 | fields.name: [ |
255 | - UntranslatableFieldValidator, |
256 | - TemplateVariantFieldValidator, |
257 | + concrete_validators.untranslatable, |
258 | + concrete_validators.templateVariant, |
259 | DeprecatedFieldValidator( |
260 | _("use 'id' and 'summary' instead of 'name'")), |
261 | ], |
262 | # NOTE: 'id' validators are "inherited" so we don't have it here |
263 | fields.summary: [ |
264 | - TranslatableFieldValidator, |
265 | - TemplateVariantFieldValidator, |
266 | + concrete_validators.translatable, |
267 | + concrete_validators.templateVariant, |
268 | PresentFieldValidator(severity=Severity.advice), |
269 | - # We want the summary to be a single line |
270 | - CorrectFieldValueValidator( |
271 | - lambda summary: summary.count("\n") == 0, |
272 | - Problem.wrong, Severity.warning, |
273 | - message=_("please use only one line"), |
274 | - onlyif=lambda unit: unit.summary is not None), |
275 | - # We want the summary to be relatively short |
276 | - CorrectFieldValueValidator( |
277 | - lambda summary: len(summary) <= 80, |
278 | - Problem.wrong, Severity.warning, |
279 | - message=_("please stay under 80 characters"), |
280 | - onlyif=lambda unit: unit.summary is not None), |
281 | + concrete_validators.oneLine, |
282 | + concrete_validators.shortValue, |
283 | ], |
284 | fields.plugin: [ |
285 | - UntranslatableFieldValidator, |
286 | - TemplateInvariantFieldValidator, |
287 | - PresentFieldValidator, |
288 | - CorrectFieldValueValidator( |
289 | - lambda plugin: ( |
290 | - plugin in JobDefinition.plugin.get_all_symbols()), |
291 | - message=_('valid values are: {}').format( |
292 | - ', '.join(str(sym) for sym in sorted( |
293 | - _PluginValues.get_all_symbols())))), |
294 | - CorrectFieldValueValidator( |
295 | - lambda plugin: plugin != 'local', |
296 | - Problem.deprecated, Severity.advice, |
297 | - message=_("please migrate to job templates, " |
298 | - "see plainbox-template-unit(7) for details")), |
299 | + concrete_validators.untranslatable, |
300 | + concrete_validators.templateInvariant, |
301 | + concrete_validators.present, |
302 | + MemberOfFieldValidator(_PluginValues.get_all_symbols()), |
303 | + concrete_validators.localDeprecated, |
304 | CorrectFieldValueValidator( |
305 | lambda plugin: plugin != 'user-verify', |
306 | Problem.deprecated, Severity.advice, |
307 | message=_("please migrate to user-interact-verify")), |
308 | ], |
309 | fields.command: [ |
310 | - UntranslatableFieldValidator, |
311 | + concrete_validators.untranslatable, |
312 | # All jobs except for manual must have a command |
313 | PresentFieldValidator( |
314 | message=_("command is mandatory for non-manual jobs"), |
315 | @@ -768,11 +749,11 @@ |
316 | " instead of CHECKBOX_DATA"), |
317 | onlyif=lambda unit: unit.command is not None), |
318 | # We want to catch silly mistakes that shlex can detect |
319 | - ShellProgramValidator, |
320 | + ShellProgramValidator(), |
321 | ], |
322 | fields.description: [ |
323 | - TranslatableFieldValidator, |
324 | - TemplateVariantFieldValidator, |
325 | + concrete_validators.translatable, |
326 | + concrete_validators.templateVariant, |
327 | # Description is mandatory for manual jobs |
328 | PresentFieldValidator( |
329 | message=_("manual jobs must have a description field, or a" |
330 | @@ -796,7 +777,7 @@ |
331 | unit.verification is None))), |
332 | ], |
333 | fields.purpose: [ |
334 | - TranslatableFieldValidator, |
335 | + concrete_validators.translatable, |
336 | PresentFieldValidator( |
337 | severity=Severity.advice, |
338 | message=("please use purpose, steps, and verification" |
339 | @@ -807,7 +788,7 @@ |
340 | unit.get_record_value('summary') is None), |
341 | ], |
342 | fields.steps: [ |
343 | - TranslatableFieldValidator, |
344 | + concrete_validators.translatable, |
345 | PresentFieldValidator( |
346 | severity=Severity.advice, |
347 | message=("please use purpose, steps, and verification" |
348 | @@ -817,7 +798,7 @@ |
349 | unit.startup_user_interaction_required), |
350 | ], |
351 | fields.verification: [ |
352 | - TranslatableFieldValidator, |
353 | + concrete_validators.translatable, |
354 | PresentFieldValidator( |
355 | severity=Severity.advice, |
356 | message=("please use purpose, steps, and verification" |
357 | @@ -827,8 +808,8 @@ |
358 | 'manual', 'user-verify', 'user-interact-verify')), |
359 | ], |
360 | fields.user: [ |
361 | - UntranslatableFieldValidator, |
362 | - TemplateInvariantFieldValidator, |
363 | + concrete_validators.untranslatable, |
364 | + concrete_validators.templateInvariant, |
365 | # User should be either None or 'root' |
366 | CorrectFieldValueValidator( |
367 | message=_("user can only be 'root'"), |
368 | @@ -839,16 +820,16 @@ |
369 | onlyif=lambda unit: unit.command is None) |
370 | ], |
371 | fields.environ: [ |
372 | - UntranslatableFieldValidator, |
373 | - TemplateInvariantFieldValidator, |
374 | + concrete_validators.untranslatable, |
375 | + concrete_validators.templateInvariant, |
376 | # Environ is useless without a command to run |
377 | UselessFieldValidator( |
378 | message=_("environ without a command makes no sense"), |
379 | onlyif=lambda unit: unit.command is None), |
380 | ], |
381 | fields.estimated_duration: [ |
382 | - UntranslatableFieldValidator, |
383 | - TemplateInvariantFieldValidator, |
384 | + concrete_validators.untranslatable, |
385 | + concrete_validators.templateInvariant, |
386 | PresentFieldValidator( |
387 | severity=Severity.advice, |
388 | onlyif=lambda unit: 'simple' not in unit.get_flag_set() |
389 | @@ -860,7 +841,7 @@ |
390 | unit.get_record_value('estimated_duration'))), |
391 | ], |
392 | fields.depends: [ |
393 | - UntranslatableFieldValidator, |
394 | + concrete_validators.untranslatable, |
395 | CorrectFieldValueValidator( |
396 | lambda value, unit: ( |
397 | unit.get_direct_dependencies() is not None)), |
398 | @@ -874,7 +855,7 @@ |
399 | # onlyif job itself is not deprecated |
400 | ], |
401 | fields.after: [ |
402 | - UntranslatableFieldValidator, |
403 | + concrete_validators.untranslatable, |
404 | CorrectFieldValueValidator( |
405 | lambda value, unit: ( |
406 | unit.get_after_dependencies() is not None)), |
407 | @@ -886,7 +867,7 @@ |
408 | message=_("the referenced unit is not a job"))]) |
409 | ], |
410 | fields.requires: [ |
411 | - UntranslatableFieldValidator, |
412 | + concrete_validators.untranslatable, |
413 | CorrectFieldValueValidator( |
414 | lambda value, unit: unit.get_resource_program(), |
415 | onlyif=lambda unit: unit.requires is not None), |
416 | @@ -908,16 +889,16 @@ |
417 | # onlyif job itself is not deprecated |
418 | ], |
419 | fields.shell: [ |
420 | - UntranslatableFieldValidator, |
421 | - TemplateInvariantFieldValidator, |
422 | + concrete_validators.untranslatable, |
423 | + concrete_validators.templateInvariant, |
424 | # Shell should be only '/bin/sh', or None (which gives bash) |
425 | - CorrectFieldValueValidator( |
426 | - lambda shell: shell in ('/bin/sh', '/bin/bash', 'bash'), |
427 | + MemberOfFieldValidator( |
428 | + ['/bin/sh', '/bin/bash', 'bash'], |
429 | message=_("only /bin/sh and /bin/bash are allowed")), |
430 | ], |
431 | fields.imports: [ |
432 | - UntranslatableFieldValidator, |
433 | - TemplateInvariantFieldValidator, |
434 | + concrete_validators.untranslatable, |
435 | + concrete_validators.templateInvariant, |
436 | CorrectFieldValueValidator( |
437 | lambda value, unit: ( |
438 | list(unit.get_imported_jobs()) is not None)), |
439 | @@ -933,8 +914,8 @@ |
440 | # onlyif job itself is not deprecated |
441 | ], |
442 | fields.category_id: [ |
443 | - UntranslatableFieldValidator, |
444 | - TemplateInvariantFieldValidator, |
445 | + concrete_validators.untranslatable, |
446 | + concrete_validators.templateInvariant, |
447 | UnitReferenceValidator( |
448 | lambda unit: ( |
449 | [unit.get_category_id()] if unit.category_id else ()), |
450 | @@ -948,8 +929,8 @@ |
451 | # onlyif job itself is not deprecated |
452 | ], |
453 | fields.flags: [ |
454 | - UntranslatableFieldValidator, |
455 | - TemplateInvariantFieldValidator, |
456 | + concrete_validators.untranslatable, |
457 | + concrete_validators.templateInvariant, |
458 | CorrectFieldValueValidator( |
459 | lambda value, unit: ( |
460 | 'simple' in unit.get_flag_set() or |
461 | @@ -999,8 +980,8 @@ |
462 | onlyif=lambda unit: unit.command is None), |
463 | ], |
464 | fields.qml_file: [ |
465 | - UntranslatableFieldValidator, |
466 | - TemplateInvariantFieldValidator, |
467 | + concrete_validators.untranslatable, |
468 | + concrete_validators.templateInvariant, |
469 | PresentFieldValidator( |
470 | onlyif=lambda unit: unit.plugin == 'qml'), |
471 | CorrectFieldValueValidator( |
472 | @@ -1016,14 +997,9 @@ |
473 | unit.qml_file)), |
474 | ], |
475 | fields.certification_status: [ |
476 | - UntranslatableFieldValidator, |
477 | - TemplateInvariantFieldValidator, |
478 | - CorrectFieldValueValidator( |
479 | - lambda certification_status: ( |
480 | - certification_status in |
481 | - _CertificationStatusValues.get_all_symbols()), |
482 | - message=_('valid values are: {}').format( |
483 | - ', '.join(str(sym) for sym in sorted( |
484 | - _CertificationStatusValues.get_all_symbols())))), |
485 | + concrete_validators.untranslatable, |
486 | + concrete_validators.templateInvariant, |
487 | + MemberOfFieldValidator( |
488 | + _CertificationStatusValues.get_all_symbols()), |
489 | ], |
490 | } |
491 | |
492 | === modified file 'plainbox/plainbox/impl/unit/manifest.py' |
493 | --- plainbox/plainbox/impl/unit/manifest.py 2015-03-30 17:35:30 +0000 |
494 | +++ plainbox/plainbox/impl/unit/manifest.py 2016-09-28 20:21:08 +0000 |
495 | @@ -1,8 +1,9 @@ |
496 | # This file is part of Checkbox. |
497 | # |
498 | -# Copyright 2012-2015 Canonical Ltd. |
499 | +# Copyright 2012-2016 Canonical Ltd. |
500 | # Written by: |
501 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
502 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
503 | # |
504 | # Checkbox is free software: you can redistribute it and/or modify |
505 | # it under the terms of the GNU General Public License version 3, |
506 | @@ -20,12 +21,9 @@ |
507 | import logging |
508 | |
509 | from plainbox.impl.symbol import SymbolDef |
510 | +from plainbox.impl.unit import concrete_validators |
511 | from plainbox.impl.unit.unit_with_id import UnitWithId |
512 | -from plainbox.impl.unit.validators import CorrectFieldValueValidator |
513 | -from plainbox.impl.unit.validators import PresentFieldValidator |
514 | -from plainbox.impl.unit.validators import TemplateVariantFieldValidator |
515 | -from plainbox.impl.unit.validators import TranslatableFieldValidator |
516 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
517 | +from plainbox.impl.unit.validators import MemberOfFieldValidator |
518 | |
519 | logger = logging.getLogger("plainbox.unit.manifest") |
520 | |
521 | @@ -98,20 +96,19 @@ |
522 | |
523 | field_validators = { |
524 | fields.name: [ |
525 | - TranslatableFieldValidator, |
526 | - TemplateVariantFieldValidator, |
527 | - PresentFieldValidator, |
528 | + concrete_validators.translatable, |
529 | + concrete_validators.templateVariant, |
530 | + concrete_validators.present, |
531 | ], |
532 | fields.value_type: [ |
533 | - UntranslatableFieldValidator, |
534 | - PresentFieldValidator(), |
535 | - CorrectFieldValueValidator( |
536 | - lambda value_type: value_type in ('bool', 'natural')), |
537 | + concrete_validators.untranslatable, |
538 | + concrete_validators.present, |
539 | + MemberOfFieldValidator(['bool', 'natural']), |
540 | ], |
541 | fields.value_unit: [ |
542 | # OPTIONAL |
543 | ], |
544 | fields.resource_key: [ |
545 | - UntranslatableFieldValidator, |
546 | + concrete_validators.untranslatable |
547 | ] |
548 | } |
549 | |
550 | === modified file 'plainbox/plainbox/impl/unit/packaging.py' |
551 | --- plainbox/plainbox/impl/unit/packaging.py 2016-05-20 13:54:59 +0000 |
552 | +++ plainbox/plainbox/impl/unit/packaging.py 2016-09-28 20:21:08 +0000 |
553 | @@ -1,8 +1,9 @@ |
554 | # This file is part of Checkbox. |
555 | # |
556 | -# Copyright 2012-2015 Canonical Ltd. |
557 | +# Copyright 2012-2016 Canonical Ltd. |
558 | # Written by: |
559 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
560 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
561 | # |
562 | # Checkbox is free software: you can redistribute it and/or modify |
563 | # it under the terms of the GNU General Public License version 3, |
564 | @@ -120,9 +121,8 @@ |
565 | from plainbox.i18n import gettext as _ |
566 | from plainbox.impl.device import get_os_release |
567 | from plainbox.impl.symbol import SymbolDef |
568 | +from plainbox.impl.unit import concrete_validators |
569 | from plainbox.impl.unit.unit import Unit |
570 | -from plainbox.impl.unit.validators import PresentFieldValidator |
571 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
572 | |
573 | _logger = logging.getLogger("plainbox.unit.packaging") |
574 | |
575 | @@ -164,11 +164,11 @@ |
576 | |
577 | field_validators = { |
578 | fields.os_id: [ |
579 | - UntranslatableFieldValidator, |
580 | - PresentFieldValidator, |
581 | + concrete_validators.untranslatable, |
582 | + concrete_validators.present, |
583 | ], |
584 | fields.os_version_id: [ |
585 | - UntranslatableFieldValidator, |
586 | + concrete_validators.untranslatable, |
587 | ], |
588 | } |
589 | |
590 | |
591 | === modified file 'plainbox/plainbox/impl/unit/template.py' |
592 | --- plainbox/plainbox/impl/unit/template.py 2016-05-11 14:36:13 +0000 |
593 | +++ plainbox/plainbox/impl/unit/template.py 2016-09-28 20:21:08 +0000 |
594 | @@ -1,8 +1,9 @@ |
595 | # This file is part of Checkbox. |
596 | # |
597 | -# Copyright 2012-2014 Canonical Ltd. |
598 | +# Copyright 2012-2016 Canonical Ltd. |
599 | # Written by: |
600 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
601 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
602 | # |
603 | # Checkbox is free software: you can redistribute it and/or modify |
604 | # it under the terms of the GNU General Public License version 3, |
605 | @@ -32,14 +33,13 @@ |
606 | from plainbox.impl.secure.origin import Origin |
607 | from plainbox.impl.symbol import SymbolDef |
608 | from plainbox.impl.unit import all_units |
609 | +from plainbox.impl.unit import concrete_validators |
610 | from plainbox.impl.unit import get_accessed_parameters |
611 | from plainbox.impl.unit.unit import Unit |
612 | from plainbox.impl.unit.unit import UnitValidator |
613 | from plainbox.impl.unit.validators import CorrectFieldValueValidator |
614 | -from plainbox.impl.unit.validators import PresentFieldValidator |
615 | from plainbox.impl.unit.validators import ReferenceConstraint |
616 | from plainbox.impl.unit.validators import UnitReferenceValidator |
617 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
618 | from plainbox.impl.validation import Problem |
619 | from plainbox.impl.validation import Severity |
620 | |
621 | @@ -427,7 +427,7 @@ |
622 | |
623 | field_validators = { |
624 | fields.template_unit: [ |
625 | - UntranslatableFieldValidator, |
626 | + concrete_validators.untranslatable, |
627 | CorrectFieldValueValidator( |
628 | lambda value, unit: ( |
629 | unit.get_record_value('template-unit') is not None), |
630 | @@ -436,8 +436,8 @@ |
631 | " unit type")), |
632 | ], |
633 | fields.template_resource: [ |
634 | - UntranslatableFieldValidator, |
635 | - PresentFieldValidator, |
636 | + concrete_validators.untranslatable, |
637 | + concrete_validators.present, |
638 | UnitReferenceValidator( |
639 | lambda unit: ( |
640 | [unit.resource_id] if unit.resource_id else []), |
641 | @@ -457,7 +457,7 @@ |
642 | # onlyif job itself is not deprecated |
643 | ], |
644 | fields.template_filter: [ |
645 | - UntranslatableFieldValidator, |
646 | + concrete_validators.untranslatable, |
647 | # All templates need a valid (or empty) template filter |
648 | CorrectFieldValueValidator( |
649 | lambda value, unit: unit.get_filter_program(), |
650 | @@ -465,7 +465,7 @@ |
651 | # TODO: must refer to the same job as template-resource |
652 | ], |
653 | fields.template_imports: [ |
654 | - UntranslatableFieldValidator, |
655 | + concrete_validators.untranslatable, |
656 | CorrectFieldValueValidator( |
657 | lambda value, unit: ( |
658 | list(unit.get_imported_jobs()) is not None)), |
659 | |
660 | === modified file 'plainbox/plainbox/impl/unit/testplan.py' |
661 | --- plainbox/plainbox/impl/unit/testplan.py 2016-06-09 20:12:35 +0000 |
662 | +++ plainbox/plainbox/impl/unit/testplan.py 2016-09-28 20:21:08 +0000 |
663 | @@ -1,8 +1,9 @@ |
664 | # This file is part of Checkbox. |
665 | # |
666 | -# Copyright 2012-2014 Canonical Ltd. |
667 | +# Copyright 2012-2016 Canonical Ltd. |
668 | # Written by: |
669 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
670 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
671 | # |
672 | # Checkbox is free software: you can redistribute it and/or modify |
673 | # it under the terms of the GNU General Public License version 3, |
674 | @@ -32,16 +33,14 @@ |
675 | from plainbox.impl.secure.qualifiers import OperatorMatcher |
676 | from plainbox.impl.secure.qualifiers import PatternMatcher |
677 | from plainbox.impl.symbol import SymbolDef |
678 | +from plainbox.impl.unit import concrete_validators |
679 | from plainbox.impl.unit.unit_with_id import UnitWithId |
680 | from plainbox.impl.unit.validators import CorrectFieldValueValidator |
681 | from plainbox.impl.unit.validators import FieldValidatorBase |
682 | from plainbox.impl.unit.validators import PresentFieldValidator |
683 | from plainbox.impl.unit.validators import ReferenceConstraint |
684 | from plainbox.impl.unit.validators import TemplateInvariantFieldValidator |
685 | -from plainbox.impl.unit.validators import TemplateVariantFieldValidator |
686 | -from plainbox.impl.unit.validators import TranslatableFieldValidator |
687 | from plainbox.impl.unit.validators import UnitReferenceValidator |
688 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
689 | from plainbox.impl.unit.validators import compute_value_map |
690 | from plainbox.impl.validation import Problem |
691 | from plainbox.impl.validation import Severity |
692 | @@ -609,40 +608,30 @@ |
693 | |
694 | field_validators = { |
695 | fields.name: [ |
696 | - TranslatableFieldValidator, |
697 | - TemplateVariantFieldValidator, |
698 | - PresentFieldValidator, |
699 | - # We want the summary to be a single line |
700 | - CorrectFieldValueValidator( |
701 | - lambda name: name.count("\n") == 0, |
702 | - Problem.wrong, Severity.warning, |
703 | - message=_("please use only one line"), |
704 | - onlyif=lambda unit: unit.name is not None), |
705 | - # We want the summary to be relatively short |
706 | - CorrectFieldValueValidator( |
707 | - lambda name: len(name) <= 80, |
708 | - Problem.wrong, Severity.warning, |
709 | - message=_("please stay under 80 characters"), |
710 | - onlyif=lambda unit: unit.name is not None), |
711 | + concrete_validators.translatable, |
712 | + concrete_validators.templateVariant, |
713 | + concrete_validators.present, |
714 | + concrete_validators.oneLine, |
715 | + concrete_validators.shortValue, |
716 | ], |
717 | fields.description: [ |
718 | - TranslatableFieldValidator, |
719 | - TemplateVariantFieldValidator, |
720 | + concrete_validators.translatable, |
721 | + concrete_validators.templateVariant, |
722 | PresentFieldValidator( |
723 | severity=Severity.advice, |
724 | onlyif=lambda unit: unit.virtual is False), |
725 | ], |
726 | fields.include: [ |
727 | - NonEmptyPatternIntersectionValidator, |
728 | - PresentFieldValidator(), |
729 | + NonEmptyPatternIntersectionValidator(), |
730 | + concrete_validators.present, |
731 | ], |
732 | fields.mandatory_include: [ |
733 | - NonEmptyPatternIntersectionValidator, |
734 | - NoBaseIncludeValidator, |
735 | + NonEmptyPatternIntersectionValidator(), |
736 | + NoBaseIncludeValidator(), |
737 | ], |
738 | fields.bootstrap_include: [ |
739 | - UntranslatableFieldValidator, |
740 | - NoBaseIncludeValidator, |
741 | + concrete_validators.untranslatable, |
742 | + NoBaseIncludeValidator(), |
743 | UnitReferenceValidator( |
744 | lambda unit: unit.get_bootstrap_job_ids(), |
745 | constraints=[ |
746 | @@ -656,14 +645,14 @@ |
747 | "allowed in bootstrapping_include"))]) |
748 | ], |
749 | fields.exclude: [ |
750 | - NonEmptyPatternIntersectionValidator, |
751 | + NonEmptyPatternIntersectionValidator(), |
752 | ], |
753 | fields.nested_part: [ |
754 | - NonEmptyPatternIntersectionValidator, |
755 | + NonEmptyPatternIntersectionValidator(), |
756 | ], |
757 | fields.estimated_duration: [ |
758 | - UntranslatableFieldValidator, |
759 | - TemplateInvariantFieldValidator, |
760 | + concrete_validators.untranslatable, |
761 | + concrete_validators.templateInvariant, |
762 | PresentFieldValidator( |
763 | severity=Severity.advice, |
764 | onlyif=lambda unit: unit.virtual is False), |
765 | @@ -675,7 +664,7 @@ |
766 | unit.get_record_value('estimated_duration'))), |
767 | ], |
768 | fields.icon: [ |
769 | - UntranslatableFieldValidator, |
770 | + concrete_validators.untranslatable, |
771 | ], |
772 | fields.category_overrides: [ |
773 | # optional |
774 | |
775 | === modified file 'plainbox/plainbox/impl/unit/unit.py' |
776 | --- plainbox/plainbox/impl/unit/unit.py 2016-05-20 13:54:59 +0000 |
777 | +++ plainbox/plainbox/impl/unit/unit.py 2016-09-28 20:21:08 +0000 |
778 | @@ -1,8 +1,9 @@ |
779 | # This file is part of Checkbox. |
780 | # |
781 | -# Copyright 2012-2014 Canonical Ltd. |
782 | +# Copyright 2012-2016 Canonical Ltd. |
783 | # Written by: |
784 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
785 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
786 | # |
787 | # Checkbox is free software: you can redistribute it and/or modify |
788 | # it under the terms of the GNU General Public License version 3, |
789 | @@ -35,13 +36,12 @@ |
790 | from plainbox.impl.symbol import SymbolDef |
791 | from plainbox.impl.symbol import SymbolDefMeta |
792 | from plainbox.impl.symbol import SymbolDefNs |
793 | +from plainbox.impl.unit import concrete_validators |
794 | from plainbox.impl.unit import get_accessed_parameters |
795 | from plainbox.impl.unit.validators import IFieldValidator |
796 | from plainbox.impl.unit.validators import MultiUnitFieldIssue |
797 | from plainbox.impl.unit.validators import PresentFieldValidator |
798 | -from plainbox.impl.unit.validators import TemplateInvariantFieldValidator |
799 | from plainbox.impl.unit.validators import UnitFieldIssue |
800 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
801 | from plainbox.impl.validation import Problem |
802 | from plainbox.impl.validation import Severity |
803 | |
804 | @@ -77,9 +77,10 @@ |
805 | :returns: |
806 | A generator yielding subsequent issues |
807 | """ |
808 | - for field_validator, field in self.make_field_validators(unit): |
809 | - for issue in field_validator.check(self, unit, field): |
810 | - yield issue |
811 | + for field, validators in sorted(unit.Meta.field_validators.items()): |
812 | + for validator in validators: |
813 | + for issue in validator.check(self, unit, field): |
814 | + yield issue |
815 | |
816 | def check_in_context(self, unit, context): |
817 | """ |
818 | @@ -92,41 +93,11 @@ |
819 | :returns: |
820 | A generator yielding subsequent issues |
821 | """ |
822 | - for field_validator, field in self.make_field_validators(unit): |
823 | - for issue in field_validator.check_in_context( |
824 | - self, unit, field, context): |
825 | - yield issue |
826 | - |
827 | - def make_field_validators(self, unit): |
828 | - """ |
829 | - Convert unit meta-data to a sequence of validators |
830 | - |
831 | - :returns: |
832 | - A generator for pairs (field_validator, field) where |
833 | - field_validator is an instance of :class:`IFieldValidator` and |
834 | - field is a symbol with the field name. |
835 | - """ |
836 | - for field, spec in sorted(unit.Meta.field_validators.items()): |
837 | - if isinstance(spec, type): |
838 | - validator_list = [spec] |
839 | - elif isinstance(spec, list): |
840 | - validator_list = spec |
841 | - else: |
842 | - raise TypeError(_( |
843 | - "{}.Meta.fields[{!r}] is not a validator" |
844 | - ).format(unit.__class__.__name__, field)) |
845 | - for index, spec in enumerate(validator_list): |
846 | - # If it's a validator class, instantiate it |
847 | - if isinstance(spec, type) \ |
848 | - and issubclass(spec, IFieldValidator): |
849 | - yield spec(), field |
850 | - # If it's a validator instance, just return it |
851 | - elif isinstance(spec, IFieldValidator): |
852 | - yield spec, field |
853 | - else: |
854 | - raise TypeError(_( |
855 | - "{}.Meta.fields[{!r}][{}] is not a validator" |
856 | - ).format(unit.__class__.__name__, field, index)) |
857 | + for field, validators in sorted(unit.Meta.field_validators.items()): |
858 | + for validator in validators: |
859 | + for issue in validator.check_in_context( |
860 | + self, unit, field, context): |
861 | + yield issue |
862 | |
863 | def advice(self, unit, field, kind, message=None, *, offset=0, |
864 | origin=None): |
865 | @@ -840,12 +811,8 @@ |
866 | |
867 | field_validators = { |
868 | fields.unit: [ |
869 | - # We don't want anyone marking unit type up for translation |
870 | - UntranslatableFieldValidator, |
871 | - # We want each instantiated template to define same unit type |
872 | - TemplateInvariantFieldValidator, |
873 | - # We want to gently advise everyone to mark all units with |
874 | - # and explicit unit type so that we can disable default 'job' |
875 | + concrete_validators.untranslatable, |
876 | + concrete_validators.templateInvariant, |
877 | PresentFieldValidator( |
878 | severity=Severity.advice, |
879 | message=_("unit should explicitly define its type")), |
880 | |
881 | === modified file 'plainbox/plainbox/impl/unit/unit_with_id.py' |
882 | --- plainbox/plainbox/impl/unit/unit_with_id.py 2016-05-11 14:36:13 +0000 |
883 | +++ plainbox/plainbox/impl/unit/unit_with_id.py 2016-09-28 20:21:08 +0000 |
884 | @@ -1,8 +1,9 @@ |
885 | # This file is part of Checkbox. |
886 | # |
887 | -# Copyright 2012-2014 Canonical Ltd. |
888 | +# Copyright 2012-2016 Canonical Ltd. |
889 | # Written by: |
890 | # Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
891 | +# Maciej Kisielewski <maciej.kisielewski@canonical.com> |
892 | # |
893 | # Checkbox is free software: you can redistribute it and/or modify |
894 | # it under the terms of the GNU General Public License version 3, |
895 | @@ -26,13 +27,11 @@ |
896 | from plainbox.i18n import gettext as _ |
897 | from plainbox.i18n import gettext_noop as N_ |
898 | from plainbox.impl.symbol import SymbolDef |
899 | +from plainbox.impl.unit import concrete_validators |
900 | from plainbox.impl.unit.unit import Unit |
901 | from plainbox.impl.unit.unit import UnitValidator |
902 | from plainbox.impl.unit.validators import CorrectFieldValueValidator |
903 | -from plainbox.impl.unit.validators import PresentFieldValidator |
904 | -from plainbox.impl.unit.validators import TemplateVariantFieldValidator |
905 | from plainbox.impl.unit.validators import UniqueValueValidator |
906 | -from plainbox.impl.unit.validators import UntranslatableFieldValidator |
907 | |
908 | __all__ = ['UnitWithId'] |
909 | |
910 | @@ -111,14 +110,10 @@ |
911 | |
912 | field_validators = { |
913 | fields.id: [ |
914 | - # We don't want anyone marking id up for translation |
915 | - UntranslatableFieldValidator, |
916 | - # We want this field to be present at all times |
917 | - PresentFieldValidator, |
918 | - # We want each instance to have a different identifier |
919 | - TemplateVariantFieldValidator, |
920 | - # When checking in a globally, all units need an unique value |
921 | - UniqueValueValidator, |
922 | + concrete_validators.untranslatable, |
923 | + concrete_validators.present, |
924 | + concrete_validators.templateVariant, |
925 | + UniqueValueValidator(), |
926 | # We want to have bare, namespace-less identifiers |
927 | CorrectFieldValueValidator( |
928 | lambda value, unit: ( |
929 | |
930 | === modified file 'plainbox/plainbox/impl/unit/validators.py' |
931 | --- plainbox/plainbox/impl/unit/validators.py 2016-05-20 13:54:59 +0000 |
932 | +++ plainbox/plainbox/impl/unit/validators.py 2016-09-28 20:21:08 +0000 |
933 | @@ -364,6 +364,36 @@ |
934 | super().__init__(correct_fn, kind, severity, message, onlyif) |
935 | |
936 | |
937 | +class MemberOfFieldValidator(CorrectFieldValueValidator): |
938 | + """Validator ensuring the value is a member of a given set.""" |
939 | + |
940 | + def __init__(self, possible_values, kind=None, severity=None, message=None, |
941 | + onlyif=None): |
942 | + """ |
943 | + possible_values: |
944 | + Iterable with values that the membership will be testsed against. |
945 | + kind: |
946 | + Kind of issue to report. By default this is Problem.useless |
947 | + severity: |
948 | + Severity of the issue to report. By default this is |
949 | + Severity.warning |
950 | + message: |
951 | + Customized error message. This message will be used to report the |
952 | + issue if the validation fails. By default it is derived from the |
953 | + specified issue ``kind`` by :meth:`UnitValidator.explain()`. |
954 | + onlyif: |
955 | + An optional function that checks if this validator should be |
956 | + applied or not. The function is called with the `unit` as the only |
957 | + argument. If it returns True then the validator proceeds to |
958 | + perform its check. |
959 | + """ |
960 | + def correct_fn(value): return value in possible_values |
961 | + if not message: |
962 | + message = _('valid values are: {}').format( |
963 | + ', '.join(str(val) for val in sorted(possible_values))) |
964 | + super().__init__(correct_fn, kind, severity, message, onlyif) |
965 | + |
966 | + |
967 | class DeprecatedFieldValidator(FieldValidatorBase): |
968 | """ |
969 | Validator ensuring that deprecated field is not used (passed a value) |
Great stuff!
Just one question, see below, but applicable to all remaining PresentFieldVal idator( severity= Severity. advice) .