xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/copyreg.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Helper to provide extensibility for pickle.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerThis is only useful to add pickle support for extension types defined in
4*cda5da8dSAndroid Build Coastguard WorkerC, not for instances of user-defined classes.
5*cda5da8dSAndroid Build Coastguard Worker"""
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard Worker__all__ = ["pickle", "constructor",
8*cda5da8dSAndroid Build Coastguard Worker           "add_extension", "remove_extension", "clear_extension_cache"]
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Workerdispatch_table = {}
11*cda5da8dSAndroid Build Coastguard Worker
12*cda5da8dSAndroid Build Coastguard Workerdef pickle(ob_type, pickle_function, constructor_ob=None):
13*cda5da8dSAndroid Build Coastguard Worker    if not callable(pickle_function):
14*cda5da8dSAndroid Build Coastguard Worker        raise TypeError("reduction functions must be callable")
15*cda5da8dSAndroid Build Coastguard Worker    dispatch_table[ob_type] = pickle_function
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker    # The constructor_ob function is a vestige of safe for unpickling.
18*cda5da8dSAndroid Build Coastguard Worker    # There is no reason for the caller to pass it anymore.
19*cda5da8dSAndroid Build Coastguard Worker    if constructor_ob is not None:
20*cda5da8dSAndroid Build Coastguard Worker        constructor(constructor_ob)
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Workerdef constructor(object):
23*cda5da8dSAndroid Build Coastguard Worker    if not callable(object):
24*cda5da8dSAndroid Build Coastguard Worker        raise TypeError("constructors must be callable")
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Worker# Example: provide pickling support for complex numbers.
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Workertry:
29*cda5da8dSAndroid Build Coastguard Worker    complex
30*cda5da8dSAndroid Build Coastguard Workerexcept NameError:
31*cda5da8dSAndroid Build Coastguard Worker    pass
32*cda5da8dSAndroid Build Coastguard Workerelse:
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard Worker    def pickle_complex(c):
35*cda5da8dSAndroid Build Coastguard Worker        return complex, (c.real, c.imag)
36*cda5da8dSAndroid Build Coastguard Worker
37*cda5da8dSAndroid Build Coastguard Worker    pickle(complex, pickle_complex, complex)
38*cda5da8dSAndroid Build Coastguard Worker
39*cda5da8dSAndroid Build Coastguard Workerdef pickle_union(obj):
40*cda5da8dSAndroid Build Coastguard Worker    import functools, operator
41*cda5da8dSAndroid Build Coastguard Worker    return functools.reduce, (operator.or_, obj.__args__)
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Workerpickle(type(int | str), pickle_union)
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Worker# Support for pickling new-style objects
46*cda5da8dSAndroid Build Coastguard Worker
47*cda5da8dSAndroid Build Coastguard Workerdef _reconstructor(cls, base, state):
48*cda5da8dSAndroid Build Coastguard Worker    if base is object:
49*cda5da8dSAndroid Build Coastguard Worker        obj = object.__new__(cls)
50*cda5da8dSAndroid Build Coastguard Worker    else:
51*cda5da8dSAndroid Build Coastguard Worker        obj = base.__new__(cls, state)
52*cda5da8dSAndroid Build Coastguard Worker        if base.__init__ != object.__init__:
53*cda5da8dSAndroid Build Coastguard Worker            base.__init__(obj, state)
54*cda5da8dSAndroid Build Coastguard Worker    return obj
55*cda5da8dSAndroid Build Coastguard Worker
56*cda5da8dSAndroid Build Coastguard Worker_HEAPTYPE = 1<<9
57*cda5da8dSAndroid Build Coastguard Worker_new_type = type(int.__new__)
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Worker# Python code for object.__reduce_ex__ for protocols 0 and 1
60*cda5da8dSAndroid Build Coastguard Worker
61*cda5da8dSAndroid Build Coastguard Workerdef _reduce_ex(self, proto):
62*cda5da8dSAndroid Build Coastguard Worker    assert proto < 2
63*cda5da8dSAndroid Build Coastguard Worker    cls = self.__class__
64*cda5da8dSAndroid Build Coastguard Worker    for base in cls.__mro__:
65*cda5da8dSAndroid Build Coastguard Worker        if hasattr(base, '__flags__') and not base.__flags__ & _HEAPTYPE:
66*cda5da8dSAndroid Build Coastguard Worker            break
67*cda5da8dSAndroid Build Coastguard Worker        new = base.__new__
68*cda5da8dSAndroid Build Coastguard Worker        if isinstance(new, _new_type) and new.__self__ is base:
69*cda5da8dSAndroid Build Coastguard Worker            break
70*cda5da8dSAndroid Build Coastguard Worker    else:
71*cda5da8dSAndroid Build Coastguard Worker        base = object # not really reachable
72*cda5da8dSAndroid Build Coastguard Worker    if base is object:
73*cda5da8dSAndroid Build Coastguard Worker        state = None
74*cda5da8dSAndroid Build Coastguard Worker    else:
75*cda5da8dSAndroid Build Coastguard Worker        if base is cls:
76*cda5da8dSAndroid Build Coastguard Worker            raise TypeError(f"cannot pickle {cls.__name__!r} object")
77*cda5da8dSAndroid Build Coastguard Worker        state = base(self)
78*cda5da8dSAndroid Build Coastguard Worker    args = (cls, base, state)
79*cda5da8dSAndroid Build Coastguard Worker    try:
80*cda5da8dSAndroid Build Coastguard Worker        getstate = self.__getstate__
81*cda5da8dSAndroid Build Coastguard Worker    except AttributeError:
82*cda5da8dSAndroid Build Coastguard Worker        if getattr(self, "__slots__", None):
83*cda5da8dSAndroid Build Coastguard Worker            raise TypeError(f"cannot pickle {cls.__name__!r} object: "
84*cda5da8dSAndroid Build Coastguard Worker                            f"a class that defines __slots__ without "
85*cda5da8dSAndroid Build Coastguard Worker                            f"defining __getstate__ cannot be pickled "
86*cda5da8dSAndroid Build Coastguard Worker                            f"with protocol {proto}") from None
87*cda5da8dSAndroid Build Coastguard Worker        try:
88*cda5da8dSAndroid Build Coastguard Worker            dict = self.__dict__
89*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
90*cda5da8dSAndroid Build Coastguard Worker            dict = None
91*cda5da8dSAndroid Build Coastguard Worker    else:
92*cda5da8dSAndroid Build Coastguard Worker        if (type(self).__getstate__ is object.__getstate__ and
93*cda5da8dSAndroid Build Coastguard Worker            getattr(self, "__slots__", None)):
94*cda5da8dSAndroid Build Coastguard Worker            raise TypeError("a class that defines __slots__ without "
95*cda5da8dSAndroid Build Coastguard Worker                            "defining __getstate__ cannot be pickled")
96*cda5da8dSAndroid Build Coastguard Worker        dict = getstate()
97*cda5da8dSAndroid Build Coastguard Worker    if dict:
98*cda5da8dSAndroid Build Coastguard Worker        return _reconstructor, args, dict
99*cda5da8dSAndroid Build Coastguard Worker    else:
100*cda5da8dSAndroid Build Coastguard Worker        return _reconstructor, args
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker# Helper for __reduce_ex__ protocol 2
103*cda5da8dSAndroid Build Coastguard Worker
104*cda5da8dSAndroid Build Coastguard Workerdef __newobj__(cls, *args):
105*cda5da8dSAndroid Build Coastguard Worker    return cls.__new__(cls, *args)
106*cda5da8dSAndroid Build Coastguard Worker
107*cda5da8dSAndroid Build Coastguard Workerdef __newobj_ex__(cls, args, kwargs):
108*cda5da8dSAndroid Build Coastguard Worker    """Used by pickle protocol 4, instead of __newobj__ to allow classes with
109*cda5da8dSAndroid Build Coastguard Worker    keyword-only arguments to be pickled correctly.
110*cda5da8dSAndroid Build Coastguard Worker    """
111*cda5da8dSAndroid Build Coastguard Worker    return cls.__new__(cls, *args, **kwargs)
112*cda5da8dSAndroid Build Coastguard Worker
113*cda5da8dSAndroid Build Coastguard Workerdef _slotnames(cls):
114*cda5da8dSAndroid Build Coastguard Worker    """Return a list of slot names for a given class.
115*cda5da8dSAndroid Build Coastguard Worker
116*cda5da8dSAndroid Build Coastguard Worker    This needs to find slots defined by the class and its bases, so we
117*cda5da8dSAndroid Build Coastguard Worker    can't simply return the __slots__ attribute.  We must walk down
118*cda5da8dSAndroid Build Coastguard Worker    the Method Resolution Order and concatenate the __slots__ of each
119*cda5da8dSAndroid Build Coastguard Worker    class found there.  (This assumes classes don't modify their
120*cda5da8dSAndroid Build Coastguard Worker    __slots__ attribute to misrepresent their slots after the class is
121*cda5da8dSAndroid Build Coastguard Worker    defined.)
122*cda5da8dSAndroid Build Coastguard Worker    """
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker    # Get the value from a cache in the class if possible
125*cda5da8dSAndroid Build Coastguard Worker    names = cls.__dict__.get("__slotnames__")
126*cda5da8dSAndroid Build Coastguard Worker    if names is not None:
127*cda5da8dSAndroid Build Coastguard Worker        return names
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Worker    # Not cached -- calculate the value
130*cda5da8dSAndroid Build Coastguard Worker    names = []
131*cda5da8dSAndroid Build Coastguard Worker    if not hasattr(cls, "__slots__"):
132*cda5da8dSAndroid Build Coastguard Worker        # This class has no slots
133*cda5da8dSAndroid Build Coastguard Worker        pass
134*cda5da8dSAndroid Build Coastguard Worker    else:
135*cda5da8dSAndroid Build Coastguard Worker        # Slots found -- gather slot names from all base classes
136*cda5da8dSAndroid Build Coastguard Worker        for c in cls.__mro__:
137*cda5da8dSAndroid Build Coastguard Worker            if "__slots__" in c.__dict__:
138*cda5da8dSAndroid Build Coastguard Worker                slots = c.__dict__['__slots__']
139*cda5da8dSAndroid Build Coastguard Worker                # if class has a single slot, it can be given as a string
140*cda5da8dSAndroid Build Coastguard Worker                if isinstance(slots, str):
141*cda5da8dSAndroid Build Coastguard Worker                    slots = (slots,)
142*cda5da8dSAndroid Build Coastguard Worker                for name in slots:
143*cda5da8dSAndroid Build Coastguard Worker                    # special descriptors
144*cda5da8dSAndroid Build Coastguard Worker                    if name in ("__dict__", "__weakref__"):
145*cda5da8dSAndroid Build Coastguard Worker                        continue
146*cda5da8dSAndroid Build Coastguard Worker                    # mangled names
147*cda5da8dSAndroid Build Coastguard Worker                    elif name.startswith('__') and not name.endswith('__'):
148*cda5da8dSAndroid Build Coastguard Worker                        stripped = c.__name__.lstrip('_')
149*cda5da8dSAndroid Build Coastguard Worker                        if stripped:
150*cda5da8dSAndroid Build Coastguard Worker                            names.append('_%s%s' % (stripped, name))
151*cda5da8dSAndroid Build Coastguard Worker                        else:
152*cda5da8dSAndroid Build Coastguard Worker                            names.append(name)
153*cda5da8dSAndroid Build Coastguard Worker                    else:
154*cda5da8dSAndroid Build Coastguard Worker                        names.append(name)
155*cda5da8dSAndroid Build Coastguard Worker
156*cda5da8dSAndroid Build Coastguard Worker    # Cache the outcome in the class if at all possible
157*cda5da8dSAndroid Build Coastguard Worker    try:
158*cda5da8dSAndroid Build Coastguard Worker        cls.__slotnames__ = names
159*cda5da8dSAndroid Build Coastguard Worker    except:
160*cda5da8dSAndroid Build Coastguard Worker        pass # But don't die if we can't
161*cda5da8dSAndroid Build Coastguard Worker
162*cda5da8dSAndroid Build Coastguard Worker    return names
163*cda5da8dSAndroid Build Coastguard Worker
164*cda5da8dSAndroid Build Coastguard Worker# A registry of extension codes.  This is an ad-hoc compression
165*cda5da8dSAndroid Build Coastguard Worker# mechanism.  Whenever a global reference to <module>, <name> is about
166*cda5da8dSAndroid Build Coastguard Worker# to be pickled, the (<module>, <name>) tuple is looked up here to see
167*cda5da8dSAndroid Build Coastguard Worker# if it is a registered extension code for it.  Extension codes are
168*cda5da8dSAndroid Build Coastguard Worker# universal, so that the meaning of a pickle does not depend on
169*cda5da8dSAndroid Build Coastguard Worker# context.  (There are also some codes reserved for local use that
170*cda5da8dSAndroid Build Coastguard Worker# don't have this restriction.)  Codes are positive ints; 0 is
171*cda5da8dSAndroid Build Coastguard Worker# reserved.
172*cda5da8dSAndroid Build Coastguard Worker
173*cda5da8dSAndroid Build Coastguard Worker_extension_registry = {}                # key -> code
174*cda5da8dSAndroid Build Coastguard Worker_inverted_registry = {}                 # code -> key
175*cda5da8dSAndroid Build Coastguard Worker_extension_cache = {}                   # code -> object
176*cda5da8dSAndroid Build Coastguard Worker# Don't ever rebind those names:  pickling grabs a reference to them when
177*cda5da8dSAndroid Build Coastguard Worker# it's initialized, and won't see a rebinding.
178*cda5da8dSAndroid Build Coastguard Worker
179*cda5da8dSAndroid Build Coastguard Workerdef add_extension(module, name, code):
180*cda5da8dSAndroid Build Coastguard Worker    """Register an extension code."""
181*cda5da8dSAndroid Build Coastguard Worker    code = int(code)
182*cda5da8dSAndroid Build Coastguard Worker    if not 1 <= code <= 0x7fffffff:
183*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("code out of range")
184*cda5da8dSAndroid Build Coastguard Worker    key = (module, name)
185*cda5da8dSAndroid Build Coastguard Worker    if (_extension_registry.get(key) == code and
186*cda5da8dSAndroid Build Coastguard Worker        _inverted_registry.get(code) == key):
187*cda5da8dSAndroid Build Coastguard Worker        return # Redundant registrations are benign
188*cda5da8dSAndroid Build Coastguard Worker    if key in _extension_registry:
189*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("key %s is already registered with code %s" %
190*cda5da8dSAndroid Build Coastguard Worker                         (key, _extension_registry[key]))
191*cda5da8dSAndroid Build Coastguard Worker    if code in _inverted_registry:
192*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("code %s is already in use for key %s" %
193*cda5da8dSAndroid Build Coastguard Worker                         (code, _inverted_registry[code]))
194*cda5da8dSAndroid Build Coastguard Worker    _extension_registry[key] = code
195*cda5da8dSAndroid Build Coastguard Worker    _inverted_registry[code] = key
196*cda5da8dSAndroid Build Coastguard Worker
197*cda5da8dSAndroid Build Coastguard Workerdef remove_extension(module, name, code):
198*cda5da8dSAndroid Build Coastguard Worker    """Unregister an extension code.  For testing only."""
199*cda5da8dSAndroid Build Coastguard Worker    key = (module, name)
200*cda5da8dSAndroid Build Coastguard Worker    if (_extension_registry.get(key) != code or
201*cda5da8dSAndroid Build Coastguard Worker        _inverted_registry.get(code) != key):
202*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("key %s is not registered with code %s" %
203*cda5da8dSAndroid Build Coastguard Worker                         (key, code))
204*cda5da8dSAndroid Build Coastguard Worker    del _extension_registry[key]
205*cda5da8dSAndroid Build Coastguard Worker    del _inverted_registry[code]
206*cda5da8dSAndroid Build Coastguard Worker    if code in _extension_cache:
207*cda5da8dSAndroid Build Coastguard Worker        del _extension_cache[code]
208*cda5da8dSAndroid Build Coastguard Worker
209*cda5da8dSAndroid Build Coastguard Workerdef clear_extension_cache():
210*cda5da8dSAndroid Build Coastguard Worker    _extension_cache.clear()
211*cda5da8dSAndroid Build Coastguard Worker
212*cda5da8dSAndroid Build Coastguard Worker# Standard extension code assignments
213*cda5da8dSAndroid Build Coastguard Worker
214*cda5da8dSAndroid Build Coastguard Worker# Reserved ranges
215*cda5da8dSAndroid Build Coastguard Worker
216*cda5da8dSAndroid Build Coastguard Worker# First  Last Count  Purpose
217*cda5da8dSAndroid Build Coastguard Worker#     1   127   127  Reserved for Python standard library
218*cda5da8dSAndroid Build Coastguard Worker#   128   191    64  Reserved for Zope
219*cda5da8dSAndroid Build Coastguard Worker#   192   239    48  Reserved for 3rd parties
220*cda5da8dSAndroid Build Coastguard Worker#   240   255    16  Reserved for private use (will never be assigned)
221*cda5da8dSAndroid Build Coastguard Worker#   256   Inf   Inf  Reserved for future assignment
222*cda5da8dSAndroid Build Coastguard Worker
223*cda5da8dSAndroid Build Coastguard Worker# Extension codes are assigned by the Python Software Foundation.
224