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

Source Code for Module pyxb.binding.basis

   1  # Copyright 2009-2012, Peter A. Bigot 
   2  # 
   3  # Licensed under the Apache License, Version 2.0 (the "License"); you may 
   4  # not use this file except in compliance with the License. You may obtain a 
   5  # copy of the License at: 
   6  # 
   7  #            http://www.apache.org/licenses/LICENSE-2.0 
   8  # 
   9  # Unless required by applicable law or agreed to in writing, software 
  10  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
  11  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
  12  # License for the specific language governing permissions and limitations 
  13  # under the License. 
  14   
  15  """This module contains support classes from which schema-specific bindings 
  16  inherit, and that describe the content models of those schema.""" 
  17   
  18  import pyxb 
  19  import xml.dom 
  20  import pyxb.utils.domutils as domutils 
  21  import pyxb.utils.utility as utility 
  22  import types 
  23  import pyxb.namespace 
  24  from pyxb.namespace.builtin import XMLSchema_instance as XSI 
  25   
  26  BINDING_STYLE_ACCESSOR = 'accessor' 
  27  BINDING_STYLE_PROPERTY = 'property' 
  28   
  29  BINDING_STYLES = (BINDING_STYLE_ACCESSOR, BINDING_STYLE_PROPERTY) 
  30  DEFAULT_BINDING_STYLE = BINDING_STYLE_PROPERTY 
  31  CURRENT_BINDING_STYLE = None 
