Merge lp:~kissiel/checkbox/validation-rework into lp:checkbox

Proposed by Maciej Kisielewski
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
Reviewer Review Type Date Requested Status
Sylvain Pineau Approve
Review via email: mp+307082@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Great stuff!

Just one question, see below, but applicable to all remaining PresentFieldValidator(severity=Severity.advice).

review: Needs Information
Revision history for this message
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?

Revision history for this message
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

review: Approve
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

s/bug/big hehe

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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)

Subscribers

People subscribed via source and target branches