Skip to content

Commit

Permalink
Fix assert and sequence types
Browse files Browse the repository at this point in the history
  - Add sequence_type property to types that returns always a
    valid XPath sequence type
  - Fix root_type property to return xs:anyType for complex
    types with attributes or without a simple base
  - modify get_primitive_type() of XPath proxy to return root_type
  • Loading branch information
brunato committed Sep 13, 2020
1 parent 6ed0a9d commit 077fefd
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 34 deletions.
6 changes: 3 additions & 3 deletions tests/validators/test_xsdbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from xmlschema.testing import print_test_header
from xmlschema.validators import XsdValidator, XsdComponent, XMLSchema10, \
XMLSchema11, XMLSchemaParseError, XMLSchemaValidationError, XsdGroup, XsdSimpleType
from xmlschema.qnames import XSD_ELEMENT, XSD_ANNOTATION
from xmlschema.qnames import XSD_ELEMENT, XSD_ANNOTATION, XSD_ANY_TYPE
from xmlschema.namespaces import XSD_NAMESPACE

CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases')
Expand Down Expand Up @@ -503,9 +503,9 @@ def test_root_type(self):
self.assertIs(self.schema.types['fooListType'].root_type,
self.schema.meta_schema.types['string'])
self.assertIs(self.schema.types['mixedType'].root_type,
self.schema.types['mixedType'])
self.schema.maps.types[XSD_ANY_TYPE])
self.assertIs(self.schema.types['barExtType'].root_type,
self.schema.types['barType'])
self.schema.maps.types[XSD_ANY_TYPE])

def test_is_atomic(self):
self.assertFalse(self.schema.types['barType'].is_atomic())
Expand Down
15 changes: 3 additions & 12 deletions xmlschema/validators/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import threading
from elementpath import XPath2Parser, XPathContext, ElementPathError

from ..qnames import XSD_ASSERT, XSD_UNTYPED_ATOMIC, get_prefixed_qname
from ..qnames import XSD_ASSERT
from ..xpath import ElementPathMixin, XMLSchemaProxy

from .exceptions import XMLSchemaValidationError
Expand Down Expand Up @@ -79,17 +79,9 @@ def built(self):
return self.token is not None and (self.base_type.parent is None or self.base_type.built)

def build(self):
if not self.base_type.has_simple_content():
sequence_type = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces)
else:
try:
sequence_type = self.base_type.content.primitive_type.prefixed_name
except AttributeError:
sequence_type = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces)

self.parser = XPath2Parser(
namespaces=self.namespaces,
variable_types={'value': sequence_type},
variable_types={'value': self.base_type.sequence_type},
strict=False,
default_namespace=self.xpath_default_namespace,
schema=XMLSchemaProxy(self.schema, self)
Expand Down Expand Up @@ -118,8 +110,7 @@ def __call__(self, elem, value=None, namespaces=None, source=None, **kwargs):

try:
if not self.token.evaluate(context):
msg = "expression is not true with test path %r."
yield XMLSchemaValidationError(self, obj=elem, reason=msg % self.path)
yield XMLSchemaValidationError(self, obj=elem, reason="assertion test if false")
except ElementPathError as err:
yield XMLSchemaValidationError(self, obj=elem, reason=str(err))

Expand Down
21 changes: 19 additions & 2 deletions xmlschema/validators/complex_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from ..exceptions import XMLSchemaValueError
from ..qnames import XSD_GROUP, XSD_ATTRIBUTE_GROUP, XSD_SEQUENCE, \
XSD_ALL, XSD_CHOICE, XSD_ANY_ATTRIBUTE, XSD_ATTRIBUTE, XSD_COMPLEX_CONTENT, \
XSD_RESTRICTION, XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_ANY_TYPE, \
XSD_SIMPLE_CONTENT, XSD_OPEN_CONTENT, XSD_ASSERT, \
XSD_RESTRICTION, XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_ANY_TYPE, XSD_ASSERT, \
XSD_UNTYPED_ATOMIC, XSD_SIMPLE_CONTENT, XSD_OPEN_CONTENT, get_prefixed_qname, \
get_qname, local_name, is_not_xsd_annotation, is_xsd_override
from ..helpers import get_xsd_derivation_attribute

Expand Down Expand Up @@ -504,6 +504,23 @@ def content_type_label(self):
else:
return 'element-only'

@property
def sequence_type(self):
if self.is_empty():
return 'empty-sequence()'
elif not self.has_simple_content():
sequence_type = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces)
else:
try:
sequence_type = self.content.primitive_type.prefixed_name
except AttributeError:
sequence_type = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces)
else:
if sequence_type is None:
sequence_type = 'item()'

