[IMP] validation error messages through optional use of jing

A long-standing issue with data files is that lxml (libxml2) has
trouble reporting useful errors, often going no further than "the file
is not valid" (libxml2 apparently has issues reporting useful errors
within non-trivial <choice>, which Odoo's data file schema makes
extensive use of) e.g. if a data file has some stray text in an
unexpected place (in this case, after a `</field>` tag in a
`<record>`), libxml2 will report:

ERROR:RELAXNGV:RELAXNG_ERR_EXTRACONTENT: Element odoo has extra content: data

Jing (the reference implementation) provides significantly better
error reporting:

error: text not allowed here; expected the element end-tag or element "field"

It's in java which is inconvenient and expensive for baseline
validation (and as a hard dependency), but there's now a "jingtrang"
package which bundles the relevant jars & invocation on
pypi (https://pypi.org/project/jingtrang/), making for a convenient
optional dependency for better development experience.

closes odoo/odoo#33666

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
This commit is contained in:
Xavier Morel
2019-05-27 06:58:48 +00:00
parent 9b823c9c6a
commit 16cd987a53
+15 -4
View File
@@ -5,6 +5,7 @@ import io
import logging
import os.path
import re
import subprocess
import sys
import time
@@ -13,6 +14,10 @@ from dateutil.relativedelta import relativedelta
import pytz
from lxml import etree, builder
try:
import jingtrang
except ImportError:
jingtrang = None
import odoo
from . import assertion_report, pycompat
@@ -771,13 +776,19 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=False, report=None):
doc = etree.parse(xmlfile)
relaxng = etree.RelaxNG(
etree.parse(os.path.join(config['root_path'],'import_xml.rng' )))
schema = os.path.join(config['root_path'], 'import_xml.rng')
relaxng = etree.RelaxNG(etree.parse(schema))
try:
relaxng.assert_(doc)
except Exception:
_logger.info("The XML file '%s' does not fit the required schema !", xmlfile.name, exc_info=True)
_logger.info(ustr(relaxng.error_log.last_error))
_logger.exception("The XML file '%s' does not fit the required schema !", xmlfile.name)
if jingtrang:
p = subprocess.run(['pyjing', schema, xmlfile.name], stdout=subprocess.PIPE)
_logger.warn(p.stdout.decode())
else:
for e in relaxng.error_log:
_logger.warn(e)
_logger.info("Install 'jingtrang' for more precise and useful validation messages.")
raise
if isinstance(xmlfile, str):