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

# Source Code for Package pyxb.namespace

       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  """Classes and global objects related to U{XML Namespaces<http://www.w3.org/TR/2006/REC-xml-names-20060816/index.html>}.
      17
      18  Since namespaces hold all referenceable objects, this module also defines the
      19  infrastructure for resolving named object references, such as schema
      20  components.
      21  """
      22
      23  import pyxb
      24  import pyxb.utils.utility
      25  import xml.dom
      26  import logging
      27
      28  _log = logging.getLogger(__name__)
      29
      30  @pyxb.utils.utility.BackfillComparisons
      31 -class ExpandedName (object):
      32
      33      """Represent an U{expanded name
      34      <http://www.w3.org/TR/REC-xml-names/#dt-expname>}, which pairs a
      35      namespace with a local name.
      36
      37      Because a large number of local elements, and most attributes, have no
      38      namespace associated with them, this is optimized for representing names
      39      with an absent namespace.  The hash and equality test methods are set so
      40      that a plain string is equivalent to a tuple of C{None} and that string.
      41
      42      Note that absent namespaces can be represented in two ways: with a
      43      namespace of C{None} (the name "has no namespace"), and with a namespace
      44      that is an L{absent namespace <Namespace.CreateAbsentNamespace>} (the name
      45      "has an absent namespace").  Hash code calculations are done so that the
      46      two alternatives produce the same hash; however, comparison is done so
      47      that the two are distinguished.  The latter is the intended behavior; the
      48      former should not be counted upon.
      49
      50      This class allows direct lookup of the named object within a category by
      51      using the category name as an accessor function.  That is, if the
      52      namespace of the expanded name C{en} has a category 'typeDefinition', then
      53      the following two expressions are equivalent::
      54
      55        en.typeDefinition()
      56        en.namespace().categoryMap('typeDefinition').get(en.localName())
      57
      58      This class descends from C{tuple} so that its values can be used as
      59      dictionary keys without concern for pointer equivalence.
      60      """
      61 -    def namespace (self):
      62          """The L{Namespace} part of the expanded name."""
      63          return self.__namespace
      64      __namespace = None
      65
      66 -    def namespaceURI (self):
      67          """Return the URI of the namespace, or C{None} if the namespace is absent."""
      68          return self.__namespaceURI
      69      __namespaceURI = None
      70
      71 -    def localName (self):
      72          """The local part of the expanded name."""
      73          return self.__localName
      74      __localName = None
      75
      76      # Cached tuple representation
      77      __expandedName = None
      78
      79 -    def validateComponentModel (self):
      80          """Pass model validation through to namespace part."""
      81          return self.namespace().validateComponentModel()
      82
      83 -    def uriTuple (self):
      84          """Return a tuple consisting of the namespace URI and the local name.
      85
      86          This presents the expanded name as base Python types for persistent
      87          storage.  Be aware, though, that it will lose the association of the
      88          name with an absent namespace, if that matters to you."""
      89          return ( self.__namespaceURI, self.__localName )
      90
      91      # Treat unrecognized attributes as potential accessor functions
      92 -    def __getattr__ (self, name):
      93          # Don't try to recognize private names (like __setstate__)
      94          if name.startswith('__'):
      95              return super(ExpandedName, self).__getattr__(name)
      96          if self.namespace() is None:
      97              return lambda: None
      98          # NOTE: This will raise pyxb.NamespaceError if the category does not exist.
      99          category_value = self.namespace().categoryMap(name).get(self.localName())
     100          return lambda : category_value
     101
     102 -    def createName (self, local_name):
     103          """Return a new expanded name in the namespace of this name.
     104
     105          @param local_name: The local name portion of an expanded name.
     106          @return: An instance of L{ExpandedName}.
     107          """
     108          return ExpandedName(self.namespace(), local_name)
     109
     110 -    def adoptName (self, name):
     111          """Return the input name, except if the input name has no namespace,
     112          return a name that uses the namespace from this name with the local
     113          name from the input name.
     114
     115          Use this when the XML document has an unqualified name and we're
     116          processing using an absent default namespace.
     117
     118          @warning: Be careful when using a global name to adopt a name from a
     119          local element: if the local element (with no namespace) has the same
     120          localName as but is different from the global element (with a
     121          namespace), this will improperly provide a namespace when one should
     122          not be present.  See the comments in
     123          L{pyxb.binding.basis.element.elementForName}.
     124          """
     125
     126          if not isinstance(name, ExpandedName):
     127              name = ExpandedName(name)
     128          if name.namespace() is None:
     129              name = self.createName(name.localName())
     130          return name
     131
     132 -    def __init__ (self, *args, **kw):
     133          """Create an expanded name.
     134
     135          Expected argument patterns are:
     136
     137           - ( C{str} ) : the local name in an absent namespace
     138           - ( L{ExpandedName} ) : a copy of the given expanded name
     139           - ( C{xml.dom.Node} ) : The name extracted from node.namespaceURI and node.localName
     140           - ( C{str}, C{str} ) : the namespace URI and the local name
     141           - ( L{Namespace}, C{str} ) : the namespace and the local name
     142           - ( L{ExpandedName}, C{str}) : the namespace from the expanded name, and the local name
     143
     144          Wherever C{str} occurs C{unicode} is also permitted.
     145
     146          @keyword fallback_namespace: Optional Namespace instance to use if the
     147          namespace would otherwise be None.  This is only used if it is an
     148          absent namespace.
     149
     150          """
     151          fallback_namespace = kw.get('fallback_namespace')
     152          if 0 == len(args):
     153              raise pyxb.LogicError('Too few arguments to ExpandedName constructor')
     154          if 2 < len(args):
     155              raise pyxb.LogicError('Too many arguments to ExpandedName constructor')
     156          if 2 == len(args):
     157              # Namespace(str, unicode, Namespace) and local name (str, unicode)
     158              ( ns, ln ) = args
     159          else:
     160              # Local name (str, unicode) or ExpandedName or Node
     161              assert 1 == len(args)
     162              ln = args[0]
     163              ns = None
     164              if isinstance(ln, basestring):
     165                  pass
     166              elif isinstance(ln, tuple) and (2 == len(ln)):
     167                  (ns, ln) = ln
     168              elif isinstance(ln, ExpandedName):
     169                  ns = ln.namespace()
     170                  ln = ln.localName()
     171              elif isinstance(ln, xml.dom.Node):
     172                  if not(ln.nodeType in (xml.dom.Node.ELEMENT_NODE, xml.dom.Node.ATTRIBUTE_NODE)):
     173                      raise pyxb.LogicError('Cannot create expanded name from non-element DOM node %s' % (ln.nodeType,))
     174                  ns = ln.namespaceURI
     175                  ln = ln.localName
     176              else:
     177                  raise pyxb.LogicError('Unrecognized argument type %s' % (type(ln),))
     178          if (ns is None) and (fallback_namespace is not None):
     179              if fallback_namespace.isAbsentNamespace():
     180                  ns = fallback_namespace
     181          if isinstance(ns, (str, unicode)):
     182              ns = NamespaceForURI(ns, create_if_missing=True)
     183          if isinstance(ns, ExpandedName):
     184              ns = ns.namespace()
     185          if (ns is not None) and not isinstance(ns, Namespace):
     186              raise pyxb.LogicError('ExpandedName must include a valid (perhaps absent) namespace, or None.')
     187          self.__namespace = ns
     188          if self.__namespace is not None:
     189              self.__namespaceURI = self.__namespace.uri()
     190          self.__localName = ln
     191          assert self.__localName is not None
     192          self.__expandedName = ( self.__namespace, self.__localName )
     193          self.__uriTuple = ( self.__namespaceURI, self.__localName )
     194
     195
     196 -    def __str__ (self):
     197          assert self.__localName is not None
     198          if self.__namespaceURI is not None:
     199              return '{%s}%s' % (self.__namespaceURI, self.__localName)
     200          return self.localName()
     201
     202 -    def __hash__ (self):
     203          if self.__namespaceURI is None:
     204              # Handle both str and unicode hashes
     205              return type(self.__localName).__hash__(self.__localName)
     206          return tuple.__hash__(self.__expandedName)
     207
     208 -    def __otherForCompare (self, other):
     209          if isinstance(other, (str, unicode)):
     210              other = ( None, other )
     211          if not isinstance(other, tuple):
     212              other = other.__uriTuple
     213          if isinstance(other[0], Namespace):
     214              other = ( other[0].uri(), other[1] )
     215          return other
     216
     217 -    def __eq__ (self, other):
     218          if other is None:
     219              return False
     220          return 0 == pyxb.utils.utility.IteratedCompareMixed(self.__uriTuple, self.__otherForCompare(other))
     221
     222 -    def __lt__ (self, other):
     223          if other is None:
     224              return False
     225          return 0 > pyxb.utils.utility.IteratedCompareMixed(self.__uriTuple, self.__otherForCompare(other))
     226
     227 -    def getAttribute (self, dom_node):
     228          """Return the value of the attribute identified by this name in the given node.
     229
     230          @return: An instance of C{xml.dom.Attr}, or C{None} if the node does
     231          not have an attribute with this name.
     232          """
     233          if dom_node.hasAttributeNS(self.__namespaceURI, self.__localName):
     234              return dom_node.getAttributeNS(self.__namespaceURI, self.__localName)
     235          return None
     236
     237 -    def nodeMatches (self, dom_node):
     238          """Return C{True} iff the dom node expanded name matches this expanded name."""
     239          return (dom_node.localName == self.__localName) and (dom_node.namespaceURI == self.__namespaceURI)
     240
     241 -class NamedObjectMap (dict):
     242      """An extended dictionary intended to assist with QName resolution.
     243
     244      These dictionaries have an attribute that identifies a category of named
     245      objects within a Namespace; the specifications for various documents
     246      require that certain groups of objects must be unique, while uniqueness is
     247      not required between groups.  The dictionary also retains a pointer to the
     248      Namespace instance for which it holds objects."""
     249 -    def namespace (self):
     250          """The namespace to which the object map belongs."""
     251          return self.__namespace
     252      __namespace = None
     253
     254 -    def category (self):
     255          """The category of objects (e.g., typeDefinition, elementDeclaration)."""
     256          return self.__category
     257      __category = None
     258
     259 -    def __init__ (self, category, namespace, *args, **kw):
     260          self.__category = category
     261          self.__namespace = namespace
     262          super(NamedObjectMap, self).__init__(*args, **kw)
     263
     264 -class _NamespaceCategory_mixin (pyxb.cscRoot):
     265      """Mix-in that aggregates those aspects of XMLNamespaces that hold
     266      references to categories of named objects.
     267
     268      Arbitrary groups of named objects, each requiring unique names within
     269      themselves, can be saved.  Unless configured otherwise, the Namespace
     270      instance is extended with accessors that provide direct access to
     271      individual category maps.  The name of the method is the category name
     272      with a suffix of "s"; e.g., if a category "typeDefinition" exists, it can
     273      be accessed from the namespace using the syntax C{ns.typeDefinitions()}.
     274
     275      Note that the returned value from the accessor is a live reference to
     276      the category map; changes made to the map are reflected in the
     277      namespace.
     278      """
     279
     280      # Map from category strings to NamedObjectMap instances that
     281      # contain the dictionary for that category.
     282      __categoryMap = None
     283
     284 -    def _reset (self):
     285          """CSC extension to reset fields of a Namespace.
     286
     287          This one handles category-related data."""
     288          getattr(super(_NamespaceCategory_mixin, self), '_reset', lambda *args, **kw: None)()
     289          self.__categoryMap = { }
     290
     291 -    def categories (self):
     292          """The list of individual categories held in this namespace."""
     293          return list(self.__categoryMap.keys())
     294
     295 -    def _categoryMap (self):
     296          """Return the whole map from categories to named objects."""
     297          return self.__categoryMap
     298
     299 -    def categoryMap (self, category):
     300          """Map from local names to NamedObjectMap instances for the given category."""
     301          try:
     302              return self.__categoryMap[category]
     303          except KeyError:
     304              raise pyxb.NamespaceError(self, '%s has no category %s' % (self, category))
     305
     306 -    def __defineCategoryAccessors (self):
     307          """Define public methods on the Namespace which provide access to
     308          individual NamedObjectMaps based on their category.
     309
     310          """
     311          for category in self.categories():
     312              accessor_name = category + 's'
     313              setattr(self, accessor_name, lambda _map=self.categoryMap(category): _map)
     314
     315 -    def configureCategories (self, categories):
     316          """Ensure there is a map for each of the given categories.
     317
     318          Category configuration
     319          L{activates<archive._NamespaceArchivable_mixin.isActive>} a namespace.
     320
     321          Existing maps are not affected."""
     322
     323          self._activate()
     324          if self.__categoryMap is None:
     325              self.__categoryMap = { }
     326          for category in categories:
     327              if not (category in self.__categoryMap):
     328                  self.__categoryMap[category] = NamedObjectMap(category, self)
     329          self.__defineCategoryAccessors()
     330          return self
     331
     332 -    def addCategoryObject (self, category, local_name, named_object):
     333          """Allow access to the named_object by looking up the local_name in
     334          the given category.
     335
     336          Raises pyxb.NamespaceUniquenessError if an object with the same name
     337          already exists in the category."""
     338          name_map = self.categoryMap(category)
     339          old_object = name_map.get(local_name)
     340          if (old_object is not None) and (old_object != named_object):
     341              raise pyxb.NamespaceUniquenessError(self, '%s: name %s used for multiple values in %s' % (self, local_name, category))
     342          name_map[local_name] = named_object
     343          return named_object
     344
     345 -    def replaceCategoryObject (self, category, local_name, old_object, new_object):
     346          """Replace the referenced object in the category.
     347
     348          The new object will be added only if the old_object matches the
     349          current entry for local_name in the category."""
     350          name_map = self.categoryMap(category)
     351          if old_object == name_map.get(local_name):
     352              name_map[local_name] = new_object
     353          return name_map[local_name]
     354
     355 -    def _replaceComponent_csc (self, existing_def, replacement_def):
     356          """Replace a component definition where present in the category maps.
     357
     358          @note: This is a high-cost operation, as every item in every category
     359          map must be examined to see whether its value field matches
     360          C{existing_def}."""
     361          for (cat, registry) in self.__categoryMap.iteritems():
     362              for (k, v) in registry.items(): # NB: Not iteritems
     363                  if v == existing_def:
     364                      del registry[k]
     365                      if replacement_def is not None:
     366                          registry[k] = replacement_def
     367          return getattr(super(_NamespaceCategory_mixin, self), '_replaceComponent_csc', lambda *args, **kw: replacement_def)(existing_def, replacement_def)
     368
     369      # Verify that the namespace category map has no components recorded.  This
     370      # is the state that should hold prior to loading a saved namespace; at
     371      # tthe moment, we do not support aggregating components defined separately
     372      # into the same namespace.  That should be done at the schema level using
     373      # the "include" element.
     374 -    def __checkCategoriesEmpty (self):
     375          if self.__categoryMap is None:
     376              return True
     377          assert isinstance(self.__categoryMap, dict)
     378          if 0 == len(self.__categoryMap):
     379              return True
     380          for k in self.categories():
     381              if 0 < len(self.categoryMap(k)):
     382                  return False
     383          return True
     384
     385 -    def _namedObjects (self):
     386          objects = set()
     387          for category_map in self.__categoryMap.itervalues():
     388              objects.update(category_map.itervalues())
     389          return objects
     390
     391 -    def _loadNamedObjects (self, category_map):
     392          """Add the named objects from the given map into the set held by this namespace.
     393          It is an error to name something which is already present."""
     394          self.configureCategories(category_map.iterkeys())
     395          for category in category_map.iterkeys():
     396              current_map = self.categoryMap(category)
     397              new_map = category_map[category]
     398              for (local_name, component) in new_map.iteritems():
     399                  existing_component = current_map.get(local_name)
     400                  if existing_component is None:
     401                      current_map[local_name] = component
     402                  elif existing_component._allowUpdateFromOther(component):
     403                      existing_component._updateFromOther(component)
     404                  else:
     405                      raise pyxb.NamespaceError(self, 'Load attempted to override %s %s in %s' % (category, local_name, self.uri()))
     406          self.__defineCategoryAccessors()
     407
     408 -    def hasSchemaComponents (self):
     409          """Return C{True} iff schema components have been associated with this namespace.
     410
     411          This only checks whether the corresponding categories have been added,
     412          not whether there are any entries in those categories.  It is useful
     413          for identifying namespaces that were incorporated through a
     414          declaration but never actually referenced."""
     415          return 'typeDefinition' in self.__categoryMap
     416
     417 -    def _associateOrigins (self, module_record):
     418          """Add links from L{pyxb.namespace.archive._ObjectOrigin} instances.
     419
     420          For any resolvable item in this namespace from an origin managed by
     421          the module_record, ensure that item can be found via a lookup through
     422          that origin.
     423
     424          This allows these items to be found when a single namespace comprises
     425          items translated from different schema at different times using
     426          archives to maintain consistency."""
     427          assert module_record.namespace() == self
     428          module_record.resetCategoryObjects()
     429          self.configureCategories([archive.NamespaceArchive._AnonymousCategory()])
     430          origin_set = module_record.origins()
     431          for (cat, cat_map) in self.__categoryMap.iteritems():
     432              for (n, v) in cat_map.iteritems():
     433                  if isinstance(v, archive._ArchivableObject_mixin) and (v._objectOrigin() in origin_set):
     434                      v._objectOrigin().addCategoryMember(cat, n, v)
     435
     436 -class _ComponentDependency_mixin (pyxb.utils.utility.PrivateTransient_mixin, pyxb.cscRoot):
     437      """Mix-in for components that can depend on other components."""
     438
     439      __PrivateTransient = set()
     440
     441      # Cached frozenset of components on which this component depends.
     442      __bindingRequires = None
     443      __PrivateTransient.add('bindingRequires')
     444
     445 -    def _resetClone_csc (self, **kw):
     446          """CSC extension to reset fields of a component.  This one clears
     447          dependency-related data, since the clone will have to revise its
     448          dependencies.
     449          @rtype: C{None}"""
     450          getattr(super(_ComponentDependency_mixin, self), '_resetClone_csc', lambda *_args, **_kw: None)(**kw)
     451          self.__bindingRequires = None
     452
     453 -    def bindingRequires (self, reset=False, include_lax=False):
     454          """Return a set of components upon whose bindings this component's
     455          bindings depend.
     456
     457          For example, bindings that are extensions or restrictions depend on
     458          their base types.  Complex type definition bindings require that the
     459          types of their attribute declarations be available at the class
     460          definition, and the types of their element declarations in the
     461          postscript.
     462
     463          @keyword include_lax: if C{False} (default), only the requirements of
     464          the class itself are returned.  If C{True}, all requirements are
     465          returned.
     466          @rtype: C{set(L{pyxb.xmlschema.structures._SchemaComponent_mixin})}
     467          """
     468          if reset or (self.__bindingRequires is None):
     469              if isinstance(self, resolution._Resolvable_mixin) and not (self.isResolved()):
     470                  raise pyxb.LogicError('Unresolved %s in %s: %s' % (self.__class__.__name__, self._namespaceContext().targetNamespace(), self.name()))
     471              self.__bindingRequires = self._bindingRequires_vx(include_lax)
     472          return self.__bindingRequires
     473
     474 -    def _bindingRequires_vx (self, include_lax):
     475          """Placeholder for subclass method that identifies the necessary components.
     476
     477          @note: Override in subclasses.
     478
     479          @return: The component instances on which this component depends
     480          @rtype: C{frozenset}
     481          @raise LogicError: A subclass failed to implement this method
     482          """
     483          raise pyxb.LogicError('%s does not implement _bindingRequires_vx' % (type(self),))
     484
     485 -class _NamespaceComponentAssociation_mixin (pyxb.cscRoot):
     486      """Mix-in for managing components defined within this namespace.
     487
     488      The component set includes not only top-level named components (such as
     489      those accessible through category maps), but internal anonymous
     490      components, such as those involved in representing the content model of a
     491      complex type definition.  We need to be able to get a list of these
     492      components, sorted in dependency order, so that generated bindings do not
     493      attempt to refer to a binding that has not yet been generated."""
     494
     495      # A set containing all components, named or unnamed, that belong to this
     496      # namespace.
     497      __components = None
     498
     499 -    def _reset (self):
     500          """CSC extension to reset fields of a Namespace.
     501
     502          This one handles data related to component association with a
     503          namespace."""
     504          getattr(super(_NamespaceComponentAssociation_mixin, self), '_reset', lambda *args, **kw: None)()
     505          self.__components = set()
     506          self.__origins = set()
     507          self.__schemaMap = { }
     508
     509 -    def _associateComponent (self, component):
     510          """Record that the responsibility for the component belongs to this namespace."""
     511          self._activate()
     512          assert self.__components is not None
     513          assert isinstance(component, _ComponentDependency_mixin)
     514          assert component not in self.__components
     515          self.__components.add(component)
     516
     517 -    def _replaceComponent_csc (self, existing_def, replacement_def):
     518          """Replace a component definition in the set of associated components.
     519
     520          @raise KeyError: C{existing_def} is not in the set of components."""
     521
     522          self.__components.remove(existing_def)
     523          if replacement_def is not None:
     524              self.__components.add(replacement_def)
     525          return getattr(super(_NamespaceComponentAssociation_mixin, self), '_replaceComponent_csc', lambda *args, **kw: replacement_def)(existing_def, replacement_def)
     526
     527 -    def addSchema (self, schema):
     528          for sr in self.__origins:
     529              if isinstance(sr, archive._SchemaOrigin) and sr.match(schema=schema):
     530                  _log.info('Hash for %s matches %s already registered as %s', schema.location(), sr.schema().location(), self)
     531                  raise pyxb.SchemaUniquenessError(self, schema.location(), sr.schema())
     532          sr = archive._SchemaOrigin(schema=schema)
     533          schema.generationUID().associateObject(sr)
     534          self.__origins.add(sr)
     535          return sr
     536
     537 -    def lookupSchemaByLocation (self, schema_location):
     538          for sr in self.__origins:
     539              if isinstance(sr, archive._SchemaOrigin) and sr.match(location=schema_location):
     540                  return (True, sr.schema())
     541          for mr in self.moduleRecords():
     542              if mr.hasMatchingOrigin(location=schema_location):
     543                  return (True, None)
     544          return (False, None)
     545
     546 -    def schemas (self):
     547          s = set()
     548          for sr in self.__origins:
     549              if isinstance(sr, archive._SchemaOrigin) and (sr.schema() is not None):
     550                  s.add(sr.schema())
     551          return s
     552
     553      __origins = None
     554
     555 -    def components (self):
     556          """Return a frozenset of all components, named or unnamed, belonging
     557          to this namespace."""
     558          return frozenset(self.__components)
     559
     560 -    def _releaseNamespaceContexts (self):
     561          for c in self.__components:
     562              c._clearNamespaceContext()
     563
     564  from pyxb.namespace import archive
     565  from pyxb.namespace.utility import NamespaceInstance
     566  from pyxb.namespace.utility import NamespaceForURI
     567  from pyxb.namespace.utility import CreateAbsentNamespace
     568  from pyxb.namespace.utility import AvailableNamespaces
     569  from pyxb.namespace import resolution
     570
     571 -class Namespace (_NamespaceCategory_mixin, resolution._NamespaceResolution_mixin, _NamespaceComponentAssociation_mixin, archive._NamespaceArchivable_mixin):
     572      """Represents an XML namespace (a URI).
     573
     574      There is at most one L{Namespace} class instance per namespace (URI).  The
     575      instance also supports associating arbitrary L{maps<NamedObjectMap>} from
     576      names to objects, in separate categories.  The default categories are
     577      configured externally; for example, the
     578      L{Schema<pyxb.xmlschema.structures.Schema>} component defines a category
     579      for each named component in XMLSchema, and the customizing subclass for
     580      WSDL definitions adds categories for the service bindings, messages, etc.
     581
     582      Namespaces can be written to and loaded from pickled files.  See
     583      L{NamespaceArchive} for information.
     584      """
     585
     586      # The URI for the namespace.  If the URI is None, this is an absent
     587      # namespace.
     588      __uri = None
     589
     590      # An identifier, unique within a program using PyXB, used to distinguish
     591      # absent namespaces.  Currently this value is not accessible to the user,
     592      # and exists solely to provide a unique identifier when printing the
     593      # namespace as a string.  The class variable is used as a one-up counter,
     594      # which is assigned to the instance variable when an absent namespace
     595      # instance is created.
     596      __absentNamespaceID = 0
     597
     598      # A prefix bound to this namespace by standard.  Current set known are applies to
     599      # xml and xmlns.
     600      __boundPrefix = None
     601
     602      # A prefix set as a preferred prefix, generally by processing a namespace
     603      # declaration.
     604      __prefix = None
     605
     606      # A map from URIs to Namespace instances.  Namespaces instances
     607      # must be unique for their URI.  See __new__().
     608      __Registry = { }
     609
     610      # A set of all absent namespaces created.
     611      __AbsentNamespaces = set()
     612
     613      # Optional description of the namespace
     614      __description = None
     615
     616      # Indicates whether this namespace is built-in to the system
     617      __isBuiltinNamespace = False
     618
     619      # Indicates whether this namespace is undeclared (available always)
     620      __isUndeclaredNamespace = False
     621
     622      # Indicates whether this namespace was loaded from an archive
     623      __isLoadedNamespace = False
     624
     625      # Archive from which the namespace can be read, or None if no archive
     626      # defines this namespace.
     627      __namespaceArchive = None
     628
     629      # Indicates whether this namespace has been written to an archive
     630      __hasBeenArchived = False
     631
     632      # Holds the module path for builtin modules until we get a ModuleRecord to
     633      # store that in.
     634      __builtinModulePath = None
     635
     636      # A set of options defining how the Python bindings for this namespace
     637      # were generated.  Not currently used, since we don't have different
     638      # binding configurations yet.
     639      __bindingConfiguration = None
     640
     641      # The namespace to use as the default namespace when constructing the
     642      # The namespace context used when creating built-in components that belong
     643      # to this namespace.  This is used to satisfy the low-level requirement
     644      # that all schema components have a namespace context; normally, that
     645      # context is built dynamically from the schema element.
     646      __initialNamespaceContext = None
     647
     648      # The default_namespace parameter when creating the initial namespace
     649      # context.  Only used with built-in namespaces.
     650      __contextDefaultNamespace = None
     651
     652      # The map from prefixes to namespaces as defined by the schema element for
     653      # this namespace.  Only used with built-in namespaces.
     654      __contextInScopeNamespaces = None
     655
     656      @classmethod
     657 -    def _NamespaceForURI (cls, uri):
     658          """If a Namespace instance for the given URI exists, return it; otherwise return None.
     659
     660          Note; Absent namespaces are not stored in the registry.  If you use
     661          one (e.g., for a schema with no target namespace), don't lose hold of
     662          it."""
     663          assert uri is not None
     664          return cls.__Registry.get(uri)
     665
     666 -    def __getnewargs__ (self):
     667          """Pickling support.
     668
     669          To ensure that unpickled Namespace instances are unique per
     670          URI, we ensure that the routine that creates unpickled
     671          instances knows what it's supposed to return."""
     672          if self.uri() is None:
     673              raise pyxb.LogicError('Illegal to serialize absent namespaces')
     674          return (self.uri(),)
     675
     676 -    def __new__ (cls, *args, **kw):
     677          """Pickling and singleton support.
     678
     679          This ensures that no more than one Namespace instance exists
     680          for any given URI.  We could do this up in __init__, but that
     681          doesn't normally get called when unpickling instances; this
     682          does.  See also __getnewargs__()."""
     683          (uri,) = args
     684          if not (uri in cls.__Registry):
     685              instance = object.__new__(cls)
     686              # Do this one step of __init__ so we can do checks during unpickling
     687              instance.__uri = uri
     688              instance._reset()
     689              # Absent namespaces are not stored in the registry.
     690              if uri is None:
     691                  cls.__AbsentNamespaces.add(instance)
     692                  return instance
     693              cls.__Registry[uri] = instance
     694          return cls.__Registry[uri]
     695
     696      @classmethod
     697 -    def AvailableNamespaces (cls):
     698          """Return a set of all Namespace instances defined so far."""
     699          return cls.__AbsentNamespaces.union(cls.__Registry.itervalues())
     700
     701 -    def __init__ (self, uri,
     702                    description=None,
     703                    builtin_namespace=None,
     704                    builtin_module_path=None,
     705                    is_undeclared_namespace=False,
     706                    is_loaded_namespace=False,
     707                    bound_prefix=None,
     708                    default_namespace=None,
     709                    in_scope_namespaces=None):
     710          """Create a new Namespace.
     711
     712          The URI must be non-None, and must not already be assigned to
     713          a Namespace instance.  See _NamespaceForURI().
     714
     715          User-created Namespace instances may also provide a description.
     716
     717          Users should never provide a builtin_namespace parameter.
     718          """
     719
     720          # New-style superclass invocation
     721          super(Namespace, self).__init__()
     722
     723          self.__contextDefaultNamespace = default_namespace
     724          self.__contextInScopeNamespaces = in_scope_namespaces
     725
     726          # Make sure that we're not trying to do something restricted to
     727          # built-in namespaces
     728          is_builtin_namespace = not (builtin_namespace is None)
     729          if not is_builtin_namespace:
     730              if bound_prefix is not None:
     731                  raise pyxb.LogicError('Only permanent Namespaces may have bound prefixes')
     732
     733          # We actually set the uri when this instance was allocated;
     734          # see __new__().
     735          assert self.__uri == uri
     736          self.__boundPrefix = bound_prefix
     737          self.__description = description
     738          self.__isBuiltinNamespace = is_builtin_namespace
     739          self.__builtinNamespaceVariable = builtin_namespace
     740          self.__builtinModulePath = builtin_module_path
     741          self.__isUndeclaredNamespace = is_undeclared_namespace
     742          self.__isLoadedNamespace = is_loaded_namespace
     743
     744          self._reset()
     745
     746          assert (self.__uri is None) or (self.__Registry[self.__uri] == self)
     747
     748 -    def _reset (self):
     749          assert not self.isActive()
     750          getattr(super(Namespace, self), '_reset', lambda *args, **kw: None)()
     751          self.__initialNamespaceContext = None
     752
     753 -    def uri (self):
     754          """Return the URI for the namespace represented by this instance.
     755
     756          If the URI is None, this is an absent namespace, used to hold
     757          declarations not associated with a namespace (e.g., from schema with
     758          no target namespace)."""
     759          return self.__uri
     760
     761 -    def setPrefix (self, prefix):
     762          if self.__boundPrefix is not None:
     763              if self.__boundPrefix == prefix:
     764                  return self
     765              raise pyxb.NamespaceError(self, 'Cannot change the prefix of a bound namespace')
     766          self.__prefix = prefix
     767          return self
     768
     769 -    def prefix (self):
     770          if self.__boundPrefix:
     771              return self.__boundPrefix
     772          return self.__prefix
     773
     774 -    def isAbsentNamespace (self):
     775          """Return True iff this namespace is an absent namespace.
     776
     777          Absent namespaces have no namespace URI; they exist only to
     778          hold components created from schemas with no target
     779          namespace."""
     780          return self.__uri is None
     781
     782 -    def fallbackNamespace (self):
     783          """When known to be operating in this namespace, provide the Namespace
     784          instance to be used when names are associated with no namespace."""
     785          if self.isAbsentNamespace():
     786              return self
     787          return None
     788
     789      @classmethod
     790 -    def CreateAbsentNamespace (cls):
     791          """Create an absent namespace.
     792
     793          Use this instead of the standard constructor, in case we need
     794          to augment it with a uuid or the like."""
     795          rv = Namespace(None)
     796          rv.__absentNamespaceID = cls.__absentNamespaceID
     797          cls.__absentNamespaceID += 1
     798
     799          return rv
     800
     801 -    def _overrideAbsentNamespace (self, uri):
     802          assert self.isAbsentNamespace()
     803          self.__uri = uri
     804
     805 -    def boundPrefix (self):
     806          """Return the standard prefix to be used for this namespace.
     807
     808          Only a few namespace prefixes are bound to namespaces: xml and xmlns
     809          are two.  In all other cases, this method should return None.  The
     810          infrastructure attempts to prevent user creation of Namespace
     811          instances that have bound prefixes."""
     812          return self.__boundPrefix
     813
     814 -    def isBuiltinNamespace (self):
     815          """Return True iff this namespace was defined by the infrastructure.
     816
     817          That is the case for all namespaces in the Namespace module."""
     818          return self.__isBuiltinNamespace
     819
     820 -    def builtinNamespaceRepresentation (self):
     821          assert self.__builtinNamespaceVariable is not None
     822          return 'pyxb.namespace.%s' % (self.__builtinNamespaceVariable,)
     823
     824 -    def builtinModulePath (self):
     825          from pyxb.namespace import builtin
     826          if not self.__builtinModulePath:
     827              raise pyxb.LogicError('Namespace has no built-in module: %s' % (self,))
     828          mr = self.lookupModuleRecordByUID(builtin.BuiltInObjectUID)
     829          assert mr is not None
     830          assert mr.modulePath() == self.__builtinModulePath
     831          return self.__builtinModulePath
     832
     833 -    def isUndeclaredNamespace (self):
     834          """Return True iff this namespace is always available
     835          regardless of whether there is a declaration for it.
     836
     837          This is the case only for the
     838          xml(http://www.w3.org/XML/1998/namespace) and
     839          xmlns(http://www.w3.org/2000/xmlns/) namespaces."""
     840          return self.__isUndeclaredNamespace
     841
     842 -    def isLoadedNamespace (self):
     843          """Return C{True} iff this namespace was loaded from a namespace archive."""
     844          return self.__isLoadedNamespace
     845
     846 -    def hasBeenArchived (self):
     847          """Return C{True} iff this namespace has been saved to a namespace archive.
     848          See also L{isLoadedNamespace}."""
     849          return self.__hasBeenArchived
     850
     851 -    def description (self, description=None):
     852          """Get, or set, a textual description of the namespace."""
     853          if description is not None:
     854              self.__description = description
     855          return self.__description
     856
     857 -    def nodeIsNamed (self, node, *local_names):
     858          return (node.namespaceURI == self.uri()) and (node.localName in local_names)
     859
     860 -    def createExpandedName (self, local_name):
     861          return ExpandedName(self, local_name)
     862
     863 -    def __getstate__ (self):
     864          """Support pickling.
     865
     866          Well, no, not really.  Because namespace instances must be unique, we
     867          represent them as their URI, and that's done by __getnewargs__
     868          above.  All the interesting information is in the ModuleRecords."""
     869          return {}
     870
     871 -    def _defineBuiltins_ox (self, structures_module):
     872          pass
     873
     874      __definedBuiltins = False
     875 -    def _defineBuiltins (self, structures_module):
     876          assert self.isBuiltinNamespace()
     877          if not self.__definedBuiltins:
     878              from pyxb.namespace import builtin
     879              mr = self.lookupModuleRecordByUID(builtin.BuiltInObjectUID, create_if_missing=True, module_path=self.__builtinModulePath)
     880              self._defineBuiltins_ox(structures_module)
     881              self.__definedBuiltins = True
     882              mr.markIncorporated()
     883          return self
     884
     885 -    def _loadComponentsFromArchives (self, structures_module):
     886          """Attempts to load the named objects held in this namespace.
     887
     888          The base class implementation looks at the set of available archived
     889          namespaces, and if one contains this namespace unserializes its named
     890          object maps.
     891
     892          Sub-classes may choose to look elsewhere, if this version fails or
     893          before attempting it.
     894
     895          There is no guarantee that any particular category of named object has
     896          been located when this returns.  Caller must check.
     897          """
     898          for mr in self.moduleRecords():
     899              if mr.isLoadable():
     900                  if mr.isPublic():
     901                      _log.info('Load %s from %s', mr, mr.archive())
     902                      try:
     903                          mr.archive().readNamespaces()
     904                      except pyxb.NamespaceArchiveError:
     905                          _log.exception("Failure reading namespaces in archive")
     906                  else:
     907                      _log.info('Ignoring private module %s in validation', mr)
     908          self._activate()
     909
     910      __didValidation = False
     911      __inValidation = False
     912 -    def validateComponentModel (self, structures_module=None):
     913          """Ensure this namespace is ready for use.
     914
     915          If the namespace does not have a map of named objects, the system will
     916          attempt to load one.
     917          """
     918          if not self.__didValidation:
     919              # assert not self.__inValidation, 'Nested validation of %s' % (self.uri(),)
     920              if structures_module is None:
     921                  import pyxb.xmlschema.structures as structures_module
     922              if self.isBuiltinNamespace():
     923                  self._defineBuiltins(structures_module)
     924              try:
     925                  self.__inValidation = True
     926                  self._loadComponentsFromArchives(structures_module)
     927                  self.__didValidation = True
     928              finally:
     929                  self.__inValidation = False
     930          return True
     931
     932 -    def _replaceComponent (self, existing_def, replacement_def):
     933          """Replace the existing definition with another.
     934
     935          This is used in a situation where building the component model
     936          resulted in a new component instance being created and registered, but
     937          for which an existing component is to be preferred.  An example is
     938          when parsing the schema for XMLSchema itself: the built-in datatype
     939          components should be retained instead of the simple type definition
     940          components dynamically created from the schema.
     941
     942          By providing the value C{None} as the replacement definition, this can
     943          also be used to remove components.
     944
     945          @note: Invoking this requires scans of every item in every category
     946          map in the namespace.
     947
     948          @return: C{replacement_def}
     949          """
     950          # We need to do replacements in the category map handler, the
     951          # resolver, and the component associator.
     952          return self._replaceComponent_csc(existing_def, replacement_def)
     953
     954 -    def initialNamespaceContext (self):
     955          """Obtain the namespace context to be used when creating components in this namespace.
     956
     957          Usually applies only to built-in namespaces, but is also used in the
     958          autotests when creating a namespace without a xs:schema element.  .
     959          Note that we must create the instance dynamically, since the
     960          information that goes into it has cross-dependencies that can't be
     961          resolved until this module has been completely loaded."""
     962
     963          if self.__initialNamespaceContext is None:
     964              isn = { }
     965              if self.__contextInScopeNamespaces is not None:
     966                  for (k, v) in self.__contextInScopeNamespaces.iteritems():
     967                      isn[k] = self.__identifyNamespace(v)
     968              kw = { 'target_namespace' : self
     969                   , 'default_namespace' : self.__identifyNamespace(self.__contextDefaultNamespace)
     970                   , 'in_scope_namespaces' : isn }
     971              self.__initialNamespaceContext = resolution.NamespaceContext(None, **kw)
     972          return self.__initialNamespaceContext
     973
     974
     975 -    def __identifyNamespace (self, nsval):
     976          """Identify the specified namespace, which should be a built-in.
     977
     978          Normally we can just use a reference to the Namespace module instance,
     979          but when creating those instances we sometimes need to refer to ones
     980          for which the instance has not yet been created.  In that case, we use
     981          the name of the instance, and resolve the namespace when we need to
     982          create the initial context."""
     983          if nsval is None:
     984              return self
     985          if isinstance(nsval, (str, unicode)):
     986              nsval = globals().get(nsval)
     987          if isinstance(nsval, Namespace):
     988              return nsval
     989          raise pyxb.LogicError('Cannot identify namespace from %s' % (nsval,))
     990
     991 -    def __str__ (self):
     992          if self.__uri is None:
     993              return 'AbsentNamespace%d' % (self.__absentNamespaceID,)
     994          assert self.__uri is not None
     995          if self.__boundPrefix is not None:
     996              rv = '%s=%s' % (self.__boundPrefix, self.__uri)
     997          else:
     998              rv = self.__uri
     999          return rv
    1000
    1001  from pyxb.namespace.builtin import XMLSchema_instance
    1002  from pyxb.namespace.builtin import XMLNamespaces
    1003  from pyxb.namespace.builtin import XMLSchema
    1004  from pyxb.namespace.builtin import XHTML
    1005  from pyxb.namespace.builtin import XML
    1006  from pyxb.namespace.builtin import XMLSchema_hfp
    1007  from pyxb.namespace.builtin import BuiltInObjectUID
    1008
    1009  resolution.NamespaceContext._AddTargetNamespaceAttribute(XMLSchema.createExpandedName('schema'), ExpandedName('targetNamespace'))
    1010
    1011  ## Local Variables:
    1012  ## fill-column:78
    1013  ## End:
    1014