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

Source Code for Module pyxb.binding.content

   1  # Copyright 2009-2011, 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  """Helper classes that maintain the content model of XMLSchema in the binding 
  16  classes. 
  17   
  18  L{AttributeUse} and L{ElementUse} record information associated with a binding 
  19  class, for example the types of values, the original XML QName or NCName, and 
  20  the Python field in which the values are stored.  They also provide the 
  21  low-level interface to set and get the corresponding values in a binding 
  22  instance. 
  23   
  24   
  25   
  26  L{Wildcard} holds content-related information used in the content model. 
  27  """ 
  28   
  29  import pyxb 
  30  import pyxb.namespace 
  31  import basis 
  32   
  33  import xml.dom 
  34   
35 -class ContentState_mixin (pyxb.cscRoot):
36 """Declares methods used by classes that hold state while validating a 37 content model component.""" 38
39 - def accepts (self, particle_state, instance, value, element_use):
40 """Determine whether the provided value can be added to the instance 41 without violating state validation. 42 43 This method must not throw any non-catastrophic exceptions; general 44 failures should be transformed to a C{False} return value. 45 46 @param particle_state: The L{ParticleState} instance serving as the 47 parent to this state. The implementation must inform that state when 48 the proposed value completes the content model. 49 50 @param instance: An instance of a subclass of 51 {basis.complexTypeDefinition}, into which the provided value will be 52 stored if it is consistent with the current model state. 53 54 @param value: The value that is being validated against the state. 55 56 @param element_use: An optional L{ElementUse} instance that specifies 57 the element to which the value corresponds. This will be available 58 when the value is extracted by parsing a document, but will be absent 59 if the value was passed as a constructor positional parameter. 60 61 @return: C{True} if the value was successfully matched against the 62 state. C{False} if the value did not match against the state.""" 63 raise Exception('ContentState_mixin.accepts not implemented in %s' % (type(self),))
64
65 - def notifyFailure (self, sub_state, particle_ok):
66 """Invoked by a sub-state to indicate that validation cannot proceed 67 in the current state. 68 69 Normally this is used when an intermediate content model must reset 70 itself to permit alternative models to be evaluated. 71 72 @param sub_state: the state that was unable to accept a value 73 74 @param particle_ok: C{True} if the particle that rejected the value is 75 in an accepting terminal state 76 77 """ 78 raise Exception('ContentState_mixin.notifyFailure not implemented in %s' % (type(self),))
79
80 - def _verifyComplete (self, parent_particle_state):
81 """Determine whether the deep state is complete without further elements. 82 83 No-op for non-aggregate state. For aggregate state, all contained 84 particles should be checked to see whether the overall model can be 85 satisfied if no additional elements are provided. 86 87 This method does not have a meaningful return value; violations of the 88 content model should produce the corresponding exception (generally, 89 L{MissingContentError}). 90 91 @param parent_particle_state: the L{ParticleState} for which this state 92 is the term. 93 """ 94 pass
95
96 -class ContentModel_mixin (pyxb.cscRoot):
97 """Declares methods used by classes representing content model components.""" 98
99 - def newState (self, parent_particle_state):
100 """Return a L{ContentState_mixin} instance that will validate the 101 state of this model component. 102 103 @param parent_particle_state: The L{ParticleState} instance for which 104 this instance is a term. C{None} for the top content model of a 105 complex data type. 106 """ 107 raise Exception('ContentModel_mixin.newState not implemented in %s' % (type(self),))
108
109 - def _validateCloneSymbolSet (self, symbol_set_im):
110 """Create a mutable copy of the symbol set. 111 112 The top-level map is copied, as are the lists of values to which the 113 symbols map. The values within the lists are unchanged, as validation 114 does not affect them.""" 115 rv = symbol_set_im.copy() 116 for (k, v) in rv.items(): 117 rv[k] = v[:] 118 return rv
119
120 - def _validateCloneOutputSequence (self, output_sequence_im):
121 """Create a mutable copy of the output sequence.""" 122 return output_sequence_im[:]
123
124 - def _validateReplaceResults (self, symbol_set_out, symbol_set_new, output_sequence_out, output_sequence_new):
125 """In-place update of symbol set and output sequence structures. 126 127 Use this to copy from temporary mutable structures updated by local 128 validation into the structures that were passed in once the validation 129 has succeeded.""" 130 symbol_set_out.clear() 131 symbol_set_out.update(symbol_set_new) 132 output_sequence_out[:] = output_sequence_new
133
134 - def _validate (self, symbol_set, output_sequence):
135 """Determine whether an output sequence created from the symbols can 136 be made consistent with the model. 137 138 The symbol set represents letters in an alphabet; the output sequence 139 orders those letters in a way that satisfies the regular expression 140 expressed in the model. Both are changed as a result of a successful 141 validation; both remain unchanged if the validation failed. In 142 recursing, implementers may assume that C{output_sequence} is 143 monotonic: its length remains unchanged after an invocation iff the 144 symbol set also remains unchanged. The L{_validateCloneSymbolSet}, 145 L{_validateCloneOutputSequence}, and L{_validateReplaceResults} 146 methods are available to help preserve this behavior. 147 148 @param symbol_set: A map from L{ElementUse} instances to a list of 149 values. The order of the values corresponds to the order in which 150 they should appear. A key of C{None} identifies values that are 151 stored as wildcard elements. Values are removed from the lists as 152 they are used; when the last value of a list is removed, its key is 153 removed from the map. Thus an empty dictionary is the indicator that 154 no more symbols are available. 155 156 @param output_sequence: A mutable list to which should be appended 157 tuples C{( eu, val )} where C{eu} is an L{ElementUse} from the set of 158 symbol keys, and C{val} is a value from the corresponding list. A 159 document generated by producing the elements in the given order is 160 expected to validate. 161 162 @return: C{True} iff the model validates. C{symbol_set} and 163 C{output_path} will be unchanged if this returns C{False}. 164 """ 165 raise Exception('ContentState_mixin._validate not implemented in %s' % (type(self),))
166 167
168 -class AttributeUse (pyxb.cscRoot):
169 """A helper class that encapsulates everything we need to know 170 about the way an attribute is used within a binding class. 171 172 Attributes are stored internally as pairs C{(provided, value)}, where 173 C{provided} is a boolean indicating whether a value for the attribute was 174 provided externally, and C{value} is an instance of the attribute 175 datatype. The C{provided} flag is used to determine whether an XML 176 attribute should be added to a created DOM node when generating the XML 177 corresponding to a binding instance. 178 """ 179 180 __name = None 181 """ExpandedName of the attribute""" 182 183 __id = None 184 """Identifier used for this attribute within the owning class""" 185 186 __key = None 187 """Private Python attribute used in instances to hold the attribute value""" 188 189 __dataType = None 190 """The L{pyxb.binding.basis.simpleTypeDefinition} for values of the attribute""" 191 192 __unicodeDefault = None 193 """The default attribute value as a unicode string, or C{None}""" 194 195 __defaultValue = None 196 """The default value as an instance of L{__dataType}, or C{None}""" 197 198 __fixed = False 199 """C{True} if the attribute value cannot be changed""" 200 201 __required = False 202 """C{True} if the attribute must appear in every instance of the type""" 203 204 __prohibited = False 205 """C{True} if the attribute must not appear in any instance of the type""" 206
207 - def __init__ (self, name, id, key, data_type, unicode_default=None, fixed=False, required=False, prohibited=False):
208 """Create an AttributeUse instance. 209 210 @param name: The name by which the attribute is referenced in the XML 211 @type name: L{pyxb.namespace.ExpandedName} 212 213 @param id: The Python identifier for the attribute within the 214 containing L{pyxb.basis.binding.complexTypeDefinition}. This is a 215 public identifier, derived from the local part of the attribute name 216 and modified to be unique, and is usually used as the name of the 217 attribute's inspector method. 218 @type id: C{str} 219 220 @param key: The string used to store the attribute 221 value in the dictionary of the containing 222 L{pyxb.basis.binding.complexTypeDefinition}. This is mangled so 223 that it is unique among and is treated as a Python private member. 224 @type key: C{str} 225 226 @param data_type: The class reference to the subclass of 227 L{pyxb.binding.basis.simpleTypeDefinition} of which the attribute 228 values must be instances. 229 @type data_type: C{type} 230 231 @keyword unicode_default: The default value of the attribute as 232 specified in the schema, or None if there is no default attribute 233 value. The default value (of the keyword) is C{None}. 234 @type unicode_default: C{unicode} 235 236 @keyword fixed: If C{True}, indicates that the attribute, if present, 237 must have the value that was given via C{unicode_default}. The 238 default value is C{False}. 239 @type fixed: C{bool} 240 241 @keyword required: If C{True}, indicates that the attribute must appear 242 in the DOM node used to create an instance of the corresponding 243 L{pyxb.binding.basis.complexTypeDefinition}. The default value is 244 C{False}. No more that one of L{required} and L{prohibited} should be 245 assigned C{True}. 246 @type required: C{bool} 247 248 @keyword prohibited: If C{True}, indicates that the attribute must 249 B{not} appear in the DOM node used to create an instance of the 250 corresponding L{pyxb.binding.basis.complexTypeDefinition}. The 251 default value is C{False}. No more that one of L{required} and 252 L{prohibited} should be assigned C{True}. 253 @type prohibited: C{bool} 254 255 @raise pyxb.BadTypeValueError: the L{unicode_default} cannot be used 256 to initialize an instance of L{data_type} 257 """ 258 259 self.__name = name 260 self.__id = id 261 self.__key = key 262 self.__dataType = data_type 263 self.__unicodeDefault = unicode_default 264 if self.__unicodeDefault is not None: 265 self.__defaultValue = self.__dataType.Factory(self.__unicodeDefault, _from_xml=True) 266 self.__fixed = fixed 267 self.__required = required 268 self.__prohibited = prohibited
269
270 - def name (self):
271 """The expanded name of the element. 272 273 @rtype: L{pyxb.namespace.ExpandedName} 274 """ 275 return self.__name
276
277 - def defaultValue (self):
278 """The default value of the attribute.""" 279 return self.__defaultValue
280
281 - def fixed (self):
282 """C{True} iff the value of the attribute cannot be changed.""" 283 return self.__fixed
284
285 - def required (self):
286 """C{True} iff the attribute must be assigned a value.""" 287 return self.__required
288
289 - def prohibited (self):
290 """C{True} iff the attribute must not be assigned a value.""" 291 return self.__prohibited
292
293 - def provided (self, ctd_instance):
294 """C{True} iff the given instance has been explicitly given a value 295 for the attribute. 296 297 This is used for things like only generating an XML attribute 298 assignment when a value was originally given (even if that value 299 happens to be the default). 300 """ 301 return self.__getProvided(ctd_instance)
302
303 - def id (self):
304 """Tag used within Python code for the attribute. 305 306 This is not used directly in the default code generation template.""" 307 return self.__id
308
309 - def key (self):
310 """String used as key within object dictionary when storing attribute value.""" 311 return self.__key
312
313 - def dataType (self):
314 """The subclass of L{pyxb.binding.basis.simpleTypeDefinition} of which any attribute value must be an instance.""" 315 return self.__dataType
316
317 - def __getValue (self, ctd_instance):
318 """Retrieve the value information for this attribute in a binding instance. 319 320 @param ctd_instance: The instance object from which the attribute is to be retrieved. 321 @type ctd_instance: subclass of L{pyxb.binding.basis.complexTypeDefinition} 322 @return: C{(provided, value)} where C{provided} is a C{bool} and 323 C{value} is C{None} or an instance of the attribute's datatype. 324 325 """ 326 return getattr(ctd_instance, self.__key, (False, None))
327
328 - def __getProvided (self, ctd_instance):
329 return self.__getValue(ctd_instance)[0]
330
331 - def value (self, ctd_instance):
332 """Get the value of the attribute from the instance.""" 333 return self.__getValue(ctd_instance)[1]
334
335 - def __setValue (self, ctd_instance, new_value, provided):
336 return setattr(ctd_instance, self.__key, (provided, new_value))
337
338 - def reset (self, ctd_instance):
339 """Set the value of the attribute in the given instance to be its 340 default value, and mark that it has not been provided.""" 341 self.__setValue(ctd_instance, self.__defaultValue, False)
342
343 - def addDOMAttribute (self, dom_support, ctd_instance, element):
344 """If this attribute as been set, add the corresponding attribute to the DOM element.""" 345 ( provided, value ) = self.__getValue(ctd_instance) 346 if provided: 347 assert value is not None 348 dom_support.addAttribute(element, self.__name, value.xsdLiteral()) 349 return self
350
351 - def validate (self, ctd_instance):
352 """Validate the instance against the requirements imposed by this 353 attribute use. 354 355 There is no return value; calls raise an exception if the content does 356 not validate. 357 358 @param ctd_instance : An instance of a complex type definition. 359 360 @raise pyxb.ProhibitedAttributeError: when instance has attribute but must not 361 @raise pyxb.MissingAttributeError: when instance lacks attribute but 362 must have it (including when a required fixed-value attribute is 363 missing). 364 @raise pyxb.BindingValidationError: when instance has attribute but its value is not acceptable 365 """ 366 (provided, value) = self.__getValue(ctd_instance) 367 if value is not None: 368 if self.__prohibited: 369 raise pyxb.ProhibitedAttributeError('Value given for prohibited attribute %s' % (self.__name,)) 370 if self.__required and not provided: 371 assert self.__fixed 372 raise pyxb.MissingAttributeError('Fixed required attribute %s was never set' % (self.__name,)) 373 if not self.__dataType._IsValidValue(value): 374 raise pyxb.BindingValidationError('Attribute %s value type %s not %s' % (self.__name, type(value), self.__dataType)) 375 self.__dataType.XsdConstraintsOK(value) 376 else: 377 if self.__required: 378 raise pyxb.MissingAttributeError('Required attribute %s does not have a value' % (self.__name,))
379
380 - def set (self, ctd_instance, new_value):
381 """Set the value of the attribute. 382 383 This validates the value against the data type, creating a new instance if necessary. 384 385 @param ctd_instance: The binding instance for which the attribute 386 value is to be set 387 @type ctd_instance: subclass of L{pyxb.binding.basis.complexTypeDefinition} 388 @param new_value: The value for the attribute 389 @type new_value: An C{xml.dom.Node} instance, or any value that is 390 permitted as the input parameter to the C{Factory} method of the 391 attribute's datatype. 392 """ 393 provided = True 394 from_xml = False 395 if isinstance(new_value, xml.dom.Node): 396 from_xml = True 397 unicode_value = self.__name.getAttribute(new_value) 398 if unicode_value is None: 399 if self.__required: 400 raise pyxb.MissingAttributeError('Required attribute %s from %s not found' % (self.__name, ctd_instance._ExpandedName or type(ctd_instance))) 401 provided = False 402 unicode_value = self.__unicodeDefault 403 if unicode_value is None: 404 # Must be optional and absent 405 provided = False 406 new_value = None 407 else: 408 new_value = unicode_value 409 else: 410 assert new_value is not None 411 if self.__prohibited: 412 raise pyxb.ProhibitedAttributeError('Value given for prohibited attribute %s' % (self.__name,)) 413 if (new_value is not None) and (not isinstance(new_value, self.__dataType)): 414 new_value = self.__dataType.Factory(new_value, _from_xml=from_xml) 415 if self.__fixed and (new_value != self.__defaultValue): 416 raise pyxb.AttributeChangeError('Attempt to change value of fixed attribute %s' % (self.__name,)) 417 self.__setValue(ctd_instance, new_value, provided) 418 return new_value
419
420 - def _description (self, name_only=False, user_documentation=True):
421 if name_only: 422 return str(self.__name) 423 assert issubclass(self.__dataType, basis._TypeBinding_mixin) 424 desc = [ str(self.__id), ': ', str(self.__name), ' (', self.__dataType._description(name_only=True, user_documentation=False), '), ' ] 425 if self.__required: 426 desc.append('required') 427 elif self.__prohibited: 428 desc.append('prohibited') 429 else: 430 desc.append('optional') 431 if self.__defaultValue is not None: 432 desc.append(', ') 433 if self.__fixed: 434 desc.append('fixed') 435 else: 436 desc.append('default') 437 desc.extend(['=', self.__unicodeDefault ]) 438 return ''.join(desc)
439
440 -class ElementUse (ContentState_mixin, ContentModel_mixin):
441 """Aggregate the information relevant to an element of a complex type. 442 443 This includes the L{original tag name<name>}, the spelling of L{the 444 corresponding object in Python <id>}, an L{indicator<isPlural>} of whether 445 multiple instances might be associated with the field, and other relevant 446 information. 447 """ 448
449 - def name (self):
450 """The expanded name of the element. 451 452 @rtype: L{pyxb.namespace.ExpandedName} 453 """ 454 return self.__name
455 __name = None 456
457 - def id (self):
458 """The string name of the binding class field used to hold the element 459 values. 460 461 This is the user-visible name, and excepting disambiguation will be 462 equal to the local name of the element.""" 463 return self.__id
464 __id = None 465 466 # The dictionary key used to identify the value of the element. The value 467 # is the same as that used for private member variables in the binding 468 # class within which the element declaration occurred. 469 __key = None 470
471 - def elementBinding (self):
472 """The L{basis.element} instance identifying the information 473 associated with the element declaration. 474 """ 475 return self.__elementBinding
476 - def _setElementBinding (self, element_binding):
477 # Set the element binding for this use. Only visible at all because 478 # we have to define the uses before the element instances have been 479 # created. 480 self.__elementBinding = element_binding 481 return self
482 __elementBinding = None 483
484 - def isPlural (self):
485 """True iff the content model indicates that more than one element 486 can legitimately belong to this use. 487 488 This includes elements in particles with maxOccurs greater than one, 489 and when multiple elements with the same NCName are declared in the 490 same type. 491 """ 492 return self.__isPlural
493 __isPlural = False 494
495 - def __init__ (self, name, id, key, is_plural, element_binding=None):
496 """Create an ElementUse instance. 497 498 @param name: The name by which the element is referenced in the XML 499 @type name: L{pyxb.namespace.ExpandedName} 500 501 @param id: The Python name for the element within the containing 502 L{pyxb.basis.binding.complexTypeDefinition}. This is a public 503 identifier, albeit modified to be unique, and is usually used as the 504 name of the element's inspector method or property. 505 @type id: C{str} 506 507 @param key: The string used to store the element 508 value in the dictionary of the containing 509 L{pyxb.basis.binding.complexTypeDefinition}. This is mangled so 510 that it is unique among and is treated as a Python private member. 511 @type key: C{str} 512 513 @param is_plural: If C{True}, documents for the corresponding type may 514 have multiple instances of this element. As a consequence, the value 515 of the element will be a list. If C{False}, the value will be C{None} 516 if the element is absent, and a reference to an instance of the type 517 identified by L{pyxb.binding.basis.element.typeDefinition} if present. 518 @type is_plural: C{bool} 519 520 @param element_binding: Reference to the class that serves as the 521 binding for the element. 522 """ 523 self.__name = name 524 self.__id = id 525 self.__key = key 526 self.__isPlural = is_plural 527 self.__elementBinding = element_binding
528
529 - def defaultValue (self):
530 """Return the default value for this element. 531 532 @todo: Right now, this returns C{None} for non-plural and an empty 533 list for plural elements. Need to support schema-specified default 534 values for simple-type content. 535 """ 536 if self.isPlural(): 537 return [] 538 return None
539
540 - def value (self, ctd_instance):
541 """Return the value for this use within the given instance.""" 542 return getattr(ctd_instance, self.__key, self.defaultValue())
543
544 - def reset (self, ctd_instance):
545 """Set the value for this use in the given element to its default.""" 546 setattr(ctd_instance, self.__key, self.defaultValue()) 547 return self
548
549 - def set (self, ctd_instance, value):
550 """Set the value of this element in the given instance.""" 551 if value is None: 552 return self.reset(ctd_instance) 553 assert self.__elementBinding is not None 554 if basis._TypeBinding_mixin._PerformValidation: 555 value = self.__elementBinding.compatibleValue(value, is_plural=self.isPlural()) 556 setattr(ctd_instance, self.__key, value) 557 ctd_instance._addContent(value, self.__elementBinding) 558 return self
559
560 - def setOrAppend (self, ctd_instance, value):
561 """Invoke either L{set} or L{append}, depending on whether the element 562 use is plural.""" 563 if self.isPlural(): 564 return self.append(ctd_instance, value) 565 return self.set(ctd_instance, value)
566
567 - def append (self, ctd_instance, value):
568 """Add the given value as another instance of this element within the binding instance. 569 @raise pyxb.StructuralBadDocumentError: invoked on an element use that is not plural 570 """ 571 if not self.isPlural(): 572 raise pyxb.StructuralBadDocumentError('Cannot append to element with non-plural multiplicity') 573 values = self.value(ctd_instance) 574 if basis._TypeBinding_mixin._PerformValidation: 575 value = self.__elementBinding.compatibleValue(value) 576 values.append(value) 577 ctd_instance._addContent(value, self.__elementBinding) 578 return values
579
580 - def toDOM (self, dom_support, parent, value):
581 """Convert the given value to DOM as an instance of this element. 582 583 @param dom_support: Helper for managing DOM properties 584 @type dom_support: L{pyxb.utils.domutils.BindingDOMSupport} 585 @param parent: The DOM node within which this element should be generated. 586 @type parent: C{xml.dom.Element} 587 @param value: The content for this element. May be text (if the 588 element allows mixed content), or an instance of 589 L{basis._TypeBinding_mixin}. 590 """ 591 if isinstance(value, basis._TypeBinding_mixin): 592 element_binding = self.__elementBinding 593 if value._substitutesFor(element_binding): 594 element_binding = value._element() 595 assert element_binding is not None 596 if element_binding.abstract(): 597 raise pyxb.DOMGenerationError('Element %s is abstract but content %s not associated with substitution group member' % (self.name(), value)) 598 element = dom_support.createChildElement(element_binding.name(), parent) 599 elt_type = element_binding.typeDefinition() 600 val_type = type(value) 601 if isinstance(value, basis.complexTypeDefinition): 602 assert isinstance(value, elt_type) 603 else: 604 if isinstance(value, basis.STD_union) and isinstance(value, elt_type._MemberTypes): 605 val_type = elt_type 606 if dom_support.requireXSIType() or elt_type._RequireXSIType(val_type): 607 val_type_qname = value._ExpandedName.localName() 608 tns_prefix = dom_support.namespacePrefix(value._ExpandedName.namespace()) 609 if tns_prefix is not None: 610 val_type_qname = '%s:%s' % (tns_prefix, val_type_qname) 611 dom_support.addAttribute(element, pyxb.namespace.XMLSchema_instance.createExpandedName('type'), val_type_qname) 612 value._toDOM_csc(dom_support, element) 613 elif isinstance(value, (str, unicode)): 614 element = dom_support.createChildElement(self.name(), parent) 615 element.appendChild(dom_support.document().createTextNode(value)) 616 else: 617 raise pyxb.LogicError('toDOM with unrecognized value type %s: %s' % (type(value), value))
618
619 - def _description (self, name_only=False, user_documentation=True):
620 if name_only: 621 return str(self.__name) 622 desc = [ str(self.__id), ': '] 623 if self.isPlural(): 624 desc.append('MULTIPLE ') 625 desc.append(self.elementBinding()._description(user_documentation=user_documentation)) 626 return ''.join(desc)
627 628 # CM.newState:ElementUse
629 - def newState (self, parent_particle_state):
630 """Implement parent class method.""" 631 return self
632 633 # CS.accepts:ElementUse
634 - def accepts (self, particle_state, instance, value, element_use):
635 ## Implement ContentState_mixin.accepts 636 rv = self._accepts(instance, value, element_use) 637 if rv: 638 particle_state.incrementCount() 639 return rv
640
641 - def _accepts (self, instance, value, element_use):
642 if element_use == self: 643 self.setOrAppend(instance, value) 644 return True 645 if element_use is not None: 646 # If there's a known element, and it's not this one, the content 647 # does not match. This assumes we handled xsi:type and 648 # substitution groups earlier, which may be true. 649 return False 650 if isinstance(value, xml.dom.Node): 651 # If we haven't been able to identify an element for this before, 652 # then we don't recognize it, and will have to treat it as a 653 # wildcard. 654 return False 655 # See if we can accept the value by converting it to something 656 # compatible. 657 try: 658 self.setOrAppend(instance, self.__elementBinding.compatibleValue(value, _convert_string_values=False)) 659 return True 660 except pyxb.BadTypeValueError, e: 661 pass 662 #print '%s %s %s in %s' % (instance, value, element_use, self) 663 return False
664 665 # CM._validate:ElementUse
666 - def _validate (self, symbol_set, output_sequence):
667 values = symbol_set.get(self) 668 #print 'values %s' % (values,) 669 if values is None: 670 return False 671 used = values.pop(0) 672 output_sequence.append( (self, used) ) 673 if 0 == len(values): 674 del symbol_set[self] 675 return True
676
677 - def __str__ (self):
678 return 'EU.%s@%x' % (self.__name, id(self))
679 680
681 -class Wildcard (ContentState_mixin, ContentModel_mixin):
682 """Placeholder for wildcard objects.""" 683 684 NC_any = '##any' #<<< The namespace constraint "##any" 685 NC_not = '##other' #<<< A flag indicating constraint "##other" 686 NC_targetNamespace = '##targetNamespace' #<<< A flag identifying the target namespace 687 NC_local = '##local' #<<< A flag indicating the namespace must be absent 688 689 __namespaceConstraint = None
690 - def namespaceConstraint (self):
691 """A constraint on the namespace for the wildcard. 692 693 Valid values are: 694 695 - L{Wildcard.NC_any} 696 - A tuple ( L{Wildcard.NC_not}, a L{namespace<pyxb.namespace.Namespace>} instance ) 697 - set(of L{namespace<pyxb.namespace.Namespace>} instances) 698 699 Namespaces are represented by their URIs. Absence is 700 represented by C{None}, both in the "not" pair and in the set. 701 """ 702 return self.__namespaceConstraint
703 704 PC_skip = 'skip' 705 """No namespace constraint is applied to the wildcard.""" 706 707 PC_lax = 'lax' 708 """Validate against available uniquely determined declaration.""" 709 710 PC_strict = 'strict' 711 """Validate against declaration or xsi:type, which must be available.""" 712 713 __processContents = None 714 """One of L{PC_skip}, L{PC_lax}, L{PC_strict}."""
715 - def processContents (self):
716 """Indicate how this wildcard's contents should be processed.""" 717 return self.__processContents
718
719 - def __normalizeNamespace (self, nsv):
720 if nsv is None: 721 return None 722 if isinstance(nsv, basestring): 723 nsv = pyxb.namespace.NamespaceForURI(nsv, create_if_missing=True) 724 assert isinstance(nsv, pyxb.namespace.Namespace), 'unexpected non-namespace %s' % (nsv,) 725 return nsv
726
727 - def __init__ (self, *args, **kw):
728 """ 729 @keyword namespace_constraint: Required namespace constraint(s) 730 @keyword process_contents: Required""" 731 732 # Namespace constraint and process contents are required parameters. 733 nsc = kw['namespace_constraint'] 734 if isinstance(nsc, tuple): 735 nsc = (nsc[0], self.__normalizeNamespace(nsc[1])) 736 elif isinstance(nsc, set): 737 nsc = set([ self.__normalizeNamespace(_uri) for _uri in nsc ]) 738 self.__namespaceConstraint = nsc 739 self.__processContents = kw['process_contents']
740
741 - def matches (self, instance, value):
742 """Return True iff the value is a valid match against this wildcard. 743 744 Validation per U{Wildcard allows Namespace Name<http://www.w3.org/TR/xmlschema-1/#cvc-wildcard-namespace>}. 745 """ 746 747 ns = None 748 if isinstance(value, xml.dom.Node): 749 if value.namespaceURI is not None: 750 ns = pyxb.namespace.NamespaceForURI(value.namespaceURI) 751 elif isinstance(value, basis._TypeBinding_mixin): 752 elt = value._element() 753 if elt is not None: 754 ns = elt.name().namespace() 755 else: 756 ns = value._ExpandedName.namespace() 757 else: 758 # Assume that somebody will handle the conversion to xs:anyType 759 pass 760 if isinstance(ns, pyxb.namespace.Namespace) and ns.isAbsentNamespace(): 761 ns = None 762 if self.NC_any == self.__namespaceConstraint: 763 return True 764 if isinstance(self.__namespaceConstraint, tuple): 765 (_, constrained_ns) = self.__namespaceConstraint 766 assert self.NC_not == _ 767 if ns is None: 768 return False 769 if constrained_ns == ns: 770 return False 771 return True 772 return ns in self.__namespaceConstraint
773 774 # CM.newState:Wildcard
775 - def newState (self, parent_particle_state):
776 return self
777 778 # CS.accepts:Wildcard
779 - def accepts (self, particle_state, instance, value, element_use):
780 ## Implement ContentState_mixin.accepts 781 if isinstance(value, xml.dom.Node): 782 value_desc = 'value in %s' % (value.nodeName,) 783 else: 784 value_desc = 'value of type %s' % (type(value),) 785 if not self.matches(instance, value): 786 return False 787 if not isinstance(value, basis._TypeBinding_mixin): 788 print 'NOTE: Created unbound wildcard element from %s' % (value_desc,) 789 assert isinstance(instance.wildcardElements(), list), 'Uninitialized wildcard list in %s' % (instance._ExpandedName,) 790 instance._appendWildcardElement(value) 791 particle_state.incrementCount() 792 return True
793 794 # CM._validate:Wildcard
795 - def _validate (self, symbol_set, output_sequence):
796 # @todo check node against namespace constraint and process contents 797 #print 'WARNING: Accepting node as wildcard match without validating.' 798 wc_values = symbol_set.get(None) 799 if wc_values is None: 800 return False 801 used = wc_values.pop(0) 802 output_sequence.append( (None, used) ) 803 if 0 == len(wc_values): 804 del symbol_set[None] 805 return True
806
807 -class SequenceState (ContentState_mixin):
808 """Represent the state of validation against a sequence of particles.""" 809 810 __sequence = None #<<< A L{GroupSequence} instance 811 __particleState = None #<<< The state corresponding to model within the sequence model 812 __parentParticleState = None #<<< The state corresponding to the model containing the sequence 813 814 __index = -1 #<<< Index in __sequence at which validation is proceeding 815 816 __failed = False 817 """C{True} iff the content provided is in conflict with the sequence 818 requirements. 819 820 Specifically, the model requires content that has not been provided. Set 821 within L{accepts}. This state is sticky.""" 822 823 __satisfied = False 824 """C{True} iff the content provided is consistent with the sequence 825 requirements. 826 827 Specifically, nothing has been presented with conflicts with the model. 828 Set within L{notifyFailure}.""" 829
830 - def __init__ (self, group, parent_particle_state):
831 super(SequenceState, self).__init__(group) 832 self.__sequence = group 833 self.__parentParticleState = parent_particle_state 834 self.__particles = group.particles() 835 self.__index = -1 836 self.__satisfied = False 837 self.__failed = False 838 # Kick this into the first element of the sequence 839 self.notifyFailure(None, False)
840 #print 'SS.CTOR %s: %d elts' % (self, len(self.__particles)) 841 842 # CS.accepts:SequenceState
843 - def accepts (self, particle_state, instance, value, element_use):
844 ## Implement ContentState_mixin.accepts 845 assert self.__parentParticleState == particle_state 846 assert not self.__failed 847 #print 'SS.ACC %s: %s %s %s' % (self, instance, value, element_use) 848 while self.__particleState is not None: 849 (consume, underflow_exc) = self.__particleState.step(instance, value, element_use) 850 if consume: 851 return True 852 if underflow_exc is not None: 853 self.__failed = True 854 raise underflow_exc 855 return False
856 857 # CS._verifyComplete:SequenceState
858 - def _verifyComplete (self, parent_particle_state):
859 while self.__particleState is not None: 860 self.__particleState.verifyComplete()
861 862 # CS.notifyFailure:SequenceState
863 - def notifyFailure (self, sub_state, particle_ok):
864 self.__index += 1 865 self.__particleState = None 866 if self.__index < len(self.__particles): 867 self.__particleState = ParticleState(self.__particles[self.__index], self) 868 else: 869 self.__satisfied = particle_ok 870 if particle_ok: 871 self.__parentParticleState.incrementCount()
872 #print 'SS.NF %s: %d %s %s' % (self, self.__index, particle_ok, self.__particleState) 873
874 -class ChoiceState (ContentState_mixin):
875 - def __init__ (self, group, parent_particle_state):
876 self.__parentParticleState = parent_particle_state 877 super(ChoiceState, self).__init__(group) 878 self.__choices = [ ParticleState(_p, self) for _p in group.particles() ] 879 self.__activeChoice = None
880 #print 'CS.CTOR %s: %d choices' % (self, len(self.__choices)) 881 882 # CS.accepts:ChoiceState
883 - def accepts (self, particle_state, instance, value, element_use):
884 ## Implement ContentState_mixin.accepts 885 #print 'CS.ACC %s %s: %s %s %s' % (self, self.__activeChoice, instance, value, element_use) 886 if self.__activeChoice is None: 887 for choice in self.__choices: 888 #print 'CS.ACC %s candidate %s' % (self, choice) 889 try: 890 (consume, underflow_exc) = choice.step(instance, value, element_use) 891 except Exception, e: 892 consume = False 893 underflow_exc = e 894 #print 'CS.ACC %s: candidate %s : %s' % (self, choice, consume) 895 if consume: 896 self.__activeChoice = choice 897 self.__choices = None 898 return True 899 return False 900 (consume, underflow_exc) = self.__activeChoice.step(instance, value, element_use) 901 #print 'CS.ACC %s : active choice %s %s %s' % (self, self.__activeChoice, consume, underflow_exc) 902 if consume: 903 return True 904 if underflow_exc is not None: 905 self.__failed = True 906 raise underflow_exc 907 return False
908 909 # CS._verifyComplete:ChoiceState
910 - def _verifyComplete (self, parent_particle_state):
911 rv = True 912 #print 'CS.VC %s: %s' % (self, self.__activeChoice) 913 if self.__activeChoice is None: 914 # Use self.__activeChoice as the iteration value so that it's 915 # non-None when notifyFailure is invoked. 916 for self.__activeChoice in self.__choices: 917 try: 918 #print 'CS.VC: try %s' % (self.__activeChoice,) 919 self.__activeChoice.verifyComplete() 920 return 921 except Exception, e: 922 pass 923 #print 'Missing components %s' % ("\n".join([ "\n ".join([str(_p2.term()) for _p2 in _p.particle().term().particles()]) for _p in self.__choices ]),) 924 raise pyxb.MissingContentError('choice') 925 self.__activeChoice.verifyComplete()
926 927 # CS.notifyFailure:ChoiceState
928 - def notifyFailure (self, sub_state, particle_ok):
929 #print 'CS.NF %s %s' % (self, particle_ok) 930 if particle_ok and (self.__activeChoice is not None): 931 self.__parentParticleState.incrementCount() 932 pass
933
934 -class AllState (ContentState_mixin):
935 __activeChoice = None 936 __needRetry = False
937 - def __init__ (self, group, parent_particle_state):
938 self.__parentParticleState = parent_particle_state 939 super(AllState, self).__init__(group) 940 self.__choices = set([ ParticleState(_p, self) for _p in group.particles() ])
941 #print 'AS.CTOR %s: %d choices' % (self, len(self.__choices)) 942 943 # CS.accepts:AllState
944 - def accepts (self, particle_state, instance, value, element_use):
945 #print 'AS.ACC %s %s: %s %s %s' % (self, self.__activeChoice, instance, value, element_use) 946 self.__needRetry = True 947 while self.__needRetry: 948 self.__needRetry = False 949 if self.__activeChoice is None: 950 for choice in self.__choices: 951 #print 'AS.ACC %s candidate %s' % (self, choice) 952 try: 953 (consume, underflow_exc) = choice.step(instance, value, element_use) 954 except Exception, e: 955 consume = False 956 underflow_exc = e 957 #print 'AS.ACC %s: candidate %s : %s' % (self, choice, consume) 958 if consume: 959 self.__activeChoice = choice 960 self.__choices.discard(self.__activeChoice) 961 return True 962 return False 963 (consume, underflow_exc) = self.__activeChoice.step(instance, value, element_use) 964 #print 'AS.ACC %s : active choice %s %s %s' % (self, self.__activeChoice, consume, underflow_exc) 965 if consume: 966 return True 967 if underflow_exc is not None: 968 self.__failed = True 969 raise underflow_exc 970 return False
971 972 # CS._verifyComplete:AllState
973 - def _verifyComplete (self, parent_particle_state):
974 #print 'AS.VC %s: %s, %d left' % (self, self.__activeChoice, len(self.__choices)) 975 if self.__activeChoice is not None: 976 self.__activeChoice.verifyComplete() 977 while self.__choices: 978 self.__activeChoice = self.__choices.pop() 979 self.__activeChoice.verifyComplete()
980 981 # CS.notifyFailure:AllState
982 - def notifyFailure (self, sub_state, particle_ok):
983 #print 'AS.NF %s %s' % (self, particle_ok) 984 self.__needRetry = True 985 self.__activeChoice = None 986 if particle_ok and (0 == len(self.__choices)): 987 self.__parentParticleState.incrementCount()
988
989 -class ParticleState (pyxb.cscRoot):
990 991 __parentState = None 992 """The L{ContentState_mixin} which contains the mode for which this is state.""" 993 994 __termState = None 995 """A L{ContentState_mixin} instance for one occurrence of this particle's term.""" 996 997 __tryAccept = None 998 """A flag indicating whether a proposed value should be applied to the 999 state by L{step}.""" 1000
1001 - def __init__ (self, particle, parent_state=None):
1002 self.__particle = particle 1003 self.__parentState = parent_state 1004 self.__count = -1 1005 #print 'PS.CTOR %s: particle %s' % (self, particle) 1006 self.incrementCount()
1007 1008 __particle = None 1009 """The L{ParticleModel} for which this represents state.""" 1010
1011 - def particle (self):
1012 """The L{ParticleModel} for which this represents state.""" 1013 return self.__particle
1014 1015 __count = None 1016 """The number of times this particle's term has been matched.""" 1017
1018 - def incrementCount (self):
1019 """Reset for a new occurrence of the particle's term.""" 1020 #print 'PS.IC %s' % (self,) 1021 self.__count += 1 1022 self.__termState = self.__particle.term().newState(self) 1023 self.__tryAccept = True
1024
1025 - def verifyComplete (self):
1026 """Check whether the particle's occurrence constraints are satisfied. 1027 1028 @raise pyxb.MissingContentError: Particle requires additional content to be satisfied.""" 1029 1030 # @TODO@ Set a flag so we can make verifyComplete safe to call 1031 # multiple times? 1032 #print 'PS.VC %s entry' % (self,) 1033 1034 # If we're not satisfied, check the term: that might do it. 1035 if not self.__particle.satisfiesOccurrences(self.__count): 1036 self.__termState._verifyComplete(self) 1037 1038 # If we're still not satisfied, raise an error 1039 if not self.__particle.satisfiesOccurrences(self.__count): 1040 #print 'PS.VC %s incomplete' % (self,) 1041 raise pyxb.MissingContentError('incomplete') 1042 1043 # If we are satisfied, tell the parent 1044 if self.__parentState is not None: 1045 self.__parentState.notifyFailure(self, True)
1046
1047 - def step (self, instance, value, element_use):
1048 """Attempt to apply the value as a new instance of the particle's term. 1049 1050 The L{ContentState_mixin} created for the particle's term is consulted 1051 to determine whether the instance can accept the given value. If so, 1052 the particle's maximum occurrence limit is checked; if not, and the 1053 particle has a parent state, it is informed of the failure. 1054 1055 @param instance: An instance of a subclass of 1056 {basis.complexTypeDefinition}, into which the provided value will be 1057 stored if it is consistent with the current model state. 1058 1059 @param value: The value that is being validated against the state. 1060 1061 @param element_use: An optional L{ElementUse} instance that specifies 1062 the element to which the value corresponds. This will be available 1063 when the value is extracted by parsing a document, but will be absent 1064 if the value was passed as a constructor positional parameter. 1065 1066 @return: C{( consumed, underflow_exc )} A tuple where the first element 1067 is C{True} iff the provided value was accepted in the current state. 1068 When this first element is C{False}, the second element will be 1069 C{None} if the particle's occurrence requirements have been met, and 1070 is an instance of C{MissingElementError} if the observed number of 1071 terms is less than the minimum occurrence count. Depending on 1072 context, the caller may raise this exception, or may try an 1073 alternative content model. 1074 1075 @raise pyxb.UnexpectedElementError: if the value satisfies the particle, 1076 but having done so exceeded the allowable number of instances of the 1077 term. 1078 """ 1079 1080 #print 'PS.STEP %s: %s %s %s' % (self, instance, value, element_use) 1081 1082 # Only try if we're not already at the upper limit on occurrences 1083 consumed = False 1084 underflow_exc = None 1085 1086 # We can try the value against the term if we aren't at the maximum 1087 # count for the term. Also, if we fail to consume, but as a side 1088 # effect of the test the term may have reset itself, we can try again. 1089 self.__tryAccept = True 1090 while self.__tryAccept and (self.__count != self.__particle.maxOccurs()): 1091 self.__tryAccept = False 1092 consumed = self.__termState.accepts(self, instance, value, element_use) 1093 #print 'PS.STEP %s: ta %s %s' % (self, self.__tryAccept, consumed) 1094 self.__tryAccept = self.__tryAccept and (not consumed) 1095 #print 'PS.STEP %s: %s' % (self, consumed) 1096 if consumed: 1097 if not self.__particle.meetsMaximum(self.__count): 1098 raise pyxb.UnexpectedElementError('too many') 1099 else: 1100 if self.__parentState is not None: 1101 self.__parentState.notifyFailure(self, self.__particle.satisfiesOccurrences(self.__count)) 1102 if not self.__particle.meetsMinimum(self.__count): 1103 # @TODO@ Use better exception; changing this will require 1104 # changing some unit tests. 1105 underflow_exc = pyxb.MissingElementError(content=value, container=instance) 1106 return (consumed, underflow_exc)
1107
1108 - def __str__ (self):
1109 particle = self.__particle 1110 return 'ParticleState(%d:%d,%s:%s)@%x' % (self.__count, particle.minOccurs(), particle.maxOccurs(), particle.term(), id(self))
1111
1112 -class ParticleModel (ContentModel_mixin):
1113 """Content model dealing with particles: terms with occurrence restrictions""" 1114 1115 __minOccurs = None
1116 - def minOccurs (self):
1117 """The minimum number of times the term must occur. 1118 1119 This will be a non-negative integer.""" 1120 return self.__minOccurs
1121 1122 __maxOccurs = None
1123 - def maxOccurs (self):
1124 """The maximum number of times the term may occur. 1125 1126 This will be a positive integer, or C{None} indicating an unbounded 1127 number of occurrences.""" 1128 return self.__maxOccurs
1129 1130 __term = None 1131 """The L{ContentModel_mixin} for a single occurrence."""
1132 - def term (self):
1133 """The term for a single occurrence.""" 1134 return self.__term
1135
1136 - def meetsMaximum (self, count):
1137 """@return: C{True} iff there is no maximum on term occurrence, or the 1138 provided count does not exceed that maximum""" 1139 return (self.__maxOccurs is None) or (count <= self.__maxOccurs)
1140
1141 - def meetsMinimum (self, count):
1142 """@return: C{True} iff the provided count meets the minimum number of 1143 occurrences""" 1144 return count >= self.__minOccurs
1145
1146 - def satisfiesOccurrences (self, count):
1147 """@return: C{True} iff the provided count satisfies the occurrence 1148 requirements""" 1149 return self.meetsMinimum(count) and self.meetsMaximum(count)
1150
1151 - def __init__ (self, term, min_occurs=1, max_occurs=1):
1152 self.__term = term 1153 self.__minOccurs = min_occurs 1154 self.__maxOccurs = max_occurs
1155 1156 # CM.newState:ParticleModel
1157 - def newState (self):
1158 return ParticleState(self)
1159
1160 - def validate (self, symbol_set):
1161 """Determine whether the particle requirements are satisfiable by the 1162 given symbol set. 1163 1164 The symbol set represents letters in an alphabet. If those letters 1165 can be combined in a way that satisfies the regular expression 1166 expressed in the model, a satisfying sequence is returned and the 1167 symbol set is reduced by the letters used to form the sequence. If 1168 the content model cannot be satisfied, C{None} is returned and the 1169 symbol set remains unchanged. 1170 1171 @param symbol_set: A map from L{ElementUse} instances to a list of 1172 values. The order of the values corresponds to the order in which 1173 they should appear. A key of C{None} identifies values that are 1174 stored as wildcard elements. Values are removed from the lists as 1175 they are used; when the last value of a list is removed, its key is 1176 removed from the map. Thus an empty dictionary is the indicator that 1177 no more symbols are available. 1178 1179 @return: returns C{None}, or a list of tuples C{( eu, val )} where 1180 C{eu} is an L{ElementUse} from the set of symbol keys, and C{val} is a 1181 value from the corresponding list. 1182 """ 1183 1184 output_sequence = [] 1185 #print 'Start: %d %s %s : %s' % (self.__minOccurs, self.__maxOccurs, self.__term, symbol_set) 1186 result = self._validate(symbol_set, output_sequence) 1187 #print 'End: %s %s %s' % (result, symbol_set, output_sequence) 1188 if result: 1189 return (symbol_set, output_sequence) 1190 return None
1191 1192 # CM._validate:ParticleModel
1193 - def _validate (self, symbol_set, output_sequence):
1194 symbol_set_mut = self._validateCloneSymbolSet(symbol_set) 1195 output_sequence_mut = self._validateCloneOutputSequence(output_sequence) 1196 count = 0 1197 #print 'VAL start %s: %d %s' % (self.__term, self.__minOccurs, self.__maxOccurs) 1198 last_size = len(output_sequence_mut) 1199 while (count != self.__maxOccurs) and self.__term._validate(symbol_set_mut, output_sequence_mut): 1200 #print 'VAL %s old cnt %d, left %s' % (self.__term, count, symbol_set_mut) 1201 this_size = len(output_sequence_mut) 1202 if this_size == last_size: 1203 # Validated without consuming anything. Assume we can 1204 # continue to do so, jump to the minimum, and exit. 1205 if count < self.__minOccurs: 1206 count = self.__minOccurs 1207 break 1208 count += 1 1209 last_size = this_size 1210 result = self.satisfiesOccurrences(count) 1211 if (result): 1212 self._validateReplaceResults(symbol_set, symbol_set_mut, output_sequence, output_sequence_mut) 1213 #print 'VAL end PRT %s res %s: %s %s %s' % (self.__term, result, self.__minOccurs, count, self.__maxOccurs) 1214 return result
1215
1216 -class _Group (ContentModel_mixin):
1217 """Base class for content information pertaining to a U{model 1218 group<http://www.w3.org/TR/xmlschema-1/#Model_Groups>}. 1219 1220 There is a specific subclass for each group compositor. 1221 """ 1222 1223 _StateClass = None 1224 """A reference to a L{ContentState_mixin} class that maintains state when 1225 validating an instance of this group.""" 1226 1227 __particles = None 1228 """List of L{ParticleModel}s comprising the group.""" 1229
1230 - def particles (self):
1231 """The sequence of particles comprising the group""" 1232 return self.__particles
1233
1234 - def __init__ (self, *particles):
1235 self.__particles = particles
1236 1237 # CM.newState:_Group 1238 # CM.newState:GroupAll CM.newState:GroupSequence CM.newState:GroupChoice
1239 - def newState (self, parent_particle_state):
1240 return self._StateClass(self, parent_particle_state)
1241 1242 # All and Sequence share the same validation code, so it's up here. 1243 # CM._validate:GroupAll CM._validate:GroupSequence
1244 - def _validate (self, symbol_set, output_sequence):
1245 symbol_set_mut = self._validateCloneSymbolSet(symbol_set) 1246 output_sequence_mut = self._validateCloneOutputSequence(output_sequence) 1247 for p in self.particles(): 1248 if not p._validate(symbol_set_mut, output_sequence_mut): 1249 return False 1250 self._validateReplaceResults(symbol_set, symbol_set_mut, output_sequence, output_sequence_mut) 1251 return True
1252 1253
1254 -class GroupChoice (_Group):
1255 _StateClass = ChoiceState 1256 1257 # CM._validate:GroupChoice
1258 - def _validate (self, symbol_set, output_sequence):
1259 # Only reset the state variables on partial success (or on entry), 1260 # when they've been "corrupted" from copies of the input. 1261 reset_mutables = True 1262 for p in self.particles(): 1263 if reset_mutables: 1264 symbol_set_mut = self._validateCloneSymbolSet(symbol_set) 1265 output_sequence_mut = self._validateCloneOutputSequence(output_sequence) 1266 if p._validate(symbol_set_mut, output_sequence_mut): 1267 self._validateReplaceResults(symbol_set, symbol_set_mut, output_sequence, output_sequence_mut) 1268 return True 1269 # If we succeeded partially but not completely, reset the state 1270 # variables 1271 reset_mutables = len(output_sequence) != len(output_sequence_mut) 1272 return False
1273
1274 -class GroupAll (_Group):
1275 _StateClass = AllState
1276
1277 -class GroupSequence (_Group):
1278 _StateClass = SequenceState
1279 1280 ## Local Variables: 1281 ## fill-column:78 1282 ## End: 1283