1# -*- coding: utf-8 -*- 2# Copyright 2009-2013, Peter A. Bigot 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); you may 5# not use this file except in compliance with the License. You may obtain a 6# copy of the License at: 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13# License for the specific language governing permissions and limitations 14# under the License. 15 16"""Extensions of standard exceptions for PyXB events. 17 18Yeah, I'd love this module to be named exceptions.py, but it can't 19because the standard library has one of those, and we need to 20reference it below. 21""" 22 23import pyxb 24from pyxb.utils import six 25 26class PyXBException (Exception): 27 """Base class for exceptions that indicate a problem that the user should fix.""" 28 29 """The arguments passed to the exception constructor.""" 30 _args = None 31 32 """The keywords passed to the exception constructor. 33 34 @note: Do not pop values from the keywords array in subclass 35 constructors that recognize and extract values from them. They 36 should be kept around so they're accessible generically.""" 37 _kw = None 38 39 def __init__ (self, *args, **kw): 40 """Create an exception indicating a PyXB-related problem. 41 42 If no args are present, a default argument is taken from the 43 C{message} keyword. 44 45 @keyword message : Text to provide the user with information about the problem. 46 """ 47 if 0 == len(args) and 'message' in kw: 48 args = (kw.pop('message'),) 49 self._args = args 50 self._kw = kw 51 super(PyXBException, self).__init__(*args) 52 53 if six.PY2: 54 def _str_from_unicode (self): 55 return unicode(self).encode(pyxb._OutputEncoding) 56 57class PyXBVersionError (PyXBException): 58 """Raised on import of a binding generated with a different version of PYXB""" 59 pass 60 61class DOMGenerationError (PyXBException): 62 """A non-validation error encountered converting bindings to DOM.""" 63 pass 64 65@six.python_2_unicode_compatible 66class UnboundElementError (DOMGenerationError): 67 """An instance converting to DOM had no bound element.""" 68 69 instance = None 70 """The binding instance. This is missing an element binding (via 71 L{pyxb.binding.basis._TypeBinding_mixin._element}) and no 72 C{element_name} was passed.""" 73 74 def __init__ (self, instance): 75 super(UnboundElementError, self).__init__(instance) 76 self.instance = instance 77 78 def __str__ (self): 79 return six.u('Instance of type %s has no bound element for start tag') % (self.instance._diagnosticName(),) 80 81class SchemaValidationError (PyXBException): 82 """Raised when the XML hierarchy does not appear to be valid for an XML schema.""" 83 pass 84 85class NamespaceError (PyXBException): 86 """Violation of some rule relevant to XML Namespaces""" 87 def __init__ (self, namespace, *args, **kw): 88 PyXBException.__init__(self, *args, **kw) 89 self.__namespace = namespace 90 91 def namespace (self): return self.__namespace 92 93class NamespaceArchiveError (PyXBException): 94 """Problem related to namespace archives""" 95 pass 96 97class SchemaUniquenessError (PyXBException): 98 """Raised when somebody tries to create a schema component using a 99 schema that has already been used in that namespace. Import and 100 include processing would have avoided this, so somebody asked for 101 it specifically.""" 102 def __init__ (self, namespace, schema_location, existing_schema, *args, **kw): 103 super(SchemaUniquenessError, self).__init__(*args, **kw) 104 self.__namespace = namespace 105 self.__schemaLocation = schema_location 106 self.__existingSchema = existing_schema 107 108 def namespace (self): return self.__namespace 109 def schemaLocation (self): return self.__schemaLocation 110 def existingSchema (self): return self.__existingSchema 111 112class BindingGenerationError (PyXBException): 113 """Raised when something goes wrong generating the binding classes""" 114 pass 115 116class NamespaceUniquenessError (NamespaceError): 117 """Raised when an attempt is made to record multiple objects of the same name in the same namespace category.""" 118 pass 119 120class NotInNamespaceError (PyXBException): 121 '''Raised when a name is referenced that is not defined in the appropriate namespace.''' 122 __namespace = None 123 __ncName = None 124 125class QNameResolutionError (NamespaceError): 126 '''Raised when a QName cannot be associated with a namespace.''' 127 namespaceContext = None 128 qname = None 129 130 def __init__ (self, message, qname, xmlns_context): 131 self.qname = qname 132 self.namespaceContext = xmlns_context 133 super(QNameResolutionError, self).__init__(message, qname, xmlns_context) 134 135class BadDocumentError (PyXBException): 136 """Raised when processing document content and an error is encountered.""" 137 pass 138 139class StructuralBadDocumentError (BadDocumentError): 140 """Raised when processing document and the content model is not satisfied.""" 141 @property 142 def element_use (self): 143 """The L{pyxb.binding.content.ElementDeclaration} instance to which the content should conform, if available.""" 144 return self.__elementUse 145 146 @property 147 def container (self): 148 """The L{pyxb.binding.basis.complexTypeDefinition} instance to which the content would belong, if available.""" 149 return self.__container 150 151 @property 152 def content (self): 153 """The value which could not be reconciled with the content model.""" 154 return self.__content 155 156 def __init__ (self, *args, **kw): 157 """Raised when processing document and the content model is not satisfied. 158 159 @keyword content : The value that could not be reconciled with the content model 160 @keyword container : Optional binding instance into which the content was to be assigned 161 @keyword element_use : Optional reference to an element use identifying the element to which the value was to be reconciled 162 """ 163 self.__content = kw.pop('content', None) 164 if args: 165 self.__content = args[0] 166 self.__container = kw.pop('container', None) 167 self.__elementUse = kw.pop('element_use', None) 168 if self.__content is not None: 169 if self.__container is not None: 170 kw.setdefault('message', '%s cannot accept wildcard content %s' % (self.__container._Name(), self.__content)) 171 elif self.__elementUse is not None: 172 kw.setdefault('message', '%s not consistent with content model for %s' % (self.__content, self.__elementUse)) 173 else: 174 kw.setdefault('message', six.text_type(self.__content)) 175 BadDocumentError.__init__(self, **kw) 176 177class UnrecognizedDOMRootNodeError (StructuralBadDocumentError): 178 """A root DOM node could not be resolved to a schema element""" 179 180 node = None 181 """The L{xml.dom.Element} instance that could not be recognized""" 182 183 def __get_node_name (self): 184 """The QName of the L{node} as a L{pyxb.namespace.ExpandedName}""" 185 import pyxb.namespace 186 return pyxb.namespace.ExpandedName(self.node.namespaceURI, self.node.localName) 187 node_name = property(__get_node_name) 188 189 def __init__ (self, node): 190 """@param node: the value for the L{node} attribute.""" 191 self.node = node 192 super(UnrecognizedDOMRootNodeError, self).__init__(node) 193 194class ValidationError (PyXBException): 195 """Raised when something in the infoset fails to satisfy a content model or attribute requirement. 196 197 All validation errors include a L{location} attribute which shows 198 where in the original XML the problem occurred. The attribute may 199 be C{None} if the content did not come from an XML document, or 200 the underlying XML infrastructure did not provide a location. 201 202 More refined validation error exception classes add more attributes.""" 203 204 location = None 205 """Where the error occurred in the document being parsed, if 206 available. This will be C{None}, or an instance of 207 L{pyxb.utils.utility.Location}.""" 208 209 def details (self): 210 """Provide information describing why validation failed. 211 212 In many cases, this is simply the informal string content that 213 would be obtained through the C{str} built-in function. For 214 certain errors this method gives more details on what would be 215 acceptable and where the descriptions can be found in the 216 original schema. 217 218 @return: a string description of validation failure""" 219 return six.text_type(self) 220 221@six.python_2_unicode_compatible 222class NonElementValidationError (ValidationError): 223 """Raised when an element (or a value bound to an element) appears 224 in context that does not permit an element.""" 225 226 element = None 227 """The content that is not permitted. This may be an element, or 228 a DOM representation that would have been made into an element had 229 matters progressed further.""" 230 231 def __init__ (self, element, location=None): 232 """@param element: the value for the L{element} attribute. 233 @param location: the value for the L{location} attribute. 234 """ 235 self.element = element 236 if (location is None) and isinstance(element, pyxb.utils.utility.Locatable_mixin): 237 location = element._location() 238 self.location = location 239 super(NonElementValidationError, self).__init__(element, location) 240 241 def __str__ (self): 242 import pyxb.binding.basis 243 import xml.dom 244 value = '' 245 boundto = '' 246 location = '' 247 if isinstance(self.element, pyxb.binding.basis._TypeBinding_mixin): 248 eb = self.element._element() 249 boundto = '' 250 if eb is not None: 251 boundto = ' bound to %s' % (eb.name(),) 252 if isinstance(self.element, pyxb.binding.basis.simpleTypeDefinition): 253 value = self.element.xsdLiteral() 254 elif self.element._IsSimpleTypeContent(): 255 value = six.text_type(self.element.value()) 256 else: 257 value = 'Complex value' 258 elif isinstance(self.element, xml.dom.Node): 259 value = 'DOM node %s' % (self.element.nodeName,) 260 else: 261 value = '%s type %s' % (six.text_type(self.element), type(self.element)) 262 if self.location is not None: 263 location = ' at %s' % (self.location,) 264 return six.u('%s%s not permitted%s') % (value, boundto, location) 265 266class ElementValidationError (ValidationError): 267 """Raised when a validation requirement for an element is not satisfied.""" 268 pass 269 270@six.python_2_unicode_compatible 271class AbstractElementError (ElementValidationError): 272 """Attempt to create an instance of an abstract element. 273 274 Raised when an element is created and the identified binding is 275 abstract. Such elements cannot be created directly; instead the 276 creation must derive from an instance of the abstract element's 277 substitution group. 278 279 Since members of the substitution group self-identify using the 280 C{substitutionGroup} attribute, there is no general way to find 281 the set of elements which would be acceptable in place of the 282 abstract element.""" 283 284 element = None 285 """The abstract L{pyxb.binding.basis.element} in question""" 286 287 value = None 288 """The value proposed for the L{element}. This is usually going 289 to be a C{xml.dom.Node} used in the attempt to create the element, 290 C{None} if the abstract element was invoked without a node, or 291 another type if 292 L{pyxb.binding.content.ElementDeclaration.toDOM} is 293 mis-used.""" 294 295 def __init__ (self, element, location, value=None): 296 """@param element: the value for the L{element} attribute. 297 @param location: the value for the L{location} attribute. 298 @param value: the value for the L{value} attribute.""" 299 self.element = element 300 self.location = location 301 self.value = value 302 super(AbstractElementError, self).__init__(element, location, value) 303 304 def __str__ (self): 305 return six.u('Cannot instantiate abstract element %s directly') % (self.element.name(),) 306 307@six.python_2_unicode_compatible 308class ContentInNilInstanceError (ElementValidationError): 309 """Raised when an element that is marked to be nil is assigned content.""" 310 311 instance = None 312 """The binding instance which is xsi:nil""" 313 314 content = None 315 """The content that was to be assigned to the instance.""" 316 317 def __init__ (self, instance, content, location=None): 318 """@param instance: the value for the L{instance} attribute. 319 @param content: the value for the L{content} attribute. 320 @param location: the value for the L{location} attribute. Default taken from C{instance} if possible.""" 321 322 self.instance = instance 323 self.content = content 324 if location is None: 325 location = self.instance._location() 326 self.location = location 327 super(ContentInNilInstanceError, self).__init__(instance, content, location) 328 329 def __str__ (self): 330 from pyxb.namespace.builtin import XMLSchema_instance as XSI 331 return six.u('%s with %s=true cannot have content') % (self.instance._diagnosticName(), XSI.nil) 332 333class NoNillableSupportError (ElementValidationError): 334 """Raised when invoking L{_setIsNil<pyxb.binding.basis._TypeBinding_mixin._setIsNil>} on a type that does not support nillable.""" 335 336 instance = None 337 """The binding instance on which an inappropriate operation was invoked.""" 338 339 def __init__ (self, instance, location=None): 340 """@param instance: the value for the L{instance} attribute. 341 @param location: the value for the L{location} attribute. Default taken from C{instance} if possible.""" 342 self.instance = instance 343 if location is None: 344 location = self.instance._location() 345 self.location = location 346 super(NoNillableSupportError, self).__init__(instance, location) 347 348@six.python_2_unicode_compatible 349class ElementChangeError (ElementValidationError): 350 """Attempt to change an element that has a fixed value constraint.""" 351 352 element = None 353 """The L{pyxb.binding.basis.element} that has a fixed value.""" 354 355 value = None 356 """The value that was to be assigned to the element.""" 357 358 def __init__ (self, element, value, location=None): 359 """@param element: the value for the L{element} attribute. 360 @param value: the value for the L{value} attribute. 361 @param location: the value for the L{location} attribute. Default taken from C{value} if possible.""" 362 363 import pyxb.utils.utility 364 self.element = element 365 self.value = value 366 if (location is None) and isinstance(value, pyxb.utils.utility.Locatable_mixin): 367 location = value._location() 368 self.location = location 369 super(ElementChangeError, self).__init__(element, value, location) 370 371 def __str__ (self): 372 return six.u('Value %s for element %s incompatible with fixed content') % (self.value, self.element.name()) 373 374class ComplexTypeValidationError (ValidationError): 375 """Raised when a validation requirement for a complex type is not satisfied.""" 376 pass 377 378@six.python_2_unicode_compatible 379class AbstractInstantiationError (ComplexTypeValidationError): 380 """Attempt to create an instance of an abstract complex type. 381 382 These types are analogous to abstract base classes, and cannot be 383 created directly. A type should be used that extends the abstract 384 class. 385 386 When an incoming document is missing the xsi:type attribute which 387 redirects an element with an abstract type to the correct type, 388 the L{node} attribute is provided so the user can get a clue as to 389 where the problem occured. When this exception is a result of 390 constructor mis-use in Python code, the traceback will tell you 391 where the problem lies. 392 """ 393 394 type = None 395 """The abstract L{pyxb.binding.basis.complexTypeDefinition} subclass used.""" 396 397 node = None 398 """The L{xml.dom.Element} from which instantiation was attempted, if available.""" 399 400 def __init__ (self, type, location, node): 401 """@param type: the value for the L{type} attribute. 402 @param location: the value for the L{location} attribute. 403 @param node: the value for the L{node} attribute.""" 404 self.type = type 405 self.location = location 406 self.node = node 407 super(AbstractInstantiationError, self).__init__(type, location, node) 408 409 def __str__ (self): 410 # If the type is abstract, it has to have a name. 411 return six.u('Cannot instantiate abstract type %s directly') % (self.type._ExpandedName,) 412 413@six.python_2_unicode_compatible 414class AttributeOnSimpleTypeError (ComplexTypeValidationError): 415 """Attempt made to set an attribute on an element with simple type. 416 417 Note that elements with complex type and simple content may have 418 attributes; elements with simple type must not.""" 419 420 instance = None 421 """The simple type binding instance on which no attributes exist.""" 422 423 tag = None 424 """The name of the proposed attribute.""" 425 426 value = None 427 """The value proposed to be assigned to the non-existent attribute.""" 428 429 def __init__ (self, instance, tag, value, location=None): 430 """@param instance: the value for the L{instance} attribute. 431 @param tag: the value for the L{tag} attribute. 432 @param value: the value for the L{value} attribute. 433 @param location: the value for the L{location} attribute. Default taken from C{instance} if possible.""" 434 435 self.instance = instance 436 self.tag = tag 437 self.value = value 438 if location is None: 439 location = self.instance._location() 440 self.location = location 441 super(AttributeOnSimpleTypeError, self).__init__(instance, tag, value, location) 442 443 def __str__ (self): 444 return six.u('Simple type %s cannot support attribute %s') % (self.instance._Name(), self.tag) 445 446class ContentValidationError (ComplexTypeValidationError): 447 """Violation of a complex type content model.""" 448 pass 449 450@six.python_2_unicode_compatible 451class ContentNondeterminismExceededError (ContentValidationError): 452 """Content validation exceeded the allowed limits of nondeterminism.""" 453 454 instance = None 455 """The binding instance being validated.""" 456 457 def __init__ (self, instance): 458 """@param instance: the value for the L{instance} attribute.""" 459 self.instance = instance 460 super(ContentNondeterminismExceededError, self).__init__(instance) 461 462 def __str__ (self): 463 return six.u('Nondeterminism exceeded validating %s') % (self.instance._Name(),) 464 465@six.python_2_unicode_compatible 466class SimpleContentAbsentError (ContentValidationError): 467 """An instance with simple content was not provided with a value.""" 468 469 instance = None 470 """The binding instance for which simple content is missing.""" 471 472 def __init__ (self, instance, location): 473 """@param instance: the value for the L{instance} attribute. 474 @param location: the value for the L{location} attribute.""" 475 self.instance = instance 476 self.location = location 477 super(SimpleContentAbsentError, self).__init__(instance, location) 478 479 def __str__ (self): 480 return six.u('Type %s requires content') % (self.instance._Name(),) 481 482@six.python_2_unicode_compatible 483class ExtraSimpleContentError (ContentValidationError): 484 """A complex type with simple content was provided too much content.""" 485 486 instance = None 487 """The binding instance that already has simple content assigned.""" 488 489 value = None 490 """The proposed addition to that simple content.""" 491 492 def __init__ (self, instance, value, location=None): 493 """@param instance: the value for the L{instance} attribute. 494 @param value: the value for the L{value} attribute. 495 @param location: the value for the L{location} attribute.""" 496 self.instance = instance 497 self.value = value 498 self.location = location 499 super(ExtraSimpleContentError, self).__init__(instance, value, location) 500 501 def __str__ (self): 502 return six.u('Instance of %s already has simple content value assigned') % (self.instance._Name(),) 503 504@six.python_2_unicode_compatible 505class NonPluralAppendError (ContentValidationError): 506 """Attempt to append to an element which does not accept multiple instances.""" 507 508 instance = None 509 """The binding instance containing the element""" 510 511 element_declaration = None 512 """The L{pyxb.binding.content.ElementDeclaration} contained in C{instance} that does not accept multiple instances""" 513 514 value = None 515 """The proposed addition to the element in the instance""" 516 517 def __init__ (self, instance, element_declaration, value): 518 """@param instance: the value for the L{instance} attribute. 519 @param element_declaration: the value for the L{element_declaration} attribute. 520 @param value: the value for the L{value} attribute.""" 521 self.instance = instance 522 self.element_declaration = element_declaration 523 self.value = value 524 super(NonPluralAppendError, self).__init__(instance, element_declaration, value) 525 526 def __str__ (self): 527 return six.u('Instance of %s cannot append to element %s') % (self.instance._Name(), self.element_declaration.name()) 528 529@six.python_2_unicode_compatible 530class MixedContentError (ContentValidationError): 531 """Non-element content added to a complex type instance that does not support mixed content.""" 532 533 instance = None 534 """The binding instance.""" 535 536 value = None 537 """The non-element content.""" 538 539 def __init__ (self, instance, value, location=None): 540 """@param instance: the value for the L{instance} attribute. 541 @param value: the value for the L{value} attribute. 542 @param location: the value for the L{location} attribute.""" 543 self.instance = instance 544 self.value = value 545 self.location = location 546 super(MixedContentError, self).__init__(instance, value, location) 547 548 def __str__ (self): 549 if self.location is not None: 550 return six.u('Invalid non-element content at %s') % (self.location,) 551 return six.u('Invalid non-element content') 552 553@six.python_2_unicode_compatible 554class UnprocessedKeywordContentError (ContentValidationError): 555 """A complex type constructor was provided with keywords that could not be recognized.""" 556 557 instance = None 558 """The binding instance being constructed.""" 559 560 keywords = None 561 """The keywords that could not be recognized. These may have been 562 intended to be attributes or elements, but cannot be identified as 563 either.""" 564 565 def __init__ (self, instance, keywords, location=None): 566 """@param instance: the value for the L{instance} attribute. 567 @param keywords: the value for the L{keywords} attribute. 568 @param location: the value for the L{location} attribute.""" 569 self.instance = instance 570 self.keywords = keywords 571 self.location = location 572 super(UnprocessedKeywordContentError, self).__init__(instance, keywords, location) 573 574 def __str__ (self): 575 return six.u('Unprocessed keywords instantiating %s: %s') % (self.instance._Name(), ' '.join(six.iterkeys(self.keywords))) 576 577class IncrementalElementContentError (ContentValidationError): 578 """Element or element-like content could not be validly associated with an sub-element in the content model. 579 580 This exception occurs when content is added to an element during 581 incremental validation, such as when positional arguments are used 582 in a constructor or material is appended either explicitly or 583 through parsing a DOM instance.""" 584 585 instance = None 586 """The binding for which the L{value} could not be associated with an element.""" 587 588 automaton_configuration = None 589 """The L{pyxb.binding.content.AutomatonConfiguration} representing the current state of the L{instance} content.""" 590 591 value = None 592 """The value that could not be associated with allowable content.""" 593 594 def __init__ (self, instance, automaton_configuration, value, location=None): 595 """@param instance: the value for the L{instance} attribute. 596 @param automaton_configuration: the value for the L{automaton_configuration} attribute. 597 @param value: the value for the L{value} attribute. 598 @param location: the value for the L{location} attribute.""" 599 self.instance = instance 600 self.automaton_configuration = automaton_configuration 601 self.value = value 602 self.location = location 603 super(IncrementalElementContentError, self).__init__(instance, automaton_configuration, value, location) 604 605 def _valueDescription (self): 606 import xml.dom 607 if isinstance(self.value, pyxb.binding.basis._TypeBinding_mixin): 608 return self.value._diagnosticName() 609 if isinstance(self.value, xml.dom.Node): 610 return self.value.nodeName 611 return six.text_type(self.value) 612 613@six.python_2_unicode_compatible 614class UnrecognizedContentError (IncrementalElementContentError): 615 """Element or element-like content could not be validly associated with an sub-element in the content model. 616 617 This exception occurs when content is added to an element during incremental validation.""" 618 619 def __str__ (self): 620 value = self._valueDescription() 621 acceptable = self.automaton_configuration.acceptableContent() 622 if 0 == acceptable: 623 expect = 'no more content' 624 else: 625 import pyxb.binding.content 626 seen = set() 627 names = [] 628 for u in acceptable: 629 if isinstance(u, pyxb.binding.content.ElementUse): 630 n = six.text_type(u.elementBinding().name()) 631 else: 632 assert isinstance(u, pyxb.binding.content.WildcardUse) 633 n = 'xs:any' 634 if not (n in seen): 635 names.append(n) 636 seen.add(n) 637 expect = ' or '.join(names) 638 location = '' 639 if self.location is not None: 640 location = ' at %s' % (self.location,) 641 return six.u('Invalid content %s%s (expect %s)') % (value, location, expect) 642 643 def details (self): 644 import pyxb.binding.basis 645 import pyxb.binding.content 646 i = self.instance 647 rv = [ ] 648 if i._element() is not None: 649 rv.append('The containing element %s is defined at %s.' % (i._element().name(), i._element().xsdLocation())) 650 rv.append('The containing element type %s is defined at %s' % (self.instance._Name(), six.text_type(self.instance._XSDLocation))) 651 if self.location is not None: 652 rv.append('The unrecognized content %s begins at %s' % (self._valueDescription(), self.location)) 653 else: 654 rv.append('The unrecognized content is %s' % (self._valueDescription(),)) 655 rv.append('The %s automaton %s in an accepting state.' % (self.instance._Name(), self.automaton_configuration.isAccepting() and "is" or "is not")) 656 if isinstance(self.instance, pyxb.binding.basis.complexTypeDefinition) and self.instance._IsMixed(): 657 rv.append('Character information content would be permitted.') 658 acceptable = self.automaton_configuration.acceptableContent() 659 if 0 == len(acceptable): 660 rv.append('No elements or wildcards would be accepted at this point.') 661 else: 662 rv.append('The following element and wildcard content would be accepted:') 663 rv2 = [] 664 for u in acceptable: 665 if isinstance(u, pyxb.binding.content.ElementUse): 666 rv2.append('An element %s per %s' % (u.elementBinding().name(), u.xsdLocation())) 667 else: 668 assert isinstance(u, pyxb.binding.content.WildcardUse) 669 rv2.append('A wildcard per %s' % (u.xsdLocation(),)) 670 rv.append('\t' + '\n\t'.join(rv2)) 671 return '\n'.join(rv) 672 673class BatchElementContentError (ContentValidationError): 674 """Element/wildcard content cannot be reconciled with the required content model. 675 676 This exception occurs in post-construction validation using a 677 fresh validating automaton.""" 678 679 instance = None 680 """The binding instance being constructed.""" 681 682 fac_configuration = None 683 """The L{pyxb.utils.fac.Configuration} representing the current state of the L{instance} automaton.""" 684 685 symbols = None 686 """The sequence of symbols that were accepted as content prior to the error.""" 687 688 symbol_set = None 689 """The leftovers from L{pyxb.binding.basis.complexTypeDefinition._symbolSet} that could not be reconciled with the content model.""" 690 691 def __init__ (self, instance, fac_configuration, symbols, symbol_set): 692 """@param instance: the value for the L{instance} attribute. 693 @param fac_configuration: the value for the L{fac_configuration} attribute. 694 @param symbols: the value for the L{symbols} attribute. 695 @param symbol_set: the value for the L{symbol_set} attribute.""" 696 self.instance = instance 697 self.fac_configuration = fac_configuration 698 self.symbols = symbols 699 self.symbol_set = symbol_set 700 super(BatchElementContentError, self).__init__(instance, fac_configuration, symbols, symbol_set) 701 702 def details (self): 703 import pyxb.binding.basis 704 import pyxb.binding.content 705 i = self.instance 706 rv = [ ] 707 if i._element() is not None: 708 rv.append('The containing element %s is defined at %s.' % (i._element().name(), i._element().xsdLocation())) 709 rv.append('The containing element type %s is defined at %s' % (self.instance._Name(), six.text_type(self.instance._XSDLocation))) 710 rv.append('The %s automaton %s in an accepting state.' % (self.instance._Name(), self.fac_configuration.isAccepting() and "is" or "is not")) 711 if self.symbols is None: 712 rv.append('Any accepted content has been stored in instance') 713 elif 0 == len(self.symbols): 714 rv.append('No content has been accepted') 715 else: 716 rv.append('The last accepted content was %s' % (self.symbols[-1].value._diagnosticName(),)) 717 if isinstance(self.instance, pyxb.binding.basis.complexTypeDefinition) and self.instance._IsMixed(): 718 rv.append('Character information content would be permitted.') 719 acceptable = self.fac_configuration.acceptableSymbols() 720 if 0 == len(acceptable): 721 rv.append('No elements or wildcards would be accepted at this point.') 722 else: 723 rv.append('The following element and wildcard content would be accepted:') 724 rv2 = [] 725 for u in acceptable: 726 if isinstance(u, pyxb.binding.content.ElementUse): 727 rv2.append('An element %s per %s' % (u.elementBinding().name(), u.xsdLocation())) 728 else: 729 assert isinstance(u, pyxb.binding.content.WildcardUse) 730 rv2.append('A wildcard per %s' % (u.xsdLocation(),)) 731 rv.append('\t' + '\n\t'.join(rv2)) 732 if (self.symbol_set is None) or (0 == len(self.symbol_set)): 733 rv.append('No content remains unconsumed') 734 else: 735 rv.append('The following content was not processed by the automaton:') 736 rv2 = [] 737 for (ed, syms) in six.iteritems(self.symbol_set): 738 if ed is None: 739 rv2.append('xs:any (%u instances)' % (len(syms),)) 740 else: 741 rv2.append('%s (%u instances)' % (ed.name(), len(syms))) 742 rv.append('\t' + '\n\t'.join(rv2)) 743 return '\n'.join(rv) 744 745class IncompleteElementContentError (BatchElementContentError): 746 """Validation of an instance failed to produce an accepting state. 747 748 This exception occurs in batch-mode validation.""" 749 pass 750 751class UnprocessedElementContentError (BatchElementContentError): 752 """Validation of an instance produced an accepting state but left element material unconsumed. 753 754 This exception occurs in batch-mode validation.""" 755 pass 756 757class InvalidPreferredElementContentError (BatchElementContentError): 758 """Use of a preferred element led to inability to generate a valid document""" 759 760 preferred_symbol = None 761 """The element symbol which was not accepted.""" 762 763 def __init__ (self, instance, fac_configuration, symbols, symbol_set, preferred_symbol): 764 """@param instance: the value for the L{instance} attribute. 765 @param fac_configuration: the value for the L{fac_configuration} attribute. 766 @param symbols: the value for the L{symbols} attribute. 767 @param symbol_set: the value for the L{symbol_set} attribute. 768 @param preferred_symbol: the value for the L{preferred_symbol} attribute. 769 """ 770 self.instance = instance 771 self.fac_configuration = fac_configuration 772 self.symbols = symbols 773 self.symbol_set = symbol_set 774 self.preferred_symbol = preferred_symbol 775 # Bypass immediate parent so we preserve the last argument 776 super(BatchElementContentError, self).__init__(instance, fac_configuration, symbols, symbol_set, preferred_symbol) 777 778@six.python_2_unicode_compatible 779class OrphanElementContentError (ContentValidationError): 780 """An element expected to be used in content is not present in the instance. 781 782 This exception occurs in batch-mode validation when 783 L{pyxb.ValidationConfig.contentInfluencesGeneration} applies, 784 L{pyxb.ValidationConfig.orphanElementInContent} is set to 785 L{pyxb.ValidationConfig.RAISE_EXCEPTION}, and the content list 786 includes an element that is not in the binding instance 787 content. 788 """ 789 790 instance = None 791 """The binding instance.""" 792 793 preferred = None 794 """An element value from the L{instance} L{content<pyxb.binding.basis.complexTypeDefinition.content>} list which was not found in the L{instance}.""" 795 796 def __init__ (self, instance, preferred): 797 """@param instance: the value for the L{instance} attribute. 798 @param preferred: the value for the L{preferred} attribute. 799 """ 800 self.instance = instance 801 self.preferred = preferred 802 super(OrphanElementContentError, self).__init__(instance, preferred) 803 804 def __str__ (self): 805 return six.u('Preferred content element not found in instance') 806 807@six.python_2_unicode_compatible 808class SimpleTypeValueError (ValidationError): 809 """Raised when a simple type value does not satisfy its constraints.""" 810 type = None 811 """The L{pyxb.binding.basis.simpleTypeDefinition} that constrains values.""" 812 813 value = None 814 """The value that violates the constraints of L{type}. In some 815 cases this is a tuple of arguments passed to a constructor that 816 failed with a built-in exception likeC{ValueError} or 817 C{OverflowError}.""" 818 819 def __init__ (self, type, value, location=None): 820 """@param type: the value for the L{type} attribute. 821 @param value: the value for the L{value} attribute. 822 @param location: the value for the L{location} attribute. Default taken from C{value} if possible.""" 823 import pyxb.utils.utility 824 self.type = type 825 self.value = value 826 if (location is None) and isinstance(value, pyxb.utils.utility.Locatable_mixin): 827 location = value._location() 828 self.location = location 829 super(SimpleTypeValueError, self).__init__(type, value, location) 830 831 def __str__ (self): 832 import pyxb.binding.basis 833 if isinstance(self.value, pyxb.binding.basis._TypeBinding_mixin): 834 return six.u('Type %s cannot be created from %s: %s') % (self.type._Name(), self.value._Name(), self.value) 835 return six.u('Type %s cannot be created from: %s') % (self.type._Name(), self.value) 836 837@six.python_2_unicode_compatible 838class SimpleListValueError (SimpleTypeValueError): 839 """Raised when a list simple type contains a member that does not satisfy its constraints. 840 841 In this case, L{type} is the type of the list, and value 842 C{type._ItemType} is the type for which the L{value} is 843 unacceptable.""" 844 845 def __str__ (self): 846 return six.u('Member type %s of list type %s cannot accept %s') % (self.type._ItemType._Name(), self.type._Name(), self.value) 847 848@six.python_2_unicode_compatible 849class SimpleUnionValueError (SimpleTypeValueError): 850 """Raised when a union simple type contains a member that does not satisfy its constraints. 851 852 In this case, L{type} is the type of the union, and the value 853 C{type._MemberTypes} is the set of types for which the value is 854 unacceptable. 855 856 The L{value} itself is the tuple of arguments passed to the 857 constructor for the union.""" 858 859 def __str__ (self): 860 return six.u('No memberType of %s can be constructed from %s') % (self.type._Name(), self.value) 861 862@six.python_2_unicode_compatible 863class SimpleFacetValueError (SimpleTypeValueError): 864 """Raised when a simple type value does not satisfy a facet constraint. 865 866 This extends L{SimpleTypeValueError} with the L{facet} field which 867 can be used to determine why the value is unacceptable.""" 868 869 type = None 870 """The L{pyxb.binding.basis.simpleTypeDefinition} that constrains values.""" 871 872 value = None 873 """The value that violates the constraints of L{type}. In some 874 cases this is a tuple of arguments passed to a constructor that 875 failed with a built-in exception likeC{ValueError} or 876 C{OverflowError}.""" 877 878 facet = None 879 """The specific facet that is violated by the value.""" 880 881 def __init__ (self, type, value, facet, location=None): 882 """@param type: the value for the L{type} attribute. 883 @param value: the value for the L{value} attribute. 884 @param facet: the value for the L{facet} attribute. 885 @param location: the value for the L{location} attribute. Default taken from C{value} if possible.""" 886 import pyxb.utils.utility 887 888 self.type = type 889 self.value = value 890 self.facet = facet 891 if (location is None) and isinstance(value, pyxb.utils.utility.Locatable_mixin): 892 location = value._location() 893 self.location = location 894 # Bypass immediate parent 895 super(SimpleTypeValueError, self).__init__(type, value, facet) 896 897 def __str__ (self): 898 return six.u('Type %s %s constraint violated by value %s') % (self.type._Name(), self.facet._Name, self.value) 899 900class SimplePluralValueError (SimpleTypeValueError): 901 """Raised when context requires a plural value. 902 903 Unlike L{SimpleListValueError}, in this case the plurality is 904 external to C{type}, for example when an element has simple 905 content and allows multiple occurrences.""" 906 pass 907 908class AttributeValidationError (ValidationError): 909 """Raised when an attribute requirement is not satisfied.""" 910 911 type = None 912 """The L{pyxb.binding.basis.complexTypeDefinition} subclass of the instance.""" 913 914 tag = None 915 """The name of the attribute.""" 916 917 instance = None 918 """The binding instance, if available.""" 919 920 def __init__ (self, type, tag, instance=None, location=None): 921 """@param type: the value for the L{type} attribute. 922 @param tag: the value for the L{tag} attribute. 923 @param instance: the value for the L{instance} attribute. 924 @param location: the value for the L{location} attribute. Default taken from C{instance} if possible. 925 """ 926 import pyxb.utils.utility as utility 927 self.type = type 928 self.tag = tag 929 self.instance = instance 930 if (location is None) and isinstance(instance, utility.Locatable_mixin): 931 location = instance._location() 932 self.location = location 933 super(AttributeValidationError, self).__init__(type, tag, instance, location) 934 935@six.python_2_unicode_compatible 936class UnrecognizedAttributeError (AttributeValidationError): 937 """Attempt to reference an attribute not sanctioned by content model.""" 938 def __str__ (self): 939 return six.u('Attempt to reference unrecognized attribute %s in type %s') % (self.tag, self.type) 940 941@six.python_2_unicode_compatible 942class ProhibitedAttributeError (AttributeValidationError): 943 """Raised when an attribute that is prohibited is set or referenced in an element.""" 944 def __str__ (self): 945 return six.u('Attempt to reference prohibited attribute %s in type %s') % (self.tag, self.type) 946 947@six.python_2_unicode_compatible 948class MissingAttributeError (AttributeValidationError): 949 """Raised when an attribute that is required is missing in an element.""" 950 def __str__ (self): 951 return six.u('Instance of %s lacks required attribute %s') % (self.type, self.tag) 952 953@six.python_2_unicode_compatible 954class AttributeChangeError (AttributeValidationError): 955 """Attempt to change an attribute that has a fixed value constraint.""" 956 def __str__ (self): 957 return six.u('Cannot change fixed attribute %s in type %s') % (self.tag, self.type) 958 959class BindingError (PyXBException): 960 """Raised when the bindings are mis-used. 961 962 These are not validation errors, but rather structural errors. 963 For example, attempts to extract complex content from a type that 964 requires simple content, or vice versa. """ 965 966@six.python_2_unicode_compatible 967class NotSimpleContentError (BindingError): 968 """An operation that requires simple content was invoked on a 969 complex type instance that does not have simple content.""" 970 971 instance = None 972 """The binding instance which should have had simple content.""" 973 974 def __init__ (self, instance): 975 """@param instance: the binding instance that was mis-used. 976 This will be available in the L{instance} attribute.""" 977 self.instance = instance 978 super(BindingError, self).__init__(instance) 979 pass 980 981 def __str__ (self): 982 return six.u('type %s does not have simple content') % (self.instance._Name(),) 983 984@six.python_2_unicode_compatible 985class NotComplexContentError (BindingError): 986 """An operation that requires a content model was invoked on a 987 complex type instance that has empty or simple content.""" 988 989 instance = None 990 """The binding instance which should have had a content model.""" 991 992 def __init__ (self, instance): 993 """@param instance: the binding instance that was mis-used. 994 This will be available in the L{instance} attribute.""" 995 self.instance = instance 996 super(BindingError, self).__init__(instance) 997 998 def __str__ (self): 999 return six.u('type %s has simple/empty content') % (self.instance._Name(),) 1000 1001@six.python_2_unicode_compatible 1002class ReservedNameError (BindingError): 1003 """Reserved name set in binding instance.""" 1004 1005 instance = None 1006 """The binding instance.""" 1007 1008 name = None 1009 """The name that was caught being assigned""" 1010 1011 def __init__ (self, instance, name): 1012 """@param instance: the value for the L{instance} attribute. 1013 p@param name: the value for the L{name} attribute.""" 1014 self.instance = instance 1015 self.name = name 1016 super(ReservedNameError, self).__init__(instance, name) 1017 1018 def __str__ (self): 1019 return six.u('%s is a reserved name within %s') % (self.name, self.instance._Name()) 1020 1021class PyXBError (Exception): 1022 """Base class for exceptions that indicate a problem that the user probably can't fix.""" 1023 pass 1024 1025class UsageError (PyXBError): 1026 """Raised when the code detects user violation of an API.""" 1027 1028class LogicError (PyXBError): 1029 """Raised when the code detects an implementation problem.""" 1030 1031class IncompleteImplementationError (LogicError): 1032 """Raised when required capability has not been implemented. 1033 1034 This is only used where it is reasonable to expect the capability 1035 to be present, such as a feature of XML schema that is not 1036 supported (e.g., the redefine directive).""" 1037