3131import types
3232import traceback
3333import logging
34+ import numpy
35+ import pickle
3436
3537
3638_badModuleCache = set ()
3739
3840
41+ def pickledByStr (module_name : str , name : str ) -> None :
42+ """Generate the object given the module_name and name.
43+
44+ This mimics pickle's behavior when given a string from __reduce__. The
45+ string is interpreted as the name of a global variable, and pickle.whichmodules
46+ is used to search the module namespace, generating module_name.
47+ """
48+ module = importlib .import_module (module_name )
49+ return getattr (module , name )
50+
51+
3952def createFunctionWithLocalsAndGlobals (code , globals ):
4053 if globals is None :
4154 globals = {}
@@ -708,26 +721,30 @@ def walkCodeObject(code):
708721 return (createFunctionWithLocalsAndGlobals , args , representation )
709722
710723 if not isinstance (inst , type ) and hasattr (type (inst ), '__reduce_ex__' ):
711- res = inst .__reduce_ex__ (4 )
724+ if isinstance (inst , numpy .ufunc ):
725+ res = inst .__name__
726+ else :
727+ res = inst .__reduce_ex__ (4 )
712728
713- # pickle supports a protocol where __reduce__ can return a string
714- # giving a global name. We'll already find that separately, so we
715- # don't want to handle it here. We ought to look at this in more detail
716- # however
729+ # mimic pickle's behaviour when a string is received.
717730 if isinstance (res , str ):
718- return None
731+ name_tuple = (inst , res )
732+ module_name = pickle .whichmodule (* name_tuple )
733+ res = (pickledByStr , (module_name , res ,), pickledByStr )
719734
720735 return res
721736
722737 if not isinstance (inst , type ) and hasattr (type (inst ), '__reduce__' ):
723- res = inst .__reduce__ ()
738+ if isinstance (inst , numpy .ufunc ):
739+ res = inst .__name__
740+ else :
741+ res = inst .__reduce ()
724742
725- # pickle supports a protocol where __reduce__ can return a string
726- # giving a global name. We'll already find that separately, so we
727- # don't want to handle it here. We ought to look at this in more detail
728- # however
743+ # mimic pickle's behaviour when a string is received.
729744 if isinstance (res , str ):
730- return None
745+ name_tuple = (inst , res )
746+ module_name = pickle .whichmodule (* name_tuple )
747+ res = (pickledByStr , (module_name , res ,), pickledByStr )
731748
732749 return res
733750
@@ -736,6 +753,9 @@ def walkCodeObject(code):
736753 def setInstanceStateFromRepresentation (
737754 self , instance , representation = None , itemIt = None , kvPairIt = None , setStateFun = None
738755 ):
756+ if representation is pickledByStr :
757+ return
758+
739759 if representation is reconstructTypeFunctionType :
740760 return
741761
0 commit comments