Package xmlschema_acue :: Package validators :: Module attributes

Source Code for Module xmlschema_acue.validators.attributes

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (c), 2016-2019, SISSA (International School for Advanced Studies). 
  4  # All rights reserved. 
  5  # This file is distributed under the terms of the MIT License. 
  6  # See the file 'LICENSE' in the root directory of the present 
  7  # distribution, or http://opensource.org/licenses/MIT. 
  8  # 
  9  # @author Davide Brunato <brunato@sissa.it> 
 10  # 
 11  """ 
 12  This module contains classes for XML Schema attributes and attribute groups. 
 13  """ 
 14  from __future__ import unicode_literals 
 15  from decimal import Decimal 
 16  from elementpath.datatypes import AbstractDateTime, Duration 
 17   
 18  from xmlschema_acue.compat import MutableMapping, ordered_dict_class 
 19  from xmlschema_acue.exceptions import XMLSchemaAttributeError, XMLSchemaTypeError, XMLSchemaValueError 
 20  from xmlschema_acue.qnames import XSD_ANY_SIMPLE_TYPE, XSD_SIMPLE_TYPE, XSD_ATTRIBUTE_GROUP, XSD_COMPLEX_TYPE, \ 
 21      XSD_RESTRICTION, XSD_EXTENSION, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE 
 22  from xmlschema_acue.helpers import get_namespace, get_qname, get_xsd_form_attribute 
 23  from xmlschema_acue.namespaces import XSI_NAMESPACE 
 24   
 25  from xmlschema_acue.validators.exceptions import XMLSchemaValidationError 
 26  from xmlschema_acue.validators.xsdbase import XsdComponent, ValidationMixin 
 27  from xmlschema_acue.validators.simple_types import XsdSimpleType 
 28  from xmlschema_acue.validators.wildcards import XsdAnyAttribute 
