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"""This module contains support classes from which schema-specific bindings 17inherit, and that describe the content models of those schema.""" 18 19import logging 20import collections 21import xml.dom 22import pyxb 23from pyxb.utils import domutils, utility, six 24import pyxb.namespace 25from pyxb.namespace.builtin import XMLSchema_instance as XSI 26import decimal 27 28_log = logging.getLogger(__name__) 29 30class _TypeBinding_mixin (utility.Locatable_mixin): 31 # Private member holding the validation configuration that applies to the 32 # class or instance. Can't really make it private with __ prefix because 33 # that would screw up parent classes. You end users---stay away from 34 # this. 35 _validationConfig_ = pyxb.GlobalValidationConfig 36 37 @classmethod 38 def _SetValidationConfig (cls, validation_config): 39 """Set the validation configuration for this class.""" 40 cls._validationConfig_ = validation_config 41 42 @classmethod 43 def _GetValidationConfig (cls): 44 """The L{pyxb.ValidationConfig} instance that applies to this class. 45 46 By default this will reference L{pyxb.GlobalValidationConfig}.""" 47 return cls._validationConfig_ 48 49 def _setValidationConfig (self, validation_config): 50 """Set the validation configuration for this instance.""" 51 self._validationConfig_ = validation_config 52 53 def __getValidationConfig (self): 54 """The L{pyxb.ValidationConfig} instance that applies to this instance. 55 56 By default this will reference the class value from 57 L{_GetValidationConfig}, which defaults to 58 L{pyxb.GlobalValidationConfig}.""" 59 return self._validationConfig_ 60 61 # This is how you should be accessing this value. 62 _validationConfig = property(__getValidationConfig) 63 64 @classmethod 65 def _PerformValidation (cls): 66 """Determine whether the content model should be validated for this class. 67 68 In the absence of context, this returns C{True} iff both binding and 69 document validation are in force. 70 71 @deprecated: use L{_GetValidationConfig} and check specific requirements.""" 72 # Bypass the property since this is a class method 73 vo = cls._validationConfig_ 74 return vo.forBinding and vo.forDocument 75 76 def _performValidation (self): 77 """Determine whether the content model should be validated for this 78 instance. 79 80 In the absence of context, this returns C{True} iff both binding and 81 document validation are in force. 82 83 @deprecated: use L{_validationConfig} and check specific requirements.""" 84 vo = self._validationConfig 85 return vo.forBinding and vo.forDocument 86 87 _ExpandedName = None 88 """The expanded name of the component.""" 89 90 _XSDLocation = None 91 """Where the definition can be found in the originating schema.""" 92 93 _ReservedSymbols = set([ 'validateBinding', 'toDOM', 'toxml', 'Factory', 'property' ]) 94 95 if pyxb._CorruptionDetectionEnabled: 96 def __setattr__ (self, name, value): 97 if name in self._ReservedSymbols: 98 raise pyxb.ReservedNameError(self, name) 99 return super(_TypeBinding_mixin, self).__setattr__(name, value) 100 101 _PyXBFactoryKeywords = ( '_dom_node', '_fallback_namespace', '_from_xml', 102 '_apply_whitespace_facet', '_validate_constraints', 103 '_require_value', '_nil', '_element', '_apply_attributes', 104 '_convert_string_values', '_location' ) 105 """Keywords that are interpreted by __new__ or __init__ in one or more 106 classes in the PyXB type hierarchy. All these keywords must be removed 107 before invoking base Python __init__ or __new__.""" 108 109 # While simple type definitions cannot be abstract, they can appear in 110 # many places where complex types can, so we want it to be legal to test 111 # for abstractness without checking whether the object is a complex type. 112 _Abstract = False 113 114 def _namespaceContext (self): 115 """Return a L{namespace context <pyxb.binding.NamespaceContext>} 116 associated with the binding instance. 117 118 This will return C{None} unless something has provided a context to 119 the instance. Context is provided when instances are generated by the 120 DOM and SAX-based translators.""" 121 return self.__namespaceContext 122 def _setNamespaceContext (self, namespace_context): 123 """Associate a L{namespace context <pyxb.binding.NamespaceContext>} 124 with the binding instance.""" 125 self.__namespaceContext = namespace_context 126 return self 127 __namespaceContext = None 128 129 def _setElement (self, elt): 130 """Associate an element binding with the instance. 131 132 Since the value of a binding instance reflects only its content, an 133 associated element is necessary to generate an XML document or DOM 134 tree. 135 136 @param elt: the L{pyxb.binding.basis.element} instance associated with 137 the value. This may be C{None} when disassociating a value from a 138 specific element.""" 139 import pyxb.binding.content 140 assert (elt is None) or isinstance(elt, element) 141 self.__element = elt 142 return self 143 def _element (self): 144 """Return a L{pyxb.binding.basis.element} associated with the binding 145 instance. 146 147 This will return C{None} unless an element has been associated. 148 Constructing a binding instance using the element instance will add 149 this association. 150 """ 151 return self.__element 152 __element = None 153 154 __xsiNil = None 155 def _isNil (self): 156 """Indicate whether this instance is U{nil 157 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>}. 158 159 The value is set by the DOM and SAX parsers when building an instance 160 from a DOM element with U{xsi:nil 161 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>} set to C{true}. 162 163 @return: C{None} if the element used to create the instance is not 164 U{nillable<http://www.w3.org/TR/xmlschema-1/#nillable>}. 165 If it is nillable, returns C{True} or C{False} depending on 166 whether the instance itself is U{nil<http://www.w3.org/TR/xmlschema-1/#xsi_nil>}. 167 """ 168 return self.__xsiNil 169 def _setIsNil (self, nil=True): 170 """Set the xsi:nil property of the instance. 171 172 @param nil: C{True} if the value of xsi:nil should be C{true}, 173 C{False} if the value of xsi:nil should be C{false}. 174 175 @raise pyxb.NoNillableSupportError: the instance is not associated 176 with an element that is L{nillable 177 <pyxb.binding.basis.element.nillable>}. 178 """ 179 if self.__xsiNil is None: 180 raise pyxb.NoNillableSupportError(self) 181 self.__xsiNil = not not nil 182 if self.__xsiNil: 183 # The element must be empty, so also remove all element content. 184 # Attribute values are left unchanged. 185 self._resetContent(reset_elements=True) 186 187 def _resetContent (self, reset_elements=False): 188 """Reset the content of an element value. 189 190 This is not a public method. 191 192 For simple types, this does nothing. For complex types, this clears the 193 L{content<complexTypeDefinition.content>} array, removing all 194 non-element content from the instance. It optionally also removes all 195 element content. 196 197 @param reset_elements: If C{False} (default) only the content array is 198 cleared, which has the effect of removing any preference for element 199 order when generating a document. If C{True}, the element content 200 stored within the binding is also cleared, leaving it with no content 201 at all. 202 203 @note: This is not the same thing as L{complexTypeDefinition.reset}, 204 which unconditionally resets attributes and element and non-element 205 content. 206 """ 207 pass 208 209 __constructedWithValue = False 210 def __checkNilCtor (self, args): 211 self.__constructedWithValue = (0 < len(args)) 212 if self.__xsiNil: 213 if self.__constructedWithValue: 214 raise pyxb.ContentInNilInstanceError(self, args[0]) 215 else: 216 # Types that descend from string will, when constructed from an 217 # element with empty content, appear to have no constructor value, 218 # while in fact an empty string should have been passed. 219 if issubclass(type(self), six.string_types): 220 self.__constructedWithValue = True 221 def _constructedWithValue (self): 222 return self.__constructedWithValue 223 224 # Flag used to control whether we print a warning when creating a complex 225 # type instance that does not have an associated element. Not sure yet 226 # whether that'll be common practice or common error. 227 __WarnedUnassociatedElement = False 228 229 def __init__ (self, *args, **kw): 230 # Strip keyword not used above this level. 231 element = kw.pop('_element', None) 232 is_nil = kw.pop('_nil', False) 233 super(_TypeBinding_mixin, self).__init__(*args, **kw) 234 if (element is None) or element.nillable(): 235 self.__xsiNil = is_nil 236 if element is not None: 237 self._setElement(element) 238 self.__checkNilCtor(args) 239 240 @classmethod 241 def _PreFactory_vx (cls, args, kw): 242 """Method invoked upon entry to the Factory method. 243 244 This method is entitled to modify the keywords array. It can also 245 return a state value which is passed to _postFactory_vx.""" 246 return None 247 248 def _postFactory_vx (cls, state): 249 """Method invoked prior to leaving the Factory method. 250 251 This is an instance method, and is given the state that was returned 252 by _PreFactory_vx.""" 253 return None 254 255 @classmethod 256 def Factory (cls, *args, **kw): 257 """Provide a common mechanism to create new instances of this type. 258 259 The class constructor won't do, because you can't create 260 instances of union types. 261 262 This method may be overridden in subclasses (like STD_union). Pre- 263 and post-creation actions can be customized on a per-class instance by 264 overriding the L{_PreFactory_vx} and L{_postFactory_vx} methods. 265 266 @keyword _dom_node: If provided, the value must be a DOM node, the 267 content of which will be used to set the value of the instance. 268 269 @keyword _location: An optional instance of 270 L{pyxb.utils.utility.Location} showing the origin the binding. If 271 C{None}, a value from C{_dom_node} is used if available. 272 273 @keyword _from_xml: If C{True}, the input must be either a DOM node or 274 a unicode string comprising a lexical representation of a value. This 275 is a further control on C{_apply_whitespace_facet} and arises from 276 cases where the lexical and value representations cannot be 277 distinguished by type. The default value is C{True} iff C{_dom_node} 278 is not C{None}. 279 280 @keyword _apply_whitespace_facet: If C{True} and this is a 281 simpleTypeDefinition with a whiteSpace facet, the first argument will 282 be normalized in accordance with that facet prior to invoking the 283 parent constructor. The value is always C{True} if text content is 284 extracted from a C{_dom_node}, and otherwise defaults to the defaulted 285 value of C{_from_xml}. 286 287 @keyword _validate_constraints: If C{True}, any constructed value is 288 checked against constraints applied to the union as well as the member 289 type. 290 291 @keyword _require_value: If C{False} (default), it is permitted to 292 create a value without an initial value. If C{True} and no initial 293 value was provided, causes L{pyxb.SimpleContentAbsentError} to be raised. 294 Only applies to simpleTypeDefinition instances; this is used when 295 creating values from DOM nodes. 296 """ 297 # Invoke _PreFactory_vx for the superseding class, which is where 298 # customizations will be found. 299 dom_node = kw.get('_dom_node') 300 location = kw.get('_location') 301 if (location is None) and isinstance(dom_node, utility.Locatable_mixin): 302 location = dom_node._location() 303 kw.setdefault('_from_xml', dom_node is not None) 304 used_cls = cls._SupersedingClass() 305 state = used_cls._PreFactory_vx(args, kw) 306 rv = cls._DynamicCreate(*args, **kw) 307 rv._postFactory_vx(state) 308 if (rv._location is None) and (location is not None): 309 rv._setLocation(location) 310 return rv 311 312 def _substitutesFor (self, element): 313 if (element is None) or (self._element() is None): 314 return False 315 return self._element().substitutesFor(element) 316 317 @classmethod 318 def _IsUrType (cls): 319 """Return C{True} iff this is the ur-type. 320 321 The only ur-type is {http://www.w3.org/2001/XMLSchema}anyType. The 322 implementation of this method is overridden for 323 L{pyxb.binding.datatypes.anyType}.""" 324 return False 325 326 @classmethod 327 def _RequireXSIType (cls, value_type): 328 if cls._IsUrType(): 329 # Require xsi:type if value refines xs:anyType 330 return value_type != cls 331 if cls._Abstract: 332 # You can't instantiate an abstract class, so if the element 333 # declaration expects one we're gonna need to be told what type 334 # this really is. 335 return value_type != cls._SupersedingClass() 336 # For unions delegate to whether the selected member type requires 337 # the attribute. Most times they won't. 338 if issubclass(cls, STD_union): 339 for mt in cls._MemberTypes: 340 if issubclass(value_type, mt): 341 return mt._RequireXSIType(value_type) 342 raise pyxb.LogicError('Union %s instance type %s not sublass of member type?' % (cls, value_type)) 343 # Otherwise we need the qualifier if the value type extends or 344 # restricts the type schema expects. 345 return value_type != cls._SupersedingClass() 346 347 @classmethod 348 def _CompatibleValue (cls, value, **kw): 349 """Return a variant of the value that is compatible with this type. 350 351 Compatibility is defined relative to the type definition associated 352 with the element. The value C{None} is always compatible. If 353 C{value} has a Python type (e.g., C{int}) that is a superclass of the 354 required L{_TypeBinding_mixin} class (e.g., C{xs:byte}), C{value} is 355 used as a constructor parameter to return a new instance of the 356 required type. Note that constraining facets are applied here if 357 necessary (e.g., although a Python C{int} with value C{500} is 358 type-compatible with C{xs:byte}, it is outside the value space, and 359 compatibility will fail). 360 361 @keyword _convert_string_values: If C{True} (default) and the incoming value is 362 a string, an attempt will be made to form a compatible value by using 363 the string as a constructor argument to the this class. This flag is 364 set to C{False} when testing automaton transitions. 365 366 @raise pyxb.SimpleTypeValueError: if the value is not both 367 type-consistent and value-consistent with the element's type. 368 """ 369 convert_string_values = kw.get('_convert_string_values', True) 370 # None is always None 371 if value is None: 372 return None 373 # Already an instance? 374 if isinstance(value, cls): 375 # @todo: Consider whether we should change the associated _element 376 # of this value. (**Consider** it, don't just do it.) 377 return value 378 value_type = type(value) 379 # All string-based PyXB binding types use unicode, not str 380 if six.PY2 and str == value_type: 381 value_type = six.text_type 382 383 # See if we got passed a Python value which needs to be "downcasted" 384 # to the _TypeBinding_mixin version. 385 if issubclass(cls, value_type): 386 return cls(value) 387 388 # See if we have a numeric type that needs to be cast across the 389 # numeric hierarchy. int to long is the *only* conversion we accept. 390 if isinstance(value, int) and issubclass(cls, six.long_type): 391 return cls(value) 392 393 # Same, but for boolean, which Python won't let us subclass 394 if isinstance(value, bool) and issubclass(cls, pyxb.binding.datatypes.boolean): 395 return cls(value) 396 397 # See if we have convert_string_values on, and have a string type that 398 # somebody understands. 399 if convert_string_values and value_type == six.text_type: 400 return cls(value) 401 402 # Maybe this is a union? 403 if issubclass(cls, STD_union): 404 for mt in cls._MemberTypes: 405 try: 406 return mt._CompatibleValue(value, **kw) 407 except: 408 pass 409 410 # Any type is compatible with the corresponding ur-type 411 if (pyxb.binding.datatypes.anySimpleType == cls) and issubclass(value_type, simpleTypeDefinition): 412 return value 413 if pyxb.binding.datatypes.anyType == cls: 414 if not isinstance(value, _TypeBinding_mixin): 415 _log.info('Created %s instance from value of type %s', cls._ExpandedName, type(value)) 416 value = cls(value) 417 return value 418 419 # Is this the wrapper class that indicates we should create a binding 420 # from arguments? 421 if isinstance(value, pyxb.BIND): 422 return value.createInstance(cls.Factory, **kw) 423 424 # Does the class have simple content which we can convert? 425 if cls._IsSimpleTypeContent(): 426 # NB: byte(34.2) will create a value, but it may not be one we 427 # want to accept, so only do this if the output is equal to the 428 # input. 429 rv = cls.Factory(value) 430 if isinstance(rv, simpleTypeDefinition) and (rv == value): 431 return rv 432 # Python decimal instances do not compare equal to float values; 433 # test whether the string representation is equal instead. 434 if isinstance(rv, decimal.Decimal) and (str(rv) == str(value)): 435 return rv 436 if isinstance(rv, complexTypeDefinition) and (rv.value() == value): 437 return rv 438 439 # There may be other things that can be converted to the desired type, 440 # but we can't tell that from the type hierarchy. Too many of those 441 # things result in an undesirable loss of information: for example, 442 # when an all model supports both numeric and string transitions, the 443 # candidate is a number, and the string transition is tested first. 444 raise pyxb.SimpleTypeValueError(cls, value) 445 446 @classmethod 447 def _IsSimpleTypeContent (cls): 448 """Return True iff the content of this binding object is a simple type. 449 450 This is true only for descendents of simpleTypeDefinition and instances 451 of complexTypeDefinition that have simple type content.""" 452 raise pyxb.LogicError('Failed to override _TypeBinding_mixin._IsSimpleTypeContent') 453 454 # If the type supports wildcard attributes, this describes their 455 # constraints. (If it doesn't, this should remain None.) Supporting 456 # classes should override this value. 457 _AttributeWildcard = None 458 459 _AttributeMap = { } 460 """Map from expanded names to AttributeUse instances. Non-empty only in 461 L{complexTypeDefinition} subclasses.""" 462 463 @classmethod 464 def __AttributesFromDOM (cls, node): 465 attribute_settings = { } 466 for ai in range(0, node.attributes.length): 467 attr = node.attributes.item(ai) 468 # NB: Specifically do not consider attr's NamespaceContext, since 469 # attributes do not accept a default namespace. 470 attr_en = pyxb.namespace.ExpandedName(attr) 471 472 # Ignore xmlns and xsi attributes; we've already handled those 473 if attr_en.namespace() in ( pyxb.namespace.XMLNamespaces, XSI ): 474 continue 475 476 attribute_settings[attr_en] = attr.value 477 return attribute_settings 478 479 def _setAttributesFromKeywordsAndDOM (self, kw, dom_node): 480 """Invoke self._setAttribute based on node attributes and keywords. 481 482 Though attributes can only legally appear in complexTypeDefinition 483 instances, delayed conditional validation requires caching them in 484 simpleTypeDefinition. 485 486 @param kw: keywords passed to the constructor. This map is mutated by 487 the call: keywords corresponding to recognized attributes are removed. 488 489 @param dom_node: an xml.dom Node instance, possibly C{None} 490 """ 491 492 # Extract keywords that match field names 493 attribute_settings = { } 494 if dom_node is not None: 495 attribute_settings.update(self.__AttributesFromDOM(dom_node)) 496 for fu in six.itervalues(self._AttributeMap): 497 iv = kw.pop(fu.id(), None) 498 if iv is not None: 499 attribute_settings[fu.name()] = iv 500 for (attr_en, value_lex) in six.iteritems(attribute_settings): 501 self._setAttribute(attr_en, value_lex) 502 503 def toDOM (self, bds=None, parent=None, element_name=None): 504 """Convert this instance to a DOM node. 505 506 The name of the top-level element is either the name of the L{element} 507 instance associated with this instance, or the XML name of the type of 508 this instance. 509 510 @param bds: Support for customizing the generated document 511 @type bds: L{pyxb.utils.domutils.BindingDOMSupport} 512 @param parent: If C{None}, a standalone document is created; 513 otherwise, the created element is a child of the given element. 514 @type parent: C{xml.dom.Element} or C{None} 515 @rtype: C{xml.dom.Document} 516 """ 517 518 if bds is None: 519 bds = domutils.BindingDOMSupport() 520 need_xsi_type = bds.requireXSIType() 521 if isinstance(element_name, six.string_types): 522 element_name = pyxb.namespace.ExpandedName(bds.defaultNamespace(), element_name) 523 if (element_name is None) and (self._element() is not None): 524 element_binding = self._element() 525 element_name = element_binding.name() 526 need_xsi_type = need_xsi_type or element_binding.typeDefinition()._RequireXSIType(type(self)) 527 if element_name is None: 528 raise pyxb.UnboundElementError(self) 529 element = bds.createChildElement(element_name, parent) 530 if need_xsi_type: 531 bds.addAttribute(element, XSI.type, self._ExpandedName) 532 self._toDOM_csc(bds, element) 533 bds.finalize() 534 return bds.document() 535 536 def toxml (self, encoding=None, bds=None, root_only=False, element_name=None): 537 """Shorthand to get the object as an XML document. 538 539 If you want to set the default namespace, pass in a pre-configured 540 C{bds}. 541 542 @param encoding: The encoding to be used. See 543 @C{xml.dom.Node.toxml()} for a description of why you should always 544 pass @C{'utf-8'} here. Because this method follows the contract of 545 the corresponding C{xml.dom.Node} method, it does not automatically 546 get the default PyXB output encoding. 547 548 @param bds: Optional L{pyxb.utils.domutils.BindingDOMSupport} instance 549 to use for creation. If not provided (default), a new generic one is 550 created. 551 552 @param root_only: Set to C{True} to automatically deference the 553 C{documentElement} of the resulting DOM node. This eliminates the XML 554 declaration that would otherwise be generated. 555 556 @param element_name: This value is passed through to L{toDOM}, and is 557 useful when the value has no bound element but you want to convert it 558 to XML anyway. 559 """ 560 dom = self.toDOM(bds, element_name=element_name) 561 if root_only: 562 dom = dom.documentElement 563 return dom.toxml(encoding) 564 565 def _toDOM_csc (self, dom_support, parent): 566 assert parent is not None 567 if self.__xsiNil: 568 dom_support.addAttribute(parent, XSI.nil, 'true') 569 return getattr(super(_TypeBinding_mixin, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent) 570 571 def _validateBinding_vx (self): 572 """Override in subclasses for type-specific validation of instance 573 content. 574 575 @return: C{True} if the instance validates 576 @raise pyxb.BatchContentValidationError: complex content does not match model 577 @raise pyxb.SimpleTypeValueError: simple content fails to satisfy constraints 578 """ 579 raise NotImplementedError('%s._validateBinding_vx' % (type(self).__name__,)) 580 581 def validateBinding (self): 582 """Check whether the binding content matches its content model. 583 584 @return: C{True} if validation succeeds. 585 @raise pyxb.BatchContentValidationError: complex content does not match model 586 @raise pyxb.SimpleTypeValueError: attribute or simple content fails to satisfy constraints 587 """ 588 if self._performValidation(): 589 self._validateBinding_vx() 590 return True 591 592 def _finalizeContentModel (self): 593 """Inform content model that all additions have been provided. 594 595 This is used to resolve any pending non-determinism when the content 596 of an element is provided through a DOM assignment or through 597 positional arguments in a constructor.""" 598 return self 599 600 def _postDOMValidate (self): 601 self.validateBinding() 602 return self 603 604 @classmethod 605 def _Name (cls): 606 """Return the best descriptive name for the type of the instance. 607 608 This is intended to be a human-readable value used in diagnostics, and 609 is the expanded name if the type has one, or the Python type name if 610 it does not.""" 611 if cls._ExpandedName is not None: 612 return six.text_type(cls._ExpandedName) 613 return six.text_type(cls) 614 615 def _diagnosticName (self): 616 """The best name available for this instance in diagnostics. 617 618 If the instance is associated with an element, it is the element name; 619 otherwise it is the best name for the type of the instance per L{_Name}.""" 620 if self.__element is None: 621 return self._Name() 622 return six.text_type(self.__element.name()) 623 624class _DynamicCreate_mixin (pyxb.cscRoot): 625 """Helper to allow overriding the implementation class. 626 627 Generally we'll want to augment the generated bindings by subclassing 628 them, and adding functionality to the subclass. This mix-in provides a 629 way to communicate the existence of the superseding subclass back to the 630 binding infrastructure, so that when it creates an instance it uses the 631 subclass rather than the unaugmented binding class. 632 633 When a raw generated binding is subclassed, L{_SetSupersedingClass} should be 634 invoked on the raw class passing in the superseding subclass. E.g.:: 635 636 class mywsdl (raw.wsdl): 637 pass 638 raw.wsdl._SetSupersedingClass(mywsdl) 639 640 """ 641 642 @classmethod 643 def __SupersedingClassAttribute (cls): 644 return '_%s__SupersedingClass' % (cls.__name__,) 645 646 @classmethod 647 def __AlternativeConstructorAttribute (cls): 648 return '_%s__AlternativeConstructor' % (cls.__name__,) 649 650 @classmethod 651 def _SupersedingClass (cls): 652 """Return the class stored in the class reference attribute.""" 653 return getattr(cls, cls.__SupersedingClassAttribute(), cls) 654 655 @classmethod 656 def _AlternativeConstructor (cls): 657 """Return the class stored in the class reference attribute.""" 658 rv = getattr(cls, cls.__AlternativeConstructorAttribute(), None) 659 if isinstance(rv, tuple): 660 rv = rv[0] 661 return rv 662 663 @classmethod 664 def _SetSupersedingClass (cls, superseding): 665 """Set the class reference attribute. 666 667 @param superseding: A Python class that is a subclass of this class. 668 """ 669 assert (superseding is None) or issubclass(superseding, cls) 670 if superseding is None: 671 cls.__dict__.pop(cls.__SupersedingClassAttribute(), None) 672 else: 673 setattr(cls, cls.__SupersedingClassAttribute(), superseding) 674 return superseding 675 676 @classmethod 677 def _SetAlternativeConstructor (cls, alternative_constructor): 678 attr = cls.__AlternativeConstructorAttribute() 679 if alternative_constructor is None: 680 cls.__dict__.pop(attr, None) 681 else: 682 # Need to use a tuple as the value: if you use an invokable, this 683 # ends up converting it from a function to an unbound method, 684 # which is not what we want. 685 setattr(cls, attr, (alternative_constructor,)) 686 assert cls._AlternativeConstructor() == alternative_constructor 687 return alternative_constructor 688 689 @classmethod 690 def _DynamicCreate (cls, *args, **kw): 691 """Invoke the constructor for this class or the one that supersedes it.""" 692 ctor = cls._AlternativeConstructor() 693 if ctor is None: 694 ctor = cls._SupersedingClass() 695 try: 696 return ctor(*args, **kw) 697 except TypeError: 698 raise pyxb.SimpleTypeValueError(ctor, args) 699 700class _RepresentAsXsdLiteral_mixin (pyxb.cscRoot): 701 """Marker class for data types using XSD literal string as pythonLiteral. 702 703 This is necessary for any simple data type where Python repr() produces a 704 constructor call involving a class that may not be available by that name; 705 e.g. duration, decimal, and any of the date/time types.""" 706 pass 707 708class _NoNullaryNonNillableNew_mixin (pyxb.cscRoot): 709 """Marker class indicating that a simple data type cannot construct 710 a value from XML through an empty string. 711 712 This class should appear immediately L{simpleTypeDefinition} (or whatever 713 inherits from L{simpleTypeDefinition} in cases where it applies.""" 714 pass 715 716class simpleTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin): 717 """L{simpleTypeDefinition} is a base class that is part of the 718 hierarchy of any class that represents the Python datatype for a 719 L{SimpleTypeDefinition<pyxb.xmlschema.structures.SimpleTypeDefinition>}. 720 721 @note: This class, or a descendent of it, must be the first class 722 in the method resolution order when a subclass has multiple 723 parents. Otherwise, constructor keyword arguments may not be 724 removed before passing them on to Python classes that do not 725 accept them. 726 """ 727 728 # A map from leaf classes in the facets module to instance of 729 # those classes that constrain or otherwise affect the datatype. 730 # Note that each descendent of simpleTypeDefinition has its own map. 731 __FacetMap = {} 732 733 _ReservedSymbols = _TypeBinding_mixin._ReservedSymbols.union(set([ 'XsdLiteral', 'xsdLiteral', 734 'XsdSuperType', 'XsdPythonType', 'XsdConstraintsOK', 735 'xsdConstraintsOK', 'XsdValueLength', 'xsdValueLength', 736 'PythonLiteral', 'pythonLiteral', 737 'SimpleTypeDefinition' ])) 738 """Symbols that remain the responsibility of this class. Any 739 public symbols in generated binding subclasses are deconflicted 740 by providing an alternative name in the subclass. (There 741 currently are no public symbols in generated SimpleTypeDefinion 742 bindings.""" 743 744 745 # Determine the name of the class-private facet map. For the base class 746 # this should produce the same attribute name as Python's privatization 747 # scheme. 748 __FacetMapAttributeNameMap = { } 749 @classmethod 750 def __FacetMapAttributeName (cls): 751 """ """ 752 ''' 753 if cls == simpleTypeDefinition: 754 return '_%s__FacetMap' % (cls.__name__.strip('_'),) 755 756 # It is not uncommon for a class in one namespace to extend a class of 757 # the same name in a different namespace, so encode the namespace URI 758 # in the attribute name (if it is part of a namespace). 759 ns_uri = '' 760 try: 761 ns_uri = cls._ExpandedName.namespaceURI() 762 except Exception: 763 pass 764 nm = '_' + utility.MakeIdentifier('%s_%s_FacetMap' % (ns_uri, cls.__name__.strip('_'))) 765 ''' 766 nm = cls.__FacetMapAttributeNameMap.get(cls) 767 if nm is None: 768 nm = cls.__name__ 769 if nm.endswith('_'): 770 nm += '1' 771 if cls == simpleTypeDefinition: 772 nm = '_%s__FacetMap' % (nm,) 773 else: 774 # It is not uncommon for a class in one namespace to extend a class of 775 # the same name in a different namespace, so encode the namespace URI 776 # in the attribute name (if it is part of a namespace). 777 ns_uri = '' 778 try: 779 ns_uri = cls._ExpandedName.namespaceURI() 780 except Exception: 781 pass 782 nm = '_' + utility.MakeIdentifier('%s_%s_FacetMap' % (ns_uri, nm)) 783 cls.__FacetMapAttributeNameMap[cls] = nm 784 return nm 785 786 @classmethod 787 def _FacetMap (cls): 788 """Return a reference to the facet map for this datatype. 789 790 The facet map is a map from leaf facet classes to instances of those 791 classes that constrain or otherwise apply to the lexical or value 792 space of the datatype. Classes may inherit their facet map from their 793 superclass, or may create a new class instance if the class adds a new 794 constraint type. 795 796 @raise AttributeError: if the facet map has not been defined""" 797 return getattr(cls, cls.__FacetMapAttributeName()) 798 799 @classmethod 800 def _InitializeFacetMap (cls, *args): 801 """Initialize the facet map for this datatype. 802 803 This must be called exactly once, after all facets belonging to the 804 datatype have been created. 805 806 @raise pyxb.LogicError: if called multiple times (on the same class) 807 @raise pyxb.LogicError: if called when a parent class facet map has not been initialized 808 :return: the facet map""" 809 fm = None 810 try: 811 fm = cls._FacetMap() 812 except AttributeError: 813 pass 814 if fm is not None: 815 raise pyxb.LogicError('%s facet map initialized multiple times: %s' % (cls.__name__, cls.__FacetMapAttributeName())) 816 817 # Search up the type hierarchy to find the nearest ancestor that has a 818 # facet map. This gets a bit tricky: if we hit the ceiling early 819 # because the PSTD hierarchy re-based itself on a new Python type, we 820 # have to jump to the XsdSuperType. 821 source_class = cls 822 while fm is None: 823 # Assume we're staying in this hierarchy. Include source_class in 824 # the candidates, since we might have jumped to it. 825 for super_class in source_class.mro(): 826 assert super_class is not None 827 if (super_class == simpleTypeDefinition): # and (source_class.XsdSuperType() is not None): 828 break 829 if issubclass(super_class, simpleTypeDefinition): 830 try: 831 fm = super_class._FacetMap() 832 break 833 except AttributeError: 834 pass 835 if fm is None: 836 try: 837 source_class = source_class.XsdSuperType() 838 except AttributeError: 839 source_class = None 840 if source_class is None: 841 fm = { } 842 if fm is None: 843 raise pyxb.LogicError('%s is not a child of simpleTypeDefinition' % (cls.__name__,)) 844 fm = fm.copy() 845 for facet in args: 846 fm[type(facet)] = facet 847 setattr(cls, cls.__FacetMapAttributeName(), fm) 848 return fm 849 850 @classmethod 851 def _ConvertArguments_vx (cls, args, kw): 852 return args 853 854 @classmethod 855 def _ConvertArguments (cls, args, kw): 856 """Pre-process the arguments. 857 858 This is used before invoking the parent constructor. One application 859 is to apply the whitespace facet processing; if such a request is in 860 the keywords, it is removed so it does not propagate to the 861 superclass. Another application is to convert the arguments from a 862 string to a list. Binding-specific applications are performed in the 863 overloaded L{_ConvertArguments_vx} method.""" 864 dom_node = kw.pop('_dom_node', None) 865 from_xml = kw.get('_from_xml', dom_node is not None) 866 if dom_node is not None: 867 text_content = domutils.ExtractTextContent(dom_node) 868 if text_content is not None: 869 args = (domutils.ExtractTextContent(dom_node),) + args 870 kw['_apply_whitespace_facet'] = True 871 apply_whitespace_facet = kw.pop('_apply_whitespace_facet', from_xml) 872 if (0 < len(args)) and isinstance(args[0], six.string_types) and apply_whitespace_facet: 873 cf_whitespace = getattr(cls, '_CF_whiteSpace', None) 874 if cf_whitespace is not None: 875 norm_str = six.text_type(cf_whitespace.normalizeString(args[0])) 876 args = (norm_str,) + args[1:] 877 kw['_from_xml'] = from_xml 878 return cls._ConvertArguments_vx(args, kw) 879 880 # Must override new, because new gets invoked before init, and usually 881 # doesn't accept keywords. In case it does (e.g., datetime.datetime), 882 # only remove the ones that would normally be interpreted by this class. 883 # Do the same argument conversion as is done in init. Trap errors and 884 # convert them to BadTypeValue errors. 885 # 886 # Note: We explicitly do not validate constraints here. That's 887 # done in the normal constructor; here, we might be in the process 888 # of building a value that eventually will be legal, but isn't 889 # yet. 890 def __new__ (cls, *args, **kw): 891 # PyXBFactoryKeywords 892 kw.pop('_validate_constraints', None) 893 kw.pop('_require_value', None) 894 kw.pop('_element', None) 895 kw.pop('_fallback_namespace', None) 896 kw.pop('_apply_attributes', None) 897 is_nil = kw.pop('_nil', None) 898 # ConvertArguments will remove _dom_node, _element, and 899 # _apply_whitespace_facet, and it will set _from_xml. 900 args = cls._ConvertArguments(args, kw) 901 from_xml = kw.pop('_from_xml', False) 902 if ((0 == len(args)) 903 and from_xml 904 and not is_nil 905 and issubclass(cls, _NoNullaryNonNillableNew_mixin)): 906 raise pyxb.SimpleTypeValueError(cls, args); 907 kw.pop('_location', None) 908 assert issubclass(cls, _TypeBinding_mixin) 909 try: 910 parent = super(simpleTypeDefinition, cls) 911 if parent.__new__ is object.__new__: 912 return parent.__new__(cls) 913 return parent.__new__(cls, *args, **kw) 914 except ValueError: 915 raise pyxb.SimpleTypeValueError(cls, args) 916 except OverflowError: 917 raise pyxb.SimpleTypeValueError(cls, args) 918 919 # Validate the constraints after invoking the parent constructor, 920 # unless told not to. 921 def __init__ (self, *args, **kw): 922 """Initialize a newly created STD instance. 923 924 Usually there is one positional argument, which is a value that can be 925 converted to the underlying Python type. 926 927 @keyword _validate_constraints: If True (default if validation is 928 enabled), the newly constructed value is checked against its 929 constraining facets. 930 @type _validate_constraints: C{bool} 931 932 @keyword _apply_attributes: If C{True} (default), any attributes 933 present in the keywords or DOM node are applied. Normally presence of 934 such an attribute should produce an error; when creating simple 935 content for a complex type we need the DOM node, but do not want to 936 apply the attributes, so we bypass the application. 937 """ 938 # PyXBFactoryKeywords 939 validate_constraints = kw.pop('_validate_constraints', self._validationConfig.forBinding) 940 require_value = kw.pop('_require_value', False) 941 # Save DOM node so we can pull attributes off it 942 dom_node = kw.get('_dom_node') 943 location = kw.get('_location') 944 if (location is None) and isinstance(dom_node, utility.Locatable_mixin): 945 location = dom_node._location() 946 apply_attributes = kw.pop('_apply_attributes', True) 947 # _ConvertArguments handles _dom_node and _apply_whitespace_facet 948 # TypeBinding_mixin handles _nil and _element 949 args = self._ConvertArguments(args, kw) 950 try: 951 super(simpleTypeDefinition, self).__init__(*args, **kw) 952 except OverflowError: 953 raise pyxb.SimpleTypeValueError(type(self), args) 954 if apply_attributes and (dom_node is not None): 955 self._setAttributesFromKeywordsAndDOM(kw, dom_node) 956 if require_value and (not self._constructedWithValue()): 957 if location is None: 958 location = self._location() 959 raise pyxb.SimpleContentAbsentError(self, location) 960 if validate_constraints and not kw.pop('_nil', False): 961 self.xsdConstraintsOK(location) 962 963 # The class attribute name used to store the reference to the STD 964 # component instance must be unique to the class, not to this base class. 965 # Otherwise we mistakenly believe we've already associated a STD instance 966 # with a class (e.g., xsd:normalizedString) when in fact it's associated 967 # with the superclass (e.g., xsd:string) 968 @classmethod 969 def __STDAttrName (cls): 970 return '_%s__SimpleTypeDefinition' % (cls.__name__,) 971 972 @classmethod 973 def _SimpleTypeDefinition (cls, std): 974 """Set the L{pyxb.xmlschema.structures.SimpleTypeDefinition} instance 975 associated with this binding.""" 976 attr_name = cls.__STDAttrName() 977 if hasattr(cls, attr_name): 978 old_value = getattr(cls, attr_name) 979 if old_value != std: 980 raise pyxb.LogicError('%s: Attempt to override existing STD %s with %s' % (cls, old_value.name(), std.name())) 981 setattr(cls, attr_name, std) 982 983 @classmethod 984 def SimpleTypeDefinition (cls): 985 """Return the SimpleTypeDefinition instance for the given 986 class. 987 988 This should only be invoked when generating bindings. An STD must 989 have been associated with the class using L{_SimpleTypeDefinition}.""" 990 attr_name = cls.__STDAttrName() 991 assert hasattr(cls, attr_name) 992 return getattr(cls, attr_name) 993 994 @classmethod 995 def XsdLiteral (cls, value): 996 """Convert from a python value to a string usable in an XML 997 document. 998 999 This should be implemented in the subclass.""" 1000 raise pyxb.LogicError('%s does not implement XsdLiteral' % (cls,)) 1001 1002 def xsdLiteral (self): 1003 """Return text suitable for representing the value of this 1004 instance in an XML document. 1005 1006 The base class implementation delegates to the object class's 1007 XsdLiteral method.""" 1008 if self._isNil(): 1009 return '' 1010 return self.XsdLiteral(self) 1011 1012 @classmethod 1013 def XsdSuperType (cls): 1014 """Find the nearest parent class in the PST hierarchy. 1015 1016 The value for anySimpleType is None; for all others, it's a 1017 primitive or derived PST descendent (including anySimpleType).""" 1018 for sc in cls.mro(): 1019 if sc == cls: 1020 continue 1021 if simpleTypeDefinition == sc: 1022 # If we hit the PST base, this is a primitive type or 1023 # otherwise directly descends from a Python type; return 1024 # the recorded XSD supertype. 1025 return cls._XsdBaseType 1026 if issubclass(sc, simpleTypeDefinition): 1027 return sc 1028 raise pyxb.LogicError('No supertype found for %s' % (cls,)) 1029 1030 @classmethod 1031 def _XsdConstraintsPreCheck_vb (cls, value): 1032 """Pre-extended class method to verify other things before 1033 checking constraints. 1034 1035 This is used for list types, to verify that the values in the 1036 list are acceptable, and for token descendents, to check the 1037 lexical/value space conformance of the input. 1038 """ 1039 super_fn = getattr(super(simpleTypeDefinition, cls), '_XsdConstraintsPreCheck_vb', lambda *a,**kw: value) 1040 return super_fn(value) 1041 1042 # Cache of pre-computed sequences of class facets in the order required 1043 # for constraint validation 1044 __ClassFacetSequence = { } 1045 1046 @classmethod 1047 def XsdConstraintsOK (cls, value, location=None): 1048 """Validate the given value against the constraints on this class. 1049 1050 @raise pyxb.SimpleTypeValueError: if any constraint is violated. 1051 """ 1052 1053 value = cls._XsdConstraintsPreCheck_vb(value) 1054 1055 facet_values = cls.__ClassFacetSequence.get(cls) 1056 if facet_values is None: 1057 # Constraints for simple type definitions are inherited. Check them 1058 # from least derived to most derived. 1059 classes = [ _x for _x in cls.mro() if issubclass(_x, simpleTypeDefinition) ] 1060 classes.reverse() 1061 cache_result = True 1062 facet_values = [] 1063 for clazz in classes: 1064 # When setting up the datatypes, if we attempt to validate 1065 # something before the facets have been initialized (e.g., a 1066 # nonNegativeInteger used as a length facet for the parent 1067 # integer datatype), just ignore that for now. Don't cache 1068 # the value, though, since a subsequent check after 1069 # initialization should succceed. 1070 try: 1071 clazz_facets = list(six.itervalues(clazz._FacetMap())) 1072 except AttributeError: 1073 cache_result = False 1074 clazz_facets = [] 1075 for v in clazz_facets: 1076 if not (v in facet_values): 1077 facet_values.append(v) 1078 if cache_result: 1079 cls.__ClassFacetSequence[cls] = facet_values 1080 for f in facet_values: 1081 if not f.validateConstraint(value): 1082 raise pyxb.SimpleFacetValueError(cls, value, f, location) 1083 return value 1084 1085 def xsdConstraintsOK (self, location=None): 1086 """Validate the value of this instance against its constraints.""" 1087 return self.XsdConstraintsOK(self, location) 1088 1089 def _validateBinding_vx (self): 1090 if not self._isNil(): 1091 self._checkValidValue() 1092 return True 1093 1094 @classmethod 1095 def XsdValueLength (cls, value): 1096 """Return the length of the given value. 1097 1098 The length is calculated by a subclass implementation of 1099 _XsdValueLength_vx in accordance with 1100 http://www.w3.org/TR/xmlschema-2/#rf-length. 1101 1102 The return value is a non-negative integer, or C{None} if length 1103 constraints should be considered trivially satisfied (as with 1104 QName and NOTATION). 1105 1106 @raise pyxb.LogicError: the provided value is not an instance of cls. 1107 @raise pyxb.LogicError: an attempt is made to calculate a length for 1108 an instance of a type that does not support length calculations. 1109 """ 1110 assert isinstance(value, cls) 1111 if not hasattr(cls, '_XsdValueLength_vx'): 1112 raise pyxb.LogicError('Class %s does not support length validation' % (cls.__name__,)) 1113 return cls._XsdValueLength_vx(value) 1114 1115 def xsdValueLength (self): 1116 """Return the length of this instance within its value space. 1117 1118 See XsdValueLength.""" 1119 return self.XsdValueLength(self) 1120 1121 @classmethod 1122 def PythonLiteral (cls, value): 1123 """Return a string which can be embedded into Python source to 1124 represent the given value as an instance of this class.""" 1125 class_name = cls.__name__ 1126 if issubclass(cls, _RepresentAsXsdLiteral_mixin): 1127 value = value.xsdLiteral() 1128 return '%s(%s)' % (class_name, pyxb.utils.utility.repr2to3(value)) 1129 1130 def pythonLiteral (self): 1131 """Return a string which can be embedded into Python source to 1132 represent the value of this instance.""" 1133 return self.PythonLiteral(self) 1134 1135 def _toDOM_csc (self, dom_support, parent): 1136 assert parent is not None 1137 dom_support.appendTextChild(self, parent) 1138 return getattr(super(simpleTypeDefinition, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent) 1139 1140 @classmethod 1141 def _IsSimpleTypeContent (cls): 1142 """STDs have simple type content.""" 1143 return True 1144 1145 @classmethod 1146 def _IsValidValue (self, value): 1147 try: 1148 self._CheckValidValue(value) 1149 return True 1150 except pyxb.PyXBException: 1151 pass 1152 return False 1153 1154 @classmethod 1155 def _CheckValidValue (cls, value): 1156 1157 """NB: Invoking this on a value that is a list will, if necessary, 1158 replace the members of the list with new values that are of the 1159 correct item type. This is permitted because only with lists is it 1160 possible to bypass the normal content validation (by invoking 1161 append/extend on the list instance).""" 1162 if value is None: 1163 raise pyxb.SimpleTypeValueError(cls, value) 1164 value_class = cls 1165 if issubclass(cls, STD_list): 1166 if not isinstance(value, collections.Iterable): 1167 raise pyxb.SimpleTypeValueError(cls, value) 1168 for v in value: 1169 if not cls._ItemType._IsValidValue(v): 1170 raise pyxb.SimpleListValueError(cls, v) 1171 else: 1172 if issubclass(cls, STD_union): 1173 value_class = None 1174 for mt in cls._MemberTypes: 1175 if mt._IsValidValue(value): 1176 value_class = mt 1177 break 1178 if value_class is None: 1179 raise pyxb.SimpleUnionValueError(cls, value) 1180 #if not (isinstance(value, value_class) or issubclass(value_class, type(value))): 1181 if not isinstance(value, value_class): 1182 raise pyxb.SimpleTypeValueError(cls, value) 1183 value_class.XsdConstraintsOK(value) 1184 1185 def _checkValidValue (self): 1186 self._CheckValidValue(self) 1187 1188 def _isValidValue (self): 1189 self._IsValidValue(self) 1190 1191 def _setAttribute (self, attr_en, value_lex): 1192 # Simple types have no attributes, but the parsing infrastructure 1193 # might invoke this to delegate responsibility for notifying the user 1194 # of the failure. 1195 raise pyxb.AttributeOnSimpleTypeError(self, attr_en, value_lex) 1196 1197 @classmethod 1198 def _description (cls, name_only=False, user_documentation=True): 1199 name = cls._Name() 1200 if name_only: 1201 return name 1202 desc = [ name, ' restriction of ', cls.XsdSuperType()._description(name_only=True) ] 1203 if user_documentation and (cls._Documentation is not None): 1204 desc.extend(["\n", cls._Documentation]) 1205 return ''.join(desc) 1206 1207class STD_union (simpleTypeDefinition): 1208 """Base class for union datatypes. 1209 1210 This class descends only from simpleTypeDefinition. A pyxb.LogicError is 1211 raised if an attempt is made to construct an instance of a subclass of 1212 STD_union. Values consistent with the member types are constructed using 1213 the Factory class method. Values are validated using the _ValidatedMember 1214 class method. 1215 1216 Subclasses must provide a class variable _MemberTypes which is a 1217 tuple of legal members of the union.""" 1218 1219 _MemberTypes = None 1220 """A list of classes which are permitted as values of the union.""" 1221 1222 # Ick: If we don't declare this here, this class's map doesn't get 1223 # initialized. Alternative is to not descend from simpleTypeDefinition. 1224 # @todo Ensure that pattern and enumeration are valid constraints 1225 __FacetMap = {} 1226 1227 @classmethod 1228 def Factory (cls, *args, **kw): 1229 """Given a value, attempt to create an instance of some member of this 1230 union. The first instance which can be legally created is returned. 1231 1232 @keyword _validate_constraints: If C{True} (default if validation is 1233 enabled), any constructed value is checked against constraints applied 1234 to the union as well as the member type. 1235 1236 @raise pyxb.SimpleTypeValueError: no member type will permit creation of 1237 an instance from the parameters in C{args} and C{kw}. 1238 """ 1239 1240 used_cls = cls._SupersedingClass() 1241 state = used_cls._PreFactory_vx(args, kw) 1242 1243 rv = None 1244 # NB: get, not pop: preserve it for the member type invocations 1245 validate_constraints = kw.get('_validate_constraints', cls._GetValidationConfig().forBinding) 1246 assert isinstance(validate_constraints, bool) 1247 if 0 < len(args): 1248 arg = args[0] 1249 try: 1250 rv = cls._ValidatedMember(arg) 1251 except pyxb.SimpleTypeValueError: 1252 pass 1253 if rv is None: 1254 kw['_validate_constraints'] = True 1255 for mt in cls._MemberTypes: 1256 try: 1257 rv = mt.Factory(*args, **kw) 1258 break 1259 except pyxb.SimpleTypeValueError: 1260 pass 1261 except (ValueError, OverflowError): 1262 pass 1263 except: 1264 pass 1265 location = None 1266 if kw is not None: 1267 location = kw.get('_location') 1268 if rv is not None: 1269 if validate_constraints: 1270 cls.XsdConstraintsOK(rv, location) 1271 rv._postFactory_vx(state) 1272 return rv 1273 # The constructor may take any number of arguments, so pass the whole thing. 1274 # Should we also provide the keywords? 1275 raise pyxb.SimpleUnionValueError(cls, args, location) 1276 1277 @classmethod 1278 def _ValidatedMember (cls, value): 1279 """Validate the given value as a potential union member. 1280 1281 @raise pyxb.SimpleTypeValueError: the value is not an instance of a 1282 member type.""" 1283 if not isinstance(value, cls._MemberTypes): 1284 for mt in cls._MemberTypes: 1285 try: 1286 # Force validation so we get the correct type, otherwise 1287 # first member will be accepted. 1288 value = mt.Factory(value, _validate_constraints=True) 1289 return value 1290 except (TypeError, pyxb.SimpleTypeValueError): 1291 pass 1292 raise pyxb.SimpleUnionValueError(cls, value) 1293 return value 1294 1295 def __new__ (self, *args, **kw): 1296 raise pyxb.LogicError('%s: cannot construct instances of union' % (self.__class__.__name__,)) 1297 1298 def __init__ (self, *args, **kw): 1299 raise pyxb.LogicError('%s: cannot construct instances of union' % (self.__class__.__name__,)) 1300 1301 @classmethod 1302 def _description (cls, name_only=False, user_documentation=True): 1303 name = cls._Name() 1304 if name_only: 1305 return name 1306 desc = [ name, ', union of '] 1307 desc.append(', '.join([ _td._description(name_only=True) for _td in cls._MemberTypes ])) 1308 return ''.join(desc) 1309 1310 @classmethod 1311 def XsdLiteral (cls, value): 1312 """Convert from a binding value to a string usable in an XML document.""" 1313 return cls._ValidatedMember(value).xsdLiteral() 1314 1315 1316class STD_list (simpleTypeDefinition, six.list_type): 1317 """Base class for collection datatypes. 1318 1319 This class descends from the Python list type, and incorporates 1320 simpleTypeDefinition. Subclasses must define a class variable _ItemType 1321 which is a reference to the class of which members must be instances.""" 1322 1323 _ItemType = None 1324 """A reference to the binding class for items within this list.""" 1325 1326 # Ick: If we don't declare this here, this class's map doesn't get 1327 # initialized. Alternative is to not descend from simpleTypeDefinition. 1328 __FacetMap = {} 1329 1330 @classmethod 1331 def _ValidatedItem (cls, value, kw=None): 1332 """Verify that the given value is permitted as an item of this list. 1333 1334 This may convert the value to the proper type, if it is 1335 compatible but not an instance of the item type. Returns the 1336 value that should be used as the item, or raises an exception 1337 if the value cannot be converted. 1338 1339 @param kw: optional dictionary of standard constructor keywords used 1340 when exceptions must be built. In particular, C{_location} may be 1341 useful. 1342 """ 1343 if isinstance(value, cls._ItemType): 1344 pass 1345 elif issubclass(cls._ItemType, STD_union): 1346 value = cls._ItemType._ValidatedMember(value) 1347 else: 1348 try: 1349 value = cls._ItemType(value) 1350 except (pyxb.SimpleTypeValueError, TypeError): 1351 location = None 1352 if kw is not None: 1353 location = kw.get('_location') 1354 raise pyxb.SimpleListValueError(cls, value, location) 1355 return value 1356 1357 @classmethod 1358 def _ConvertArguments_vx (cls, args, kw): 1359 # If the first argument is a string, split it on spaces and use the 1360 # resulting list of tokens. 1361 if 0 < len(args): 1362 arg1 = args[0] 1363 if isinstance(arg1, six.string_types): 1364 args = (arg1.split(),) + args[1:] 1365 arg1 = args[0] 1366 if isinstance(arg1, collections.Iterable): 1367 new_arg1 = [ cls._ValidatedItem(_v, kw) for _v in arg1 ] 1368 args = (new_arg1,) + args[1:] 1369 super_fn = getattr(super(STD_list, cls), '_ConvertArguments_vx', lambda *a,**kw: args) 1370 return super_fn(args, kw) 1371 1372 @classmethod 1373 def _XsdValueLength_vx (cls, value): 1374 return len(value) 1375 1376 @classmethod 1377 def XsdLiteral (cls, value): 1378 """Convert from a binding value to a string usable in an XML document.""" 1379 return ' '.join([ cls._ItemType.XsdLiteral(_v) for _v in value ]) 1380 1381 @classmethod 1382 def _description (cls, name_only=False, user_documentation=True): 1383 name = cls._Name() 1384 if name_only: 1385 return name 1386 desc = [ name, ', list of ', cls._ItemType._description(name_only=True) ] 1387 return ''.join(desc) 1388 1389 # Convert a single value to the required type, if not already an instance 1390 @classmethod 1391 def __ConvertOne (cls, v): 1392 return cls._ValidatedItem(v) 1393 1394 # Convert a sequence of values to the required type, if not already instances 1395 def __convertMany (self, values): 1396 return [ self._ValidatedItem(_v) for _v in values ] 1397 1398 def __setitem__ (self, key, value): 1399 if isinstance(key, slice): 1400 super(STD_list, self).__setitem__(key, self.__convertMany(value)) 1401 else: 1402 super(STD_list, self).__setitem__(key, self._ValidatedItem(value)) 1403 1404 if six.PY2: 1405 def __setslice__ (self, start, end, values): 1406 super(STD_list, self).__setslice__(start, end, self.__convertMany(values)) 1407 1408 def __contains__ (self, item): 1409 return super(STD_list, self).__contains__(self._ValidatedItem(item)) 1410 1411 # Standard mutable sequence methods, per Python Library Reference "Mutable Sequence Types" 1412 1413 def append (self, x): 1414 super(STD_list, self).append(self._ValidatedItem(x)) 1415 1416 def extend (self, x, _from_xml=False): 1417 super(STD_list, self).extend(self.__convertMany(x)) 1418 1419 def count (self, x): 1420 return super(STD_list, self).count(self._ValidatedItem(x)) 1421 1422 def index (self, x, *args): 1423 return super(STD_list, self).index(self._ValidatedItem(x), *args) 1424 1425 def insert (self, i, x): 1426 super(STD_list, self).insert(i, self._ValidatedItem(x)) 1427 1428 def remove (self, x): 1429 super(STD_list, self).remove(self._ValidatedItem(x)) 1430 1431class element (utility._DeconflictSymbols_mixin, _DynamicCreate_mixin): 1432 """Class that represents a schema element within a binding. 1433 1434 This gets a little confusing. Within a schema, the 1435 L{pyxb.xmlschema.structures.ElementDeclaration} type represents an 1436 U{element 1437 declaration<http://www.w3.org/TR/xmlschema-1/#cElement_Declarations>}. 1438 Those declarations may be global (have a name that is visible in the 1439 namespace), or local (have a name that is visible only within a complex 1440 type definition). Further, local (but not global) declarations may have a 1441 reference to a global declaration (which might be in a different 1442 namespace). 1443 1444 Within a PyXB binding, the element declarations from the original complex 1445 type definition that have the same 1446 U{QName<http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-qname>} 1447 (after deconflicting the 1448 U{LocalPart<http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-LocalPart>}) 1449 are associated with an attribute in the class for the complex type. Each 1450 of these attributes is defined via a 1451 L{pyxb.binding.content.ElementDeclaration} which provides the mechanism by 1452 which the binding holds values associated with that element. 1453 1454 Furthermore, in the FAC-based content model each schema element 1455 declaration is associated with an 1456 L{ElementUse<pyxb.binding.content.ElementUse>} instance to locate the 1457 point in the schema where content came from. Instances that refer to the 1458 same schema element declaration share the same underlying 1459 L{pyxb.binding.content.ElementDeclaration}. 1460 1461 This element isn't any of those elements. This element is the type used 1462 for an attribute which associates the name of a element with data required 1463 to represent it, all within a particular scope (a module for global scope, 1464 the binding class for a complex type definition for local scope). From 1465 the perspective of a PyXB user they look almost like a class, in that you 1466 can call them to create instances of the underlying complex type. 1467 1468 Global and local elements are represented by instances of this class. 1469 """ 1470 1471 def name (self): 1472 """The expanded name of the element within its scope.""" 1473 return self.__name 1474 __name = None 1475 1476 def typeDefinition (self): 1477 """The L{_TypeBinding_mixin} subclass for values of this element.""" 1478 return self.__typeDefinition._SupersedingClass() 1479 __typeDefinition = None 1480 1481 def xsdLocation (self): 1482 """The L{pyxb.utils.utility.Location} where the element appears in the schema.""" 1483 return self.__xsdLocation 1484 __xsdLocation = None 1485 1486 def scope (self): 1487 """The scope of the element. This is either C{None}, representing a 1488 top-level element, or an instance of C{complexTypeDefinition} for 1489 local elements.""" 1490 return self.__scope 1491 __scope = None 1492 1493 def nillable (self): 1494 """Indicate whether values matching this element can have U{nil 1495 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>} set.""" 1496 return self.__nillable 1497 __nillable = False 1498 1499 def abstract (self): 1500 """Indicate whether this element is abstract (must use substitution 1501 group members for matches).""" 1502 return self.__abstract 1503 __abstract = False 1504 1505 def documentation (self): 1506 """Contents of any documentation annotation in the definition.""" 1507 return self.__documentation 1508 __documentation = None 1509 1510 def defaultValue (self): 1511 """The default value of the element. 1512 1513 C{None} if the element has no default value. 1514 1515 @note: A non-C{None} value is always an instance of a simple type, 1516 even if the element has complex content.""" 1517 return self.__defaultValue 1518 __defaultValue = None 1519 1520 def fixed (self): 1521 """C{True} if the element content cannot be changed""" 1522 return self.__fixed 1523 __fixed = False 1524 1525 def substitutionGroup (self): 1526 """The L{element} instance to whose substitution group this element 1527 belongs. C{None} if this element is not part of a substitution 1528 group.""" 1529 return self.__substitutionGroup 1530 def _setSubstitutionGroup (self, substitution_group): 1531 self.__substitutionGroup = substitution_group 1532 if substitution_group is not None: 1533 self.substitutesFor = self._real_substitutesFor 1534 return self 1535 __substitutionGroup = None 1536 1537 def findSubstituendDecl (self, ctd_class): 1538 ed = ctd_class._ElementMap.get(self.name()) 1539 if ed is not None: 1540 return ed 1541 if self.substitutionGroup() is None: 1542 return None 1543 return self.substitutionGroup().findSubstituendDecl(ctd_class) 1544 1545 def _real_substitutesFor (self, other): 1546 """Determine whether an instance of this element can substitute for the other element. 1547 1548 See U{Substitution Group OK<http://www.w3.org/TR/xmlschema-1/#cos-equiv-derived-ok-rec>}. 1549 1550 @todo: Do something about blocking constraints. This ignores them, as 1551 does everything leading to this point. 1552 """ 1553 if self.substitutionGroup() is None: 1554 return False 1555 if other is None: 1556 return False 1557 assert isinstance(other, element) 1558 # On the first call, other is likely to be the local element. We need 1559 # the global one. 1560 if other.scope() is not None: 1561 other = other.name().elementBinding() 1562 if other is None: 1563 return False 1564 assert other.scope() is None 1565 # Do both these refer to the same (top-level) element? 1566 if self.name().elementBinding() == other: 1567 return True 1568 return (self.substitutionGroup() == other) or self.substitutionGroup().substitutesFor(other) 1569 1570 def substitutesFor (self, other): 1571 """Stub replaced by _real_substitutesFor when element supports substitution groups.""" 1572 return False 1573 1574 def memberElement (self, name): 1575 """Return a reference to the element instance used for the given name 1576 within this element. 1577 1578 The type for this element must be a complex type definition.""" 1579 return self.typeDefinition()._UseForTag(name).elementBinding() 1580 1581 def __init__ (self, name, type_definition, scope=None, nillable=False, abstract=False, unicode_default=None, fixed=False, substitution_group=None, documentation=None, location=None): 1582 """Create a new element binding. 1583 """ 1584 assert isinstance(name, pyxb.namespace.ExpandedName) 1585 self.__name = name 1586 self.__typeDefinition = type_definition 1587 self.__scope = scope 1588 self.__nillable = nillable 1589 self.__abstract = abstract 1590 if unicode_default is not None: 1591 # Override default None. If this is a complex type with simple 1592 # content, use the underlying simple type value. 1593 self.__defaultValue = self.__typeDefinition.Factory(unicode_default, _from_xml=True) 1594 if isinstance(self.__defaultValue, complexTypeDefinition): 1595 self.__defaultValue = self.__defaultValue.value() 1596 self.__fixed = fixed 1597 self.__substitutionGroup = substitution_group 1598 self.__documentation = documentation 1599 self.__xsdLocation = location 1600 super(element, self).__init__() 1601 1602 def __call__ (self, *args, **kw): 1603 """Invoke the Factory method on the type associated with this element. 1604 1605 @keyword _dom_node: This keyword is removed. If present, it must be C{None}. 1606 1607 @note: Other keywords are passed to L{_TypeBinding_mixin.Factory}. 1608 1609 @raise pyxb.AbstractElementError: This element is abstract and no DOM 1610 node was provided. 1611 """ 1612 dom_node = kw.pop('_dom_node', None) 1613 assert dom_node is None, 'Cannot pass DOM node directly to element constructor; use createFromDOM' 1614 if '_element' in kw: 1615 raise pyxb.LogicError('Cannot set _element in element-based instance creation') 1616 kw['_element'] = self 1617 # Can't create instances of abstract elements. 1618 if self.abstract(): 1619 location = kw.get('_location') 1620 if (location is None) and isinstance(dom_node, utility.Locatable_mixin): 1621 location = dom_node._location() 1622 raise pyxb.AbstractElementError(self, location, args) 1623 if self.__defaultValue is not None: 1624 if 0 == len(args): 1625 # No initial value; use the default 1626 args = [ self.__defaultValue ] 1627 elif self.__fixed: 1628 # Validate that the value is consistent with the fixed value 1629 if 1 < len(args): 1630 raise ValueError(*args) 1631 args = [ self.compatibleValue(args[0], **kw) ] 1632 rv = self.typeDefinition().Factory(*args, **kw) 1633 rv._setElement(self) 1634 return rv 1635 1636 def compatibleValue (self, value, **kw): 1637 """Return a variant of the value that is compatible with this element. 1638 1639 This mostly defers to L{_TypeBinding_mixin._CompatibleValue}. 1640 1641 @raise pyxb.SimpleTypeValueError: if the value is not both 1642 type-consistent and value-consistent with the element's type. 1643 """ 1644 # None is always None, unless there's a default. 1645 if value is None: 1646 return self.__defaultValue 1647 is_plural = kw.pop('is_plural', False) 1648 if is_plural: 1649 if not isinstance(value, collections.Iterable): 1650 raise pyxb.SimplePluralValueError(self.typeDefinition(), value) 1651 return [ self.compatibleValue(_v) for _v in value ] 1652 compValue = self.typeDefinition()._CompatibleValue(value, **kw); 1653 if self.__fixed and (compValue != self.__defaultValue): 1654 raise pyxb.ElementChangeError(self, value) 1655 if isinstance(value, _TypeBinding_mixin) and (value._element() is not None) and value._element().substitutesFor(self): 1656 return value 1657 if self.abstract(): 1658 location = None 1659 if isinstance(value, utility.Locatable_mixin): 1660 location = value._location() 1661 raise pyxb.AbstractElementError(self, location, value) 1662 return compValue 1663 1664 @classmethod 1665 def CreateDOMBinding (cls, node, element_binding, **kw): 1666 """Create a binding from a DOM node. 1667 1668 @param node: The DOM node 1669 1670 @param element_binding: An instance of L{element} that would normally 1671 be used to determine the type of the binding. The actual type of 1672 object returned is determined by the type definition associated with 1673 the C{element_binding} and the value of any U{xsi:type 1674 <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute found in 1675 C{node}, modulated by 1676 L{XSI._InterpretTypeAttribute<pyxb.namespace.builtin._XMLSchema_instance._InterpretTypeAttribute>}. 1677 1678 @keyword _fallback_namespace: The namespace to use as the namespace for 1679 the node, if the node name is unqualified. This should be an absent 1680 namespace. 1681 1682 @return: A binding for the DOM node. 1683 1684 @raises pyxb.UnrecognizedDOMRootNodeError: if no underlying element or 1685 type for the node can be identified. 1686 """ 1687 1688 if xml.dom.Node.ELEMENT_NODE != node.nodeType: 1689 raise ValueError('node is not an element') 1690 1691 fallback_namespace = kw.get('_fallback_namespace') 1692 1693 # Record the element to be associated with the created binding 1694 # instance. 1695 if '_element' in kw: 1696 raise pyxb.LogicError('Cannot set _element in element-based instance creation') 1697 1698 type_class = None 1699 if element_binding is not None: 1700 # Can't create instances of abstract elements. @todo: Is there any 1701 # way this could be legal given an xsi:type attribute? I'm pretty 1702 # sure "no"... 1703 if element_binding.abstract(): 1704 location = kw.get('location') 1705 if (location is None) and isinstance(node, utility.Locatable_mixin): 1706 location = node._location() 1707 raise pyxb.AbstractElementError(element_binding, location, node) 1708 kw['_element'] = element_binding 1709 type_class = element_binding.typeDefinition() 1710 1711 # Get the namespace context for the value being created. If none is 1712 # associated, one will be created. Do not make assumptions about the 1713 # namespace context; if the user cared, she should have assigned a 1714 # context before calling this. 1715 ns_ctx = pyxb.namespace.NamespaceContext.GetNodeContext(node) 1716 (did_replace, type_class) = XSI._InterpretTypeAttribute(XSI.type.getAttribute(node), ns_ctx, fallback_namespace, type_class) 1717 1718 if type_class is None: 1719 raise pyxb.UnrecognizedDOMRootNodeError(node) 1720 1721 # Pass xsi:nil on to the constructor regardless of whether the element 1722 # is nillable. Another sop to SOAP-encoding WSDL fans who don't 1723 # bother to provide valid schema for their message content. 1724 is_nil = XSI.nil.getAttribute(node) 1725 if is_nil is not None: 1726 kw['_nil'] = pyxb.binding.datatypes.boolean(is_nil) 1727 1728 try: 1729 pyxb.namespace.NamespaceContext.PushContext(ns_ctx) 1730 rv = type_class.Factory(_dom_node=node, **kw) 1731 finally: 1732 pyxb.namespace.NamespaceContext.PopContext() 1733 assert rv._element() == element_binding 1734 rv._setNamespaceContext(pyxb.namespace.NamespaceContext.GetNodeContext(node)) 1735 return rv._postDOMValidate() 1736 1737 # element 1738 @classmethod 1739 def AnyCreateFromDOM (cls, node, fallback_namespace): 1740 """Create an instance of an element from a DOM node. 1741 1742 This method does minimal processing of C{node} and delegates to 1743 L{CreateDOMBinding}. 1744 1745 @param node: An C{xml.dom.Node} representing a root element. If the 1746 node is a document, that document's root node will be substituted. 1747 The name of the node is extracted as the name of the element to be 1748 created, and the node and the name are passed to L{CreateDOMBinding}. 1749 1750 @param fallback_namespace: The value to pass as C{_fallback_namespace} 1751 to L{CreateDOMBinding} 1752 1753 @return: As with L{CreateDOMBinding}""" 1754 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1755 node = node.documentElement 1756 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=fallback_namespace) 1757 return cls.CreateDOMBinding(node, expanded_name.elementBinding(), _fallback_namespace=fallback_namespace) 1758 1759 def elementForName (self, name): 1760 """Return the element that should be used if this element binding is 1761 permitted and an element with the given name is encountered. 1762 1763 Normally, the incoming name matches the name of this binding, and 1764 C{self} is returned. If the incoming name is different, it is 1765 expected to be the name of a global element which is within this 1766 element's substitution group. In that case, the binding corresponding 1767 to the named element is return. 1768 1769 @return: An instance of L{element}, or C{None} if no element with the 1770 given name can be found. 1771 """ 1772 1773 # Name match means OK. 1774 if self.name() == name: 1775 return self 1776 # No name match means only hope is a substitution group, for which the 1777 # element must be top-level. 1778 top_elt = self.name().elementBinding() 1779 if top_elt is None: 1780 return None 1781 # Members of the substitution group must also be top-level. NB: If 1782 # named_elt == top_elt, then the adoptName call below improperly 1783 # associated the global namespace with a local element of the same 1784 # name; cf. test-namespace-uu:testBad. 1785 elt_en = top_elt.name().adoptName(name) 1786 assert 'elementBinding' in elt_en.namespace()._categoryMap(), 'No element bindings in %s' % (elt_en.namespace(),) 1787 named_elt = elt_en.elementBinding() 1788 if (named_elt is None) or (named_elt == top_elt): 1789 return None 1790 if named_elt.substitutesFor(top_elt): 1791 return named_elt 1792 return None 1793 1794 def createFromDOM (self, node, fallback_namespace=None, **kw): 1795 """Create an instance of this element using a DOM node as the source 1796 of its content. 1797 1798 This method does minimal processing of C{node} and delegates to 1799 L{_createFromDOM}. 1800 1801 @param node: An C{xml.dom.Node} representing a root element. If the 1802 node is a document, that document's root node will be substituted. 1803 The name of the node is extracted as the name of the element to be 1804 created, and the node and the name are passed to L{_createFromDOM} 1805 1806 @keyword fallback_namespace: Used as default for 1807 C{_fallback_namespace} in call to L{_createFromDOM} 1808 1809 @note: Keyword parameters are passed to L{CreateDOMBinding}. 1810 1811 @return: As with L{_createFromDOM} 1812 """ 1813 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1814 node = node.documentElement 1815 if fallback_namespace is not None: 1816 kw.setdefault('_fallback_namespace', fallback_namespace) 1817 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=fallback_namespace) 1818 return self._createFromDOM(node, expanded_name, **kw) 1819 1820 def _createFromDOM (self, node, expanded_name, **kw): 1821 """Create an instance from a DOM node given the name of an element. 1822 1823 This method does minimal processing of C{node} and C{expanded_name} 1824 and delegates to L{CreateDOMBinding}. 1825 1826 @param node: An C{xml.dom.Node} representing a root element. If the 1827 node is a document, that document's root node will be substituted. 1828 The value is passed to L{CreateDOMBinding}. 1829 1830 @param expanded_name: The expanded name of the element to be used for 1831 content. This is passed to L{elementForName} to obtain the binding 1832 that is passed to L{CreateDOMBinding}, superseding any identification 1833 that might be inferred from C{node}. If no name is available, use 1834 L{createFromDOM}. 1835 1836 @note: Keyword parameters are passed to L{CreateDOMBinding}. 1837 1838 @return: As with L{CreateDOMBinding}. 1839 """ 1840 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1841 node = node.documentElement 1842 return element.CreateDOMBinding(node, self.elementForName(expanded_name), **kw) 1843 1844 def __str__ (self): 1845 return 'Element %s' % (self.name(),) 1846 1847 def _description (self, name_only=False, user_documentation=True): 1848 name = six.text_type(self.name()) 1849 if name_only: 1850 return name 1851 desc = [ name, ' (', self.typeDefinition()._description(name_only=True), ')' ] 1852 if self.scope() is not None: 1853 desc.extend([', local to ', self.scope()._description(name_only=True) ]) 1854 if self.nillable(): 1855 desc.append(', nillable') 1856 if self.substitutionGroup() is not None: 1857 desc.extend([', substitutes for ', self.substitutionGroup()._description(name_only=True) ]) 1858 if user_documentation and (self.documentation() is not None): 1859 desc.extend(["\n", self.documentation() ]) 1860 return six.u('').join(desc) 1861 1862class enumeration_mixin (pyxb.cscRoot): 1863 """Marker in case we need to know that a PST has an enumeration constraint facet.""" 1864 1865 _ReservedSymbols = set([ 'itervalues', 'values', 'iteritems', 'items' ]) 1866 1867 @classmethod 1868 def itervalues (cls): 1869 """Return a generator for the values that the enumeration can take.""" 1870 return six.itervalues(cls._CF_enumeration) 1871 1872 @classmethod 1873 def values (cls): 1874 """Return a list of values that the enumeration can take.""" 1875 return list(cls.itervalues()) # nosix 1876 1877 @classmethod 1878 def iteritems (cls): 1879 """Generate the associated L{pyxb.binding.facet._EnumerationElement} instances.""" 1880 return six.iteritems(cls._CF_enumeration) 1881 1882 @classmethod 1883 def items (cls): 1884 """Return the associated L{pyxb.binding.facet._EnumerationElement} instances.""" 1885 return list(cls.iteritems()) # nosix 1886 1887 @classmethod 1888 def _elementForValue (cls, value): 1889 """Return the L{_EnumerationElement} instance that has the given value. 1890 1891 @raise KeyError: the value is not valid for the enumeration.""" 1892 return cls._CF_enumeration.elementForValue(value) 1893 1894 @classmethod 1895 def _valueForUnicode (cls, ustr): 1896 """Return the enumeration value corresponding to the given unicode string. 1897 1898 If ustr is not a valid option for this enumeration, return None.""" 1899 return cls._CF_enumeration.valueForUnicode(ustr) 1900 1901class _Content (object): 1902 """Base for any wrapper added to L{complexTypeDefinition.orderedContent}.""" 1903 1904 def __getValue (self): 1905 """The value of the content. 1906 1907 This is a unicode string for L{NonElementContent}, and (ideally) an 1908 instance of L{_TypeBinding_mixin} for L{ElementContent}.""" 1909 return self.__value 1910 __value = None 1911 value = property(__getValue) 1912 1913 @classmethod 1914 def ContentIterator (cls, input): 1915 """Return an iterator that filters and maps a sequence of L{_Content} 1916 instances. 1917 1918 The returned iterator will filter out sequence members that are not 1919 instances of the class from which the iterator was created. Further, 1920 only the L{value} field of the sequence member is returned. 1921 1922 Thus the catenated text of the non-element content of an instance can 1923 be obtained with:: 1924 1925 text = six.u('').join(NonElementContent.ContentIterator(instance.orderedContent())) 1926 1927 See also L{pyxb.NonElementContent} 1928 """ 1929 class _Iterator (six.Iterator): 1930 def __init__ (self, input): 1931 self.__input = iter(input) 1932 def __iter__ (self): 1933 return self 1934 def __next__ (self): 1935 while True: 1936 content = next(self.__input) 1937 if isinstance(content, cls): 1938 return content.value 1939 return _Iterator(input) 1940 1941 def __init__ (self, value): 1942 self.__value = value 1943 1944class ElementContent (_Content): 1945 """Marking wrapper for element content. 1946 1947 The value should be translated into XML and made a child of its parent.""" 1948 1949 def __getElementDeclaration (self): 1950 """The L{pyxb.binding.content.ElementDeclaration} associated with the element content. 1951 This may be C{None} if the value is a wildcard.""" 1952 return self.__elementDeclaration 1953 __elementDeclaration = None 1954 1955 elementDeclaration = property(__getElementDeclaration) 1956 1957 def __init__ (self, value, element_declaration=None, instance=None, tag=None): 1958 """Create a wrapper associating a value with its element declaration. 1959 1960 Normally the element declaration is determined by consulting the 1961 content model when creating a binding instance. When manipulating the 1962 preferred content list, this may be inconvenient to obtain; in that case 1963 provide the C{instance} in which the content appears immediately, 1964 along with the C{tag} that is used for the Python attribute that holds 1965 the element. 1966 1967 @param value: the value of the element. Should be an instance of 1968 L{_TypeBinding_mixin}, but for simple types might be a Python native 1969 type. 1970 1971 @keyword element_declaration: The 1972 L{pyxb.binding.content.ElementDeclaration} associated with the element 1973 value. Should be C{None} if the element matches wildcard content. 1974 1975 @keyword instance: Alternative path to providing C{element_declaration} 1976 @keyword tag: Alternative path to providing C{element_declaration} 1977 """ 1978 1979 import pyxb.binding.content 1980 super(ElementContent, self).__init__(value) 1981 if instance is not None: 1982 if not isinstance(instance, complexTypeDefinition): 1983 raise pyxb.UsageError('Unable to determine element declaration') 1984 element_declaration = instance._UseForTag(tag) 1985 assert (element_declaration is None) or isinstance(element_declaration, pyxb.binding.content.ElementDeclaration) 1986 self.__elementDeclaration = element_declaration 1987 1988class NonElementContent (_Content): 1989 """Marking wrapper for non-element content. 1990 1991 The value will be unicode text, and should be appended as character 1992 data.""" 1993 def __init__ (self, value): 1994 super(NonElementContent, self).__init__(six.text_type(value)) 1995 1996class complexTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin): 1997 """Base for any Python class that serves as the binding for an 1998 XMLSchema complexType. 1999 2000 Subclasses should define a class-level _AttributeMap variable which maps 2001 from the unicode tag of an attribute to the AttributeUse instance that 2002 defines it. Similarly, subclasses should define an _ElementMap variable. 2003 """ 2004 2005 _CT_EMPTY = 'EMPTY' #<<< No content 2006 _CT_SIMPLE = 'SIMPLE' #<<< Simple (character) content 2007 _CT_MIXED = 'MIXED' #<<< Children may be elements or other (e.g., character) content 2008 _CT_ELEMENT_ONLY = 'ELEMENT_ONLY' #<<< Expect only element content. 2009 2010 _ContentTypeTag = None 2011 2012 _TypeDefinition = None 2013 """Subclass of simpleTypeDefinition that corresponds to the type content. 2014 Only valid if _ContentTypeTag is _CT_SIMPLE""" 2015 2016 # A value that indicates whether the content model for this type supports 2017 # wildcard elements. Supporting classes should override this value. 2018 _HasWildcardElement = False 2019 2020 # Map from expanded names to ElementDeclaration instances 2021 _ElementMap = { } 2022 """Map from expanded names to ElementDeclaration instances.""" 2023 2024 # Per-instance map from tags to attribute values for wildcard attributes. 2025 # Value is C{None} if the type does not support wildcard attributes. 2026 __wildcardAttributeMap = None 2027 2028 def wildcardAttributeMap (self): 2029 """Obtain access to wildcard attributes. 2030 2031 The return value is C{None} if this type does not support wildcard 2032 attributes. If wildcard attributes are allowed, the return value is a 2033 map from QNames to the unicode string value of the corresponding 2034 attribute. 2035 2036 @todo: The map keys should be namespace extended names rather than 2037 QNames, as the in-scope namespace may not be readily available to the 2038 user. 2039 """ 2040 return self.__wildcardAttributeMap 2041 2042 # Per-instance list of DOM nodes interpreted as wildcard elements. 2043 # Value is None if the type does not support wildcard elements. 2044 __wildcardElements = None 2045 2046 def wildcardElements (self): 2047 """Obtain access to wildcard elements. 2048 2049 The return value is C{None} if the content model for this type does not 2050 support wildcard elements. If wildcard elements are allowed, the 2051 return value is a list of values corresponding to conformant 2052 unrecognized elements, in the order in which they were encountered. 2053 If the containing binding was created from an XML document and enough 2054 information was present to determine the binding of the member 2055 element, the value is a binding instance. Otherwise, the value is the 2056 original DOM Element node. 2057 """ 2058 return self.__wildcardElements 2059 2060 def __init__ (self, *args, **kw): 2061 """Create a new instance of this binding. 2062 2063 Arguments are used as transition values along the content model. 2064 Keywords are passed to the constructor of any simple content, or used 2065 to initialize attribute and element values whose L{id 2066 <content.ElementDeclaration.id>} (not L{name <content.ElementDeclaration.name>}) 2067 matches the keyword. 2068 2069 @keyword _dom_node: The node to use as the source of binding content. 2070 @type _dom_node: C{xml.dom.Element} 2071 2072 @keyword _location: An optional instance of 2073 L{pyxb.utils.utility.Location} showing the origin the binding. If 2074 C{None}, a value from C{_dom_node} is used if available. 2075 2076 @keyword _from_xml: See L{_TypeBinding_mixin.Factory} 2077 2078 @keyword _finalize_content_model: If C{True} the constructor invokes 2079 L{_TypeBinding_mixin._finalizeContentModel} prior to return. The 2080 value defaults to C{False} when content is assigned through keyword 2081 parameters (bypassing the content model) or neither a C{_dom_node} nor 2082 positional element parameters have been provided, and to C{True} in 2083 all other cases. 2084 """ 2085 2086 fallback_namespace = kw.pop('_fallback_namespace', None) 2087 is_nil = False 2088 dom_node = kw.pop('_dom_node', None) 2089 location = kw.pop('_location', None) 2090 from_xml = kw.pop('_from_xml', dom_node is not None) 2091 do_finalize_content_model = kw.pop('_finalize_content_model', None) 2092 if dom_node is not None: 2093 if (location is None) and isinstance(dom_node, pyxb.utils.utility.Locatable_mixin): 2094 location = dom_node._location() 2095 if xml.dom.Node.DOCUMENT_NODE == dom_node.nodeType: 2096 dom_node = dom_node.documentElement 2097 #kw['_validate_constraints'] = False 2098 is_nil = XSI.nil.getAttribute(dom_node) 2099 if is_nil is not None: 2100 is_nil = kw['_nil'] = pyxb.binding.datatypes.boolean(is_nil) 2101 if location is not None: 2102 self._setLocation(location) 2103 if self._AttributeWildcard is not None: 2104 self.__wildcardAttributeMap = { } 2105 if self._HasWildcardElement: 2106 self.__wildcardElements = [] 2107 if self._Abstract: 2108 raise pyxb.AbstractInstantiationError(type(self), location, dom_node) 2109 super(complexTypeDefinition, self).__init__(**kw) 2110 self.reset() 2111 self._setAttributesFromKeywordsAndDOM(kw, dom_node) 2112 did_set_kw_elt = False 2113 for fu in six.itervalues(self._ElementMap): 2114 iv = kw.pop(fu.id(), None) 2115 if iv is not None: 2116 did_set_kw_elt = True 2117 fu.set(self, iv) 2118 if do_finalize_content_model is None: 2119 do_finalize_content_model = not did_set_kw_elt 2120 if kw and kw.pop('_strict_keywords', True): 2121 [ kw.pop(_fkw, None) for _fkw in self._PyXBFactoryKeywords ] 2122 if kw: 2123 raise pyxb.UnprocessedKeywordContentError(self, kw) 2124 if 0 < len(args): 2125 if did_set_kw_elt: 2126 raise pyxb.UsageError('Cannot mix keyword and positional args for element initialization') 2127 self.extend(args, _from_xml=from_xml, _location=location) 2128 elif self._CT_SIMPLE == self._ContentTypeTag: 2129 value = self._TypeDefinition.Factory(_require_value=not self._isNil(), _dom_node=dom_node, _location=location, _nil=self._isNil(), _apply_attributes=False, *args) 2130 if value._constructedWithValue(): 2131 self.append(value) 2132 elif dom_node is not None: 2133 self.extend(dom_node.childNodes[:], fallback_namespace) 2134 else: 2135 do_finalize_content_model = False 2136 if do_finalize_content_model: 2137 self._finalizeContentModel() 2138 2139 # Specify the symbols to be reserved for all CTDs. 2140 _ReservedSymbols = _TypeBinding_mixin._ReservedSymbols.union(set([ 'wildcardElements', 'wildcardAttributeMap', 2141 'xsdConstraintsOK', 'content', 'orderedContent', 'append', 'extend', 'value', 'reset' ])) 2142 2143 # None, or a reference to a pyxb.utils.fac.Automaton instance that defines 2144 # the content model for the type. 2145 _Automaton = None 2146 2147 @classmethod 2148 def _AddElement (cls, element): 2149 """Method used by generated code to associate the element binding with a use in this type. 2150 2151 This is necessary because all complex type classes appear in the 2152 module prior to any of the element instances (which reference type 2153 classes), so the association must be formed after the element 2154 instances are available.""" 2155 return cls._UseForTag(element.name())._setElementBinding(element) 2156 2157 @classmethod 2158 def _UseForTag (cls, tag, raise_if_fail=True): 2159 """Return the ElementDeclaration object corresponding to the element name. 2160 2161 @param tag: The L{ExpandedName} of an element in the class.""" 2162 try: 2163 rv = cls._ElementMap[tag] 2164 except KeyError: 2165 if raise_if_fail: 2166 raise 2167 rv = None 2168 return rv 2169 2170 def __childrenForDOM (self): 2171 """Generate a list of children in the order in which they should be 2172 added to the parent when creating a DOM representation of this 2173 object. 2174 2175 @note: This is only used when L{pyxb.RequireValidWhenGenerating} has 2176 disabled validation. Consequently, it may not generate valid XML. 2177 """ 2178 order = [] 2179 for ed in six.itervalues(self._ElementMap): 2180 value = ed.value(self) 2181 if value is None: 2182 continue 2183 if isinstance(value, list) and ed.isPlural(): 2184 order.extend([ ElementContent(_v, ed) for _v in value ]) 2185 continue 2186 order.append(ElementContent(value, ed)) 2187 return order 2188 2189 def _validatedChildren (self): 2190 """Provide the child elements and non-element content in an order 2191 consistent with the content model. 2192 2193 Returns a sequence of tuples representing a valid path through the 2194 content model where each transition corresponds to one of the member 2195 element instances within this instance. The tuple is a pair 2196 comprising the L{content.ElementDeclaration} instance and the value for the 2197 transition. 2198 2199 If the content of the instance does not validate against the content 2200 model, an exception is raised. 2201 2202 @return: C{None} or a list as described above. 2203 """ 2204 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 2205 return [] 2206 self._resetAutomaton() 2207 return self.__automatonConfiguration.sequencedChildren() 2208 2209 def _symbolSet (self): 2210 """Return a map from L{content.ElementDeclaration} instances to a list of 2211 values associated with that use. 2212 2213 This is used as the set of symbols available for transitions when 2214 validating content against a model. Note that the original 2215 L{content.ElementUse} that may have validated the assignment of the 2216 symbol to the content is no longer available, which may result in a 2217 different order being generated by the content model. Preservation of 2218 the original order mitigates this risk. 2219 2220 The value C{None} is used to provide the wildcard members, if any. 2221 2222 If an element use has no associated values, it must not appear in the 2223 returned map. 2224 2225 @raise pyxb.SimpleTypeValueError: when unable to convert element 2226 content to the binding declaration type. 2227 """ 2228 rv = { } 2229 for eu in six.itervalues(self._ElementMap): 2230 value = eu.value(self) 2231 if value is None: 2232 continue 2233 converter = eu.elementBinding().compatibleValue 2234 if eu.isPlural(): 2235 if 0 < len(value): 2236 rv[eu] = [ converter(_v) for _v in value ] 2237 else: 2238 rv[eu] = [ converter(value)] 2239 wce = self.__wildcardElements 2240 if (wce is not None) and (0 < len(wce)): 2241 rv[None] = wce[:] 2242 return rv 2243 2244 def _validateAttributes (self): 2245 for au in six.itervalues(self._AttributeMap): 2246 au.validate(self) 2247 2248 def _validateBinding_vx (self): 2249 if self._isNil(): 2250 if (self._IsSimpleTypeContent() and (self.__content is not None)) or self.__content: 2251 raise pyxb.ContentInNilInstanceError(self, self.__content) 2252 return True 2253 if self._IsSimpleTypeContent() and (self.__content is None): 2254 raise pyxb.SimpleContentAbsentError(self, self._location()) 2255 order = self._validatedChildren() 2256 for content in order: 2257 if isinstance (content, NonElementContent): 2258 continue 2259 if isinstance(content.value, _TypeBinding_mixin): 2260 content.value.validateBinding() 2261 elif content.elementDeclaration is not None: 2262 _log.warning('Cannot validate value %s in field %s', content.value, content.elementDeclaration.id()) 2263 self._validateAttributes() 2264 return True 2265 2266 def _setAttribute (self, attr_en, value_lex): 2267 au = self._AttributeMap.get(attr_en) 2268 if au is None: 2269 if self._AttributeWildcard is None: 2270 raise pyxb.UnrecognizedAttributeError(type(self), attr_en, self) 2271 self.__wildcardAttributeMap[attr_en] = value_lex 2272 else: 2273 au.set(self, value_lex, from_xml=True) 2274 return au 2275 2276 def xsdConstraintsOK (self, location=None): 2277 """Validate the content against the simple type. 2278 2279 @return: C{True} if the content validates against its type. 2280 @raise pyxb.NotSimpleContentError: this type does not have simple content. 2281 @raise pyxb.SimpleContentAbsentError: the content of this type has not been set 2282 """ 2283 # @todo: type check 2284 if self._CT_SIMPLE != self._ContentTypeTag: 2285 raise pyxb.NotSimpleContentError(self) 2286 if self._isNil(): 2287 return True 2288 if self.__content is None: 2289 if location is None: 2290 location = self._location() 2291 raise pyxb.SimpleContentAbsentError(self, location) 2292 return self.value().xsdConstraintsOK(location) 2293 2294 # __content is used in two ways: when complex content is used, it is as 2295 # documented in L{orderedContent}. When simple content is used, it is as 2296 # documented in L{value}. 2297 __content = None 2298 2299 def orderedContent (self): 2300 """Return the element and non-element content of the instance in order. 2301 2302 This must be a complex type with complex content. The return value is 2303 a list of the element and non-element content in a preferred order. 2304 2305 The returned list contains L{element<ElementContent>} and 2306 L{non-element<NonElementContent>} content in the order which it was 2307 added to the instance. This may have been through parsing a document, 2308 constructing an instance using positional arguments, invoking the 2309 L{append} or L{extend} methods, or assigning directly to an instance 2310 attribute associated with an element binding. 2311 2312 @note: Be aware that assigning directly to an element attribute does not 2313 remove any previous value for the element from the content list. 2314 2315 @note: Be aware that element values directly appended to an instance 2316 attribute with list type (viz., that corresponds to an element that 2317 allows more than one occurrence) will not appear in the ordered 2318 content list. 2319 2320 The order in the list may influence the generation of documents 2321 depending on L{pyxb.ValidationConfig} values that apply to an 2322 instance. Non-element content is emitted immediately prior to the 2323 following element in this list. Any trailing non-element content is 2324 emitted after the last element in the content. The list should 2325 include all element content. Element content in this list that is not 2326 present within an element member of the binding instance may result in 2327 an error, or may be ignored. 2328 2329 @note: The returned value is mutable, allowing the caller to change 2330 the order to be used. 2331 2332 @raise pyxb.NotComplexContentError: this is not a complex type with mixed or element-only content 2333 """ 2334 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 2335 raise pyxb.NotComplexContentError(self) 2336 return self.__content 2337 2338 @classmethod 2339 def __WarnOnContent (cls): 2340 if cls.__NeedWarnOnContent: 2341 import traceback 2342 cls.__NeedWarnOnContent = False 2343 _log.warning('Deprecated complexTypeDefinition method "content" invoked\nPlease use "orderedContent"\n%s', ''.join(traceback.format_stack()[:-2])) 2344 pass 2345 __NeedWarnOnContent = True 2346 2347 def content (self): 2348 """Legacy interface for ordered content. 2349 2350 This version does not accurately distinguish non-element content from 2351 element content that happens to have unicode type. 2352 2353 @deprecated: use L{orderedContent}.""" 2354 self.__WarnOnContent() 2355 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 2356 raise pyxb.NotComplexContentError(self) 2357 return [ _v.value for _v in self.__content ] 2358 2359 def value (self): 2360 """Return the value of the element. 2361 2362 This must be a complex type with simple content. The returned value 2363 is expected to be an instance of some L{simpleTypeDefinition} class. 2364 2365 @raise pyxb.NotSimpleContentError: this is not a complex type with simple content 2366 """ 2367 if self._CT_SIMPLE != self._ContentTypeTag: 2368 raise pyxb.NotSimpleContentError(self) 2369 return self.__content 2370 2371 def _setValue (self, value): 2372 """Change the simple content value without affecting attributes.""" 2373 if self._CT_SIMPLE != self._ContentTypeTag: 2374 raise pyxb.NotSimpleContentError(self) 2375 location = self._location() 2376 if self._isNil(): 2377 if value is not None: 2378 raise pyxb.ContentInNilInstanceError(self, value, location) 2379 else: 2380 if not isinstance(value, self._TypeDefinition): 2381 value = self._TypeDefinition.Factory(value) 2382 self.__setContent(value) 2383 if self._validationConfig.forBinding: 2384 self.xsdConstraintsOK(location) 2385 return self 2386 2387 def _resetContent (self, reset_elements=False): 2388 if reset_elements: 2389 for eu in six.itervalues(self._ElementMap): 2390 eu.reset(self) 2391 nv = None 2392 if self._ContentTypeTag in (self._CT_MIXED, self._CT_ELEMENT_ONLY): 2393 nv = [] 2394 return self.__setContent(nv) 2395 2396 __automatonConfiguration = None 2397 def _resetAutomaton (self): 2398 if self._Automaton is not None: 2399 if self.__automatonConfiguration is None: 2400 import pyxb.binding.content 2401 self.__automatonConfiguration = pyxb.binding.content.AutomatonConfiguration(self) 2402 self.__automatonConfiguration.reset() 2403 return self.__automatonConfiguration 2404 2405 def _automatonConfiguration (self): 2406 """For whitebox testing use only""" 2407 return self.__automatonConfiguration 2408 2409 def reset (self): 2410 """Reset the instance. 2411 2412 This resets all element and attribute fields, and discards any 2413 recorded content. It resets the content model automaton to its 2414 initial state. 2415 2416 @see: Manipulate the return value of L{orderedContent} if your intent is 2417 to influence the generation of documents from the binding instance 2418 without changing its (element) content. 2419 """ 2420 2421 self._resetContent(reset_elements=True) 2422 for au in six.itervalues(self._AttributeMap): 2423 au.reset(self) 2424 self._resetAutomaton() 2425 return self 2426 2427 @classmethod 2428 def _ElementBindingDeclForName (cls, element_name): 2429 """Determine what the given name means as an element in this type. 2430 2431 Normally, C{element_name} identifies an element definition within this 2432 type. If so, the returned C{element_decl} identifies that definition, 2433 and the C{element_binding} is extracted from that use. 2434 2435 It may also be that the C{element_name} does not appear as an element 2436 definition, but that it identifies a global element. In that case, 2437 the returned C{element_binding} identifies the global element. If, 2438 further, that element is a member of a substitution group which does 2439 have an element definition in this class, then the returned 2440 C{element_decl} identifies that definition. 2441 2442 If a non-C{None} C{element_decl} is returned, there will be an 2443 associated C{element_binding}. However, it is possible to return a 2444 non-C{None} C{element_binding}, but C{None} as the C{element_decl}. In 2445 that case, the C{element_binding} can be used to create a binding 2446 instance, but the content model will have to treat it as a wildcard. 2447 2448 @param element_name: The name of the element in this type, either an 2449 expanded name or a local name if the element has an absent namespace. 2450 2451 @return: C{( element_binding, element_decl )} 2452 """ 2453 element_decl = cls._ElementMap.get(element_name) 2454 element_binding = None 2455 if element_decl is None: 2456 try: 2457 element_binding = element_name.elementBinding() 2458 except pyxb.NamespaceError: 2459 pass 2460 if element_binding is not None: 2461 element_decl = element_binding.findSubstituendDecl(cls) 2462 else: 2463 element_binding = element_decl.elementBinding() 2464 return (element_binding, element_decl) 2465 2466 def append (self, value, **kw): 2467 """Add the value to the instance. 2468 2469 The value should be a DOM node or other value that is or can be 2470 converted to a binding instance, or a string if the instance allows 2471 mixed content. The value must be permitted by the content model. 2472 2473 @raise pyxb.ContentValidationError: the value is not permitted at the current 2474 state of the content model. 2475 """ 2476 2477 # @todo: Allow caller to provide default element use; it's available 2478 # in saxer. 2479 element_decl = kw.get('_element_decl', None) 2480 maybe_element = kw.get('_maybe_element', True) 2481 location = kw.get('_location', None) 2482 if self._isNil(): 2483 raise pyxb.ContentInNilInstanceError(self, value, location) 2484 fallback_namespace = kw.get('_fallback_namespace', None) 2485 require_validation = kw.get('_require_validation', self._validationConfig.forBinding) 2486 from_xml = kw.get('_from_xml', False) 2487 element_binding = None 2488 if element_decl is not None: 2489 from pyxb.binding import content 2490 assert isinstance(element_decl, content.ElementDeclaration) 2491 element_binding = element_decl.elementBinding() 2492 assert element_binding is not None 2493 # Convert the value if it's XML and we recognize it. 2494 if isinstance(value, xml.dom.Node): 2495 from_xml = True 2496 assert maybe_element 2497 assert element_binding is None 2498 node = value 2499 require_validation = pyxb.GlobalValidationConfig.forBinding 2500 if xml.dom.Node.COMMENT_NODE == node.nodeType: 2501 # @todo: Note that we're allowing comments inside the bodies 2502 # of simple content elements, which isn't really Hoyle. 2503 return self 2504 if node.nodeType in (xml.dom.Node.TEXT_NODE, xml.dom.Node.CDATA_SECTION_NODE): 2505 value = node.data 2506 maybe_element = False 2507 else: 2508 # Do type conversion here 2509 assert xml.dom.Node.ELEMENT_NODE == node.nodeType 2510 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=fallback_namespace) 2511 (element_binding, element_decl) = self._ElementBindingDeclForName(expanded_name) 2512 if element_binding is not None: 2513 # If we have an element binding, we need to use it because 2514 # it knows how to resolve substitution groups. 2515 value = element_binding._createFromDOM(node, expanded_name, _fallback_namespace=fallback_namespace) 2516 else: 2517 # If we don't have an element binding, we might still be 2518 # able to convert this if it has an xsi:type attribute 2519 # that names a valid type. 2520 xsi_type = XSI.type.getAttribute(node) 2521 try_create = False 2522 if xsi_type is not None: 2523 ns_ctx = pyxb.namespace.NamespaceContext.GetNodeContext(node) 2524 (try_create, type_class) = XSI._InterpretTypeAttribute(xsi_type, ns_ctx, fallback_namespace, None) 2525 if try_create: 2526 value = element.CreateDOMBinding(node, None, _fallback_namespace=fallback_namespace) 2527 else: 2528 _log.warning('Unable to convert DOM node %s at %s to binding', expanded_name, getattr(node, 'location', '[UNAVAILABLE]')) 2529 if (not maybe_element) and isinstance(value, six.string_types) and (self._ContentTypeTag in (self._CT_EMPTY, self._CT_ELEMENT_ONLY)): 2530 if (0 == len(value.strip())) and not self._isNil(): 2531 return self 2532 if maybe_element and (self.__automatonConfiguration is not None): 2533 # Allows element content. 2534 if not require_validation: 2535 if element_decl is not None: 2536 element_decl.setOrAppend(self, value) 2537 return self 2538 if self.__wildcardElements is not None: 2539 self._appendWildcardElement(value) 2540 return self 2541 raise pyxb.StructuralBadDocumentError(container=self, content=value) 2542 # Attempt to place the value based on the content model 2543 num_cand = self.__automatonConfiguration.step(value, element_decl) 2544 if 1 <= num_cand: 2545 # Resolution was successful (possibly non-deterministic) 2546 return self 2547 # We couldn't place this thing. If it's element content, it has 2548 # to be placed. Is it element content? 2549 # 2550 # If it's bound to an element, it's element content. 2551 # 2552 # Complex type instance? Element content. 2553 # 2554 # Uninterpretable DOM nodes or binding wrappers? Element content. 2555 # 2556 # Simple type definition? Well, if the thing we're trying to fill 2557 # accepts mixed content or has simple content, technically we 2558 # could convert the value to text and use it. So that's not 2559 # element content. 2560 if ((element_binding is not None) 2561 or isinstance(value, (xml.dom.Node, complexTypeDefinition, pyxb.BIND)) 2562 or (isinstance(value, simpleTypeDefinition) and not (self._IsSimpleTypeContent() or self._IsMixed()))): 2563 # Element content. If it has an automaton we can provide more 2564 # information. If it doesn't, it must consume text and we should 2565 # use a different exception. 2566 if self.__automatonConfiguration: 2567 raise pyxb.UnrecognizedContentError(self, self.__automatonConfiguration, value, location) 2568 raise pyxb.NonElementValidationError(value, location) 2569 2570 # We have something that doesn't seem to be an element. Are we 2571 # expecting simple content? 2572 if self._IsSimpleTypeContent(): 2573 if self.__content is not None: 2574 raise pyxb.ExtraSimpleContentError(self, value) 2575 if not self._isNil(): 2576 if not isinstance(value, self._TypeDefinition): 2577 value = self._TypeDefinition.Factory(value, _from_xml=from_xml) 2578 self.__setContent(value) 2579 if require_validation: 2580 # NB: This only validates the value, not any associated 2581 # attributes, which is correct to be parallel to complex 2582 # content validation. 2583 self.xsdConstraintsOK(location) 2584 return self 2585 2586 # Do we allow non-element content? 2587 if not self._IsMixed(): 2588 raise pyxb.MixedContentError(self, value, location) 2589 2590 # It's character information. 2591 self._addContent(NonElementContent(value)) 2592 return self 2593 2594 def _appendWildcardElement (self, value): 2595 if (isinstance(value, xml.dom.Node) 2596 or (isinstance(value, _TypeBinding_mixin) and (value._element is not None))): 2597 # Something that we can interpret as an element 2598 self._addContent(ElementContent(value, None)) 2599 self.__wildcardElements.append(value) 2600 elif self._IsMixed(): 2601 # Not an element, but allowed as mixed content 2602 self._addContent(NonElementContent(value)) 2603 else: 2604 # Not an element and no mixed content allowed: error 2605 raise pyxb.MixedContentError(self, value) 2606 2607 def extend (self, value_list, _fallback_namespace=None, _from_xml=False, _location=None): 2608 """Invoke L{append} for each value in the list, in turn.""" 2609 kw = { '_fallback_namespace': _fallback_namespace, 2610 '_from_xml': _from_xml, 2611 '_location': _location } 2612 [ self.append(_v, **kw) for _v in value_list ] 2613 return self 2614 2615 def __setContent (self, value): 2616 self.__content = value 2617 return self.__content 2618 2619 def _addContent (self, wrapped_value): 2620 # This assert is inadequate in the case of plural/non-plural elements with an STD_list base type. 2621 # Trust that validation elsewhere was done correctly. 2622 #assert self._IsMixed() or (not self._performValidation()) or isinstance(child, _TypeBinding_mixin) or isinstance(child, six.string_types), 'Unrecognized child %s type %s' % (child, type(child)) 2623 assert not (self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE)) 2624 assert isinstance(wrapped_value, _Content) 2625 self.__content.append(wrapped_value) 2626 if isinstance(wrapped_value, ElementContent): 2627 value = wrapped_value.value 2628 ed = wrapped_value.elementDeclaration 2629 if isinstance(value, _TypeBinding_mixin) and (ed is not None) and (value._element() is None): 2630 assert isinstance(ed.elementBinding(), element) 2631 value._setElement(ed.elementBinding()) 2632 2633 @classmethod 2634 def _IsMixed (cls): 2635 return (cls._CT_MIXED == cls._ContentTypeTag) 2636 2637 def _finalizeContentModel (self): 2638 # Override parent implementation. 2639 if self.__automatonConfiguration: 2640 self.__automatonConfiguration.resolveNondeterminism() 2641 2642 def _postDOMValidate (self): 2643 # It's probably finalized already, but just in case... 2644 self._finalizeContentModel() 2645 if self._validationConfig.forBinding: 2646 # @todo isNil should verify that no content is present. 2647 if (not self._isNil()) and (self.__automatonConfiguration is not None): 2648 if not self.__automatonConfiguration.isAccepting(): 2649 if self._IsSimpleTypeContent(): 2650 raise pyxb.SimpleContentAbsentError(self, self._location()) 2651 self.__automatonConfiguration.diagnoseIncompleteContent() 2652 self._validateAttributes() 2653 return self 2654 2655 def _setDOMFromAttributes (self, dom_support, element): 2656 """Add any appropriate attributes from this instance into the DOM element.""" 2657 for au in six.itervalues(self._AttributeMap): 2658 if pyxb.GlobalValidationConfig.forDocument: 2659 au.validate(self) 2660 au.addDOMAttribute(dom_support, self, element) 2661 if self.__wildcardAttributeMap: 2662 for (an, av) in six.iteritems(self.__wildcardAttributeMap): 2663 dom_support.addAttribute(element, an, av) 2664 return element 2665 2666 def _toDOM_csc (self, dom_support, parent): 2667 """Create a DOM element with the given tag holding the content of this instance.""" 2668 element = parent 2669 self._setDOMFromAttributes(dom_support, element) 2670 if self._isNil(): 2671 pass 2672 elif self._CT_EMPTY == self._ContentTypeTag: 2673 pass 2674 elif self._CT_SIMPLE == self._ContentTypeTag: 2675 if self.__content is None: 2676 raise pyxb.SimpleContentAbsentError(self, self._location()) 2677 dom_support.appendTextChild(self.value(), element) 2678 else: 2679 if pyxb.GlobalValidationConfig.forDocument: 2680 order = self._validatedChildren() 2681 else: 2682 order = self.__childrenForDOM() 2683 for content in order: 2684 assert id(content.value) != id(self) 2685 if isinstance(content, NonElementContent): 2686 dom_support.appendTextChild(content.value, element) 2687 continue 2688 if content.elementDeclaration is None: 2689 if isinstance(content.value, xml.dom.Node): 2690 dom_support.appendChild(content.value, element) 2691 else: 2692 content.value.toDOM(dom_support, parent) 2693 else: 2694 content.elementDeclaration.toDOM(dom_support, parent, content.value) 2695 mixed_content = self.orderedContent() 2696 for mc in mixed_content: 2697 pass 2698 return getattr(super(complexTypeDefinition, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent) 2699 2700 @classmethod 2701 def _IsSimpleTypeContent (cls): 2702 """CTDs with simple content are simple; other CTDs are not.""" 2703 return cls._CT_SIMPLE == cls._ContentTypeTag 2704 2705 @classmethod 2706 def _description (cls, name_only=False, user_documentation=True): 2707 name = cls._Name() 2708 if name_only: 2709 return name 2710 desc = [ name ] 2711 if cls._CT_EMPTY == cls._ContentTypeTag: 2712 desc.append(', empty content') 2713 elif cls._CT_SIMPLE == cls._ContentTypeTag: 2714 desc.extend([', simple content type ', cls._TypeDefinition._description(name_only=True)]) 2715 else: 2716 if cls._CT_MIXED == cls._ContentTypeTag: 2717 desc.append(', mixed content') 2718 else: 2719 assert cls._CT_ELEMENT_ONLY == cls._ContentTypeTag 2720 desc.append(', element-only content') 2721 if (0 < len(cls._AttributeMap)) or (cls._AttributeWildcard is not None): 2722 desc.append("\nAttributes:\n ") 2723 desc.append("\n ".join([ _au._description(user_documentation=False) for _au in six.itervalues(cls._AttributeMap) ])) 2724 if cls._AttributeWildcard is not None: 2725 desc.append("\n Wildcard attribute(s)") 2726 if (0 < len(cls._ElementMap)) or cls._HasWildcardElement: 2727 desc.append("\nElements:\n ") 2728 desc.append("\n ".join([ _eu._description(user_documentation=False) for _eu in six.itervalues(cls._ElementMap) ])) 2729 if cls._HasWildcardElement: 2730 desc.append("\n Wildcard element(s)") 2731 return ''.join(desc) 2732 2733## Local Variables: 2734## fill-column:78 2735## End: 2736