(self, func, args, state=None, listitems=None,
dictitems=None, state_setter=None, *, obj=None)
| 634 | "persistent IDs in protocol 0 must be ASCII strings") |
| 635 | |
| 636 | def save_reduce(self, func, args, state=None, listitems=None, |
| 637 | dictitems=None, state_setter=None, *, obj=None): |
| 638 | # This API is called by some subclasses |
| 639 | |
| 640 | if not callable(func): |
| 641 | raise PicklingError(f"first item of the tuple returned by __reduce__ " |
| 642 | f"must be callable, not {_T(func)}") |
| 643 | if not isinstance(args, tuple): |
| 644 | raise PicklingError(f"second item of the tuple returned by __reduce__ " |
| 645 | f"must be a tuple, not {_T(args)}") |
| 646 | |
| 647 | save = self.save |
| 648 | write = self.write |
| 649 | |
| 650 | func_name = getattr(func, "__name__", "") |
| 651 | if self.proto >= 2 and func_name == "__newobj_ex__": |
| 652 | cls, args, kwargs = args |
| 653 | if not hasattr(cls, "__new__"): |
| 654 | raise PicklingError("first argument to __newobj_ex__() has no __new__") |
| 655 | if obj is not None and cls is not obj.__class__: |
| 656 | raise PicklingError(f"first argument to __newobj_ex__() " |
| 657 | f"must be {obj.__class__!r}, not {cls!r}") |
| 658 | if self.proto >= 4: |
| 659 | try: |
| 660 | save(cls) |
| 661 | except BaseException as exc: |
| 662 | exc.add_note(f'when serializing {_T(obj)} class') |
| 663 | raise |
| 664 | try: |
| 665 | save(args) |
| 666 | save(kwargs) |
| 667 | except BaseException as exc: |
| 668 | exc.add_note(f'when serializing {_T(obj)} __new__ arguments') |
| 669 | raise |
| 670 | write(NEWOBJ_EX) |
| 671 | else: |
| 672 | func = partial(cls.__new__, cls, *args, **kwargs) |
| 673 | try: |
| 674 | save(func) |
| 675 | except BaseException as exc: |
| 676 | exc.add_note(f'when serializing {_T(obj)} reconstructor') |
| 677 | raise |
| 678 | save(()) |
| 679 | write(REDUCE) |
| 680 | elif self.proto >= 2 and func_name == "__newobj__": |
| 681 | # A __reduce__ implementation can direct protocol 2 or newer to |
| 682 | # use the more efficient NEWOBJ opcode, while still |
| 683 | # allowing protocol 0 and 1 to work normally. For this to |
| 684 | # work, the function returned by __reduce__ should be |
| 685 | # called __newobj__, and its first argument should be a |
| 686 | # class. The implementation for __newobj__ |
| 687 | # should be as follows, although pickle has no way to |
| 688 | # verify this: |
| 689 | # |
| 690 | # def __newobj__(cls, *args): |
| 691 | # return cls.__new__(cls, *args) |
| 692 | # |
| 693 | # Protocols 0 and 1 will pickle a reference to __newobj__, |
no test coverage detected