pythonpytesttempdir

Deleting py.test tmpdir directory after successful test case


I'm running tests that create a lot of large files during execution. For this purpose I would like to delete the tmpdir directory if a test has passed. But if a test fails the contents of tmpdir should be left unchanged.

I know how to determine the result of the test:

from _pytest.runner import runtestprotocol

def pytest_runtest_protocol(item, nextitem):
    reports = runtestprotocol(item, nextitem=nextitem)
    for report in reports:
        if report.when == 'call':
            # value will be set to passed or filed
            test_outcome = report.outcome
            # But what next?

return True

but I don't know how to find out the path of the created tmpdir directory.


Solution

  • you can retrieve easily your tmpdir from funcargs of your actual item.

    In your case:

    from _pytest.runner import runtestprotocol
    
    def pytest_runtest_protocol(item, nextitem):
        reports = runtestprotocol(item, nextitem=nextitem)
        for report in reports:
            if report.when == 'call':
                # value will be set to passed or filed
                test_outcome = report.outcome
                # depending on test_outcome value, remove tmpdir
                if test_outcome is "OK for you":
                   if 'tmpdir' in item.funcargs:
                      tmpdir = item.funcargs['tmpdir'] #retrieve tmpdir
                      if tmpdir.check(): tmpdir.remove()
    
    return True
    

    For the story, item.funcargs is a dictionary containing {arguments:value} passed to the test item we are currently checking. So the first step is to check that tmpdir is indeed an arg of the actual test, then retrieved it. And finaly check its existence before removing it.

    Hope this will help.

    Edit: it seems like your pytest_runtest_protocol(..) has not still fully initialized the item. To make sure it is..

    Just override the pytest_runtest_teardown(item), it acts on each test item once its run is done (succesfully or failed). Try to add the method like that:

    def pytest_runtest_teardown(item):
       if item.rep_call.passed:
          if 'tmpdir' in item.funcargs:
             tmpdir = item.funcargs['tmpdir'] #retrieve tmpdir
             if tmpdir.check(): tmpdir.remove()
    

    And of couse, dont forget the following (given in the documentation) to have access to your reports easily.

    @pytest.hookimpl(tryfirst=True, hookwrapper=True)
    def pytest_runtest_makereport(item, call,):
        # execute all other hooks to obtain the report object
        outcome = yield
        rep = outcome.get_result()
        # set an report attribute for each phase of a call, which can
        # be "setup", "call", "teardown"
        setattr(item, "rep_" + rep.when, rep)