Package pyxb :: Module exceptions_ |
[hide private]
[frames] | no frames]

# Source Code for Module pyxb.exceptions_

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