Fix datetime types validation on encoding

- Add is_datetime() to XSD types classes
This commit is contained in:
Davide Brunato 2019-10-11 13:26:17 +02:00
parent 997c59c837
commit a79a5583ae
4 changed files with 32 additions and 32 deletions

View File

@ -23,7 +23,7 @@ except ImportError:
lxml_etree = None
from .compat import PY3
from .exceptions import XMLSchemaTypeError, XMLSchemaValueError
from .exceptions import XMLSchemaTypeError
from .namespaces import XSLT_NAMESPACE, HFP_NAMESPACE, VC_NAMESPACE, get_namespace
from .qnames import get_qname, qname_to_prefixed

View File

@ -385,11 +385,10 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
for e in self.meta_schema.iter_errors(root, namespaces=self.namespaces):
self.parse_error(e.reason, elem=e.elem)
# Inclusions and imports schemas (errors are treated as warnings)
self._parse_inclusions()
self._parse_imports()
# Imports by argument (usually from XML schemaLocation attribute).
# Imports by argument (usually from xsi:schemaLocation attribute).
for ns in self.locations:
if ns not in self.maps.namespaces:
self._import_namespace(ns, self.locations[ns])

View File

@ -400,6 +400,7 @@ class XsdAtomic(XsdSimpleType):
a base_type attribute that refers to primitive or derived atomic
built-in type or another derived simpleType.
"""
to_python = str
_special_types = {XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE, XSD_ANY_ATOMIC_TYPE}
_ADMITTED_TAGS = {XSD_RESTRICTION, XSD_SIMPLE_TYPE}
@ -502,6 +503,9 @@ class XsdAtomicBuiltin(XsdAtomic):
def admitted_facets(self):
return self._admitted_facets or self.primitive_type.admitted_facets
def is_datetime(self):
return self.to_python.__name__ == 'fromstring'
def iter_decode(self, obj, validation='lax', **kwargs):
if isinstance(obj, (string_base_type, bytes)):
obj = self.normalize(obj)
@ -1151,35 +1155,21 @@ class XsdAtomicRestriction(XsdAtomic):
if self.is_list():
if not hasattr(obj, '__iter__') or isinstance(obj, (str, unicode_type, bytes)):
obj = [] if obj is None or obj == '' else [obj]
if validation != 'skip' and obj is not None:
for validator in self.validators:
for error in validator(obj):
yield error
for result in self.base_type.iter_encode(obj, validation):
if isinstance(result, XMLSchemaValidationError):
yield result
if isinstance(result, XMLSchemaEncodeError):
yield unicode_type(obj) if validation == 'skip' else None
return
else:
yield result
return
if isinstance(obj, (string_base_type, bytes)):
obj = self.normalize(obj)
if self.base_type.is_simple():
base_type = self.base_type
elif self.base_type.has_simple_content():
base_type = self.base_type.content_type
elif self.base_type.mixed:
yield unicode_type(obj)
return
else:
raise XMLSchemaValueError("wrong base type %r: a simpleType or a complexType with "
"simple or mixed content required." % self.base_type)
if isinstance(obj, (string_base_type, bytes)):
obj = self.normalize(obj)
if self.base_type.is_simple():
base_type = self.base_type
elif self.base_type.has_simple_content():
base_type = self.base_type.content_type
elif self.base_type.mixed:
yield unicode_type(obj)
return
else:
raise XMLSchemaValueError("wrong base type %r: a simpleType or a complexType with "
"simple or mixed content required." % self.base_type)
for result in base_type.iter_encode(obj, validation):
if isinstance(result, XMLSchemaValidationError):
@ -1188,7 +1178,11 @@ class XsdAtomicRestriction(XsdAtomic):
yield unicode_type(obj) if validation == 'skip' else None
return
else:
if validation != 'skip' and obj is not None:
if validation != 'skip' and self.validators and obj is not None:
if isinstance(obj, (string_base_type, bytes)):
if self.primitive_type.is_datetime():
obj = self.primitive_type.to_python(obj)
for validator in self.validators:
for error in validator(obj):
yield error

View File

@ -625,7 +625,14 @@ class XsdType(XsdComponent):
@staticmethod
def is_atomic():
"""Returns `True` if the instance is an atomic simpleType, `False` otherwise."""
return None
return False
@staticmethod
def is_datetime():
"""
Returns `True` if the instance is a datetime/duration XSD builtin-type, `False` otherwise.
"""
return False
def is_empty(self):
"""Returns `True` if the instance has an empty value or content, `False` otherwise."""