diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index 6d7a4d9cfc286..fdae3c0efea7c 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -1268,6 +1268,27 @@ def testReturningType(self, message_module): self.assertEqual(bool, type(m.repeated_bool[0])) self.assertEqual(True, m.repeated_bool[0]) + def testDir(self, message_module): + m = message_module.TestAllTypes() + attributes = dir(m) + self.assertGreaterEqual(len(attributes), 55) + self.assertIn('DESCRIPTOR', attributes) + + class_attributes = dir(type(m)) + attribute_set = set(attributes) + for attr in class_attributes: + if attr != 'Extensions': + self.assertIn(attr, attribute_set) + + def testAllAttributeFromDirAccessible(self, message_module): + m = message_module.TestAllTypes() + attributes = dir(m) + for attribute in attributes: + try: + getattr(m, attribute) + except AttributeError: + self.fail(f'Attribute {attribute} is not accessible.') + def testEquality(self, message_module): m = message_module.TestAllTypes() m2 = message_module.TestAllTypes() diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py index ae9cb147e326f..0eed00eed0c49 100755 --- a/python/google/protobuf/message.py +++ b/python/google/protobuf/message.py @@ -13,6 +13,9 @@ __author__ = 'robinson@google.com (Will Robinson)' +_INCONSISTENT_MESSAGE_ATTRIBUTES = ('Extensions',) + + class Error(Exception): """Base error type for this module.""" pass @@ -56,6 +59,20 @@ def __deepcopy__(self, memo=None): clone.MergeFrom(self) return clone + def __dir__(self): + """Filters out attributes that would raise AttributeError if accessed.""" + missing_attributes = set() + for attribute in _INCONSISTENT_MESSAGE_ATTRIBUTES: + try: + getattr(self, attribute) + except AttributeError: + missing_attributes.add(attribute) + return [ + attribute + for attribute in super().__dir__() + if attribute not in missing_attributes + ] + def __eq__(self, other_msg): """Recursively compares two messages by value and structure.""" raise NotImplementedError