Skip to content

Commit 32d6bce

Browse files
Enable pickling main by reference option within CloudpickleConfig (#37554)
* Enable pickling main by reference in cloudpickle vendor * Reverted changes to paths not taken for the main by ref * yapf * undo unnecessary move
1 parent 9eb3a18 commit 32d6bce

1 file changed

Lines changed: 14 additions & 9 deletions

File tree

sdks/python/apache_beam/internal/cloudpickle/cloudpickle.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,15 @@ class CloudPickleConfig:
161161
code changes: when a particular lambda function is slightly
162162
modified but the location of the function in the codebase has not
163163
changed, the pickled representation might stay the same.
164+
165+
pickle_main_by_ref: An optional boolean. If provided, cloudpickle will
166+
pickle main by reference instead of by value.
164167
"""
165168
id_generator: typing.Optional[callable] = uuid_generator
166169
skip_reset_dynamic_type_state: bool = False
167170
filepath_interceptor: typing.Optional[callable] = None
168171
get_code_object_params: typing.Optional[GetCodeObjectParams] = None
172+
pickle_main_by_ref: bool = False
169173

170174

171175
DEFAULT_CONFIG = CloudPickleConfig()
@@ -316,7 +320,7 @@ def _whichmodule(obj, name):
316320
return None
317321

318322

319-
def _should_pickle_by_reference(obj, name=None):
323+
def _should_pickle_by_reference(obj, name=None, config=DEFAULT_CONFIG):
320324
"""Test whether an function or a class should be pickled by reference
321325
322326
Pickling by reference means by that the object (typically a function or a
@@ -331,7 +335,7 @@ def _should_pickle_by_reference(obj, name=None):
331335
explicitly registered to be pickled by value.
332336
"""
333337
if isinstance(obj, types.FunctionType) or issubclass(type(obj), type):
334-
module_and_name = _lookup_module_and_qualname(obj, name=name)
338+
module_and_name = _lookup_module_and_qualname(obj, name=name, config=config)
335339
if module_and_name is None:
336340
return False
337341
module, name = module_and_name
@@ -351,7 +355,7 @@ def _should_pickle_by_reference(obj, name=None):
351355
"cannot check importability of {} instances".format(type(obj).__name__))
352356

353357

354-
def _lookup_module_and_qualname(obj, name=None):
358+
def _lookup_module_and_qualname(obj, name=None, config=DEFAULT_CONFIG):
355359
if name is None:
356360
name = getattr(obj, "__qualname__", None)
357361
if name is None: # pragma: no cover
@@ -367,7 +371,7 @@ def _lookup_module_and_qualname(obj, name=None):
367371
# imported module. obj is thus treated as dynamic.
368372
return None
369373

370-
if module_name == "__main__":
374+
if module_name == "__main__" and not config.pickle_main_by_ref:
371375
return None
372376

373377
# Note: if module_name is in sys.modules, the corresponding module is
@@ -718,7 +722,8 @@ def _decompose_typevar(obj, config: CloudPickleConfig):
718722
def _typevar_reduce(obj, config: CloudPickleConfig):
719723
# TypeVar instances require the module information hence why we
720724
# are not using the _should_pickle_by_reference directly
721-
module_and_name = _lookup_module_and_qualname(obj, name=obj.__name__)
725+
module_and_name = _lookup_module_and_qualname(
726+
obj, name=obj.__name__, config=config)
722727

723728
if module_and_name is None:
724729
return (_make_typevar, _decompose_typevar(obj, config))
@@ -1185,7 +1190,7 @@ def _class_reduce(obj, config: CloudPickleConfig):
11851190
return type, (NotImplemented, )
11861191
elif obj in _BUILTIN_TYPE_NAMES:
11871192
return _builtin_type, (_BUILTIN_TYPE_NAMES[obj], )
1188-
elif not _should_pickle_by_reference(obj):
1193+
elif not _should_pickle_by_reference(obj, config=config):
11891194
return _dynamic_class_reduce(obj, config)
11901195
return NotImplemented
11911196

@@ -1410,7 +1415,7 @@ def _function_reduce(self, obj):
14101415
obj using a custom cloudpickle reducer designed specifically to handle
14111416
dynamic functions.
14121417
"""
1413-
if _should_pickle_by_reference(obj):
1418+
if _should_pickle_by_reference(obj, config=self.config):
14141419
return NotImplemented
14151420
elif self.config.get_code_object_params is not None:
14161421
return self._stable_identifier_function_reduce(obj)
@@ -1617,7 +1622,7 @@ def save_global(self, obj, name=None, pack=struct.pack):
16171622

16181623
if name is not None:
16191624
super().save_global(obj, name=name)
1620-
elif not _should_pickle_by_reference(obj, name=name):
1625+
elif not _should_pickle_by_reference(obj, name=name, config=self.config):
16211626
self._save_reduce_pickle5(
16221627
*_dynamic_class_reduce(obj, self.config), obj=obj)
16231628
else:
@@ -1642,7 +1647,7 @@ def save_function(self, obj, name=None):
16421647
Determines what kind of function obj is (e.g. lambda, defined at
16431648
interactive prompt, etc) and handles the pickling appropriately.
16441649
"""
1645-
if _should_pickle_by_reference(obj, name=name):
1650+
if _should_pickle_by_reference(obj, name=name, config=self.config):
16461651
return super().save_global(obj, name=name)
16471652
elif PYPY and isinstance(obj.__code__, builtin_code_type):
16481653
return self.save_pypy_builtin_func(obj)

0 commit comments

Comments
 (0)