mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
[3.13] gh-82951: Fix serializing by name in pickle protocols < 4 (GH-122149) (GH-122264)
Serializing objects with complex __qualname__ (such as unbound methods and
nested classes) by name no longer involves serializing parent objects by value
in pickle protocols < 4.
(cherry picked from commit dc07f65a53
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
977c799286
commit
984f8aaa2f
4 changed files with 82 additions and 26 deletions
|
@ -1110,11 +1110,35 @@ class _Pickler:
|
|||
self.save(module_name)
|
||||
self.save(name)
|
||||
write(STACK_GLOBAL)
|
||||
elif parent is not module:
|
||||
self.save_reduce(getattr, (parent, lastname))
|
||||
elif self.proto >= 3:
|
||||
write(GLOBAL + bytes(module_name, "utf-8") + b'\n' +
|
||||
bytes(name, "utf-8") + b'\n')
|
||||
elif '.' in name:
|
||||
# In protocol < 4, objects with multi-part __qualname__
|
||||
# are represented as
|
||||
# getattr(getattr(..., attrname1), attrname2).
|
||||
dotted_path = name.split('.')
|
||||
name = dotted_path.pop(0)
|
||||
save = self.save
|
||||
for attrname in dotted_path:
|
||||
save(getattr)
|
||||
if self.proto < 2:
|
||||
write(MARK)
|
||||
self._save_toplevel_by_name(module_name, name)
|
||||
for attrname in dotted_path:
|
||||
save(attrname)
|
||||
if self.proto < 2:
|
||||
write(TUPLE)
|
||||
else:
|
||||
write(TUPLE2)
|
||||
write(REDUCE)
|
||||
else:
|
||||
self._save_toplevel_by_name(module_name, name)
|
||||
|
||||
self.memoize(obj)
|
||||
|
||||
def _save_toplevel_by_name(self, module_name, name):
|
||||
if self.proto >= 3:
|
||||
# Non-ASCII identifiers are supported only with protocols >= 3.
|
||||
self.write(GLOBAL + bytes(module_name, "utf-8") + b'\n' +
|
||||
bytes(name, "utf-8") + b'\n')
|
||||
else:
|
||||
if self.fix_imports:
|
||||
r_name_mapping = _compat_pickle.REVERSE_NAME_MAPPING
|
||||
|
@ -1124,15 +1148,13 @@ class _Pickler:
|
|||
elif module_name in r_import_mapping:
|
||||
module_name = r_import_mapping[module_name]
|
||||
try:
|
||||
write(GLOBAL + bytes(module_name, "ascii") + b'\n' +
|
||||
bytes(name, "ascii") + b'\n')
|
||||
self.write(GLOBAL + bytes(module_name, "ascii") + b'\n' +
|
||||
bytes(name, "ascii") + b'\n')
|
||||
except UnicodeEncodeError:
|
||||
raise PicklingError(
|
||||
"can't pickle global identifier '%s.%s' using "
|
||||
"pickle protocol %i" % (module, name, self.proto)) from None
|
||||
|
||||
self.memoize(obj)
|
||||
|
||||
def save_type(self, obj):
|
||||
if obj is type(None):
|
||||
return self.save_reduce(type, (None,), obj=obj)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue