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

Source Code for Module pyxb.binding.facets

  1  # Copyright 2009, 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  """Classes related to XMLSchema facets. 
 16   
 17  The definitions herein are from sections U{4.2<http://www.w3.org/TR/xmlschema-2/index.html#rf-facets>} 
 18  and U{4.3<http://www.w3.org/TR/xmlschema-2/index.html#rf-facets>} of 
 19  U{XML Schema Part 2: Datatypes<http://www.w3.org/TR/xmlschema-2/>}. 
 20  Facets are attributes of a datatype that constrain its lexical and 
 21  value spaces. 
 22   
 23  """ 
 24   
 25  from xml.dom import Node 
 26  import pyxb 
 27  import types 
 28  import datatypes 
 29  import basis 
 30  from pyxb.utils import utility 
 31  from pyxb.utils import domutils 
 32  import re 
33 34 -class Facet (pyxb.cscRoot):
35 """The base class for facets. 36 37 This provides association with STDs, a name, and a value for the facet. 38 """ 39 40 _Name = None 41 @classmethod
42 - def Name (self):
43 """The name of a facet is a class constant.""" 44 return self._Name
45 46 __baseTypeDefinition = None
47 - def baseTypeDefinition (self):
48 """The SimpleTypeDefinition component restricted by this facet. 49 50 Note: this is NOT the STD to which the facet belongs, but is 51 usually that STD's base type. I.e., this jumps us through all 52 the containing restrictions and extensions to get to the core 53 type definition.""" 54 return self.__baseTypeDefinition
55 56 __ownerTypeDefinition = None
57 - def ownerTypeDefinition (self):
58 """The SimpleTypeDefinition component to which this facet belongs. 59 60 I.e., the one in which the hasFacet specification was found. 61 This value is None if the facet is not associated with an 62 STD.""" 63 return self.__ownerTypeDefinition
64 65 # The default valueDatatype to use for instances of this class. 66 # This is overridden in subclasses that do not use late value 67 # datatype bindings. 68 _ValueDatatype = None 69 70 # The datatype used for facet values. 71 __valueDatatype = None
72 - def valueDatatype (self):
73 """Get the datatype used to represent values of the facet. 74 75 This usually has nothing to do with the owner datatype; for 76 example, the length facet may apply to any STD but the value 77 of the facet is an integer. In generated bindings this is 78 usually set explicitly in the facet constructor; when 79 processing a schema, it is derived from the value's type 80 definition. 81 """ 82 if self.__valueDatatype is None: 83 assert self.baseTypeDefinition() is not None 84 return self.baseTypeDefinition().pythonSupport() 85 return self.__valueDatatype
86 87 __value = None
88 - def _value (self, v): self.__value = v
89 - def value (self): return self.__value
90 91 __annotation = None
92 - def annotation (self): return self.__annotation
93
94 - def __init__ (self, **kw):
95 """Create a facet instance, initializing it from the keyword parameters.""" 96 super(Facet, self).__init__(**kw) 97 # Can't create base class instances 98 assert Facet != self.__class__ 99 self.setFromKeywords(_reset=True, _constructor=True, **kw)
100
101 - def _setFromKeywords_vb (self, **kw):
102 """Configure values of the facet from a set of keywords. 103 104 This method is pre-extended; subclasses should invoke the 105 parent method after setting their local configuration. 106 107 @keyword _reset: If C{False} or missing, existing values will 108 be retained if they do not appear in the 109 keywords. If C{True}, members not defined in 110 the keywords are set to a default. 111 @keyword base_type_definition: 112 @keyword owner_type_definition: 113 @keyword value_datatype: 114 """ 115 116 if not kw.get('_reset', False): 117 kw.setdefault('base_type_definition', self.__baseTypeDefinition) 118 kw.setdefault('owner_type_definition', self.__ownerTypeDefinition) 119 kw.setdefault('value_datatype', self.__valueDatatype) 120 self.__baseTypeDefinition = kw.get('base_type_definition', None) 121 self.__ownerTypeDefinition = kw.get('owner_type_definition', None) 122 self.__valueDatatype = kw.get('value_datatype', self._ValueDatatype) 123 # Verify that there's enough information that we should be 124 # able to identify a PST suitable for representing facet 125 # values. 126 assert (self.__valueDatatype is not None) or (self.__baseTypeDefinition is not None) 127 super_fn = getattr(super(Facet, self), '_setFromKeywords_vb', lambda *a,**kw: self) 128 return super_fn(**kw)
129
130 - def setFromKeywords (self, **kw):
131 """Public entrypoint to the _setFromKeywords_vb call hierarchy.""" 132 return self._setFromKeywords_vb(**kw)
133 134 @classmethod
135 - def ClassForFacet (cls, name):
136 """Given the name of a facet, return the Facet subclass that represents it.""" 137 assert cls != Facet 138 if 0 <= name.find(':'): 139 name = name.split(':', 1)[1] 140 facet_class = globals().get('%s_%s' % (cls._FacetPrefix, name), None) 141 if facet_class is None: 142 raise pyxb.LogicError('Unrecognized facet name %s: expect %s' % (name, ','.join([_f._Name for _f in cls.Facets]))) 143 assert facet_class is not None 144 return facet_class
145
146 - def _valueString (self):
147 if isinstance(self, _CollectionFacet_mixin): 148 return ','.join([ str(_i) for _i in self.items() ]) 149 if (self.valueDatatype() is not None) and (self.value() is not None): 150 try: 151 return self.valueDatatype().XsdLiteral(self.value()) 152 except Exception, e: 153 print 'Stringize facet %s produced %s' % (self.Name(), e) 154 raise 155 return str(self.value())
156
157 - def __str__ (self):
158 rv = [] 159 rv.append('%s="%s"' % (self.Name(), self._valueString())) 160 if isinstance(self, _Fixed_mixin) and self.fixed(): 161 rv.append('[fixed]') 162 return ''.join(rv)
163
164 -class ConstrainingFacet (Facet):
165 """One of the facets defined in section 4.3, which provide 166 constraints on the lexical space of a type definition.""" 167 168 # The prefix used for Python classes used for a constraining 169 # facet. Note that this is not the prefix used when generating a 170 # Python class member that specifies a constraining instance, even 171 # if it happens to be the same digraph. 172 _FacetPrefix = 'CF' 173
174 - def __init__ (self, **kw):
175 super(ConstrainingFacet, self).__init__(**kw)
176
177 - def _validateConstraint_vx (self, value):
178 raise pyxb.LogicError("Facet %s does not implement constraints" % (self.Name(),))
179
180 - def validateConstraint (self, value):
181 """Return True iff the given value satisfies the constraint represented by this facet instance. 182 183 The actual test is delegated to the subclasses.""" 184 return self._validateConstraint_vx(value)
185
186 - def __setFromKeywords(self, **kw):
187 kwv = kw.get('value', None) 188 if kwv is not None: 189 if not isinstance(kwv, self.valueDatatype()): 190 kwv = self.valueDatatype()(kwv) 191 self._value(kwv)
192
193 - def _setFromKeywords_vb (self, **kw):
194 """Extend base class. 195 196 Additional keywords: 197 * value 198 """ 199 # NB: This uses post-extension because it makes reference to the value_data_type 200 super_fn = getattr(super(ConstrainingFacet, self), '_setFromKeywords_vb', lambda *a,**kw: self) 201 rv = super_fn(**kw) 202 self.__setFromKeywords(**kw) 203 return rv
204
205 -class _LateDatatype_mixin (pyxb.cscRoot):
206 """Marker class to indicate that the facet instance must be told 207 its datatype when it is constructed. 208 209 This is necessary for facets like L{CF_minInclusive} and 210 L{CF_minExclusive}, for which the value is determined by the base 211 type definition of the associated STD. In some cases the value 212 that must be used in the facet cannot be represented in the Python 213 type used for the facet; see L{LateDatatypeBindsSuperclass}. 214 """ 215 216 _LateDatatypeBindsSuperclass = None 217 """The class variable that indicates that the Subclasses must 218 override this variable with a value of C{True} or C{False}. The 219 value is C{True} iff the value used for the facet is not within 220 the value space of the corresponding value datatype; for example, 221 L{CF_minExclusive}.""" 222 223 224 @classmethod
226 """Return true if false if the proposed datatype should be 227 used, or True if the base type definition of the proposed 228 datatype should be used.""" 229 if cls._LateDatatypeBindsSuperclass is None: 230 raise pyxb.LogicError('Class %s did not set _LateDatatypeBindsSuperclass variable.') 231 return cls._LateDatatypeBindsSuperclass
232 233 @classmethod
234 - def BindingValueDatatype (cls, value_type):
235 """Find the datatype for facet values when this facet is bound 236 to the given value_type. 237 238 If the C{value_type} is an STD, the associated Python support 239 datatype from this value_type scanning up through the base 240 type hierarchy is used. 241 """ 242 243 import pyxb.xmlschema.structures as structures 244 if isinstance(value_type, structures.SimpleTypeDefinition): 245 # Back up until we find something that actually has a 246 # datatype 247 while not value_type.hasPythonSupport(): 248 value_type = value_type.baseTypeDefinition() 249 value_type = value_type.pythonSupport() 250 assert issubclass(value_type, basis.simpleTypeDefinition) 251 if cls.LateDatatypeBindsSuperclass(): 252 value_type = value_type.XsdSuperType() 253 return value_type
254
255 - def bindValueDatatype (self, value_datatype):
256 self.setFromKeywords(_constructor=True, value_datatype=self.BindingValueDatatype(value_datatype))
257
258 -class _Fixed_mixin (pyxb.cscRoot):
259 """Mix-in to a constraining facet that adds support for the 'fixed' property.""" 260 __fixed = None
261 - def fixed (self): return self.__fixed
262
263 - def __setFromKeywords (self, **kw):
264 if kw.get('_reset', False): 265 self.__fixed = None 266 kwv = kw.get('fixed', None) 267 if kwv is not None: 268 self.__fixed = datatypes.boolean(kwv)
269
270 - def _setFromKeywords_vb (self, **kw):
271 """Extend base class. 272 273 Additional keywords: 274 * fixed 275 """ 276 self.__setFromKeywords(**kw) 277 super_fn = getattr(super(_Fixed_mixin, self), '_setFromKeywords_vb', lambda *a,**kw: self) 278 return super_fn(**kw)
279
280 -class _CollectionFacet_mixin (pyxb.cscRoot):
281 """Mix-in to handle facets whose values are collections, not scalars. 282 283 For example, the enumeration and pattern facets maintain a list of 284 enumeration values and patterns, respectively, as their value 285 space. 286 287 Subclasses must define a class variable _CollectionFacet_itemType 288 which is a reference to a class that is used to construct members 289 of the collection. 290 """ 291 292 __items = None
293 - def _setFromKeywords_vb (self, **kw):
294 """Extend base class. 295 296 @keyword _constructor: If C{False} or absent, the object being 297 set is a member of the collection. If 298 C{True}, the object being set is the 299 collection itself. 300 """ 301 if kw.get('_reset', False): 302 self.__items = [] 303 if not kw.get('_constructor', False): 304 #print self._CollectionFacet_itemType 305 self.__items.append(self._CollectionFacet_itemType(facet_instance=self, **kw)) 306 super_fn = getattr(super(_CollectionFacet_mixin, self), '_setFromKeywords_vb', lambda *a,**kw: self) 307 return super_fn(**kw)
308
309 - def _items (self):
310 """The members of the collection, as a reference.""" 311 return self.__items
312
313 - def items (self):
314 """The members of the collection, as a copy.""" 315 return self.__items[:]
316
317 - def iteritems (self):
318 """The members of the collection as an iterator""" 319 return iter(self.__items)
320
321 -class CF_length (ConstrainingFacet, _Fixed_mixin):
322 """A facet that specifies the length of the lexical representation of a value. 323 324 See U{http://www.w3.org/TR/xmlschema-2/#rf-length} 325 """ 326 _Name = 'length' 327 _ValueDatatype = datatypes.nonNegativeInteger 328
329 - def _validateConstraint_vx (self, value):
330 value_length = value.xsdValueLength() 331 return (value_length is None) or (self.value() is None) or (value_length == self.value())
332
333 -class CF_minLength (ConstrainingFacet, _Fixed_mixin):
334 """A facet that constrains the length of the lexical representation of a value. 335 336 See U{http://www.w3.org/TR/xmlschema-2/#rf-minLength} 337 """ 338 _Name = 'minLength' 339 _ValueDatatype = datatypes.nonNegativeInteger 340
341 - def _validateConstraint_vx (self, value):
342 value_length = value.xsdValueLength() 343 return (value_length is None) or (self.value() is None) or (value_length >= self.value())
344
345 -class CF_maxLength (ConstrainingFacet, _Fixed_mixin):
346 """A facet that constrains the length of the lexical representation of a value. 347 348 See U{http://www.w3.org/TR/xmlschema-2/#rf-minLength} 349 """ 350 _Name = 'maxLength' 351 _ValueDatatype = datatypes.nonNegativeInteger 352
353 - def _validateConstraint_vx (self, value):
354 value_length = value.xsdValueLength() 355 return (value_length is None) or (self.value() is None) or (value_length <= self.value())
356 357 import pyxb.utils.xmlre
358 359 -class _PatternElement (utility.PrivateTransient_mixin):
360 """This class represents individual patterns that appear within a CF_pattern collection.""" 361 362 # The compiled regular expression is marked transient because we 363 # normally do development with Python 2.5, and consequently save 364 # the pickled namespace archives that go into the distribution 365 # with that version. Compiled regular expressions in Python 2.5 366 # include a reference to the re._compile method, which does not 367 # exist in Python 2.4. As a result, attempts to load a namespace 368 # which includes types with pattern restrictions fail. 369 __PrivateTransient = set() 370 371 __compiledExpression = None 372 __PrivateTransient.add('compiledExpression') 373 374 __pythonExpression = None 375 376 pattern = None 377 annotation = None
378 - def __init__ (self, pattern=None, value=None, annotation=None, **kw):
379 if pattern is None: 380 assert value is not None 381 pattern = value 382 assert isinstance(pattern, types.StringTypes) 383 self.pattern = pattern 384 self.annotation = annotation 385 self.__pythonExpression = pyxb.utils.xmlre.XMLToPython(pattern)
386 #print 'Translated pattern %s to %s' % (pattern.encode('ascii', 'xmlcharrefreplace'), 387 # self.__pythonExpression.encode('ascii', 'xmlcharrefreplace')) 388
389 - def __str__ (self): return self.pattern
390
391 - def matches (self, text):
392 if self.__compiledExpression is None: 393 self.__compiledExpression = re.compile(self.__pythonExpression) 394 return self.__compiledExpression.match(text)
395
396 -class CF_pattern (ConstrainingFacet, _CollectionFacet_mixin):
397 """A facet that constrains the lexical representation of a value 398 to match one of a set of patterns. 399 400 See U{http://www.w3.org/TR/xmlschema-2/#rf-pattern} 401 402 @note: In PyXB, pattern constraints are ignored for any type with 403 a Python representation that does not derive from C{basestring}. 404 This is due to the difficulty in reconstructing the lexical 405 representation of a non-string type after it has been converted to 406 its value space. 407 408 @todo: On creating new instances of non-string simple types from 409 string representations, we could apply pattern constraints. That 410 would mean checking them prior to invoking the Factory method. 411 """ 412 _Name = 'pattern' 413 _CollectionFacet_itemType = _PatternElement 414 _ValueDatatype = datatypes.string 415 416 __patternElements = None
417 - def patternElements (self): return self.__patternElements
418
419 - def __init__ (self, **kw):
420 super(CF_pattern, self).__init__(**kw) 421 self.__patternElements = []
422
423 - def addPattern (self, **kw):
424 pattern = self._CollectionFacet_itemType(**kw) 425 self.__patternElements.append(pattern) 426 return pattern
427
428 - def _validateConstraint_vx (self, value):
429 # If validation is inhibited, or if the facet hasn't had any 430 # restrictions applied yet, return True. 431 if 0 == len(self.__patternElements): 432 return True 433 if not isinstance(value, basestring): 434 return True 435 for pe in self.__patternElements: 436 if pe.matches(value): 437 return True 438 return False
439
440 -class _EnumerationElement (object):
441 """This class represents individual values that appear within a 442 L{CF_enumeration} collection.""" 443 444 __value = None
445 - def value (self):
446 """The Python value that is used for equality testing 447 against this enumeration. 448 449 This is an instance of L{enumeration.valueDatatype()<CF_enumeration.valueDatatype>}, 450 initialized from the unicodeValue.""" 451 return self.__value
452 453 __tag = None
454 - def tag (self):
455 """The Python identifier used for the named constant representing 456 the enumeration value. 457 458 This should include any desired prefix, since it must be 459 unique within its binding class. If C{None}, no enumeration 460 constant will be generated.""" 461 return self.__tag
462 - def _setTag (self, tag):
463 """Set the tag to be used for this enumeration.""" 464 self.__tag = tag
465 466 __enumeration = None
467 - def enumeration (self):
468 """A reference to the L{CF_enumeration} instance that owns this element.""" 469 return self.__enumeration
470 471 __unicodeValue = None
472 - def unicodeValue (self):
473 """The unicode string that defines the enumeration value.""" 474 return self.__unicodeValue
475
476 - def __init__ (self, enumeration=None, unicode_value=None, 477 description=None, annotation=None, tag=None, 478 **kw):
479 # The preferred keyword is "unicode_value", but when being 480 # generically applied by 481 # structures.SimpleTypeDefinition.__updateFacets, the unicode 482 # value comes in through the keyword "value". Similarly for 483 # "enumeration" and "facet_instance". 484 if unicode_value is None: 485 unicode_value = kw['value'] 486 if enumeration is None: 487 enumeration = kw['facet_instance'] 488 self.__unicodeValue = unicode_value 489 self.__enumeration = enumeration 490 self.__description = description 491 self.__annotation = annotation 492 self.__tag = tag 493 494 assert self.__enumeration is not None 495 496 value_datatype = self.enumeration().valueDatatype() 497 self.__value = value_datatype.Factory(self.unicodeValue(), _validate_constraints=False, _from_xml=True) 498 499 if (self.__description is None) and (self.__annotation is not None): 500 self.__description = str(self.__annotation)
501
502 - def __str__ (self):
503 return utility.QuotedEscaped(self.unicodeValue())
504
505 -class CF_enumeration (ConstrainingFacet, _CollectionFacet_mixin, _LateDatatype_mixin):
506 """Capture a constraint that restricts valid values to a fixed set. 507 508 A STD that has an enumeration restriction should mix-in 509 L{pyxb.binding.basis.enumeration_mixin}, and should have a class 510 variable titled C{_CF_enumeration} that is an instance of this 511 class. 512 513 "unicode" refers to the Unicode string by which the value is 514 represented in XML. 515 516 "tag" refers to the Python member reference associated with the 517 enumeration. The value is derived from the unicode value of the 518 enumeration element and an optional prefix that identifies the 519 owning simple type when the tag is promoted to module-level 520 visibility. 521 522 "value" refers to the Python value held in the tag 523 524 See U{http://www.w3.org/TR/xmlschema-2/#rf-enumeration} 525 """ 526 _Name = 'enumeration' 527 _CollectionFacet_itemType = _EnumerationElement 528 _LateDatatypeBindsSuperclass = False 529 530 __tagToElement = None 531 __valueToElement = None 532 __unicodeToElement = None 533 534 # The prefix to be used when making enumeration tags visible at 535 # the module level. If None, tags are not made visible. 536 __enumPrefix = None 537
538 - def __init__ (self, **kw):
539 super(CF_enumeration, self).__init__(**kw) 540 self.__enumPrefix = kw.get('enum_prefix', self.__enumPrefix) 541 self.__tagToElement = { } 542 self.__valueToElement = { } 543 self.__unicodeToElement = { }
544
545 - def enumPrefix (self):
546 return self.__enumPrefix
547
548 - def elements (self):
549 """@deprecated: Use L{items} or L{iteritems} instead.""" 550 return self.items()
551
552 - def values (self):
553 """Return a list of enumeration values.""" 554 return [ _ee.value() for _ee in self.iteritems() ]
555
556 - def itervalues (self):
557 """Generate the enumeration values.""" 558 for ee in self.iteritems(): 559 yield ee.value()
560
561 - def addEnumeration (self, **kw):
562 kw['enumeration'] = self 563 ee = _EnumerationElement(**kw) 564 if ee.tag in self.__tagToElement: 565 raise pyxb.IncompleteImplementationError('Duplicate enumeration tags') 566 self.__tagToElement[ee.tag()] = ee 567 self.__unicodeToElement[ee.unicodeValue()] = ee 568 value = ee.value() 569 # Not just issubclass(self.valueDatatype(), basis.STD_list); 570 # this may be a union with one of those as a member type. 571 if isinstance(value, list): 572 value = ' '.join([ _v.xsdLiteral() for _v in value ]) 573 self.__valueToElement[value] = ee 574 self._items().append(ee) 575 return value
576
577 - def elementForValue (self, value):
578 """Return the L{_EnumerationElement} instance that has the given value. 579 580 @raise KeyError: the value is not valid for the enumeration.""" 581 return self.__valueToElement[value]
582
583 - def valueForUnicode (self, ustr):
584 """Return the enumeration value corresponding to the given unicode string. 585 586 If ustr is not a valid option for this enumeration, return None.""" 587 rv = self.__unicodeToElement.get(ustr, None) 588 if rv is not None: 589 rv = rv.value() 590 return rv
591
592 - def _validateConstraint_vx (self, value):
593 # If validation is inhibited, or if the facet hasn't had any 594 # restrictions applied yet, return True. 595 if 0 == len(self._items()): 596 return True 597 for ee in self.iteritems(): 598 if ee.value() == value: 599 return True 600 return False
601
602 -class _Enumeration_mixin (pyxb.cscRoot):
603 """Marker class to indicate that the generated binding has enumeration members.""" 604 @classmethod
605 - def valueForUnicode (cls, ustr):
606 return cls._CF_enumeration.valueForUnicode(ustr)
607
608 -class _WhiteSpace_enum (datatypes.NMTOKEN, _Enumeration_mixin):
609 """The enumeration used to constrain the whiteSpace facet""" 610 pass
611 _WhiteSpace_enum._CF_enumeration = CF_enumeration(value_datatype=_WhiteSpace_enum) 612 _WhiteSpace_enum.preserve = _WhiteSpace_enum._CF_enumeration.addEnumeration(unicode_value=u'preserve', tag='preserve') 613 _WhiteSpace_enum.replace = _WhiteSpace_enum._CF_enumeration.addEnumeration(unicode_value=u'replace', tag='replace') 614 _WhiteSpace_enum.collapse = _WhiteSpace_enum._CF_enumeration.addEnumeration(unicode_value=u'collapse', tag='collapse') 615 # NOTE: For correctness we really need to initialize the facet map for 616 # WhiteSpace_enum, even though at the moment it isn't necessary. We 617 # can't right now, because its parent datatypes.NMTOKEN hasn't been 618 # initialized yet 619 _WhiteSpace_enum._InitializeFacetMap(_WhiteSpace_enum._CF_enumeration)
620 621 -class CF_whiteSpace (ConstrainingFacet, _Fixed_mixin):
622 """Specify the value-space interpretation of whitespace. 623 624 See U{http://www.w3.org/TR/xmlschema-2/#rf-whiteSpace} 625 """ 626 _Name = 'whiteSpace' 627 _ValueDatatype = _WhiteSpace_enum 628 629 __TabCRLF_re = re.compile("[\t\n\r]") 630 __MultiSpace_re = re.compile(" +")
631 - def normalizeString (self, value):
632 """Normalize the given string in accordance with the configured whitespace interpretation.""" 633 if self.value() is None: 634 return value 635 if self.value() == _WhiteSpace_enum.preserve: 636 return utility.NormalizeWhitespace(value, preserve=True) 637 if self.value() == _WhiteSpace_enum.replace: 638 return utility.NormalizeWhitespace(value, replace=True) 639 assert self.value() == _WhiteSpace_enum.collapse, 'Unexpected value "%s" for whiteSpace facet' % (self.value(),) 640 return utility.NormalizeWhitespace(value, collapse=True)
641
642 - def _validateConstraint_vx (self, value):
643 """No validation rules for whitespace facet.""" 644 return True
645
646 -class CF_minInclusive (ConstrainingFacet, _Fixed_mixin, _LateDatatype_mixin):
647 """Specify the minimum legal value for the constrained type. 648 649 See U{http://www.w3.org/TR/xmlschema-2/#rf-minInclusive} 650 """ 651 _Name = 'minInclusive' 652 _LateDatatypeBindsSuperclass = False 653
654 - def _validateConstraint_vx (self, value):
655 return (self.value() is None) or (self.value() <= value)
656
657 658 -class CF_maxInclusive (ConstrainingFacet, _Fixed_mixin, _LateDatatype_mixin):
659 """Specify the maximum legal value for the constrained type. 660 661 See U{http://www.w3.org/TR/xmlschema-2/#rf-maxInclusive} 662 """ 663 _Name = 'maxInclusive' 664 _LateDatatypeBindsSuperclass = False 665
666 - def _validateConstraint_vx (self, value):
667 return (self.value() is None) or (self.value() >= value)
668
669 -class CF_minExclusive (ConstrainingFacet, _Fixed_mixin, _LateDatatype_mixin):
670 """Specify the exclusive lower bound of legal values for the constrained type. 671 672 See U{http://www.w3.org/TR/xmlschema-2/#rf-minExclusive} 673 """ 674 _Name = 'minExclusive' 675 _LateDatatypeBindsSuperclass = True 676
677 - def _validateConstraint_vx (self, value):
678 return (self.value() is None) or (self.value() < value)
679
680 -class CF_maxExclusive (ConstrainingFacet, _Fixed_mixin, _LateDatatype_mixin):
681 """Specify the exclusive upper bound of legal values for the constrained type. 682 683 See U{http://www.w3.org/TR/xmlschema-2/#rf-maxExclusive} 684 """ 685 _Name = 'maxExclusive' 686 _LateDatatypeBindsSuperclass = True 687
688 - def _validateConstraint_vx (self, value):
689 return (self.value() is None) or (self.value() > value)
690
691 -class CF_totalDigits (ConstrainingFacet, _Fixed_mixin):
692 """Specify the number of digits in the *value* space of the type. 693 694 See U{http://www.w3.org/TR/xmlschema-2/#rf-totalDigits} 695 """ 696 _Name = 'totalDigits' 697 _ValueDatatype = datatypes.positiveInteger 698
699 - def _validateConstraint_vx (self, value):
700 if self.value() is None: 701 return True 702 n = 0 703 scale = 1 704 match = False 705 v = None 706 while (n <= self.value()) and (not match): 707 v = long(value * scale) 708 match = ((value * scale) == v) 709 if self.value() == n: 710 break 711 n += 1 712 scale *= 10 713 while n < self.value(): 714 n += 1 715 scale *= 10 716 return match and (v is not None) and (abs(v) < scale)
717
718 -class CF_fractionDigits (ConstrainingFacet, _Fixed_mixin):
719 """Specify the number of sub-unit digits in the *value* space of the type. 720 721 See U{http://www.w3.org/TR/xmlschema-2/#rf-fractionDigits} 722 """ 723 _Name = 'fractionDigits' 724 _ValueDatatype = datatypes.nonNegativeInteger 725
726 - def _validateConstraint_vx (self, value):
727 if self.value() is None: 728 return True 729 n = 0 730 scale = 1 731 while n <= self.value(): 732 if ((value * scale) == long(value * scale)): 733 return True 734 n += 1 735 scale *= 10 736 return False
737
738 -class FundamentalFacet (Facet):
739 """A fundamental facet provides information on the value space of the associated type.""" 740 741 _FacetPrefix = 'FF' 742 743 @classmethod
744 - def CreateFromDOM (cls, node, owner_type_definition, base_type_definition=None):
745 facet_class = cls.ClassForFacet(node.getAttribute('name')) 746 rv = facet_class(base_type_definition=base_type_definition, 747 owner_type_definition=owner_type_definition) 748 rv.updateFromDOM(node)
749
750 - def updateFromDOM (self, node):
751 if not node.hasAttribute('name'): 752 raise pyxb.SchemaValidationError('No name attribute in facet') 753 assert node.getAttribute('name') == self.Name() 754 self._updateFromDOM(node)
755
756 - def _updateFromDOM (self, node):
757 try: 758 super(FundamentalFacet, self)._updateFromDOM(node) 759 except AttributeError, e: 760 pass 761 if (self.valueDatatype() is not None) and node.hasAttribute('value'): 762 self._value(self.valueDatatype()(node.getAttribute('value'))) 763 # @todo 764 self.__annotation = None 765 return self
766
767 -class FF_equal (FundamentalFacet):
768 """Specifies that the associated type supports a notion of equality. 769 770 See U{http://www.w3.org/TR/xmlschema-2/#equal} 771 """ 772 773 _Name = 'equal'
774
775 -class FF_ordered (FundamentalFacet):
776 """Specifies that the associated type supports a notion of order. 777 778 See U{http://www.w3.org/TR/xmlschema-2/#rf-ordered} 779 """ 780 781 _LegalValues = ( 'false', 'partial', 'total' ) 782 _Name = 'ordered' 783 _ValueDatatype = datatypes.string 784
785 - def __init__ (self, **kw):
786 # @todo: correct value type definition 787 super(FF_ordered, self).__init__(**kw)
788
789 -class FF_bounded (FundamentalFacet):
790 """Specifies that the associated type supports a notion of bounds. 791 792 See U{http://www.w3.org/TR/xmlschema-2/#rf-bounded} 793 """ 794 795 _Name = 'bounded' 796 _ValueDatatype = datatypes.boolean
797
798 -class FF_cardinality (FundamentalFacet):
799 """Specifies that the associated type supports a notion of length. 800 801 See U{http://www.w3.org/TR/xmlschema-2/#rf-cardinality} 802 """ 803 804 _LegalValues = ( 'finite', 'countably infinite' ) 805 _Name = 'cardinality' 806 _ValueDatatype = datatypes.string
807 - def __init__ (self, **kw):
808 # @todo correct value type definition 809 super(FF_cardinality, self).__init__(value_datatype=datatypes.string, **kw)
810
811 -class FF_numeric (FundamentalFacet):
812 """Specifies that the associated type represents a number. 813 814 See U{http://www.w3.org/TR/xmlschema-2/#rf-numeric} 815 """ 816 817 _Name = 'numeric' 818 _ValueDatatype = datatypes.boolean
819 820 # The fixed set of expected facets 821 ConstrainingFacet.Facets = [ 822 CF_length, CF_minLength, CF_maxLength, CF_pattern, CF_enumeration, 823 CF_whiteSpace, CF_minInclusive, CF_maxInclusive, CF_minExclusive, 824 CF_maxExclusive, CF_totalDigits, CF_fractionDigits ] 825 826 FundamentalFacet.Facets = [ 827 FF_equal, FF_ordered, FF_bounded, FF_cardinality, FF_numeric ] 828 829 Facet.Facets = [] 830 Facet.Facets.extend(ConstrainingFacet.Facets) 831 Facet.Facets.extend(FundamentalFacet.Facets) 832