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