@@ -109,10 +109,28 @@ def uuid_generator(_):
109109
110110@dataclasses .dataclass
111111class CloudPickleConfig :
112- """Configuration for cloudpickle behavior."""
112+ """Configuration for cloudpickle behavior.
113+
114+ This class controls various aspects of how cloudpickle serializes objects.
115+
116+ Attributes:
117+ id_generator: Callable that generates unique identifiers for dynamic
118+ types. Controls isinstance semantics preservation. If None,
119+ disables type tracking and isinstance relationships are not
120+ preserved across pickle/unpickle cycles. If callable, generates
121+ unique IDs to maintain object identity.
122+ Default: uuid_generator (generates UUID hex strings).
123+
124+ skip_reset_dynamic_type_state: Whether to skip resetting state when
125+ reconstructing dynamic types. If True, skips state reset for
126+ already-reconstructed types.
127+
128+ filepath_interceptor: Used to modify filepaths in `co_filename` and
129+ function.__globals__['__file__'].
130+ """
113131 id_generator : typing .Optional [callable ] = uuid_generator
114132 skip_reset_dynamic_type_state : bool = False
115- use_relative_filepaths : bool = False
133+ filepath_interceptor : typing . Optional [ callable ] = None
116134
117135
118136DEFAULT_CONFIG = CloudPickleConfig ()
@@ -398,7 +416,7 @@ def func():
398416 return subimports
399417
400418
401- def _get_relative_path (path ):
419+ def get_relative_path (path ):
402420 """Returns the path of a filename relative to the longest matching directory
403421 in sys.path.
404422 Args:
@@ -631,7 +649,7 @@ def _make_typevar(
631649 return _lookup_class_or_track (class_tracker_id , tv )
632650
633651
634- def _decompose_typevar (obj , config ):
652+ def _decompose_typevar (obj , config : CloudPickleConfig ):
635653 return (
636654 obj .__name__ ,
637655 obj .__bound__ ,
@@ -642,7 +660,7 @@ def _decompose_typevar(obj, config):
642660 )
643661
644662
645- def _typevar_reduce (obj , config ):
663+ def _typevar_reduce (obj , config : CloudPickleConfig ):
646664 # TypeVar instances require the module information hence why we
647665 # are not using the _should_pickle_by_reference directly
648666 module_and_name = _lookup_module_and_qualname (obj , name = obj .__name__ )
@@ -694,7 +712,7 @@ def _make_dict_items(obj, is_ordered=False):
694712# -------------------------------------------------
695713
696714
697- def _class_getnewargs (obj , config ):
715+ def _class_getnewargs (obj , config : CloudPickleConfig ):
698716 type_kwargs = {}
699717 if "__module__" in obj .__dict__ :
700718 type_kwargs ["__module__" ] = obj .__module__
@@ -713,7 +731,7 @@ def _class_getnewargs(obj, config):
713731 )
714732
715733
716- def _enum_getnewargs (obj , config ):
734+ def _enum_getnewargs (obj , config : CloudPickleConfig ):
717735 members = {e .name : e .value for e in obj }
718736 return (
719737 obj .__bases__ ,
@@ -854,7 +872,7 @@ def _enum_getstate(obj):
854872# these holes".
855873
856874
857- def _code_reduce (obj , config ):
875+ def _code_reduce (obj , config : CloudPickleConfig ):
858876 """code object reducer."""
859877 # If you are not sure about the order of arguments, take a look at help
860878 # of the specific type from types, for example:
@@ -875,8 +893,8 @@ def _code_reduce(obj, config):
875893 co_cellvars = tuple (name for name in obj .co_cellvars )
876894
877895 co_filename = obj .co_filename
878- if (config and config .use_relative_filepaths ):
879- co_filename = _get_relative_path (co_filename )
896+ if (config and config .filepath_interceptor ):
897+ co_filename = config . filepath_interceptor (co_filename )
880898
881899 if hasattr (obj , "co_exceptiontable" ):
882900 # Python 3.11 and later: there are some new attributes
@@ -1071,7 +1089,7 @@ def _weakset_reduce(obj):
10711089 return weakref .WeakSet , (list (obj ), )
10721090
10731091
1074- def _dynamic_class_reduce (obj , config ):
1092+ def _dynamic_class_reduce (obj , config : CloudPickleConfig ):
10751093 """Save a class that can't be referenced as a module attribute.
10761094
10771095 This method is used to serialize classes that are defined inside
@@ -1102,7 +1120,7 @@ def _dynamic_class_reduce(obj, config):
11021120 )
11031121
11041122
1105- def _class_reduce (obj , config ):
1123+ def _class_reduce (obj , config : CloudPickleConfig ):
11061124 """Select the reducer depending on the dynamic nature of the class obj."""
11071125 if obj is type (None ): # noqa
11081126 return type , (None , )
@@ -1197,7 +1215,7 @@ def _function_setstate(obj, state):
11971215 setattr (obj , k , v )
11981216
11991217
1200- def _class_setstate (obj , state , skip_reset_dynamic_type_state ):
1218+ def _class_setstate (obj , state , skip_reset_dynamic_type_state = False ):
12011219 # Lock while potentially modifying class state.
12021220 with _DYNAMIC_CLASS_TRACKER_LOCK :
12031221 if skip_reset_dynamic_type_state and obj in _DYNAMIC_CLASS_STATE_TRACKER_BY_CLASS :
@@ -1330,12 +1348,12 @@ def _function_getnewargs(self, func):
13301348 if "__file__" in func .__globals__ :
13311349 # Apply normalization ONLY to the __file__ attribute
13321350 file_path = func .__globals__ ["__file__" ]
1333- if self .config .use_relative_filepaths :
1334- file_path = _get_relative_path (file_path )
1351+ if self .config .filepath_interceptor :
1352+ file_path = self . config . filepath_interceptor (file_path )
13351353 base_globals ["__file__" ] = file_path
13361354 # Add module attributes used to resolve relative imports
13371355 # instructions inside func.
1338- for k in ["__package__" , "__name__" , "__path__" , "__file__" ]:
1356+ for k in ["__package__" , "__name__" , "__path__" ]:
13391357 if k in func .__globals__ :
13401358 base_globals [k ] = func .__globals__ [k ]
13411359
@@ -1351,15 +1369,16 @@ def _function_getnewargs(self, func):
13511369 def dump (self , obj ):
13521370 try :
13531371 return super ().dump (obj )
1354- except RuntimeError as e :
1355- if len (e .args ) > 0 and "recursion" in e .args [0 ]:
1356- msg = "Could not pickle object as excessively deep recursion required."
1357- raise pickle .PicklingError (msg ) from e
1358- else :
1359- raise
1372+ except RecursionError as e :
1373+ msg = "Could not pickle object as excessively deep recursion required."
1374+ raise pickle .PicklingError (msg ) from e
13601375
13611376 def __init__ (
1362- self , file , protocol = None , buffer_callback = None , config = DEFAULT_CONFIG ):
1377+ self ,
1378+ file ,
1379+ protocol = None ,
1380+ buffer_callback = None ,
1381+ config : CloudPickleConfig = DEFAULT_CONFIG ):
13631382 if protocol is None :
13641383 protocol = DEFAULT_PROTOCOL
13651384 super ().__init__ (file , protocol = protocol , buffer_callback = buffer_callback )
@@ -1572,7 +1591,12 @@ def save_pypy_builtin_func(self, obj):
15721591# Shorthands similar to pickle.dump/pickle.dumps
15731592
15741593
1575- def dump (obj , file , protocol = None , buffer_callback = None , config = DEFAULT_CONFIG ):
1594+ def dump (
1595+ obj ,
1596+ file ,
1597+ protocol = None ,
1598+ buffer_callback = None ,
1599+ config : CloudPickleConfig = DEFAULT_CONFIG ):
15761600 """Serialize obj as bytes streamed into file
15771601
15781602 protocol defaults to cloudpickle.DEFAULT_PROTOCOL which is an alias to
@@ -1590,7 +1614,11 @@ def dump(obj, file, protocol=None, buffer_callback=None, config=DEFAULT_CONFIG):
15901614 config = config ).dump (obj )
15911615
15921616
1593- def dumps (obj , protocol = None , buffer_callback = None , config = DEFAULT_CONFIG ):
1617+ def dumps (
1618+ obj ,
1619+ protocol = None ,
1620+ buffer_callback = None ,
1621+ config : CloudPickleConfig = DEFAULT_CONFIG ):
15941622 """Serialize obj as a string of bytes allocated in memory
15951623
15961624 protocol defaults to cloudpickle.DEFAULT_PROTOCOL which is an alias to
0 commit comments