Package pyxb |
[hide private]
[frames] | no frames]

# Source Code for Package pyxb

      1  # -*- coding: utf-8 -*-
      2
      3  """PyXB stands for Python U{W3C XML
      4  Schema<http://www.w3.org/XML/Schema>} Bindings, and is pronounced
      5  "pixbee".  It enables translation between XML instance documents and
      6  Python objects following rules specified by an XML Schema document.
      7
      8  This is the top-level entrypoint to the PyXB system.  Importing this
      9  gets you all the L{exceptions<pyxb.exceptions_.PyXBException>}, and
     10  L{pyxb.namespace}.  For more functionality, delve into these
     11  submodules:
     12
     13   - L{pyxb.xmlschema} Module holding the
     14     L{structures<pyxb.xmlschema.structures>} that convert XMLSchema
     15     from a DOM model to a Python class model based on the XMLSchema
     16     components.  Use this when you need to operate on the component
     17     model.
     18
     19   - L{pyxb.binding} Module used to generate the bindings and at runtime
     20     to support the generated bindings.  Use this if you need to use the
     21     binding model or content model.
     22
     23   - L{pyxb.utils} Common utilities used in parsing, generating, and
     24     executing.  The submodules must be imported separately.
     25
     26  """
     27
     28  import logging
     29
     30  _log = logging.getLogger(__name__)
     31
     32 -class cscRoot (object):
     33      """This little bundle of joy exists because in Python 2.6 it
     34      became an error to invoke C{object.__init__} with parameters (unless
     35      you also override C{__new__}, in which case it's only a warning.
     36      Whatever.).  Since I'm bloody not going to check in every class
     37      whether C{super(Myclass,self)} refers to C{object} (even if I could
     38      figure out how to do that, 'cuz the obvious solutions don't work),
     39      we'll just make this thing the root of all U{cooperative super
     40      calling<http://www.geocities.com/foetsch/python/new_style_classes.htm#super>}
     41      hierarchies.  The standard syntax in PyXB for this pattern is::
     42
     43        def method_csc (self, *args, **kw):
     44          self_fn = lambda *_args, **_kw: self
     45          super_fn = getattr(super(ThisClass, self), 'method_csc', self_fn)
     46          return super_fn(*args, **kw)
     47
     48      """
     49
     50 -    def __init__ (self, *args, **kw):
     51          # Oh gross.  If this class descends from list (and probably dict), we
     52          # get here when object is *not* our direct superclass.  In that case,
     53          # we have to pass the arguments on up, or the strings don't get
     54          # created right.  Below is the only way I've figured out to detect the
     55          # situation.
     56          #
     57          # Note that we might also get here if you mix-in a class that used
     58          # object as a parent instead of cscRoot.  Don't do that.  Printing the
     59          # mro() is a decent way of identifying the problem.
     60          if issubclass(self.__class__.mro()[-2], ( list, dict )):
     61              super(cscRoot, self).__init__(*args)
     62
     63  __version__ = '1.2.3'
     64  """The version of PyXB"""
     65
     66  __url__ = 'http://pyxb.sourceforge.net'
     67  """The URL for PyXB's homepage"""
     68
     69  __license__ = 'Apache License 2.0'
     70
     71  # Bring in the exception hierarchy
     72  from .exceptions_ import *
     73
     74  # Bring in namespace stuff
     75  from . import namespace
     76
     77 -class BIND (object):
     78      """Bundle data for automated binding generation.
     79
     80      Instances of this class capture positional and keyword arguments that are
     81      used to create binding instances based on context.  For example, if C{w}
     82      is an instance of a complex type whose C{option} element is declared to be
     83      an anonymous class with simple content of type integer and an attribute of
     84      C{units}, a correct assignment to that element could be achieved with::
     85
     86        w.option = BIND(54, units="m")
     87
     88      """
     89      __args = None
     90      __kw = None
     91
     92 -    def __init__ (self, *args, **kw):
     93          """Cache parameters for subsequent binding creation.
     94          Invoke just as you would the factory for a binding class."""
     95          self.__args = args
     96          self.__kw = kw
     97
     98 -    def createInstance (self, factory, **kw):
     99          """Invoke the given factory method.
    100
    101          Position arguments to the factory are those cached in this instance.
    102          Keyword arguments are the ones on the command line, updated from the
    103          ones in this instance."""
    104          kw.update(self.__kw)
    105          return factory(*self.__args, **kw)
    106
    107
    108  XMLStyle_minidom = 0
    109  """Use xml.dom.minidom for XML processing.  This is the fastest, but does not
    110  provide location information.  It produces DOM instances."""
    111
    112  XMLStyle_saxdom = 1
    113  """Use pyxb.utils.saxdom for XML processing.  This is the slowest, but both
    114  provides location information and generates a DOM instance."""
    115
    116  XMLStyle_saxer = 2
    117  """Use pyxb.binding.saxer when converting documents to binding instances.
    118  This style supports location information in the bindings.  It produces binding
    119  instances directly, without going through a DOM stage, so is faster than
    120  XMLStyle_saxdom.  However, since the pyxb.xmlschema.structures classes require
    121  a DOM model, XMLStyle_saxdom will be used for pyxb.utils.domutils.StringToDOM
    122  if this style is selected."""
    123
    124  _XMLStyle = XMLStyle_saxer
    125  """The current XML processing style."""
    126
    127  _XMLStyleMap = { 'minidom' : XMLStyle_minidom,
    128                   'saxdom' : XMLStyle_saxdom,
    129                   'saxer' : XMLStyle_saxer }
    130  _XMLStyleMapReverse = dict([ (_v, _k) for (_k, _v) in _XMLStyleMap.iteritems() ])
    131
    132  _XMLStyle_envvar = 'PYXB_XML_STYLE'
    133
    134 -def _SetXMLStyle (style=None):
    135      """Set the interface used to parse XML content.
    136
    137      This can be invoked within code.  The system default of L{XMLStyle_saxer}
    138      can also be overridden at runtime by setting the environment variable
    139      C{PYXB_XML_STYLE} to one of C{minidom}, C{saxdom}, or C{saxer}.
    140
    141      @param style: One of L{XMLStyle_minidom}, L{XMLStyle_saxdom},
    142      L{XMLStyle_saxer}.  If not provided, the system default is used.
    143      """
    144      global _XMLStyle
    145      if style is None:
    146          import os
    147          style_name = os.environ.get(_XMLStyle_envvar)
    148          if style_name is None:
    149              style_name = 'saxer'
    150          style = _XMLStyleMap.get(style_name)
    151          if style is None:
    152              raise PyXBException('Bad value "%s" for %s' % (style_name, _XMLStyle_envvar))
    153      if _XMLStyleMapReverse.get(style) is None:
    154          raise PyXBException('Bad value %s for _SetXMLStyle' % (style,))
    155      _XMLStyle = style
    156
    157  _SetXMLStyle()
    158
    159  # Global flag that we can use to determine whether optimization is active in
    160  # this session.  There may be cases where we can bypass methods that just
    161  # check for things we don't care about in an optimized context
    162  _OptimizationActive = False
    163  try:
    164      assert False
    165      _OptimizationActive = True
    166  except:
    167      pass
    168
    169  _CorruptionDetectionEnabled = not _OptimizationActive
    170  """If C{True}, blocks attempts to assign to attributes that are reserved for
    171  PyXB methods.
    172
    173  Applies only at compilation time; dynamic changes are ignored.
    174  """
    175
    176 -class ValidationConfig (object):
    177      """Class holding configuration related to validation.
    178
    179      L{pyxb.GlobalValidationConfig} is available to influence validation in all
    180      contexts.  Each binding class has a reference to an instance of this
    181      class, which can be inspected using
    182      L{pyxb.binding.basis._TypeBinding_mixin._GetValidationConfig} and changed
    183      using L{pyxb.binding.basis._TypeBinding_mixin._SetValidationConfig}.  Each
    184      binding instance has a reference inherited from its class which can be
    185      inspected using L{pyxb.binding.basis._TypeBinding_mixin._validationConfig}
    186      and changed using
    187      L{pyxb.binding.basis._TypeBinding_mixin._setValidationConfig}.
    188
    189      This allows fine control on a per class and per-instance basis.
    190
    191      L{forBinding} replaces L{RequireValidWhenParsing}.
    192
    193      L{forDocument} replaces L{RequireValidWhenGenerating}.
    194
    195      L{contentInfluencesGeneration}, L{orphanElementInContent}, and
    196      L{invalidElementInContent} control how
    197      L{pyxb.binding.basis.complexTypeDefinition.orderedContent} affects
    198      generated documents.
    199      """
    200
    201      __forBinding = True
    202 -    def _getForBinding (self):
    203          """C{True} iff validation should be performed when manipulating a
    204          binding instance.
    205
    206          This includes parsing a document or DOM tree, using a binding instance
    207          class constructor, or assigning to an element or attribute field of a
    208          binding instance."""
    209          return self.__forBinding
    210 -    def _setForBinding (self, value):
    211          """Configure whether validation should be performed when manipulating
    212          a binding instance."""
    213          if not isinstance(value, bool):
    214              raise TypeError(value)
    215          self.__forBinding = value
    216          return value
    217      forBinding = property(_getForBinding)
    218
    219      __forDocument = True
    220 -    def _getForDocument (self):
    221          """C{True} iff validation should be performed when creating a document
    222          from a binding instance.
    223
    224          This applies at invocation of
    225          L{toDOM()<pyxb.binding.basis._TypeBinding_mixin.toDOM>}.
    226          L{toxml()<pyxb.binding.basis._TypeBinding_mixin.toDOM>} invokes C{toDOM()}."""
    227          return self.__forDocument
    228 -    def _setForDocument (self, value):
    229          """Configure whether validation should be performed when generating
    230          a document from a binding instance."""
    231          if not isinstance(value, bool):
    232              raise TypeError(value)
    233          self.__forDocument = value
    234          return value
    235      forDocument = property(_getForDocument)
    236
    237      ALWAYS = -1
    238      """Always do it."""
    239
    240      NEVER = 0
    241      """Never do it."""
    242
    243      IGNORE_ONCE = 1
    244      """If an error occurs ignore it and continue with the next one.  (E.g., if
    245      an element in a content list fails skip it and continue with the next
    246      element in the list.)"""
    247
    248      GIVE_UP = 2
    249      """If an error occurs ignore it and stop using whatever provided the cause
    250      of the error.  (E.g., if an element in a content list fails stop
    251      processing the content list and execute as though it was absent)."""
    252
    253      RAISE_EXCEPTION = 3
    254      """If an error occurs, raise an exception."""
    255
    256      MIXED_ONLY = 4
    257      """Only when content type is mixed."""
    258
    259      __contentInfluencesGeneration = MIXED_ONLY
    260 -    def __getContentInfluencesGeneration (self):
    261          """Determine whether complex type content influences element order in
    262          document generation.
    263
    264          The value is one of L{ALWAYS}, L{NEVER}, L{MIXED_ONLY} (default)."""
    265          return self.__contentInfluencesGeneration
    266 -    def _setContentInfluencesGeneration (self, value):
    267          """Set the value of L{contentInfluencesGeneration}."""
    268          if not (value in ( self.ALWAYS, self.NEVER, self.MIXED_ONLY )):
    269              raise ValueError(value)
    270          self.__contentInfluencesGeneration = value
    271      contentInfluencesGeneration = property(__getContentInfluencesGeneration)
    272
    273      __orphanElementInContent = IGNORE_ONCE
    274 -    def __getOrphanElementInContent (self):
    275          """How to handle unrecognized elements in content lists.
    276
    277          This is used when consulting a complex type instance content list to
    278          influence the generation of documents from a binding instance.
    279
    280          The value is one of L{IGNORE_ONCE} (default), L{GIVE_UP},
    281          L{RAISE_EXCEPTION}."""
    282          return self.__orphanElementInContent
    283 -    def _setOrphanElementInContent (self, value):
    284          """Set the value of L{orphanElementInContent}."""
    285          if not (value in ( self.IGNORE_ONCE, self.GIVE_UP, self.RAISE_EXCEPTION )):
    286              raise ValueError(value)
    287          self.__orphanElementInContent = value
    288      orphanElementInContent = property(__getOrphanElementInContent)
    289
    290      __invalidElementInContent = IGNORE_ONCE
    291 -    def __getInvalidElementInContent (self):
    292          """How to handle invalid elements in content lists.
    293
    294          The value is one of L{IGNORE_ONCE} (default), L{GIVE_UP},
    295          L{RAISE_EXCEPTION}."""
    296          return self.__invalidElementInContent
    297 -    def _setInvalidElementInContent (self, value):
    298          """Set the value of L{invalidElementInContent}."""
    299          if not (value in ( self.IGNORE_ONCE, self.GIVE_UP, self.RAISE_EXCEPTION )):
    300              raise ValueError(value)
    301          self.__invalidElementInContent = value
    302      invalidElementInContent = property(__getInvalidElementInContent)
    303
    304 -    def copy (self):
    305          """Make a copy of this instance.
    306
    307          Use this to get a starting point when you need to customize validation
    308          on a per-instance/per-class basis."""
    309          import copy
    310          return copy.copy(self)
    311
    312  GlobalValidationConfig = ValidationConfig()
    313
    314  _GenerationRequiresValid = True
    315  """Legacy flag; prefer L{forDocument<ValidationConfig.forDocument>} in L{GlobalValidationConfig}."""
    316
    317 -def RequireValidWhenGenerating (value=None):
    318      """Query or set a flag that controls validation checking in XML generation.
    319
    320      Normally any attempts to convert a binding instance to a DOM or XML
    321      representation requires that the binding validate against the content
    322      model, since only in this way can the content be generated in the correct
    323      order.  In some cases it may be necessary or useful to generate a document
    324      from a binding that is incomplete.  If validation is not required, the
    325      generated documents may not validate even if the content validates,
    326      because ordering constraints will be ignored.
    327
    328      @keyword value: If absent or C{None}, no change is made; otherwise, this
    329      enables (C{True}) or disables (C{False}) the requirement that instances
    330      validate before being converted to XML.
    331      @type value: C{bool}
    332
    333      @return: C{True} iff attempts to generate XML for a binding that does not
    334      validate should raise an exception.  """
    335      if value is None:
    336          return GlobalValidationConfig.forDocument
    337      global _GenerationRequiresValid
    338      _GenerationRequiresValid = GlobalValidationConfig._setForDocument(value)
    339      return value
    340
    341  _ParsingRequiresValid = True
    342  """Legacy flag; prefer L{forBinding<ValidationConfig.forBinding>} in L{GlobalValidationConfig}."""
    343 -def RequireValidWhenParsing (value=None):
    344      """Query or set a flag that controls validation checking in XML parsing.
    345
    346      Normally any attempts to convert XML to a binding instance to a binding
    347      instance requires that the document validate against the content model.
    348      In some cases it may be necessary or useful to process a document that is
    349      incomplete.  If validation is not required, the generated documents may
    350      not validate even if the content validates, because ordering constraints
    351      will be ignored.
    352
    353      @keyword value: If absent or C{None}, no change is made; otherwise, this
    354      enables (C{True}) or disables (C{False}) the requirement that documents
    355      validate when being converted to bindings.
    356      @type value: C{bool}
    357
    358      @return: C{True} iff attempts to generate bindings for a document that
    359      does not validate should raise an exception."""
    360      if value is None:
    361          return GlobalValidationConfig.forBinding
    362      global _ParsingRequiresValid
    363      _ParsingRequiresValid = GlobalValidationConfig._setForBinding(value)
    364      return _ParsingRequiresValid
    365
    366  _PreserveInputTimeZone = False
    367 -def PreserveInputTimeZone (value=None):
    368      """Control whether time values are converted to UTC during input.
    369
    370      The U{specification <http://www.w3.org/TR/xmlschema-2/#dateTime>} makes
    371      clear that timezoned times are in UTC and that times in other timezones
    372      are to be translated to UTC when converted from literal to value form.
    373      Provide an option to bypass this step, so the input timezone is preserved.
    374
    375      @note: Naive processing of unnormalized times--i.e., ignoring the
    376      C{tzinfo} field--may result in errors."""
    377      global _PreserveInputTimeZone
    378      if value is None:
    379          return _PreserveInputTimeZone
    380      if not isinstance(value, bool):
    381          raise TypeError(value)
    382      _PreserveInputTimeZone = value
    383      return _PreserveInputTimeZone
    384
    385  _OutputEncoding = 'utf-8'
    386  """Default unicode encoding to use when creating output.
    387
    388  Material being written to an XML parser is not output."""
    389
    390  _InputEncoding = 'utf-8'
    391  """Default unicode encoding to assume when decoding input.
    392
    393  Material being written to an XML parser is treated as input."""
    394
    395 -def NonElementContent (instance):
    396      """Return an iterator producing the non-element content of the provided instance.
    397
    398      The catenated text of the non-element content of an instance can
    399      be obtained with::
    400
    401         text = u''.join(pyxb.NonElementContent(instance))
    402
    403      @param instance: An instance of L{pyxb.binding.basis.complexTypeDefinition}.
    404
    405      @return: an iterator producing text values
    406      """
    407      import pyxb.binding.basis
    408      return pyxb.binding.basis.NonElementContent.ContentIterator(instance.orderedContent())
    409
    410  ## Local Variables:
    411  ## fill-column:78
    412  ## End:
    413