Skip to content

Commit a118353

Browse files
committed
Cache unbound process fn per review feedback
1 parent 3cb42b1 commit a118353

1 file changed

Lines changed: 17 additions & 5 deletions

File tree

sdks/python/apache_beam/typehints/typecheck.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,24 @@ class RuntimeTypeCheckWrapperDoFn(AbstractDoFnWrapper):
100100
def __init__(self, dofn, type_hints, full_label):
101101
super().__init__(dofn)
102102
self.full_label = full_label
103-
# Note that the bound process method must not be cached on the instance:
103+
# Note that a *bound* process method must not be cached on the instance:
104104
# an attribute holding a bound method is visible to the stateful DoFn
105105
# reflection in userstate.get_dofn_specs, and a cached copy can diverge
106106
# from self.dofn.process across (de)serialization, in which case stateful
107-
# DoFn validation would see duplicate StateSpecs/TimerSpecs.
107+
# DoFn validation would see duplicate StateSpecs/TimerSpecs. Caching the
108+
# underlying (unbound) function is safe: plain functions stored on an
109+
# instance are not bound methods, so DoFn reflection ignores them.
110+
process_fn = dofn._process_argspec_fn()
111+
if hasattr(process_fn, '__func__'):
112+
self._process_fn = process_fn.__func__
113+
self._process_fn_needs_self = True
114+
else:
115+
self._process_fn = process_fn
116+
self._process_fn_needs_self = False
108117
if type_hints.input_types:
109118
input_args, input_kwargs = type_hints.input_types
110119
self._input_hints = getcallargs_forhints(
111-
dofn._process_argspec_fn(), *input_args, **input_kwargs)
120+
process_fn, *input_args, **input_kwargs)
112121
else:
113122
self._input_hints = None
114123
# TODO(robertwb): Multi-output.
@@ -125,8 +134,11 @@ def wrapper(self, method, args, kwargs):
125134
def process(self, *args, **kwargs):
126135
try:
127136
if self._input_hints:
128-
actual_inputs = inspect.getcallargs(
129-
self.dofn._process_argspec_fn(), *args, **kwargs) # pylint: disable=deprecated-method
137+
if self._process_fn_needs_self:
138+
actual_inputs = inspect.getcallargs(
139+
self._process_fn, self.dofn, *args, **kwargs) # pylint: disable=deprecated-method
140+
else:
141+
actual_inputs = inspect.getcallargs(self._process_fn, *args, **kwargs) # pylint: disable=deprecated-method
130142
for var, hint in self._input_hints.items():
131143
if hint is actual_inputs[var]:
132144
# self parameter

0 commit comments

Comments
 (0)