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 elif new_value is None: 410 if self.__required: 411 raise pyxb.MissingAttributeError('Required attribute %s in %s may not be set to None' % (self.__name, ctd_instance._ExpandedName or type(ctd_instance))) 412 provided = False 413 if provided and self.__prohibited: 414 raise pyxb.ProhibitedAttributeError('Value given for prohibited attribute %s' % (self.__name,)) 415 if (new_value is not None) and (not isinstance(new_value, self.__dataType)): 416 new_value = self.__dataType.Factory(new_value, _from_xml=from_xml) 417 if self.__fixed and (new_value != self.__defaultValue): 418 raise pyxb.AttributeChangeError('Attempt to change value of fixed attribute %s' % (self.__name,)) 419 self.__setValue(ctd_instance, new_value, provided) 420 return new_value
421
422 - def _description (self, name_only=False, user_documentation=True):
423 if name_only: 424 return str(self.__name) 425 assert issubclass(self.__dataType, basis._TypeBinding_mixin) 426 desc = [ str(self.__id), ': ', str(self.__name), ' (', self.__dataType._description(name_only=True, user_documentation=False), '), ' ] 427 if self.__required: 428 desc.append('required') 429 elif self.__prohibited: 430 desc.append('prohibited') 431 else: 432 desc.append('optional') 433 if self.__defaultValue is not None: 434 desc.append(', ') 435 if self.__fixed: 436 desc.append('fixed') 437 else: 438 desc.append('default') 439 desc.extend(['=', self.__unicodeDefault ]) 440 return ''.join(desc)
441
442 -class ElementUse (ContentState_mixin, ContentModel_mixin):
443 """Aggregate the information relevant to an element of a complex type. 444 445 This includes the L{original tag name<name>}, the spelling of L{the 446 corresponding object in Python <id>}, an L{indicator<isPlural>} of whether 447 multiple instances might be associated with the field, and other relevant 448 information. 449 """ 450
451 - def name (self):
452 """The expanded name of the element. 453 454 @rtype: L{pyxb.namespace.ExpandedName} 455 """ 456 return self.__name
457 __name = None 458
459 - def id (self):
460 """The string name of the binding class field used to hold the element 461 values. 462 463 This is the user-visible name, and excepting disambiguation will be 464 equal to the local name of the element.""" 465 return self.__id
466 __id = None 467 468 # The dictionary key used to identify the value of the element. The value 469 # is the same as that used for private member variables in the binding 470 # class within which the element declaration occurred. 471 __key = None 472
473 - def elementBinding (self):
474 """The L{basis.element} instance identifying the information 475 associated with the element declaration. 476 """ 477 return self.__elementBinding
478 - def _setElementBinding (self, element_binding):
479 # Set the element binding for this use. Only visible at all because 480 # we have to define the uses before the element instances have been 481 # created. 482 self.__elementBinding = element_binding 483 return self
484 __elementBinding = None 485
486 - def isPlural (self):
487 """True iff the content model indicates that more than one element 488 can legitimately belong to this use. 489 490 This includes elements in particles with maxOccurs greater than one, 491 and when multiple elements with the same NCName are declared in the 492 same type. 493 """ 494 return self.__isPlural
495 __isPlural = False 496
497 - def __init__ (self, name, id, key, is_plural, element_binding=None):
498 """Create an ElementUse instance. 499 500 @param name: The name by which the element is referenced in the XML 501 @type name: L{pyxb.namespace.ExpandedName} 502 503 @param id: The Python name for the element within the containing 504 L{pyxb.basis.binding.complexTypeDefinition}. This is a public 505 identifier, albeit modified to be unique, and is usually used as the 506 name of the element's inspector method or property. 507 @type id: C{str} 508 509 @param key: The string used to store the element 510 value in the dictionary of the containing 511 L{pyxb.basis.binding.complexTypeDefinition}. This is mangled so 512 that it is unique among and is treated as a Python private member. 513 @type key: C{str} 514 515 @param is_plural: If C{True}, documents for the corresponding type may 516 have multiple instances of this element. As a consequence, the value 517 of the element will be a list. If C{False}, the value will be C{None} 518 if the element is absent, and a reference to an instance of the type 519 identified by L{pyxb.binding.basis.element.typeDefinition} if present. 520 @type is_plural: C{bool} 521 522 @param element_binding: Reference to the class that serves as the 523 binding for the element. 524 """ 525 self.__name = name 526 self.__id = id 527 self.__key = key 528 self.__isPlural = is_plural 529 self.__elementBinding = element_binding
530
531 - def defaultValue (self):
532 """Return the default value for this element. 533 534 @todo: Right now, this returns C{None} for non-plural and an empty 535 list for plural elements. Need to support schema-specified default 536 values for simple-type content. 537 """ 538 if self.isPlural(): 539 return [] 540 return None
541
542 - def value (self, ctd_instance):
543 """Return the value for this use within the given instance.""" 544 return getattr(ctd_instance, self.__key, self.defaultValue())
545
546 - def reset (self, ctd_instance):
547 """Set the value for this use in the given element to its default.""" 548 setattr(ctd_instance, self.__key, self.defaultValue()) 549 return self
550
551 - def set (self, ctd_instance, value):
552 """Set the value of this element in the given instance.""" 553 if value is None: 554 return self.reset(ctd_instance) 555 assert self.__elementBinding is not None 556 if basis._TypeBinding_mixin._PerformValidation: 557 value = self.__elementBinding.compatibleValue(value, is_plural=self.isPlural()) 558 setattr(ctd_instance, self.__key, value) 559 ctd_instance._addContent(value, self.__elementBinding) 560 return self
561
562 - def setOrAppend (self, ctd_instance, value):
563 """Invoke either L{set} or L{append}, depending on whether the element 564 use is plural.""" 565 if self.isPlural(): 566 return self.append(ctd_instance, value) 567 return self.set(ctd_instance, value)
568
569 - def append (self, ctd_instance, value):
570 """Add the given value as another instance of this element within the binding instance. 571 @raise pyxb.StructuralBadDocumentError: invoked on an element use that is not plural 572 """ 573 if not self.isPlural(): 574 raise pyxb.StructuralBadDocumentError('Cannot append to element with non-plural multiplicity') 575 values = self.value(ctd_instance) 576 if basis._TypeBinding_mixin._PerformValidation: 577 value = self.__elementBinding.compatibleValue(value) 578 values.append(value) 579 ctd_instance._addContent(value, self.__elementBinding) 580 return values
581
582 - def toDOM (self, dom_support, parent, value):
583 """Convert the given value to DOM as an instance of this element. 584 585 @param dom_support: Helper for managing DOM properties 586 @type dom_support: L{pyxb.utils.domutils.BindingDOMSupport} 587 @param parent: The DOM node within which this element should be generated. 588 @type parent: C{xml.dom.Element} 589 @param value: The content for this element. May be text (if the 590 element allows mixed content), or an instance of 591 L{basis._TypeBinding_mixin}. 592 """ 593 if isinstance(value, basis._TypeBinding_mixin): 594 element_binding = self.__elementBinding 595 if value._substitutesFor(element_binding): 596 element_binding = value._element() 597 assert element_binding is not None 598 if element_binding.abstract(): 599 raise pyxb.DOMGenerationError('Element %s is abstract but content %s not associated with substitution group member' % (self.name(), value)) 600 element = dom_support.createChildElement(element_binding.name(), parent) 601 elt_type = element_binding.typeDefinition() 602 val_type = type(value) 603 if isinstance(value, basis.complexTypeDefinition): 604 assert isinstance(value, elt_type) 605 else: 606 if isinstance(value, basis.STD_union) and isinstance(value, elt_type._MemberTypes): 607 val_type = elt_type 608 if dom_support.requireXSIType() or elt_type._RequireXSIType(val_type): 609 val_type_qname = value._ExpandedName.localName() 610 tns_prefix = dom_support.namespacePrefix(value._ExpandedName.namespace()) 611 if tns_prefix is not None: 612 val_type_qname = '%s:%s' % (tns_prefix, val_type_qname) 613 dom_support.addAttribute(element, pyxb.namespace.XMLSchema_instance.createExpandedName('type'), val_type_qname) 614 value._toDOM_csc(dom_support, element) 615 elif isinstance(value, (str, unicode)): 616 element = dom_support.createChildElement(self.name(), parent) 617 element.appendChild(dom_support.document().createTextNode(value)) 618 else: 619 raise pyxb.LogicError('toDOM with unrecognized value type %s: %s' % (type(value), value))
620
621 - def _description (self, name_only=False, user_documentation=True):
622 if name_only: 623 return str(self.__name) 624 desc = [ str(self.__id), ': '] 625 if self.isPlural(): 626 desc.append('MULTIPLE ') 627 desc.append(self.elementBinding()._description(user_documentation=user_documentation)) 628 return ''.join(desc)
629 630 # CM.newState:ElementUse
631 - def newState (self, parent_particle_state):
632 """Implement parent class method.""" 633 return self
634 635 # CS.accepts:ElementUse
636 - def accepts (self, particle_state, instance, value, element_use):
637 ## Implement ContentState_mixin.accepts 638 rv = self._accepts(instance, value, element_use) 639 if rv: 640 particle_state.incrementCount() 641 return rv
642
643 - def _accepts (self, instance, value, element_use):
644 if element_use == self: 645 self.setOrAppend(instance, value) 646 return True 647 if element_use is not None: 648 # If there's a known element, and it's not this one, the content 649 # does not match. This assumes we handled xsi:type and 650 # substitution groups earlier, which may be true. 651 return False 652 if isinstance(value, xml.dom.Node): 653 # If we haven't been able to identify an element for this before, 654 # then we don't recognize it, and will have to treat it as a 655 # wildcard. 656 return False 657 # See if we can accept the value by converting it to something 658 # compatible. 659 try: 660 self.setOrAppend(instance, self.__elementBinding.compatibleValue(value, _convert_string_values=False)) 661 return True 662 except pyxb.BadTypeValueError, e: 663 pass 664 #print '%s %s %s in %s' % (instance, value, element_use, self) 665 return False
666 667 # CM._validate:ElementUse
668 - def _validate (self, symbol_set, output_sequence):
669 values = symbol_set.get(self) 670 #print 'values %s' % (values,) 671 if values is None: 672 return False 673 used = values.pop(0) 674 output_sequence.append( (self, used) ) 675 if 0 == len(values): 676 del symbol_set[self] 677 return True
678
679 - def __str__ (self):
680 return 'EU.%s@%x' % (self.__name, id(self))
681 682
683 -class Wildcard (ContentState_mixin, ContentModel_mixin):
684 """Placeholder for wildcard objects.""" 685 686 NC_any = '##any' #<<< The namespace constraint "##any" 687 NC_not = '##other' #<<< A flag indicating constraint "##other" 688 NC_targetNamespace = '##targetNamespace' #<<< A flag identifying the target namespace 689 NC_local = '##local' #<<< A flag indicating the namespace must be absent 690 691 __namespaceConstraint = None
692 - def namespaceConstraint (self):
693 """A constraint on the namespace for the wildcard. 694 695 Valid values are: 696 697 - L{Wildcard.NC_any} 698 - A tuple ( L{Wildcard.NC_not}, a L{namespace<pyxb.namespace.Namespace>} instance ) 699 - set(of L{namespace<pyxb.namespace.Namespace>} instances) 700 701 Namespaces are represented by their URIs. Absence is 702 represented by C{None}, both in the "not" pair and in the set. 703 """ 704 return self.__namespaceConstraint
705 706 PC_skip = 'skip' 707 """No namespace constraint is applied to the wildcard.""" 708 709 PC_lax = 'lax' 710 """Validate against available uniquely determined declaration.""" 711 712 PC_strict = 'strict' 713 """Validate against declaration or xsi:type, which must be available.""" 714 715 __processContents = None 716 """One of L{PC_skip}, L{PC_lax}, L{PC_strict}."""
717 - def processContents (self):
718 """Indicate how this wildcard's contents should be processed.""" 719 return self.__processContents
720
721 - def __normalizeNamespace (self, nsv):
722 if nsv is None: 723 return None 724 if isinstance(nsv, basestring): 725 nsv = pyxb.namespace.NamespaceForURI(nsv, create_if_missing=True) 726 assert isinstance(nsv, pyxb.namespace.Namespace), 'unexpected non-namespace %s' % (nsv,) 727 return nsv
728
729 - def __init__ (self, *args, **kw):
730 """ 731 @keyword namespace_constraint: Required namespace constraint(s) 732 @keyword process_contents: Required""" 733 734 # Namespace constraint and process contents are required parameters. 735 nsc = kw['namespace_constraint'] 736 if isinstance(nsc, tuple): 737 nsc = (nsc[0], self.__normalizeNamespace(nsc[1])) 738 elif isinstance(nsc, set): 739 nsc = set([ self.__normalizeNamespace(_uri) for _uri in nsc ]) 740 self.__namespaceConstraint = nsc 741 self.__processContents = kw['process_contents']
742
743 - def matches (self, instance, value):
744 """Return True iff the value is a valid match against this wildcard. 745 746 Validation per U{Wildcard allows Namespace Name<http://www.w3.org/TR/xmlschema-1/#cvc-wildcard-namespace>}. 747 """ 748 749 ns = None 750 if isinstance(value, xml.dom.Node): 751 if value.namespaceURI is not None: 752 ns = pyxb.namespace.NamespaceForURI(value.namespaceURI) 753 elif isinstance(value, basis._TypeBinding_mixin): 754 elt = value._element() 755 if elt is not None: 756 ns = elt.name().namespace() 757 else: 758 ns = value._ExpandedName.namespace() 759 else: 760 # Assume that somebody will handle the conversion to xs:anyType 761 pass 762 if isinstance(ns, pyxb.namespace.Namespace) and ns.isAbsentNamespace(): 763 ns = None 764 if self.NC_any == self.__namespaceConstraint: 765 return True 766 if isinstance(self.__namespaceConstraint, tuple): 767 (_, constrained_ns) = self.__namespaceConstraint 768 assert self.NC_not == _ 769 if ns is None: 770 return False 771 if constrained_ns == ns: 772 return False 773 return True 774 return ns in self.__namespaceConstraint
775 776 # CM.newState:Wildcard
777 - def newState (self, parent_particle_state):
778 return self
779 780 # CS.accepts:Wildcard
781 - def accepts (self, particle_state, instance, value, element_use):
782 ## Implement ContentState_mixin.accepts 783 if isinstance(value, xml.dom.Node): 784 value_desc = 'value in %s' % (value.nodeName,) 785 else: 786 value_desc = 'value of type %s' % (type(value),) 787 if not self.matches(instance, value): 788 return False 789 if not isinstance(value, basis._TypeBinding_mixin): 790 print 'NOTE: Created unbound wildcard element from %s' % (value_desc,) 791 assert isinstance(instance.wildcardElements(), list), 'Uninitialized wildcard list in %s' % (instance._ExpandedName,) 792 instance._appendWildcardElement(value) 793 particle_state.incrementCount() 794 return True
795 796 # CM._validate:Wildcard
797 - def _validate (self, symbol_set, output_sequence):
798 # @todo check node against namespace constraint and process contents 799 #print 'WARNING: Accepting node as wildcard match without validating.' 800 wc_values = symbol_set.get(None) 801 if wc_values is None: 802 return False 803 used = wc_values.pop(0) 804 output_sequence.append( (None, used) ) 805 if 0 == len(wc_values): 806 del symbol_set[None] 807 return True
808
809 -class SequenceState (ContentState_mixin):
810 """Represent the state of validation against a sequence of particles.""" 811 812 __sequence = None #<<< A L{GroupSequence} instance 813 __particleState = None #<<< The state corresponding to model within the sequence model 814 __parentParticleState = None #<<< The state corresponding to the model containing the sequence 815 816 __index = -1 #<<< Index in __sequence at which validation is proceeding 817 818 __failed = False 819 """C{True} iff the content provided is in conflict with the sequence 820 requirements. 821 822 Specifically, the model requires content that has not been provided. Set 823 within L{accepts}. This state is sticky.""" 824 825 __satisfied = False 826 """C{True} iff the content provided is consistent with the sequence 827 requirements. 828 829 Specifically, nothing has been presented with conflicts with the model. 830 Set within L{notifyFailure}.""" 831
832 - def __init__ (self, group, parent_particle_state):
833 super(SequenceState, self).__init__(group) 834 self.__sequence = group 835 self.__parentParticleState = parent_particle_state 836 self.__particles = group.particles() 837 self.__index = -1 838 self.__satisfied = False 839 self.__failed = False 840 # Kick this into the first element of the sequence 841 self.notifyFailure(None, False)
842 #print 'SS.CTOR %s: %d elts' % (self, len(self.__particles)) 843 844 # CS.accepts:SequenceState
845 - def accepts (self, particle_state, instance, value, element_use):
846 ## Implement ContentState_mixin.accepts 847 assert self.__parentParticleState == particle_state 848 assert not self.__failed 849 #print 'SS.ACC %s: %s %s %s' % (self, instance, value, element_use) 850 while self.__particleState is not None: 851 (consume, underflow_exc) = self.__particleState.step(instance, value, element_use) 852 if consume: 853 return True 854 if underflow_exc is not None: 855 self.__failed = True 856 raise underflow_exc 857 return False
858 859 # CS._verifyComplete:SequenceState
860 - def _verifyComplete (self, parent_particle_state):
861 while self.__particleState is not None: 862 self.__particleState.verifyComplete()
863 864 # CS.notifyFailure:SequenceState
865 - def notifyFailure (self, sub_state, particle_ok):
866 self.__index += 1 867 self.__particleState = None 868 if self.__index < len(self.__particles): 869 self.__particleState = ParticleState(self.__particles[self.__index], self) 870 else: 871 self.__satisfied = particle_ok 872 if particle_ok: 873 self.__parentParticleState.incrementCount()
874 #print 'SS.NF %s: %d %s %s' % (self, self.__index, particle_ok, self.__particleState) 875
876 -class ChoiceState (ContentState_mixin):
877 - def __init__ (self, group, parent_particle_state):
878 self.__parentParticleState = parent_particle_state 879 super(ChoiceState, self).__init__(group) 880 self.__choices = [ ParticleState(_p, self) for _p in group.particles() ] 881 self.__activeChoice = None
882 #print 'CS.CTOR %s: %d choices' % (self, len(self.__choices)) 883 884 # CS.accepts:ChoiceState
885 - def accepts (self, particle_state, instance, value, element_use):
886 ## Implement ContentState_mixin.accepts 887 #print 'CS.ACC %s %s: %s %s %s' % (self, self.__activeChoice, instance, value, element_use) 888 if self.__activeChoice is None: 889 for choice in self.__choices: 890 #print 'CS.ACC %s candidate %s' % (self, choice) 891 try: 892 (consume, underflow_exc) = choice.step(instance, value, element_use) 893 except Exception, e: 894 consume = False 895 underflow_exc = e 896 #print 'CS.ACC %s: candidate %s : %s' % (self, choice, consume) 897 if consume: 898 self.__activeChoice = choice 899 self.__choices = None 900 return True 901 return False 902 (consume, underflow_exc) = self.__activeChoice.step(instance, value, element_use) 903 #print 'CS.ACC %s : active choice %s %s %s' % (self, self.__activeChoice, consume, underflow_exc) 904 if consume: 905 return True 906 if underflow_exc is not None: 907 self.__failed = True 908 raise underflow_exc 909 return False
910 911 # CS._verifyComplete:ChoiceState
912 - def _verifyComplete (self, parent_particle_state):
913 rv = True 914 #print 'CS.VC %s: %s' % (self, self.__activeChoice) 915 if self.__activeChoice is None: 916 # Use self.__activeChoice as the iteration value so that it's 917 # non-None when notifyFailure is invoked. 918 for self.__activeChoice in self.__choices: 919 try: 920 #print 'CS.VC: try %s' % (self.__activeChoice,) 921 self.__activeChoice.verifyComplete() 922 return 923 except Exception, e: 924 pass 925 #print 'Missing components %s' % ("\n".join([ "\n ".join([str(_p2.term()) for _p2 in _p.particle().term().particles()]) for _p in self.__choices ]),) 926 raise pyxb.MissingContentError('choice') 927 self.__activeChoice.verifyComplete()
928 929 # CS.notifyFailure:ChoiceState
930 - def notifyFailure (self, sub_state, particle_ok):
931 #print 'CS.NF %s %s' % (self, particle_ok) 932 if particle_ok and (self.__activeChoice is not None): 933 self.__parentParticleState.incrementCount() 934 pass
935
936 -class AllState (ContentState_mixin):
937 __activeChoice = None 938 __needRetry = False
939 - def __init__ (self, group, parent_particle_state):
940 self.__parentParticleState = parent_particle_state 941 super(AllState, self).__init__(group) 942 self.__choices = set([ ParticleState(_p, self) for _p in group.particles() ])
943 #print 'AS.CTOR %s: %d choices' % (self, len(self.__choices)) 944 945 # CS.accepts:AllState
946 - def accepts (self, particle_state, instance, value, element_use):
947 #print 'AS.ACC %s %s: %s %s %s' % (self, self.__activeChoice, instance, value, element_use) 948 self.__needRetry = True 949 while self.__needRetry: 950 self.__needRetry = False 951 if self.__activeChoice is None: 952 for choice in self.__choices: 953 #print 'AS.ACC %s candidate %s' % (self, choice) 954 try: 955 (consume, underflow_exc) = choice.step(instance, value, element_use) 956 except Exception, e: 957 consume = False 958 underflow_exc = e 959 #print 'AS.ACC %s: candidate %s : %s' % (self, choice, consume) 960 if consume: 961 self.__activeChoice = choice 962 self.__choices.discard(self.__activeChoice) 963 return True 964 return False 965 (consume, underflow_exc) = self.__activeChoice.step(instance, value, element_use) 966 #print 'AS.ACC %s : active choice %s %s %s' % (self, self.__activeChoice, consume, underflow_exc) 967 if consume: 968 return True 969 if underflow_exc is not None: 970 self.__failed = True 971 raise underflow_exc 972 return False
973 974 # CS._verifyComplete:AllState
975 - def _verifyComplete (self, parent_particle_state):
976 #print 'AS.VC %s: %s, %d left' % (self, self.__activeChoice, len(self.__choices)) 977 if self.__activeChoice is not None: 978 self.__activeChoice.verifyComplete() 979 while self.__choices: 980 self.__activeChoice = self.__choices.pop() 981 self.__activeChoice.verifyComplete()
982 983 # CS.notifyFailure:AllState
984 - def notifyFailure (self, sub_state, particle_ok):
985 #print 'AS.NF %s %s' % (self, particle_ok) 986 self.__needRetry = True 987 self.__activeChoice = None 988 if particle_ok and (0 == len(self.__choices)): 989 self.__parentParticleState.incrementCount()
990
991 -class ParticleState (pyxb.cscRoot):
992 993 __parentState = None 994 """The L{ContentState_mixin} which contains the mode for which this is state.""" 995 996 __termState = None 997 """A L{ContentState_mixin} instance for one occurrence of this particle's term.""" 998 999 __tryAccept = None 1000 """A flag indicating whether a proposed value should be applied to the 1001 state by L{step}.""" 1002
1003 - def __init__ (self, particle, parent_state=None):
1004 self.__particle = particle 1005 self.__parentState = parent_state 1006 self.__count = -1 1007 #print 'PS.CTOR %s: particle %s' % (self, particle) 1008 self.incrementCount()
1009 1010 __particle = None 1011 """The L{ParticleModel} for which this represents state.""" 1012
1013 - def particle (self):
1014 """The L{ParticleModel} for which this represents state.""" 1015 return self.__particle
1016 1017 __count = None 1018 """The number of times this particle's term has been matched.""" 1019
1020 - def incrementCount (self):
1021 """Reset for a new occurrence of the particle's term.""" 1022 #print 'PS.IC %s' % (self,) 1023 self.__count += 1 1024 self.__termState = self.__particle.term().newState(self) 1025 self.__tryAccept = True
1026
1027 - def verifyComplete (self):
1028 """Check whether the particle's occurrence constraints are satisfied. 1029 1030 @raise pyxb.MissingContentError: Particle requires additional content to be satisfied.""" 1031 1032 # @TODO@ Set a flag so we can make verifyComplete safe to call 1033 # multiple times? 1034 #print 'PS.VC %s entry' % (self,) 1035 1036 # If we're not satisfied, check the term: that might do it. 1037 if not self.__particle.satisfiesOccurrences(self.__count): 1038 self.__termState._verifyComplete(self) 1039 1040 # If we're still not satisfied, raise an error 1041 if not self.__particle.satisfiesOccurrences(self.__count): 1042 #print 'PS.VC %s incomplete' % (self,) 1043 raise pyxb.MissingContentError('incomplete') 1044 1045 # If we are satisfied, tell the parent 1046 if self.__parentState is not None: 1047 self.__parentState.notifyFailure(self, True)
1048
1049 - def step (self, instance, value, element_use):
1050 """Attempt to apply the value as a new instance of the particle's term. 1051 1052 The L{ContentState_mixin} created for the particle's term is consulted 1053 to determine whether the instance can accept the given value. If so, 1054 the particle's maximum occurrence limit is checked; if not, and the 1055 particle has a parent state, it is informed of the failure. 1056 1057 @param instance: An instance of a subclass of 1058 {basis.complexTypeDefinition}, into which the provided value will be 1059 stored if it is consistent with the current model state. 1060 1061 @param value: The value that is being validated against the state. 1062 1063 @param element_use: An optional L{ElementUse} instance that specifies 1064 the element to which the value corresponds. This will be available 1065 when the value is extracted by parsing a document, but will be absent 1066 if the value was passed as a constructor positional parameter. 1067 1068 @return: C{( consumed, underflow_exc )} A tuple where the first element 1069 is C{True} iff the provided value was accepted in the current state. 1070 When this first element is C{False}, the second element will be 1071 C{None} if the particle's occurrence requirements have been met, and 1072 is an instance of C{MissingElementError} if the observed number of 1073 terms is less than the minimum occurrence count. Depending on 1074 context, the caller may raise this exception, or may try an 1075 alternative content model. 1076 1077 @raise pyxb.UnexpectedElementError: if the value satisfies the particle, 1078 but having done so exceeded the allowable number of instances of the 1079 term. 1080 """ 1081 1082 #print 'PS.STEP %s: %s %s %s' % (self, instance, value, element_use) 1083 1084 # Only try if we're not already at the upper limit on occurrences 1085 consumed = False 1086 underflow_exc = None 1087 1088 # We can try the value against the term if we aren't at the maximum 1089 # count for the term. Also, if we fail to consume, but as a side 1090 # effect of the test the term may have reset itself, we can try again. 1091 self.__tryAccept = True 1092 while self.__tryAccept and (self.__count != self.__particle.maxOccurs()): 1093 self.__tryAccept = False 1094 consumed = self.__termState.accepts(self, instance, value, element_use) 1095 #print 'PS.STEP %s: ta %s %s' % (self, self.__tryAccept, consumed) 1096 self.__tryAccept = self.__tryAccept and (not consumed) 1097 #print 'PS.STEP %s: %s' % (self, consumed) 1098 if consumed: 1099 if not self.__particle.meetsMaximum(self.__count): 1100 raise pyxb.UnexpectedElementError('too many') 1101 else: 1102 if self.__parentState is not None: 1103 self.__parentState.notifyFailure(self, self.__particle.satisfiesOccurrences(self.__count)) 1104 if not self.__particle.meetsMinimum(self.__count): 1105 # @TODO@ Use better exception; changing this will require 1106 # changing some unit tests. 1107 underflow_exc = pyxb.MissingElementError(content=value, container=instance) 1108 return (consumed, underflow_exc)
1109
1110 - def __str__ (self):
1111 particle = self.__particle 1112 return 'ParticleState(%d:%d,%s:%s)@%x' % (self.__count, particle.minOccurs(), particle.maxOccurs(), particle.term(), id(self))
1113
1114 -class ParticleModel (ContentModel_mixin):
1115 """Content model dealing with particles: terms with occurrence restrictions""" 1116 1117 __minOccurs = None
1118 - def minOccurs (self):
1119 """The minimum number of times the term must occur. 1120 1121 This will be a non-negative integer.""" 1122 return self.__minOccurs
1123 1124 __maxOccurs = None
1125 - def maxOccurs (self):
1126 """The maximum number of times the term may occur. 1127 1128 This will be a positive integer, or C{None} indicating an unbounded 1129 number of occurrences.""" 1130 return self.__maxOccurs
1131 1132 __term = None 1133 """The L{ContentModel_mixin} for a single occurrence."""
1134 - def term (self):
1135 """The term for a single occurrence.""" 1136 return self.__term
1137
1138 - def meetsMaximum (self, count):
1139 """@return: C{True} iff there is no maximum on term occurrence, or the 1140 provided count does not exceed that maximum""" 1141 return (self.__maxOccurs is None) or (count <= self.__maxOccurs)
1142
1143 - def meetsMinimum (self, count):
1144 """@return: C{True} iff the provided count meets the minimum number of 1145 occurrences""" 1146 return count >= self.__minOccurs
1147
1148 - def satisfiesOccurrences (self, count):
1149 """@return: C{True} iff the provided count satisfies the occurrence 1150 requirements""" 1151 return self.meetsMinimum(count) and self.meetsMaximum(count)
1152
1153 - def __init__ (self, term, min_occurs=1, max_occurs=1):
1154 self.__term = term 1155 self.__minOccurs = min_occurs 1156 self.__maxOccurs = max_occurs
1157 1158 # CM.newState:ParticleModel
1159 - def newState (self):
1160 return ParticleState(self)
1161
1162 - def validate (self, symbol_set):
1163 """Determine whether the particle requirements are satisfiable by the 1164 given symbol set. 1165 1166 The symbol set represents letters in an alphabet. If those letters 1167 can be combined in a way that satisfies the regular expression 1168 expressed in the model, a satisfying sequence is returned and the 1169 symbol set is reduced by the letters used to form the sequence. If 1170 the content model cannot be satisfied, C{None} is returned and the 1171 symbol set remains unchanged. 1172 1173 @param symbol_set: A map from L{ElementUse} instances to a list of 1174 values. The order of the values corresponds to the order in which 1175 they should appear. A key of C{None} identifies values that are 1176 stored as wildcard elements. Values are removed from the lists as 1177 they are used; when the last value of a list is removed, its key is 1178 removed from the map. Thus an empty dictionary is the indicator that 1179 no more symbols are available. 1180 1181 @return: returns C{None}, or a list of tuples C{( eu, val )} where 1182 C{eu} is an L{ElementUse} from the set of symbol keys, and C{val} is a 1183 value from the corresponding list. 1184 """ 1185 1186 output_sequence = [] 1187 #print 'Start: %d %s %s : %s' % (self.__minOccurs, self.__maxOccurs, self.__term, symbol_set) 1188 result = self._validate(symbol_set, output_sequence) 1189 #print 'End: %s %s %s' % (result, symbol_set, output_sequence) 1190 if result: 1191 return (symbol_set, output_sequence) 1192 return None
1193 1194 # CM._validate:ParticleModel
1195 - def _validate (self, symbol_set, output_sequence):
1196 symbol_set_mut = self._validateCloneSymbolSet(symbol_set) 1197 output_sequence_mut = self._validateCloneOutputSequence(output_sequence) 1198 count = 0 1199 #print 'VAL start %s: %d %s' % (self.__term, self.__minOccurs, self.__maxOccurs) 1200 last_size = len(output_sequence_mut) 1201 while (count != self.__maxOccurs) and self.__term._validate(symbol_set_mut, output_sequence_mut): 1202 #print 'VAL %s old cnt %d, left %s' % (self.__term, count, symbol_set_mut) 1203 this_size = len(output_sequence_mut) 1204 if this_size == last_size: 1205 # Validated without consuming anything. Assume we can 1206 # continue to do so, jump to the minimum, and exit. 1207 if count < self.__minOccurs: 1208 count = self.__minOccurs 1209 break 1210 count += 1 1211 last_size = this_size 1212 result = self.satisfiesOccurrences(count) 1213 if (result): 1214 self._validateReplaceResults(symbol_set, symbol_set_mut, output_sequence, output_sequence_mut) 1215 #print 'VAL end PRT %s res %s: %s %s %s' % (self.__term, result, self.__minOccurs, count, self.__maxOccurs) 1216 return result
1217
1218 -class _Group (ContentModel_mixin):
1219 """Base class for content information pertaining to a U{model 1220 group<http://www.w3.org/TR/xmlschema-1/#Model_Groups>}. 1221 1222 There is a specific subclass for each group compositor. 1223 """ 1224 1225 _StateClass = None 1226 """A reference to a L{ContentState_mixin} class that maintains state when 1227 validating an instance of this group.""" 1228 1229 __particles = None 1230 """List of L{ParticleModel}s comprising the group.""" 1231
1232 - def particles (self):
1233 """The sequence of particles comprising the group""" 1234 return self.__particles
1235
1236 - def __init__ (self, *particles):
1237 self.__particles = particles
1238 1239 # CM.newState:_Group 1240 # CM.newState:GroupAll CM.newState:GroupSequence CM.newState:GroupChoice
1241 - def newState (self, parent_particle_state):
1242 return self._StateClass(self, parent_particle_state)
1243 1244 # All and Sequence share the same validation code, so it's up here. 1245 # CM._validate:GroupAll CM._validate:GroupSequence
1246 - def _validate (self, symbol_set, output_sequence):
1247 symbol_set_mut = self._validateCloneSymbolSet(symbol_set) 1248 output_sequence_mut = self._validateCloneOutputSequence(output_sequence) 1249 for p in self.particles(): 1250 if not p._validate(symbol_set_mut, output_sequence_mut): 1251 return False 1252 self._validateReplaceResults(symbol_set, symbol_set_mut, output_sequence, output_sequence_mut) 1253 return True
1254 1255
1256 -class GroupChoice (_Group):
1257 _StateClass = ChoiceState 1258 1259 # CM._validate:GroupChoice
1260 - def _validate (self, symbol_set, output_sequence):
1261 # Only reset the state variables on partial success (or on entry), 1262 # when they've been "corrupted" from copies of the input. 1263 reset_mutables = True 1264 for p in self.particles(): 1265 if reset_mutables: 1266 symbol_set_mut = self._validateCloneSymbolSet(symbol_set) 1267 output_sequence_mut = self._validateCloneOutputSequence(output_sequence) 1268 if p._validate(symbol_set_mut, output_sequence_mut): 1269 self._validateReplaceResults(symbol_set, symbol_set_mut, output_sequence, output_sequence_mut) 1270 return True 1271 # If we succeeded partially but not completely, reset the state 1272 # variables 1273 reset_mutables = len(output_sequence) != len(output_sequence_mut) 1274 return False
1275
1276 -class GroupAll (_Group):
1277 _StateClass = AllState
1278
1279 -class GroupSequence (_Group):
1280 _StateClass = SequenceState
1281 1282 ## Local Variables: 1283 ## fill-column:78 1284 ## End: 1285