From 9bfeea83b30903c94602606ea9a6ec6394dbfdc3 Mon Sep 17 00:00:00 2001 From: OpenHTF Owners Date: Wed, 12 Aug 2026 17:29:04 -0700 Subject: [PATCH] Prevent calling as_base_types on class objects in openhtf.util.data. Update openhtf.util.data to check that an object is not a class before calling its as_base_types method. This ensures that class objects themselves are converted to their string representations instead of attempting to call the method on the class. Also add corresponding unit tests. PiperOrigin-RevId: 963749692 --- openhtf/util/data.py | 2 +- test/util/data_test.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/openhtf/util/data.py b/openhtf/util/data.py index 3809eaf1f..b1e4124cd 100644 --- a/openhtf/util/data.py +++ b/openhtf/util/data.py @@ -163,7 +163,7 @@ def convert_to_base_types(obj, # Because it's *really* annoying to pass a single string accidentally. assert not isinstance(ignore_keys, str), 'Pass a real iterable!' - if hasattr(obj, 'as_base_types'): + if hasattr(obj, 'as_base_types') and not inspect.isclass(obj): return obj.as_base_types() if hasattr(obj, '_asdict') and not inspect.isclass(obj): obj = obj._asdict() diff --git a/test/util/data_test.py b/test/util/data_test.py index 0e9a53e04..6e9a3db88 100644 --- a/test/util/data_test.py +++ b/test/util/data_test.py @@ -46,6 +46,11 @@ def __init__(self): def as_base_types(self): return self.value + class ClassWithAsBaseTypes(object): + + def as_base_types(self): + return 'called on instance' + @attr.s(slots=True, frozen=True) class FrozenAttr(object): value = attr.ib(type=int) @@ -72,7 +77,8 @@ class EnumClass(enum.Enum): 'special': SpecialBaseTypes('must_not_be_present'), 'not_copied': not_copied, 'enum': EnumClass.A, - + 'class_with_as_base_types_instance': ClassWithAsBaseTypes(), + 'class_with_as_base_types_class': ClassWithAsBaseTypes, # Some plugs such as UserInputPlug will return None as a response to # AsDict(). 'none_dict': AsDict(), @@ -99,6 +105,12 @@ class StrEnumClass(enum.StrEnum): self.assertIsInstance(converted['special'], dict) self.assertEqual(converted['special'], {'safe_value': True}) self.assertIs(converted['not_copied'], not_copied.value) + self.assertEqual( + converted['class_with_as_base_types_instance'], 'called on instance' + ) + self.assertEqual( + converted['class_with_as_base_types_class'], str(ClassWithAsBaseTypes) + ) self.assertIsNone(converted['none_dict'])