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