This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: unittest module cleanup functions not run unless tearDownModule() is defined
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: ezio.melotti, lukasz.langa, michael.foord, miguendes, miss-islington, python-dev, rbcollins, rtarpine, serhiy.storchaka, terry.reedy
Priority: normal Keywords: patch

Created on 2021-04-22 17:30 by rtarpine, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 25700 closed python-dev, 2021-04-28 22:19
PR 28006 merged serhiy.storchaka, 2021-08-27 20:46
PR 28070 merged miss-islington, 2021-08-30 16:26
PR 28071 merged serhiy.storchaka, 2021-08-30 16:32
Messages (12)
msg391619 - (view) Author: Ryan Tarpine (rtarpine) Date: 2021-04-22 17:30
Functions registered with unittest.addModuleCleanup are not called unless the user defines tearDownModule in their test module.

This behavior is unexpected because functions registered with TestCase.addClassCleanup are called even the user doesn't define tearDownClass, and similarly with addCleanup/tearDown.

The implementing code is basically the same for all 3 cases, the difference is that unittest.TestCase itself defines tearDown and tearDownClass; so even though doClassCleanups is only called if tearDownClass is defined, in practice it always is.

doModuleCleanups should be called even if tearDownModule is not defined.
msg391800 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2021-04-24 20:34
import unittest

#def setUpModule(): raise Exception()
#def tearDownModule(): print('module teardown')

unittest.addModuleCleanup(print, 'module cleanup')

class Dummy(unittest.TestCase):
    def test_dummy(self):
        self.addCleanup(print, 'test cleanup')
        self.addClassCleanup(print, 'class cleanup')

unittest.main()
----------------------------------------------
Above verifies the claim in 3.10.0a7.   Only 'test cleanup' and 'class cleanup' print. Uncomment either function and 'module cleanup' is also printed.

https://docs.python.org/3/library/unittest.html#unittest.addModuleCleanu
"""
unittest.addModuleCleanup(function, /, *args, **kwargs)

    Add a function to be called after tearDownModule() to cleanup resources used during the test class. Functions will be called in reverse order to the order they are added (LIFO). They are called with any arguments and keyword arguments passed into addModuleCleanup() when they are added.

    If setUpModule() fails, meaning that tearDownModule() is not called, then any cleanup functions added will still be called.
"""
This seems slightly ambiguous as to behavior when no tearDownModule.  However, the doc for addClassCleanup is exactly parallel.

https://docs.python.org/3/library/unittest.html#unittest.TestCase.addClassCleanup
"""
classmethod addClassCleanup(function, /, *args, **kwargs)

    Add a function to be called after tearDownClass() to cleanup resources used during the test class. Functions will be called in reverse order to the order they are added (LIFO). They are called with any arguments and keyword arguments passed into addClassCleanup() when they are added.

    If setUpClass() fails, meaning that tearDownClass() is not called, then any cleanup functions added will still be called.
"""

The doc for addCleanup is also parallel.  The behavior difference therefore seems like a bug and calling in any case seems more correct.

Ryan, can you prepare a PR?
msg392268 - (view) Author: Miguel Brito (miguendes) * Date: 2021-04-28 23:23
Hello, first time here. I created an PR for that. Managed to reproduce the issue both manually and via unit test.

I hope there's no edge case but all tests pass on my machine.
msg392580 - (view) Author: Miguel Brito (miguendes) * Date: 2021-05-01 09:59
I was reading through the dev guide and past issues and I didn't know it's advisable to give the author of the issue a chance to submit the PR.

Sorry about that, you can close mine in this case.
msg392590 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2021-05-01 12:42
No apology needed.  I don't know what has been added to the devguide, but most OPs never submit a PR unless they either do so or say they will when opening an issue.  In any case, a week is more than a chance.
msg392773 - (view) Author: Miguel Brito (miguendes) * Date: 2021-05-03 07:27
Thanks terry.reedy, actually I read it in the mailing list, someones comment not a guideline.

