1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """Classes supporting U{XMLSchema Part 2: Datatypes<http://www.w3.org/TR/xmlschema-2/>}.
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 pyxb.utils.unicode
51 import basis
52 import re
53 import binascii
54 import base64
55
56 _PrimitiveDatatypes = []
57 _DerivedDatatypes = []
58 _ListDatatypes = []
59
60
61
62
63 -class anySimpleType (basis.simpleTypeDefinition, unicode):
71
72
73
74 -class string (basis.simpleTypeDefinition, unicode):
87
88 _PrimitiveDatatypes.append(string)
89
90
91
92 -class boolean (basis.simpleTypeDefinition, types.IntType):
93 """XMLSchema datatype U{boolean<http://www.w3.org/TR/xmlschema-2/#boolean>}."""
94 _XsdBaseType = anySimpleType
95 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('boolean')
96
97 @classmethod
99 if value:
100 return 'true'
101 return 'false'
102
104 if self:
105 return 'true'
106 return 'false'
107
109 args = cls._ConvertArguments(args, kw)
110 if 0 < len(args):
111 value = args[0]
112 args = args[1:]
113 if value in (1, 0, '1', '0', 'true', 'false'):
114 if value in (1, '1', 'true'):
115 iv = True
116 else:
117 iv = False
118 return super(boolean, cls).__new__(cls, iv, *args, **kw)
119 raise BadTypeValueError('[xsd:boolean] Initializer "%s" not valid for type' % (value,))
120 return super(boolean, cls).__new__(cls, *args, **kw)
121
122 _PrimitiveDatatypes.append(boolean)
123
124 -class decimal (basis.simpleTypeDefinition, types.FloatType):
137
138 _PrimitiveDatatypes.append(decimal)
139
140 -class float (basis.simpleTypeDefinition, types.FloatType):
148
149 _PrimitiveDatatypes.append(float)
150
151 -class double (basis.simpleTypeDefinition, types.FloatType):
159
160 _PrimitiveDatatypes.append(double)
161
162 import time as python_time
163 import datetime
164
165 -class duration (basis.simpleTypeDefinition, datetime.timedelta):
166 """XMLSchema datatype U{duration<http://www.w3.org/TR/xmlschema-2/#duration>}.
167
168 This class uses the Python C{datetime.timedelta} class as its
169 underlying representation. This works fine as long as no months
170 or years are involved, and no negative durations are involved.
171 Because the XML Schema value space is so much larger, it is kept
172 distinct from the Python value space, which reduces to integral
173 days, seconds, and microseconds.
174
175 In other words, the implementation of this type is a little
176 shakey.
177
178 """
179
180 _XsdBaseType = anySimpleType
181 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('duration')
182
183 __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)?)?$')
184
185
186 __XSDFields = ( 'years', 'months', 'days', 'hours', 'minutes', 'seconds' )
187 __PythonFields = ( 'days', 'seconds', 'microseconds', 'minutes', 'hours' )
188
191 __negativeDuration = None
192
195 __durationData = None
196
198 args = cls._ConvertArguments(args, kw)
199 if 0 == len(args):
200 raise BadTypeValueError('[xsd:duration] Type requires an initializer')
201 text = args[0]
202 have_kw_update = False
203 if isinstance(text, (str, unicode)):
204 match = cls.__Lexical_re.match(text)
205 if match is None:
206 raise BadTypeValueError('Value "%s" not in %s lexical space' % (text, cls._ExpandedName))
207 match_map = match.groupdict()
208 if 'T' == match_map.get('Time', None):
209
210 raise BadTypeValueError('Value "%s" not in %s lexical space' % (text, cls._ExpandedName))
211
212 negative_duration = ('-' == match_map.get('neg', None))
213
214 fractional_seconds = 0.0
215 if match_map.get('fracsec', None) is not None:
216 fractional_seconds = types.FloatType('0%s' % (match_map['fracsec'],))
217 usec = types.IntType(1000000 * fractional_seconds)
218 if negative_duration:
219 kw['microseconds'] = - usec
220 else:
221 kw['microseconds'] = usec
222 else:
223
224 kw.pop('microsecond', None)
225
226 data = { }
227 for fn in cls.__XSDFields:
228 v = match_map.get(fn, 0)
229 if v is None:
230 v = 0
231 data[fn] = types.IntType(v)
232 if fn in cls.__PythonFields:
233 if negative_duration:
234 kw[fn] = - data[fn]
235 else:
236 kw[fn] = data[fn]
237 data['seconds'] += fractional_seconds
238 have_kw_update = True
239 elif isinstance(text, cls):
240 data = text.durationData().copy()
241 negative_duration = text.negativeDuration()
242 elif isinstance(text, datetime.timedelta):
243 data = { 'days' : text.days,
244 'seconds' : text.seconds + (text.microseconds / 1000000.0) }
245 negative_duration = (0 > data['days'])
246 if negative_duration:
247 if 0.0 == data['seconds']:
248 data['days'] = - data['days']
249 else:
250 data['days'] = 1 - data['days']
251 data['seconds'] = 24 * 60 * 60.0 - data['seconds']
252 data['minutes'] = 0
253 data['hours'] = 0
254 else:
255 raise BadTypeValueError('[xsd:duration] Initializer "%s" type %s not valid for type' % (text, type(text)))
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 data['seconds'] = rem_time % 60
263 rem_time = data['minutes'] + (rem_time // 60)
264 data['minutes'] = rem_time % 60
265 rem_time = data['hours'] + (rem_time // 60)
266 data['hours'] = rem_time % 24
267 data['days'] += (rem_time // 24)
268 for fn in cls.__PythonFields:
269 if fn in data:
270 if negative_duration:
271 kw[fn] = - data[fn]
272 else:
273 kw[fn] = data[fn]
274 else:
275 kw.pop(fn, None)
276 kw['microseconds'] = data.pop('microseconds', 0)
277 data['seconds'] += kw['microseconds'] / 1000000.0
278
279 rv = super(duration, cls).__new__(cls, **kw)
280 rv.__durationData = data
281 rv.__negativeDuration = negative_duration
282 return rv
283
284 @classmethod
306
307 _PrimitiveDatatypes.append(duration)
310
311 _Lexical_fmt = None
312 """Format for the lexical representation of a date-related instance, excluding timezone.
313
314 Subclasses must define this."""
315
316
317
318
319 __PatternMap = { '%Y' : '(?P<negYear>-?)(?P<year>\d{4,})'
320 , '%m' : '(?P<month>\d{2})'
321 , '%d' : '(?P<day>\d{2})'
322 , '%H' : '(?P<hour>\d{2})'
323 , '%M' : '(?P<minute>\d{2})'
324 , '%S' : '(?P<second>\d{2})(?P<fracsec>\.\d+)?'
325 , '%Z' : '(?P<tzinfo>Z|[-+]\d\d:\d\d)' }
326
327
328
329 __LexicalREMap = { }
330
331
332 __LexicalIntegerFields = ( 'year', 'month', 'day', 'hour', 'minute', 'second' )
333
334 _UTCTimeZone = pyxb.utils.utility.UTCOffsetTimeZone(0)
335 """A L{datetime.tzinfo} instance representing UTC."""
336
337 _LocalTimeZone = pyxb.utils.utility.LocalTimeZone()
338 """A L{datetime.tzinfo} instance representing the local time zone."""
339
340 _DefaultYear = 1900
341 _DefaultMonth = 1
342 _DefaultDay = 1
343
344 @classmethod
346 lexical_re = cls.__LexicalREMap.get(cls)
347 if lexical_re is None:
348 pattern = '^' + cls._Lexical_fmt + '%Z?$'
349 for (k, v) in cls.__PatternMap.items():
350 pattern = pattern.replace(k, v)
351 lexical_re = re.compile(pattern)
352 cls.__LexicalREMap[cls] = lexical_re
353 match = lexical_re.match(text)
354 if match is None:
355 raise BadTypeValueError('Value "%s" not in %s lexical space' % (text, cls._ExpandedName))
356 match_map = match.groupdict()
357 kw = { }
358 for (k, v) in match_map.iteritems():
359 if (k in cls.__LexicalIntegerFields) and (v is not None):
360 kw[k] = types.IntType(v)
361 if '-' == match_map.get('negYear', None):
362 kw['year'] = - kw['year']
363 if match_map.get('fracsec', None) is not None:
364 kw['microsecond'] = types.IntType(round(1000000 * types.FloatType('0%s' % (match_map['fracsec'],))))
365 else:
366
367 kw.pop('microsecond', None)
368 if match_map.get('tzinfo', None) is not None:
369 kw['tzinfo'] = pyxb.utils.utility.UTCOffsetTimeZone(match_map['tzinfo'])
370 else:
371 kw.pop('tzinfo', None)
372 return kw
373
374 @classmethod
376 for f in fields:
377 kw[f] = getattr(python_value, f)
378 return getattr(super(_PyXBDateTime_base, cls), '_SetKeysFromPython_csc', lambda *a,**kw: None)(python_value, kw, fields)
379
380 @classmethod
383
384
385
386
389
390 @classmethod
392 """Update datetime keywords to account for timezone effects.
393
394 All XML schema timezoned times are in UTC, with the time "in
395 its timezone". If the keywords indicate a non-UTC timezone is
396 in force, and L{pyxb.PreserveInputTimeZone()} has not been
397 set, adjust the values to account for the zone by subtracting
398 the corresponding UTC offset and mark explicitly that the time
399 is in UTC by leaving a C{tzinfo} attribute identifying the UTC
400 time zone.
401
402 @param kw: A dictionary of keywords relevant for a date or
403 time instance. The dictionary is updated by this call.
404 """
405 if pyxb.PreserveInputTimeZone():
406 return
407 tzoffs = kw.pop('tzinfo', None)
408 if tzoffs is not None:
409 use_kw = kw.copy()
410
411 use_kw.setdefault('year', cls._DefaultYear)
412 use_kw.setdefault('month', cls._DefaultMonth)
413 use_kw.setdefault('day', cls._DefaultDay)
414 dt = datetime.datetime(tzinfo=tzoffs, **use_kw)
415 dt -= tzoffs.utcoffset(dt)
416 for k in kw.iterkeys():
417 kw[k] = getattr(dt, k)
418 kw['tzinfo'] = cls._UTCTimeZone
419
420 @classmethod
422 iso = value.replace(tzinfo=None).isoformat()
423 if 0 <= iso.find('.'):
424 iso = iso.rstrip('0')
425 if value.tzinfo is not None:
426 iso += value.tzinfo.tzname(value)
427 return iso
428
429 -class dateTime (_PyXBDateTime_base, datetime.datetime):
430 """XMLSchema datatype U{dateTime<http://www.w3.org/TR/xmlschema-2/#dateTime>}.
431
432 This class uses the Python C{datetime.datetime} class as its
433 underlying representation. Unless L{pyxb.PreserveInputTimeZone()}
434 is used, all timezoned dateTime objects are in UTC. Presence of
435 time zone information in the lexical space is preserved by a
436 non-empty tzinfo field, which should always be zero minutes offset
437 from UTC unless the input time zone was preserved.
438
439 @warning: The value space of Python's C{datetime.datetime} class
440 is more restricted than that of C{xs:datetime}. As a specific
441 example, Python does not support negative years or years with more
442 than four digits. For now, the convenience of having an object
443 that is compatible with Python is more important than supporting
444 the full value space. In the future, the choice may be left up to
445 the developer.
446 """
447
448 _XsdBaseType = anySimpleType
449 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('dateTime')
450
451 _Lexical_fmt = '%Y-%m-%dT%H:%M:%S'
452 __CtorFields = ( 'year', 'month', 'day', 'hour', 'minute', 'second', 'microsecond', 'tzinfo' )
453
455 args = cls._ConvertArguments(args, kw)
456 ctor_kw = { }
457 if 1 == len(args):
458 value = args[0]
459 if isinstance(value, types.StringTypes):
460 ctor_kw.update(cls._LexicalToKeywords(value))
461 elif isinstance(value, datetime.datetime):
462 cls._SetKeysFromPython(value, ctor_kw, cls.__CtorFields)
463 elif isinstance(value, (types.IntType, types.LongType)):
464 raise TypeError('function takes at least 3 arguments (%d given)' % (len(args),))
465 else:
466 raise BadTypeValueError('Unexpected type %s in %s' % (type(value), cls._ExpandedName))
467 elif 3 <= len(args):
468 for fi in range(len(cls.__CtorFields)):
469 fn = cls.__CtorFields[fi]
470 if fi < len(args):
471 ctor_kw[fn] = args[fi]
472 elif fn in kw:
473 ctor_kw[fn] = kw[fn]
474 kw.pop(fn, None)
475 else:
476 raise TypeError('function takes at least 3 arguments (%d given)' % (len(args),))
477
478 cls._AdjustForTimezone(ctor_kw)
479 kw.update(ctor_kw)
480 year = kw.pop('year')
481 month = kw.pop('month')
482 day = kw.pop('day')
483 rv = super(dateTime, cls).__new__(cls, year, month, day, **kw)
484 return rv
485
486 @classmethod
488 """Return today.
489
490 Just like datetime.datetime.today(), except this one sets a
491 tzinfo field so it's clear the value is UTC."""
492 return cls(datetime.datetime.now(cls._UTCTimeZone))
493
495 """Returns a C{datetime.datetime} instance denoting the same
496 time as this instance but adjusted to be in the local time
497 zone.
498
499 @rtype: C{datetime.datetime} (B{NOT} C{xsd.dateTime})
500 """
501 return self.replace(tzinfo=self._UTCTimeZone).astimezone(self._LocalTimeZone)
502
503 _PrimitiveDatatypes.append(dateTime)
504
505 -class time (_PyXBDateTime_base, datetime.time):
506 """XMLSchema datatype U{time<http://www.w3.org/TR/xmlschema-2/#time>}.
507
508 This class uses the Python C{datetime.time} class as its
509 underlying representation. Note that per the XMLSchema spec, all
510 dateTime objects are in UTC, and that timezone information in the
511 string representation in XML is an indication of the local time
512 zone's offset from UTC. Presence of time zone information in the
513 lexical space is indicated by the tzinfo field.
514
515 @note: C{pyxb.PreserveInputTimeZone()} can be used to bypass the
516 normalization to UTC.
517 """
518
519 _XsdBaseType = anySimpleType
520 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('time')
521
522 _Lexical_fmt = '%H:%M:%S'
523 __CtorFields = ( 'hour', 'minute', 'second', 'microsecond', 'tzinfo' )
524
526 args = cls._ConvertArguments(args, kw)
527 ctor_kw = { }
528 if 1 <= len(args):
529 value = args[0]
530 if isinstance(value, types.StringTypes):
531 ctor_kw.update(cls._LexicalToKeywords(value))
532 elif isinstance(value, (datetime.time, datetime.datetime)):
533 cls._SetKeysFromPython(value, ctor_kw, cls.__CtorFields)
534 elif isinstance(value, (types.IntType, types.LongType)):
535 for fi in range(len(cls.__CtorFields)):
536 fn = cls.__CtorFields[fi]
537 if fi < len(args):
538 ctor_kw[fn] = args[fi]
539 elif fn in kw:
540 ctor_kw[fn] = kw[fn]
541 kw.pop(fn, None)
542 else:
543 raise BadTypeValueError('Unexpected type %s' % (type(value),))
544
545 cls._AdjustForTimezone(ctor_kw)
546 kw.update(ctor_kw)
547 return super(time, cls).__new__(cls, **kw)
548
549 _PrimitiveDatatypes.append(time)
552 _XsdBaseType = anySimpleType
553
554 _ValidFields = ( 'year', 'month', 'day' )
555
557 args = cls._ConvertArguments(args, kw)
558 ctor_kw = { }
559 ctor_kw['year'] = cls._DefaultYear
560 ctor_kw['month'] = cls._DefaultMonth
561 ctor_kw['day'] = cls._DefaultDay
562 ctor_kw['hour'] = 0
563 ctor_kw['minute'] = 0
564 ctor_kw['second'] = 0
565 if 1 <= len(args):
566 value = args[0]
567 if isinstance(value, types.StringTypes):
568 if 1 != len(args):
569 raise TypeError('construction from string requires exactly 1 argument')
570 ctor_kw.update(cls._LexicalToKeywords(value))
571 elif isinstance(value, (datetime.date, datetime.datetime)):
572 if 1 != len(args):
573 raise TypeError('construction from instance requires exactly 1 argument')
574 cls._SetKeysFromPython(value, ctor_kw, cls._ValidFields)
575 try:
576 tzinfo = value.tzinfo
577 if tzinfo is not None:
578 ctor_kw['tzinfo'] = tzinfo
579 except AttributeError:
580 pass
581 else:
582 fi = 0
583 while fi < len(cls._ValidFields):
584 fn = cls._ValidFields[fi]
585 if fi < len(args):
586 ctor_kw[fn] = args[fi]
587 elif fn in kw:
588 ctor_kw[fn] = kw[fn]
589 kw.pop(fn, None)
590 fi += 1
591 if fi < len(args):
592 ctor_kw['tzinfo'] = args[fi]
593 fi += 1
594 if fi != len(args):
595 raise TypeError('function takes %d arguments plus optional tzinfo (%d given)' % (len(cls._ValidFields), len(args)))
596 else:
597 raise TypeError('function takes %d arguments plus optional tzinfo' % (len(cls._ValidFields),))
598
599
600
601
602
603 kw.update(ctor_kw)
604 argv = []
605 argv.append(kw.pop('year'))
606 argv.append(kw.pop('month'))
607 argv.append(kw.pop('day'))
608 return super(_PyXBDateOnly_base, cls).__new__(cls, *argv, **kw)
609
610 @classmethod
620
621 -class date (_PyXBDateOnly_base):
622 """XMLSchema datatype U{date<http://www.w3.org/TR/xmlschema-2/#date>}.
623
624 This class uses the Python C{datetime.datetime} class as its
625 underlying representation; fields not relevant to this type are
626 derived from 1900-01-01T00:00:00.
627
628 @note: Unlike L{dateTime}, timezoned date values are not converted
629 to UTC. The provided timezone information is retained along with
630 the instance; however, the lexical representation generated for
631 output is canonicalized (timezones no more than 12 hours off UTC).
632 """
633
634 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('date')
635 _Lexical_fmt = '%Y-%m-%d'
636 _Fields = ( 'year', 'month', 'day' )
637
638 __SecondsPerMinute = 60
639 __MinutesPerHalfDay = 12 * 60
640 __MinutesPerDay = 24 * 60
642 """Return the recoverable tzinfo for the date.
643
644 Return a L{pyxb.utils.utility.UTCOffsetTimeZone} instance
645 reflecting the timezone associated with the date, or C{None}
646 if the date is not timezoned.
647
648 @note: This is not the recoverable timezone, because timezones are
649 represented as timedeltas which get normalized in ways that
650 don't match what we expect for a tzinfo.
651 """
652 if self.tzinfo is None:
653 return None
654 sdt = self.replace(hour=0, minute=0, second=0, tzinfo=self._UTCTimeZone)
655 utc_offset = (sdt - self).seconds / self.__SecondsPerMinute
656 if utc_offset > self.__MinutesPerHalfDay:
657 utc_offset -= self.__MinutesPerDay
658 return pyxb.utils.utility.UTCOffsetTimeZone(utc_offset)
659
660 @classmethod
678
679
680 _PrimitiveDatatypes.append(date)
683 """XMLSchema datatype U{gYearMonth<http://www.w3.org/TR/xmlschema-2/#gYearMonth>}.
684
685 This class uses the Python C{datetime.datetime} class as its
686 underlying representation; fields not relevant to this type are
687 derived from 1900-01-01T00:00:00.
688 """
689 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gYearMonth')
690 _Lexical_fmt = '%Y-%m'
691 _ValidFields = ( 'year', 'month' )
692
693 _PrimitiveDatatypes.append(gYearMonth)
694
695 -class gYear (_PyXBDateOnly_base):
696 """XMLSchema datatype U{gYear<http://www.w3.org/TR/xmlschema-2/#gYear>}.
697
698 This class uses the Python C{datetime.datetime} class as its
699 underlying representation; fields not relevant to this type are
700 derived from 1900-01-01T00:00:00.
701 """
702 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gYear')
703 _Lexical_fmt = '%Y'
704 _ValidFields = ( 'year', )
705 _PrimitiveDatatypes.append(gYear)
708 """XMLSchema datatype U{gMonthDay<http://www.w3.org/TR/xmlschema-2/#gMonthDay>}.
709
710 This class uses the Python C{datetime.datetime} class as its
711 underlying representation; fields not relevant to this type are
712 derived from 1900-01-01T00:00:00.
713 """
714 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gMonthDay')
715 _Lexical_fmt = '--%m-%d'
716 _ValidFields = ( 'month', 'day' )
717 _PrimitiveDatatypes.append(gMonthDay)
718
719 -class gDay (_PyXBDateOnly_base):
720 """XMLSchema datatype U{gDay<http://www.w3.org/TR/xmlschema-2/#gDay>}.
721
722 This class uses the Python C{datetime.datetime} class as its
723 underlying representation; fields not relevant to this type are
724 derived from 1900-01-01T00:00:00.
725 """
726 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gDay')
727 _Lexical_fmt = '---%d'
728 _ValidFields = ( 'day', )
729 _PrimitiveDatatypes.append(gDay)
730
731 -class gMonth (_PyXBDateOnly_base):
732 """XMLSchema datatype U{gMonth<http://www.w3.org/TR/xmlschema-2/#gMonth>}.
733
734 This class uses the Python C{datetime.datetime} class as its
735 underlying representation; fields not relevant to this type are
736 derived from 1900-01-01T00:00:00.
737 """
738 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('gMonth')
739 _Lexical_fmt = '--%m'
740 _ValidFields = ( 'month', )
741 _PrimitiveDatatypes.append(gMonth)
742
743 -class hexBinary (basis.simpleTypeDefinition, types.StringType):
744 """XMLSchema datatype U{hexBinary<http://www.w3.org/TR/xmlschema-2/#hexBinary>}."""
745 _XsdBaseType = anySimpleType
746 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('hexBinary')
747
748 @classmethod
750 if kw.get('_from_xml', False):
751 try:
752 args = (binascii.unhexlify(args[0]),) + args[1:]
753 except TypeError, e:
754 raise BadTypeValueError('%s is not a valid hexBinary string' % (cls.__class__.__name__,))
755 return args
756
757 @classmethod
759 return binascii.hexlify(value).upper()
760
761 @classmethod
764
765 _PrimitiveDatatypes.append(hexBinary)
766
767 -class base64Binary (basis.simpleTypeDefinition, types.StringType):
768 """XMLSchema datatype U{base64Binary<http://www.w3.org/TR/xmlschema-2/#base64Binary>}.
769
770 See also U{RFC2045<http://tools.ietf.org/html/rfc2045>} and U{RFC4648<http://tools.ietf.org/html/rfc4648>}.
771 """
772 _XsdBaseType = anySimpleType
773 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('base64Binary')
774
775
776
777
778 _B04 = '[AQgw]'
779 _B04S = '(%s ?)' % (_B04,)
780 _B16 = '[AEIMQUYcgkosw048]'
781 _B16S = '(%s ?)' % (_B16,)
782 _B64 = '[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/]'
783 _B64S = '(%s ?)' % (_B64,)
784
785 __Pattern = '^((' + _B64S + '{4})*((' + _B64S + '{3}' + _B64 + ')|(' + _B64S + '{2}' + _B16S + '=)|(' + _B64S + _B04S + '= ?=)))?$'
786 __Lexical_re = re.compile(__Pattern)
787
788 @classmethod
790 if kw.get('_from_xml', False):
791 xmls = args[0]
792 try:
793 args = (base64.standard_b64decode(xmls),) + args[1:]
794 except TypeError, e:
795 raise BadTypeValueError('%s is not a valid base64Binary string: %s' % (cls.__class__.__name__, str(e)))
796
797 if cls.__Lexical_re.match(xmls) is None:
798 raise BadTypeValueError('%s is not a valid base64Binary string: XML strict failed' % (cls.__class__.__name__,))
799 return args
800
801 @classmethod
803 return base64.standard_b64encode(value)
804
805 @classmethod
808
809 _PrimitiveDatatypes.append(base64Binary)
810
811 -class anyURI (basis.simpleTypeDefinition, unicode):
823
824 _PrimitiveDatatypes.append(anyURI)
825
826 -class QName (basis.simpleTypeDefinition, unicode):
827 """XMLSchema datatype U{QName<http://www.w3.org/TR/xmlschema-2/#QName>}."""
828 _XsdBaseType = anySimpleType
829 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('QName')
830
831 @classmethod
833 """Section 4.3.1.3: Legacy length return None to indicate no check"""
834 return None
835
836 __localName = None
837 __prefix = None
838
840 """Return the prefix portion of the QName, or None if the name is not qualified."""
841 if self.__localName is None:
842 self.__resolveLocals()
843 return self.__prefix
844
850
856
857 @classmethod
860
861 @classmethod
863 if not isinstance(value, types.StringTypes):
864 raise BadTypeValueError('%s value must be a string' % (cls.__name__,))
865 if 0 <= value.find(':'):
866 (prefix, local) = value.split(':', 1)
867 if (NCName._ValidRE.match(prefix) is None) or (NCName._ValidRE.match(local) is None):
868 raise BadTypeValueError('%s lexical/value space violation for "%s"' % (cls.__name__, value))
869 else:
870 if NCName._ValidRE.match(value) is None:
871 raise BadTypeValueError('%s lexical/value space violation for "%s"' % (cls.__name__, value))
872 super_fn = getattr(super(QName, cls), '_XsdConstraintsPreCheck_vb', lambda *a,**kw: True)
873 return super_fn(value)
874
875
876 _PrimitiveDatatypes.append(QName)
877
878 -class NOTATION (basis.simpleTypeDefinition):
887
888 _PrimitiveDatatypes.append(NOTATION)
891 """XMLSchema datatype U{normalizedString<http:///www.w3.org/TR/xmlschema-2/#normalizedString>}.
892
893 Normalized strings can't have carriage returns, linefeeds, or
894 tabs in them."""
895
896
897
898
899
900
901
902
903
904
905 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('normalizedString')
906
907
908
909
910 __BadChars = re.compile("[\r\n\t]")
911
912 _ValidRE = None
913 _InvalidRE = None
914
915 @classmethod
931
932 @classmethod
934 """Post-extended method to validate that a string matches a given pattern.
935
936 If you can express the valid strings as a compiled regular
937 expression in the class variable _ValidRE, or the invalid
938 strings as a compiled regular expression in the class variable
939 _InvalidRE, you can just use those. If the acceptable matches
940 are any trickier, you should invoke the superclass
941 implementation, and if it returns True then perform additional
942 tests."""
943 super_fn = getattr(super(normalizedString, cls), '_ValidateString_va', lambda *a,**kw: True)
944 if not super_fn(value):
945 return False
946 return cls.__ValidateString(value)
947
948 @classmethod
956
957 _DerivedDatatypes.append(normalizedString)
958 assert normalizedString.XsdSuperType() == string
959
960 -class token (normalizedString):
961 """XMLSchema datatype U{token<http:///www.w3.org/TR/xmlschema-2/#token>}.
962
963 Tokens cannot leading or trailing space characters; any
964 carriage return, line feed, or tab characters; nor any occurrence
965 of two or more consecutive space characters."""
966
967 _ExpandedName = pyxb.namespace.XMLSchema.createExpandedName('token')
968
969 @classmethod
971 super_fn = getattr(super(token, cls), '_ValidateString_va', lambda *a,**kw: True)
972 if not super_fn(value):
973 return False
974 if value.startswith(" "):
975 raise BadTypeValueError('Leading spaces in token')
976 if value.endswith(" "):
977 raise BadTypeValueError('Trailing spaces in token')
978 if 0 <= value.find(' '):
979 raise BadTypeValueError('Multiple internal spaces in token')
980 return True
981 _DerivedDatatypes.append(token)
987 _DerivedDatatypes.append(language)
998 _DerivedDatatypes.append(NMTOKEN)
1002 _ListDatatypes.append(NMTOKENS)
1003
1004 -class Name (token):
1010 _DerivedDatatypes.append(Name)
1018 _DerivedDatatypes.append(NCName)
1019
1020 -class ID (NCName):
1025 _DerivedDatatypes.append(ID)
1026
1027 -class IDREF (NCName):
1032 _DerivedDatatypes.append(IDREF)
1033
1034 -class IDREFS (basis.STD_list):
1038 _ListDatatypes.append(IDREFS)
1050 _DerivedDatatypes.append(ENTITY)
1056 _ListDatatypes.append(ENTITIES)
1057
1058 -class integer (basis.simpleTypeDefinition, types.LongType):
1066
1067 _DerivedDatatypes.append(integer)
1072 _DerivedDatatypes.append(nonPositiveInteger)
1077 _DerivedDatatypes.append(negativeInteger)
1078
1079 -class long (integer):
1082 _DerivedDatatypes.append(long)
1083
1084 -class int (basis.simpleTypeDefinition, types.IntType):
1094 _DerivedDatatypes.append(int)
1099 _DerivedDatatypes.append(short)
1100
1101 -class byte (short):
1104 _DerivedDatatypes.append(byte)
1109 _DerivedDatatypes.append(nonNegativeInteger)
1114 _DerivedDatatypes.append(unsignedLong)
1119 _DerivedDatatypes.append(unsignedInt)
1124 _DerivedDatatypes.append(unsignedShort)
1129 _DerivedDatatypes.append(unsignedByte)
1134 _DerivedDatatypes.append(positiveInteger)
1135
1136 import datatypes_facets
1137 import content
1138
1139 -class anyType (basis.complexTypeDefinition):
1151
1152
1153
1154 anyType._IsUrType = classmethod(lambda _c: _c == anyType)
1155