Search code examples
pythonpython-unittestassert

TypeError: 'list' object is not callable - assertWarns()


I have the following function:

def checking_remote_local_groups(data: List[dict], groups: List[dict]) -> List[dict]:
    step = 'GET_GROUPS_TO_CHECK'
    groups_to_check = []
    local_groups = [x['group'] for x in data]

    # Using set to get differences between local and AAD groups
    local_groups_set = set(local_groups)
   
    groups_set = set(x['name'] for x in groups)
    # If local AAD groups set are not in AAD groups, raise an Error on the workflow.
    if local_groups_set - groups_set:
        # SyncException is implemented somewhere.
        raise SyncException(
            f'{local_groups_set - groups_set} local group is not an AAD group\nCreate it via speckle-infra terraform',
            "We need to get in line, local and AAD groups. Additional {} group received from users.yaml".format(
                local_groups_set - groups_set
            ),
            step
        )
    # If remote groups set are not in local groups 
    if groups_set - local_groups_set:
        # Just notify it to the user
        warnings.warn(
            f"""
            {groups_set - local_groups_set} AAD group is not on users.yml as a local group
            Please add it if needed
            """
            )
    # If remote groups are the same than local groups
    elif local_groups_set == groups_set:
        print("AAD and local groups are inline"
            )
    return groups_to_check

I want to check the behavior of the second if section code (If remote groups set are not in local groups) by doing unittests using the assertWarns assertion, since I am triggering a warning in that case. So I have:

class MyTestCase(unittest.TestCase):

    def test_warning_checking_remote_group_not_in_local_groups(self):
        # local groups
        data = [{'group': 'foobar'}, {'group': 'test'}]
        
        # remote groups
        groups = [{'name': 'foobar'}, {'name': 'test'}, {'name': 'missing'}]
        self.assertWarns(
            UserWarning,
            checking_aad_local_groups(data, groups),
            [{"name": "missing"}]
        )

I got this output:

test_sync.py .F...........                                               [100%]

=================================== FAILURES ===================================
______ GroupsTestCase.test_warning_checking_aad_group_not_in_local_groups ______

self = <test_sync.GroupsTestCase testMethod=test_warning_checking_remote_group_not_in_local_groups>

    def test_warning_checking_remote_group_not_in_local_groups(self):
        data = [{'group': 'foobar'}, {'group': 'test'}]
        groups = [{'name': 'foobar'}, {'name': 'test'}, {'name': 'missing'}]
>       self.assertWarns(
            UserWarning,
            checking_aad_local_groups(data, groups),
            [{"name": "missing"}]
        )
E       TypeError: 'list' object is not callable

test_sync.py:158: TypeError
=============================== warnings summary ===============================
test_sync.py::GroupsTestCase::test_warning_checking_aad_group_not_in_local_groups
  /home/runner/work/speckle-user-management/speckle-user-management/groups.py:31: UserWarning: 
              *********************** WARNING ... ***********************
              {'missing'} AAD group is not on users.yml as a local group
              Please add it if needed
              *********************** WARNING ... ***********************
              
    warnings.warn(

-- Docs: docs.pytest.org/en/latest/warnings.html
=========================== short test summary info ============================
FAILED test_sync.py::GroupsTestCase::test_warning_checking_remote_group_not_in_local_groups

I understand probably the list of dictionaries I am sending as a parameters are not accepted or are not available for the types of data assertWarns() expect?

Despite that, the message I expected ({'missing'} AAD group is not on users.yml as a local group, Please add it if needed) is shown, but I expect from this test pass.

What is the best way to use assertWarns().

If I use assertFalse, the test pass, although I am not sure if is the most specific/better assert I can use.


Solution

  • When you call assertWarns(UserWarning, checking_aad_local_groups(...)) then you are calling checking_aad_local_groups and passing the result to assertWarns. You want to give assertWarns a callable so that it can wrap it in the warning detection code.

    self.assertWarns(UserWarning, checking_aad_local_groups, (data, groups))
    

    Alternatively, you can use it as a context manager

    with self.assertWarns() as w:
       checking_aad_local_groups(data, groups)