Do you mind having a look at the PR?
msg400090 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2021-08-22 18:36
Functions registered with TestCase.addClassCleanup are called because TestCase has default implementation of tearDownClass. But you can suppress it by setting tearDownClass = None. So there is a similar issue with class cleanup functions.
msg400442 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2021-08-27 20:28
There are several other bugs in the code for cleaning up classes and modules:

* Functions registered with addClassCleanup() are not called if tearDownClass is set to None or its look up raises AttributeError.
* Buffering in TestResult blows up when functions registered with addClassCleanup() and addModuleCleanup() produce raise exceptions.
* Buffering in TestResult does not buffer output of functions registered with addClassCleanup() and addModuleCleanup().
* TestSuite.debug() blows up if functions registered with addClassCleanup() and addModuleCleanup() raise exceptions.
* Errors in setUpModule() and function registered with addModuleCleanup() are reported in wrong order.

And several lesser bugs.
msg400633 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2021-08-30 16:26
New changeset 08d9e597c8ef5a2b26375ac954fdf224f5d82c3c by Serhiy Storchaka in branch 'main':
bpo-43913: Fix bugs in cleaning up classes and modules in unittest. (GH-28006)
https://github.com/python/cpython/commit/08d9e597c8ef5a2b26375ac954fdf224f5d82c3c
msg400637 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2021-08-30 17:22
New changeset 9827710a400848c9430ed364ed5d2d54f0926701 by Serhiy Storchaka in branch '3.9':
[3.9] bpo-43913: Fix bugs in cleaning up classes and modules in unittest. (GH-28006) (GH-28071)
https://github.com/python/cpython/commit/9827710a400848c9430ed364ed5d2d54f0926701
msg400641 - (view) Author: miss-islington (miss-islington) Date: 2021-08-30 17:38
New changeset d65fad04fad1a73b6bb17bcb08ca6f0a24376952 by Miss Islington (bot) in branch '3.10':
bpo-43913: Fix bugs in cleaning up classes and modules in unittest. (GH-28006)
https://github.com/python/cpython/commit/d65fad04fad1a73b6bb17bcb08ca6f0a24376952
msg400644 - (view) Author: Łukasz Langa (lukasz.langa) * (Python committer) Date: 2021-08-30 18:02
Thanks for the fix, Serhiy, and Ryan for reporting the problem! ✨ 🍰 ✨
History
Date User Action Args
2022-04-11 14:59:44adminsetgithub: 88079
2021-08-30 18:02:06lukasz.langasetstatus: open -> closed
resolution: fixed
messages: + msg400644

stage: patch review -> resolved
2021-08-30 17:38:42miss-islingtonsetmessages: + msg400641
2021-08-30 17:22:29lukasz.langasetmessages: + msg400637
2021-08-30 16:32:02serhiy.storchakasetpull_requests: + pull_request26515
2021-08-30 16:26:08miss-islingtonsetnosy: + miss-islington
pull_requests: + pull_request26514
2021-08-30 16:26:07lukasz.langasetnosy: + lukasz.langa
messages: + msg400633
2021-08-27 20:46:55serhiy.storchakasetpull_requests: + pull_request26448
2021-08-27 20:28:09serhiy.storchakasetmessages: + msg400442
2021-08-22 18:36:52serhiy.storchakasetversions: + Python 3.11, - Python 3.8
2021-08-22 18:36:37serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg400090
2021-05-03 07:27:00miguendessetmessages: + msg392773
2021-05-01 12:42:11terry.reedysetmessages: + msg392590
2021-05-01 09:59:31miguendessetmessages: + msg392580
2021-04-28 23:23:25miguendessetnosy: + miguendes
messages: + msg392268
2021-04-28 22:19:40python-devsetkeywords: + patch
nosy: + python-dev

pull_requests: + pull_request24390
stage: needs patch -> patch review
2021-04-24 20:34:45terry.reedysetstage: needs patch
versions: + Python 3.9, Python 3.10
2021-04-24 20:34:29terry.reedysetnosy: + ezio.melotti, terry.reedy, michael.foord, rbcollins
messages: + msg391800
2021-04-22 17:30:03rtarpinecreate