nose-devs / nose

nose is nicer testing for python
http://readthedocs.org/docs/nose/en/latest/
1.36k stars 395 forks source link

`nose.plugins.xunit.Tee` doesn't fully implement `io.IOBase`; triggers issues with items that expect full `io.IOBase` compatibility #1097

Open ngie-eign opened 5 years ago

ngie-eign commented 5 years ago

Using the XUnit plugin triggers failures with items that expect sys.stdout and sys.stderr to be File-like objects that implement the full io.IOBase spec. For example, .closed is used in the atexit handler for the logging module and will result in these tracebacks:

Error in sys.exitfunc:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/atexit.py", line 24, in _run_exitfuncs
    func(*targs, **kargs)
  File "/usr/local/lib/python2.7/logging/__init__.py", line 1675, in shutdown
    h.flush()
  File "/usr/local/lib/python2.7/logging/__init__.py", line 851, in flush
    if self.stream and hasattr(self.stream, "flush") and not self.stream.closed:
AttributeError: 'Tee' object has no attribute 'closed'

Line 851 is the line of affected code:

    827 class StreamHandler(Handler):
    828     """
    829     A handler class which writes logging records, appropriately formatted,
    830     to a stream. Note that this class does not close the stream, as
    831     sys.stdout or sys.stderr may be used.
    832     """
    833
    834     def __init__(self, stream=None):
    835         """
    836         Initialize the handler.
    837
    838         If stream is not specified, sys.stderr is used.
    839         """
    840         Handler.__init__(self)
    841         if stream is None:
    842             stream = sys.stderr
    843         self.stream = stream
    844
    845     def flush(self):
    846         """
    847         Flushes the stream.
    848         """
    849         self.acquire()
    850         try:
    851             if self.stream and hasattr(self.stream, "flush") and not self.stream.closed:
    852                 self.stream.flush()
    853         finally:
    854             self.release()

More information:

# nosetests -V
nosetests version 1.3.7
# python -V
Python 2.7.16

This doesn't need to be fixed in this version of nose, but in the event that the pattern was propagated on to a later version, it will need to be fixed properly.

I'll submit a patch for this soon.