| 703 | self._fp.write(struct.pack('>5xBBBQQQ', *trailer)) |
| 704 | |
| 705 | def _flatten(self, value): |
| 706 | # First check if the object is in the object table, not used for |
| 707 | # containers to ensure that two subcontainers with the same contents |
| 708 | # will be serialized as distinct values. |
| 709 | if isinstance(value, _scalars): |
| 710 | if (type(value), value) in self._objtable: |
| 711 | return |
| 712 | |
| 713 | elif id(value) in self._objidtable: |
| 714 | return |
| 715 | |
| 716 | # Add to objectreference map |
| 717 | refnum = len(self._objlist) |
| 718 | self._objlist.append(value) |
| 719 | if isinstance(value, _scalars): |
| 720 | self._objtable[(type(value), value)] = refnum |
| 721 | else: |
| 722 | self._objidtable[id(value)] = refnum |
| 723 | |
| 724 | # And finally recurse into containers |
| 725 | if isinstance(value, dict): |
| 726 | keys = [] |
| 727 | values = [] |
| 728 | items = value.items() |
| 729 | if self._sort_keys: |
| 730 | items = sorted(items) |
| 731 | |
| 732 | for k, v in items: |
| 733 | if not isinstance(k, str): |
| 734 | if self._skipkeys: |
| 735 | continue |
| 736 | raise TypeError("keys must be strings") |
| 737 | keys.append(k) |
| 738 | values.append(v) |
| 739 | |
| 740 | for o in itertools.chain(keys, values): |
| 741 | self._flatten(o) |
| 742 | |
| 743 | elif isinstance(value, (list, tuple)): |
| 744 | for o in value: |
| 745 | self._flatten(o) |
| 746 | |
| 747 | def _getrefnum(self, value): |
| 748 | if isinstance(value, _scalars): |