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 18Since namespaces hold all referenceable objects, this module also defines the 19infrastructure for resolving named object references, such as schema 20components. 21""" 22 23import pyxb 24import pyxb.utils.utility 25from pyxb.utils import six 26import xml.dom 27import logging 28 29_log = logging.getLogger(__name__) 30 31@pyxb.utils.utility.BackfillComparisons 32class 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 246class 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 269class _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 441class _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 490class _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 569from pyxb.namespace import archive 570from pyxb.namespace.utility import NamespaceInstance 571from pyxb.namespace.utility import NamespaceForURI 572from pyxb.namespace.utility import CreateAbsentNamespace 573from pyxb.namespace.utility import AvailableNamespaces 574from pyxb.namespace import resolution 575NamespaceContext = resolution.NamespaceContext 576 577class 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 if (None is not prefix) and (0 == len(prefix)): 804 raise pyxb.UsageError('prefix must be non-empty string') 805 self.__prefix = prefix 806 return self 807 808 def prefix (self): 809 if self.__boundPrefix: 810 return self.__boundPrefix 811 return self.__prefix 812 813 def isAbsentNamespace (self): 814 """Return True iff this namespace is an absent namespace. 815 816 Absent namespaces have no namespace URI; they exist only to 817 hold components created from schemas with no target 818 namespace.""" 819 return self.__uri is None 820 821 def fallbackNamespace (self): 822 """When known to be operating in this namespace, provide the Namespace 823 instance to be used when names are associated with no namespace.""" 824 if self.isAbsentNamespace(): 825 return self 826 return None 827 828 @classmethod 829 def CreateAbsentNamespace (cls): 830 """Create an absent namespace. 831 832 Use this instead of the standard constructor, in case we need 833 to augment it with a uuid or the like.""" 834 rv = Namespace(None) 835 rv.__absentNamespaceID = cls.__absentNamespaceID 836 cls.__absentNamespaceID += 1 837 838 return rv 839 840 def _overrideAbsentNamespace (self, uri): 841 assert self.isAbsentNamespace() 842 self.__uri = uri 843 844 def boundPrefix (self): 845 """Return the standard prefix to be used for this namespace. 846 847 Only a few namespace prefixes are bound to namespaces: xml and xmlns 848 are two. In all other cases, this method should return None. The 849 infrastructure attempts to prevent user creation of Namespace 850 instances that have bound prefixes.""" 851 return self.__boundPrefix 852 853 def isBuiltinNamespace (self): 854 """Return True iff this namespace was defined by the infrastructure. 855 856 That is the case for all namespaces in the Namespace module.""" 857 return self.__isBuiltinNamespace 858 859 def builtinNamespaceRepresentation (self): 860 assert self.__builtinNamespaceVariable is not None 861 return 'pyxb.namespace.%s' % (self.__builtinNamespaceVariable,) 862 863 def builtinModulePath (self): 864 from pyxb.namespace import builtin 865 if not self.__builtinModulePath: 866 raise pyxb.LogicError('Namespace has no built-in module: %s' % (self,)) 867 mr = self.lookupModuleRecordByUID(builtin.BuiltInObjectUID) 868 assert mr is not None 869 assert mr.modulePath() == self.__builtinModulePath 870 return self.__builtinModulePath 871 872 def isUndeclaredNamespace (self): 873 """Return True iff this namespace is always available 874 regardless of whether there is a declaration for it. 875 876 This is the case only for the 877 xml(http://www.w3.org/XML/1998/namespace) and 878 xmlns(http://www.w3.org/2000/xmlns/) namespaces.""" 879 return self.__isUndeclaredNamespace 880 881 def isLoadedNamespace (self): 882 """Return C{True} iff this namespace was loaded from a namespace archive.""" 883 return self.__isLoadedNamespace 884 885 def hasBeenArchived (self): 886 """Return C{True} iff this namespace has been saved to a namespace archive. 887 See also L{isLoadedNamespace}.""" 888 return self.__hasBeenArchived 889 890 def description (self, description=None): 891 """Get, or set, a textual description of the namespace.""" 892 if description is not None: 893 self.__description = description 894 return self.__description 895 896 def nodeIsNamed (self, node, *local_names): 897 return (node.namespaceURI == self.uri()) and (node.localName in local_names) 898 899 def createExpandedName (self, local_name): 900 return ExpandedName(self, local_name) 901 902 def __getstate__ (self): 903 """Support pickling. 904 905 Well, no, not really. Because namespace instances must be unique, we 906 represent them as their URI, and that's done by __getnewargs__ 907 above. All the interesting information is in the ModuleRecords.""" 908 return {} 909 910 def _defineBuiltins_ox (self, structures_module): 911 pass 912 913 __definedBuiltins = False 914 def _defineBuiltins (self, structures_module): 915 assert self.isBuiltinNamespace() 916 if not self.__definedBuiltins: 917 from pyxb.namespace import builtin 918 mr = self.lookupModuleRecordByUID(builtin.BuiltInObjectUID, create_if_missing=True, module_path=self.__builtinModulePath) 919 self._defineBuiltins_ox(structures_module) 920 self.__definedBuiltins = True 921 mr.markIncorporated() 922 return self 923 924 def _loadComponentsFromArchives (self, structures_module): 925 """Attempts to load the named objects held in this namespace. 926 927 The base class implementation looks at the set of available archived 928 namespaces, and if one contains this namespace unserializes its named 929 object maps. 930 931 Sub-classes may choose to look elsewhere, if this version fails or 932 before attempting it. 933 934 There is no guarantee that any particular category of named object has 935 been located when this returns. Caller must check. 936 """ 937 for mr in self.moduleRecords(): 938 if mr.isLoadable(): 939 if mr.isPublic(): 940 _log.info('Load %s from %s', mr, mr.archive()) 941 try: 942 mr.archive().readNamespaces() 943 except pyxb.NamespaceArchiveError: 944 _log.exception("Failure reading namespaces in archive") 945 else: 946 _log.info('Ignoring private module %s in validation', mr) 947 self._activate() 948 949 __didValidation = False 950 __inValidation = False 951 def validateComponentModel (self, structures_module=None): 952 """Ensure this namespace is ready for use. 953 954 If the namespace does not have a map of named objects, the system will 955 attempt to load one. 956 """ 957 if not self.__didValidation: 958 # assert not self.__inValidation, 'Nested validation of %s' % (self.uri(),) 959 if structures_module is None: 960 import pyxb.xmlschema.structures as structures_module 961 if self.isBuiltinNamespace(): 962 self._defineBuiltins(structures_module) 963 try: 964 self.__inValidation = True 965 self._loadComponentsFromArchives(structures_module) 966 self.__didValidation = True 967 finally: 968 self.__inValidation = False 969 return True 970 971 def _replaceComponent (self, existing_def, replacement_def): 972 """Replace the existing definition with another. 973 974 This is used in a situation where building the component model 975 resulted in a new component instance being created and registered, but 976 for which an existing component is to be preferred. An example is 977 when parsing the schema for XMLSchema itself: the built-in datatype 978 components should be retained instead of the simple type definition 979 components dynamically created from the schema. 980 981 By providing the value C{None} as the replacement definition, this can 982 also be used to remove components. 983 984 @note: Invoking this requires scans of every item in every category 985 map in the namespace. 986 987 @return: C{replacement_def} 988 """ 989 # We need to do replacements in the category map handler, the 990 # resolver, and the component associator. 991 return self._replaceComponent_csc(existing_def, replacement_def) 992 993 def initialNamespaceContext (self): 994 """Obtain the namespace context to be used when creating components in this namespace. 995 996 Usually applies only to built-in namespaces, but is also used in the 997 autotests when creating a namespace without a xs:schema element. . 998 Note that we must create the instance dynamically, since the 999 information that goes into it has cross-dependencies that can't be 1000 resolved until this module has been completely loaded.""" 1001 1002 if self.__initialNamespaceContext is None: 1003 isn = { } 1004 if self.__contextInScopeNamespaces is not None: 1005 for (k, v) in six.iteritems(self.__contextInScopeNamespaces): 1006 isn[k] = self.__identifyNamespace(v) 1007 kw = { 'target_namespace' : self 1008 , 'default_namespace' : self.__identifyNamespace(self.__contextDefaultNamespace) 1009 , 'in_scope_namespaces' : isn } 1010 self.__initialNamespaceContext = resolution.NamespaceContext(None, **kw) 1011 return self.__initialNamespaceContext 1012 1013 1014 def __identifyNamespace (self, nsval): 1015 """Identify the specified namespace, which should be a built-in. 1016 1017 Normally we can just use a reference to the Namespace module instance, 1018 but when creating those instances we sometimes need to refer to ones 1019 for which the instance has not yet been created. In that case, we use 1020 the name of the instance, and resolve the namespace when we need to 1021 create the initial context.""" 1022 if nsval is None: 1023 return self 1024 if isinstance(nsval, six.string_types): 1025 nsval = globals().get(nsval) 1026 if isinstance(nsval, Namespace): 1027 return nsval 1028 raise pyxb.LogicError('Cannot identify namespace from %s' % (nsval,)) 1029 1030 def __str__ (self): 1031 if self.__uri is None: 1032 return 'AbsentNamespace%d' % (self.__absentNamespaceID,) 1033 assert self.__uri is not None 1034 if self.__boundPrefix is not None: 1035 rv = '%s=%s' % (self.__boundPrefix, self.__uri) 1036 else: 1037 rv = self.__uri 1038 return rv 1039 1040from pyxb.namespace.builtin import XMLSchema_instance 1041from pyxb.namespace.builtin import XMLNamespaces 1042from pyxb.namespace.builtin import XMLSchema 1043from pyxb.namespace.builtin import XHTML 1044from pyxb.namespace.builtin import XML 1045from pyxb.namespace.builtin import XMLSchema_hfp 1046from pyxb.namespace.builtin import BuiltInObjectUID 1047 1048resolution.NamespaceContext._AddTargetNamespaceAttribute(XMLSchema.createExpandedName('schema'), ExpandedName('targetNamespace')) 1049 1050## Local Variables: 1051## fill-column:78 1052## End: 1053