From a76b3caa6e3cb9bf20c37f1c5e4e862cef406b7c Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 3 Mar 2016 10:43:39 +0100 Subject: [PATCH] [IMP] custom view validators system Add possibility for modules to add validators, getting closer to defining views outside of base. --- openerp/tools/view_validation.py | 84 +++++++++++++++++--------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/openerp/tools/view_validation.py b/openerp/tools/view_validation.py index dc0a8d51830..f3703712d24 100644 --- a/openerp/tools/view_validation.py +++ b/openerp/tools/view_validation.py @@ -1,80 +1,84 @@ """ View validation code (using assertions, not the RNG schema). """ +import collections import logging _logger = logging.getLogger(__name__) +_validators = collections.defaultdict(list) +def valid_view(arch): + for pred in _validators[arch.tag]: + if not pred(arch): + _logger.error("Invalid XML: %s", pred.__doc__) + return False + return True + + +def validate(*view_types): + """ Registers a view-validation function for the specific view types + """ + def decorator(fn): + for arch in view_types: + _validators[arch].append(fn) + return fn + return decorator + + +@validate('form') def valid_page_in_book(arch): """A `page` node must be below a `book` node.""" return not arch.xpath('//page[not(ancestor::notebook)]') +@validate('graph') def valid_field_in_graph(arch): """ Children of ``graph`` can only be ``field`` """ - for child in arch.xpath('/graph/child::*'): - if child.tag != 'field': - return False - return True + return all( + child.tag == 'field' + for child in arch.xpath('/graph/*') + ) +@validate('tree') def valid_field_in_tree(arch): """ Children of ``tree`` view must be ``field`` or ``button``.""" - for child in arch.xpath('/tree/child::*'): - if child.tag not in ('field', 'button'): - return False - return True + return all( + child.tag in ('field', 'button') + for child in arch.xpath('/tree/*') + ) +@validate('form', 'graph', 'tree') def valid_att_in_field(arch): """ ``field`` nodes must all have a ``@name`` """ return not arch.xpath('//field[not(@name)]') +@validate('form') def valid_att_in_label(arch): """ ``label`` nodes must have a ``@for`` or a ``@string`` """ return not arch.xpath('//label[not(@for or @string)]') +@validate('form') def valid_att_in_form(arch): return True +@validate('form') def valid_type_in_colspan(arch): """A `colspan` attribute must be an `integer` type.""" - for attrib in arch.xpath('//*/@colspan'): - try: - int(attrib) - except: - return False - return True + return all( + attrib.isdigit() + for attrib in arch.xpath('//@colspan') + ) +@validate('form') def valid_type_in_col(arch): """A `col` attribute must be an `integer` type.""" - for attrib in arch.xpath('//*/@col'): - try: - int(attrib) - except: - return False - return True - - -def valid_view(arch): - if arch.tag == 'form': - for pred in [valid_page_in_book, valid_att_in_form, valid_type_in_colspan, - valid_type_in_col, valid_att_in_field, valid_att_in_label]: - if not pred(arch): - _logger.error('Invalid XML: %s', pred.__doc__) - return False - elif arch.tag == 'graph': - for pred in [valid_field_in_graph, valid_att_in_field]: - if not pred(arch): - _logger.error('Invalid XML: %s', pred.__doc__) - return False - elif arch.tag == 'tree': - for pred in [valid_field_in_tree, valid_att_in_field]: - if not pred(arch): - _logger.error('Invalid XML: %s', pred.__doc__) - return False - return True + return all( + attrib.isdigit() + for attrib in arch.xpath('//@col') + )