29 30 31 -class XsdAttribute(XsdComponent, ValidationMixin):
32 """ 33 Class for XSD 1.0 'attribute' declarations. 34 35 <attribute 36 default = string 37 fixed = string 38 form = (qualified | unqualified) 39 id = ID 40 name = NCName 41 ref = QName 42 type = QName 43 use = (optional | prohibited | required) : optional 44 {any attributes with non-schema namespace ...}> 45 Content: (annotation?, simpleType?) 46 </attribute> 47 """ 48 _admitted_tags = {XSD_ATTRIBUTE} 49 qualified = False 50
51 - def __init__(self, elem, schema, parent, name=None, xsd_type=None):
52 if xsd_type is not None: 53 self.type = xsd_type 54 super(XsdAttribute, self).__init__(elem, schema, parent, name) 55 self.names = (self.qualified_name,) if self.qualified else (self.qualified_name, self.local_name) 56 if not hasattr(self, 'type'): 57 raise XMLSchemaAttributeError("undefined 'type' for %r." % self)
58
59 - def __repr__(self):
60 if self.ref is None: 61 return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) 62 else: 63 return '%s(ref=%r)' % (self.__class__.__name__, self.prefixed_name)
64
65 - def __setattr__(self, name, value):
66 if name == "type": 67 if not isinstance(value, XsdSimpleType): 68 raise XMLSchemaTypeError("An XSD attribute's type must be a simpleType.") 69 super(XsdAttribute, self).__setattr__(name, value)
70
71 - def _parse(self):
72 super(XsdAttribute, self)._parse() 73 elem = self.elem 74 75 try: 76 form = self.form 77 except ValueError as err: 78 self.parse_error(err) 79 else: 80 if form is None: 81 self.qualified = self.schema.attribute_form_default == 'qualified' 82 elif self.parent is None: 83 self.parse_error("attribute 'form' not allowed in a global attribute.") 84 else: 85 self.qualified = form == 'qualified' 86 87 self.use = elem.get('use') 88 if self.use is None: 89 self.use = 'optional' 90 elif self.parent is None: 91 self.parse_error("attribute 'use' not allowed in a global attribute.") 92 elif self.use not in {'optional', 'prohibited', 'required'}: 93 self.parse_error("wrong value %r for 'use' attribute." % self.use) 94 self.use = 'optional' 95 96 name = elem.get('name') 97 if name is not None: 98 if 'ref' in elem.attrib: 99 self.parse_error("both 'name' and 'ref' in attribute declaration") 100 elif name == 'xmlns': 101 self.parse_error("an attribute name must be different from 'xmlns'") 102 103 if self.parent is None or self.qualified: 104 if self.target_namespace == XSI_NAMESPACE and \ 105 name not in {'nil', 'type', 'schemaLocation', 'noNamespaceSchemaLocation'}: 106 self.parse_error("Cannot add attributes in %r namespace" % XSI_NAMESPACE) 107 self.name = get_qname(self.target_namespace, name) 108 else: 109 self.name = name 110 elif self.parent is None: 111 self.parse_error("missing 'name' in global attribute declaration") 112 else: 113 try: 114 attribute_qname = self.schema.resolve_qname(elem.attrib['ref']) 115 except KeyError: 116 self.parse_error("missing both 'name' and 'ref' in attribute declaration") 117 self.xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE) 118 return 119 except ValueError as err: 120 self.parse_error(err) 121 self.xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE) 122 return 123 else: 124 try: 125 xsd_attribute = self.maps.lookup_attribute(attribute_qname) 126 except LookupError: 127 self.parse_error("unknown attribute %r" % elem.attrib['ref']) 128 self.type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE) 129 else: 130 self.type = xsd_attribute.type 131 self.qualified = xsd_attribute.qualified 132 if xsd_attribute.fixed is not None and 'fixed' in elem.attrib and \ 133 elem.get('fixed') != xsd_attribute.fixed: 134 self.parse_error("referenced attribute has a different fixed value %r" % xsd_attribute.fixed) 135 136 self.name = attribute_qname 137 for attribute in ('form', 'type'): 138 if attribute in self.elem.attrib: 139 self.parse_error("attribute %r is not allowed when attribute reference is used." % attribute) 140 xsd_declaration = self._parse_component(elem, required=False) 141 142 if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE: 143 self.parse_error("not allowed type declaration for XSD attribute reference") 144 return 145 146 xsd_declaration = self._parse_component(elem, required=False) 147 try: 148 type_qname = self.schema.resolve_qname(elem.attrib['type']) 149 except ValueError as err: 150 self.parse_error(err, elem) 151 xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE) 152 except KeyError: 153 if xsd_declaration is not None: 154 # No 'type' attribute in declaration, parse for child local simpleType 155 xsd_type = self.schema.BUILDERS.simple_type_factory(xsd_declaration, self.schema, self) 156 else: 157 # Empty declaration means xsdAnySimpleType 158 xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE) 159 else: 160 try: 161 xsd_type = self.maps.lookup_type(type_qname) 162 except LookupError as err: 163 self.parse_error(err, elem) 164 xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE) 165 166 if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE: 167 self.parse_error("ambiguous type declaration for XSD attribute") 168 elif xsd_declaration: 169 self.parse_error("not allowed element in XSD attribute declaration: %r" % xsd_declaration[0]) 170 171 try: 172 self.type = xsd_type 173 except TypeError as err: 174 self.parse_error(err) 175 176 # Check value constraints 177 if 'default' in elem.attrib: 178 if 'fixed' in elem.attrib: 179 self.parse_error("'default' and 'fixed' attributes are mutually exclusive") 180 if self.use != 'optional': 181 self.parse_error("the attribute 'use' must be 'optional' if the attribute 'default' is present") 182 if not self.type.is_valid(elem.attrib['default']): 183 msg = "'default' value {!r} is not compatible with the type {!r}" 184 self.parse_error(msg.format(elem.attrib['default'], self.type)) 185 elif self.type.is_key(): 186 self.parse_error("'xs:ID' or a type derived from 'xs:ID' cannot has a 'default'") 187 elif 'fixed' in elem.attrib: 188 if not self.type.is_valid(elem.attrib['fixed']): 189 msg = "'fixed' value {!r} is not compatible with the type {!r}" 190 self.parse_error(msg.format(elem.attrib['fixed'], self.type)) 191 elif self.type.is_key(): 192 self.parse_error("'xs:ID' or a type derived from 'xs:ID' cannot has a 'default'")
193 194 @property
195 - def built(self):
196 return self.type.parent is None or self.type.built
197 198 @property
199 - def validation_attempted(self):
200 if self.built: 201 return 'full' 202 else: 203 return self.type.validation_attempted
204 205 # XSD declaration attributes 206 @property
207 - def ref(self):
208 return self.elem.get('ref')
209 210 @property
211 - def default(self):
212 return self.elem.get('default')
213 214 @property
215 - def fixed(self):
216 return self.elem.get('fixed')
217 218 @property
219 - def form(self):
220 return get_xsd_form_attribute(self.elem, 'form')
221
222 - def is_optional(self):
223 return self.use == 'optional'
224
225 - def iter_components(self, xsd_classes=None):
226 if xsd_classes is None or isinstance(self, xsd_classes): 227 yield self 228 if self.ref is None and self.type.parent is not None: 229 for obj in self.type.iter_components(xsd_classes): 230 yield obj
231
232 - def iter_decode(self, text, validation='lax', **kwargs):
233 if not text and kwargs.get('use_defaults', True) and self.default is not None: 234 text = self.default 235 if self.fixed is not None and text != self.fixed and validation != 'skip': 236 yield self.validation_error(validation, "value differs from fixed value", text, **kwargs) 237 238 for result in self.type.iter_decode(text, validation, **kwargs): 239 if isinstance(result, XMLSchemaValidationError): 240 yield result 241 elif isinstance(result, Decimal): 242 try: 243 yield kwargs['decimal_type'](result) 244 except (KeyError, TypeError): 245 yield result 246 break 247 elif isinstance(result, (AbstractDateTime, Duration)): 248 try: 249 yield result if kwargs['datetime_types'] is True else text 250 except KeyError: 251 yield text 252 else: 253 yield result 254 break
255
256 - def iter_encode(self, obj, validation='lax', **kwargs):
257 for result in self.type.iter_encode(obj, validation): 258 yield result 259 if not isinstance(result, XMLSchemaValidationError): 260 return
261
262 263 -class Xsd11Attribute(XsdAttribute):
264 """ 265 Class for XSD 1.1 'attribute' declarations. 266 267 <attribute 268 default = string 269 fixed = string 270 form = (qualified | unqualified) 271 id = ID 272 name = NCName 273 ref = QName 274 targetNamespace = anyURI 275 type = QName 276 use = (optional | prohibited | required) : optional 277 inheritable = boolean 278 {any attributes with non-schema namespace . . .}> 279 Content: (annotation?, simpleType?) 280 </attribute> 281 """ 282 @property
283 - def inheritable(self):
284 return self.elem.get('inheritable') in ('0', 'true')
285 286 @property
287 - def target_namespace(self):
288 return self.elem.get('targetNamespace', self.schema.target_namespace)
289
290 - def _parse(self):
291 super(Xsd11Attribute, self)._parse() 292 if not self.elem.get('inheritable') not in {'0', '1', 'false', 'true'}: 293 self.parse_error("an XML boolean value is required for attribute 'inheritable'") 294 self._parse_target_namespace()
295
296 297 -class XsdAttributeGroup(MutableMapping, XsdComponent, ValidationMixin):
298 """ 299 Class for XSD 'attributeGroup' definitions. 300 301 <attributeGroup 302 id = ID 303 name = NCName 304 ref = QName 305 {any attributes with non-schema namespace . . .}> 306 Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?)) 307 </attributeGroup> 308 """ 309 redefine = None 310 _admitted_tags = { 311 XSD_ATTRIBUTE_GROUP, XSD_COMPLEX_TYPE, XSD_RESTRICTION, XSD_EXTENSION, 312 XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE 313 } 314
315 - def __init__(self, elem, schema, parent, name=None, derivation=None, base_attributes=None):
316 self.derivation = derivation 317 self._attribute_group = ordered_dict_class() 318 self.base_attributes = base_attributes 319 XsdComponent.__init__(self, elem, schema, parent, name)
320
321 - def __repr__(self):
322 if self.ref is not None: 323 return '%s(ref=%r)' % (self.__class__.__name__, self.prefixed_name) 324 elif self.name is not None: 325 return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) 326 elif self: 327 names = [a if a.name is None else a.prefixed_name for a in self.values()] 328 return '%s(%r)' % (self.__class__.__name__, names) 329 else: 330 return '%s()' % self.__class__.__name__
331 332 # Implementation of abstract methods
333 - def __getitem__(self, key):
334 return self._attribute_group[key]
335
336 - def __setitem__(self, key, value):
337 if key is None: 338 assert isinstance(value, XsdAnyAttribute), 'An XsdAnyAttribute instance is required.' 339 self._attribute_group[key] = value 340 else: 341 assert isinstance(value, XsdAttribute), 'An XsdAttribute instance is required.' 342 if key[0] != '{': 343 if value.local_name != key: 344 raise XMLSchemaValueError("%r name and key %r mismatch." % (value.name, key)) 345 if value.target_namespace != self.target_namespace: 346 # Qualify attributes of other namespaces 347 key = value.qualified_name 348 elif value.qualified_name != key: 349 raise XMLSchemaValueError("%r name and key %r mismatch." % (value.name, key)) 350 351 self._attribute_group[key] = value
352
353 - def __delitem__(self, key):
354 del self._attribute_group[key]
355
356 - def __iter__(self):
357 if None in self._attribute_group: 358 # Put AnyAttribute ('None' key) at the end of iteration 359 return iter(sorted(self._attribute_group, key=lambda x: (x is None, x))) 360 else: 361 return iter(self._attribute_group)
362
363 - def __len__(self):
364 return len(self._attribute_group)
365 366 # Other methods
367 - def __setattr__(self, name, value):
368 super(XsdAttributeGroup, self).__setattr__(name, value) 369 if name == '_attribute_group': 370 assert isinstance(value, dict), 'A dictionary object is required.' 371 for k, v in value.items(): 372 if k is None: 373 assert isinstance(value, XsdAnyAttribute), 'An XsdAnyAttribute instance is required.' 374 else: 375 assert isinstance(value, XsdAttribute), 'An XsdAttribute instance is required.'
376
377 - def _parse(self):
378 super(XsdAttributeGroup, self)._parse() 379 elem = self.elem 380 any_attribute = False 381 attribute_group_refs = [] 382 383 if elem.tag == XSD_ATTRIBUTE_GROUP: 384 if self.parent is not None: 385 return # Skip dummy definitions 386 try: 387 self.name = get_qname(self.target_namespace, self.elem.attrib['name']) 388 except KeyError: 389 self.parse_error("an attribute group declaration requires a 'name' attribute.") 390 return 391 392 attributes = ordered_dict_class() 393 for child in self._iterparse_components(elem): 394 if any_attribute: 395 if child.tag == XSD_ANY_ATTRIBUTE: 396 self.parse_error("more anyAttribute declarations in the same attribute group") 397 else: 398 self.parse_error("another declaration after anyAttribute") 399 400 elif child.tag == XSD_ANY_ATTRIBUTE: 401 any_attribute = True 402 attributes.update([(None, XsdAnyAttribute(child, self.schema, self))]) 403 404 elif child.tag == XSD_ATTRIBUTE: 405 attribute = self.schema.BUILDERS.attribute_class(child, self.schema, self) 406 if attribute.name in attributes: 407 self.parse_error("multiple declaration for attribute {!r}".format(attribute.name)) 408 else: 409 attributes[attribute.name] = attribute 410 411 elif child.tag == XSD_ATTRIBUTE_GROUP: 412 try: 413 ref = child.attrib['ref'] 414 attribute_group_qname = self.schema.resolve_qname(ref) 415 except ValueError as err: 416 self.parse_error(err, elem) 417 except KeyError: 418 self.parse_error("the attribute 'ref' is required in a local attributeGroup", elem) 419 else: 420 if attribute_group_qname in attribute_group_refs: 421 self.parse_error("duplicated attributeGroup %r" % ref) 422 elif self.redefine is not None: 423 if attribute_group_qname == self.name: 424 if attribute_group_refs: 425 self.parse_error("in a redefinition the reference to itself must be the first") 426 attribute_group_refs.append(attribute_group_qname) 427 attributes.update(self._attribute_group.items()) 428 continue 429 elif not attribute_group_refs: 430 # May be an attributeGroup restriction with a ref to another group 431 if not any(e.tag == XSD_ATTRIBUTE_GROUP and ref == e.get('ref') 432 for e in self.redefine.elem): 433 self.parse_error("attributeGroup ref=%r is not in the redefined group" % ref) 434 elif attribute_group_qname == self.name and self.schema.XSD_VERSION == '1.0': 435 self.parse_error("Circular attribute groups not allowed in XSD 1.0") 436 attribute_group_refs.append(attribute_group_qname) 437 438 try: 439 base_attributes = self.maps.lookup_attribute_group(attribute_group_qname) 440 except LookupError: 441 self.parse_error("unknown attribute group %r" % child.attrib['ref'], elem) 442 else: 443 if isinstance(base_attributes, tuple): 444 self.parse_error("Circular reference found between attribute groups " 445 "{!r} and {!r}".format(self.name, attribute_group_qname)) 446 447 for name, attr in base_attributes.items(): 448 if name is not None and name in attributes: 449 self.parse_error("multiple declaration for attribute {!r}".format(name)) 450 else: 451 attributes[name] = attr 452 453 elif self.name is not None: 454 self.parse_error("(attribute | attributeGroup) expected, found %r." % child) 455 456 # Check and copy base attributes 457 if self.base_attributes is not None: 458 wildcard = self.base_attributes.get(None) 459 for name, attr in attributes.items(): 460 if name not in self.base_attributes: 461 if self.derivation != 'restriction': 462 continue 463 elif wildcard is None or not wildcard.is_matching(name, self.default_namespace): 464 self.parse_error("Unexpected attribute %r in restriction" % name) 465 continue 466 467 base_attr = self.base_attributes[name] 468 469 if name is None: 470 if self.derivation == 'extension': 471 try: 472 attr.extend_namespace(base_attr) 473 except ValueError as err: 474 self.parse_error(err) 475 elif not attr.is_restriction(base_attr): 476 self.parse_error("Attribute wildcard is not a restriction of the base wildcard") 477 continue 478 if self.derivation == 'restriction' and attr.type.name != XSD_ANY_SIMPLE_TYPE and \ 479 not attr.type.is_derived(base_attr.type, 'restriction'): 480 self.parse_error("Attribute type is not a restriction of the base attribute type") 481 if base_attr.use != 'optional' and attr.use == 'optional' or \ 482 base_attr.use == 'required' and attr.use != 'required': 483 self.parse_error("Attribute %r: unmatched attribute use in restriction" % name) 484 if base_attr.fixed is not None and \ 485 attr.type.normalize(attr.fixed) != base_attr.type.normalize(base_attr.fixed): 486 self.parse_error("Attribute %r: derived attribute has a different fixed value" % name) 487 488 self._attribute_group.update(self.base_attributes.items()) 489 elif self.redefine is not None and not attribute_group_refs: 490 for name, attr in self._attribute_group.items(): 491 if name is None: 492 continue 493 elif name not in attributes: 494 if attr.use == 'required': 495 self.parse_error("Missing required attribute %r in redefinition restriction" % name) 496 continue 497 if attr.use != 'optional' and attributes[name].use != attr.use: 498 self.parse_error("Attribute %r: unmatched attribute use in redefinition" % name) 499 if attr.fixed is not None and attributes[name].fixed is None: 500 self.parse_error("Attribute %r: redefinition remove fixed constraint" % name) 501 502 pos = 0 503 keys = list(self._attribute_group.keys()) 504 for name in attributes: 505 try: 506 next_pos = keys.index(name) 507 except ValueError: 508 self.parse_error("Redefinition restriction contains additional attribute %r" % name) 509 else: 510 if next_pos < pos: 511 self.parse_error("Wrong attribute order in redefinition restriction") 512 break 513 pos = next_pos 514 self.clear() 515 516 self._attribute_group.update(attributes) 517 518 if self.schema.XSD_VERSION == '1.0': 519 has_key = False 520 for attr in self._attribute_group.values(): 521 if attr.name is not None and attr.type.is_key(): 522 if has_key: 523 self.parse_error("multiple key attributes in a group not allowed in XSD 1.0") 524 has_key = True 525 526 elif self.parent is None and self.schema.default_attributes == self.name: 527 self.schema.default_attributes = self
528 529 @property
530 - def built(self):
531 return all([attr.built for attr in self.values()])
532 533 @property
534 - def validation_attempted(self):
535 if self.built: 536 return 'full' 537 elif any([attr.validation_attempted == 'partial' for attr in self.values()]): 538 return 'partial' 539 else: 540 return 'none'
541 542 @property
543 - def ref(self):
544 return self.elem.get('ref')
545
546 - def iter_required(self):
547 for k, v in self._attribute_group.items(): 548 if k is not None and v.use == 'required': 549 yield k
550
551 - def iter_components(self, xsd_classes=None):
552 if xsd_classes is None or isinstance(self, xsd_classes): 553 yield self 554 if self.ref is None: 555 for attr in self.values(): 556 if attr.parent is not None: 557 for obj in attr.iter_components(xsd_classes): 558 yield obj
559
560 - def iter_decode(self, attrs, validation='lax', **kwargs):
561 if not attrs and not self: 562 return 563 564 result_list = [] 565 required_attributes = {a for a in self.iter_required()} 566 for name, value in attrs.items(): 567 try: 568 xsd_attribute = self[name] 569 except KeyError: 570 if get_namespace(name) == XSI_NAMESPACE: 571 try: 572 xsd_attribute = self.maps.lookup_attribute(name) 573 except LookupError: 574 if validation != 'skip': 575 reason = "%r is not an attribute of the XSI namespace." % name 576 yield self.validation_error(validation, reason, attrs, **kwargs) 577 continue 578 else: 579 try: 580 xsd_attribute = self[None] # None key ==> anyAttribute 581 value = (name, value) 582 except KeyError: 583 if validation != 'skip': 584 reason = "%r attribute not allowed for element." % name 585 yield self.validation_error(validation, reason, attrs, **kwargs) 586 continue 587 else: 588 required_attributes.discard(name) 589 590 for result in xsd_attribute.iter_decode(value, validation, **kwargs): 591 if isinstance(result, XMLSchemaValidationError): 592 yield result 593 else: 594 result_list.append((name, result)) 595 break 596 597 if required_attributes and validation != 'skip': 598 reason = "missing required attributes: %r" % required_attributes 599 yield self.validation_error(validation, reason, attrs, **kwargs) 600 601 yield result_list
602
603 - def iter_encode(self, attrs, validation='lax', **kwargs):
604 result_list = [] 605 required_attributes = {a for a in self.iter_required()} 606 try: 607 attrs = attrs.items() 608 except AttributeError: 609 pass 610 611 for name, value in attrs: 612 try: 613 xsd_attribute = self[name] 614 except KeyError: 615 namespace = get_namespace(name) or self.target_namespace 616 if namespace == XSI_NAMESPACE: 617 try: 618 xsd_attribute = self.maps.lookup_attribute(name) 619 except LookupError: 620 if validation != 'skip': 621 reason = "%r is not an attribute of the XSI namespace." % name 622 yield self.validation_error(validation, reason, attrs, **kwargs) 623 continue 624 else: 625 try: 626 xsd_attribute = self[None] # None key ==> anyAttribute 627 value = (name, value) 628 except KeyError: 629 if validation != 'skip': 630 reason = "%r attribute not allowed for element." % name 631 yield self.validation_error(validation, reason, attrs, **kwargs) 632 continue 633 else: 634 required_attributes.discard(name) 635 636 for result in xsd_attribute.iter_encode(value, validation, **kwargs): 637 if isinstance(result, XMLSchemaValidationError): 638 yield result 639 else: 640 result_list.append((name, result)) 641 break 642 643 if required_attributes and validation != 'skip': 644 reason = "missing required attributes %r" % required_attributes 645 yield self.validation_error(validation, reason, attrs, **kwargs) 646 yield result_list
647