diff --git a/src/taskgraph/util/attributes.py b/src/taskgraph/util/attributes.py index 74d69966..0d44be45 100644 --- a/src/taskgraph/util/attributes.py +++ b/src/taskgraph/util/attributes.py @@ -16,8 +16,10 @@ def attrmatch(attributes, **kwargs): * Given a set or list, the attribute value must be contained within it. * A callable is called with the attribute value and returns a boolean. - If an attribute is specified as a keyword argument but not present in the - task's attributes, the result is False. + Attributes that are not defined in a task are considered to have a value of + None. Therefore to match tasks that *don't* have an attribute, you can use: + + { "attr_name": None } Args: attributes (dict): The task's attributes object. @@ -27,16 +29,14 @@ def attrmatch(attributes, **kwargs): bool: Whether the task's attributes match the conditions or not. """ for kwkey, kwval in kwargs.items(): - if kwkey not in attributes: - return False - attval = attributes[kwkey] + attval = attributes.get(kwkey) if isinstance(kwval, (set, list)): if attval not in kwval: return False elif callable(kwval): if not kwval(attval): return False - elif kwval != attributes[kwkey]: + elif kwval != attval: return False return True diff --git a/test/test_util_attributes.py b/test/test_util_attributes.py index a8687f06..fc2afbbc 100644 --- a/test/test_util_attributes.py +++ b/test/test_util_attributes.py @@ -18,8 +18,13 @@ def test_trivial_match(self): self.assertTrue(attrmatch({})) def test_missing_attribute(self): - """If a filtering attribute is not present, no match""" - self.assertFalse(attrmatch({}, someattr=10)) + """If a filtering attribute is not present, no match unless it is + None""" + self.assertFalse(attrmatch({"a": 1}, a=1, b=2)) + self.assertTrue(attrmatch({"a": 1}, a=1, b=None)) + self.assertTrue(attrmatch({"a": 1, "b": None}, a=1, b=None)) + self.assertTrue(attrmatch({"a": 1}, a=1, b=[None, 2])) + self.assertTrue(attrmatch({"a": 1, "b": 2}, a=1, b=[None, 2])) def test_literal_attribute(self): """Literal attributes must match exactly"""