Package pyxb :: Package binding :: Module basis
[hide private]
[frames] | no frames]

Source Code for Module pyxb.binding.basis

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