return '{}{}'.format(sequence_type, '*' if self.is_emptiable() else '+')

@staticmethod
def is_simple():
return False
Expand Down
2 changes: 2 additions & 0 deletions xmlschema/validators/facets.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,8 @@ def _parse_value(self, elem):
self.parse_error("missing 'value' attribute", elem)
except XMLSchemaDecodeError as err:
self.parse_error(err, elem)
except XMLSchemaValidationError as err:
self.base_type.parse_error(err, elem) # FIXME
else:
if self.base_type.name == XSD_NOTATION_TYPE:
try:
Expand Down
22 changes: 20 additions & 2 deletions xmlschema/validators/simple_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, XSD_WHITE_SPACE, XSD_ENUMERATION,\
XSD_LIST, XSD_ANY_SIMPLE_TYPE, XSD_UNION, XSD_RESTRICTION, XSD_ANNOTATION, \
XSD_ASSERTION, XSD_ID, XSD_IDREF, XSD_FRACTION_DIGITS, XSD_TOTAL_DIGITS, \
XSD_EXPLICIT_TIMEZONE, XSD_ERROR, XSD_ASSERT, XSD_QNAME, get_qname, local_name, \
is_not_xsd_annotation
XSD_EXPLICIT_TIMEZONE, XSD_ERROR, XSD_ASSERT, XSD_QNAME, XSD_UNTYPED_ATOMIC, \
get_qname, get_prefixed_qname, local_name, is_not_xsd_annotation
from ..namespaces import XSD_NAMESPACE
from ..helpers import get_xsd_derivation_attribute

Expand Down Expand Up @@ -327,6 +327,24 @@ def is_complex():
def content_type_label(self):
return 'empty' if self.max_length == 0 else 'simple'

@property
def sequence_type(self):
if self.is_empty():
return 'empty-sequence()'

root_type = self.root_type
if root_type.name is None:
sequence_type = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces)
else:
sequence_type = root_type.prefixed_name

if not self.is_list():
return sequence_type
elif self.is_emptiable():
return '{}*'.format(sequence_type)
else:
return '{}+'.format(sequence_type)

def is_empty(self):
return self.max_length == 0

Expand Down
19 changes: 15 additions & 4 deletions xmlschema/validators/xsdbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,11 +596,22 @@ def content_type_label(self):
"""The content type classification."""
raise NotImplementedError()

@property
def sequence_type(self):
"""The XPath sequence type associated with the content."""
raise NotImplementedError()

@property
def root_type(self):
"""The root type of the type definition hierarchy. Is itself for a root type."""
if self.base_type is None:
return self # Note that a XsdUnion type is always considered a root type
"""
The root type of the type definition hierarchy. For an atomic type
is the primitive type. For a list is the primitive type of the item.
For a union is the base union type. For a complex type is xs:anyType.
"""
if self.is_complex() and self.attributes:
return self.maps.types[XSD_ANY_TYPE]
elif self.base_type is None:
return self if self.is_simple() else self.maps.types[XSD_ANY_TYPE]

try:
if self.base_type.is_simple():
Expand All @@ -609,7 +620,7 @@ def root_type(self):
return self.base_type.content.primitive_type
except AttributeError:
# The type has complex or XsdList content
return self.base_type
return self.base_type.root_type

@property
def simple_type(self):
Expand Down
12 changes: 1 addition & 11 deletions xmlschema/xpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from elementpath import AttributeNode, TypedElement, XPath2Parser, \
XPathSchemaContext, AbstractSchemaProxy

from .qnames import XSD_ANY_TYPE
from .namespaces import XSD_NAMESPACE
from .exceptions import XMLSchemaValueError, XMLSchemaTypeError

Expand Down Expand Up @@ -159,16 +158,7 @@ def iter_atomic_types(self):
yield xsd_type

def get_primitive_type(self, xsd_type):
if xsd_type.is_complex():
return self._schema.maps.types[XSD_ANY_TYPE]
elif not hasattr(xsd_type, 'primitive_type'):
if xsd_type.base_type is None:
return xsd_type
return self.get_primitive_type(xsd_type.base_type)
elif xsd_type.primitive_type is not xsd_type:
return self.get_primitive_type(xsd_type.primitive_type)
else:
return xsd_type
return xsd_type.root_type


class ElementPathMixin(Sequence):
Expand Down

0 comments on commit 077fefd

Please sign in to comment.