def check_errors(self, path, expected): """ Checks schema or validation errors, checking information completeness of the instances and those number against expected. :param path: the path of the test case. :param expected: the number of expected errors. """ for e in self.errors: error_string = unicode_type(e) self.assertTrue(e.path, "Missing path for: %s" % error_string) self.assertTrue(e.namespaces, "Missing namespaces for: %s" % error_string) self.check_namespace_prefixes(error_string) if not self.errors and expected: raise ValueError("{!r}: found no errors when {} expected.".format( path, expected)) elif len(self.errors) != expected: num_errors = len(self.errors) if num_errors == 1: msg = "{!r}: n.{} errors expected, found {}:\n\n{}" elif num_errors <= 5: msg = "{!r}: n.{} errors expected, found {}. Errors follow:\n\n{}" else: msg = "{!r}: n.{} errors expected, found {}. First five errors follow:\n\n{}" error_string = '\n++++++++++\n\n'.join( [unicode_type(e) for e in self.errors[:5]]) raise ValueError( msg.format(path, expected, len(self.errors), error_string))
def check_xsd_file_with_lxml(self, xmlschema_time): start_time = time.time() lxs = lxml_etree.parse(xsd_file) try: lxml_etree.XMLSchema(lxs.getroot()) except lxml_etree.XMLSchemaParseError as err: if not self.errors: print( "\nSchema error with lxml.etree.XMLSchema for file {!r} ({}): {}" .format(xsd_file, self.__class__.__name__, unicode_type(err))) else: if self.errors: print( "\nUnrecognized errors with lxml.etree.XMLSchema for file {!r} ({}): {}" .format( xsd_file, self.__class__.__name__, '\n++++++\n'.join( [unicode_type(e) for e in self.errors]))) lxml_schema_time = time.time() - start_time if lxml_schema_time >= xmlschema_time: print( "\nSlower lxml.etree.XMLSchema ({:.3f}s VS {:.3f}s) with file {!r} ({})" .format(lxml_schema_time, xmlschema_time, xsd_file, self.__class__.__name__))
def check_errors(self, path, expected): """ Checks schema or validation errors, checking information completeness of the instances and those number against expected. :param path: the path of the test case. :param expected: the number of expected errors. """ for e in self.errors: error_string = unicode_type(e) self.assertTrue(e.path, "Missing path for: %s" % error_string) self.assertTrue(e.namespaces, "Missing namespaces for: %s" % error_string) self.check_namespace_prefixes(error_string) if not self.errors and expected: raise ValueError("found no errors when %d expected." % expected) elif len(self.errors) != expected: num_errors = len(self.errors) if num_errors == 1: msg = "{!r}: n.{} errors expected, found {}:\n\n{}" elif num_errors <= 5: msg = "{!r}: n.{} errors expected, found {}. Errors follow:\n\n{}" else: msg = "{!r}: n.{} errors expected, found {}. First five errors follow:\n\n{}" error_string = '\n++++++++++\n\n'.join([unicode_type(e) for e in self.errors[:5]]) raise ValueError(msg.format(path, expected, len(self.errors), error_string))
def test_date_decoding(self): # Issue #136 schema = xmlschema.XMLSchema("""<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> <xs:element name="Date"> <xs:simpleType> <xs:restriction base="xs:date"> <xs:minInclusive value="2000-01-01"/> <xs:maxInclusive value="2099-12-31"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:schema>""") self.assertEqual(schema.to_dict("<Date>2019-01-01</Date>"), '2019-01-01') self.assertEqual( schema.to_dict("<Date>2019-01-01</Date>", datetime_types=True), datatypes.Date10.fromstring('2019-01-01')) data, errors = schema.to_dict("<Date>2019-01-01</Date>", validation='lax') self.assertEqual(data, '2019-01-01') self.assertEqual(errors, []) data, errors = schema.to_dict("<Date>2019-01-01</Date>", validation='lax', datetime_types=True) self.assertEqual(data, datatypes.Date10.fromstring('2019-01-01')) self.assertEqual(errors, []) data, errors = schema.to_dict("<Date>1999-12-31</Date>", validation='lax') self.assertEqual(data, '1999-12-31') self.assertEqual(len(errors), 1) self.assertIn('value has to be greater or equal than', unicode_type(errors[0])) data, errors = schema.to_dict("<Date>1999-12-31</Date>", validation='lax', datetime_types=True) self.assertEqual(data, datatypes.Date10.fromstring('1999-12-31')) self.assertEqual(len(errors), 1) data, errors = schema.to_dict("<Date>2019</Date>", validation='lax') self.assertIsNone(data) self.assertEqual(len(errors), 1) with self.assertRaises(XMLSchemaValidationError): schema.to_dict("<Date>2019</Date>") data, errors = schema.to_dict("<Date>2019</Date>", validation='lax') self.assertIsNone(data) self.assertEqual(len(errors), 1)
def check_lxml_schema(self, xmlschema_time): start_time = time.time() lxs = lxml_etree.parse(xsd_file) try: lxml_etree.XMLSchema(lxs.getroot()) except lxml_etree.XMLSchemaParseError as err: if not self.errors: print("\nSchema error with lxml.etree.XMLSchema for file {!r} ({}): {}".format( xsd_file, self.__class__.__name__, unicode_type(err) )) else: if self.errors: print("\nUnrecognized errors with lxml.etree.XMLSchema for file {!r} ({}): {}".format( xsd_file, self.__class__.__name__, '\n++++++\n'.join([unicode_type(e) for e in self.errors]) )) lxml_schema_time = time.time() - start_time if lxml_schema_time >= xmlschema_time: print( "\nSlower lxml.etree.XMLSchema ({:.3f}s VS {:.3f}s) with file {!r} ({})".format( lxml_schema_time, xmlschema_time, xsd_file, self.__class__.__name__ ))
def test_error_message(self): schema = self.schema_class( self.casepath('issues/issue_115/Rotation.xsd')) rotation_data = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" ' \ 'pitch="0.0" roll="0.0" yaw="-1.0" />' message_lines = [] try: schema.decode(rotation_data) except Exception as err: message_lines = unicode_type(err).split('\n') self.assertTrue(message_lines, msg="Empty error message!") self.assertEqual(message_lines[-6], 'Instance:') self.assertEqual(message_lines[-4].strip(), rotation_data) self.assertEqual(message_lines[-2], 'Path: /tns:rotation')
def test_error_message(self): schema = self.schema_class( self.casepath('issues/issue_115/Rotation.xsd')) rotation_data = { "@roll": 0.0, "@pitch": 0.0, "@yaw": -1.0 # <----- invalid value, must be between 0 and 360 } message_lines = [] try: schema.encode(rotation_data) except Exception as err: message_lines = unicode_type(err).split('\n') self.assertTrue(message_lines, msg="Empty error message!") self.assertEqual(message_lines[-4], 'Instance:') if sys.version_info < (3, 8): text = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" pitch="0.0" roll="0.0" yaw="-1.0" />' else: text = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" roll="0.0" pitch="0.0" yaw="-1.0" />' self.assertEqual(message_lines[-2].strip(), text)
def check_etree_encode(self, root, converter=None, **kwargs): namespaces = kwargs.get('namespaces', {}) data1 = self.schema.decode(root, converter=converter, **kwargs) if isinstance(data1, tuple): data1 = data1[0] # When validation='lax' for _ in iter_nested_items(data1, dict_class=ordered_dict_class): pass elem1 = self.schema.encode(data1, path=root.tag, converter=converter, **kwargs) if isinstance(elem1, tuple): # When validation='lax' if converter is not ParkerConverter: for e in elem1[1]: self.check_namespace_prefixes(unicode_type(e)) elem1 = elem1[0] # Checks the encoded element to not contains reserved namespace prefixes if namespaces and all('ns%d' % k not in namespaces for k in range(10)): self.check_namespace_prefixes( etree_tostring(elem1, namespaces=namespaces)) # Main check: compare original a re-encoded tree try: etree_elements_assert_equal(root, elem1, strict=False) except AssertionError as err: # If the check fails retry only if the converter is lossy (eg. ParkerConverter) # or if the XML case has defaults taken from the schema or some part of data # decoding is skipped by schema wildcards (set the specific argument in testfiles). if converter not in (ParkerConverter, AbderaConverter, JsonMLConverter) and not skip_strict: if debug_mode: pdb.set_trace() raise AssertionError( str(err) + msg_tmpl % "encoded tree differs from original") elif converter is ParkerConverter and any( XSI_TYPE in e.attrib for e in root.iter()): return # can't check encode equivalence if xsi:type is provided else: # Lossy or augmenting cases are checked after another decoding/encoding pass data2 = self.schema.decode(elem1, converter=converter, **kwargs) if isinstance(data2, tuple): data2 = data2[0] if sys.version_info >= (3, 6): # For Python < 3.6 cannot ensure attribute decoding order try: self.assertEqual( data1, data2, msg_tmpl % "re-decoded data changed") except AssertionError: if debug_mode: pdb.set_trace() raise elem2 = self.schema.encode(data2, path=root.tag, converter=converter, **kwargs) if isinstance(elem2, tuple): elem2 = elem2[0] try: etree_elements_assert_equal(elem1, elem2, strict=False) except AssertionError as err: if debug_mode: pdb.set_trace() raise AssertionError( str(err) + msg_tmpl % "encoded tree differs after second pass")
def test_schema(self): if debug_mode: print("\n##\n## Testing schema %s in debug mode.\n##" % rel_path) import pdb pdb.set_trace() if inspect: SchemaObserver.clear() def check_schema(): if expected_errors > 0: xs = schema_class(xsd_file, validation='lax', locations=locations, defuse=defuse) else: xs = schema_class(xsd_file, locations=locations, defuse=defuse) errors_ = xs.all_errors if inspect: components_ids = set([id(c) for c in xs.iter_components()]) missing = [c for c in SchemaObserver.components if id(c) not in components_ids] if any([c for c in missing]): raise ValueError("schema missing %d components: %r" % (len(missing), missing)) # Pickling test (only for Python 3, skip inspected schema classes test) if not inspect and PY3: deserialized_schema = pickle.loads(pickle.dumps(xs)) self.assertTrue(isinstance(deserialized_schema, XMLSchemaBase)) self.assertEqual(xs.built, deserialized_schema.built) # XPath API tests if not inspect and not errors_: context = ElementPathContext(xs) elements = [x for x in xs.iter()] context_elements = [x for x in context.iter() if isinstance(x, XsdValidator)] self.assertEqual(context_elements, [x for x in context.iter_descendants()]) self.assertEqual(context_elements, elements) return errors_ if expected_warnings > 0: with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter("always") errors = check_schema() self.assertEqual(len(ctx), expected_warnings, "Wrong number of include/import warnings") else: errors = check_schema() # Checks errors completeness for e in errors: error_string = unicode_type(e) self.assertTrue(e.path, "Missing path for: %s" % error_string) self.assertTrue(e.namespaces, "Missing namespaces for: %s" % error_string) self.check_namespace_prefixes(error_string) num_errors = len(errors) if num_errors != expected_errors: print("\n%s: %r errors, %r expected." % (self.id()[13:], num_errors, expected_errors)) if num_errors == 0: raise ValueError("found no errors when %d expected." % expected_errors) else: raise ValueError("n.%d errors expected, found %d: %s" % ( expected_errors, num_errors, '\n++++++\n'.join([str(e) for e in errors]) )) else: self.assertTrue(True, "Successfully created schema for {}".format(xsd_file))