1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 from __future__ import absolute_import
21
22 import uuid
23
24 from cproton import PN_TIMESTAMP, PN_FLOAT, PN_DESCRIBED, PN_DECIMAL64, PN_UBYTE, PN_UUID, PN_NULL, PN_BINARY, \
25 PN_LIST, PN_OVERFLOW, PN_MAP, PN_LONG, PN_SHORT, PN_CHAR, PN_UINT, PN_ULONG, PN_STRING, PN_USHORT, PN_DOUBLE, \
26 PN_BYTE, PN_DECIMAL32, PN_DECIMAL128, PN_ARRAY, PN_SYMBOL, PN_BOOL, PN_INT, \
27 pn_data_get_binary, pn_data_get_decimal64, pn_data_put_symbol, pn_data_put_float, \
28 pn_data_is_array_described, pn_data_exit, pn_data_put_uint, pn_data_put_decimal128, \
29 pn_data_lookup, pn_data_put_char, pn_data_encoded_size, pn_data_get_bool, \
30 pn_data_get_short, pn_data_prev, pn_data_type, pn_data_widen, pn_data_put_decimal64, \
31 pn_data_put_string, pn_data_get_array, pn_data_put_ulong, pn_data_get_byte, pn_data_get_symbol, pn_data_encode, \
32 pn_data_rewind, pn_data_put_bool, pn_data_is_null, pn_data_error, \
33 pn_data_put_double, pn_data_copy, pn_data_put_int, pn_data_get_ubyte, pn_data_free, pn_data_clear, \
34 pn_data_get_double, pn_data_put_byte, pn_data_put_uuid, pn_data_put_ushort, pn_data_is_described, \
35 pn_data_get_float, pn_data_get_uint, pn_data_put_described, pn_data_get_decimal128, pn_data, \
36 pn_data_get_array_type, pn_data_put_map, pn_data_put_list, pn_data_get_string, pn_data_get_char, \
37 pn_data_put_decimal32, pn_data_enter, pn_data_put_short, pn_data_put_timestamp, \
38 pn_data_get_long, pn_data_get_map, pn_data_narrow, pn_data_put_array, pn_data_get_ushort, \
39 pn_data_get_int, pn_data_get_list, pn_data_get_ulong, pn_data_put_ubyte, \
40 pn_data_format, pn_data_dump, pn_data_get_uuid, pn_data_get_decimal32, \
41 pn_data_put_binary, pn_data_get_timestamp, pn_data_decode, pn_data_next, pn_data_put_null, pn_data_put_long, \
42 pn_error_text
43
44 from ._common import Constant
45 from ._exceptions import EXCEPTIONS, DataException
46
47 from . import _compat
48
49
50
51
52
53
54
55
56 try:
57 long()
58 except NameError:
59 long = int
60 try:
61 unicode()
62 except NameError:
63 unicode = str
67
70
72 return "UnmappedType(%s)" % self.msg
73
76
78 return "ulong(%s)" % long.__repr__(self)
79
82
84 return "timestamp(%s)" % long.__repr__(self)
85
88
90 return "symbol(%s)" % unicode.__repr__(self)
91
92
93 -class char(unicode):
94
96 return "char(%s)" % unicode.__repr__(self)
97
103
109
115
121
127
128
129 -class uint(long):
130
132 return "uint(%s)" % long.__repr__(self)
133
136
138 return "float32(%s)" % float.__repr__(self)
139
145
148
150 return "decimal64(%s)" % long.__repr__(self)
151
154
156 return "decimal128(%s)" % bytes.__repr__(self)
157
160
162 self.descriptor = descriptor
163 self.value = value
164
166 return "Described(%r, %r)" % (self.descriptor, self.value)
167
169 if isinstance(o, Described):
170 return self.descriptor == o.descriptor and self.value == o.value
171 else:
172 return False
173
174
175 UNDESCRIBED = Constant("UNDESCRIBED")
176
177
178 -class Array(object):
179
180 - def __init__(self, descriptor, type, *elements):
181 self.descriptor = descriptor
182 self.type = type
183 self.elements = elements
184
186 return iter(self.elements)
187
189 if self.elements:
190 els = ", %s" % (", ".join(map(repr, self.elements)))
191 else:
192 els = ""
193 return "Array(%r, %r%s)" % (self.descriptor, self.type, els)
194
196 if isinstance(o, Array):
197 return self.descriptor == o.descriptor and \
198 self.type == o.type and self.elements == o.elements
199 else:
200 return False
201
204 """
205 The L{Data} class provides an interface for decoding, extracting,
206 creating, and encoding arbitrary AMQP data. A L{Data} object
207 contains a tree of AMQP values. Leaf nodes in this tree correspond
208 to scalars in the AMQP type system such as L{ints<INT>} or
209 L{strings<STRING>}. Non-leaf nodes in this tree correspond to
210 compound values in the AMQP type system such as L{lists<LIST>},
211 L{maps<MAP>}, L{arrays<ARRAY>}, or L{described values<DESCRIBED>}.
212 The root node of the tree is the L{Data} object itself and can have
213 an arbitrary number of children.
214
215 A L{Data} object maintains the notion of the current sibling node
216 and a current parent node. Siblings are ordered within their parent.
217 Values are accessed and/or added by using the L{next}, L{prev},
218 L{enter}, and L{exit} methods to navigate to the desired location in
219 the tree and using the supplied variety of put_*/get_* methods to
220 access or add a value of the desired type.
221
222 The put_* methods will always add a value I{after} the current node
223 in the tree. If the current node has a next sibling the put_* method
224 will overwrite the value on this node. If there is no current node
225 or the current node has no next sibling then one will be added. The
226 put_* methods always set the added/modified node to the current
227 node. The get_* methods read the value of the current node and do
228 not change which node is current.
229
230 The following types of scalar values are supported:
231
232 - L{NULL}
233 - L{BOOL}
234 - L{UBYTE}
235 - L{USHORT}
236 - L{SHORT}
237 - L{UINT}
238 - L{INT}
239 - L{ULONG}
240 - L{LONG}
241 - L{FLOAT}
242 - L{DOUBLE}
243 - L{BINARY}
244 - L{STRING}
245 - L{SYMBOL}
246
247 The following types of compound values are supported:
248
249 - L{DESCRIBED}
250 - L{ARRAY}
251 - L{LIST}
252 - L{MAP}
253 """
254
255 NULL = PN_NULL; "A null value."
256 BOOL = PN_BOOL; "A boolean value."
257 UBYTE = PN_UBYTE; "An unsigned byte value."
258 BYTE = PN_BYTE; "A signed byte value."
259 USHORT = PN_USHORT; "An unsigned short value."
260 SHORT = PN_SHORT; "A short value."
261 UINT = PN_UINT; "An unsigned int value."
262 INT = PN_INT; "A signed int value."
263 CHAR = PN_CHAR; "A character value."
264 ULONG = PN_ULONG; "An unsigned long value."
265 LONG = PN_LONG; "A signed long value."
266 TIMESTAMP = PN_TIMESTAMP; "A timestamp value."
267 FLOAT = PN_FLOAT; "A float value."
268 DOUBLE = PN_DOUBLE; "A double value."
269 DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value."
270 DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value."
271 DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value."
272 UUID = PN_UUID; "A UUID value."
273 BINARY = PN_BINARY; "A binary string."
274 STRING = PN_STRING; "A unicode string."
275 SYMBOL = PN_SYMBOL; "A symbolic string."
276 DESCRIBED = PN_DESCRIBED; "A described value."
277 ARRAY = PN_ARRAY; "An array value."
278 LIST = PN_LIST; "A list value."
279 MAP = PN_MAP; "A map value."
280
281 type_names = {
282 NULL: "null",
283 BOOL: "bool",
284 BYTE: "byte",
285 UBYTE: "ubyte",
286 SHORT: "short",
287 USHORT: "ushort",
288 INT: "int",
289 UINT: "uint",
290 CHAR: "char",
291 LONG: "long",
292 ULONG: "ulong",
293 TIMESTAMP: "timestamp",
294 FLOAT: "float",
295 DOUBLE: "double",
296 DECIMAL32: "decimal32",
297 DECIMAL64: "decimal64",
298 DECIMAL128: "decimal128",
299 UUID: "uuid",
300 BINARY: "binary",
301 STRING: "string",
302 SYMBOL: "symbol",
303 DESCRIBED: "described",
304 ARRAY: "array",
305 LIST: "list",
306 MAP: "map"
307 }
308
309 @classmethod
312
320
322 if self._free and hasattr(self, "_data"):
323 pn_data_free(self._data)
324 del self._data
325
327 if err < 0:
328 exc = EXCEPTIONS.get(err, DataException)
329 raise exc("[%s]: %s" % (err, pn_error_text(pn_data_error(self._data))))
330 else:
331 return err
332
334 """
335 Clears the data object.
336 """
337 pn_data_clear(self._data)
338
340 """
341 Clears current node and sets the parent to the root node. Clearing the
342 current node sets it _before_ the first node, calling next() will advance to
343 the first node.
344 """
345 assert self._data is not None
346 pn_data_rewind(self._data)
347
349 """
350 Advances the current node to its next sibling and returns its
351 type. If there is no next sibling the current node remains
352 unchanged and None is returned.
353 """
354 found = pn_data_next(self._data)
355 if found:
356 return self.type()
357 else:
358 return None
359
361 """
362 Advances the current node to its previous sibling and returns its
363 type. If there is no previous sibling the current node remains
364 unchanged and None is returned.
365 """
366 found = pn_data_prev(self._data)
367 if found:
368 return self.type()
369 else:
370 return None
371
373 """
374 Sets the parent node to the current node and clears the current node.
375 Clearing the current node sets it _before_ the first child,
376 call next() advances to the first child.
377 """
378 return pn_data_enter(self._data)
379
381 """
382 Sets the current node to the parent node and the parent node to
383 its own parent.
384 """
385 return pn_data_exit(self._data)
386
389
391 pn_data_narrow(self._data)
392
394 pn_data_widen(self._data)
395
397 """
398 Returns the type of the current node.
399 """
400 dtype = pn_data_type(self._data)
401 if dtype == -1:
402 return None
403 else:
404 return dtype
405
407 """
408 Returns the size in bytes needed to encode the data in AMQP format.
409 """
410 return pn_data_encoded_size(self._data)
411
413 """
414 Returns a representation of the data encoded in AMQP format.
415 """
416 size = 1024
417 while True:
418 cd, enc = pn_data_encode(self._data, size)
419 if cd == PN_OVERFLOW:
420 size *= 2
421 elif cd >= 0:
422 return enc
423 else:
424 self._check(cd)
425
427 """
428 Decodes the first value from supplied AMQP data and returns the
429 number of bytes consumed.
430
431 @type encoded: binary
432 @param encoded: AMQP encoded binary data
433 """
434 return self._check(pn_data_decode(self._data, encoded))
435
437 """
438 Puts a list value. Elements may be filled by entering the list
439 node and putting element values.
440
441 >>> data = Data()
442 >>> data.put_list()
443 >>> data.enter()
444 >>> data.put_int(1)
445 >>> data.put_int(2)
446 >>> data.put_int(3)
447 >>> data.exit()
448 """
449 self._check(pn_data_put_list(self._data))
450
452 """
453 Puts a map value. Elements may be filled by entering the map node
454 and putting alternating key value pairs.
455
456 >>> data = Data()
457 >>> data.put_map()
458 >>> data.enter()
459 >>> data.put_string("key")
460 >>> data.put_string("value")
461 >>> data.exit()
462 """
463 self._check(pn_data_put_map(self._data))
464
465 - def put_array(self, described, element_type):
466 """
467 Puts an array value. Elements may be filled by entering the array
468 node and putting the element values. The values must all be of the
469 specified array element type. If an array is described then the
470 first child value of the array is the descriptor and may be of any
471 type.
472
473 >>> data = Data()
474 >>>
475 >>> data.put_array(False, Data.INT)
476 >>> data.enter()
477 >>> data.put_int(1)
478 >>> data.put_int(2)
479 >>> data.put_int(3)
480 >>> data.exit()
481 >>>
482 >>> data.put_array(True, Data.DOUBLE)
483 >>> data.enter()
484 >>> data.put_symbol("array-descriptor")
485 >>> data.put_double(1.1)
486 >>> data.put_double(1.2)
487 >>> data.put_double(1.3)
488 >>> data.exit()
489
490 @type described: bool
491 @param described: specifies whether the array is described
492 @type element_type: int
493 @param element_type: the type of the array elements
494 """
495 self._check(pn_data_put_array(self._data, described, element_type))
496
498 """
499 Puts a described value. A described node has two children, the
500 descriptor and the value. These are specified by entering the node
501 and putting the desired values.
502
503 >>> data = Data()
504 >>> data.put_described()
505 >>> data.enter()
506 >>> data.put_symbol("value-descriptor")
507 >>> data.put_string("the value")
508 >>> data.exit()
509 """
510 self._check(pn_data_put_described(self._data))
511
513 """
514 Puts a null value.
515 """
516 self._check(pn_data_put_null(self._data))
517
519 """
520 Puts a boolean value.
521
522 @param b: a boolean value
523 """
524 self._check(pn_data_put_bool(self._data, b))
525
527 """
528 Puts an unsigned byte value.
529
530 @param ub: an integral value
531 """
532 self._check(pn_data_put_ubyte(self._data, ub))
533
535 """
536 Puts a signed byte value.
537
538 @param b: an integral value
539 """
540 self._check(pn_data_put_byte(self._data, b))
541
543 """
544 Puts an unsigned short value.
545
546 @param us: an integral value.
547 """
548 self._check(pn_data_put_ushort(self._data, us))
549
551 """
552 Puts a signed short value.
553
554 @param s: an integral value
555 """
556 self._check(pn_data_put_short(self._data, s))
557
559 """
560 Puts an unsigned int value.
561
562 @param ui: an integral value
563 """
564 self._check(pn_data_put_uint(self._data, ui))
565
567 """
568 Puts a signed int value.
569
570 @param i: an integral value
571 """
572 self._check(pn_data_put_int(self._data, i))
573
575 """
576 Puts a char value.
577
578 @param c: a single character
579 """
580 self._check(pn_data_put_char(self._data, ord(c)))
581
583 """
584 Puts an unsigned long value.
585
586 @param ul: an integral value
587 """
588 self._check(pn_data_put_ulong(self._data, ul))
589
591 """
592 Puts a signed long value.
593
594 @param l: an integral value
595 """
596 self._check(pn_data_put_long(self._data, l))
597
599 """
600 Puts a timestamp value.
601
602 @param t: an integral value
603 """
604 self._check(pn_data_put_timestamp(self._data, t))
605
607 """
608 Puts a float value.
609
610 @param f: a floating point value
611 """
612 self._check(pn_data_put_float(self._data, f))
613
615 """
616 Puts a double value.
617
618 @param d: a floating point value.
619 """
620 self._check(pn_data_put_double(self._data, d))
621
623 """
624 Puts a decimal32 value.
625
626 @param d: a decimal32 value
627 """
628 self._check(pn_data_put_decimal32(self._data, d))
629
631 """
632 Puts a decimal64 value.
633
634 @param d: a decimal64 value
635 """
636 self._check(pn_data_put_decimal64(self._data, d))
637
639 """
640 Puts a decimal128 value.
641
642 @param d: a decimal128 value
643 """
644 self._check(pn_data_put_decimal128(self._data, d))
645
647 """
648 Puts a UUID value.
649
650 @param u: a uuid value
651 """
652 self._check(pn_data_put_uuid(self._data, u.bytes))
653
655 """
656 Puts a binary value.
657
658 @type b: binary
659 @param b: a binary value
660 """
661 self._check(pn_data_put_binary(self._data, b))
662
664 """Put a python memoryview object as an AMQP binary value"""
665 self.put_binary(mv.tobytes())
666
668 """Put a python buffer object as an AMQP binary value"""
669 self.put_binary(bytes(buff))
670
672 """
673 Puts a unicode value.
674
675 @type s: unicode
676 @param s: a unicode value
677 """
678 self._check(pn_data_put_string(self._data, s.encode("utf8")))
679
681 """
682 Puts a symbolic value.
683
684 @type s: string
685 @param s: the symbol name
686 """
687 self._check(pn_data_put_symbol(self._data, s.encode('ascii')))
688
690 """
691 If the current node is a list, return the number of elements,
692 otherwise return zero. List elements can be accessed by entering
693 the list.
694
695 >>> count = data.get_list()
696 >>> data.enter()
697 >>> for i in range(count):
698 ... type = data.next()
699 ... if type == Data.STRING:
700 ... print data.get_string()
701 ... elif type == ...:
702 ... ...
703 >>> data.exit()
704 """
705 return pn_data_get_list(self._data)
706
708 """
709 If the current node is a map, return the number of child elements,
710 otherwise return zero. Key value pairs can be accessed by entering
711 the map.
712
713 >>> count = data.get_map()
714 >>> data.enter()
715 >>> for i in range(count/2):
716 ... type = data.next()
717 ... if type == Data.STRING:
718 ... print data.get_string()
719 ... elif type == ...:
720 ... ...
721 >>> data.exit()
722 """
723 return pn_data_get_map(self._data)
724
726 """
727 If the current node is an array, return a tuple of the element
728 count, a boolean indicating whether the array is described, and
729 the type of each element, otherwise return (0, False, None). Array
730 data can be accessed by entering the array.
731
732 >>> # read an array of strings with a symbolic descriptor
733 >>> count, described, type = data.get_array()
734 >>> data.enter()
735 >>> data.next()
736 >>> print "Descriptor:", data.get_symbol()
737 >>> for i in range(count):
738 ... data.next()
739 ... print "Element:", data.get_string()
740 >>> data.exit()
741 """
742 count = pn_data_get_array(self._data)
743 described = pn_data_is_array_described(self._data)
744 type = pn_data_get_array_type(self._data)
745 if type == -1:
746 type = None
747 return count, described, type
748
750 """
751 Checks if the current node is a described value. The descriptor
752 and value may be accessed by entering the described value.
753
754 >>> # read a symbolically described string
755 >>> assert data.is_described() # will error if the current node is not described
756 >>> data.enter()
757 >>> data.next()
758 >>> print data.get_symbol()
759 >>> data.next()
760 >>> print data.get_string()
761 >>> data.exit()
762 """
763 return pn_data_is_described(self._data)
764
766 """
767 Checks if the current node is a null.
768 """
769 return pn_data_is_null(self._data)
770
772 """
773 If the current node is a boolean, returns its value, returns False
774 otherwise.
775 """
776 return pn_data_get_bool(self._data)
777
779 """
780 If the current node is an unsigned byte, returns its value,
781 returns 0 otherwise.
782 """
783 return ubyte(pn_data_get_ubyte(self._data))
784
786 """
787 If the current node is a signed byte, returns its value, returns 0
788 otherwise.
789 """
790 return byte(pn_data_get_byte(self._data))
791
793 """
794 If the current node is an unsigned short, returns its value,
795 returns 0 otherwise.
796 """
797 return ushort(pn_data_get_ushort(self._data))
798
800 """
801 If the current node is a signed short, returns its value, returns
802 0 otherwise.
803 """
804 return short(pn_data_get_short(self._data))
805
807 """
808 If the current node is an unsigned int, returns its value, returns
809 0 otherwise.
810 """
811 return uint(pn_data_get_uint(self._data))
812
814 """
815 If the current node is a signed int, returns its value, returns 0
816 otherwise.
817 """
818 return int32(pn_data_get_int(self._data))
819
821 """
822 If the current node is a char, returns its value, returns 0
823 otherwise.
824 """
825 return char(_compat.unichr(pn_data_get_char(self._data)))
826
828 """
829 If the current node is an unsigned long, returns its value,
830 returns 0 otherwise.
831 """
832 return ulong(pn_data_get_ulong(self._data))
833
835 """
836 If the current node is an signed long, returns its value, returns
837 0 otherwise.
838 """
839 return long(pn_data_get_long(self._data))
840
842 """
843 If the current node is a timestamp, returns its value, returns 0
844 otherwise.
845 """
846 return timestamp(pn_data_get_timestamp(self._data))
847
849 """
850 If the current node is a float, returns its value, raises 0
851 otherwise.
852 """
853 return float32(pn_data_get_float(self._data))
854
856 """
857 If the current node is a double, returns its value, returns 0
858 otherwise.
859 """
860 return pn_data_get_double(self._data)
861
862
864 """
865 If the current node is a decimal32, returns its value, returns 0
866 otherwise.
867 """
868 return decimal32(pn_data_get_decimal32(self._data))
869
870
872 """
873 If the current node is a decimal64, returns its value, returns 0
874 otherwise.
875 """
876 return decimal64(pn_data_get_decimal64(self._data))
877
878
880 """
881 If the current node is a decimal128, returns its value, returns 0
882 otherwise.
883 """
884 return decimal128(pn_data_get_decimal128(self._data))
885
887 """
888 If the current node is a UUID, returns its value, returns None
889 otherwise.
890 """
891 if pn_data_type(self._data) == Data.UUID:
892 return uuid.UUID(bytes=pn_data_get_uuid(self._data))
893 else:
894 return None
895
897 """
898 If the current node is binary, returns its value, returns ""
899 otherwise.
900 """
901 return pn_data_get_binary(self._data)
902
904 """
905 If the current node is a string, returns its value, returns ""
906 otherwise.
907 """
908 return pn_data_get_string(self._data).decode("utf8")
909
911 """
912 If the current node is a symbol, returns its value, returns ""
913 otherwise.
914 """
915 return symbol(pn_data_get_symbol(self._data).decode('ascii'))
916
917 - def copy(self, src):
918 self._check(pn_data_copy(self._data, src._data))
919
930
932 pn_data_dump(self._data)
933
943
945 if self.enter():
946 try:
947 result = {}
948 while self.next():
949 k = self.get_object()
950 if self.next():
951 v = self.get_object()
952 else:
953 v = None
954 result[k] = v
955 finally:
956 self.exit()
957 return result
958
967
969 if self.enter():
970 try:
971 result = []
972 while self.next():
973 result.append(self.get_object())
974 finally:
975 self.exit()
976 return result
977
988
997
999 """
1000 If the current node is an array, return an Array object
1001 representing the array and its contents. Otherwise return None.
1002 This is a convenience wrapper around get_array, enter, etc.
1003 """
1004
1005 count, described, type = self.get_array()
1006 if type is None: return None
1007 if self.enter():
1008 try:
1009 if described:
1010 self.next()
1011 descriptor = self.get_object()
1012 else:
1013 descriptor = UNDESCRIBED
1014 elements = []
1015 while self.next():
1016 elements.append(self.get_object())
1017 finally:
1018 self.exit()
1019 return Array(descriptor, type, *elements)
1020
1032
1033 put_mappings = {
1034 None.__class__: lambda s, _: s.put_null(),
1035 bool: put_bool,
1036 ubyte: put_ubyte,
1037 ushort: put_ushort,
1038 uint: put_uint,
1039 ulong: put_ulong,
1040 byte: put_byte,
1041 short: put_short,
1042 int32: put_int,
1043 long: put_long,
1044 float32: put_float,
1045 float: put_double,
1046 decimal32: put_decimal32,
1047 decimal64: put_decimal64,
1048 decimal128: put_decimal128,
1049 char: put_char,
1050 timestamp: put_timestamp,
1051 uuid.UUID: put_uuid,
1052 bytes: put_binary,
1053 unicode: put_string,
1054 symbol: put_symbol,
1055 list: put_sequence,
1056 tuple: put_sequence,
1057 dict: put_dict,
1058 Described: put_py_described,
1059 Array: put_py_array
1060 }
1061
1062
1063 if int not in put_mappings:
1064 put_mappings[int] = put_int
1065
1066 try:
1067 put_mappings[memoryview] = put_memoryview
1068 except NameError:
1069 pass
1070 try:
1071 put_mappings[buffer] = put_buffer
1072 except NameError:
1073 pass
1074 get_mappings = {
1075 NULL: lambda s: None,
1076 BOOL: get_bool,
1077 BYTE: get_byte,
1078 UBYTE: get_ubyte,
1079 SHORT: get_short,
1080 USHORT: get_ushort,
1081 INT: get_int,
1082 UINT: get_uint,
1083 CHAR: get_char,
1084 LONG: get_long,
1085 ULONG: get_ulong,
1086 TIMESTAMP: get_timestamp,
1087 FLOAT: get_float,
1088 DOUBLE: get_double,
1089 DECIMAL32: get_decimal32,
1090 DECIMAL64: get_decimal64,
1091 DECIMAL128: get_decimal128,
1092 UUID: get_uuid,
1093 BINARY: get_binary,
1094 STRING: get_string,
1095 SYMBOL: get_symbol,
1096 DESCRIBED: get_py_described,
1097 ARRAY: get_py_array,
1098 LIST: get_sequence,
1099 MAP: get_dict
1100 }
1101
1103 putter = self.put_mappings[obj.__class__]
1104 putter(self, obj)
1105
1114
1124
1130