32 33 -def ConfigureBindingStyle (style):
34 global CURRENT_BINDING_STYLE 35 simpleTypeDefinition._ConfigureBindingStyle(style) 36 complexTypeDefinition._ConfigureBindingStyle(style) 37 CURRENT_BINDING_STYLE = style
38
39 -class _TypeBinding_mixin (utility.Locatable_mixin):
40 41 @classmethod
42 - def _PerformValidation (cls):
43 """Determine whether the content model should be validated. 44 45 Proper validation is not yet supported in PyXB. The low level binding 46 material consults this function, but not always in a context where the 47 direction of translation is clear. Conseequently, this method 48 indicates that validation should be performed only when both 49 generation and parsing validation are enabled.""" 50 # return True 51 return pyxb._GenerationRequiresValid and pyxb._ParsingRequiresValid
52 53 _ExpandedName = None 54 """The expanded name of the component.""" 55 56 _ReservedSymbols = set([ 'validateBinding', 'toDOM', 'toxml', 'Factory', 'property' ]) 57 58 if pyxb._CorruptionDetectionEnabled:
59 - def __setattr__ (self, name, value):
60 if name in self._ReservedSymbols: 61 raise pyxb.BindingError('Attempt to set reserved name %s in instance of %s' % (name, type(self))) 62 return super(_TypeBinding_mixin, self).__setattr__(name, value)
63 64 # @todo: We don't actually use this anymore; get rid of it, just leaving a 65 # comment describing each keyword. 66 _PyXBFactoryKeywords = ( '_dom_node', '_fallback_namespace', '_from_xml', 67 '_apply_whitespace_facet', '_validate_constraints', 68 '_require_value', '_nil', '_element', 69 '_convert_string_values' ) 70 """Keywords that are interpreted by __new__ or __init__ in one or more 71 classes in the PyXB type hierarchy. All these keywords must be removed 72 before invoking base Python __init__ or __new__.""" 73 74 # While simple type definitions cannot be abstract, they can appear in 75 # many places where complex types can, so we want it to be legal to test 76 # for abstractness without checking whether the object is a complex type. 77 _Abstract = False 78
79 - def _namespaceContext (self):
80 """Return a L{namespace context <pyxb.binding.NamespaceContext>} 81 associated with the binding instance. 82 83 This will return C{None} unless something has provided a context to 84 the instance. Context is provided when instances are generated by the 85 DOM and SAX-based translators.""" 86 return self.__namespaceContext
87 - def _setNamespaceContext (self, namespace_context):
88 """Associate a L{namespace context <pyxb.binding.NamespaceContext>} 89 with the binding instance.""" 90 self.__namespaceContext = namespace_context 91 return self
92 __namespaceContext = None 93
94 - def _setElement (self, element):
95 """Associate a L{pyxb.binding.basis.element} with the instance.""" 96 self.__element = element 97 return self
98 - def _element (self):
99 """Return a L{pyxb.binding.basis.element} associated with the binding 100 instance. 101 102 This will return C{None} unless an element has been associated. 103 Constructing a binding instance using the element instance will add 104 this association. 105 """ 106 return self.__element
107 __element = None 108 109 __xsiNil = None
110 - def _isNil (self):
111 """Indicate whether this instance is U{nil 112 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>}. 113 114 The value is set by the DOM and SAX parsers when building an instance 115 from a DOM element with U{xsi:nil 116 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>} set to C{true}. 117 118 @return: C{None} if the element used to create the instance is not 119 U{nillable<http://www.w3.org/TR/xmlschema-1/#nillable>}. 120 If it is nillable, returns C{True} or C{False} depending on 121 whether the instance itself is U{nil<http://www.w3.org/TR/xmlschema-1/#xsi_nil>}. 122 """ 123 return self.__xsiNil
124 - def _setIsNil (self):
125 """Set the xsi:nil property of the instance. 126 127 @raise pyxb.NoNillableSupportError: the instance is not associated 128 with an element that is L{nillable 129 <pyxb.binding.basis.element.nillable>}. 130 """ 131 if self.__xsiNil is None: 132 raise pyxb.NoNillableSupportError(type(self)) 133 self.__xsiNil = True 134 self._resetContent()
135
136 - def _resetContent (self):
137 pass
138 139 __constructedWithValue = False
140 - def __checkNilCtor (self, args):
141 self.__constructedWithValue = (0 < len(args)) 142 if self.__xsiNil: 143 if self.__constructedWithValue: 144 raise pyxb.ContentInNilElementError(args[0]) 145 else: 146 # Types that descend from string will, when constructed from an 147 # element with empty content, appear to have no constructor value, 148 # while in fact an empty string should have been passed. 149 if issubclass(type(self), basestring): 150 self.__constructedWithValue = True
151 - def _constructedWithValue (self):
152 return self.__constructedWithValue
153 154 # Flag used to control whether we print a warning when creating a complex 155 # type instance that does not have an associated element. Not sure yet 156 # whether that'll be common practice or common error. 157 __WarnedUnassociatedElement = False 158
159 - def __init__ (self, *args, **kw):
160 # Strip keyword not used above this level. 161 element = kw.pop('_element', None) 162 is_nil = kw.pop('_nil', False) 163 super(_TypeBinding_mixin, self).__init__(*args, **kw) 164 if (element is None) or element.nillable(): 165 self.__xsiNil = is_nil 166 self.__checkNilCtor(args) 167 if element is not None: 168 self._setElement(element)
169 170 @classmethod
171 - def _PreFactory_vx (cls, args, kw):
172 """Method invoked upon entry to the Factory method. 173 174 This method is entitled to modify the keywords array. It can also 175 return a state value which is passed to _postFactory_vx.""" 176 return None
177
178 - def _postFactory_vx (cls, state):
179 """Method invoked prior to leaving the Factory method. 180 181 This is an instance method, and is given the state that was returned 182 by _PreFactory_vx.""" 183 return None
184 185 @classmethod
186 - def Factory (cls, *args, **kw):
187 """Provide a common mechanism to create new instances of this type. 188 189 The class constructor won't do, because you can't create 190 instances of union types. 191 192 This method may be overridden in subclasses (like STD_union). Pre- 193 and post-creation actions can be customized on a per-class instance by 194 overriding the L{_PreFactory_vx} and L{_postFactory_vx} methods. 195 196 @keyword _dom_node: If provided, the value must be a DOM node, the 197 content of which will be used to set the value of the instance. 198 199 @keyword _from_xml: If C{True}, the input must be either a DOM node or 200 a unicode string comprising a lexical representation of a value. This 201 is a further control on C{_apply_whitespace_facet} and arises from 202 cases where the lexical and value representations cannot be 203 distinguished by type. The default value is C{True} iff C{_dom_node} 204 is not C{None}. 205 206 @keyword _apply_whitespace_facet: If C{True} and this is a 207 simpleTypeDefinition with a whiteSpace facet, the first argument will 208 be normalized in accordance with that facet prior to invoking the 209 parent constructor. 210 211 @keyword _validate_constraints: If C{True}, any constructed value is 212 checked against constraints applied to the union as well as the member 213 type. 214 215 @keyword _require_value: If C{False} (default), it is permitted to 216 create a value without an initial value. If C{True} and no initial 217 value was provided, causes L{pyxb.MissingContentError} to be raised. 218 Only applies to simpleTypeDefinition instances; this is used when 219 creating values from DOM nodes. 220 """ 221 # Invoke _PreFactory_vx for the superseding class, which is where 222 # customizations will be found. 223 dom_node = kw.get('_dom_node') 224 kw.setdefault('_from_xml', dom_node is not None) 225 used_cls = cls._SupersedingClass() 226 state = used_cls._PreFactory_vx(args, kw) 227 rv = cls._DynamicCreate(*args, **kw) 228 rv._postFactory_vx(state) 229 if isinstance(dom_node, utility.Locatable_mixin): 230 rv._setLocation(dom_node.location) 231 return rv
232
233 - def _substitutesFor (self, element):
234 if (element is None) or (self._element() is None): 235 return False 236 return self._element().substitutesFor(element)
237 238 @classmethod
239 - def _IsUrType (cls):
240 """Return C{True} iff this is the ur-type. 241 242 The only ur-type is {http://www.w3.org/2001/XMLSchema}anyType. The 243 implementation of this method is overridden for 244 L{pyxb.binding.datatypes.anyType}.""" 245 return False
246 247 @classmethod
248 - def _RequireXSIType (cls, value_type):
249 if cls._IsUrType(): 250 # Require xsi:type if value refines xs:anyType 251 return value_type != cls 252 return cls._Abstract and value_type != cls._SupersedingClass()
253 254 @classmethod
255 - def _CompatibleValue (cls, value, **kw):
256 """Return a variant of the value that is compatible with this type. 257 258 Compatibility is defined relative to the type definition associated 259 with the element. The value C{None} is always compatible. If 260 C{value} has a Python type (e.g., C{int}) that is a superclass of the 261 required L{_TypeBinding_mixin} class (e.g., C{xs:byte}), C{value} is 262 used as a constructor parameter to return a new instance of the 263 required type. Note that constraining facets are applied here if 264 necessary (e.g., although a Python C{int} with value C{500} is 265 type-compatible with C{xs:byte}, it is outside the value space, and 266 compatibility will fail. 267 268 @keyword _convert_string_values: If C{True} (default) and the incoming value is 269 a string, an attempt will be made to form a compatible value by using 270 the string as a constructor argument to the this class. This flag is 271 set to C{False} when testing automaton transitions. 272 273 @raise pyxb.BadTypeValueError: if the value is not both 274 type-consistent and value-consistent with the element's type. 275 """ 276 convert_string_values = kw.get('_convert_string_values', True) 277 # None is always None 278 if value is None: 279 return None 280 # Already an instance? 281 if isinstance(value, cls): 282 # @todo: Consider whether we should change the associated _element 283 # of this value. (**Consider** it, don't just do it.) 284 return value 285 value_type = type(value) 286 # All string-based PyXB binding types use unicode, not str 287 if str == value_type: 288 value_type = unicode 289 290 # See if we got passed a Python value which needs to be "downcasted" 291 # to the _TypeBinding_mixin version. 292 if issubclass(cls, value_type): 293 return cls(value) 294 295 # See if we have a numeric type that needs to be cast across the 296 # numeric hierarchy. int to long is the *only* conversion we accept. 297 if isinstance(value, int) and issubclass(cls, long): 298 return cls(value) 299 300 # Same, but for boolean, which Python won't let us subclass 301 if isinstance(value, bool) and issubclass(cls, pyxb.binding.datatypes.boolean): 302 return cls(value) 303 304 # See if we have convert_string_values on, and have a string type that 305 # somebody understands. 306 if convert_string_values and (unicode == value_type): 307 return cls(value) 308 309 # Maybe this is a union? 310 if issubclass(cls, STD_union): 311 for mt in cls._MemberTypes: 312 try: 313 return mt._CompatibleValue(value, **kw) 314 except: 315 pass 316 317 # Any type is compatible with the corresponding ur-type 318 if (pyxb.binding.datatypes.anySimpleType == cls) and issubclass(value_type, simpleTypeDefinition): 319 return value 320 if pyxb.binding.datatypes.anyType == cls: 321 if not isinstance(value, _TypeBinding_mixin): 322 print 'NOTE: Created %s instance from value of type %s' % (cls._ExpandedName, type(value)) 323 value = cls(value) 324 return value 325 326 # Is this the wrapper class that indicates we should create a binding 327 # from arguments? 328 if isinstance(value, pyxb.BIND): 329 return value.createInstance(cls.Factory, **kw) 330 331 # There may be other things that can be converted to the desired type, 332 # but we can't tell that from the type hierarchy. Too many of those 333 # things result in an undesirable loss of information: for example, 334 # when an all model supports both numeric and string transitions, the 335 # candidate is a number, and the string transition is tested first. 336 raise pyxb.BadTypeValueError('No conversion from %s to %s' % (value_type, cls))
337 338 @classmethod
339 - def _IsSimpleTypeContent (cls):
340 """Return True iff the content of this binding object is a simple type. 341 342 This is true only for descendents of simpleTypeDefinition and instances 343 of complexTypeDefinition that have simple type content.""" 344 raise pyxb.LogicError('Failed to override _TypeBinding_mixin._IsSimpleTypeContent')
345 346 # If the type supports wildcard attributes, this describes their 347 # constraints. (If it doesn't, this should remain None.) Supporting 348 # classes should override this value. 349 _AttributeWildcard = None 350 351 _AttributeMap = { } 352 """Map from expanded names to AttributeUse instances. Non-empty only in 353 L{complexTypeDefinition} subclasses.""" 354 355 @classmethod
356 - def __AttributesFromDOM (cls, node):
357 attribute_settings = { } 358 for ai in range(0, node.attributes.length): 359 attr = node.attributes.item(ai) 360 # NB: Specifically do not consider attr's NamespaceContext, since 361 # attributes do not accept a default namespace. 362 attr_en = pyxb.namespace.ExpandedName(attr) 363 364 # Ignore xmlns and xsi attributes; we've already handled those 365 if attr_en.namespace() in ( pyxb.namespace.XMLNamespaces, XSI ): 366 continue 367 368 value = attr.value 369 au = cls._AttributeMap.get(attr_en) 370 if au is None: 371 if cls._AttributeWildcard is None: 372 raise pyxb.UnrecognizedAttributeError('Attribute %s is not permitted in type %s' % (attr_en, cls._ExpandedName)) 373 attribute_settings[attr_en] = value 374 return attribute_settings
375
376 - def _setAttributesFromKeywordsAndDOM (self, kw, dom_node):
377 """Invoke self._setAttribute based on node attributes and keywords. 378 379 Though attributes can only legally appear in complexTypeDefinition 380 instances, delayed conditional validation requires caching them in 381 simpleTypeDefinition. 382 383 @param kw: keywords passed to the constructor. This map is mutated by 384 the call: keywords corresponding to recognized attributes are removed. 385 386 @param dom_node: an xml.dom Node instance, possibly C{None} 387 """ 388 389 # Extract keywords that match field names 390 attribute_settings = { } 391 if dom_node is not None: 392 attribute_settings.update(self.__AttributesFromDOM(dom_node)) 393 for fu in self._AttributeMap.values(): 394 iv = kw.pop(fu.id(), None) 395 if iv is not None: 396 attribute_settings[fu.name()] = iv 397 for (attr_en, value) in attribute_settings.items(): 398 au = self._setAttribute(attr_en, value)
399
400 - def toDOM (self, bds=None, parent=None, element_name=None):
401 """Convert this instance to a DOM node. 402 403 The name of the top-level element is either the name of the L{element} 404 instance associated with this instance, or the XML name of the type of 405 this instance. 406 407 @param bds: Support for customizing the generated document 408 @type bds: L{pyxb.utils.domutils.BindingDOMSupport} 409 @param parent: If C{None}, a standalone document is created; 410 otherwise, the created element is a child of the given element. 411 @type parent: C{xml.dom.Element} or C{None} 412 @rtype: C{xml.dom.Document} 413 """ 414 415 if bds is None: 416 bds = domutils.BindingDOMSupport() 417 need_xsi_type = bds.requireXSIType() 418 if isinstance(element_name, (str, unicode)): 419 element_name = pyxb.namespace.ExpandedName(bds.defaultNamespace(), element_name) 420 if (element_name is None) and (self._element() is not None): 421 element_binding = self._element() 422 element_name = element_binding.name() 423 need_xsi_type = need_xsi_type or element_binding.typeDefinition()._RequireXSIType(type(self)) 424 if element_name is None: 425 element_name = self._ExpandedName 426 element = bds.createChildElement(element_name, parent) 427 if need_xsi_type: 428 val_type_qname = self._ExpandedName.localName() 429 tns_prefix = bds.namespacePrefix(self._ExpandedName.namespace()) 430 if tns_prefix is not None: 431 val_type_qname = '%s:%s' % (tns_prefix, val_type_qname) 432 bds.addAttribute(element, XSI.type, val_type_qname) 433 self._toDOM_csc(bds, element) 434 bds.finalize() 435 return bds.document()
436
437 - def toxml (self, encoding=None, bds=None, root_only=False):
438 """Shorthand to get the object as an XML document. 439 440 If you want to set the default namespace, pass in a pre-configured 441 C{bds}. 442 443 @param encoding: The encoding to be used. See 444 @C{xml.dom.Node.toxml()} for a description of why you should always 445 pass @C{'utf-8'} here. Because this method follows the contract of 446 the corresponding C{xml.dom.Node} method, it does not automatically 447 get the default PyXB output encoding. 448 449 @param bds: Optional L{pyxb.utils.domutils.BindingDOMSupport} instance 450 to use for creation. If not provided (default), a new generic one is 451 created. 452 """ 453 dom = self.toDOM(bds) 454 if root_only: 455 dom = dom.documentElement 456 return dom.toxml(encoding)
457
458 - def _toDOM_csc (self, dom_support, parent):
459 assert parent is not None 460 if self.__xsiNil: 461 dom_support.addAttribute(parent, XSI.nil, 'true') 462 return getattr(super(_TypeBinding_mixin, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent)
463
464 - def _validateBinding_vx (self):
465 """Override in subclasses for type-specific validation of instance 466 content. 467 468 @return: C{True} if the instance validates 469 @raise pyxb.BindingValidationError: complex content does not match model 470 @raise pyxb.BadTypeValueError: simple content fails to satisfy constraints 471 """ 472 raise pyxb.IncompleteImplementationError('%s did not override _validateBinding_vx' % (type(self),))
473
474 - def validateBinding (self):
475 """Check whether the binding content matches its content model. 476 477 @return: C{True} if validation succeeds. 478 @raise pyxb.BindingValidationError: complex content does not match model 479 @raise pyxb.BadTypeValueError: simple content fails to satisfy constraints 480 """ 481 if self._PerformValidation(): 482 self._validateBinding_vx() 483 return True
484
485 - def _postDOMValidate (self):
486 self.validateBinding() 487 return self
488 489 @classmethod
490 - def _Name (cls):
491 if cls._ExpandedName is not None: 492 name = str(cls._ExpandedName) 493 else: 494 name = str(type(cls)) 495 return name
496
497 -class _DynamicCreate_mixin (pyxb.cscRoot):
498 """Helper to allow overriding the implementation class. 499 500 Generally we'll want to augment the generated bindings by subclassing 501 them, and adding functionality to the subclass. This mix-in provides a 502 way to communicate the existence of the superseding subclass back to the 503 binding infrastructure, so that when it creates an instance it uses the 504 subclass rather than the unaugmented binding class. 505 506 When a raw generated binding is subclassed, L{_SetSupersedingClass} should be 507 invoked on the raw class passing in the superseding subclass. E.g.:: 508 509 class mywsdl (raw.wsdl): 510 pass 511 raw.wsdl._SetSupersedingClass(mywsdl) 512 513 """ 514 515 @classmethod
517 return '_%s__SupersedingClass' % (cls.__name__,)
518 519 @classmethod
521 return '_%s__AlternativeConstructor' % (cls.__name__,)
522 523 @classmethod
524 - def _SupersedingClass (cls):
525 """Return the class stored in the class reference attribute.""" 526 return getattr(cls, cls.__SupersedingClassAttribute(), cls)
527 528 @classmethod
529 - def _AlternativeConstructor (cls):
530 """Return the class stored in the class reference attribute.""" 531 rv = getattr(cls, cls.__AlternativeConstructorAttribute(), None) 532 if isinstance(rv, tuple): 533 rv = rv[0] 534 return rv
535 536 @classmethod
537 - def _SetSupersedingClass (cls, superseding):
538 """Set the class reference attribute. 539 540 @param superseding: A Python class that is a subclass of this class. 541 """ 542 assert (superseding is None) or issubclass(superseding, cls) 543 if superseding is None: 544 cls.__dict__.pop(cls.__SupersedingClassAttribute(), None) 545 else: 546 setattr(cls, cls.__SupersedingClassAttribute(), superseding) 547 return superseding
548 549 @classmethod
550 - def _SetAlternativeConstructor (cls, alternative_constructor):
551 attr = cls.__AlternativeConstructorAttribute() 552 if alternative_constructor is None: 553 cls.__dict__.pop(attr, None) 554 else: 555 # Need to use a tuple as the value: if you use an invokable, this 556 # ends up converting it from a function to an unbound method, 557 # which is not what we want. 558 setattr(cls, attr, (alternative_constructor,)) 559 assert cls._AlternativeConstructor() == alternative_constructor 560 return alternative_constructor
561 562 @classmethod
563 - def _DynamicCreate (cls, *args, **kw):
564 """Invoke the constructor for this class or the one that supersedes it.""" 565 ctor = cls._AlternativeConstructor() 566 if ctor is None: 567 ctor = cls._SupersedingClass() 568 try: 569 return ctor(*args, **kw) 570 except TypeError, e: 571 #import traceback 572 #traceback.print_exc() 573 raise pyxb.BadTypeValueError(e)
574
575 -class simpleTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin):
576 """L{simpleTypeDefinition} is a base class that is part of the 577 hierarchy of any class that represents the Python datatype for a 578 L{SimpleTypeDefinition<pyxb.xmlschema.structures.SimpleTypeDefinition>}. 579 580 @note: This class, or a descendent of it, must be the first class 581 in the method resolution order when a subclass has multiple 582 parents. Otherwise, constructor keyword arguments may not be 583 removed before passing them on to Python classes that do not 584 accept them. 585 """ 586 587 # A map from leaf classes in the facets module to instance of 588 # those classes that constrain or otherwise affect the datatype. 589 # Note that each descendent of simpleTypeDefinition has its own map. 590 __FacetMap = {} 591 592 _ReservedSymbols = _TypeBinding_mixin._ReservedSymbols.union(set([ 'XsdLiteral', 'xsdLiteral', 593 'XsdSuperType', 'XsdPythonType', 'XsdConstraintsOK', 594 'xsdConstraintsOK', 'XsdValueLength', 'xsdValueLength', 595 'PythonLiteral', 'pythonLiteral', 596 'SimpleTypeDefinition' ])) 597 """Symbols that remain the responsibility of this class. Any 598 public symbols in generated binding subclasses are deconflicted 599 by providing an alternative name in the subclass. (There 600 currently are no public symbols in generated SimpleTypeDefinion 601 bindings.""" 602 603 604 @classmethod
605 - def _ConfigureBindingStyle (cls, style):
606 if BINDING_STYLE_PROPERTY == style: 607 pass 608 elif BINDING_STYLE_ACCESSOR == style: 609 pass 610 else: 611 raise pyxb.LogicError('Unrecognized binding style %s' % (style,))
612 613 # Determine the name of the class-private facet map. For the base class 614 # this should produce the same attribute name as Python's privatization 615 # scheme. 616 __FacetMapAttributeNameMap = { } 617 @classmethod
618 - def __FacetMapAttributeName (cls):
619 """ """ 620 ''' 621 if cls == simpleTypeDefinition: 622 return '_%s__FacetMap' % (cls.__name__.strip('_'),) 623 624 # It is not uncommon for a class in one namespace to extend a class of 625 # the same name in a different namespace, so encode the namespace URI 626 # in the attribute name (if it is part of a namespace). 627 ns_uri = '' 628 try: 629 ns_uri = cls._ExpandedName.namespaceURI() 630 except Exception, e: 631 pass 632 nm = '_' + utility.MakeIdentifier('%s_%s_FacetMap' % (ns_uri, cls.__name__.strip('_'))) 633 ''' 634 nm = cls.__FacetMapAttributeNameMap.get(cls) 635 if nm is None: 636 nm = cls.__name__ 637 if nm.endswith('_'): 638 nm += '1' 639 if cls == simpleTypeDefinition: 640 nm = '_%s__FacetMap' % (nm,) 641 else: 642 # It is not uncommon for a class in one namespace to extend a class of 643 # the same name in a different namespace, so encode the namespace URI 644 # in the attribute name (if it is part of a namespace). 645 ns_uri = '' 646 try: 647 ns_uri = cls._ExpandedName.namespaceURI() 648 except Exception, e: 649 pass 650 nm = '_' + utility.MakeIdentifier('%s_%s_FacetMap' % (ns_uri, nm)) 651 cls.__FacetMapAttributeNameMap[cls] = nm 652 return nm
653 654 @classmethod
655 - def _FacetMap (cls):
656 """Return a reference to the facet map for this datatype. 657 658 The facet map is a map from leaf facet classes to instances of those 659 classes that constrain or otherwise apply to the lexical or value 660 space of the datatype. Classes may inherit their facet map from their 661 superclass, or may create a new class instance if the class adds a new 662 constraint type. 663 664 :raise AttributeError: if the facet map has not been defined""" 665 return getattr(cls, cls.__FacetMapAttributeName())
666 667 @classmethod
668 - def _InitializeFacetMap (cls, *args):
669 """Initialize the facet map for this datatype. 670 671 This must be called exactly once, after all facets belonging to the 672 datatype have been created. 673 674 :raise pyxb.LogicError: if called multiple times (on the same class) 675 :raise pyxb.LogicError: if called when a parent class facet map has not been initialized 676 :return: the facet map""" 677 fm = None 678 try: 679 fm = cls._FacetMap() 680 except AttributeError: 681 pass 682 if fm is not None: 683 raise pyxb.LogicError('%s facet map initialized multiple times: %s' % (cls.__name__, cls.__FacetMapAttributeName())) 684 685 # Search up the type hierarchy to find the nearest ancestor that has a 686 # facet map. This gets a bit tricky: if we hit the ceiling early 687 # because the PSTD hierarchy re-based itself on a new Python type, we 688 # have to jump to the XsdSuperType. 689 source_class = cls 690 while fm is None: 691 # Assume we're staying in this hierarchy. Include source_class in 692 # the candidates, since we might have jumped to it. 693 for super_class in source_class.mro(): 694 #print 'Superclass for %s is %s' % (source_class, super_class) 695 assert super_class is not None 696 if (super_class == simpleTypeDefinition): # and (source_class.XsdSuperType() is not None): 697 break 698 if issubclass(super_class, simpleTypeDefinition): 699 try: 700 fm = super_class._FacetMap() 701 #print 'Selected facet map for %s from %s: %s' % (cls, super_class, fm) 702 break 703 except AttributeError: 704 pass 705 if fm is None: 706 try: 707 source_class = source_class.XsdSuperType() 708 except AttributeError: 709 source_class = None 710 #print 'Nothing acceptable found, jumped to %s' % (source_class,) 711 if source_class is None: 712 fm = { } 713 #print 'Done with set' 714 if fm is None: 715 raise pyxb.LogicError('%s is not a child of simpleTypeDefinition' % (cls.__name__,)) 716 fm = fm.copy() 717 #print 'Augmenting %s map had %d elts with %d from args' % (cls, len(fm), len(args)) 718 for facet in args: 719 fm[type(facet)] = facet 720 #for (fc, fi) in fm.items(): 721 # print ' %s : %s' % (fc, fi) 722 setattr(cls, cls.__FacetMapAttributeName(), fm) 723 return fm
724 725 @classmethod
726 - def _ConvertArguments_vx (cls, args, kw):
727 return args
728 729 @classmethod
730 - def _ConvertArguments (cls, args, kw):
731 """Pre-process the arguments. 732 733 This is used before invoking the parent constructor. One application 734 is to apply the whitespace facet processing; if such a request is in 735 the keywords, it is removed so it does not propagate to the 736 superclass. Another application is to convert the arguments from a 737 string to a list. Binding-specific applications are performed in the 738 overloaded L{_ConvertArguments_vx} method.""" 739 dom_node = kw.pop('_dom_node', None) 740 from_xml = kw.get('_from_xml', dom_node is not None) 741 if dom_node is not None: 742 text_content = domutils.ExtractTextContent(dom_node) 743 if text_content is not None: 744 args = (domutils.ExtractTextContent(dom_node),) + args 745 kw['_apply_whitespace_facet'] = True 746 apply_whitespace_facet = kw.pop('_apply_whitespace_facet', from_xml) 747 if (0 < len(args)) and isinstance(args[0], types.StringTypes) and apply_whitespace_facet: 748 cf_whitespace = getattr(cls, '_CF_whiteSpace', None) 749 if cf_whitespace is not None: 750 #print 'Apply whitespace %s to "%s"' % (cf_whitespace, args[0]) 751 norm_str = unicode(cf_whitespace.normalizeString(args[0])) 752 args = (norm_str,) + args[1:] 753 kw['_from_xml'] = from_xml 754 return cls._ConvertArguments_vx(args, kw)
755 756 # Must override new, because new gets invoked before init, and usually 757 # doesn't accept keywords. In case it does (e.g., datetime.datetime), 758 # only remove the ones that would normally be interpreted by this class. 759 # Do the same argument conversion as is done in init. Trap errors and 760 # convert them to BadTypeValue errors. 761 # 762 # Note: We explicitly do not validate constraints here. That's 763 # done in the normal constructor; here, we might be in the process 764 # of building a value that eventually will be legal, but isn't 765 # yet.
766 - def __new__ (cls, *args, **kw):
767 # PyXBFactoryKeywords 768 kw.pop('_validate_constraints', None) 769 kw.pop('_require_value', None) 770 kw.pop('_element', None) 771 kw.pop('_fallback_namespace', None) 772 kw.pop('_nil', None) 773 # ConvertArguments will remove _element and _apply_whitespace_facet 774 dom_node = kw.get('_dom_node') 775 args = cls._ConvertArguments(args, kw) 776 kw.pop('_from_xml', dom_node is not None) 777 assert issubclass(cls, _TypeBinding_mixin) 778 try: 779 rv = super(simpleTypeDefinition, cls).__new__(cls, *args, **kw) 780 rv._setAttributesFromKeywordsAndDOM(kw, dom_node) 781 return rv 782 except ValueError, e: 783 raise pyxb.BadTypeValueError(e) 784 except OverflowError, e: 785 raise pyxb.BadTypeValueError(e)
786 787 # Validate the constraints after invoking the parent constructor, 788 # unless told not to.
789 - def __init__ (self, *args, **kw):
790 """Initialize a newly created STD instance. 791 792 Usually there is one positional argument, which is a value that can be 793 converted to the underlying Python type. 794 795 @keyword _validate_constraints: If True (default), the newly 796 constructed value is checked against its constraining facets. 797 @type _validate_constraints: C{bool} 798 """ 799 # PyXBFactoryKeywords 800 validate_constraints = kw.pop('_validate_constraints', self._PerformValidation()) 801 require_value = kw.pop('_require_value', False) 802 # _ConvertArguments handles _dom_node and _apply_whitespace_facet 803 # TypeBinding_mixin handles _nil and _element 804 args = self._ConvertArguments(args, kw) 805 try: 806 super(simpleTypeDefinition, self).__init__(*args, **kw) 807 except OverflowError, e: 808 raise pyxb.BadTypeValueError(e) 809 if require_value and (not self._constructedWithValue()): 810 raise pyxb.MissingContentError('missing value') 811 812 if validate_constraints: 813 self.xsdConstraintsOK()
814 815 816 # The class attribute name used to store the reference to the STD 817 # component instance must be unique to the class, not to this base class. 818 # Otherwise we mistakenly believe we've already associated a STD instance 819 # with a class (e.g., xsd:normalizedString) when in fact it's associated 820 # with the superclass (e.g., xsd:string) 821 @classmethod
822 - def __STDAttrName (cls):
823 return '_%s__SimpleTypeDefinition' % (cls.__name__,)
824 825 @classmethod
826 - def _SimpleTypeDefinition (cls, std):
827 """Set the L{pyxb.xmlschema.structures.SimpleTypeDefinition} instance 828 associated with this binding.""" 829 attr_name = cls.__STDAttrName() 830 if hasattr(cls, attr_name): 831 old_value = getattr(cls, attr_name) 832 if old_value != std: 833 raise pyxb.LogicError('%s: Attempt to override existing STD %s with %s' % (cls, old_value.name(), std.name())) 834 setattr(cls, attr_name, std)
835 836 @classmethod
837 - def SimpleTypeDefinition (cls):
838 """Return the SimpleTypeDefinition instance for the given 839 class. 840 841 This should only be invoked when generating bindings. 842 843 @raise pyxb.IncompleteImplementationError: no STD instance has been 844 associated with the class. 845 846 """ 847 attr_name = cls.__STDAttrName() 848 if hasattr(cls, attr_name): 849 return getattr(cls, attr_name) 850 raise pyxb.IncompleteImplementationError('%s: No STD available' % (cls,))
851 852 @classmethod
853 - def XsdLiteral (cls, value):
854 """Convert from a python value to a string usable in an XML 855 document. 856 857 This should be implemented in the subclass.""" 858 raise pyxb.LogicError('%s does not implement XsdLiteral' % (cls,))
859
860 - def xsdLiteral (self):
861 """Return text suitable for representing the value of this 862 instance in an XML document. 863 864 The base class implementation delegates to the object class's 865 XsdLiteral method.""" 866 if self._isNil(): 867 return '' 868 return self.XsdLiteral(self)
869 870 @classmethod
871 - def XsdSuperType (cls):
872 """Find the nearest parent class in the PST hierarchy. 873 874 The value for anySimpleType is None; for all others, it's a 875 primitive or derived PST descendent (including anySimpleType).""" 876 for sc in cls.mro(): 877 if sc == cls: 878 continue 879 if simpleTypeDefinition == sc: 880 # If we hit the PST base, this is a primitive type or 881 # otherwise directly descends from a Python type; return 882 # the recorded XSD supertype. 883 return cls._XsdBaseType 884 if issubclass(sc, simpleTypeDefinition): 885 return sc 886 raise pyxb.LogicError('No supertype found for %s' % (cls,))
887 888 @classmethod
889 - def _XsdConstraintsPreCheck_vb (cls, value):
890 """Pre-extended class method to verify other things before 891 checking constraints. 892 893 This is used for list types, to verify that the values in the 894 list are acceptable, and for token descendents, to check the 895 lexical/value space conformance of the input. 896 """ 897 super_fn = getattr(super(simpleTypeDefinition, cls), '_XsdConstraintsPreCheck_vb', lambda *a,**kw: value) 898 return super_fn(value)
899 900 # Cache of pre-computed sequences of class facets in the order required 901 # for constraint validation 902 __ClassFacetSequence = { } 903 904 @classmethod
905 - def XsdConstraintsOK (cls, value):
906 """Validate the given value against the constraints on this class. 907 908 @raise pyxb.BadTypeValueError: if any constraint is violated. 909 """ 910 911 value = cls._XsdConstraintsPreCheck_vb(value) 912 913 facet_values = cls.__ClassFacetSequence.get(cls) 914 if facet_values is None: 915 # Constraints for simple type definitions are inherited. Check them 916 # from least derived to most derived. 917 classes = [ _x for _x in cls.mro() if issubclass(_x, simpleTypeDefinition) ] 918 classes.reverse() 919 cache_result = True 920 facet_values = [] 921 for clazz in classes: 922 # When setting up the datatypes, if we attempt to validate 923 # something before the facets have been initialized (e.g., a 924 # nonNegativeInteger used as a length facet for the parent 925 # integer datatype), just ignore that for now. Don't cache 926 # the value, though, since a subsequent check after 927 # initialization should succceed. 928 try: 929 clazz_facets = clazz._FacetMap().values() 930 except AttributeError, e: 931 cache_result = False 932 clazz_facets = [] 933 for v in clazz_facets: 934 if not (v in facet_values): 935 facet_values.append(v) 936 if cache_result: 937 cls.__ClassFacetSequence[cls] = facet_values 938 for f in facet_values: 939 if not f.validateConstraint(value): 940 raise pyxb.BadTypeValueError('%s violation for %s in %s' % (f.Name(), value, cls.__name__)) 941 #print '%s ok for %s' % (f, value) 942 return value
943
944 - def xsdConstraintsOK (self):
945 """Validate the value of this instance against its constraints.""" 946 return self.XsdConstraintsOK(self)
947
948 - def _validateBinding_vx (self):
949 if not self._isNil(): 950 self._checkValidValue() 951 return True
952 953 @classmethod
954 - def XsdValueLength (cls, value):
955 """Return the length of the given value. 956 957 The length is calculated by a subclass implementation of 958 _XsdValueLength_vx in accordance with 959 http://www.w3.org/TR/xmlschema-2/#rf-length. 960 961 The return value is a non-negative integer, or C{None} if length 962 constraints should be considered trivially satisfied (as with 963 QName and NOTATION). 964 965 :raise pyxb.LogicError: the provided value is not an instance of cls. 966 :raise pyxb.LogicError: an attempt is made to calculate a length for 967 an instance of a type that does not support length calculations. 968 """ 969 assert isinstance(value, cls) 970 if not hasattr(cls, '_XsdValueLength_vx'): 971 raise pyxb.LogicError('Class %s does not support length validation' % (cls.__name__,)) 972 return cls._XsdValueLength_vx(value)
973
974 - def xsdValueLength (self):
975 """Return the length of this instance within its value space. 976 977 See XsdValueLength.""" 978 return self.XsdValueLength(self)
979 980 @classmethod
981 - def PythonLiteral (cls, value):
982 """Return a string which can be embedded into Python source to 983 represent the given value as an instance of this class.""" 984 class_name = cls.__name__ 985 return '%s(%s)' % (class_name, repr(value))
986
987 - def pythonLiteral (self):
988 """Return a string which can be embedded into Python source to 989 represent the value of this instance.""" 990 return self.PythonLiteral(self)
991
992 - def _toDOM_csc (self, dom_support, parent):
993 assert parent is not None 994 parent.appendChild(dom_support.document().createTextNode(self.xsdLiteral())) 995 return getattr(super(simpleTypeDefinition, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent)
996 997 @classmethod
998 - def _IsSimpleTypeContent (cls):
999 """STDs have simple type content.""" 1000 return True
1001 1002 @classmethod
1003 - def _IsValidValue (self, value):
1004 try: 1005 self._CheckValidValue(value) 1006 return True 1007 except pyxb.PyXBException, e: 1008 pass 1009 return False
1010 1011 @classmethod
1012 - def _CheckValidValue (cls, value):
1013 1014 """NB: Invoking this on a value that is a list will, if necessary, 1015 replace the members of the list with new values that are of the 1016 correct item type. This is permitted because only with lists is it 1017 possible to bypass the normal content validation (by invoking 1018 append/extend on the list instance).""" 1019 if value is None: 1020 raise pyxb.BadTypeValueError('None is not a valid instance of %s' % (cls,)) 1021 #print 'testing value %s type %s against %s' % (value, type(value), cls) 1022 value_class = cls 1023 if issubclass(cls, STD_list): 1024 #print ' -- checking list of %s' % (cls._ItemType,) 1025 try: 1026 iter(value) 1027 except TypeError, e: 1028 raise pyxb.BadTypeValueError('%s cannot have non-iterable value type %s' % (cls, type(value))) 1029 for v in value: 1030 if not cls._ItemType._IsValidValue(v): 1031 raise pyxb.BadTypeValueError('%s cannot have member of type %s (want %s)' % (cls, type(v), cls._ItemType)) 1032 else: 1033 if issubclass(cls, STD_union): 1034 #print ' -- checking union with %d types' % (len(cls._MemberTypes),) 1035 value_class = None 1036 for mt in cls._MemberTypes: 1037 if mt._IsValidValue(value): 1038 value_class = mt 1039 break 1040 if value_class is None: 1041 raise pyxb.BadTypeValueError('%s cannot have value type %s' % (cls, type(value))) 1042 #if not (isinstance(value, value_class) or issubclass(value_class, type(value))): 1043 if not isinstance(value, value_class): 1044 raise pyxb.BadTypeValueError('Value type %s is not valid for %s' % (type(value), cls)) 1045 value_class.XsdConstraintsOK(value)
1046
1047 - def _checkValidValue (self):
1048 self._CheckValidValue(self)
1049
1050 - def _isValidValue (self):
1051 self._IsValidValue(self)
1052
1053 - def _setAttribute (self, attr_en, value):
1054 raise pyxb.UnrecognizedAttributeError('Attribute %s is not permitted in simple type %s' % (attr_en, self._ExpandedName))
1055 1056 @classmethod
1057 - def _description (cls, name_only=False, user_documentation=True):
1058 name = cls._Name() 1059 if name_only: 1060 return name 1061 desc = [ name, ' restriction of ', cls.XsdSuperType()._description(name_only=True) ] 1062 if user_documentation and (cls._Documentation is not None): 1063 desc.extend(["\n", cls._Documentation]) 1064 return ''.join(desc)
1065
1066 -class STD_union (simpleTypeDefinition):
1067 """Base class for union datatypes. 1068 1069 This class descends only from simpleTypeDefinition. A pyxb.LogicError is 1070 raised if an attempt is made to construct an instance of a subclass of 1071 STD_union. Values consistent with the member types are constructed using 1072 the Factory class method. Values are validated using the _ValidatedMember 1073 class method. 1074 1075 Subclasses must provide a class variable _MemberTypes which is a 1076 tuple of legal members of the union.""" 1077 1078 _MemberTypes = None 1079 """A list of classes which are permitted as values of the union.""" 1080 1081 # Ick: If we don't declare this here, this class's map doesn't get 1082 # initialized. Alternative is to not descend from simpleTypeDefinition. 1083 # @todo Ensure that pattern and enumeration are valid constraints 1084 __FacetMap = {} 1085 1086 @classmethod
1087 - def Factory (cls, *args, **kw):
1088 """Given a value, attempt to create an instance of some member of this 1089 union. The first instance which can be legally created is returned. 1090 1091 @keyword _validate_constraints: If True (default), any constructed 1092 value is checked against constraints applied to the union as well as 1093 the member type. 1094 1095 @raise pyxb.BadTypeValueError: no member type will permit creation of 1096 an instance from the parameters in C{args} and C{kw}. 1097 """ 1098 1099 used_cls = cls._SupersedingClass() 1100 state = used_cls._PreFactory_vx(args, kw) 1101 1102 rv = None 1103 # NB: get, not pop: preserve it for the member type invocations 1104 validate_constraints = kw.get('_validate_constraints', cls._PerformValidation()) 1105 assert isinstance(validate_constraints, bool) 1106 if 0 < len(args): 1107 arg = args[0] 1108 try: 1109 rv = cls._ValidatedMember(arg) 1110 except pyxb.BadTypeValueError, e: 1111 pass 1112 if rv is None: 1113 kw['_validate_constraints'] = True 1114 for mt in cls._MemberTypes: 1115 try: 1116 rv = mt.Factory(*args, **kw) 1117 break 1118 except pyxb.BadTypeValueError: 1119 pass 1120 except ValueError: 1121 pass 1122 except: 1123 pass 1124 if rv is not None: 1125 if validate_constraints: 1126 cls.XsdConstraintsOK(rv) 1127 rv._postFactory_vx(state) 1128 return rv 1129 raise pyxb.BadTypeValueError('%s cannot construct union member from args %s' % (cls.__name__, args))
1130 1131 @classmethod
1132 - def _ValidatedMember (cls, value):
1133 """Validate the given value as a potential union member. 1134 1135 @raise pyxb.BadTypeValueError: the value is not an instance of a 1136 member type.""" 1137 if not isinstance(value, cls._MemberTypes): 1138 for mt in cls._MemberTypes: 1139 try: 1140 # Force validation so we get the correct type, otherwise 1141 # first member will be accepted. 1142 value = mt.Factory(value, _validate_constraints=True) 1143 return value 1144 except (TypeError, pyxb.BadTypeValueError): 1145 pass 1146 raise pyxb.BadTypeValueError('%s cannot hold a member of type %s' % (cls.__name__, value.__class__.__name__)) 1147 return value
1148
1149 - def __init__ (self, *args, **kw):
1150 raise pyxb.LogicError('%s: cannot construct instances of union' % (self.__class__.__name__,))
1151 1152 @classmethod
1153 - def _description (cls, name_only=False, user_documentation=True):
1154 name = cls._Name() 1155 if name_only: 1156 return name 1157 desc = [ name, ', union of '] 1158 desc.append(', '.join([ _td._description(name_only=True) for _td in cls._MemberTypes ])) 1159 return ''.join(desc)
1160 1161 @classmethod
1162 - def XsdLiteral (cls, value):
1163 """Convert from a binding value to a string usable in an XML document.""" 1164 return cls._ValidatedMember(value).xsdLiteral()
1165
1166 1167 -class STD_list (simpleTypeDefinition, types.ListType):
1168 """Base class for collection datatypes. 1169 1170 This class descends from the Python list type, and incorporates 1171 simpleTypeDefinition. Subclasses must define a class variable _ItemType 1172 which is a reference to the class of which members must be instances.""" 1173 1174 _ItemType = None 1175 """A reference to the binding class for items within this list.""" 1176 1177 # Ick: If we don't declare this here, this class's map doesn't get 1178 # initialized. Alternative is to not descend from simpleTypeDefinition. 1179 __FacetMap = {} 1180 1181 @classmethod
1182 - def _ValidatedItem (cls, value):
1183 """Verify that the given value is permitted as an item of this list. 1184 1185 This may convert the value to the proper type, if it is 1186 compatible but not an instance of the item type. Returns the 1187 value that should be used as the item, or raises an exception 1188 if the value cannot be converted.""" 1189 if isinstance(value, cls._ItemType): 1190 pass 1191 elif issubclass(cls._ItemType, STD_union): 1192 value = cls._ItemType._ValidatedMember(value) 1193 else: 1194 try: 1195 value = cls._ItemType(value) 1196 except (pyxb.BadTypeValueError, TypeError): 1197 raise pyxb.BadTypeValueError('Type %s has member of type %s, must be %s' % (cls.__name__, type(value).__name__, cls._ItemType.__name__)) 1198 return value
1199 1200 @classmethod
1201 - def _ConvertArguments_vx (cls, args, kw):
1202 # If the first argument is a string, split it on spaces and use the 1203 # resulting list of tokens. 1204 if 0 < len(args): 1205 arg1 = args[0] 1206 if isinstance(arg1, types.StringTypes): 1207 args = (arg1.split(),) + args[1:] 1208 arg1 = args[0] 1209 is_iterable = False 1210 try: 1211 iter(arg1) 1212 is_iterable = True 1213 except TypeError: 1214 pass 1215 if is_iterable: 1216 new_arg1 = [] 1217 for i in range(len(arg1)): 1218 new_arg1.append(cls._ValidatedItem(arg1[i])) 1219 args = (new_arg1,) + args[1:] 1220 super_fn = getattr(super(STD_list, cls), '_ConvertArguments_vx', lambda *a,**kw: args) 1221 return super_fn(args, kw)
1222 1223 @classmethod
1224 - def _XsdValueLength_vx (cls, value):
1225 return len(value)
1226 1227 @classmethod
1228 - def XsdLiteral (cls, value):
1229 """Convert from a binding value to a string usable in an XML document.""" 1230 return ' '.join([ cls._ItemType.XsdLiteral(_v) for _v in value ])
1231 1232 @classmethod
1233 - def _description (cls, name_only=False, user_documentation=True):
1234 name = cls._Name() 1235 if name_only: 1236 return name 1237 desc = [ name, ', list of ', cls._ItemType._description(name_only=True) ] 1238 return ''.join(desc)
1239 1240 # Convert a single value to the required type, if not already an instance 1241 @classmethod
1242 - def __ConvertOne (cls, v):
1243 return cls._ValidatedItem(v)
1244 1245 # Convert a sequence of values to the required type, if not already instances
1246 - def __convertMany (self, values):
1247 return [ self._ValidatedItem(_v) for _v in values ]
1248
1249 - def __setitem__ (self, key, value):
1250 if isinstance(key, slice): 1251 super(STD_list, self).__setitem__(key, self.__convertMany(values)) 1252 else: 1253 super(STD_list, self).__setitem__(key, self._ValidatedItem(value))
1254
1255 - def __setslice__ (self, start, end, values):
1256 super(STD_list, self).__setslice__(start, end, self.__convertMany(values))
1257
1258 - def __contains__ (self, item):
1259 return super(STD_list, self).__contains__(self._ValidatedItem(item))
1260 1261 # Standard mutable sequence methods, per Python Library Reference "Mutable Sequence Types" 1262
1263 - def append (self, x):
1264 super(STD_list, self).append(self._ValidatedItem(x))
1265
1266 - def extend (self, x, _from_xml=False):
1267 super(STD_list, self).extend(self.__convertMany(x))
1268
1269 - def count (self, x):
1270 return super(STD_list, self).count(self._ValidatedItem(x))
1271
1272 - def index (self, x, *args):
1273 return super(STD_list, self).index(self._ValidatedItem(x), *args)
1274
1275 - def insert (self, i, x):
1276 super(STD_list, self).insert(i, self._ValidatedItem(x))
1277
1278 - def remove (self, x):
1279 super(STD_list, self).remove(self._ValidatedItem(x))
1280
1281 -class element (utility._DeconflictSymbols_mixin, _DynamicCreate_mixin):
1282 """Class that represents a schema element. 1283 1284 Global and local elements are represented by instances of this class. 1285 """ 1286
1287 - def name (self):
1288 """The expanded name of the element within its scope.""" 1289 return self.__name
1290 __name = None 1291
1292 - def typeDefinition (self):
1293 """The L{_TypeBinding_mixin} subclass for values of this element.""" 1294 return self.__typeDefinition._SupersedingClass()
1295 __typeDefinition = None 1296
1297 - def scope (self):
1298 """The scope of the element. This is either C{None}, representing a 1299 top-level element, or an instance of C{complexTypeDefinition} for 1300 local elements.""" 1301 return self.__scope
1302 __scope = None 1303
1304 - def nillable (self):
1305 """Indicate whether values matching this element can have U{nil 1306 <http://www.w3.org/TR/xmlschema-1/#xsi_nil>} set.""" 1307 return self.__nillable
1308 __nillable = False 1309
1310 - def abstract (self):
1311 """Indicate whether this element is abstract (must use substitution 1312 group members for matches).""" 1313 return self.__abstract
1314 __abstract = False 1315
1316 - def documentation (self):
1317 """Contents of any documentation annotation in the definition.""" 1318 return self.__documentation
1319 __documentation = None 1320
1321 - def defaultValue (self):
1322 return self.__defaultValue
1323 __defaultValue = None 1324
1325 - def substitutionGroup (self):
1326 """The L{element} instance to whose substitution group this element 1327 belongs. C{None} if this element is not part of a substitution 1328 group.""" 1329 return self.__substitutionGroup
1330 - def _setSubstitutionGroup (self, substitution_group):
1331 self.__substitutionGroup = substitution_group 1332 if substitution_group is not None: 1333 self.substitutesFor = self._real_substitutesFor 1334 return self
1335 __substitutionGroup = None 1336
1337 - def findSubstituendUse (self, ctd_class):
1338 eu = ctd_class._ElementMap.get(self.name()) 1339 if eu is not None: 1340 return eu 1341 if self.substitutionGroup() is None: 1342 return None 1343 return self.substitutionGroup().findSubstituendUse(ctd_class)
1344
1345 - def _real_substitutesFor (self, other):
1346 """Determine whether an instance of this element can substitute for the other element. 1347 1348 See U{Substitution Group OK<http://www.w3.org/TR/xmlschema-1/#cos-equiv-derived-ok-rec>)}. 1349 1350 @todo: Do something about blocking constraints. This ignores them, as 1351 does everything leading to this point. 1352 """ 1353 if self.substitutionGroup() is None: 1354 return False 1355 if other is None: 1356 return False 1357 assert isinstance(other, element) 1358 # On the first call, other is likely to be the local element. We need 1359 # the global one. 1360 if other.scope() is not None: 1361 other = other.name().elementBinding() 1362 if other is None: 1363 return False 1364 assert other.scope() is None 1365 # Do both these refer to the same (top-level) element? 1366 if self.name().elementBinding() == other: 1367 return True 1368 return (self.substitutionGroup() == other) or self.substitutionGroup().substitutesFor(other)
1369
1370 - def substitutesFor (self, other):
1371 """Stub replaced by _real_substitutesFor when element supports substitution groups.""" 1372 return False
1373
1374 - def memberElement (self, name):
1375 """Return a reference to the element instance used for the given name 1376 within this element. 1377 1378 The type for this element must be a complex type definition.""" 1379 return self.typeDefinition()._UseForTag(name).elementBinding()
1380
1381 - def __init__ (self, name, type_definition, scope=None, nillable=False, abstract=False, default_value=None, substitution_group=None, documentation=None):
1382 """Create a new element binding. 1383 """ 1384 assert isinstance(name, pyxb.namespace.ExpandedName) 1385 self.__name = name 1386 self.__typeDefinition = type_definition 1387 self.__scope = scope 1388 self.__nillable = nillable 1389 self.__abstract = abstract 1390 self.__defaultValue = default_value 1391 self.__substitutionGroup = substitution_group 1392 self.__documentation = documentation
1393
1394 - def __call__ (self, *args, **kw):
1395 """Invoke the Factory method on the type associated with this element. 1396 1397 @keyword _dom_node: If set, specifies a DOM node that should be used 1398 for initialization. In that case, the L{createFromDOM} method is 1399 invoked instead of the type definition Factory method. 1400 1401 @note: Other keywords are passed to L{_TypeBinding_mixin.Factory}. 1402 1403 @raise pyxb.AbstractElementError: This element is abstract and no DOM 1404 node was provided. 1405 """ 1406 dom_node = kw.pop('_dom_node', None) 1407 assert dom_node is None, 'Cannot pass DOM node directly to element constructor; use createFromDOM' 1408 if '_element' in kw: 1409 raise pyxb.LogicError('Cannot set _element in element-based instance creation') 1410 kw['_element'] = self 1411 # Can't create instances of abstract elements. 1412 if self.abstract(): 1413 raise pyxb.AbstractElementError(self) 1414 return self.typeDefinition().Factory(*args, **kw)
1415
1416 - def compatibleValue (self, value, **kw):
1417 """Return a variant of the value that is compatible with this element. 1418 1419 This mostly defers to L{_TypeBinding_mixin._CompatibleValue}. 1420 1421 @raise pyxb.BadTypeValueError: if the value is not both 1422 type-consistent and value-consistent with the element's type. 1423 """ 1424 # None is always None 1425 if value is None: 1426 return None 1427 is_plural = kw.pop('is_plural', False) 1428 #print 'validating %s against %s, isPlural %s' % (type(value), self.typeDefinition(), is_plural) 1429 if is_plural: 1430 try: 1431 iter(value) 1432 except TypeError: 1433 raise pyxb.BadTypeValueError('Expected plural value, got %s' % (type(value),)) 1434 return [ self.compatibleValue(_v) for _v in value ] 1435 if isinstance(value, _TypeBinding_mixin) and (value._element() is not None) and value._element().substitutesFor(self): 1436 return value 1437 return self.typeDefinition()._CompatibleValue(value, **kw)
1438 1439 # element 1440 @classmethod
1441 - def AnyCreateFromDOM (cls, node, _fallback_namespace):
1442 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1443 node = node.documentElement 1444 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=_fallback_namespace) 1445 elt = expanded_name.elementBinding() 1446 if elt is None: 1447 raise pyxb.UnrecognizedElementError(dom_node=node, element_name=expanded_name) 1448 assert isinstance(elt, pyxb.binding.basis.element) 1449 # Pass on the namespace to use when resolving unqualified qnames as in 1450 # xsi:type 1451 return elt._createFromDOM(node, expanded_name, _fallback_namespace=_fallback_namespace)
1452
1453 - def elementForName (self, name):
1454 """Return the element that should be used if this element binding is 1455 permitted and an element with the given name is encountered. 1456 1457 Normally, the incoming name matches the name of this binding, and 1458 C{self} is returned. If the incoming name is different, it is 1459 expected to be the name of a global element which is within this 1460 element's substitution group. In that case, the binding corresponding 1461 to the named element is return. 1462 1463 @return: An instance of L{element}, or C{None} if no element with the 1464 given name can be found. 1465 """ 1466 1467 # Name match means OK. 1468 if self.name() == name: 1469 return self 1470 # No name match means only hope is a substitution group, for which the 1471 # element must be top-level. 1472 top_elt = self.name().elementBinding() 1473 if top_elt is None: 1474 return None 1475 # Members of the substitution group must also be top-level. NB: If 1476 # named_elt == top_elt, then the adoptName call below improperly 1477 # associated the global namespace with a local element of the same 1478 # name; cf. test-namespace-uu:testBad. 1479 elt_en = top_elt.name().adoptName(name) 1480 assert 'elementBinding' in elt_en.namespace()._categoryMap(), 'No element bindings in %s' % (elt_en.namespace(),) 1481 named_elt = elt_en.elementBinding() 1482 if (named_elt is None) or (named_elt == top_elt): 1483 return None 1484 if named_elt.substitutesFor(top_elt): 1485 return named_elt 1486 return None
1487
1488 - def createFromDOM (self, node, expanded_name=None, fallback_namespace=None, **kw):
1489 """Create a binding instance from the given DOM node. 1490 1491 @keyword expanded_name: Optional name for the DOM node. If not 1492 present, is inferred from C{node}. 1493 1494 @keyword fallback_namespace: Optional namespace to use when resolving 1495 unqualified names. 1496 """ 1497 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1498 node = node.documentElement 1499 if expanded_name is None: 1500 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=fallback_namespace) 1501 return self._createFromDOM(node, expanded_name, **kw)
1502
1503 - def _createFromDOM (self, node, expanded_name, **kw):
1504 """Create a binding instance from the given DOM node, using the 1505 provided name to identify the correct binding. 1506 1507 The context and information associated with this element is used to 1508 identify the actual element binding to use. By default, C{self} is 1509 used. If this element represents a term in a content model, the name 1510 and namespace of the incoming node may identify a different element. 1511 If that element is a member of this element's substitution group, the 1512 binding associated with the node's name will be used instead. 1513 1514 The type of object returned is determined by the type definition 1515 associated with the element binding and the value of any U{xsi:type 1516 <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute found in the 1517 node, modulated by the configuration of L{XSI.ProcessTypeAttribute<pyxb.namespace.builtin._XMLSchema_instance.ProcessTypeAttribute>}. 1518 1519 Keyword parameters are passed to the factory method of the type 1520 associated with the selected element binding. See 1521 L{_TypeBinding_mixin} and any specializations of it. 1522 1523 @param expanded_name: The expanded name of the node. If the value is 1524 C{None}, defaults to the name of this element. (In the case of 1525 substitution groups, the default is wrong, but correct inference 1526 depends on context not available here.) 1527 1528 @keyword _fallback_namespace: Optional namespace to use when resolving 1529 unqualified type names. 1530 1531 @param node: The DOM node specifying the element content. If this is 1532 a (top-level) Document node, its element node is used. 1533 @type node: C{xml.dom.Node} 1534 @return: An instance of L{_TypeBinding_mixin} 1535 @raise pyxb.StructuralBadDocumentError: The node's name does identify an element binding. 1536 @raise pyxb.AbstractElementError: The element binding associated with the node is abstract. 1537 @raise pyxb.BadDocumentError: An U{xsi:type <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute in the node fails to resolve to a recognized type 1538 @raise pyxb.BadDocumentError: An U{xsi:type <http://www.w3.org/TR/xmlschema-1/#xsi_type>} attribute in the node resolves to a type that is not a subclass of the type of the element binding. 1539 """ 1540 1541 # Bypass the useless top-level node and start with the element beneath 1542 # it. 1543 if xml.dom.Node.DOCUMENT_NODE == node.nodeType: 1544 node = node.documentElement 1545 1546 # Identify the element binding to be used for the given node. NB: 1547 # Even if found, this may not be equal to self, since we allow you to 1548 # use an abstract substitution group head to create instances from DOM 1549 # nodes that are in that group. 1550 fallback_namespace = kw.pop('_fallback_namespace', None) 1551 element_binding = self.elementForName(expanded_name) 1552 if element_binding is None: 1553 raise pyxb.StructuralBadDocumentError('Element %s cannot create from node %s' % (self.name(), expanded_name)) 1554 1555 # Can't create instances of abstract elements. @todo: Is there any 1556 # way this could be legal given an xsi:type attribute? I'm pretty 1557 # sure "no"... 1558 if element_binding.abstract(): 1559 raise pyxb.AbstractElementError(element_binding) 1560 1561 # Record the element to be associated with the created binding 1562 # instance. 1563 if '_element' in kw: 1564 raise pyxb.LogicError('Cannot set _element in element-based instance creation') 1565 kw['_element'] = element_binding 1566 1567 # Now determine the type binding for the content. If xsi:type is 1568 # used, it won't be the one built into the element binding. 1569 type_class = element_binding.typeDefinition() 1570 elt_ns = element_binding.name().namespace() 1571 1572 # Get the namespace context for the value being created. If none is 1573 # associated, one will be created. Do not make assumptions about the 1574 # namespace context; if the user cared, she should have assigned a 1575 # context before calling this. 1576 ns_ctx = pyxb.namespace.resolution.NamespaceContext.GetNodeContext(node) 1577 (did_replace, type_class) = XSI._InterpretTypeAttribute(XSI.type.getAttribute(node), ns_ctx, fallback_namespace, type_class) 1578 1579 # Pass xsi:nil on to the constructor regardless of whether the element 1580 # is nillable. Another sop to SOAP-encoding WSDL fans who don't 1581 # bother to provide valid schema for their message content. 1582 is_nil = XSI.nil.getAttribute(node) 1583 if is_nil is not None: 1584 kw['_nil'] = pyxb.binding.datatypes.boolean(is_nil) 1585 1586 rv = type_class.Factory(_dom_node=node, _fallback_namespace=fallback_namespace, **kw) 1587 assert rv._element() == element_binding 1588 rv._setNamespaceContext(ns_ctx) 1589 return rv._postDOMValidate()
1590
1591 - def __str__ (self):
1592 return 'Element %s' % (self.name(),)
1593
1594 - def _description (self, name_only=False, user_documentation=True):
1595 name = str(self.name()) 1596 if name_only: 1597 return name 1598 desc = [ name, ' (', self.typeDefinition()._description(name_only=True), ')' ] 1599 if self.scope() is not None: 1600 desc.extend([', local to ', self.scope()._description(name_only=True) ]) 1601 if self.nillable(): 1602 desc.append(', nillable') 1603 if self.substitutionGroup() is not None: 1604 desc.extend([', substitutes for ', self.substitutionGroup()._description(name_only=True) ]) 1605 if user_documentation and (self.documentation() is not None): 1606 desc.extend(["\n", self.documentation() ]) 1607 return ''.join(desc)
1608
1609 -class enumeration_mixin (pyxb.cscRoot):
1610 """Marker in case we need to know that a PST has an enumeration constraint facet.""" 1611 1612 @classmethod
1613 - def values (cls):
1614 """Return a list of values that the enumeration can take.""" 1615 return cls._CF_enumeration.values()
1616 1617 @classmethod
1618 - def itervalues (cls):
1619 """Return a generator for the values that the enumeration can take.""" 1620 return cls._CF_enumeration.itervalues()
1621 1622 @classmethod
1623 - def items (cls):
1624 """Return the associated L{pyxb.binding.facet._EnumerationElement} instances.""" 1625 return cls._CF_enumeration.items()
1626 1627 @classmethod
1628 - def iteritems (cls):
1629 """Generate the associated L{pyxb.binding.facet._EnumerationElement} instances.""" 1630 return cls._CF_enumeration.iteritems()
1631
1632 -class complexTypeDefinition (_TypeBinding_mixin, utility._DeconflictSymbols_mixin, _DynamicCreate_mixin):
1633 """Base for any Python class that serves as the binding for an 1634 XMLSchema complexType. 1635 1636 Subclasses should define a class-level _AttributeMap variable which maps 1637 from the unicode tag of an attribute to the AttributeUse instance that 1638 defines it. Similarly, subclasses should define an _ElementMap variable. 1639 """ 1640 1641 _CT_EMPTY = 'EMPTY' #<<< No content 1642 _CT_SIMPLE = 'SIMPLE' #<<< Simple (character) content 1643 _CT_MIXED = 'MIXED' #<<< Children may be elements or other (e.g., character) content 1644 _CT_ELEMENT_ONLY = 'ELEMENT_ONLY' #<<< Expect only element content. 1645 1646 _ContentTypeTag = None 1647 1648 _TypeDefinition = None 1649 """Subclass of simpleTypeDefinition that corresponds to the type content. 1650 Only valid if _ContentTypeTag is _CT_SIMPLE""" 1651 1652 # A value that indicates whether the content model for this type supports 1653 # wildcard elements. Supporting classes should override this value. 1654 _HasWildcardElement = False 1655 1656 # Map from expanded names to ElementUse instances 1657 _ElementMap = { } 1658 """Map from expanded names to ElementUse instances.""" 1659 1660 # Per-instance map from tags to attribute values for wildcard attributes. 1661 # Value is C{None} if the type does not support wildcard attributes. 1662 __wildcardAttributeMap = None 1663
1664 - def wildcardAttributeMap (self):
1665 """Obtain access to wildcard attributes. 1666 1667 The return value is C{None} if this type does not support wildcard 1668 attributes. If wildcard attributes are allowed, the return value is a 1669 map from QNames to the unicode string value of the corresponding 1670 attribute. 1671 1672 @todo: The map keys should be namespace extended names rather than 1673 QNames, as the in-scope namespace may not be readily available to the 1674 user. 1675 """ 1676 return self.__wildcardAttributeMap
1677 1678 # Per-instance list of DOM nodes interpreted as wildcard elements. 1679 # Value is None if the type does not support wildcard elements. 1680 __wildcardElements = None 1681
1682 - def wildcardElements (self):
1683 """Obtain access to wildcard elements. 1684 1685 The return value is C{None} if the content model for this type does not 1686 support wildcard elements. If wildcard elements are allowed, the 1687 return value is a list of values corresponding to conformant 1688 unrecognized elements, in the order in which they were encountered. 1689 If the containing binding was created from an XML document and enough 1690 information was present to determine the binding of the member 1691 element, the value is a binding instance. Otherwise, the value is the 1692 original DOM Element node. 1693 """ 1694 return self.__wildcardElements
1695 1696 @classmethod
1697 - def _ConfigureBindingStyle (cls, style):
1698 if BINDING_STYLE_PROPERTY == style: 1699 pass 1700 elif BINDING_STYLE_ACCESSOR == style: 1701 pass 1702 else: 1703 raise pyxb.LogicError('Unrecognized binding style %s' % (style,))
1704
1705 - def __init__ (self, *args, **kw):
1706 """Create a new instance of this binding. 1707 1708 Arguments are used as transition values along the content model. 1709 Keywords are passed to the constructor of any simple content, or used 1710 to initialize attribute and element values whose L{id 1711 <content.ElementUse.id>} (not L{name <content.ElementUse.name>}) 1712 matches the keyword. 1713 1714 @keyword _dom_node: The node to use as the source of binding content. 1715 @type _dom_node: C{xml.dom.Element} 1716 1717 @keyword _from_xml: See L{_TypeBinding_mixin.Factory} 1718 1719 """ 1720 1721 fallback_namespace = kw.pop('_fallback_namespace', None) 1722 is_nil = False 1723 dom_node = kw.pop('_dom_node', None) 1724 from_xml = kw.pop('_from_xml', dom_node is not None) 1725 if dom_node is not None: 1726 if isinstance(dom_node, pyxb.utils.utility.Locatable_mixin): 1727 self._setLocation(dom_node.location) 1728 if xml.dom.Node.DOCUMENT_NODE == dom_node.nodeType: 1729 dom_node = dom_node.documentElement 1730 #kw['_validate_constraints'] = False 1731 is_nil = XSI.nil.getAttribute(dom_node) 1732 if is_nil is not None: 1733 is_nil = kw['_nil'] = pyxb.binding.datatypes.boolean(is_nil) 1734 if self._AttributeWildcard is not None: 1735 self.__wildcardAttributeMap = { } 1736 if self._HasWildcardElement: 1737 self.__wildcardElements = [] 1738 if self._Abstract: 1739 raise pyxb.AbstractInstantiationError(type(self)) 1740 super(complexTypeDefinition, self).__init__(**kw) 1741 self.reset() 1742 self._setAttributesFromKeywordsAndDOM(kw, dom_node) 1743 for fu in self._ElementMap.values(): 1744 iv = kw.pop(fu.id(), None) 1745 if iv is not None: 1746 fu.set(self, iv) 1747 if kw and kw.pop('_strict_keywords', True): 1748 [ kw.pop(_fkw, None) for _fkw in self._PyXBFactoryKeywords ] 1749 if kw: 1750 raise pyxb.ExtraContentError(kw) 1751 if dom_node is not None: 1752 if self._CT_SIMPLE == self._ContentTypeTag: 1753 self.__initializeSimpleContent(args, dom_node) 1754 else: 1755 self._setContentFromDOM(dom_node, fallback_namespace) 1756 elif 0 < len(args): 1757 self.extend(args, _from_xml=from_xml) 1758 else: 1759 if self._CT_SIMPLE == self._ContentTypeTag: 1760 self.__initializeSimpleContent(args, dom_node)
1761
1762 - def __initializeSimpleContent (self, args, dom_node=None):
1763 # Don't propagate the keywords. Python base simple types usually 1764 # don't like them, and even if they do we're not using them here. (Do 1765 # need to propagate _nil, though, to correctly handle types derived 1766 # from basestring.) 1767 value = self._TypeDefinition.Factory(_require_value=not self._isNil(), _dom_node=dom_node, _nil=self._isNil(), *args) 1768 if value._constructedWithValue(): 1769 if self._isNil(): 1770 raise pyxb.ContentInNilElementError(value) 1771 else: 1772 self.append(value)
1773 1774 # Specify the symbols to be reserved for all CTDs. 1775 _ReservedSymbols = _TypeBinding_mixin._ReservedSymbols.union(set([ 'wildcardElements', 'wildcardAttributeMap', 1776 'xsdConstraintsOK', 'content', 'append', 'extend', 'value', 'reset' ])) 1777 1778 # None, or a reference to a ParticleModel instance that defines how to 1779 # reduce a DOM node list to the body of this element. 1780 _ContentModel = None 1781 1782 @classmethod
1783 - def _AddElement (cls, element):
1784 """Method used by generated code to associate the element binding with a use in this type. 1785 1786 This is necessary because all complex type classes appear in the 1787 module prior to any of the element instances (which reference type 1788 classes), so the association must be formed after the element 1789 instances are available.""" 1790 return cls._UseForTag(element.name())._setElementBinding(element)
1791 1792 @classmethod
1793 - def _UseForTag (cls, tag, raise_if_fail=True):
1794 """Return the ElementUse object corresponding to the element name. 1795 1796 @param tag: The L{ExpandedName} of an element in the class.""" 1797 rv = cls._ElementMap.get(tag) 1798 if (rv is None) and raise_if_fail: 1799 raise pyxb.NotAnElementError(tag, cls) 1800 return rv
1801
1802 - def __childrenForDOM (self):
1803 """Generate a list of children in the order in which they should be 1804 added to the parent when creating a DOM representation of this 1805 object. 1806 1807 @note: This is only used when L{pyxb.RequireValidWhenGenerating} has 1808 disabled validation. Consequently, it may not generate valid XML. 1809 """ 1810 order = [] 1811 for eu in self._ElementMap.values(): 1812 value = eu.value(self) 1813 if value is None: 1814 continue 1815 if isinstance(value, list) and eu.isPlural(): 1816 order.extend([ (eu, _v) for _v in value ]) 1817 continue 1818 order.append( (eu, value) ) 1819 return order
1820
1821 - def _validatedChildren (self):
1822 """Provide the child elements and non-element content in an order 1823 consistent with the content model. 1824 1825 Returns a sequence of tuples representing a valid path through the 1826 content model where each transition corresponds to one of the member 1827 element instances within this instance. The tuple is a pair 1828 comprising the L{content.ElementUse} instance and the value for the 1829 transition. 1830 1831 If the content of the instance does not validate against the content 1832 model, C{None} is returned. 1833 1834 The base class implementation uses the 1835 L{content.ParticleModel.validate} method. Subclasses may desire to 1836 override this in cases where the desired order is not maintained by 1837 model interpretation (for example, when an "all" model is used and the 1838 original element order is desired). See L{__childrenForDOM} as an 1839 example of an alternative approach. 1840 1841 @return: C{None} or a list as described above. 1842 """ 1843 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 1844 return [] 1845 1846 if self._ContentModel is None: 1847 raise pyxb.NoContentModel(self) 1848 path = self._ContentModel.validate(self._symbolSet()) 1849 if path is not None: 1850 ( symbols, sequence ) = path 1851 if 0 == len(symbols): 1852 return sequence 1853 raise pyxb.BindingValidationError('Ungenerated symbols: %s' % (symbols,) ) 1854 return None
1855
1856 - def _symbolSet (self):
1857 """Return a map from L{content.ElementUse} instances to a list of 1858 values associated with that use. 1859 1860 This is used as the set of symbols available for transitions when 1861 validating content against a model. Note that the order of values 1862 within a use is likely to be significant, although the model cannot 1863 detect this. 1864 1865 The value C{None} should be used to provide a list of wildcard 1866 members. 1867 1868 If an element use has no associated values, it must not appear in the 1869 returned map. 1870 """ 1871 rv = { } 1872 for eu in self._ElementMap.values(): 1873 value = eu.value(self) 1874 if value is None: 1875 continue 1876 res = None 1877 converter = eu.elementBinding().compatibleValue 1878 if eu.isPlural(): 1879 if 0 < len(value): 1880 rv[eu] = [ converter(_v) for _v in value ] 1881 else: 1882 rv[eu] = [ converter(value)] 1883 wce = self.wildcardElements() 1884 if (wce is not None) and (0 < len(wce)): 1885 rv[None] = wce[:] 1886 return rv
1887
1888 - def _validateAttributes (self):
1889 for au in self._AttributeMap.values(): 1890 au.validate(self)
1891
1892 - def _validateBinding_vx (self):
1893 if self._isNil(): 1894 if (self._IsSimpleTypeContent() and (self.__content is not None)) or self.__content: 1895 raise pyxb.ContentInNilElementError(self._ExpandedName) 1896 return True 1897 if self._IsSimpleTypeContent() and (self.__content is None): 1898 raise pyxb.MissingContentError(self._TypeDefinition) 1899 try: 1900 order = self._validatedChildren() 1901 except Exception, e: 1902 raise pyxb.BindingValidationError('Error matching content to binding model: %s' % (e,)) 1903 if order is None: 1904 raise pyxb.BindingValidationError('Unable to match content to binding model') 1905 for (eu, value) in order: 1906 if isinstance(value, _TypeBinding_mixin): 1907 value.validateBinding() 1908 elif eu is not None: 1909 print 'WARNING: Cannot validate value %s in field %s' % (value, eu.id()) 1910 self._validateAttributes() 1911 return True
1912
1913 - def _setAttribute (self, attr_en, value):
1914 au = self._AttributeMap.get(attr_en, None) 1915 if au is None: 1916 if self._AttributeWildcard is None: 1917 raise pyxb.UnrecognizedAttributeError('Attribute %s is not permitted in type %s' % (attr_en, self._ExpandedName)) 1918 self.__wildcardAttributeMap[attr_en] = value 1919 else: 1920 au.set(self, value) 1921 return au
1922
1923 - def xsdConstraintsOK (self):
1924 """Validate the content against the simple type. 1925 1926 @return: C{True} if the content validates against its type. 1927 @raise pyxb.NotSimpleContentError: this type does not have simple content. 1928 @raise pyxb.MissingContentError: the content of this type has not been set 1929 """ 1930 # @todo: type check 1931 if self._CT_SIMPLE != self._ContentTypeTag: 1932 raise pyxb.NotSimpleContentError(self) 1933 if self._isNil(): 1934 return True 1935 if self.value() is None: 1936 raise pyxb.MissingContentError(self) 1937 return self.value().xsdConstraintsOK()
1938 1939 __content = None
1940 - def content (self):
1941 """Return the content of the element. 1942 1943 This must be a complex type with complex content. The return value is 1944 a list of the element and non-element content in the order in which it 1945 was added. 1946 @raise pyxb.NotComplexContentError: this is not a complex type with mixed or element-only content 1947 """ 1948 if self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE): 1949 raise pyxb.NotComplexContentError(str(self._ExpandedName)) 1950 return self.__content
1951
1952 - def value (self):
1953 """Return the value of the element. 1954 1955 This must be a complex type with simple content. The returned value 1956 is expected to be an instance of some L{simpleTypeDefinition} class. 1957 1958 @raise pyxb.NotSimpleContentError: this is not a complex type with simple content 1959 """ 1960 if self._CT_SIMPLE != self._ContentTypeTag: 1961 raise pyxb.NotSimpleContentError('%s (%s)' % (str(self._ExpandedName), type(self))) 1962 return self.__content
1963
1964 - def _resetContent (self):
1965 if self._ContentTypeTag in (self._CT_MIXED, self._CT_ELEMENT_ONLY): 1966 self.__setContent([]) 1967 else: 1968 self.__setContent(None)
1969 1970 __modelState = None
1971 - def reset (self):
1972 """Reset the instance. 1973 1974 This resets all element and attribute fields, and discards any 1975 recorded content. It resets the DFA to the initial state of the 1976 content model. 1977 """ 1978 1979 self._resetContent() 1980 for au in self._AttributeMap.values(): 1981 au.reset(self) 1982 for eu in self._ElementMap.values(): 1983 eu.reset(self) 1984 if self._ContentModel is not None: 1985 self.__modelState = self._ContentModel.newState() 1986 return self
1987 1988 @classmethod
1989 - def _ElementBindingUseForName (cls, element_name):
1990 """Determine what the given name means as an element in this type. 1991 1992 Normally, C{element_name} identifies an element definition within this 1993 type. If so, the returned C{element_use} identifies that definition, 1994 and the C{element_binding} is extracted from that use. 1995 1996 It may also be that the C{element_name} does not appear as an element 1997 definition, but that it identifies a global element. In that case, 1998 the returned C{element_binding} identifies the global element. If, 1999 further, that element is a member of a substitution group which does 2000 have an element definition in this class, then the returned 2001 C{element_use} identifies that definition. 2002 2003 If a non-C{None} C{element_use} is returned, there will be an 2004 associated C{element_binding}. However, it is possible to return a 2005 non-C{None} C{element_binding}, but C{None} as the C{element_use}. In 2006 that case, the C{element_binding} can be used to create a binding 2007 instance, but the content model will have to treat it as a wildcard. 2008 2009 @param element_name: The name of the element in this type, either an 2010 expanded name or a local name if the element has an absent namespace. 2011 2012 @return: C{( element_binding, element_use )} 2013 """ 2014 element_use = cls._ElementMap.get(element_name) 2015 element_binding = None 2016 if element_use is None: 2017 try: 2018 element_binding = element_name.elementBinding() 2019 except pyxb.NamespaceError: 2020 pass 2021 if element_binding is not None: 2022 element_use = element_binding.findSubstituendUse(cls) 2023 else: 2024 element_binding = element_use.elementBinding() 2025 return (element_binding, element_use)
2026
2027 - def append (self, value, element_use=None, maybe_element=True, _fallback_namespace=None, require_validation=True, _from_xml=False):
2028 """Add the value to the instance. 2029 2030 The value should be a DOM node or other value that is or can be 2031 converted to a binding instance. If the instance has a DFA state, the 2032 value must be permitted by the content model. 2033 2034 @raise pyxb.ExtraContentError: the value is not permitted at the 2035 current state of the content model. 2036 """ 2037 2038 # @todo: Allow caller to provide default element use; it's available 2039 # in saxer. 2040 element_binding = None 2041 if element_use is not None: 2042 import content 2043 assert isinstance(element_use, content.ElementUse) 2044 element_binding = element_use.elementBinding() 2045 assert element_binding is not None 2046 # Convert the value if it's XML and we recognize it. 2047 if isinstance(value, xml.dom.Node): 2048 _from_xml = True 2049 assert maybe_element 2050 assert element_binding is None 2051 node = value 2052 require_validation = pyxb._ParsingRequiresValid 2053 if xml.dom.Node.COMMENT_NODE == node.nodeType: 2054 # @todo: Note that we're allowing comments inside the bodies 2055 # of simple content elements, which isn't really Hoyle. 2056 return self 2057 if node.nodeType in (xml.dom.Node.TEXT_NODE, xml.dom.Node.CDATA_SECTION_NODE): 2058 value = node.data 2059 maybe_element = False 2060 else: 2061 # Do type conversion here 2062 assert xml.dom.Node.ELEMENT_NODE == node.nodeType 2063 expanded_name = pyxb.namespace.ExpandedName(node, fallback_namespace=_fallback_namespace) 2064 (element_binding, element_use) = self._ElementBindingUseForName(expanded_name) 2065 if element_binding is not None: 2066 value = element_binding._createFromDOM(node, expanded_name, _fallback_namespace=_fallback_namespace) 2067 else: 2068 # Might be a resolvable wildcard. See if we can convert it to an 2069 # element. 2070 #print 'Attempting to create element from node %s' % (expanded_name,) 2071 try: 2072 ns = expanded_name.namespace() 2073 if ns is not None: 2074 for mr in ns.moduleRecords(): 2075 try: 2076 if (mr.module() is None) and (mr.modulePath() is not None): 2077 print 'Importing %s to get binding for wildcard %s' % (mr.modulePath(), expanded_name) 2078 mod = __import__(mr.modulePath()) 2079 for c in mr.modulePath().split('.')[1:]: 2080 mod = getattr(mod, c) 2081 mr._setModule(mod) 2082 value = mr.module().CreateFromDOM(node) 2083 break 2084 except pyxb.PyXBException, e: 2085 print 'Ignoring error when creating binding for wildcard %s: %s' % (expanded_name, e) 2086 except AttributeError, e: 2087 # The module holding XMLSchema bindnigs does not 2088 # have a CreateFromDOM method, and shouldn't since 2089 # we need to convert schema instances to DOM more 2090 # carefully. 2091 if mr.namespace() != pyxb.namespace.XMLSchema: 2092 raise 2093 except Exception, e: 2094 print 'WARNING: Unable to convert DOM node %s to Python instance: %s' % (expanded_name, e) 2095 if (not maybe_element) and isinstance(value, basestring) and (self._ContentTypeTag in (self._CT_EMPTY, self._CT_ELEMENT_ONLY)): 2096 if (0 == len(value.strip())) and not self._isNil(): 2097 return self 2098 if self._isNil() and not self._IsSimpleTypeContent(): 2099 raise pyxb.ExtraContentError('%s: Content %s present in element with xsi:nil' % (type(self), value)) 2100 if maybe_element and (self.__modelState is not None): 2101 # Allows element content. 2102 if not require_validation: 2103 if element_use is not None: 2104 element_use.setOrAppend(self, value) 2105 return self 2106 if self.wildcardElements() is not None: 2107 self._appendWildcardElement(value) 2108 return self 2109 raise pyxb.StructuralBadDocumentError('Validation is required when no element_use can be found') 2110 else: 2111 #print 'SSStep %s %s' % (value, element_use) 2112 ( consumed, underflow_exc ) = self.__modelState.step(self, value, element_use) 2113 if consumed: 2114 return self 2115 # If what we have is element content, we can't accept it, either 2116 # because the type doesn't accept element content or because it does 2117 # and what we got didn't match the content model. 2118 if (element_binding is not None) or isinstance(value, xml.dom.Node): 2119 raise pyxb.ExtraContentError('%s: Extra content %s starting with %s' % (self._ExpandedName, element_binding, value,)) 2120 2121 # We have something that doesn't seem to be an element. Are we 2122 # expecting simple content? 2123 if self._IsSimpleTypeContent(): 2124 if self.__content is not None: 2125 raise pyxb.ExtraContentError('Extra content starting with %s (already have %s)' % (value, self.__content)) 2126 if not self._isNil(): 2127 if not isinstance(value, self._TypeDefinition): 2128 value = self._TypeDefinition.Factory(value, _from_xml=_from_xml) 2129 self.__setContent(value) 2130 if require_validation: 2131 # NB: This only validates the value, not any associated 2132 # attributes, which is correct to be parallel to complex 2133 # content validation. 2134 self.xsdConstraintsOK() 2135 return self 2136 2137 # Do we allow non-element content? 2138 if not self._IsMixed(): 2139 raise pyxb.UnexpectedNonElementContentError(value) 2140 if isinstance(value, _TypeBinding_mixin): 2141 raise pyxb.ExtraContentError('Extra content starting with %s' % (value,)) 2142 2143 self._addContent(value, element_binding) 2144 return self
2145
2146 - def _appendWildcardElement (self, value):
2147 wcl = self.wildcardElements() 2148 if wcl is None: 2149 raise pyxb.UnrecognizedContentError(value, container=self) 2150 wcl.append(value)
2151
2152 - def extend (self, value_list, _fallback_namespace=None, _from_xml=False):
2153 """Invoke L{append} for each value in the list, in turn.""" 2154 [ self.append(_v, _fallback_namespace=_fallback_namespace, _from_xml=_from_xml) for _v in value_list ] 2155 return self
2156
2157 - def __setContent (self, value):
2158 self.__content = value
2159
2160 - def _addContent (self, child, element_binding):
2161 # This assert is inadequate in the case of plural/non-plural elements with an STD_list base type. 2162 # Trust that validation elsewhere was done correctly. 2163 #assert self._IsMixed() or (not self._PerformValidation()) or isinstance(child, _TypeBinding_mixin) or isinstance(child, types.StringTypes), 'Unrecognized child %s type %s' % (child, type(child)) 2164 assert not (self._ContentTypeTag in (self._CT_EMPTY, self._CT_SIMPLE)) 2165 if isinstance(child, _TypeBinding_mixin) and (child._element() is None): 2166 child._setElement(element_binding) 2167 self.__content.append(child)
2168 2169 @classmethod
2170 - def _IsMixed (cls):
2171 return (cls._CT_MIXED == cls._ContentTypeTag)
2172
2173 - def _postDOMValidate (self):
2174 if self._PerformValidation() and (not self._isNil()) and (self.__modelState is not None): 2175 self.__modelState.verifyComplete() 2176 self._validateAttributes() 2177 return self
2178
2179 - def _setContentFromDOM (self, node, _fallback_namespace):
2180 """Initialize the content of this element from the content of the DOM node.""" 2181 2182 self.extend(node.childNodes[:], _fallback_namespace) 2183 return self._postDOMValidate()
2184
2185 - def _setDOMFromAttributes (self, dom_support, element):
2186 """Add any appropriate attributes from this instance into the DOM element.""" 2187 for au in self._AttributeMap.values(): 2188 if pyxb._GenerationRequiresValid: 2189 au.validate(self) 2190 au.addDOMAttribute(dom_support, self, element) 2191 return element
2192
2193 - def _toDOM_csc (self, dom_support, parent):
2194 """Create a DOM element with the given tag holding the content of this instance.""" 2195 element = parent 2196 self._setDOMFromAttributes(dom_support, element) 2197 if self._isNil(): 2198 pass 2199 elif self._CT_EMPTY == self._ContentTypeTag: 2200 pass 2201 elif self._CT_SIMPLE == self._ContentTypeTag: 2202 assert self.value() is not None, '%s has no value' % (self,) 2203 element.appendChild(dom_support.document().createTextNode(self.value().xsdLiteral())) 2204 else: 2205 if pyxb._GenerationRequiresValid: 2206 order = self._validatedChildren() 2207 else: 2208 order = self.__childrenForDOM() 2209 if order is None: 2210 raise pyxb.DOMGenerationError('Binding value inconsistent with content model') 2211 for (eu, v) in order: 2212 assert v != self 2213 if eu is None: 2214 if isinstance(v, xml.dom.Node): 2215 dom_support.appendChild(v, element) 2216 else: 2217 v.toDOM(dom_support, parent) 2218 else: 2219 eu.toDOM(dom_support, parent, v) 2220 mixed_content = self.content() 2221 for mc in mixed_content: 2222 pass 2223 return getattr(super(complexTypeDefinition, self), '_toDOM_csc', lambda *_args,**_kw: dom_support)(dom_support, parent)
2224 2225 @classmethod
2226 - def _IsSimpleTypeContent (cls):
2227 """CTDs with simple content are simple; other CTDs are not.""" 2228 return cls._CT_SIMPLE == cls._ContentTypeTag
2229 2230 @classmethod
2231 - def _description (cls, name_only=False, user_documentation=True):
2232 name = cls._Name() 2233 if name_only: 2234 return name 2235 desc = [ name ] 2236 if cls._CT_EMPTY == cls._ContentTypeTag: 2237 desc.append(', empty content') 2238 elif cls._CT_SIMPLE == cls._ContentTypeTag: 2239 desc.extend([', simple content type ', cls._TypeDefinition._description(name_only=True)]) 2240 else: 2241 if cls._CT_MIXED == cls._ContentTypeTag: 2242 desc.append(', mixed content') 2243 else: 2244 assert cls._CT_ELEMENT_ONLY == cls._ContentTypeTag 2245 desc.append(', element-only content') 2246 if (0 < len(cls._AttributeMap)) or (cls._AttributeWildcard is not None): 2247 desc.append("\nAttributes:\n ") 2248 desc.append("\n ".join([ _au._description(user_documentation=False) for _au in cls._AttributeMap.values() ])) 2249 if cls._AttributeWildcard is not None: 2250 desc.append("\n Wildcard attribute(s)") 2251 if (0 < len(cls._ElementMap)) or cls._HasWildcardElement: 2252 desc.append("\nElements:\n ") 2253 desc.append("\n ".join([ _eu._description(user_documentation=False) for _eu in cls._ElementMap.values() ])) 2254 if cls._HasWildcardElement: 2255 desc.append("\n Wildcard element(s)") 2256 return ''.join(desc)
2257 2258 ConfigureBindingStyle(DEFAULT_BINDING_STYLE) 2259 2260 ## Local Variables: 2261 ## fill-column:78 2262 ## End: 2263