Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion sdks/python/apache_beam/internal/code_object_pickler.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,13 @@ def _search_module_or_class(
rest = qual_name_parts[1:]
if first_part == '<lambda>':
for name in dir(node):
value = getattr(node, name)
try:
value = getattr(node, name)
except Exception: # pylint: disable=broad-except
# Unrelated attributes (e.g. descriptors that only work on instances,
# or lazy module attributes with missing dependencies) can raise when
# read. They can't be the lambda we are looking for, so skip them.
continue
if (hasattr(callable, '__code__') and
isinstance(value, type(callable)) and
value.__code__ == callable.__code__):
Expand Down
23 changes: 23 additions & 0 deletions sdks/python/apache_beam/internal/code_object_pickler_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ def process(self):
return lambda: 1


class _InstanceOnlyDescriptor:
def __get__(self, instance, owner=None):
if instance is None:
raise TypeError("only valid on instances")
return 1


class ClassWithLambdaAndRaisingAttribute:
# Sorts before `fn` in dir(), so it is read first during the lambda search.
a_setting = _InstanceOnlyDescriptor()
fn = lambda self, x: x + 1


class ClassWithNestedClass:
class InnerClass:
def process(self):
Expand Down Expand Up @@ -247,6 +260,16 @@ def test_invalid_lambda_with_hash_path_raises_exception(self):
"apache_beam.internal.test_data.module_3."
"my_function.__code__.co_consts[<lambda>, ('',), 1234567890]")

def test_lambda_search_skips_attributes_that_raise(self):
fn = ClassWithLambdaAndRaisingAttribute.fn
path = code_object_pickler.get_code_object_identifier(fn)
self.assertEqual(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low: Since ClassWithLambdaAndRaisingAttribute is defined in this test module, fn.__module__ will be '__main__' if the test file is executed directly via python code_object_pickler_test.py. Using f"{prefix}." (defined at line 141 as prefix = __name__) keeps this consistent with test_cases above.

Suggested change
self.assertEqual(
f"{prefix}."

path,
"apache_beam.internal.code_object_pickler_test."
"ClassWithLambdaAndRaisingAttribute.fn.__code__")
self.assertEqual(
code_object_pickler.get_code_from_identifier(path), fn.__code__)

def test_adding_local_variable_in_class_preserves_object(self):
self.assertEqual(
code_object_pickler.get_code_from_identifier(
Expand Down
Loading