Add logging for schema initialization and building

- Add loglevel argument to schema init
  - Fallback location (for XLink and XHTML) moved at the
    end of import tentatives (full fix for issue #137)
  - Fix TestGlobalMaps after the remove of XLink from base schemas
This commit is contained in:
Davide Brunato 2019-10-08 11:07:24 +02:00
parent 433970cf72
commit 690a172502
4 changed files with 63 additions and 33 deletions

View File

@ -164,8 +164,6 @@ Resource access API
.. autofunction:: xmlschema.normalize_url
XSD components API
------------------

View File

@ -14,6 +14,7 @@ import pdb
import os
import pickle
import time
import logging
import warnings
from xmlschema import XMLSchemaBase
@ -46,6 +47,7 @@ def make_schema_test_class(test_file, test_args, test_num, schema_class, check_w
locations = test_args.locations
defuse = test_args.defuse
debug_mode = test_args.debug
loglevel = logging.DEBUG if debug_mode else None
class TestSchema(XsdValidatorTestCase):
@ -61,9 +63,10 @@ def make_schema_test_class(test_file, test_args, test_num, schema_class, check_w
def check_xsd_file(self):
if expected_errors > 0:
xs = schema_class(xsd_file, validation='lax', locations=locations, defuse=defuse)
xs = schema_class(xsd_file, validation='lax', locations=locations,
defuse=defuse, loglevel=loglevel)
else:
xs = schema_class(xsd_file, locations=locations, defuse=defuse)
xs = schema_class(xsd_file, locations=locations, defuse=defuse, loglevel=loglevel)
self.errors.extend(xs.maps.all_errors)
if inspect:

View File

@ -281,33 +281,33 @@ class TestGlobalMaps(unittest.TestCase):
def test_xsd_10_globals(self):
self.assertEqual(len(XMLSchema10.meta_schema.maps.notations), 2)
self.assertEqual(len(XMLSchema10.meta_schema.maps.types), 108)
self.assertEqual(len(XMLSchema10.meta_schema.maps.attributes), 18)
self.assertEqual(len(XMLSchema10.meta_schema.maps.attribute_groups), 9)
self.assertEqual(len(XMLSchema10.meta_schema.maps.groups), 18)
self.assertEqual(len(XMLSchema10.meta_schema.maps.elements), 45)
self.assertEqual(len([e.is_global() for e in XMLSchema10.meta_schema.maps.iter_globals()]), 200)
self.assertEqual(len(XMLSchema10.meta_schema.maps.types), 92)
self.assertEqual(len(XMLSchema10.meta_schema.maps.attributes), 8)
self.assertEqual(len(XMLSchema10.meta_schema.maps.attribute_groups), 3)
self.assertEqual(len(XMLSchema10.meta_schema.maps.groups), 12)
self.assertEqual(len(XMLSchema10.meta_schema.maps.elements), 41)
self.assertEqual(len([e.is_global() for e in XMLSchema10.meta_schema.maps.iter_globals()]), 158)
self.assertEqual(len(XMLSchema10.meta_schema.maps.substitution_groups), 0)
def test_xsd_11_globals(self):
self.assertEqual(len(XMLSchema11.meta_schema.maps.notations), 2)
self.assertEqual(len(XMLSchema11.meta_schema.maps.types), 119)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attributes), 24)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attribute_groups), 10)
self.assertEqual(len(XMLSchema11.meta_schema.maps.groups), 19)
self.assertEqual(len(XMLSchema11.meta_schema.maps.elements), 51)
self.assertEqual(len([e.is_global() for e in XMLSchema11.meta_schema.maps.iter_globals()]), 225)
self.assertEqual(len(XMLSchema11.meta_schema.maps.types), 103)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attributes), 14)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attribute_groups), 4)
self.assertEqual(len(XMLSchema11.meta_schema.maps.groups), 13)
self.assertEqual(len(XMLSchema11.meta_schema.maps.elements), 47)
self.assertEqual(len([e.is_global() for e in XMLSchema11.meta_schema.maps.iter_globals()]), 183)
self.assertEqual(len(XMLSchema11.meta_schema.maps.substitution_groups), 1)
def test_xsd_10_build(self):
self.assertEqual(len([e for e in XMLSchema10.meta_schema.maps.iter_globals()]), 200)
self.assertEqual(len([e for e in XMLSchema10.meta_schema.maps.iter_globals()]), 158)
self.assertTrue(XMLSchema10.meta_schema.maps.built)
XMLSchema10.meta_schema.maps.clear()
XMLSchema10.meta_schema.maps.build()
self.assertTrue(XMLSchema10.meta_schema.maps.built)
def test_xsd_11_build(self):
self.assertEqual(len([e for e in XMLSchema11.meta_schema.maps.iter_globals()]), 225)
self.assertEqual(len([e for e in XMLSchema11.meta_schema.maps.iter_globals()]), 183)
self.assertTrue(XMLSchema11.meta_schema.maps.built)
XMLSchema11.meta_schema.maps.clear()
XMLSchema11.meta_schema.maps.build()
@ -321,8 +321,8 @@ class TestGlobalMaps(unittest.TestCase):
total_counter += 1
if c.is_global():
global_counter += 1
self.assertEqual(global_counter, 200)
self.assertEqual(total_counter, 901)
self.assertEqual(global_counter, 158)
self.assertEqual(total_counter, 782)
def test_xsd_11_components(self):
total_counter = 0
@ -332,8 +332,8 @@ class TestGlobalMaps(unittest.TestCase):
total_counter += 1
if c.is_global():
global_counter += 1
self.assertEqual(global_counter, 225)
self.assertEqual(total_counter, 1051)
self.assertEqual(global_counter, 183)
self.assertEqual(total_counter, 932)
def test_xsd_11_restrictions(self):
all_model_type = XMLSchema11.meta_schema.types['all']

