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

Source Code for Module pyxb.binding.datatypes

   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 supporting U{XMLSchema Part 2: Datatypes<http://www/Documentation/W3C/www.w3.org/TR/xmlschema-2/index.html>}. 
  16   
  17  Each L{simple type definition<pyxb.xmlschema.structures.SimpleTypeDefinition>} component 
  18  instance is paired with at most one L{basis.simpleTypeDefinition} 
  19  class, which is a subclass of a Python type augmented with facets and 
  20  other constraining information.  This file contains the definitions of 
  21  these types. 
  22   
  23  We want the simple datatypes to be efficient Python values, but to 
  24  also hold specific constraints that don't apply to the Python types. 
  25  To do this, we subclass each PST.  Primitive PSTs inherit from the 
  26  Python type that represents them, and from a 
  27  pyxb.binding.basis.simpleTypeDefinition class which adds in the 
  28  constraint infrastructure.  Derived PSTs inherit from the parent PST. 
  29   
  30  There is an exception to this when the Python type best suited for a 
  31  derived SimpleTypeDefinition differs from the type associated with its 
  32  parent STD: for example, L{xsd:integer<integer>} has a value range 
  33  that requires it be represented by a Python C{long}, but 
  34  L{xsd:int<int>} allows representation by a Python C{int}.  In this 
  35  case, the derived PST class is structured like a primitive type, but 
  36  the PST associated with the STD superclass is recorded in a class 
  37  variable C{_XsdBaseType}. 
  38   
  39  Note the strict terminology: "datatype" refers to a class which is a 
  40  subclass of a Python type, while "type definition" refers to an 
  41  instance of either SimpleTypeDefinition or ComplexTypeDefinition. 
  42   
  43  """ 
  44   
  45  from pyxb.exceptions_ import * 
  46  import types 
  47  import pyxb.namespace 
  48  import pyxb.utils.domutils as domutils 
  49  import pyxb.utils.utility as utility 
  50  import basis 
  51  import re 
  52   
  53  _PrimitiveDatatypes = [] 
  54  _DerivedDatatypes = [] 
  55  _ListDatatypes = [] 
56 57 # We use unicode as the Python type for anything that isn't a normal 58 # primitive type. Presumably, only enumeration and pattern facets 59 # will be applied. 60 -class anySimpleType (basis.simpleTypeDefinition, unicode):
61 """See U{http://www.w3.org/TR/xmlschema-2/#dt-anySimpleType}""" 62 _XsdBaseType = None 63 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('anySimpleType') 64 65 @classmethod
66 - def XsdLiteral (cls, value):
67 return value
68 # anySimpleType is not treated as a primitive, because its variety
69 # must be absent (not atomic). 70 71 -class string (basis.simpleTypeDefinition, unicode):
72 """string. 73 74 U{http://www.w3.org/TR/xmlschema-2/#string}""" 75 _XsdBaseType = anySimpleType 76 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('string') 77 78 @classmethod
79 - def XsdLiteral (cls, value):
80 assert isinstance(value, cls) 81 return value
82 83 @classmethod
84 - def XsdValueLength (cls, value):
85 return len(value)
86 87 _PrimitiveDatatypes.append(string)
88 89 # It is illegal to subclass the bool type in Python, so we subclass 90 # int instead. 91 -class boolean (basis.simpleTypeDefinition, types.IntType):
92 """boolean. 93 94 U{http://www.w3.org/TR/xmlschema-2/#boolean}""" 95 _XsdBaseType = anySimpleType 96 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('boolean') 97 98 @classmethod
99 - def XsdLiteral (cls, value):
100 if value: 101 return 'true' 102 return 'false'
103
104 - def __str__ (self):
105 if self: 106 return 'true' 107 return 'false'
108
109 - def __new__ (cls, *args, **kw):
110 args = cls._ConvertArguments(args, kw) 111 if 0 < len(args): 112 value = args[0] 113 args = args[1:] 114 if value in (1, 0, '1', '0', 'true', 'false'): 115 if value in (1, '1', 'true'): 116 iv = True 117 else: 118 iv = False 119 return super(boolean, cls).__new__(cls, iv, *args, **kw) 120 raise BadTypeValueError('[xsd:boolean] Initializer "%s" not valid for type' % (value,)) 121 return super(boolean, cls).__new__(cls, *args, **kw)
122 123 _PrimitiveDatatypes.append(boolean)
124 125 -class decimal (basis.simpleTypeDefinition, types.FloatType):
126 """decimal. 127 128 U{http://www.w3.org/TR/xmlschema-2/#decimal} 129 130 @todo: The Python base type for this is wrong. Consider 131 U{http://code.google.com/p/mpmath/}. 132 133 """ 134 _XsdBaseType = anySimpleType 135 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('decimal') 136 137 @classmethod
138 - def XsdLiteral (cls, value):
139 return '%s' % (value,)
140 141 _PrimitiveDatatypes.append(decimal)
142 143 -class float (basis.simpleTypeDefinition, types.FloatType):
144 """float. 145 146 U{http://www.w3.org/TR/xmlschema-2/#float}""" 147 _XsdBaseType = anySimpleType 148 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('float') 149 150 @classmethod
151 - def XsdLiteral (cls, value):
152 return '%s' % (value,)
153 154 _PrimitiveDatatypes.append(float)
155 156 -class double (basis.simpleTypeDefinition, types.FloatType):
157 """double. 158 159 U{http://www.w3.org/TR/xmlschema-2/#double}""" 160 _XsdBaseType = anySimpleType 161 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('double') 162 163 @classmethod
164 - def XsdLiteral (cls, value):
165 return '%s' % (value,)
166 167 _PrimitiveDatatypes.append(double) 168 169 import time as python_time 170 import datetime
171 172 -class duration (basis.simpleTypeDefinition, datetime.timedelta):
173 """U{http://www.w3.org/TR/xmlschema-2/#duration} 174 175 This class uses the Python C{datetime.timedelta} class as its 176 underlying representation. This works fine as long as no months 177 or years are involved, and no negative durations are involved. 178 Because the XML Schema value space is so much larger, it is kept 179 distinct from the Python value space, which reduces to integral 180 days, seconds, and microseconds. 181 182 In other words, the implementation of this type is a little 183 shakey. 184 185 """ 186 187 _XsdBaseType = anySimpleType 188 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('duration') 189 190 __Lexical_re = re.compile('^(?P<neg>-?)P((?P<years>\d+)Y)?((?P<months>\d+)M)?((?P<days>\d+)D)?(?P<Time>T((?P<hours>\d+)H)?((?P<minutes>\d+)M)?(((?P<seconds>\d+)(?P<fracsec>\.\d+)?)S)?)?$') 191 192 # We do not use weeks 193 __XSDFields = ( 'years', 'months', 'days', 'hours', 'minutes', 'seconds' ) 194 __PythonFields = ( 'days', 'seconds', 'microseconds', 'minutes', 'hours' ) 195
196 - def negativeDuration (self):
197 return self.__negativeDuration
198 __negativeDuration = None 199
200 - def durationData (self):
201 return self.__durationData
202 __durationData = None 203
204 - def __new__ (cls, *args, **kw):
205 args = cls._ConvertArguments(args, kw) 206 text = args[0] 207 have_kw_update = False 208 if isinstance(text, (str, unicode)): 209 match = cls.__Lexical_re.match(text) 210 if match is None: 211 raise BadTypeValueError('Value "%s" not in %s lexical space' % (text, cls._ExpandedName)) 212 match_map = match.groupdict() 213 if 'T' == match_map.get('Time', None): 214 # Can't have T without additional time information 215 raise BadTypeValueError('Value "%s" not in %s lexical space' % (text, cls._ExpandedName)) 216 217 negative_duration = ('-' == match_map.get('neg', None)) 218 219 fractional_seconds = 0.0 220 if match_map.get('fracsec', None) is not None: 221 fractional_seconds = types.FloatType('0%s' % (match_map['fracsec'],)) 222 usec = types.IntType(1000000 * fractional_seconds) 223 if negative_duration: 224 kw['microseconds'] = - usec 225 else: 226 kw['microseconds'] = usec 227 else: 228 # Discard any bogosity passed in by the caller 229 kw.pop('microsecond', None) 230 231 data = { } 232 for fn in cls.__XSDFields: 233 v = match_map.get(fn, 0) 234 if v is None: 235 v = 0 236 data[fn] = types.IntType(v) 237 if fn in cls.__PythonFields: 238 if negative_duration: 239 kw[fn] = - data[fn] 240 else: 241 kw[fn] = data[fn] 242 data['seconds'] += fractional_seconds 243 have_kw_update = True 244 elif isinstance(text, cls): 245 data = text.durationData() 246 negative_duration = text.negativeDuration() 247 elif isinstance(text, datetime.timedelta): 248 data = { 'days' : text.days, 249 'seconds' : text.seconds + (text.microseconds / 1000000.0) } 250 negative_duration = (0 > data['days']) 251 if negative_duration: 252 data['days'] = 1 - data['days'] 253 data['seconds'] = 24 * 60 * 60.0 - data['seconds'] 254 data['minutes'] = 0 255 data['hours'] = 0 256 if not have_kw_update: 257 rem_time = data['seconds'] 258 use_seconds = rem_time 259 if (0 != (rem_time % 1)): 260 data['microseconds'] = types.IntType(1000000 * (rem_time % 1)) 261 rem_time = rem_time // 1 262 if 60 <= rem_time: 263 data['seconds'] = rem_time % 60 264 rem_time = data['minutes'] + (rem_time // 60) 265 if 60 <= rem_time: 266 data['minutes'] = rem_time % 60 267 rem_time = data['hours'] + (rem_time // 60) 268 data['hours'] = rem_time % 24 269 data['days'] += (rem_time // 24) 270 for fn in cls.__PythonFields: 271 if fn in data: 272 if negative_duration: 273 kw[fn] = - data[fn] 274 else: 275 kw[fn] = data[fn] 276 else: 277 kw.pop(fn, None) 278 kw['microseconds'] = data.pop('microseconds', 0) 279 data['seconds'] += kw['microseconds'] / 1000000.0 280 281 rv = super(duration, cls).__new__(cls, **kw) 282 rv.__durationData = data 283 rv.__negativeDuration = negative_duration 284 return rv
285 286 @classmethod
287 - def XsdLiteral (cls, value):
288 elts = [] 289 if value.negativeDuration(): 290 elts.append('-') 291 elts.append('P') 292 for k in ( 'years', 'months', 'days' ): 293 v = value.__durationData.get(k, 0) 294 if 0 != v: 295 elts.append('%d%s' % (v, k[0].upper())) 296 time_elts = [] 297 for k in ( 'hours', 'minutes' ): 298 v = value.__durationData.get(k, 0) 299 if 0 != v: 300 time_elts.append('%d%s' % (v, k[0].upper())) 301 v = value.__durationData.get('seconds', 0) 302 if 0 != v: 303 time_elts.append('%gS' % (v,)) 304 if 0 < len(time_elts): 305 elts.append('T') 306 elts.extend(time_elts) 307 return ''.join(elts)
308 309 _PrimitiveDatatypes.append(duration)
310 311 -class _PyXBDateTime_base (basis.simpleTypeDefinition):
312 313 __PatternMap = { '%Y' : '(?P<negYear>-?)(?P<year>\d{4,})' 314 , '%m' : '(?P<month>\d{2})' 315 , '%d' : '(?P<day>\d{2})' 316 , '%H' : '(?P<hour>\d{2})' 317 , '%M' : '(?P<minute>\d{2})' 318 , '%S' : '(?P<second>\d{2})(?P<fracsec>\.\d+)?' 319 , '%Z' : '(?P<tzinfo>Z|[-+]\d\d:\d\d)' } 320 @classmethod
321 - def _DateTimePattern (cls, pattern):
322 for (k, v) in cls.__PatternMap.items(): 323 pattern = pattern.replace(k, v) 324 return pattern
325 326 __Fields = ( 'year', 'month', 'day', 'hour', 'minute', 'second' ) 327 328 _DefaultYear = 1983 329 _DefaultMonth = 6 330 _DefaultDay = 18 331 332 @classmethod
333 - def _LexicalToKeywords (cls, text, lexical_re):
334 match = lexical_re.match(text) 335 if match is None: 336 raise BadTypeValueError('Value "%s" not in %s lexical space' % (text, cls._ExpandedName)) 337 match_map = match.groupdict() 338 kw = { } 339 for (k, v) in match_map.iteritems(): 340 if (k in cls.__Fields) and (v is not None): 341 kw[k] = types.IntType(v) 342 if '-' == match_map.get('negYear', None): 343 kw['year'] = - kw['year'] 344 if match_map.get('fracsec', None) is not None: 345 kw['microsecond'] = types.IntType(1000000 * types.FloatType('0%s' % (match_map['fracsec'],))) 346 else: 347 # Discard any bogosity passed in by the caller 348 kw.pop('microsecond', None) 349 if match_map.get('tzinfo', None) is not None: 350 kw['tzinfo'] = pyxb.utils.utility.UTCOffsetTimeZone(match_map['tzinfo'], flip=True) 351 else: 352 kw.pop('tzinfo', None) 353 return kw
354 355 @classmethod
356 - def _SetKeysFromPython_csc (cls, python_value, kw, fields):
357 for f in fields: 358 kw[f] = getattr(python_value, f) 359 return getattr(super(_PyXBDateTime_base, cls), '_SetKeysFromPython_csc', lambda *a,**kw: None)(python_value, kw, fields)
360 361 @classmethod
362 - def _SetKeysFromPython (cls, python_value, kw, fields):
363 return cls._SetKeysFromPython_csc(python_value, kw, fields)
364
365 -class _PyXBDateTimeZone_base (_PyXBDateTime_base):
366 - def hasTimeZone (self):
367 """True iff the time represented included time zone information. 368 369 Whether True or not, the moment denoted by an instance is 370 assumed to be in UTC. That state is expressed in the lexical 371 space iff hasTimeZone is True. 372 """ 373 return self.__hasTimeZone
374 - def _setHasTimeZone (self, has_time_zone):
375 self.__hasTimeZone = has_time_zone
376 __hasTimeZone = False 377 378 @classmethod
379 - def _AdjustForTimezone (cls, kw):
380 tzoffs = kw.pop('tzinfo', None) 381 has_time_zone = kw.pop('_force_timezone', False) 382 if tzoffs is not None: 383 use_kw = kw.copy() 384 use_kw.setdefault('year', cls._DefaultYear) 385 use_kw.setdefault('month', cls._DefaultMonth) 386 use_kw.setdefault('day', cls._DefaultDay) 387 dt = datetime.datetime(tzinfo=tzoffs, **use_kw) 388 dt = tzoffs.fromutc(dt) 389 for k in kw.iterkeys(): 390 kw[k] = getattr(dt, k) 391 has_time_zone = True 392 return has_time_zone
393 394 @classmethod
395 - def _SetKeysFromPython_csc (cls, python_value, kw, fields):
396 if python_value.tzinfo is not None: 397 kw['tzinfo'] = pyxb.utils.utility.UTCOffsetTimeZone(python_value.tzinfo.utcoffset(python_value), flip=True) 398 else: 399 kw.pop('tzinfo', None) 400 return getattr(super(_PyXBDateTimeZone_base, cls), '_SetKeysFromPython_csc', lambda *a,**kw: None)(python_value, kw, fields)
401
402 -class dateTime (_PyXBDateTimeZone_base, datetime.datetime):
403 """U{http://www.w3.org/TR/xmlschema-2/index.html#dateTime} 404 405 This class uses the Python C{datetime.datetime} class as its 406 underlying representation. Note that per the XMLSchema spec, all 407 dateTime objects are in UTC, and that timezone information in the 408 string representation in XML is an indication of the local time 409 zone's offset from UTC. Presence of time zone information in the 410 lexical space is preserved through the value of the L{hasTimeZone()} 411 field. 412 413 @warning: The value space of Python's C{datetime.datetime} class 414 is more restricted than that of C{xs:datetime}. As a specific 415 example, Python does not support negative years or years with more 416 than four digits. For now, the convenience of having an object 417 that is compatible with Python is more important than supporting 418 the full value space. In the future, the choice may be left up to 419 the developer. 420 """ 421 422 _XsdBaseType = anySimpleType 423 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('dateTime') 424 425 __Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%Y-%m-%dT%H:%M:%S%Z?$')) 426 __Fields = ( 'year', 'month', 'day', 'hour', 'minute', 'second', 'microsecond', 'tzinfo' ) 427
428 - def __new__ (cls, *args, **kw):
429 args = cls._ConvertArguments(args, kw) 430 ctor_kw = { } 431 if 1 == len(args): 432 value = args[0] 433 if isinstance(value, types.StringTypes): 434 ctor_kw.update(cls._LexicalToKeywords(value, cls.__Lexical_re)) 435 elif isinstance(value, (datetime.datetime, datetime.date, datetime.time)): 436 cls._SetKeysFromPython(value, ctor_kw, cls.__Fields) 437 if isinstance(value, _PyXBDateTimeZone_base): 438 ctor_kw['_force_timezone'] = True 439 elif isinstance(value, (types.IntType, types.LongType)): 440 raise TypeError('function takes at least 3 arguments (%d given)' % (len(args),)) 441 else: 442 raise BadTypeValueError('Unexpected type %s in %s' % (type(value), cls._ExpandedName)) 443 elif 3 <= len(args): 444 for fi in range(len(cls.__Fields)): 445 fn = cls.__Fields[fi] 446 if fi < len(args): 447 ctor_kw[fn] = args[fi] 448 elif fn in kw: 449 ctor_kw[fn] = kw[fn] 450 kw.pop(fn, None) 451 fi += 1 452 else: 453 raise TypeError('function takes at least 3 arguments (%d given)' % (len(args),)) 454 455 has_time_zone = cls._AdjustForTimezone(ctor_kw) 456 kw.update(ctor_kw) 457 year = kw.pop('year') 458 month = kw.pop('month') 459 day = kw.pop('day') 460 rv = super(dateTime, cls).__new__(cls, year, month, day, **kw) 461 rv._setHasTimeZone(has_time_zone) 462 return rv
463 464 @classmethod
465 - def XsdLiteral (cls, value):
466 iso = value.isoformat() 467 if 0 <= iso.find('.'): 468 iso = iso.rstrip('0') 469 if value.hasTimeZone(): 470 iso += 'Z' 471 return iso
472 473 __UTCZone = pyxb.utils.utility.UTCOffsetTimeZone(0) 474 __LocalZone = pyxb.utils.utility.LocalTimeZone() 475 476 @classmethod
477 - def today (cls):
478 """Return today. 479 480 Just like datetime.datetime.today(), except this one sets a 481 tzinfo field so it's clear the value is UTC.""" 482 return cls(datetime.datetime.now(cls.__UTCZone))
483
484 - def aslocal (self):
485 """Returns a C{datetime.datetime} instance denoting the same 486 time as this instance but adjusted to be in the local time 487 zone. 488 489 @rtype: C{datetime.datetime} (B{NOT} C{xsd.dateTime}) 490 """ 491 return self.replace(tzinfo=self.__UTCZone).astimezone(self.__LocalZone)
492 493 _PrimitiveDatatypes.append(dateTime)
494 495 -class time (_PyXBDateTimeZone_base, datetime.time):
496 """U{http://www.w3.org/TR/xmlschema-2/index.html#time} 497 498 This class uses the Python C{datetime.time} class as its 499 underlying representation. Note that per the XMLSchema spec, all 500 dateTime objects are in UTC, and that timezone information in the 501 string representation in XML is an indication of the local time 502 zone's offset from UTC. Presence of time zone information in the 503 lexical space is preserved through the value of the 504 L{hasTimeZone()} field. 505 """ 506 507 _XsdBaseType = anySimpleType 508 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('time') 509 510 __Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%H:%M:%S%Z?$')) 511 __Fields = ( 'hour', 'minute', 'second', 'microsecond' ) 512
513 - def __new__ (cls, *args, **kw):
514 args = cls._ConvertArguments(args, kw) 515 ctor_kw = { } 516 if 1 <= len(args): 517 value = args[0] 518 if isinstance(value, types.StringTypes): 519 ctor_kw.update(cls._LexicalToKeywords(value, cls.__Lexical_re)) 520 elif isinstance(value, datetime.time): 521 cls._SetKeysFromPython(value, ctor_kw, cls.__Fields) 522 elif isinstance(value, (types.IntType, types.LongType)): 523 for fn in range(min(len(args), len(cls.__Fields))): 524 ctor_kw[cls.__Fields[fn]] = args[fn] 525 else: 526 raise BadTypeValueError('Unexpected type %s' % (type(value),)) 527 528 has_time_zone = cls._AdjustForTimezone(ctor_kw) 529 kw.update(ctor_kw) 530 rv = super(time, cls).__new__(cls, **kw) 531 rv._setHasTimeZone(has_time_zone) 532 return rv
533 534 @classmethod
535 - def XsdLiteral (cls, value):
536 iso = value.isoformat() 537 if 0 <= iso.find('.'): 538 iso = iso.rstrip('0') 539 if value.hasTimeZone(): 540 iso += 'Z' 541 return iso
542 543 _PrimitiveDatatypes.append(time)
544 545 -class _PyXBDateOnly_base (_PyXBDateTime_base, datetime.date):
546 _XsdBaseType = anySimpleType 547 548 __DateFields = ( 'year', 'month', 'day' ) 549 _ISO_beginYear = 0 550 _ISO_endYear = 4 551 _ISO_beginMonth = 5 552 _ISO_endMonth = 7 553 _ISO_beginDay = 8 554 _ISO_endDay = 10 555 _ISOBegin = _ISO_beginYear 556 _ISOEnd = _ISO_endDay 557
558 - def __getattribute__ (self, attr):
559 ga = super(_PyXBDateOnly_base, self).__getattribute__ 560 cls = ga('__class__') 561 if (attr in cls.__DateFields) and not (attr in cls._Fields): 562 raise AttributeError(self, attr) 563 return ga(attr)
564
565 - def __new__ (cls, *args, **kw):
566 args = cls._ConvertArguments(args, kw) 567 ctor_kw = { } 568 ctor_kw['year'] = cls._DefaultYear 569 ctor_kw['month'] = cls._DefaultMonth 570 ctor_kw['day'] = cls._DefaultDay 571 if 1 == len(args): 572 value = args[0] 573 if isinstance(value, types.StringTypes): 574 ctor_kw.update(cls._LexicalToKeywords(value, cls._Lexical_re)) 575 elif isinstance(value, datetime.date): 576 cls._SetKeysFromPython(value, ctor_kw, cls._Fields) 577 elif isinstance(value, (types.IntType, types.LongType)): 578 if (1 != len(cls._Fields)): 579 raise TypeError('function takes exactly %d arguments (%d given)' % (len(cls._Fields), len(args))) 580 ctor_kw[cls._Fields[0]] = value 581 else: 582 raise BadTypeValueError('Unexpected type %s' % (type(value),)) 583 elif len(cls._Fields) == len(args): 584 for fi in range(len(cls._Fields)): 585 ctor_kw[cls._Fields[fi]] = args[fi] 586 else: 587 raise TypeError('function takes exactly %d arguments (%d given)' % (len(cls._Fields), len(args))) 588 589 kw.update(ctor_kw) 590 argv = [] 591 for f in cls.__DateFields: 592 argv.append(kw.pop(f)) 593 return super(_PyXBDateOnly_base, cls).__new__(cls, *argv, **kw)
594 595 @classmethod
596 - def XsdLiteral (cls, value):
597 return value.isoformat()[cls._ISOBegin:cls._ISOEnd]
598
599 -class date (_PyXBDateOnly_base):
600 """U{http://www.w3.org/TR/xmlschema-2/index.html#date} 601 602 This class uses the Python C{datetime.date} class as its 603 underlying representation. 604 """ 605 606 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('date') 607 _Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%Y-%m-%d$')) 608 _Fields = ( 'year', 'month', 'day' )
609 610 _PrimitiveDatatypes.append(date)
611 612 -class gYearMonth (_PyXBDateOnly_base):
613 """U{http://www.w3.org/TR/xmlschema-2/index.html#gYearMonth} 614 615 This class uses the Python C{datetime.date} class as its 616 underlying representation. 617 """ 618 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gYearMonth') 619 _Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%Y-%m$')) 620 _Fields = ( 'year', 'month' ) 621 _ISOEnd = _PyXBDateOnly_base._ISO_endMonth
622 623 _PrimitiveDatatypes.append(gYearMonth)
624 625 -class gYear (_PyXBDateOnly_base):
626 """U{http://www.w3.org/TR/xmlschema-2/index.html#gYear} 627 628 This class uses the Python C{datetime.date} class as its 629 underlying representation. 630 """ 631 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gYear') 632 _Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%Y$')) 633 _Fields = ( 'year', ) 634 _ISOEnd = _PyXBDateOnly_base._ISO_endYear
635 _PrimitiveDatatypes.append(gYear)
636 637 -class gMonthDay (_PyXBDateOnly_base):
638 """U{http://www.w3.org/TR/xmlschema-2/index.html#gMonthDay} 639 640 This class uses the Python C{datetime.date} class as its 641 underlying representation. 642 """ 643 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gMonthDay') 644 _Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%m-%d$')) 645 _Fields = ( 'month', 'day' ) 646 _ISOBegin = _PyXBDateOnly_base._ISO_beginMonth
647 _PrimitiveDatatypes.append(gMonthDay)
648 649 -class gDay (_PyXBDateOnly_base):
650 """U{http://www.w3.org/TR/xmlschema-2/index.html#gDay} 651 652 This class uses the Python C{datetime.date} class as its 653 underlying representation. 654 """ 655 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gDay') 656 _Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%d$')) 657 _Fields = ( 'day', ) 658 _ISOBegin = _PyXBDateOnly_base._ISO_beginDay
659 _PrimitiveDatatypes.append(gDay)
660 661 -class gMonth (_PyXBDateOnly_base):
662 """U{http://www.w3.org/TR/xmlschema-2/index.html#gMonth} 663 664 This class uses the Python C{datetime.date} class as its 665 underlying representation. 666 """ 667 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gMonth') 668 _Lexical_re = re.compile(_PyXBDateTime_base._DateTimePattern('^%m$')) 669 _Fields = ( 'month', ) 670 _ISOBegin = _PyXBDateOnly_base._ISO_beginMonth 671 _ISOEnd = _PyXBDateOnly_base._ISO_endMonth
672 _PrimitiveDatatypes.append(gMonth)
673 674 -class hexBinary (basis.simpleTypeDefinition, types.LongType):
675 _XsdBaseType = anySimpleType 676 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('hexBinary') 677 678 __length = None
679 - def length (self):
680 """Return the length of the value, in octets.""" 681 return self.__length
682 683 @classmethod
684 - def _ConvertString (cls, text):
685 """Convert a sequence of pairs of hex digits into a length (in 686 octets) and a binary value.""" 687 assert isinstance(text, types.StringTypes) 688 value = 0L 689 length = 0 690 while (length < len(text)): 691 v = ord(text[length].lower()) 692 if (ord('0') <= v) and (v <= ord('9')): 693 value = (value << 4) + v - ord('0') 694 elif (ord('a') <= v) and (v <= ord('f')): 695 value = (value << 4) + v - ord('a') + 10 696 else: 697 raise BadTypeValueError('Non-hexadecimal values in %s' % (cls.__class__.__name__,)) 698 length += 1 699 if 0 == length: 700 raise BadTypeValueError('%s must be non-empty string' % (cls.__class__.__name__,)) 701 if (length & 0x01): 702 raise BadTypeValueError('%s value ends mid-octet' % (cls.__class__.__name__,)) 703 return (length >> 1, value)
704 705 @classmethod
706 - def _ConvertValue (cls, value):
707 """Given an integral value, return a pair consisting of the 708 number of octets required to represent the value, and the 709 value.""" 710 length = 0 711 if 0 == value: 712 length = 1 713 else: 714 mv = value 715 while (0 != mv): 716 length += 1 717 mv = mv >> 4 718 length = (length+1) >> 1 719 return (length, value)
720
721 - def __new__ (cls, *args, **kw):
722 args = cls._ConvertArguments(args, kw) 723 value = args[0] 724 rem_args = args[1:] 725 if isinstance(value, types.StringTypes): 726 (length, binary_value) = cls._ConvertString(value) 727 else: 728 (length, binary_value) = cls._ConvertValue(value) 729 rv = super(hexBinary, cls).__new__(cls, binary_value, *rem_args, **kw) 730 rv.__length = length 731 return rv
732 733 @classmethod
734 - def XsdLiteral (cls, value):
735 mv = value 736 length = value.length() 737 pieces = [] 738 while (0 < length): 739 pieces.append('%2.2X' % (mv & 0xFF,)) 740 mv = mv >> 8 741 length -= 1 742 pieces.reverse() 743 return ''.join(pieces)
744 745 @classmethod
746 - def XsdValueLength (cls, value):
747 return value.length()
748 749 _PrimitiveDatatypes.append(hexBinary)
750 751 -class base64Binary (basis.simpleTypeDefinition):
752 """@attention: Not implemented""" 753 _XsdBaseType = anySimpleType 754 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('base64Binary') 755 756 @classmethod
757 - def XsdValueLength (cls, value):
758 raise NotImplementedError('No length calculation for base64Binary')
759 760 _PrimitiveDatatypes.append(base64Binary)
761 762 -class anyURI (basis.simpleTypeDefinition, unicode):
763 _XsdBaseType = anySimpleType 764 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('anyURI') 765 766 @classmethod
767 - def XsdValueLength (cls, value):
768 return len(value)
769 770 @classmethod
771 - def XsdLiteral (cls, value):
772 return unicode(value)
773 774 _PrimitiveDatatypes.append(anyURI)
775 776 -class QName (basis.simpleTypeDefinition, unicode):
777 _XsdBaseType = anySimpleType 778 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('QName') 779 780 @classmethod
781 - def XsdValueLength (cls, value):
782 """Section 4.3.1.3: Legacy length return None to indicate no check""" 783 return None
784 785 __localName = None 786 __prefix = None 787
788 - def prefix (self):
789 """Return the prefix portion of the QName, or None if the name is not qualified.""" 790 if self.__localName is None: 791 self.__resolveLocals() 792 return self.__prefix
793
794 - def localName (self):
795 """Return the local portion of the QName.""" 796 if self.__localName is None: 797 self.__resolveLocals() 798 return self.__localName
799
800 - def __resolveLocals (self):
801 if self.find(':'): 802 (self.__prefix, self.__localName) = self.split(':', 1) 803 else: 804 self.__localName = unicode(self)
805 806 @classmethod
807 - def XsdLiteral (cls, value):
808 return unicode(value)
809 810 @classmethod
811 - def _XsdConstraintsPreCheck_vb (cls, value):
812 if not isinstance(value, types.StringTypes): 813 raise BadTypeValueError('%s value must be a string' % (cls.__name__,)) 814 if 0 <= value.find(':'): 815 (prefix, local) = value.split(':', 1) 816 if (NCName._ValidRE.match(prefix) is None) or (NCName._ValidRE.match(local) is None): 817 raise BadTypeValueError('%s lexical/value space violation for "%s"' % (cls.__name__, value)) 818 else: 819 if NCName._ValidRE.match(value) is None: 820 raise BadTypeValueError('%s lexical/value space violation for "%s"' % (cls.__name__, value)) 821 super_fn = getattr(super(QName, cls), '_XsdConstraintsPreCheck_vb', lambda *a,**kw: True) 822 return super_fn(value)
823 824 825 _PrimitiveDatatypes.append(QName)
826 827 -class NOTATION (basis.simpleTypeDefinition):
828 _XsdBaseType = anySimpleType 829 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('NOTATION') 830 831 @classmethod
832 - def XsdValueLength (cls, value):
833 """Section 4.3.1.3: Legacy length return None to indicate no check""" 834 return None
835 836 _PrimitiveDatatypes.append(NOTATION)
837 838 -class normalizedString (string):
839 """See http:///www.w3.org/TR/xmlschema-2/index.html#normalizedString 840 841 Normalized strings can't have carriage returns, linefeeds, or 842 tabs in them.""" 843 844 # All descendents of normalizedString constrain the lexical/value 845 # space in some way. Subclasses should set the _ValidRE class 846 # variable to a compiled regular expression that matches valid 847 # input, or the _InvalidRE class variable to a compiled regular 848 # expression that detects invalid inputs. 849 # 850 # Alternatively, subclasses can override the _ValidateString 851 # class. 852 853 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('normalizedString') 854 855 # @todo Implement pattern constraints and just rely on them 856 857 # No CR, LF, or TAB 858 __BadChars = re.compile("[\r\n\t]") 859 860 _ValidRE = None 861 _InvalidRE = None 862 863 @classmethod
864 - def __ValidateString (cls, value):
865 # This regular expression doesn't work. Don't know why. 866 #if cls.__BadChars.match(value) is not None: 867 # raise BadTypeValueError('CR/NL/TAB characters illegal in %s' % (cls.__name__,)) 868 if (0 <= value.find("\n")) or (0 <= value.find("\r")) or (0 <= value.find("\t")): 869 raise BadTypeValueError('CR/NL/TAB characters illegal in %s' % (cls.__name__,)) 870 if cls._ValidRE is not None: 871 match_object = cls._ValidRE.match(value) 872 if match_object is None: 873 raise BadTypeValueError('%s pattern constraint violation for "%s"' % (cls.__name__, value)) 874 if cls._InvalidRE is not None: 875 match_object = cls._InvalidRE.match(value) 876 if not (match_object is None): 877 raise BadTypeValueError('%s pattern constraint violation for "%s"' % (cls.__name__, value)) 878 return True
879 880 @classmethod
881 - def _ValidateString_va (cls, value):
882 """Post-extended method to validate that a string matches a given pattern. 883 884 If you can express the valid strings as a compiled regular 885 expression in the class variable _ValidRE, or the invalid 886 strings as a compiled regular expression in the class variable 887 _InvalidRE, you can just use those. If the acceptable matches 888 are any trickier, you should invoke the superclass 889 implementation, and if it returns True then perform additional 890 tests.""" 891 super_fn = getattr(super(normalizedString, cls), '_ValidateString_va', lambda *a,**kw: True) 892 if not super_fn(value): 893 return False 894 return cls.__ValidateString(value)
895 896 @classmethod
897 - def _XsdConstraintsPreCheck_vb (cls, value):
898 if not isinstance(value, types.StringTypes): 899 raise BadTypeValueError('%s value must be a string' % (cls.__name__,)) 900 if not cls._ValidateString_va(value): 901 raise BadTypeValueError('%s lexical/value space violation for "%s"' % (cls.__name__, value)) 902 super_fn = getattr(super(normalizedString, cls), '_XsdConstraintsPreCheck_vb', lambda *a,**kw: True) 903 return super_fn(value)
904 905 _DerivedDatatypes.append(normalizedString) 906 assert normalizedString.XsdSuperType() == string
907 908 -class token (normalizedString):
909 """See http:///www.w3.org/TR/xmlschema-2/index.html#token 910 911 Tokens cannot leading or trailing space characters; any 912 carriage return, line feed, or tab characters; nor any occurrence 913 of two or more consecutive space characters.""" 914 915 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('token') 916 917 @classmethod
918 - def _ValidateString_va (cls, value):
919 super_fn = getattr(super(token, cls), '_ValidateString_va', lambda *a,**kw: True) 920 if not super_fn(value): 921 return False 922 if value.startswith(" "): 923 raise BadTypeValueError('Leading spaces in token') 924 if value.endswith(" "): 925 raise BadTypeValueError('Trailing spaces in token') 926 if 0 <= value.find(' '): 927 raise BadTypeValueError('Multiple internal spaces in token') 928 return True
929 _DerivedDatatypes.append(token)
930 931 -class language (token):
932 """See http:///www.w3.org/TR/xmlschema-2/index.html#language""" 933 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('language') 934 _ValidRE = re.compile('^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$')
935 _DerivedDatatypes.append(language)
936 937 -class NMTOKEN (token):
938 """See http://www.w3.org/TR/2000/WD-xml-2e-20000814.html#NT-Nmtoken 939 940 NMTOKEN is an identifier that can start with any character that is 941 legal in it.""" 942 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('NMTOKEN') 943 _ValidRE = re.compile('^[-_.:A-Za-z0-9]*$')
944 _DerivedDatatypes.append(NMTOKEN)
945 946 -class NMTOKENS (basis.STD_list):
947 _ItemType = NMTOKEN
948 _ListDatatypes.append(NMTOKENS)
949 950 -class Name (token):
951 """See http://www.w3.org/TR/2000/WD-xml-2e-20000814.html#NT-Name""" 952 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('Name') 953 _ValidRE = re.compile('^[A-Za-z_:][-_.:A-Za-z0-9]*$')
954 _DerivedDatatypes.append(Name)
955 956 -class NCName (Name):
957 """See http://www.w3.org/TR/1999/REC-xml-names-19990114/index.html#NT-NCName""" 958 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('NCName') 959 _ValidRE = re.compile('^[A-Za-z_][-_.A-Za-z0-9]*$')
960 _DerivedDatatypes.append(NCName)
961 962 -class ID (NCName):
963 # Lexical and value space match that of parent NCName 964 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('ID') 965 pass
966 _DerivedDatatypes.append(ID)
967 968 -class IDREF (NCName):
969 # Lexical and value space match that of parent NCName 970 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('IDREF') 971 pass
972 _DerivedDatatypes.append(IDREF)
973 974 -class IDREFS (basis.STD_list):
975 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('IDREFS') 976 _ItemType = IDREF
977 _ListDatatypes.append(IDREFS)
978 979 -class ENTITY (NCName):
980 # Lexical and value space match that of parent NCName; we're gonna 981 # ignore the additional requirement that it be declared as an 982 # unparsed entity 983 # 984 # @todo Don't ignore the requirement that this be declared as an 985 # unparsed entity. 986 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('ENTITY') 987 pass
988 _DerivedDatatypes.append(ENTITY)
989 990 -class ENTITIES (basis.STD_list):
991 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('ENTITIES') 992 _ItemType = ENTITY
993 _ListDatatypes.append(ENTITIES)
994 995 -class integer (basis.simpleTypeDefinition, types.LongType):
996 """integer. 997 998 http://www.w3.org/TR/xmlschema-2/#integer""" 999 _XsdBaseType = decimal 1000 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('integer') 1001 1002 @classmethod
1003 - def XsdLiteral (cls, value):
1004 return '%d' % (value,)
1005 1006 _DerivedDatatypes.append(integer)
1007 1008 -class nonPositiveInteger (integer):
1009 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('nonPositiveInteger')
1010 _DerivedDatatypes.append(nonPositiveInteger)
1011 1012 -class negativeInteger (nonPositiveInteger):
1013 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('negativeInteger')
1014 _DerivedDatatypes.append(negativeInteger)
1015 1016 -class long (integer):
1017 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('long')
1018 _DerivedDatatypes.append(long)
1019 1020 -class int (basis.simpleTypeDefinition, types.IntType):
1021 _XsdBaseType = long 1022 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('int') 1023 1024 @classmethod
1025 - def XsdLiteral (cls, value):
1026 return '%s' % (value,)
1027 1028 pass
1029 _DerivedDatatypes.append(int)
1030 1031 -class short (int):
1032 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('short')
1033 _DerivedDatatypes.append(short)
1034 1035 -class byte (short):
1036 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('byte')
1037 _DerivedDatatypes.append(byte)
1038 1039 -class nonNegativeInteger (integer):
1040 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('nonNegativeInteger')
1041 _DerivedDatatypes.append(nonNegativeInteger)
1042 1043 -class unsignedLong (nonNegativeInteger):
1044 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('unsignedLong')
1045 _DerivedDatatypes.append(unsignedLong)
1046 1047 -class unsignedInt (unsignedLong):
1048 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('unsignedInt')
1049 _DerivedDatatypes.append(unsignedInt)
1050 1051 -class unsignedShort (unsignedInt):
1052 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('unsignedShort')
1053 _DerivedDatatypes.append(unsignedShort)
1054 1055 -class unsignedByte (unsignedShort):
1056 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('unsignedByte')
1057 _DerivedDatatypes.append(unsignedByte)
1058 1059 -class positiveInteger (nonNegativeInteger):
1060 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('positiveInteger')
1061 _DerivedDatatypes.append(positiveInteger) 1062 1063 import datatypes_facets 1064 import content
1065 1066 -class anyType (basis.complexTypeDefinition):
1067 """http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/#key-urType""" 1068 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('anyType') 1069 _ContentTypeTag = basis.complexTypeDefinition._CT_MIXED 1070 _Abstract = False 1071 _HasWildcardElement = True 1072 _AttributeWildcard = content.Wildcard(namespace_constraint=content.Wildcard.NC_any, process_contents=content.Wildcard.PC_lax) 1073 1074 # Generate from tests/schemas/anyType.xsd 1075 _ContentModel = content.ContentModel(state_map = { 1076 1 : content.ContentModelState(state=1, is_final=True, transitions=[ 1077 content.ContentModelTransition(term=content.Wildcard(process_contents=content.Wildcard.PC_lax, namespace_constraint=content.Wildcard.NC_any), next_state=1, element_use=None), 1078 ]) 1079 })
1080