Coverage for /usr/local/lib/python3.13/dist-packages/pyrocko/guts.py: 97%
1417 statements
« prev ^ index » next coverage.py v7.6.0, created at 2025-12-04 10:41 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2025-12-04 10:41 +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 self.post_init()
992 def post_init(self):
993 pass
995 @classmethod
996 def D(cls, *args, **kwargs):
997 '''
998 Get a default value factory for this class, configured with
999 specified arguments.
1001 :returns:
1002 Factory for default values.
1003 :rtype:
1004 :py:class:`ObjectDefaultMaker` object
1005 '''
1006 return ObjectDefaultMaker(cls, args, kwargs)
1008 def validate(self, regularize=False, depth=-1):
1009 '''
1010 Validate this object.
1012 Raises :py:class:`ValidationError` when the object is invalid.
1014 :param depth:
1015 Maximum depth to descend into child objects.
1016 :type depth:
1017 int
1018 '''
1019 self.T.instance.validate(self, regularize, depth)
1021 def regularize(self, depth=-1):
1022 '''
1023 Regularize this object.
1025 Regularization tries to convert child objects of invalid types to the
1026 expected types.
1028 Raises :py:class:`ValidationError` when the object is invalid and
1029 cannot be regularized.
1031 :param depth:
1032 Maximum depth to descend into child objects.
1033 :type depth:
1034 int
1035 '''
1036 self.validate(regularize=True, depth=depth)
1038 def dump(self, stream=None, filename=None, header=False):
1039 '''
1040 Serialize to YAML.
1042 If neither ``stream`` nor ``filename`` is set, a string containing the
1043 serialized data is returned.
1045 :param stream:
1046 Output to stream.
1048 :param filename:
1049 Output to file of given name.
1050 :type filename:
1051 str
1053 :param header:
1054 File header to prepend to the output.
1055 :type header:
1056 str
1057 '''
1058 return dump(self, stream=stream, filename=filename, header=header)
1060 def dump_xml(
1061 self, stream=None, filename=None, header=False, ns_ignore=False):
1062 '''
1063 Serialize to XML.
1065 If neither ``stream`` nor ``filename`` is set, a string containing the
1066 serialized data is returned.
1068 :param stream:
1069 Output to stream.
1071 :param filename:
1072 Output to file of given name.
1073 :type filename:
1074 str
1076 :param header:
1077 File header to prepend to the output.
1078 :type header:
1079 str
1081 :param ns_ignore:
1082 Whether to ignore the XML namespace.
1083 :type ns_ignore:
1084 bool
1085 '''
1086 return dump_xml(
1087 self, stream=stream, filename=filename, header=header,
1088 ns_ignore=ns_ignore)
1090 @classmethod
1091 def load(cls, stream=None, filename=None, string=None):
1092 '''
1093 Deserialize from YAML.
1095 :param stream:
1096 Read input from stream.
1098 :param filename:
1099 Read input from file of given name.
1100 :type filename:
1101 str
1103 :param string:
1104 Read input from string.
1105 :type string:
1106 str
1107 '''
1108 return load(stream=stream, filename=filename, string=string)
1110 @classmethod
1111 def load_xml(cls, stream=None, filename=None, string=None, ns_hints=None,
1112 ns_ignore=False):
1113 '''
1114 Deserialize from XML.
1116 :param stream:
1117 Read input from stream.
1119 :param filename:
1120 Read input from file of given name.
1121 :type filename:
1122 str
1124 :param string:
1125 Read input from string.
1126 :type string:
1127 str
1128 '''
1130 if ns_hints is None:
1131 ns_hints = [cls.T.instance.get_xmlns()]
1133 return load_xml(
1134 stream=stream,
1135 filename=filename,
1136 string=string,
1137 ns_hints=ns_hints,
1138 ns_ignore=ns_ignore)
1140 def __str__(self):
1141 return self.dump()
1144def to_dict(obj):
1145 '''
1146 Get dict of guts object attributes.
1148 :param obj: :py:class`Object` object
1149 '''
1151 return dict(obj.T.inamevals(obj))
1154class SObject(Object):
1155 '''
1156 Base class for simple str-serializable Guts objects.
1158 Derived classes must support (de)serialization as in ``X(str(x))``.
1159 '''
1161 class __T(TBase):
1162 def regularize_extra(self, val):
1163 if isinstance(val, str):
1164 return self._cls(val)
1166 return val
1168 def to_save(self, val):
1169 return str(val)
1171 def to_save_xml(self, val):
1172 return str(val)
1175class Any(Object):
1176 '''
1177 Placeholder for any object.
1178 '''
1180 class __T(TBase):
1181 def validate(self, val, regularize=False, depth=-1):
1182 if isinstance(val, Object):
1183 val.validate(regularize, depth)
1185 return val
1188class Int(Object):
1189 '''
1190 Placeholder for :py:class:`int`.
1191 '''
1192 dummy_for = int
1194 class __T(TBase):
1195 strict = True
1197 def to_save_xml(self, value):
1198 return repr(value)
1201class Float(Object):
1202 '''
1203 Placeholder for :py:class:`float`.
1204 '''
1205 dummy_for = float
1207 class __T(TBase):
1208 strict = True
1210 def to_save_xml(self, value):
1211 return repr(value)
1214class Complex(Object):
1215 '''
1216 Placeholder for :py:class:`complex`.
1217 '''
1218 dummy_for = complex
1220 class __T(TBase):
1221 strict = True
1223 def regularize_extra(self, val):
1225 if isinstance(val, list) or isinstance(val, tuple):
1226 assert len(val) == 2
1227 val = complex(*val)
1229 elif not isinstance(val, complex):
1230 val = complex(val)
1232 return val
1234 def to_save(self, value):
1235 return repr(complex(value))
1237 def to_save_xml(self, value):
1238 return repr(complex(value))
1241class Bool(Object):
1242 '''
1243 Placeholder for :py:class:`bool`.
1244 '''
1245 dummy_for = bool
1247 class __T(TBase):
1248 strict = True
1250 def regularize_extra(self, val):
1251 if isinstance(val, str):
1252 if val.lower().strip() in ('0', 'false'):
1253 return False
1255 return bool(val)
1257 def to_save_xml(self, value):
1258 return repr(bool(value)).lower()
1261class String(Object):
1262 '''
1263 Placeholder for :py:class:`str`.
1264 '''
1265 dummy_for = str
1267 class __T(TBase):
1268 def __init__(self, *args, yamlstyle=None, **kwargs):
1269 TBase.__init__(self, *args, **kwargs)
1270 self.style_cls = str_style_map[yamlstyle]
1272 def to_save(self, val):
1273 return self.style_cls(val)
1276class Bytes(Object):
1277 '''
1278 Placeholder for :py:class:`bytes`.
1279 '''
1280 dummy_for = bytes
1282 class __T(TBase):
1284 def regularize_extra(self, val):
1285 if isinstance(val, str):
1286 val = b64decode(val)
1288 return val
1290 def to_save(self, val):
1291 return literal(b64encode(val).decode('utf-8'))
1294class Unicode(Object):
1295 '''
1296 Placeholder for :py:class:`str`.
1297 '''
1298 dummy_for = str
1300 class __T(TBase):
1301 def __init__(self, *args, yamlstyle=None, **kwargs):
1302 TBase.__init__(self, *args, **kwargs)
1303 self.style_cls = unicode_style_map[yamlstyle]
1305 def to_save(self, val):
1306 return self.style_cls(val)
1309guts_plain_dummy_types = (String, Unicode, Int, Float, Complex, Bool)
1312class Dict(Object):
1313 '''
1314 Placeholder for :py:class:`dict`.
1315 '''
1316 dummy_for = dict
1318 class __T(TBase):
1319 multivalued = dict
1321 def __init__(self, key_t=Any.T(), content_t=Any.T(), *args, **kwargs):
1322 TBase.__init__(self, *args, **kwargs)
1323 assert isinstance(key_t, TBase)
1324 assert isinstance(content_t, TBase)
1325 self.key_t = key_t
1326 self.content_t = content_t
1327 self.content_t.parent = self
1329 def default(self):
1330 if self._default is not None:
1331 return dict(
1332 (make_default(k), make_default(v))
1333 for (k, v) in self._default.items())
1335 if self.optional:
1336 return None
1337 else:
1338 return {}
1340 def has_default(self):
1341 return True
1343 def validate(self, val, regularize, depth):
1344 return TBase.validate(self, val, regularize, depth+1)
1346 def validate_children(self, val, regularize, depth):
1347 for key, ele in list(val.items()):
1348 newkey = self.key_t.validate(key, regularize, depth-1)
1349 newele = self.content_t.validate(ele, regularize, depth-1)
1350 if regularize:
1351 if newkey is not key or newele is not ele:
1352 del val[key]
1353 val[newkey] = newele
1355 return val
1357 def to_save(self, val):
1358 return dict((self.key_t.to_save(k), self.content_t.to_save(v))
1359 for (k, v) in val.items())
1361 def to_save_xml(self, val):
1362 raise NotImplementedError
1364 def classname_for_help(self, strip_module=''):
1365 return '``dict`` of %s objects' % \
1366 self.content_t.classname_for_help(strip_module=strip_module)
1369class List(Object):
1370 '''
1371 Placeholder for :py:class:`list`.
1372 '''
1373 dummy_for = list
1375 class __T(TBase):
1376 multivalued = list
1378 def __init__(self, content_t=Any.T(), *args, yamlstyle=None, **kwargs):
1379 TBase.__init__(self, *args, **kwargs)
1380 assert isinstance(content_t, TBase) or isinstance(content_t, Defer)
1381 self.content_t = content_t
1382 self.content_t.parent = self
1383 self.style_cls = list_style_map[yamlstyle]
1385 def default(self):
1386 if self._default is not None:
1387 return [make_default(x) for x in self._default]
1388 if self.optional:
1389 return None
1390 else:
1391 return []
1393 def has_default(self):
1394 return True
1396 def validate(self, val, regularize, depth):
1397 return TBase.validate(self, val, regularize, depth+1)
1399 def validate_children(self, val, regularize, depth):
1400 for i, ele in enumerate(val):
1401 newele = self.content_t.validate(ele, regularize, depth-1)
1402 if regularize and newele is not ele:
1403 val[i] = newele
1405 return val
1407 def to_save(self, val):
1408 return self.style_cls(self.content_t.to_save(v) for v in val)
1410 def to_save_xml(self, val):
1411 return [self.content_t.to_save_xml(v) for v in val]
1413 def deferred(self):
1414 if isinstance(self.content_t, Defer):
1415 return [self.content_t]
1417 return []
1419 def process_deferred(self, defer, t_inst):
1420 if defer is self.content_t:
1421 self.content_t = t_inst
1423 def classname_for_help(self, strip_module=''):
1424 return '``list`` of %s objects' % \
1425 self.content_t.classname_for_help(strip_module=strip_module)
1428def make_typed_list_class(t):
1429 class TL(List):
1430 class __T(List.T):
1431 def __init__(self, *args, **kwargs):
1432 List.T.__init__(self, content_t=t.T(), *args, **kwargs)
1434 return TL
1437class Tuple(Object):
1438 '''
1439 Placeholder for :py:class:`tuple`.
1440 '''
1441 dummy_for = tuple
1443 class __T(TBase):
1444 multivalued = tuple
1446 def __init__(self, n=None, content_t=Any.T(), *args, **kwargs):
1447 TBase.__init__(self, *args, **kwargs)
1448 assert isinstance(content_t, TBase)
1449 self.content_t = content_t
1450 self.content_t.parent = self
1451 self.n = n
1453 def default(self):
1454 if self._default is not None:
1455 return tuple(
1456 make_default(x) for x in self._default)
1458 elif self.optional:
1459 return None
1460 else:
1461 if self.n is not None:
1462 return tuple(
1463 self.content_t.default() for x in range(self.n))
1464 else:
1465 return tuple()
1467 def has_default(self):
1468 return True
1470 def validate(self, val, regularize, depth):
1471 return TBase.validate(self, val, regularize, depth+1)
1473 def validate_extra(self, val):
1474 if self.n is not None and len(val) != self.n:
1475 raise ValidationError(
1476 '%s should have length %i' % (self.xname(), self.n))
1478 def validate_children(self, val, regularize, depth):
1479 if not regularize:
1480 for ele in val:
1481 self.content_t.validate(ele, regularize, depth-1)
1483 return val
1484 else:
1485 newval = []
1486 isnew = False
1487 for ele in val:
1488 newele = self.content_t.validate(ele, regularize, depth-1)
1489 newval.append(newele)
1490 if newele is not ele:
1491 isnew = True
1493 if isnew:
1494 return tuple(newval)
1495 else:
1496 return val
1498 def to_save(self, val):
1499 return tuple(self.content_t.to_save(v) for v in val)
1501 def to_save_xml(self, val):
1502 return [self.content_t.to_save_xml(v) for v in val]
1504 def classname_for_help(self, strip_module=''):
1505 if self.n is not None:
1506 return '``tuple`` of %i %s objects' % (
1507 self.n, self.content_t.classname_for_help(
1508 strip_module=strip_module))
1509 else:
1510 return '``tuple`` of %s objects' % (
1511 self.content_t.classname_for_help(
1512 strip_module=strip_module))
1515duration_unit_factors = dict(
1516 s=1.0,
1517 m=60.0,
1518 h=3600.0,
1519 d=24*3600.0,
1520 y=365*24*3600.0)
1523def parse_duration(s):
1524 unit = s[-1]
1525 if unit in duration_unit_factors:
1526 return float(s[:-1]) * duration_unit_factors[unit]
1527 else:
1528 return float(s)
1531def str_duration(d):
1532 for k in 'ydhms':
1533 if abs(d) >= duration_unit_factors[k]:
1534 return '%g' % (d / duration_unit_factors[k]) + k
1536 return '%g' % d
1539class Duration(Object):
1540 '''
1541 Placeholder for :py:class:`float` time duration [s] with human-readable
1542 (de)serialization.
1544 Examples:
1546 - ``'1s'`` -> 1 second
1547 - ``'1m'`` -> 1 minute
1548 - ``'1h'`` -> 1 hour
1549 - ``'1d'`` -> 1 day
1550 - ``'1y'`` -> about 1 year = 365*24*3600 seconds
1551 '''
1552 dummy_for = float
1554 class __T(TBase):
1555 def regularize_extra(self, val):
1556 if isinstance(val, str):
1557 return parse_duration(val)
1559 return val
1561 def to_save(self, val):
1562 return str_duration(val)
1564 def to_save_xml(self, val):
1565 return str_duration(val)
1568re_tz = re.compile(r'(Z|([+-][0-2][0-9])(:?([0-5][0-9]))?)$')
1571class Timestamp(Object):
1572 '''
1573 Placeholder for a UTC timestamp.
1574 '''
1575 dummy_for = (hpfloat, float)
1576 dummy_for_description = 'pyrocko.util.get_time_float'
1578 class __T(TBase):
1580 def regularize_extra(self, val):
1582 time_float = get_time_float()
1584 if isinstance(val, datetime.datetime):
1585 tt = val.utctimetuple()
1586 val = time_float(calendar.timegm(tt)) + val.microsecond * 1e-6
1588 elif isinstance(val, datetime.date):
1589 tt = val.timetuple()
1590 val = time_float(calendar.timegm(tt))
1592 elif isinstance(val, str):
1593 val = val.strip()
1594 tz_offset = 0
1596 m = re_tz.search(val)
1597 if m:
1598 sh = m.group(2)
1599 sm = m.group(4)
1600 tz_offset = (int(sh)*3600 if sh else 0) \
1601 + (int(sm)*60 if sm else 0)
1603 val = re_tz.sub('', val)
1605 if len(val) > 10 and val[10] == 'T':
1606 val = val.replace('T', ' ', 1)
1608 try:
1609 val = str_to_time(val) - tz_offset
1610 except TimeStrError:
1611 raise ValidationError(
1612 '%s: cannot parse time/date: %s' % (self.xname(), val))
1614 elif isinstance(val, (int, float)):
1615 val = time_float(val)
1617 else:
1618 raise ValidationError(
1619 '%s: cannot convert "%s" to type %s' % (
1620 self.xname(), val, time_float))
1622 return val
1624 def to_save(self, val):
1625 return time_to_str(val, format='%Y-%m-%d %H:%M:%S.9FRAC')\
1626 .rstrip('0').rstrip('.')
1628 def to_save_xml(self, val):
1629 return time_to_str(val, format='%Y-%m-%dT%H:%M:%S.9FRAC')\
1630 .rstrip('0').rstrip('.') + 'Z'
1632 @classmethod
1633 def D(self, s):
1634 return TimestampDefaultMaker(s)
1637class DateTimestamp(Object):
1638 '''
1639 Placeholder for a UTC timestamp which (de)serializes as a date string.
1640 '''
1641 dummy_for = (hpfloat, float)
1642 dummy_for_description = 'pyrocko.util.get_time_float'
1644 class __T(TBase):
1646 def regularize_extra(self, val):
1648 time_float = get_time_float()
1650 if isinstance(val, datetime.datetime):
1651 tt = val.utctimetuple()
1652 val = time_float(calendar.timegm(tt)) + val.microsecond * 1e-6
1654 elif isinstance(val, datetime.date):
1655 tt = val.timetuple()
1656 val = time_float(calendar.timegm(tt))
1658 elif isinstance(val, str):
1659 val = str_to_time(val, format='%Y-%m-%d')
1661 elif isinstance(val, int):
1662 val = time_float(val)
1664 return val
1666 def to_save(self, val):
1667 return time_to_str(val, format='%Y-%m-%d')
1669 def to_save_xml(self, val):
1670 return time_to_str(val, format='%Y-%m-%d')
1672 @classmethod
1673 def D(self, s):
1674 return TimestampDefaultMaker(s, format='%Y-%m-%d')
1677class StringPattern(String):
1679 '''
1680 Any :py:class:`str` matching pattern ``%(pattern)s``.
1681 '''
1683 dummy_for = str
1684 pattern = '.*'
1686 class __T(String.T):
1687 def __init__(self, pattern=None, *args, **kwargs):
1688 String.T.__init__(self, *args, **kwargs)
1690 if pattern is not None:
1691 self.pattern = pattern
1692 else:
1693 self.pattern = self._dummy_cls.pattern
1695 def validate_extra(self, val):
1696 pat = self.pattern
1697 if not re.search(pat, val):
1698 raise ValidationError('%s: "%s" does not match pattern %s' % (
1699 self.xname(), val, repr(pat)))
1701 @classmethod
1702 def class_help_string(cls):
1703 dcls = cls._dummy_cls
1704 doc = dcls.__doc_template__ or StringPattern.__doc_template__
1705 return doc % {'pattern': repr(dcls.pattern)}
1708class UnicodePattern(Unicode):
1710 '''
1711 Any :py:class:`str` matching pattern ``%(pattern)s``.
1712 '''
1714 dummy_for = str
1715 pattern = '.*'
1717 class __T(TBase):
1718 def __init__(self, pattern=None, *args, **kwargs):
1719 TBase.__init__(self, *args, **kwargs)
1721 if pattern is not None:
1722 self.pattern = pattern
1723 else:
1724 self.pattern = self._dummy_cls.pattern
1726 def validate_extra(self, val):
1727 pat = self.pattern
1728 if not re.search(pat, val, flags=re.UNICODE):
1729 raise ValidationError('%s: "%s" does not match pattern %s' % (
1730 self.xname(), val, repr(pat)))
1732 @classmethod
1733 def class_help_string(cls):
1734 dcls = cls._dummy_cls
1735 doc = dcls.__doc_template__ or UnicodePattern.__doc_template__
1736 return doc % {'pattern': repr(dcls.pattern)}
1739class StringChoice(String):
1741 '''
1742 Any :py:class:`str` out of ``%(choices)s``.
1744 :cvar choices:
1745 Allowed choices (:py:class:`list` of :py:class:`str`).
1746 :cvar ignore_case:
1747 Whether to behave case-insensitive (:py:class:`bool`, default:
1748 ``False``).
1749 '''
1751 dummy_for = str
1752 choices = []
1753 ignore_case = False
1755 class __T(String.T):
1756 def __init__(self, choices=None, ignore_case=None, *args, **kwargs):
1757 String.T.__init__(self, *args, **kwargs)
1759 if choices is not None:
1760 self.choices = choices
1761 else:
1762 self.choices = self._dummy_cls.choices
1764 if ignore_case is not None:
1765 self.ignore_case = ignore_case
1766 else:
1767 self.ignore_case = self._dummy_cls.ignore_case
1769 if self.ignore_case:
1770 self.choices = [x.upper() for x in self.choices]
1772 def validate_extra(self, val):
1773 if self.ignore_case:
1774 val = val.upper()
1776 if val not in self.choices:
1777 raise ValidationError(
1778 '%s: "%s" is not a valid choice out of %s' % (
1779 self.xname(), val, repr(self.choices)))
1781 @classmethod
1782 def class_help_string(cls):
1783 dcls = cls._dummy_cls
1784 doc = dcls.__doc_template__ or StringChoice.__doc_template__
1785 return doc % {'choices': repr(dcls.choices)}
1788class IntChoice(Int):
1790 '''
1791 Any :py:class:`int` out of ``%(choices)s``.
1792 '''
1794 dummy_for = int
1795 choices = []
1797 class __T(Int.T):
1798 def __init__(self, choices=None, *args, **kwargs):
1799 Int.T.__init__(self, *args, **kwargs)
1801 if choices is not None:
1802 self.choices = choices
1803 else:
1804 self.choices = self._dummy_cls.choices
1806 def validate_extra(self, val):
1807 if val not in self.choices:
1808 raise ValidationError(
1809 '%s: %i is not a valid choice out of %s' % (
1810 self.xname(), val, repr(self.choices)))
1812 @classmethod
1813 def class_help_string(cls):
1814 dcls = cls._dummy_cls
1815 doc = dcls.__doc_template__ or IntChoice.__doc_template__
1816 return doc % {'choices': repr(dcls.choices)}
1819# this will not always work...
1820class StringUnion(Object):
1821 '''
1822 Any :py:class:`str` matching any of a set of constraints.
1824 :cvar members:
1825 List of constraints, e.g. :py:class:`StringChoice`,
1826 :py:class:`StringPattern`, ... (:py:class:`list` of :py:class:`TBase`
1827 derived objects).
1829 '''
1831 members = []
1833 dummy_for = str
1835 class __T(TBase):
1836 def __init__(self, members=None, *args, **kwargs):
1837 TBase.__init__(self, *args, **kwargs)
1838 if members is not None:
1839 self.members = members
1840 else:
1841 self.members = self._dummy_cls.members
1843 def validate(self, val, regularize=False, depth=-1):
1844 assert self.members
1845 e2 = None
1846 for member in self.members:
1847 try:
1848 return member.validate(val, regularize, depth=depth)
1849 except ValidationError as e:
1850 e2 = e
1852 raise e2
1855class Choice(Object):
1856 '''
1857 Any out of a set of different types.
1859 :cvar choices:
1860 Allowed types (:py:class:`list` of :py:class:`TBase` derived objects).
1862 '''
1863 choices = []
1865 class __T(TBase):
1866 def __init__(self, choices=None, *args, **kwargs):
1867 TBase.__init__(self, *args, **kwargs)
1868 if choices is not None:
1869 self.choices = choices
1870 else:
1871 self.choices = self._dummy_cls.choices
1873 self.cls_to_xmltagname = dict(
1874 (t._cls, t.get_xmltagname()) for t in self.choices)
1876 def validate(self, val, regularize=False, depth=-1):
1877 if self.optional and val is None:
1878 return val
1880 t = None
1881 for tc in self.choices:
1882 is_derived = isinstance(val, tc._cls)
1883 is_exact = type(val) is tc._cls
1884 if not (not tc.strict and not is_derived or
1885 tc.strict and not is_exact):
1887 t = tc
1888 break
1890 if t is None:
1891 if regularize:
1892 ok = False
1893 for tc in self.choices:
1894 try:
1895 val = tc.regularize_extra(val)
1896 ok = True
1897 t = tc
1898 break
1899 except (ValidationError, ValueError):
1900 pass
1902 if not ok:
1903 raise ValidationError(
1904 '%s: could not convert "%s" to any type out of '
1905 '(%s)' % (self.xname(), val, ','.join(
1906 classnames(x._cls) for x in self.choices)))
1907 else:
1908 raise ValidationError(
1909 '%s: "%s" (type: %s) is not of any type out of '
1910 '(%s)' % (self.xname(), val, type(val), ','.join(
1911 classnames(x._cls) for x in self.choices)))
1913 validator = t
1915 if isinstance(t._cls, tuple):
1916 clss = t._cls
1917 else:
1918 clss = (t._cls,)
1920 for cls in clss:
1921 try:
1922 if type(val) is not cls and isinstance(val, cls):
1923 validator = val.T.instance
1925 except AttributeError:
1926 pass
1928 validator.validate_extra(val)
1930 if depth != 0:
1931 val = validator.validate_children(val, regularize, depth)
1933 return val
1935 def extend_xmlelements(self, elems, v):
1936 elems.append((
1937 self.cls_to_xmltagname[type(v)].split(' ', 1)[-1], v))
1940def _dump(
1941 object, stream,
1942 header=False,
1943 Dumper=GutsSafeDumper,
1944 _dump_function=yaml.dump):
1946 if not getattr(stream, 'encoding', None):
1947 enc = encode_utf8
1948 else:
1949 enc = no_encode
1951 if header:
1952 stream.write(enc(u'%YAML 1.1\n'))
1953 if isinstance(header, str):
1954 banner = u'\n'.join('# ' + x for x in header.splitlines()) + '\n'
1955 stream.write(enc(banner))
1957 _dump_function(
1958 object,
1959 stream=stream,
1960 encoding='utf-8',
1961 explicit_start=True,
1962 Dumper=Dumper)
1965def _dump_all(object, stream, header=True, Dumper=GutsSafeDumper):
1966 _dump(object, stream=stream, header=header, _dump_function=yaml.dump_all)
1969def _load(stream,
1970 Loader=GutsSafeLoader, allow_include=None, filename=None,
1971 included_files=None):
1973 class _Loader(Loader):
1974 _filename = filename
1975 _allow_include = allow_include
1976 _included_files = included_files or []
1978 return yaml.load(stream=stream, Loader=_Loader)
1981def _load_all(stream,
1982 Loader=GutsSafeLoader, allow_include=None, filename=None):
1984 class _Loader(Loader):
1985 _filename = filename
1986 _allow_include = allow_include
1988 return list(yaml.load_all(stream=stream, Loader=_Loader))
1991def _iload_all(stream,
1992 Loader=GutsSafeLoader, allow_include=None, filename=None):
1994 class _Loader(Loader):
1995 _filename = filename
1996 _allow_include = allow_include
1998 return yaml.load_all(stream=stream, Loader=_Loader)
2001def multi_representer(dumper, data):
2002 node = dumper.represent_mapping(
2003 '!'+data.T.tagname, data.T.inamevals_to_save(data), flow_style=False)
2005 return node
2008# hack for compatibility with early GF Store versions
2009re_compatibility = re.compile(
2010 r'^pyrocko\.(trace|gf\.(meta|seismosizer)|fomosto\.'
2011 r'(dummy|poel|qseis|qssp))\.'
2012)
2015def multi_constructor(loader, tag_suffix, node):
2016 tagname = str(tag_suffix)
2018 tagname = re_compatibility.sub('pf.', tagname)
2020 cls = g_tagname_to_class[tagname]
2021 kwargs = dict(iter(loader.construct_pairs(node, deep=True)))
2022 o = cls(**kwargs)
2023 o.validate(regularize=True, depth=1)
2024 return o
2027def include_constructor(loader, node):
2028 allow_include = loader._allow_include \
2029 if loader._allow_include is not None \
2030 else ALLOW_INCLUDE
2032 if not allow_include:
2033 raise EnvironmentError(
2034 'Not allowed to include YAML. Load with allow_include=True')
2036 if isinstance(node, yaml.nodes.ScalarNode):
2037 inc_file = loader.construct_scalar(node)
2038 else:
2039 raise TypeError('Unsupported YAML node %s' % repr(node))
2041 if loader._filename is not None and not op.isabs(inc_file):
2042 inc_file = op.join(op.dirname(loader._filename), inc_file)
2044 if not op.isfile(inc_file):
2045 raise FileNotFoundError(inc_file)
2047 included_files = list(loader._included_files)
2048 if loader._filename is not None:
2049 included_files.append(op.abspath(loader._filename))
2051 for included_file in loader._included_files:
2052 if op.samefile(inc_file, included_file):
2053 raise ImportError(
2054 'Circular import of file "%s". Include path: %s' % (
2055 op.abspath(inc_file),
2056 ' -> '.join('"%s"' % s for s in included_files)))
2058 with open(inc_file, 'rb') as f:
2059 return _load(
2060 f,
2061 Loader=loader.__class__, filename=inc_file,
2062 allow_include=True,
2063 included_files=included_files)
2066def dict_noflow_representer(dumper, data):
2067 return dumper.represent_mapping(
2068 'tag:yaml.org,2002:map', data, flow_style=False)
2071yaml.add_multi_representer(Object, multi_representer, Dumper=GutsSafeDumper)
2072yaml.add_constructor('!include', include_constructor, Loader=GutsSafeLoader)
2073yaml.add_multi_constructor('!', multi_constructor, Loader=GutsSafeLoader)
2074yaml.add_representer(dict, dict_noflow_representer, Dumper=GutsSafeDumper)
2077def str_representer(dumper, data):
2078 return dumper.represent_scalar(
2079 'tag:yaml.org,2002:str', str(data))
2082yaml.add_representer(str, str_representer, Dumper=GutsSafeDumper)
2085class Constructor(object):
2086 def __init__(self, add_namespace_maps=False, strict=False, ns_hints=None,
2087 ns_ignore=False):
2089 self.stack = []
2090 self.queue = []
2091 self.namespaces = defaultdict(list)
2092 self.add_namespace_maps = add_namespace_maps
2093 self.strict = strict
2094 self.ns_hints = ns_hints
2095 self.ns_ignore = ns_ignore
2097 def start_element(self, ns_name, attrs):
2098 if self.ns_ignore:
2099 ns_name = ns_name.split(' ')[-1]
2101 if -1 == ns_name.find(' '):
2102 if self.ns_hints is None and ns_name in g_guessable_xmlns:
2103 self.ns_hints = g_guessable_xmlns[ns_name]
2105 if self.ns_hints:
2106 ns_names = [
2107 ns_hint + ' ' + ns_name for ns_hint in self.ns_hints]
2109 elif self.ns_hints is None:
2110 ns_names = [' ' + ns_name]
2112 else:
2113 ns_names = [ns_name]
2115 for ns_name in ns_names:
2116 if self.stack and self.stack[-1][1] is not None:
2117 cls = self.stack[-1][1].T.xmltagname_to_class.get(
2118 ns_name, None)
2120 if isinstance(cls, tuple):
2121 cls = None
2122 else:
2123 if cls is not None and (
2124 not issubclass(cls, Object)
2125 or issubclass(cls, SObject)):
2126 cls = None
2127 else:
2128 cls = g_xmltagname_to_class.get(ns_name, None)
2130 if cls:
2131 break
2133 self.stack.append((ns_name, cls, attrs, [], []))
2135 def end_element(self, _):
2136 ns_name, cls, attrs, content2, content1 = self.stack.pop()
2138 ns = ns_name.split(' ', 1)[0]
2140 if cls is not None:
2141 content2.extend(
2142 (ns + ' ' + k if -1 == k.find(' ') else k, v)
2143 for (k, v) in attrs.items())
2144 content2.append((None, ''.join(content1)))
2145 o = cls(**cls.T.translate_from_xml(content2, self.strict))
2146 o.validate(regularize=True, depth=1)
2147 if self.add_namespace_maps:
2148 o.namespace_map = self.get_current_namespace_map()
2150 if self.stack and not all(x[1] is None for x in self.stack):
2151 self.stack[-1][-2].append((ns_name, o))
2152 else:
2153 self.queue.append(o)
2154 else:
2155 content = [''.join(content1)]
2156 if self.stack:
2157 for c in content:
2158 self.stack[-1][-2].append((ns_name, c))
2160 def characters(self, char_content):
2161 if self.stack:
2162 self.stack[-1][-1].append(char_content)
2164 def start_namespace(self, ns, uri):
2165 self.namespaces[ns].append(uri)
2167 def end_namespace(self, ns):
2168 self.namespaces[ns].pop()
2170 def get_current_namespace_map(self):
2171 return dict((k, v[-1]) for (k, v) in self.namespaces.items() if v)
2173 def get_queued_elements(self):
2174 queue = self.queue
2175 self.queue = []
2176 return queue
2179def _iload_all_xml(
2180 stream,
2181 bufsize=100000,
2182 add_namespace_maps=False,
2183 strict=False,
2184 ns_hints=None,
2185 ns_ignore=False):
2187 from xml.parsers.expat import ParserCreate
2188 from pyrocko import progress
2190 parser = ParserCreate('UTF-8', namespace_separator=' ')
2192 handler = Constructor(
2193 add_namespace_maps=add_namespace_maps,
2194 strict=strict,
2195 ns_hints=ns_hints,
2196 ns_ignore=ns_ignore)
2198 parser.StartElementHandler = handler.start_element
2199 parser.EndElementHandler = handler.end_element
2200 parser.CharacterDataHandler = handler.characters
2201 parser.StartNamespaceDeclHandler = handler.start_namespace
2202 parser.EndNamespaceDeclHandler = handler.end_namespace
2204 try:
2205 nbytes = os.fstat(stream.fileno()).st_size - stream.tell()
2206 except Exception:
2207 nbytes = None
2209 ibytes = 0
2210 task = progress.task('Parsing XML', nbytes, logger=logger)
2211 try:
2212 while True:
2213 data = stream.read(bufsize)
2214 ibytes += len(data)
2215 parser.Parse(data, bool(not data))
2216 for element in handler.get_queued_elements():
2217 yield element
2219 task.update(ibytes)
2221 if not data:
2222 break
2224 except Exception:
2225 task.fail()
2226 raise
2228 finally:
2229 task.done()
2232def _load_all_xml(*args, **kwargs):
2233 return list(_iload_all_xml(*args, **kwargs))
2236def _load_xml(*args, **kwargs):
2237 g = _iload_all_xml(*args, **kwargs)
2238 return next(g)
2241def _dump_all_xml(objects, stream, root_element_name='root', header=True):
2243 if not getattr(stream, 'encoding', None):
2244 enc = encode_utf8
2245 else:
2246 enc = no_encode
2248 _dump_xml_header(stream, header)
2250 beg = u'<%s>\n' % root_element_name
2251 end = u'</%s>\n' % root_element_name
2253 stream.write(enc(beg))
2255 for ob in objects:
2256 _dump_xml(ob, stream=stream)
2258 stream.write(enc(end))
2261def _dump_xml_header(stream, banner=None):
2263 if not getattr(stream, 'encoding', None):
2264 enc = encode_utf8
2265 else:
2266 enc = no_encode
2268 stream.write(enc(u'<?xml version="1.0" encoding="UTF-8" ?>\n'))
2269 if isinstance(banner, str):
2270 stream.write(enc(u'<!-- %s -->\n' % banner))
2273def _dump_xml(
2274 obj, stream, depth=0, ns_name=None, header=False, ns_map=[],
2275 ns_ignore=False):
2277 from xml.sax.saxutils import escape, quoteattr
2279 if not getattr(stream, 'encoding', None):
2280 enc = encode_utf8
2281 else:
2282 enc = no_encode
2284 if depth == 0 and header:
2285 _dump_xml_header(stream, header)
2287 indent = ' '*depth*2
2288 if ns_name is None:
2289 ns_name = obj.T.instance.get_xmltagname()
2291 if -1 != ns_name.find(' '):
2292 ns, name = ns_name.split(' ')
2293 else:
2294 ns, name = '', ns_name
2296 if isinstance(obj, Object):
2297 obj.validate(depth=1)
2298 attrs = []
2299 elems = []
2301 added_ns = False
2302 if not ns_ignore and ns and (not ns_map or ns_map[-1] != ns):
2303 attrs.append(('xmlns', ns))
2304 ns_map.append(ns)
2305 added_ns = True
2307 for prop, v in obj.T.ipropvals_to_save(obj, xmlmode=True):
2308 if prop.xmlstyle == 'attribute':
2309 assert not prop.multivalued
2310 assert not isinstance(v, Object)
2311 attrs.append((prop.effective_xmltagname, v))
2313 elif prop.xmlstyle == 'content':
2314 assert not prop.multivalued
2315 assert not isinstance(v, Object)
2316 elems.append((None, v))
2318 else:
2319 prop.extend_xmlelements(elems, v)
2321 attr_str = ''
2322 if attrs:
2323 attr_str = ' ' + ' '.join(
2324 '%s=%s' % (k.split(' ')[-1], quoteattr(str(v)))
2325 for (k, v) in attrs)
2327 if not elems:
2328 stream.write(enc(u'%s<%s%s />\n' % (indent, name, attr_str)))
2329 else:
2330 oneline = len(elems) == 1 and elems[0][0] is None
2331 stream.write(enc(u'%s<%s%s>%s' % (
2332 indent,
2333 name,
2334 attr_str,
2335 '' if oneline else '\n')))
2337 for (k, v) in elems:
2338 if k is None:
2339 stream.write(enc(escape(str(v), {'\0': '�'})))
2340 else:
2341 _dump_xml(v, stream, depth+1, k, False, ns_map, ns_ignore)
2343 stream.write(enc(u'%s</%s>\n' % (
2344 '' if oneline else indent, name)))
2346 if added_ns:
2347 ns_map.pop()
2349 else:
2350 stream.write(enc(u'%s<%s>%s</%s>\n' % (
2351 indent,
2352 name,
2353 escape(str(obj), {'\0': '�'}),
2354 name)))
2357def walk(x, typ=None, path=()):
2358 if typ is None or isinstance(x, typ):
2359 yield path, x
2361 if isinstance(x, Object):
2362 for (prop, val) in x.T.ipropvals(x):
2363 if prop.multivalued:
2364 if val is not None:
2365 for iele, ele in enumerate(val):
2366 for y in walk(ele, typ,
2367 path=path + ((prop.name, iele),)):
2368 yield y
2369 else:
2370 for y in walk(val, typ, path=path+(prop.name,)):
2371 yield y
2374def clone(x, pool=None):
2375 '''
2376 Clone guts object tree.
2378 Traverses guts object tree and recursively clones all guts attributes,
2379 falling back to :py:func:`copy.deepcopy` for non-guts objects. Objects
2380 deriving from :py:class:`Object` are instantiated using their respective
2381 init function. Multiply referenced objects in the source tree are multiply
2382 referenced also in the destination tree.
2384 This function can be used to clone guts objects ignoring any contained
2385 run-time state, i.e. any of their attributes not defined as a guts
2386 property.
2387 '''
2389 if pool is None:
2390 pool = {}
2392 if id(x) in pool:
2393 x_copy = pool[id(x)][1]
2395 else:
2396 if isinstance(x, SObject):
2397 x_copy = x.__class__(str(x))
2398 elif isinstance(x, Object):
2399 d = {}
2400 for (prop, y) in x.T.ipropvals(x):
2401 if y is not None:
2402 if not prop.multivalued:
2403 y_copy = clone(y, pool)
2404 elif prop.multivalued is dict:
2405 y_copy = dict(
2406 (clone(zk, pool), clone(zv, pool))
2407 for (zk, zv) in y.items())
2408 else:
2409 y_copy = type(y)(clone(z, pool) for z in y)
2410 else:
2411 y_copy = y
2413 d[prop.name] = y_copy
2415 x_copy = x.__class__(**d)
2417 else:
2418 x_copy = copy.deepcopy(x)
2420 pool[id(x)] = (x, x_copy)
2421 return x_copy
2424class YPathError(Exception):
2425 '''
2426 This exception is raised for invalid ypath specifications.
2427 '''
2428 pass
2431def _parse_yname(yname):
2432 ident = r'[a-zA-Z][a-zA-Z0-9_]*'
2433 rint = r'-?[0-9]+'
2434 m = re.match(
2435 r'^(%s)(\[((%s)?(:)(%s)?|(%s))\])?$'
2436 % (ident, rint, rint, rint), yname)
2438 if not m:
2439 raise YPathError('Syntax error in component: "%s"' % yname)
2441 d = dict(
2442 name=m.group(1))
2444 if m.group(2):
2445 if m.group(5):
2446 istart = iend = None
2447 if m.group(4):
2448 istart = int(m.group(4))
2449 if m.group(6):
2450 iend = int(m.group(6))
2452 d['slice'] = (istart, iend)
2453 else:
2454 d['index'] = int(m.group(7))
2456 return d
2459def _decend(obj, ynames):
2460 if ynames:
2461 for sobj in iter_elements(obj, ynames):
2462 yield sobj
2463 else:
2464 yield obj
2467def iter_elements(obj, ypath):
2468 '''
2469 Generator yielding elements matching a given ypath specification.
2471 :param obj: guts :py:class:`Object` instance
2472 :param ypath: Dot-separated object path (e.g. 'root.child.child').
2473 To access list objects use slice notatation (e.g.
2474 'root.child[:].child[1:3].child[1]').
2476 Raises :py:exc:`YPathError` on failure.
2477 '''
2479 try:
2480 if isinstance(ypath, str):
2481 ynames = ypath.split('.')
2482 else:
2483 ynames = ypath
2485 yname = ynames[0]
2486 ynames = ynames[1:]
2487 d = _parse_yname(yname)
2488 if d['name'] not in obj.T.propnames:
2489 raise AttributeError(d['name'])
2491 obj = getattr(obj, d['name'])
2493 if 'index' in d:
2494 sobj = obj[d['index']]
2495 for ssobj in _decend(sobj, ynames):
2496 yield ssobj
2498 elif 'slice' in d:
2499 for i in range(*slice(*d['slice']).indices(len(obj))):
2500 sobj = obj[i]
2501 for ssobj in _decend(sobj, ynames):
2502 yield ssobj
2503 else:
2504 for sobj in _decend(obj, ynames):
2505 yield sobj
2507 except (AttributeError, IndexError) as e:
2508 raise YPathError('Invalid ypath: "%s" (%s)' % (ypath, str(e)))
2511def get_elements(obj, ypath):
2512 '''
2513 Get all elements matching a given ypath specification.
2515 :param obj: guts :py:class:`Object` instance
2516 :param ypath: Dot-separated object path (e.g. 'root.child.child').
2517 To access list objects use slice notatation (e.g.
2518 'root.child[:].child[1:3].child[1]').
2520 Raises :py:exc:`YPathError` on failure.
2521 '''
2522 return list(iter_elements(obj, ypath))
2525def set_elements(obj, ypath, value, validate=False, regularize=False):
2526 '''
2527 Set elements matching a given ypath specification.
2529 :param obj: guts :py:class:`Object` instance
2530 :param ypath: Dot-separated object path (e.g. 'root.child.child').
2531 To access list objects use slice notatation (e.g.
2532 'root.child[:].child[1:3].child[1]').
2533 :param value: All matching elements will be set to `value`.
2534 :param validate: Whether to validate affected subtrees.
2535 :param regularize: Whether to regularize affected subtrees.
2537 Raises :py:exc:`YPathError` on failure.
2538 '''
2540 ynames = ypath.split('.')
2541 try:
2542 d = _parse_yname(ynames[-1])
2543 if ynames[:-1]:
2544 it = iter_elements(obj, ynames[:-1])
2545 else:
2546 it = [obj]
2548 for sobj in it:
2549 if d['name'] not in sobj.T.propnames:
2550 raise AttributeError(d['name'])
2552 if 'index' in d:
2553 ssobj = getattr(sobj, d['name'])
2554 ssobj[d['index']] = value
2555 elif 'slice' in d:
2556 ssobj = getattr(sobj, d['name'])
2557 for i in range(*slice(*d['slice']).indices(len(ssobj))):
2558 ssobj[i] = value
2559 else:
2560 setattr(sobj, d['name'], value)
2561 if regularize:
2562 sobj.regularize()
2563 if validate:
2564 sobj.validate()
2566 except (AttributeError, IndexError, YPathError) as e:
2567 raise YPathError('Invalid ypath: "%s" (%s)' % (ypath, str(e)))
2570def zip_walk(x, typ=None, path=(), stack=()):
2571 if typ is None or isinstance(x, typ):
2572 yield path, stack + (x,)
2574 if isinstance(x, Object):
2575 for (prop, val) in x.T.ipropvals(x):
2576 if prop.multivalued:
2577 if val is not None:
2578 for iele, ele in enumerate(val):
2579 for y in zip_walk(
2580 ele, typ,
2581 path=path + ((prop.name, iele),),
2582 stack=stack + (x,)):
2584 yield y
2585 else:
2586 for y in zip_walk(val, typ,
2587 path=path+(prop.name,),
2588 stack=stack + (x,)):
2589 yield y
2592def path_element(x):
2593 if isinstance(x, tuple):
2594 if len(x) == 2:
2595 return '%s[%i]' % x
2596 elif len(x) == 3:
2597 return '%s[%i:%i]' % x
2599 else:
2600 return x
2603def path_to_str(path):
2604 return '.'.join(path_element(x) for x in path)
2607@expand_stream_args('w')
2608def dump(obj, stream, **kwargs):
2609 '''
2610 Serialize to YAML.
2612 If neither ``stream`` nor ``filename`` is set, a string containing the
2613 serialized data is returned.
2615 :param obj:
2616 Object to be serialized.
2617 :type obj:
2618 :py:class:`Object`
2620 :param stream:
2621 Output to stream.
2623 :param filename:
2624 Output to file of given name.
2625 :type filename:
2626 str
2628 :param header:
2629 File header to prepend to the output.
2630 :type header:
2631 str
2632 '''
2633 return _dump(obj, stream, **kwargs)
2636@expand_stream_args('r')
2637def load(stream, **kwargs):
2638 return _load(stream, **kwargs)
2641def load_string(s, **kwargs):
2642 return load(string=s, **kwargs)
2645@expand_stream_args('w')
2646def dump_all(obj, stream, **kwargs):
2647 return _dump_all(obj, stream, **kwargs)
2650@expand_stream_args('r')
2651def load_all(stream, **kwargs):
2652 return _load_all(stream, **kwargs)
2655@expand_stream_args('r')
2656def iload_all(stream, **kwargs):
2657 return _iload_all(stream, **kwargs)
2660@expand_stream_args('w')
2661def dump_xml(obj, stream, **kwargs):
2662 '''
2663 Serialize to XML.
2665 If neither ``stream`` nor ``filename`` is set, a string containing the
2666 serialized data is returned.
2668 :param obj:
2669 Object to be serialized.
2670 :type obj:
2671 :py:class:`Object`
2673 :param stream:
2674 Output to stream.
2676 :param filename:
2677 Output to file of given name.
2678 :type filename:
2679 str
2681 :param header:
2682 File header to prepend to the output.
2683 :type header:
2684 str
2686 :param ns_ignore:
2687 Whether to ignore the XML namespace.
2688 :type ns_ignore:
2689 bool
2690 '''
2691 return _dump_xml(obj, stream, **kwargs)
2694@expand_stream_args('r')
2695def load_xml(stream, **kwargs):
2696 kwargs.pop('filename', None)
2697 return _load_xml(stream, **kwargs)
2700def load_xml_string(s, **kwargs):
2701 return load_xml(string=s, **kwargs)
2704@expand_stream_args('w')
2705def dump_all_xml(obj, stream, **kwargs):
2706 return _dump_all_xml(obj, stream, **kwargs)
2709@expand_stream_args('r')
2710def load_all_xml(stream, **kwargs):
2711 kwargs.pop('filename', None)
2712 return _load_all_xml(stream, **kwargs)
2715@expand_stream_args('r')
2716def iload_all_xml(stream, **kwargs):
2717 kwargs.pop('filename', None)
2718 return _iload_all_xml(stream, **kwargs)
2721def _dump_all_spickle(objects, stream):
2722 import pickle
2723 header = b'SPICKLE'.ljust(512)
2724 stream.write(header, )
2725 for obj in objects:
2726 pickle.dump(obj, stream)
2729def _iload_all_spickle(stream):
2730 for obj, _ in _iload_all_spickle_internal(stream):
2731 yield obj
2734def _load_one_spickle_internal(stream):
2735 import pickle
2736 fpos = stream.tell()
2737 return pickle.load(stream), fpos
2740def _iload_all_spickle_internal(stream, offset=None):
2741 if offset is not None:
2742 stream.seek(offset, 0)
2743 else:
2744 header = stream.read(512)
2745 if not header.startswith(b'SPICKLE'):
2746 raise ValueError('Not a SPICKLE file.')
2748 while True:
2749 try:
2750 yield _load_one_spickle_internal(stream)
2751 except EOFError:
2752 break
2755def _load_all_spickle(stream):
2756 return list(_iload_all_spickle(stream))
2759@expand_stream_args('w')
2760def dump_all_spickle(objects, stream, **kwargs):
2761 return _dump_all_spickle(objects, stream)
2764@expand_stream_args('r')
2765def iload_all_spickle(stream, **kwargs):
2766 _iload_all_spickle(stream)
2769@expand_stream_args('r')
2770def load_all_spickle(stream, **kwargs):
2771 kwargs.pop('filename', None)
2772 return _load_all_spickle(stream, **kwargs)
2775__all__ = guts_types + [
2776 'guts_types', 'TBase', 'ValidationError',
2777 'ArgumentError', 'Defer',
2778 'DefaultMaker', 'ObjectDefaultMaker',
2779 'clone',
2780 'dump', 'load',
2781 'dump_all', 'load_all', 'iload_all',
2782 'dump_xml', 'load_xml',
2783 'dump_all_xml', 'load_all_xml', 'iload_all_xml',
2784 'load_string',
2785 'load_xml_string',
2786 'make_typed_list_class', 'walk', 'zip_walk', 'path_to_str'
2787]