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