diff --git a/reframe/utility/__init__.py b/reframe/utility/__init__.py index 824d0e1092..62c5352a4e 100644 --- a/reframe/utility/__init__.py +++ b/reframe/utility/__init__.py @@ -275,7 +275,9 @@ def repr(obj, htchar=' ', lfchar='\n', indent=4, basic_offset=0): def attrs(obj): '''Inspect object and return its attributes and their values. - This function returns also any descriptors found at the owner class. + This function returns also any descriptors found at the owner class, + with the exception of descriptors without an assigned value, which are + expected to raise an ``AttributeError``. :arg obj: The object to inspect. :returns: an iterator over ``(attr_name, value)`` tuples @@ -287,9 +289,13 @@ def attrs(obj): # Look for descriptors for cls in type(obj).mro(): - for attr, value in cls.__dict__.items(): - if inspect.isdatadescriptor(value): - ret[attr] = getattr(obj, attr) + for attr in cls.__dict__: + if inspect.isdatadescriptor(cls.__dict__[attr]): + try: + ret[attr] = getattr(obj, attr) + except AttributeError: + # Pass if the descriptor does not have an assigned value + pass return ret diff --git a/unittests/test_utility.py b/unittests/test_utility.py index 0524b7aea6..86388d1d3f 100644 --- a/unittests/test_utility.py +++ b/unittests/test_utility.py @@ -658,9 +658,14 @@ def test_repr_default(): def test_attrs(): - class C: + class B: z = fields.TypedField(int) + def __init__(self, x, y): + self.x = x + self.y = y + + class C(B): def __init__(self, x, y): self._x = x self.y = y @@ -676,6 +681,13 @@ def x(self): class D(C): pass + # Test undefined descriptors are not returned + b = B(-1, 0) + b_attrs = util.attrs(b) + assert b_attrs['x'] == -1 + assert b_attrs['y'] == 0 + assert 'z' not in b_attrs + c = C(1, 2) c_attrs = util.attrs(c) assert c_attrs['x'] == 1