Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/guts.py: 97%
1415 statements
« prev ^ index » next coverage.py v6.5.0, created at 2024-03-07 11:54 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2024-03-07 11:54 +0000
1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
7Lightweight declarative YAML and XML data binding for Python.
8'''
10import datetime
11import calendar
12import re
13import sys
14import os
15import types
16import copy
17import logging
18import os.path as op
19from collections import defaultdict
20from base64 import b64decode, b64encode
22from io import BytesIO
24try:
25 import numpy as num
26except ImportError:
27 num = None
29import yaml
30try:
31 from yaml import CSafeLoader as SafeLoader, CSafeDumper as SafeDumper
32except ImportError:
33 from yaml import SafeLoader, SafeDumper
35from .util import time_to_str, str_to_time, TimeStrError, hpfloat, \
36 get_time_float
39logger = logging.getLogger('pyrocko.guts')
41ALLOW_INCLUDE = False
44class GutsSafeDumper(SafeDumper):
45 pass
48class GutsSafeLoader(SafeLoader):
49 pass
52g_iprop = 0
54g_deferred = {}
55g_deferred_content = {}
57g_tagname_to_class = {}
58g_xmltagname_to_class = {}
59g_guessable_xmlns = {}
61guts_types = [
62 'Object', 'SObject', 'String', 'Unicode', 'Int', 'Float',
63 'Complex', 'Bool', 'Timestamp', 'DateTimestamp', 'StringPattern',
64 'UnicodePattern', 'StringChoice', 'IntChoice', 'List', 'Dict', 'Tuple',
65 'StringUnion', 'Choice', 'Any']
67us_to_cc_regex = re.compile(r'([a-z])_([a-z])')
70class literal(str):
71 pass
74class folded(str):
75 pass
78class singlequoted(str):
79 pass
82class doublequoted(str):
83 pass
86def make_str_presenter(style):
87 def presenter(dumper, data):
88 return dumper.represent_scalar(
89 'tag:yaml.org,2002:str', str(data), style=style)
91 return presenter
94str_style_map = {
95 None: lambda x: x,
96 '|': literal,
97 '>': folded,
98 "'": singlequoted,
99 '"': doublequoted}
101for (style, cls) in str_style_map.items():
102 if style:
103 GutsSafeDumper.add_representer(cls, make_str_presenter(style))
106class uliteral(str):
107 pass
110class ufolded(str):
111 pass
114class usinglequoted(str):
115 pass
118class udoublequoted(str):
119 pass
122def make_unicode_presenter(style):
123 def presenter(dumper, data):
124 return dumper.represent_scalar(
125 'tag:yaml.org,2002:str', str(data), style=style)
127 return presenter
130unicode_style_map = {
131 None: lambda x: x,
132 '|': literal,
133 '>': folded,
134 "'": singlequoted,
135 '"': doublequoted}
137for (style, cls) in unicode_style_map.items():
138 if style:
139 GutsSafeDumper.add_representer(cls, make_unicode_presenter(style))
142class blist(list):
143 pass
146class flist(list):
147 pass
150list_style_map = {
151 None: list,
152 'block': blist,
153 'flow': flist}
156def make_list_presenter(flow_style):
157 def presenter(dumper, data):
158 return dumper.represent_sequence(
159 'tag:yaml.org,2002:seq', data, flow_style=flow_style)
161 return presenter
164GutsSafeDumper.add_representer(blist, make_list_presenter(False))
165GutsSafeDumper.add_representer(flist, make_list_presenter(True))
167if num:
168 def numpy_float_presenter(dumper, data):
169 return dumper.represent_float(float(data))
171 def numpy_int_presenter(dumper, data):
172 return dumper.represent_int(int(data))
174 for dtype in (num.float64, num.float32):
175 GutsSafeDumper.add_representer(dtype, numpy_float_presenter)
177 for dtype in (num.int32, num.int64):
178 GutsSafeDumper.add_representer(dtype, numpy_int_presenter)
181def us_to_cc(s):
182 return us_to_cc_regex.sub(lambda pat: pat.group(1)+pat.group(2).upper(), s)
185cc_to_us_regex1 = re.compile(r'([a-z])([A-Z]+)([a-z]|$)')
186cc_to_us_regex2 = re.compile(r'([A-Z])([A-Z][a-z])')
189def cc_to_us(s):
190 return cc_to_us_regex2.sub('\\1_\\2', cc_to_us_regex1.sub(
191 '\\1_\\2\\3', s)).lower()
194re_frac = re.compile(r'\.[1-9]FRAC')
195frac_formats = dict([('.%sFRAC' % x, '%.'+x+'f') for x in '123456789'])
198def encode_utf8(s):
199 return s.encode('utf-8')
202def no_encode(s):
203 return s
206def make_xmltagname_from_name(name):
207 return us_to_cc(name)
210def make_name_from_xmltagname(xmltagname):
211 return cc_to_us(xmltagname)
214def make_content_name(name):
215 if name.endswith('_list'):
216 return name[:-5]
217 elif name.endswith('s'):
218 return name[:-1]
219 else:
220 return name
223def classnames(cls):
224 if isinstance(cls, tuple):
225 return '(%s)' % ', '.join(x.__name__ for x in cls)
226 else:
227 return cls.__name__
230def expand_stream_args(mode):
231 def wrap(f):
232 '''
233 Decorator to enhance functions taking stream objects.
235 Wraps a function f(..., stream, ...) so that it can also be called as
236 f(..., filename='myfilename', ...) or as f(..., string='mydata', ...).
237 '''
239 def g(*args, **kwargs):
240 stream = kwargs.pop('stream', None)
241 filename = kwargs.get('filename', None)
242 if mode != 'r':
243 filename = kwargs.pop('filename', None)
244 string = kwargs.pop('string', None)
246 assert sum(x is not None for x in (stream, filename, string)) <= 1
248 if stream is not None:
249 kwargs['stream'] = stream
250 return f(*args, **kwargs)
252 elif filename is not None:
253 stream = open(filename, mode+'b')
254 kwargs['stream'] = stream
255 retval = f(*args, **kwargs)
256 if isinstance(retval, types.GeneratorType):
257 def wrap_generator(gen):
258 try:
259 for x in gen:
260 yield x
262 except GeneratorExit:
263 pass
265 stream.close()
267 return wrap_generator(retval)
269 else:
270 stream.close()
271 return retval
273 elif string is not None:
274 assert mode == 'r', \
275 'Keyword argument string=... cannot be used in dumper ' \
276 'function.'
278 kwargs['stream'] = BytesIO(string.encode('utf-8'))
279 return f(*args, **kwargs)
281 else:
282 assert mode == 'w', \
283 'Use keyword argument stream=... or filename=... in ' \
284 'loader function.'
286 sout = BytesIO()
287 f(stream=sout, *args, **kwargs)
288 return sout.getvalue().decode('utf-8')
290 g.__doc__ = f.__doc__
291 return g
293 return wrap
296class Defer(object):
297 def __init__(self, classname, *args, **kwargs):
298 global g_iprop
299 if kwargs.get('position', None) is None:
300 kwargs['position'] = g_iprop
302 g_iprop += 1
304 self.classname = classname
305 self.args = args
306 self.kwargs = kwargs
309class TBase(object):
310 '''
311 Base class for Guts type definitions.
313 :param default:
314 Default value or :py:class:`DefaultMaker` object (see
315 :py:meth:`Object.D`) to be used to generate a default.
317 :param optional:
318 If ``True``, the attribute is optional and may be set to ``None``.
319 :type optional:
320 bool
322 :param xmlstyle:
323 Controls how the attribute is serialized in XML. :Choices:
324 ``'element'``, ``'attribute'``, ``'content'``. Only scalar and
325 :py:class:`SObject` values may be serialized as ``'attribute'``. Only
326 one attribute in a class may be serialized as ``'content'``.
327 :type xmlstyle:
328 str
330 :param xmltagname:
331 XML tag name to be used. By default, the attribute name converted to
332 camel-case is used.
333 :type xmltagname:
334 str
336 :param xmlns:
337 XML namespace to be used for this attribute.
338 :type xmlns:
339 str
341 :param help:
342 Description of the attribute used in documentation and online help.
343 :type help:
344 rst formatted :py:class:`str`
346 :param position:
347 Position index to be used when the attribute should be output in
348 non-default order.
349 :type position:
350 int
351 '''
353 strict = False
354 multivalued = None
355 force_regularize = False
356 propnames = []
357 _dummy_cls = None
358 _cls = None
359 _sphinx_doc_skip = False
361 @classmethod
362 def init_propertystuff(cls):
363 cls.properties = []
364 cls.xmltagname_to_name = {}
365 cls.xmltagname_to_name_multivalued = {}
366 cls.xmltagname_to_class = {}
367 cls.content_property = None
369 def __init__(
370 self,
371 default=None,
372 optional=False,
373 xmlstyle='element',
374 xmltagname=None,
375 xmlns=None,
376 help=None,
377 position=None):
379 global g_iprop
380 if position is not None:
381 self.position = position
382 else:
383 self.position = g_iprop
385 g_iprop += 1
386 self._default = default
388 self.optional = optional
389 self.name = None
390 self._xmltagname = xmltagname
391 self._xmlns = xmlns
392 self.parent = None
393 self.xmlstyle = xmlstyle
394 self.help = help
395 self._sphinx_doc_skip = True
397 def default(self):
398 return make_default(self._default)
400 def is_default(self, val):
401 if self._default is None:
402 return val is None
403 else:
404 return self._default == val
406 def has_default(self):
407 return self._default is not None
409 def xname(self):
410 if self.name is not None:
411 return self.name
412 elif self.parent is not None:
413 return 'element of %s' % self.parent.xname()
414 else:
415 return '?'
417 def set_xmlns(self, xmlns):
418 if self._xmlns is None and not self.xmlns:
419 self._xmlns = xmlns
421 if self.multivalued:
422 self.content_t.set_xmlns(xmlns)
424 def get_xmlns(self):
425 return self._xmlns or self.xmlns
427 def get_xmltagname(self):
428 if self._xmltagname is not None:
429 return self.get_xmlns() + ' ' + self._xmltagname
430 elif self.name:
431 return self.get_xmlns() + ' ' \
432 + make_xmltagname_from_name(self.name)
433 elif self.xmltagname:
434 return self.get_xmlns() + ' ' + self.xmltagname
435 else:
436 assert False
438 @classmethod
439 def get_property(cls, name):
440 for prop in cls.properties:
441 if prop.name == name:
442 return prop
444 raise ValueError()
446 @classmethod
447 def remove_property(cls, name):
449 prop = cls.get_property(name)
451 if not prop.multivalued:
452 del cls.xmltagname_to_class[prop.effective_xmltagname]
453 del cls.xmltagname_to_name[prop.effective_xmltagname]
454 else:
455 del cls.xmltagname_to_class[prop.content_t.effective_xmltagname]
456 del cls.xmltagname_to_name_multivalued[
457 prop.content_t.effective_xmltagname]
459 if cls.content_property is prop:
460 cls.content_property = None
462 cls.properties.remove(prop)
463 cls.propnames.remove(name)
465 return prop
467 @classmethod
468 def add_property(cls, name, prop):
470 prop.instance = prop
471 prop.name = name
472 prop.set_xmlns(cls.xmlns)
474 if isinstance(prop, Choice.T):
475 for tc in prop.choices:
476 tc.effective_xmltagname = tc.get_xmltagname()
477 cls.xmltagname_to_class[tc.effective_xmltagname] = tc._cls
478 cls.xmltagname_to_name[tc.effective_xmltagname] = prop.name
479 elif not prop.multivalued:
480 prop.effective_xmltagname = prop.get_xmltagname()
481 cls.xmltagname_to_class[prop.effective_xmltagname] = prop._cls
482 cls.xmltagname_to_name[prop.effective_xmltagname] = prop.name
483 else:
484 prop.content_t.name = make_content_name(prop.name)
485 prop.content_t.effective_xmltagname = \
486 prop.content_t.get_xmltagname()
487 cls.xmltagname_to_class[
488 prop.content_t.effective_xmltagname] = prop.content_t._cls
489 cls.xmltagname_to_name_multivalued[
490 prop.content_t.effective_xmltagname] = prop.name
492 cls.properties.append(prop)
494 cls.properties.sort(key=lambda x: x.position)
496 cls.propnames = [p.name for p in cls.properties]
498 if prop.xmlstyle == 'content':
499 cls.content_property = prop
501 @classmethod
502 def ivals(cls, val):
503 for prop in cls.properties:
504 yield getattr(val, prop.name)
506 @classmethod
507 def ipropvals(cls, val):
508 for prop in cls.properties:
509 yield prop, getattr(val, prop.name)
511 @classmethod
512 def inamevals(cls, val):
513 for prop in cls.properties:
514 yield prop.name, getattr(val, prop.name)
516 @classmethod
517 def ipropvals_to_save(cls, val, xmlmode=False):
518 for prop in cls.properties:
519 v = getattr(val, prop.name)
520 if v is not None and (
521 not (prop.optional or (prop.multivalued and not v))
522 or (not prop.is_default(v))):
524 if xmlmode:
525 yield prop, prop.to_save_xml(v)
526 else:
527 yield prop, prop.to_save(v)
529 @classmethod
530 def inamevals_to_save(cls, val, xmlmode=False):
531 for prop, v in cls.ipropvals_to_save(val, xmlmode):
532 yield prop.name, v
534 @classmethod
535 def translate_from_xml(cls, list_of_pairs, strict):
536 d = {}
537 for k, v in list_of_pairs:
538 if k in cls.xmltagname_to_name_multivalued:
539 k2 = cls.xmltagname_to_name_multivalued[k]
540 if k2 not in d:
541 d[k2] = []
543 d[k2].append(v)
544 elif k in cls.xmltagname_to_name:
545 k2 = cls.xmltagname_to_name[k]
546 if k2 in d:
547 raise ArgumentError(
548 'Unexpectedly found more than one child element "%s" '
549 'within "%s".' % (k, cls.tagname))
551 d[k2] = v
552 elif k is None:
553 if cls.content_property:
554 k2 = cls.content_property.name
555 d[k2] = v
556 else:
557 if strict:
558 raise ArgumentError(
559 'Unexpected child element "%s" found within "%s".' % (
560 k, cls.tagname))
562 return d
564 def validate(self, val, regularize=False, depth=-1):
565 if self.optional and val is None:
566 return val
568 is_derived = isinstance(val, self._cls)
569 is_exact = type(val) is self._cls
571 not_ok = not self.strict and not is_derived or \
572 self.strict and not is_exact
574 if not_ok or self.force_regularize:
575 if regularize:
576 try:
577 val = self.regularize_extra(val)
578 except ValueError:
579 raise ValidationError(
580 '%s: could not convert "%s" to type %s' % (
581 self.xname(), val, classnames(self._cls)))
582 else:
583 raise ValidationError(
584 '%s: "%s" (type: %s) is not of type %s' % (
585 self.xname(), val, type(val), classnames(self._cls)))
587 validator = self
588 if isinstance(self._cls, tuple):
589 clss = self._cls
590 else:
591 clss = (self._cls,)
593 for cls in clss:
594 try:
595 if type(val) is not cls and isinstance(val, cls):
596 validator = val.T.instance
598 except AttributeError:
599 pass
601 validator.validate_extra(val)
603 if depth != 0:
604 val = validator.validate_children(val, regularize, depth)
606 return val
608 def regularize_extra(self, val):
609 return self._cls(val)
611 def validate_extra(self, val):
612 pass
614 def validate_children(self, val, regularize, depth):
615 for prop, propval in self.ipropvals(val):
616 newpropval = prop.validate(propval, regularize, depth-1)
617 if regularize and (newpropval is not propval):
618 setattr(val, prop.name, newpropval)
620 return val
622 def to_save(self, val):
623 return val
625 def to_save_xml(self, val):
626 return self.to_save(val)
628 def extend_xmlelements(self, elems, v):
629 if self.multivalued:
630 for x in v:
631 elems.append((self.content_t.effective_xmltagname, x))
632 else:
633 elems.append((self.effective_xmltagname, v))
635 def deferred(self):
636 return []
638 def classname_for_help(self, strip_module=''):
640 if self._dummy_cls is not self._cls:
641 if self._dummy_cls.__module__ == strip_module:
642 sadd = ' (:py:class:`%s`)' % (
643 self._dummy_cls.__name__)
644 else:
645 sadd = ' (:py:class:`%s.%s`)' % (
646 self._dummy_cls.__module__, self._dummy_cls.__name__)
647 else:
648 sadd = ''
650 if self._dummy_cls in guts_plain_dummy_types:
651 return '``%s``' % self._cls.__name__
653 elif self._dummy_cls.dummy_for_description:
654 return '%s%s' % (self._dummy_cls.dummy_for_description, sadd)
656 else:
657 def sclass(cls):
658 mod = cls.__module__
659 clsn = cls.__name__
660 if mod == '__builtin__' or mod == 'builtins':
661 return '``%s``' % clsn
663 elif mod == strip_module:
664 return ':py:class:`%s`' % clsn
666 else:
667 return ':py:class:`%s.%s`' % (mod, clsn)
669 if isinstance(self._cls, tuple):
670 return '(%s)%s' % (
671 ' | '.join(sclass(cls) for cls in self._cls), sadd)
672 else:
673 return '%s%s' % (sclass(self._cls), sadd)
675 @classmethod
676 def props_help_string(cls):
677 baseprops = []
678 for base in cls._dummy_cls.__bases__:
679 if hasattr(base, 'T'):
680 baseprops.extend(base.T.properties)
682 hlp = []
683 hlp.append('')
684 for prop in cls.properties:
685 if prop in baseprops:
686 continue
688 descr = [
689 prop.classname_for_help(
690 strip_module=cls._dummy_cls.__module__)]
692 if prop.optional:
693 descr.append('*optional*')
695 if isinstance(prop._default, DefaultMaker):
696 descr.append('*default:* ``%s``' % repr(prop._default))
697 else:
698 d = prop.default()
699 if d is not None:
700 descr.append('*default:* ``%s``' % repr(d))
702 hlp.append(' .. py:gattribute:: %s' % prop.name)
703 hlp.append('')
704 hlp.append(' %s' % ', '.join(descr))
705 hlp.append(' ')
706 if prop.help is not None:
707 hlp.append(' %s' % prop.help)
708 hlp.append('')
710 return '\n'.join(hlp)
712 @classmethod
713 def class_help_string(cls):
714 return cls._dummy_cls.__doc_template__
716 @classmethod
717 def class_signature(cls):
718 r = []
719 for prop in cls.properties:
720 d = prop.default()
721 if d is not None:
722 arg = repr(d)
724 elif prop.optional:
725 arg = 'None'
727 else:
728 arg = '...'
730 r.append('%s=%s' % (prop.name, arg))
732 return '(%s)' % ', '.join(r)
734 @classmethod
735 def help(cls):
736 return cls.props_help_string()
739class ObjectMetaClass(type):
740 def __new__(meta, classname, bases, class_dict):
741 classname = class_dict.get('class_name', classname)
742 cls = type.__new__(meta, classname, bases, class_dict)
743 if classname != 'Object':
744 t_class_attr_name = '_%s__T' % classname
745 if not hasattr(cls, t_class_attr_name):
746 if hasattr(cls, 'T'):
747 class T(cls.T):
748 _sphinx_doc_skip = True
750 T.__doc__ = cls.T.__doc__
751 else:
752 class T(TBase):
753 _sphinx_doc_skip = True
755 T.__doc__ = TBase.__doc__
757 setattr(cls, t_class_attr_name, T)
759 T = getattr(cls, t_class_attr_name)
760 T.__name__ = 'T'
761 T.__qualname__ = T.__qualname__.replace('__T', 'T')
763 if cls.dummy_for is not None:
764 T._cls = cls.dummy_for
765 else:
766 T._cls = cls
768 T._dummy_cls = cls
770 if hasattr(cls, 'xmltagname'):
771 T.xmltagname = cls.xmltagname
772 else:
773 T.xmltagname = classname
775 mod = sys.modules[cls.__module__]
777 if hasattr(cls, 'xmlns'):
778 T.xmlns = cls.xmlns
779 elif hasattr(mod, 'guts_xmlns'):
780 T.xmlns = mod.guts_xmlns
781 else:
782 T.xmlns = ''
784 if T.xmlns and hasattr(cls, 'guessable_xmlns'):
785 g_guessable_xmlns[T.xmltagname] = cls.guessable_xmlns
787 if hasattr(mod, 'guts_prefix'):
788 if mod.guts_prefix:
789 T.tagname = mod.guts_prefix + '.' + classname
790 else:
791 T.tagname = classname
792 else:
793 if cls.__module__ != '__main__':
794 T.tagname = cls.__module__ + '.' + classname
795 else:
796 T.tagname = classname
798 T.classname = classname
800 T.init_propertystuff()
802 for k in dir(cls):
803 prop = getattr(cls, k)
805 if k.endswith('__'):
806 k = k[:-2]
808 if isinstance(prop, TBase):
809 if prop.deferred():
810 for defer in prop.deferred():
811 g_deferred_content.setdefault(
812 defer.classname[:-2], []).append((prop, defer))
813 g_deferred.setdefault(
814 defer.classname[:-2], []).append((T, k, prop))
816 else:
817 T.add_property(k, prop)
819 elif isinstance(prop, Defer):
820 g_deferred.setdefault(prop.classname[:-2], []).append(
821 (T, k, prop))
823 if classname in g_deferred_content:
824 for prop, defer in g_deferred_content[classname]:
825 prop.process_deferred(
826 defer, T(*defer.args, **defer.kwargs))
828 del g_deferred_content[classname]
830 if classname in g_deferred:
831 for (T_, k_, prop_) in g_deferred.get(classname, []):
832 if isinstance(prop_, Defer):
833 prop_ = T(*prop_.args, **prop_.kwargs)
835 if not prop_.deferred():
836 T_.add_property(k_, prop_)
838 del g_deferred[classname]
840 g_tagname_to_class[T.tagname] = cls
841 if hasattr(cls, 'xmltagname'):
842 g_xmltagname_to_class[T.xmlns + ' ' + T.xmltagname] = cls
844 cls.T = T
845 T.instance = T()
847 cls.__doc_template__ = cls.__doc__
848 cls.__doc__ = T.class_help_string()
850 if cls.__doc__ is None:
851 cls.__doc__ = 'Undocumented.'
853 cls.__doc__ += '\n' + T.props_help_string()
855 return cls
858class ValidationError(ValueError):
859 '''
860 Raised when an object is invalid according to its definition.
861 '''
862 pass
865class ArgumentError(ValueError):
866 '''
867 Raised when invalid arguments would be used in an object's initialization.
868 '''
869 pass
872def make_default(x):
873 if isinstance(x, DefaultMaker):
874 return x.make()
875 elif isinstance(x, Object):
876 return clone(x)
877 else:
878 return x
881class DefaultMaker(object):
882 '''
883 Base class for default value factories.
884 '''
885 def make(self):
886 '''
887 Create a new object.
888 '''
889 raise NotImplementedError
892class ObjectDefaultMaker(DefaultMaker):
893 '''
894 Default value factory for :py:class:`Object` derived classes.
895 '''
896 def __init__(self, cls, args, kwargs):
897 DefaultMaker.__init__(self)
898 self._cls = cls
899 self.args = args
900 self.kwargs = kwargs
901 self.instance = None
903 def make(self):
904 return self._cls(
905 *[make_default(x) for x in self.args],
906 **dict((k, make_default(v)) for (k, v) in self.kwargs.items()))
908 def __eq__(self, other):
909 if self.instance is None:
910 self.instance = self.make()
912 return self.instance == other
914 def __repr__(self):
915 sargs = []
916 for arg in self.args:
917 sargs.append(repr(arg))
919 for k, v in self.kwargs.items():
920 sargs.append(
921 '%s=%s' % (
922 k,
923 ' '.join(line.strip() for line in repr(v).splitlines())))
925 return '%s(%s)' % (self._cls.__name__, ', '.join(sargs))
928class TimestampDefaultMaker(DefaultMaker):
929 def __init__(self, s, format='%Y-%m-%d %H:%M:%S.OPTFRAC'):
930 DefaultMaker.__init__(self)
931 self._stime = s
932 self._format = format
934 def make(self):
935 return str_to_time(self._stime, self._format)
937 def __repr__(self):
938 return 'str_to_time(%s)' % repr(self._stime)
941def with_metaclass(meta, *bases):
942 # inlined py2/py3 compat solution from python-future
943 class metaclass(meta):
944 __call__ = type.__call__
945 __init__ = type.__init__
947 def __new__(cls, name, this_bases, d):
948 if this_bases is None:
949 return type.__new__(cls, name, (), d)
950 return meta(name, bases, d)
952 return metaclass('temp', None, {})
955class Object(with_metaclass(ObjectMetaClass, object)):
956 '''
957 Base class for Guts objects.
959 :cvar dummy_for:
960 (class variable) If set, this indicates that the containing class is a
961 dummy for another type. This can be used to hold native Python objects
962 and non-Guts based objects as children of a Guts object.
963 :cvar dummy_for_description:
964 (class variable) Overrides the name shown in the "dummy for ..."
965 documentation strings.
966 '''
968 dummy_for = None
969 dummy_for_description = None
971 def __init__(self, **kwargs):
972 if not kwargs.get('init_props', True):
973 return
975 for prop in self.T.properties:
976 k = prop.name
977 if k in kwargs:
978 setattr(self, k, kwargs.pop(k))
979 else:
980 if not prop.optional and not prop.has_default():
981 raise ArgumentError('Missing argument to %s: %s' % (
982 self.T.tagname, prop.name))
983 else:
984 setattr(self, k, prop.default())
986 if kwargs:
987 raise ArgumentError('Invalid argument to %s: %s' % (
988 self.T.tagname, ', '.join(list(kwargs.keys()))))
990 @classmethod
991 def D(cls, *args, **kwargs):
992 '''
993 Get a default value factory for this class, configured with
994 specified arguments.
996 :returns:
997 Factory for default values.
998 :rtype:
999 :py:class:`ObjectDefaultMaker` object
1000 '''
1001 return ObjectDefaultMaker(cls, args, kwargs)
1003 def validate(self, regularize=False, depth=-1):
1004 '''
1005 Validate this object.
1007 Raises :py:class:`ValidationError` when the object is invalid.
1009 :param depth:
1010 Maximum depth to descend into child objects.
1011 :type depth:
1012 int
1013 '''
1014 self.T.instance.validate(self, regularize, depth)
1016 def regularize(self, depth=-1):
1017 '''
1018 Regularize this object.
1020 Regularization tries to convert child objects of invalid types to the
1021 expected types.
1023 Raises :py:class:`ValidationError` when the object is invalid and
1024 cannot be regularized.
1026 :param depth:
1027 Maximum depth to descend into child objects.
1028 :type depth:
1029 int
1030 '''
1031 self.validate(regularize=True, depth=depth)
1033 def dump(self, stream=None, filename=None, header=False):
1034 '''
1035 Serialize to YAML.
1037 If neither ``stream`` nor ``filename`` is set, a string containing the
1038 serialized data is returned.
1040 :param stream:
1041 Output to stream.
1043 :param filename:
1044 Output to file of given name.
1045 :type filename:
1046 str
1048 :param header:
1049 File header to prepend to the output.
1050 :type header:
1051 str
1052 '''
1053 return dump(self, stream=stream, filename=filename, header=header)
1055 def dump_xml(
1056 self, stream=None, filename=None, header=False, ns_ignore=False):
1057 '''
1058 Serialize to XML.
1060 If neither ``stream`` nor ``filename`` is set, a string containing the
1061 serialized data is returned.
1063 :param stream:
1064 Output to stream.
1066 :param filename:
1067 Output to file of given name.
1068 :type filename:
1069 str
1071 :param header:
1072 File header to prepend to the output.
1073 :type header:
1074 str
1076 :param ns_ignore:
1077 Whether to ignore the XML namespace.
1078 :type ns_ignore:
1079 bool
1080 '''
1081 return dump_xml(
1082 self, stream=stream, filename=filename, header=header,
1083 ns_ignore=ns_ignore)
1085 @classmethod
1086 def load(cls, stream=None, filename=None, string=None):
1087 '''
1088 Deserialize from YAML.
1090 :param stream:
1091 Read input from stream.
1093 :param filename:
1094 Read input from file of given name.
1095 :type filename:
1096 str
1098 :param string:
1099 Read input from string.
1100 :type string:
1101 str
1102 '''
1103 return load(stream=stream, filename=filename, string=string)
1105 @classmethod
1106 def load_xml(cls, stream=None, filename=None, string=None, ns_hints=None,
1107 ns_ignore=False):
1108 '''
1109 Deserialize from XML.
1111 :param stream:
1112 Read input from stream.
1114 :param filename:
1115 Read input from file of given name.
1116 :type filename:
1117 str
1119 :param string:
1120 Read input from string.
1121 :type string:
1122 str
1123 '''
1125 if ns_hints is None:
1126 ns_hints = [cls.T.instance.get_xmlns()]
1128 return load_xml(
1129 stream=stream,
1130 filename=filename,
1131 string=string,
1132 ns_hints=ns_hints,
1133 ns_ignore=ns_ignore)
1135 def __str__(self):
1136 return self.dump()
1139def to_dict(obj):
1140 '''
1141 Get dict of guts object attributes.
1143 :param obj: :py:class`Object` object
1144 '''
1146 return dict(obj.T.inamevals(obj))
1149class SObject(Object):
1150 '''
1151 Base class for simple str-serializable Guts objects.
1153 Derived classes must support (de)serialization as in ``X(str(x))``.
1154 '''
1156 class __T(TBase):
1157 def regularize_extra(self, val):
1158 if isinstance(val, str):
1159 return self._cls(val)
1161 return val
1163 def to_save(self, val):
1164 return str(val)
1166 def to_save_xml(self, val):
1167 return str(val)
1170class Any(Object):
1171 '''
1172 Placeholder for any object.
1173 '''
1175 class __T(TBase):
1176 def validate(self, val, regularize=False, depth=-1):
1177 if isinstance(val, Object):
1178 val.validate(regularize, depth)
1180 return val
1183class Int(Object):
1184 '''
1185 Placeholder for :py:class:`int`.
1186 '''
1187 dummy_for = int
1189 class __T(TBase):
1190 strict = True
1192 def to_save_xml(self, value):
1193 return repr(value)
1196class Float(Object):
1197 '''
1198 Placeholder for :py:class:`float`.
1199 '''
1200 dummy_for = float
1202 class __T(TBase):
1203 strict = True
1205 def to_save_xml(self, value):
1206 return repr(value)
1209class Complex(Object):
1210 '''
1211 Placeholder for :py:class:`complex`.
1212 '''
1213 dummy_for = complex
1215 class __T(TBase):
1216 strict = True
1218 def regularize_extra(self, val):
1220 if isinstance(val, list) or isinstance(val, tuple):
1221 assert len(val) == 2
1222 val = complex(*val)
1224 elif not isinstance(val, complex):
1225 val = complex(val)
1227 return val
1229 def to_save(self, value):
1230 return repr(value)
1232 def to_save_xml(self, value):
1233 return repr(value)
1236class Bool(Object):
1237 '''
1238 Placeholder for :py:class:`bool`.
1239 '''
1240 dummy_for = bool
1242 class __T(TBase):
1243 strict = True
1245 def regularize_extra(self, val):
1246 if isinstance(val, str):
1247 if val.lower().strip() in ('0', 'false'):
1248 return False
1250 return bool(val)
1252 def to_save_xml(self, value):
1253 return repr(bool(value)).lower()
1256class String(Object):
1257 '''
1258 Placeholder for :py:class:`str`.
1259 '''
1260 dummy_for = str
1262 class __T(TBase):
1263 def __init__(self, *args, yamlstyle=None, **kwargs):
1264 TBase.__init__(self, *args, **kwargs)
1265 self.style_cls = str_style_map[yamlstyle]
1267 def to_save(self, val):
1268 return self.style_cls(val)
1271class Bytes(Object):
1272 '''
1273 Placeholder for :py:class:`bytes`.
1274 '''
1275 dummy_for = bytes
1277 class __T(TBase):
1279 def regularize_extra(self, val):
1280 if isinstance(val, str):
1281 val = b64decode(val)
1283 return val
1285 def to_save(self, val):
1286 return literal(b64encode(val).decode('utf-8'))
1289class Unicode(Object):
1290 '''
1291 Placeholder for :py:class:`str`.
1292 '''
1293 dummy_for = str
1295 class __T(TBase):
1296 def __init__(self, *args, yamlstyle=None, **kwargs):
1297 TBase.__init__(self, *args, **kwargs)
1298 self.style_cls = unicode_style_map[yamlstyle]
1300 def to_save(self, val):
1301 return self.style_cls(val)
1304guts_plain_dummy_types = (String, Unicode, Int, Float, Complex, Bool)
1307class Dict(Object):
1308 '''
1309 Placeholder for :py:class:`dict`.
1310 '''
1311 dummy_for = dict
1313 class __T(TBase):
1314 multivalued = dict
1316 def __init__(self, key_t=Any.T(), content_t=Any.T(), *args, **kwargs):
1317 TBase.__init__(self, *args, **kwargs)
1318 assert isinstance(key_t, TBase)
1319 assert isinstance(content_t, TBase)
1320 self.key_t = key_t
1321 self.content_t = content_t
1322 self.content_t.parent = self
1324 def default(self):
1325 if self._default is not None:
1326 return dict(
1327 (make_default(k), make_default(v))
1328 for (k, v) in self._default.items())
1330 if self.optional:
1331 return None
1332 else:
1333 return {}
1335 def has_default(self):
1336 return True
1338 def validate(self, val, regularize, depth):
1339 return TBase.validate(self, val, regularize, depth+1)
1341 def validate_children(self, val, regularize, depth):
1342 for key, ele in list(val.items()):
1343 newkey = self.key_t.validate(key, regularize, depth-1)
1344 newele = self.content_t.validate(ele, regularize, depth-1)
1345 if regularize:
1346 if newkey is not key or newele is not ele:
1347 del val[key]
1348 val[newkey] = newele
1350 return val
1352 def to_save(self, val):
1353 return dict((self.key_t.to_save(k), self.content_t.to_save(v))
1354 for (k, v) in val.items())
1356 def to_save_xml(self, val):
1357 raise NotImplementedError
1359 def classname_for_help(self, strip_module=''):
1360 return '``dict`` of %s objects' % \
1361 self.content_t.classname_for_help(strip_module=strip_module)
1364class List(Object):
1365 '''
1366 Placeholder for :py:class:`list`.
1367 '''
1368 dummy_for = list
1370 class __T(TBase):
1371 multivalued = list
1373 def __init__(self, content_t=Any.T(), *args, yamlstyle=None, **kwargs):
1374 TBase.__init__(self, *args, **kwargs)
1375 assert isinstance(content_t, TBase) or isinstance(content_t, Defer)
1376 self.content_t = content_t
1377 self.content_t.parent = self
1378 self.style_cls = list_style_map[yamlstyle]
1380 def default(self):
1381 if self._default is not None:
1382 return [make_default(x) for x in self._default]
1383 if self.optional:
1384 return None
1385 else:
1386 return []
1388 def has_default(self):
1389 return True
1391 def validate(self, val, regularize, depth):
1392 return TBase.validate(self, val, regularize, depth+1)
1394 def validate_children(self, val, regularize, depth):
1395 for i, ele in enumerate(val):
1396 newele = self.content_t.validate(ele, regularize, depth-1)
1397 if regularize and newele is not ele:
1398 val[i] = newele
1400 return val
1402 def to_save(self, val):
1403 return self.style_cls(self.content_t.to_save(v) for v in val)
1405 def to_save_xml(self, val):
1406 return [self.content_t.to_save_xml(v) for v in val]
1408 def deferred(self):
1409 if isinstance(self.content_t, Defer):
1410 return [self.content_t]
1412 return []
1414 def process_deferred(self, defer, t_inst):
1415 if defer is self.content_t:
1416 self.content_t = t_inst
1418 def classname_for_help(self, strip_module=''):
1419 return '``list`` of %s objects' % \
1420 self.content_t.classname_for_help(strip_module=strip_module)
1423def make_typed_list_class(t):
1424 class TL(List):
1425 class __T(List.T):
1426 def __init__(self, *args, **kwargs):
1427 List.T.__init__(self, content_t=t.T(), *args, **kwargs)
1429 return TL
1432class Tuple(Object):
1433 '''
1434 Placeholder for :py:class:`tuple`.
1435 '''
1436 dummy_for = tuple
1438 class __T(TBase):
1439 multivalued = tuple
1441 def __init__(self, n=None, content_t=Any.T(), *args, **kwargs):
1442 TBase.__init__(self, *args, **kwargs)
1443 assert isinstance(content_t, TBase)
1444 self.content_t = content_t
1445 self.content_t.parent = self
1446 self.n = n
1448 def default(self):
1449 if self._default is not None:
1450 return tuple(
1451 make_default(x) for x in self._default)
1453 elif self.optional:
1454 return None
1455 else:
1456 if self.n is not None:
1457 return tuple(
1458 self.content_t.default() for x in range(self.n))
1459 else:
1460 return tuple()
1462 def has_default(self):
1463 return True
1465 def validate(self, val, regularize, depth):
1466 return TBase.validate(self, val, regularize, depth+1)
1468 def validate_extra(self, val):
1469 if self.n is not None and len(val) != self.n:
1470 raise ValidationError(
1471 '%s should have length %i' % (self.xname(), self.n))
1473 def validate_children(self, val, regularize, depth):
1474 if not regularize:
1475 for ele in val:
1476 self.content_t.validate(ele, regularize, depth-1)
1478 return val
1479 else:
1480 newval = []
1481 isnew = False
1482 for ele in val:
1483 newele = self.content_t.validate(ele, regularize, depth-1)
1484 newval.append(newele)
1485 if newele is not ele:
1486 isnew = True
1488 if isnew:
1489 return tuple(newval)
1490 else:
1491 return val
1493 def to_save(self, val):
1494 return tuple(self.content_t.to_save(v) for v in val)
1496 def to_save_xml(self, val):
1497 return [self.content_t.to_save_xml(v) for v in val]
1499 def classname_for_help(self, strip_module=''):
1500 if self.n is not None:
1501 return '``tuple`` of %i %s objects' % (
1502 self.n, self.content_t.classname_for_help(
1503 strip_module=strip_module))
1504 else:
1505 return '``tuple`` of %s objects' % (
1506 self.content_t.classname_for_help(
1507 strip_module=strip_module))
1510duration_unit_factors = dict(
1511 s=1.0,
1512 m=60.0,
1513 h=3600.0,
1514 d=24*3600.0,
1515 y=365*24*3600.0)
1518def parse_duration(s):
1519 unit = s[-1]
1520 if unit in duration_unit_factors:
1521 return float(s[:-1]) * duration_unit_factors[unit]
1522 else:
1523 return float(s)
1526def str_duration(d):
1527 for k in 'ydhms':
1528 if abs(d) >= duration_unit_factors[k]:
1529 return '%g' % (d / duration_unit_factors[k]) + k
1531 return '%g' % d
1534class Duration(Object):
1535 '''
1536 Placeholder for :py:class:`float` time duration [s] with human-readable
1537 (de)serialization.
1539 Examples:
1541 - ``'1s'`` -> 1 second
1542 - ``'1m'`` -> 1 minute
1543 - ``'1h'`` -> 1 hour
1544 - ``'1d'`` -> 1 day
1545 - ``'1y'`` -> about 1 year = 365*24*3600 seconds
1546 '''
1547 dummy_for = float
1549 class __T(TBase):
1550 def regularize_extra(self, val):
1551 if isinstance(val, str):
1552 return parse_duration(val)
1554 return val
1556 def to_save(self, val):
1557 return str_duration(val)
1559 def to_save_xml(self, val):
1560 return str_duration(val)
1563re_tz = re.compile(r'(Z|([+-][0-2][0-9])(:?([0-5][0-9]))?)$')
1566class Timestamp(Object):
1567 '''
1568 Placeholder for a UTC timestamp.
1569 '''
1570 dummy_for = (hpfloat, float)
1571 dummy_for_description = 'pyrocko.util.get_time_float'
1573 class __T(TBase):
1575 def regularize_extra(self, val):
1577 time_float = get_time_float()
1579 if isinstance(val, datetime.datetime):
1580 tt = val.utctimetuple()
1581 val = time_float(calendar.timegm(tt)) + val.microsecond * 1e-6
1583 elif isinstance(val, datetime.date):
1584 tt = val.timetuple()
1585 val = time_float(calendar.timegm(tt))
1587 elif isinstance(val, str):
1588 val = val.strip()
1589 tz_offset = 0
1591 m = re_tz.search(val)
1592 if m:
1593 sh = m.group(2)
1594 sm = m.group(4)
1595 tz_offset = (int(sh)*3600 if sh else 0) \
1596 + (int(sm)*60 if sm else 0)
1598 val = re_tz.sub('', val)
1600 if len(val) > 10 and val[10] == 'T':
1601 val = val.replace('T', ' ', 1)
1603 try:
1604 val = str_to_time(val) - tz_offset
1605 except TimeStrError:
1606 raise ValidationError(
1607 '%s: cannot parse time/date: %s' % (self.xname(), val))
1609 elif isinstance(val, (int, float)):
1610 val = time_float(val)
1612 else:
1613 raise ValidationError(
1614 '%s: cannot convert "%s" to type %s' % (
1615 self.xname(), val, time_float))
1617 return val
1619 def to_save(self, val):
1620 return time_to_str(val, format='%Y-%m-%d %H:%M:%S.9FRAC')\
1621 .rstrip('0').rstrip('.')
1623 def to_save_xml(self, val):
1624 return time_to_str(val, format='%Y-%m-%dT%H:%M:%S.9FRAC')\
1625 .rstrip('0').rstrip('.') + 'Z'
1627 @classmethod
1628 def D(self, s):
1629 return TimestampDefaultMaker(s)
1632class DateTimestamp(Object):
1633 '''
1634 Placeholder for a UTC timestamp which (de)serializes as a date string.
1635 '''
1636 dummy_for = (hpfloat, float)
1637 dummy_for_description = 'pyrocko.util.get_time_float'
1639 class __T(TBase):
1641 def regularize_extra(self, val):
1643 time_float = get_time_float()
1645 if isinstance(val, datetime.datetime):
1646 tt = val.utctimetuple()
1647 val = time_float(calendar.timegm(tt)) + val.microsecond * 1e-6
1649 elif isinstance(val, datetime.date):
1650 tt = val.timetuple()
1651 val = time_float(calendar.timegm(tt))
1653 elif isinstance(val, str):
1654 val = str_to_time(val, format='%Y-%m-%d')
1656 elif isinstance(val, int):
1657 val = time_float(val)
1659 return val
1661 def to_save(self, val):
1662 return time_to_str(val, format='%Y-%m-%d')
1664 def to_save_xml(self, val):
1665 return time_to_str(val, format='%Y-%m-%d')
1667 @classmethod
1668 def D(self, s):
1669 return TimestampDefaultMaker(s, format='%Y-%m-%d')
1672class StringPattern(String):
1674 '''
1675 Any :py:class:`str` matching pattern ``%(pattern)s``.
1676 '''
1678 dummy_for = str
1679 pattern = '.*'
1681 class __T(String.T):
1682 def __init__(self, pattern=None, *args, **kwargs):
1683 String.T.__init__(self, *args, **kwargs)
1685 if pattern is not None:
1686 self.pattern = pattern
1687 else:
1688 self.pattern = self._dummy_cls.pattern
1690 def validate_extra(self, val):
1691 pat = self.pattern
1692 if not re.search(pat, val):
1693 raise ValidationError('%s: "%s" does not match pattern %s' % (
1694 self.xname(), val, repr(pat)))
1696 @classmethod
1697 def class_help_string(cls):
1698 dcls = cls._dummy_cls
1699 doc = dcls.__doc_template__ or StringPattern.__doc_template__
1700 return doc % {'pattern': repr(dcls.pattern)}
1703class UnicodePattern(Unicode):
1705 '''
1706 Any :py:class:`str` matching pattern ``%(pattern)s``.
1707 '''
1709 dummy_for = str
1710 pattern = '.*'
1712 class __T(TBase):
1713 def __init__(self, pattern=None, *args, **kwargs):
1714 TBase.__init__(self, *args, **kwargs)
1716 if pattern is not None:
1717 self.pattern = pattern
1718 else:
1719 self.pattern = self._dummy_cls.pattern
1721 def validate_extra(self, val):
1722 pat = self.pattern
1723 if not re.search(pat, val, flags=re.UNICODE):
1724 raise ValidationError('%s: "%s" does not match pattern %s' % (
1725 self.xname(), val, repr(pat)))
1727 @classmethod
1728 def class_help_string(cls):
1729 dcls = cls._dummy_cls
1730 doc = dcls.__doc_template__ or UnicodePattern.__doc_template__
1731 return doc % {'pattern': repr(dcls.pattern)}
1734class StringChoice(String):
1736 '''
1737 Any :py:class:`str` out of ``%(choices)s``.
1739 :cvar choices:
1740 Allowed choices (:py:class:`list` of :py:class:`str`).
1741 :cvar ignore_case:
1742 Whether to behave case-insensitive (:py:class:`bool`, default:
1743 ``False``).
1744 '''
1746 dummy_for = str
1747 choices = []
1748 ignore_case = False
1750 class __T(String.T):
1751 def __init__(self, choices=None, ignore_case=None, *args, **kwargs):
1752 String.T.__init__(self, *args, **kwargs)
1754 if choices is not None:
1755 self.choices = choices
1756 else:
1757 self.choices = self._dummy_cls.choices
1759 if ignore_case is not None:
1760 self.ignore_case = ignore_case
1761 else:
1762 self.ignore_case = self._dummy_cls.ignore_case
1764 if self.ignore_case:
1765 self.choices = [x.upper() for x in self.choices]
1767 def validate_extra(self, val):
1768 if self.ignore_case:
1769 val = val.upper()
1771 if val not in self.choices:
1772 raise ValidationError(
1773 '%s: "%s" is not a valid choice out of %s' % (
1774 self.xname(), val, repr(self.choices)))
1776 @classmethod
1777 def class_help_string(cls):
1778 dcls = cls._dummy_cls
1779 doc = dcls.__doc_template__ or StringChoice.__doc_template__
1780 return doc % {'choices': repr(dcls.choices)}
1783class IntChoice(Int):
1785 '''
1786 Any :py:class:`int` out of ``%(choices)s``.
1787 '''
1789 dummy_for = int
1790 choices = []
1792 class __T(Int.T):
1793 def __init__(self, choices=None, *args, **kwargs):
1794 Int.T.__init__(self, *args, **kwargs)
1796 if choices is not None:
1797 self.choices = choices
1798 else:
1799 self.choices = self._dummy_cls.choices
1801 def validate_extra(self, val):
1802 if val not in self.choices:
1803 raise ValidationError(
1804 '%s: %i is not a valid choice out of %s' % (
1805 self.xname(), val, repr(self.choices)))
1807 @classmethod
1808 def class_help_string(cls):
1809 dcls = cls._dummy_cls
1810 doc = dcls.__doc_template__ or IntChoice.__doc_template__
1811 return doc % {'choices': repr(dcls.choices)}
1814# this will not always work...
1815class StringUnion(Object):
1816 '''
1817 Any :py:class:`str` matching any of a set of constraints.
1819 :cvar members:
1820 List of constraints, e.g. :py:class:`StringChoice`,
1821 :py:class:`StringPattern`, ... (:py:class:`list` of :py:class:`TBase`
1822 derived objects).
1824 '''
1826 members = []
1828 dummy_for = str
1830 class __T(TBase):
1831 def __init__(self, members=None, *args, **kwargs):
1832 TBase.__init__(self, *args, **kwargs)
1833 if members is not None:
1834 self.members = members
1835 else:
1836 self.members = self._dummy_cls.members
1838 def validate(self, val, regularize=False, depth=-1):
1839 assert self.members
1840 e2 = None
1841 for member in self.members:
1842 try:
1843 return member.validate(val, regularize, depth=depth)
1844 except ValidationError as e:
1845 e2 = e
1847 raise e2
1850class Choice(Object):
1851 '''
1852 Any out of a set of different types.
1854 :cvar choices:
1855 Allowed types (:py:class:`list` of :py:class:`TBase` derived objects).
1857 '''
1858 choices = []
1860 class __T(TBase):
1861 def __init__(self, choices=None, *args, **kwargs):
1862 TBase.__init__(self, *args, **kwargs)
1863 if choices is not None:
1864 self.choices = choices
1865 else:
1866 self.choices = self._dummy_cls.choices
1868 self.cls_to_xmltagname = dict(
1869 (t._cls, t.get_xmltagname()) for t in self.choices)
1871 def validate(self, val, regularize=False, depth=-1):
1872 if self.optional and val is None:
1873 return val
1875 t = None
1876 for tc in self.choices:
1877 is_derived = isinstance(val, tc._cls)
1878 is_exact = type(val) is tc._cls
1879 if not (not tc.strict and not is_derived or
1880 tc.strict and not is_exact):
1882 t = tc
1883 break
1885 if t is None:
1886 if regularize:
1887 ok = False
1888 for tc in self.choices:
1889 try:
1890 val = tc.regularize_extra(val)
1891 ok = True
1892 t = tc
1893 break
1894 except (ValidationError, ValueError):
1895 pass
1897 if not ok:
1898 raise ValidationError(
1899 '%s: could not convert "%s" to any type out of '
1900 '(%s)' % (self.xname(), val, ','.join(
1901 classnames(x._cls) for x in self.choices)))
1902 else:
1903 raise ValidationError(
1904 '%s: "%s" (type: %s) is not of any type out of '
1905 '(%s)' % (self.xname(), val, type(val), ','.join(
1906 classnames(x._cls) for x in self.choices)))
1908 validator = t
1910 if isinstance(t._cls, tuple):
1911 clss = t._cls
1912 else:
1913 clss = (t._cls,)
1915 for cls in clss:
1916 try:
1917 if type(val) is not cls and isinstance(val, cls):
1918 validator = val.T.instance
1920 except AttributeError:
1921 pass
1923 validator.validate_extra(val)
1925 if depth != 0:
1926 val = validator.validate_children(val, regularize, depth)
1928 return val
1930 def extend_xmlelements(self, elems, v):
1931 elems.append((
1932 self.cls_to_xmltagname[type(v)].split(' ', 1)[-1], v))
1935def _dump(
1936 object, stream,
1937 header=False,
1938 Dumper=GutsSafeDumper,
1939 _dump_function=yaml.dump):
1941 if not getattr(stream, 'encoding', None):
1942 enc = encode_utf8
1943 else:
1944 enc = no_encode
1946 if header:
1947 stream.write(enc(u'%YAML 1.1\n'))
1948 if isinstance(header, str):
1949 banner = u'\n'.join('# ' + x for x in header.splitlines()) + '\n'
1950 stream.write(enc(banner))
1952 _dump_function(
1953 object,
1954 stream=stream,
1955 encoding='utf-8',
1956 explicit_start=True,
1957 Dumper=Dumper)
1960def _dump_all(object, stream, header=True, Dumper=GutsSafeDumper):
1961 _dump(object, stream=stream, header=header, _dump_function=yaml.dump_all)
1964def _load(stream,
1965 Loader=GutsSafeLoader, allow_include=None, filename=None,
1966 included_files=None):
1968 class _Loader(Loader):
1969 _filename = filename
1970 _allow_include = allow_include
1971 _included_files = included_files or []
1973 return yaml.load(stream=stream, Loader=_Loader)
1976def _load_all(stream,
1977 Loader=GutsSafeLoader, allow_include=None, filename=None):
1979 class _Loader(Loader):
1980 _filename = filename
1981 _allow_include = allow_include
1983 return list(yaml.load_all(stream=stream, Loader=_Loader))
1986def _iload_all(stream,
1987 Loader=GutsSafeLoader, allow_include=None, filename=None):
1989 class _Loader(Loader):
1990 _filename = filename
1991 _allow_include = allow_include
1993 return yaml.load_all(stream=stream, Loader=_Loader)
1996def multi_representer(dumper, data):
1997 node = dumper.represent_mapping(
1998 '!'+data.T.tagname, data.T.inamevals_to_save(data), flow_style=False)
2000 return node
2003# hack for compatibility with early GF Store versions
2004re_compatibility = re.compile(
2005 r'^pyrocko\.(trace|gf\.(meta|seismosizer)|fomosto\.'
2006 r'(dummy|poel|qseis|qssp))\.'
2007)
2010def multi_constructor(loader, tag_suffix, node):
2011 tagname = str(tag_suffix)
2013 tagname = re_compatibility.sub('pf.', tagname)
2015 cls = g_tagname_to_class[tagname]
2016 kwargs = dict(iter(loader.construct_pairs(node, deep=True)))
2017 o = cls(**kwargs)
2018 o.validate(regularize=True, depth=1)
2019 return o
2022def include_constructor(loader, node):
2023 allow_include = loader._allow_include \
2024 if loader._allow_include is not None \
2025 else ALLOW_INCLUDE
2027 if not allow_include:
2028 raise EnvironmentError(
2029 'Not allowed to include YAML. Load with allow_include=True')
2031 if isinstance(node, yaml.nodes.ScalarNode):
2032 inc_file = loader.construct_scalar(node)
2033 else:
2034 raise TypeError('Unsupported YAML node %s' % repr(node))
2036 if loader._filename is not None and not op.isabs(inc_file):
2037 inc_file = op.join(op.dirname(loader._filename), inc_file)
2039 if not op.isfile(inc_file):
2040 raise FileNotFoundError(inc_file)
2042 included_files = list(loader._included_files)
2043 if loader._filename is not None:
2044 included_files.append(op.abspath(loader._filename))
2046 for included_file in loader._included_files:
2047 if op.samefile(inc_file, included_file):
2048 raise ImportError(
2049 'Circular import of file "%s". Include path: %s' % (
2050 op.abspath(inc_file),
2051 ' -> '.join('"%s"' % s for s in included_files)))
2053 with open(inc_file, 'rb') as f:
2054 return _load(
2055 f,
2056 Loader=loader.__class__, filename=inc_file,
2057 allow_include=True,
2058 included_files=included_files)
2061def dict_noflow_representer(dumper, data):
2062 return dumper.represent_mapping(
2063 'tag:yaml.org,2002:map', data, flow_style=False)
2066yaml.add_multi_representer(Object, multi_representer, Dumper=GutsSafeDumper)
2067yaml.add_constructor('!include', include_constructor, Loader=GutsSafeLoader)
2068yaml.add_multi_constructor('!', multi_constructor, Loader=GutsSafeLoader)
2069yaml.add_representer(dict, dict_noflow_representer, Dumper=GutsSafeDumper)
2072def str_representer(dumper, data):
2073 return dumper.represent_scalar(
2074 'tag:yaml.org,2002:str', str(data))
2077yaml.add_representer(str, str_representer, Dumper=GutsSafeDumper)
2080class Constructor(object):
2081 def __init__(self, add_namespace_maps=False, strict=False, ns_hints=None,
2082 ns_ignore=False):
2084 self.stack = []
2085 self.queue = []
2086 self.namespaces = defaultdict(list)
2087 self.add_namespace_maps = add_namespace_maps
2088 self.strict = strict
2089 self.ns_hints = ns_hints
2090 self.ns_ignore = ns_ignore
2092 def start_element(self, ns_name, attrs):
2093 if self.ns_ignore:
2094 ns_name = ns_name.split(' ')[-1]
2096 if -1 == ns_name.find(' '):
2097 if self.ns_hints is None and ns_name in g_guessable_xmlns:
2098 self.ns_hints = g_guessable_xmlns[ns_name]
2100 if self.ns_hints:
2101 ns_names = [
2102 ns_hint + ' ' + ns_name for ns_hint in self.ns_hints]
2104 elif self.ns_hints is None:
2105 ns_names = [' ' + ns_name]
2107 else:
2108 ns_names = [ns_name]
2110 for ns_name in ns_names:
2111 if self.stack and self.stack[-1][1] is not None:
2112 cls = self.stack[-1][1].T.xmltagname_to_class.get(
2113 ns_name, None)
2115 if isinstance(cls, tuple):
2116 cls = None
2117 else:
2118 if cls is not None and (
2119 not issubclass(cls, Object)
2120 or issubclass(cls, SObject)):
2121 cls = None
2122 else:
2123 cls = g_xmltagname_to_class.get(ns_name, None)
2125 if cls:
2126 break
2128 self.stack.append((ns_name, cls, attrs, [], []))
2130 def end_element(self, _):
2131 ns_name, cls, attrs, content2, content1 = self.stack.pop()
2133 ns = ns_name.split(' ', 1)[0]
2135 if cls is not None:
2136 content2.extend(
2137 (ns + ' ' + k if -1 == k.find(' ') else k, v)
2138 for (k, v) in attrs.items())
2139 content2.append((None, ''.join(content1)))
2140 o = cls(**cls.T.translate_from_xml(content2, self.strict))
2141 o.validate(regularize=True, depth=1)
2142 if self.add_namespace_maps:
2143 o.namespace_map = self.get_current_namespace_map()
2145 if self.stack and not all(x[1] is None for x in self.stack):
2146 self.stack[-1][-2].append((ns_name, o))
2147 else:
2148 self.queue.append(o)
2149 else:
2150 content = [''.join(content1)]
2151 if self.stack:
2152 for c in content:
2153 self.stack[-1][-2].append((ns_name, c))
2155 def characters(self, char_content):
2156 if self.stack:
2157 self.stack[-1][-1].append(char_content)
2159 def start_namespace(self, ns, uri):
2160 self.namespaces[ns].append(uri)
2162 def end_namespace(self, ns):
2163 self.namespaces[ns].pop()
2165 def get_current_namespace_map(self):
2166 return dict((k, v[-1]) for (k, v) in self.namespaces.items() if v)
2168 def get_queued_elements(self):
2169 queue = self.queue
2170 self.queue = []
2171 return queue
2174def _iload_all_xml(
2175 stream,
2176 bufsize=100000,
2177 add_namespace_maps=False,
2178 strict=False,
2179 ns_hints=None,
2180 ns_ignore=False):
2182 from xml.parsers.expat import ParserCreate
2183 from pyrocko import progress
2185 parser = ParserCreate('UTF-8', namespace_separator=' ')
2187 handler = Constructor(
2188 add_namespace_maps=add_namespace_maps,
2189 strict=strict,
2190 ns_hints=ns_hints,
2191 ns_ignore=ns_ignore)
2193 parser.StartElementHandler = handler.start_element
2194 parser.EndElementHandler = handler.end_element
2195 parser.CharacterDataHandler = handler.characters
2196 parser.StartNamespaceDeclHandler = handler.start_namespace
2197 parser.EndNamespaceDeclHandler = handler.end_namespace
2199 try:
2200 nbytes = os.fstat(stream.fileno()).st_size - stream.tell()
2201 except Exception:
2202 nbytes = None
2204 ibytes = 0
2205 task = progress.task('Parsing XML', nbytes, logger=logger)
2206 try:
2207 while True:
2208 data = stream.read(bufsize)
2209 ibytes += len(data)
2210 parser.Parse(data, bool(not data))
2211 for element in handler.get_queued_elements():
2212 yield element
2214 task.update(ibytes)
2216 if not data:
2217 break
2219 except Exception:
2220 task.fail()
2221 raise
2223 finally:
2224 task.done()
2227def _load_all_xml(*args, **kwargs):
2228 return list(_iload_all_xml(*args, **kwargs))
2231def _load_xml(*args, **kwargs):
2232 g = _iload_all_xml(*args, **kwargs)
2233 return next(g)
2236def _dump_all_xml(objects, stream, root_element_name='root', header=True):
2238 if not getattr(stream, 'encoding', None):
2239 enc = encode_utf8
2240 else:
2241 enc = no_encode
2243 _dump_xml_header(stream, header)
2245 beg = u'<%s>\n' % root_element_name
2246 end = u'</%s>\n' % root_element_name
2248 stream.write(enc(beg))
2250 for ob in objects:
2251 _dump_xml(ob, stream=stream)
2253 stream.write(enc(end))
2256def _dump_xml_header(stream, banner=None):
2258 if not getattr(stream, 'encoding', None):
2259 enc = encode_utf8
2260 else:
2261 enc = no_encode
2263 stream.write(enc(u'<?xml version="1.0" encoding="UTF-8" ?>\n'))
2264 if isinstance(banner, str):
2265 stream.write(enc(u'<!-- %s -->\n' % banner))
2268def _dump_xml(
2269 obj, stream, depth=0, ns_name=None, header=False, ns_map=[],
2270 ns_ignore=False):
2272 from xml.sax.saxutils import escape, quoteattr
2274 if not getattr(stream, 'encoding', None):
2275 enc = encode_utf8
2276 else:
2277 enc = no_encode
2279 if depth == 0 and header:
2280 _dump_xml_header(stream, header)
2282 indent = ' '*depth*2
2283 if ns_name is None:
2284 ns_name = obj.T.instance.get_xmltagname()
2286 if -1 != ns_name.find(' '):
2287 ns, name = ns_name.split(' ')
2288 else:
2289 ns, name = '', ns_name
2291 if isinstance(obj, Object):
2292 obj.validate(depth=1)
2293 attrs = []
2294 elems = []
2296 added_ns = False
2297 if not ns_ignore and ns and (not ns_map or ns_map[-1] != ns):
2298 attrs.append(('xmlns', ns))
2299 ns_map.append(ns)
2300 added_ns = True
2302 for prop, v in obj.T.ipropvals_to_save(obj, xmlmode=True):
2303 if prop.xmlstyle == 'attribute':
2304 assert not prop.multivalued
2305 assert not isinstance(v, Object)
2306 attrs.append((prop.effective_xmltagname, v))
2308 elif prop.xmlstyle == 'content':
2309 assert not prop.multivalued
2310 assert not isinstance(v, Object)
2311 elems.append((None, v))
2313 else:
2314 prop.extend_xmlelements(elems, v)
2316 attr_str = ''
2317 if attrs:
2318 attr_str = ' ' + ' '.join(
2319 '%s=%s' % (k.split(' ')[-1], quoteattr(str(v)))
2320 for (k, v) in attrs)
2322 if not elems:
2323 stream.write(enc(u'%s<%s%s />\n' % (indent, name, attr_str)))
2324 else:
2325 oneline = len(elems) == 1 and elems[0][0] is None
2326 stream.write(enc(u'%s<%s%s>%s' % (
2327 indent,
2328 name,
2329 attr_str,
2330 '' if oneline else '\n')))
2332 for (k, v) in elems:
2333 if k is None:
2334 stream.write(enc(escape(str(v), {'\0': '�'})))
2335 else:
2336 _dump_xml(v, stream, depth+1, k, False, ns_map, ns_ignore)
2338 stream.write(enc(u'%s</%s>\n' % (
2339 '' if oneline else indent, name)))
2341 if added_ns:
2342 ns_map.pop()
2344 else:
2345 stream.write(enc(u'%s<%s>%s</%s>\n' % (
2346 indent,
2347 name,
2348 escape(str(obj), {'\0': '�'}),
2349 name)))
2352def walk(x, typ=None, path=()):
2353 if typ is None or isinstance(x, typ):
2354 yield path, x
2356 if isinstance(x, Object):
2357 for (prop, val) in x.T.ipropvals(x):
2358 if prop.multivalued:
2359 if val is not None:
2360 for iele, ele in enumerate(val):
2361 for y in walk(ele, typ,
2362 path=path + ((prop.name, iele),)):
2363 yield y
2364 else:
2365 for y in walk(val, typ, path=path+(prop.name,)):
2366 yield y
2369def clone(x, pool=None):
2370 '''
2371 Clone guts object tree.
2373 Traverses guts object tree and recursively clones all guts attributes,
2374 falling back to :py:func:`copy.deepcopy` for non-guts objects. Objects
2375 deriving from :py:class:`Object` are instantiated using their respective
2376 init function. Multiply referenced objects in the source tree are multiply
2377 referenced also in the destination tree.
2379 This function can be used to clone guts objects ignoring any contained
2380 run-time state, i.e. any of their attributes not defined as a guts
2381 property.
2382 '''
2384 if pool is None:
2385 pool = {}
2387 if id(x) in pool:
2388 x_copy = pool[id(x)][1]
2390 else:
2391 if isinstance(x, SObject):
2392 x_copy = x.__class__(str(x))
2393 elif isinstance(x, Object):
2394 d = {}
2395 for (prop, y) in x.T.ipropvals(x):
2396 if y is not None:
2397 if not prop.multivalued:
2398 y_copy = clone(y, pool)
2399 elif prop.multivalued is dict:
2400 y_copy = dict(
2401 (clone(zk, pool), clone(zv, pool))
2402 for (zk, zv) in y.items())
2403 else:
2404 y_copy = type(y)(clone(z, pool) for z in y)
2405 else:
2406 y_copy = y
2408 d[prop.name] = y_copy
2410 x_copy = x.__class__(**d)
2412 else:
2413 x_copy = copy.deepcopy(x)
2415 pool[id(x)] = (x, x_copy)
2416 return x_copy
2419class YPathError(Exception):
2420 '''
2421 This exception is raised for invalid ypath specifications.
2422 '''
2423 pass
2426def _parse_yname(yname):
2427 ident = r'[a-zA-Z][a-zA-Z0-9_]*'
2428 rint = r'-?[0-9]+'
2429 m = re.match(
2430 r'^(%s)(\[((%s)?(:)(%s)?|(%s))\])?$'
2431 % (ident, rint, rint, rint), yname)
2433 if not m:
2434 raise YPathError('Syntax error in component: "%s"' % yname)
2436 d = dict(
2437 name=m.group(1))
2439 if m.group(2):
2440 if m.group(5):
2441 istart = iend = None
2442 if m.group(4):
2443 istart = int(m.group(4))
2444 if m.group(6):
2445 iend = int(m.group(6))
2447 d['slice'] = (istart, iend)
2448 else:
2449 d['index'] = int(m.group(7))
2451 return d
2454def _decend(obj, ynames):
2455 if ynames:
2456 for sobj in iter_elements(obj, ynames):
2457 yield sobj
2458 else:
2459 yield obj
2462def iter_elements(obj, ypath):
2463 '''
2464 Generator yielding elements matching a given ypath specification.
2466 :param obj: guts :py:class:`Object` instance
2467 :param ypath: Dot-separated object path (e.g. 'root.child.child').
2468 To access list objects use slice notatation (e.g.
2469 'root.child[:].child[1:3].child[1]').
2471 Raises :py:exc:`YPathError` on failure.
2472 '''
2474 try:
2475 if isinstance(ypath, str):
2476 ynames = ypath.split('.')
2477 else:
2478 ynames = ypath
2480 yname = ynames[0]
2481 ynames = ynames[1:]
2482 d = _parse_yname(yname)
2483 if d['name'] not in obj.T.propnames:
2484 raise AttributeError(d['name'])
2486 obj = getattr(obj, d['name'])
2488 if 'index' in d:
2489 sobj = obj[d['index']]
2490 for ssobj in _decend(sobj, ynames):
2491 yield ssobj
2493 elif 'slice' in d:
2494 for i in range(*slice(*d['slice']).indices(len(obj))):
2495 sobj = obj[i]
2496 for ssobj in _decend(sobj, ynames):
2497 yield ssobj
2498 else:
2499 for sobj in _decend(obj, ynames):
2500 yield sobj
2502 except (AttributeError, IndexError) as e:
2503 raise YPathError('Invalid ypath: "%s" (%s)' % (ypath, str(e)))
2506def get_elements(obj, ypath):
2507 '''
2508 Get all elements matching a given ypath specification.
2510 :param obj: guts :py:class:`Object` instance
2511 :param ypath: Dot-separated object path (e.g. 'root.child.child').
2512 To access list objects use slice notatation (e.g.
2513 'root.child[:].child[1:3].child[1]').
2515 Raises :py:exc:`YPathError` on failure.
2516 '''
2517 return list(iter_elements(obj, ypath))
2520def set_elements(obj, ypath, value, validate=False, regularize=False):
2521 '''
2522 Set elements matching a given ypath specification.
2524 :param obj: guts :py:class:`Object` instance
2525 :param ypath: Dot-separated object path (e.g. 'root.child.child').
2526 To access list objects use slice notatation (e.g.
2527 'root.child[:].child[1:3].child[1]').
2528 :param value: All matching elements will be set to `value`.
2529 :param validate: Whether to validate affected subtrees.
2530 :param regularize: Whether to regularize affected subtrees.
2532 Raises :py:exc:`YPathError` on failure.
2533 '''
2535 ynames = ypath.split('.')
2536 try:
2537 d = _parse_yname(ynames[-1])
2538 if ynames[:-1]:
2539 it = iter_elements(obj, ynames[:-1])
2540 else:
2541 it = [obj]
2543 for sobj in it:
2544 if d['name'] not in sobj.T.propnames:
2545 raise AttributeError(d['name'])
2547 if 'index' in d:
2548 ssobj = getattr(sobj, d['name'])
2549 ssobj[d['index']] = value
2550 elif 'slice' in d:
2551 ssobj = getattr(sobj, d['name'])
2552 for i in range(*slice(*d['slice']).indices(len(ssobj))):
2553 ssobj[i] = value
2554 else:
2555 setattr(sobj, d['name'], value)
2556 if regularize:
2557 sobj.regularize()
2558 if validate:
2559 sobj.validate()
2561 except (AttributeError, IndexError, YPathError) as e:
2562 raise YPathError('Invalid ypath: "%s" (%s)' % (ypath, str(e)))
2565def zip_walk(x, typ=None, path=(), stack=()):
2566 if typ is None or isinstance(x, typ):
2567 yield path, stack + (x,)
2569 if isinstance(x, Object):
2570 for (prop, val) in x.T.ipropvals(x):
2571 if prop.multivalued:
2572 if val is not None:
2573 for iele, ele in enumerate(val):
2574 for y in zip_walk(
2575 ele, typ,
2576 path=path + ((prop.name, iele),),
2577 stack=stack + (x,)):
2579 yield y
2580 else:
2581 for y in zip_walk(val, typ,
2582 path=path+(prop.name,),
2583 stack=stack + (x,)):
2584 yield y
2587def path_element(x):
2588 if isinstance(x, tuple):
2589 if len(x) == 2:
2590 return '%s[%i]' % x
2591 elif len(x) == 3:
2592 return '%s[%i:%i]' % x
2594 else:
2595 return x
2598def path_to_str(path):
2599 return '.'.join(path_element(x) for x in path)
2602@expand_stream_args('w')
2603def dump(obj, stream, **kwargs):
2604 '''
2605 Serialize to YAML.
2607 If neither ``stream`` nor ``filename`` is set, a string containing the
2608 serialized data is returned.
2610 :param obj:
2611 Object to be serialized.
2612 :type obj:
2613 :py:class:`Object`
2615 :param stream:
2616 Output to stream.
2618 :param filename:
2619 Output to file of given name.
2620 :type filename:
2621 str
2623 :param header:
2624 File header to prepend to the output.
2625 :type header:
2626 str
2627 '''
2628 return _dump(obj, stream, **kwargs)
2631@expand_stream_args('r')
2632def load(stream, **kwargs):
2633 return _load(stream, **kwargs)
2636def load_string(s, **kwargs):
2637 return load(string=s, **kwargs)
2640@expand_stream_args('w')
2641def dump_all(obj, stream, **kwargs):
2642 return _dump_all(obj, stream, **kwargs)
2645@expand_stream_args('r')
2646def load_all(stream, **kwargs):
2647 return _load_all(stream, **kwargs)
2650@expand_stream_args('r')
2651def iload_all(stream, **kwargs):
2652 return _iload_all(stream, **kwargs)
2655@expand_stream_args('w')
2656def dump_xml(obj, stream, **kwargs):
2657 '''
2658 Serialize to XML.
2660 If neither ``stream`` nor ``filename`` is set, a string containing the
2661 serialized data is returned.
2663 :param obj:
2664 Object to be serialized.
2665 :type obj:
2666 :py:class:`Object`
2668 :param stream:
2669 Output to stream.
2671 :param filename:
2672 Output to file of given name.
2673 :type filename:
2674 str
2676 :param header:
2677 File header to prepend to the output.
2678 :type header:
2679 str
2681 :param ns_ignore:
2682 Whether to ignore the XML namespace.
2683 :type ns_ignore:
2684 bool
2685 '''
2686 return _dump_xml(obj, stream, **kwargs)
2689@expand_stream_args('r')
2690def load_xml(stream, **kwargs):
2691 kwargs.pop('filename', None)
2692 return _load_xml(stream, **kwargs)
2695def load_xml_string(s, **kwargs):
2696 return load_xml(string=s, **kwargs)
2699@expand_stream_args('w')
2700def dump_all_xml(obj, stream, **kwargs):
2701 return _dump_all_xml(obj, stream, **kwargs)
2704@expand_stream_args('r')
2705def load_all_xml(stream, **kwargs):
2706 kwargs.pop('filename', None)
2707 return _load_all_xml(stream, **kwargs)
2710@expand_stream_args('r')
2711def iload_all_xml(stream, **kwargs):
2712 kwargs.pop('filename', None)
2713 return _iload_all_xml(stream, **kwargs)
2716def _dump_all_spickle(objects, stream):
2717 import pickle
2718 header = b'SPICKLE'.ljust(512)
2719 stream.write(header, )
2720 for obj in objects:
2721 pickle.dump(obj, stream)
2724def _iload_all_spickle(stream):
2725 for obj, _ in _iload_all_spickle_internal(stream):
2726 yield obj
2729def _load_one_spickle_internal(stream):
2730 import pickle
2731 fpos = stream.tell()
2732 return pickle.load(stream), fpos
2735def _iload_all_spickle_internal(stream, offset=None):
2736 if offset is not None:
2737 stream.seek(offset, 0)
2738 else:
2739 header = stream.read(512)
2740 if not header.startswith(b'SPICKLE'):
2741 raise ValueError('Not a SPICKLE file.')
2743 while True:
2744 try:
2745 yield _load_one_spickle_internal(stream)
2746 except EOFError:
2747 break
2750def _load_all_spickle(stream):
2751 return list(_iload_all_spickle(stream))
2754@expand_stream_args('w')
2755def dump_all_spickle(objects, stream, **kwargs):
2756 return _dump_all_spickle(objects, stream)
2759@expand_stream_args('r')
2760def iload_all_spickle(stream, **kwargs):
2761 _iload_all_spickle(stream)
2764@expand_stream_args('r')
2765def load_all_spickle(stream, **kwargs):
2766 kwargs.pop('filename', None)
2767 return _load_all_spickle(stream, **kwargs)
2770__all__ = guts_types + [
2771 'guts_types', 'TBase', 'ValidationError',
2772 'ArgumentError', 'Defer',
2773 'DefaultMaker', 'ObjectDefaultMaker',
2774 'clone',
2775 'dump', 'load',
2776 'dump_all', 'load_all', 'iload_all',
2777 'dump_xml', 'load_xml',
2778 'dump_all_xml', 'load_all_xml', 'iload_all_xml',
2779 'load_string',
2780 'load_xml_string',
2781 'make_typed_list_class', 'walk', 'zip_walk', 'path_to_str'
2782]