classification
Title: unittest.TextTestResult.__init__ does not pass on its init arguments in super call
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.2, Python 3.3, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: michael.foord Nosy List: branker, michael.foord, python-dev, r.david.murray, rhettinger, terry.reedy
Priority: normal Keywords:

Created on 2011-06-20 17:39 by branker, last changed 2012-09-28 13:22 by michael.foord. This issue is now closed.

Files
File name Uploaded Description Edit
breakunit.py branker, 2011-06-20 17:39 reproduce example
Messages (7)
msg138744 - (view) Author: Ben Ranker (branker) Date: 2011-06-20 17:39
TextTestResult.__init__(...) calls super(TextTestResult, self).__init__() with no args. If a custom TextTestResult descendant has a complex inheritance hierarchy that puts another class between TextTestResult and TestResult in the __mro__, then that class doesn't receive the common stream, descriptions, and verbosity args. If it needs them to function then the __init__ chain explodes.

See attached breakunit.py for an example of this.
msg139007 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2011-06-25 00:22
Running your code with 2.7.2 gives:
Traceback (most recent call last):
  File "C:\Programs\Python27\misc\tem.py", line 41, in <module>
    unittest.main(testRunner=runner)
  File "C:\Programs\Python27\lib\unittest\main.py", line 95, in __init__
    self.runTests()
  File "C:\Programs\Python27\lib\unittest\main.py", line 229, in runTests
    self.result = testRunner.run(self.test)
  File "C:\Programs\Python27\lib\unittest\runner.py", line 142, in run
    result = self._makeResult()
  File "C:\Programs\Python27\lib\unittest\runner.py", line 138, in _makeResult
    return self.resultclass(self.stream, self.descriptions, self.verbosity)
  File "C:\Programs\Python27\lib\unittest\runner.py", line 37, in __init__
    super(TextTestResult, self).__init__()
TypeError: __init__() takes exactly 4 arguments (1 given)

Nothing 'explodes', just a normal exception due to what I believe is a programming error on your part that has nothing to do with unittest. The doc for super says
"The second use case is to support cooperative multiple inheritance in a dynamic execution environment. This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance. This makes it possible to implement “diamond diagrams” where multiple base classes implement the same method. Good design dictates that this method have the same calling signature in every case (because the order of calls is determined at runtime, because that order adapts to changes in the class hierarchy, and because that order can include sibling classes that are unknown prior to runtime).""

The various __init__ methods, as you know, have different and incompatible calling signatures, hence the exception. I believe this should be closed as invalid. Raymond, as super expert, do I have this right?
msg139138 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2011-06-26 02:15
I think we'll have to wait for Micheal to double check, but it looks to me like there is a bug in unittest.TextTestResult.  TestResult's init expects the three arguments the OP is talking about, but defaults them to None.  TextTestResult accepts those three arguments in its init with no defaults, but does not pass them to the base class in the super call.  If this is intentional, I would say that it needs to be documented, since it is not obvious why it would be done that way, since it does, in fact, break the "cooperating classes" model required to use super correctly.

(As an aside, I was quite surprised to find TextTestResult in the runner.py file rather than the result.py file within the unittest package.)
msg139255 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2011-06-27 10:16
I have a feeling I added the arguments to TestResult.__init__ to allow it to be used as a silent test result directly in place of TextTestResult. I still need to check this. 

Not adding the arguments to the super call in TextTestResult would have been an oversight. Let me check this understanding is correct, and if there is no reason for it not to pass on those arguments I'll fix it.
msg139324 - (view) Author: Ben Ranker (branker) Date: 2011-06-27 18:47
Sorry for any confusion caused by my imprecise use of the word "explodes."
msg171455 - (view) Author: Roundup Robot (python-dev) Date: 2012-09-28 13:14
New changeset 0362d64c783a by Michael Foord in branch '3.2':
Closes issue #12376 : Pass on parameters in unittest.TextTestResult.__init__ super call
http://hg.python.org/cpython/rev/0362d64c783a
msg171456 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2012-09-28 13:22
Fixed in 2.7, 3.2 and 3.3.1.
History
Date User Action Args
2012-09-28 13:22:12michael.foordsetstatus: open -> closed
resolution: fixed
messages: + msg171456

stage: resolved
2012-09-28 13:14:18python-devsetnosy: + python-dev
messages: + msg171455
2011-06-27 18:47:40brankersetmessages: + msg139324
2011-06-27 10:16:38michael.foordsetassignee: michael.foord
2011-06-27 10:16:23michael.foordsetmessages: + msg139255
2011-06-26 02:25:48r.david.murraysettitle: unittest.TextTestResult.__init__ breaks under complex __mro__ -> unittest.TextTestResult.__init__ does not pass on its init arguments in super call
versions: + Python 3.2, Python 3.3
2011-06-26 02:15:52r.david.murraysetnosy: + r.david.murray
messages: + msg139138
2011-06-25 00:22:49terry.reedysetnosy: + rhettinger, terry.reedy
messages: + msg139007
2011-06-20 17:50:14r.david.murraysetnosy: + michael.foord
2011-06-20 17:39:14brankercreate