View File

@ -55,6 +55,9 @@ from .wildcards import XsdAnyElement, XsdAnyAttribute, Xsd11AnyElement, \
Xsd11AnyAttribute, XsdDefaultOpenContent
from .globals_ import XsdGlobals
logger = logging.getLogger('xmlschema')
logging.basicConfig(format='[%(levelname)s] %(message)s')
XSD_VERSION_PATTERN = re.compile(r'^\d+\.\d+$')
# Elements for building dummy groups
@ -172,6 +175,9 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
meta-schema is added at the end. In the latter case the meta-schema is rebuilt if any base \
namespace has been overridden by an import. Ignored if the argument *global_maps* is provided.
:type use_meta: bool
:param loglevel: for setting a different logging level for schema initialization \
and building. For default is WARNING (30).
:type loglevel: int
:cvar XSD_VERSION: store the XSD version (1.0 or 1.1).
:vartype XSD_VERSION: str
@ -258,10 +264,18 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
default_open_content = None
override = None
def __init__(self, source, namespace=None, validation='strict', global_maps=None, converter=None,
locations=None, base_url=None, defuse='remote', timeout=300, build=True, use_meta=True):
def __init__(self, source, namespace=None, validation='strict', global_maps=None,
converter=None, locations=None, base_url=None, defuse='remote',
timeout=300, build=True, use_meta=True, loglevel=None):
super(XMLSchemaBase, self).__init__(validation)
if loglevel is not None:
logger.setLevel(loglevel)
elif build and global_maps is None:
logger.setLevel(logging.WARNING)
self.source = XMLResource(source, base_url, defuse, timeout, lazy=False)
logger.debug("Read schema from %r", self.source)
self.imports = {}
self.includes = {}
self.warnings = []
@ -291,6 +305,9 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
if '' not in self.namespaces:
self.namespaces[''] = namespace
logger.debug("Schema targetNamespace is %r", self.target_namespace)
logger.debug("Declared namespaces: %r", self.namespaces)
# Parses the schema defaults
if 'attributeFormDefault' in root.attrib:
try:
@ -321,11 +338,7 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
except ValueError as err:
self.parse_error(err, root)
# Set locations hints
self.locations = NamespaceResourcesMap(self.source.get_locations(locations))
if self.meta_schema is not None:
self.locations.update(self.FALLBACK_LOCATIONS)
self.converter = self.get_converter(converter)
self.xpath_proxy = XMLSchemaProxy(self)
self.empty_attribute_group = self.BUILDERS.attribute_group_class(
@ -396,8 +409,12 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
self.default_open_content = XsdDefaultOpenContent(child, self)
break
if build:
self.maps.build()
try:
if build:
self.maps.build()
finally:
if loglevel is not None:
logger.setLevel(logging.WARNING) # Restore default logging
def __repr__(self):
if self.url:
@ -829,7 +846,9 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
"""Processes schema document inclusions and redefinitions."""
for child in filter(lambda x: x.tag == XSD_INCLUDE, self.root):
try:
self.include_schema(child.attrib['schemaLocation'], self.base_url)
location = child.attrib['schemaLocation'].strip()
logger.info("Include schema from %r", location)
self.include_schema(location, self.base_url)
except KeyError:
pass
except (OSError, IOError) as err:
@ -850,7 +869,9 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
for child in filter(lambda x: x.tag == XSD_REDEFINE, self.root):
try:
schema = self.include_schema(child.attrib['schemaLocation'], self.base_url)
location = child.attrib['schemaLocation'].strip()
logger.info("Redefine schema %r", location)
schema = self.include_schema(location, self.base_url)
except KeyError:
pass # Attribute missing error already found by validation against meta-schema
except (OSError, IOError) as err:
@ -940,13 +961,18 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
if local_hints:
locations = local_hints + locations
if namespace in self.FALLBACK_LOCATIONS:
locations.append(self.FALLBACK_LOCATIONS[namespace])
import_error = None
for url in locations:
try:
logger.debug("Import namespace %r from %r", namespace, url)
self.import_schema(namespace, url, self.base_url)
except (OSError, IOError) as err:
# It's not an error if the location access fails (ref. section 4.2.6.2):
# https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#composition-schemaImport
logger.debug('%s', err)
if import_error is None:
import_error = err
except (XMLSchemaURLError, XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err:
@ -963,6 +989,7 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
except XMLSchemaValueError as err:
self.parse_error(err)
else:
logger.info("Namespace %r imported from %r", namespace, url)
break
else:
if import_error is not None:
@ -1505,7 +1532,9 @@ class XMLSchema11(XMLSchemaBase):
for child in filter(lambda x: x.tag == XSD_OVERRIDE, self.root):
try:
schema = self.include_schema(child.attrib['schemaLocation'], self.base_url)
location = child.attrib['schemaLocation'].strip()
logger.info("Override schema %r", location)
schema = self.include_schema(location, self.base_url)
except KeyError:
pass # Attribute missing error already found by validation against meta-schema
except (OSError, IOError) as err: