manrajgrover / halo

💫 Beautiful spinners for terminal, IPython and Jupyter
MIT License
2.86k stars 148 forks source link

Bug: "Error in atexit._run_exitfuncs" when running unit tests #97

Closed tterb closed 5 years ago

tterb commented 5 years ago

Description

I'm using the package within a download function like so:

def download(url):
  spinner = Halo(text='Downloading', spinner='dots12')
  spinner.start()
  (...)
  spinner.succeed('Download Complete')
  spinner.stop()

While, the package works as expected when running the program, when running unit test with pytest the test output is followed by the error message pasted below.

System settings

Error

Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/halo/halo.py", line 78, in clean_up
    self.stop()
  File "/usr/local/lib/python3.7/site-packages/halo/halo.py", line 419, in stop
    self.clear()
  File "/usr/local/lib/python3.7/site-packages/halo/halo.py", line 311, in clear
    self._stream.write('\r')
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 40, in write
    self.__convertor.write(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 141, in write
    self.write_and_convert(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 169, in write_and_convert
    self.write_plain_text(text, cursor, len(text))
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 174, in write_plain_text
    self.wrapped.write(text[start:end])
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 40, in write
    self.__convertor.write(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 141, in write
    self.write_and_convert(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 169, in write_and_convert
    self.write_plain_text(text, cursor, len(text))
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 174, in write_plain_text
    self.wrapped.write(text[start:end])
  File "/usr/local/lib/python3.7/site-packages/_pytest/capture.py", line 358, in write
    self.buffer.write(obj)
ValueError: I/O operation on closed file
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/halo/halo.py", line 78, in clean_up
    self.stop()
  File "/usr/local/lib/python3.7/site-packages/halo/halo.py", line 419, in stop
    self.clear()
  File "/usr/local/lib/python3.7/site-packages/halo/halo.py", line 311, in clear
    self._stream.write('\r')
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 40, in write
    self.__convertor.write(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 141, in write
    self.write_and_convert(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 169, in write_and_convert
    self.write_plain_text(text, cursor, len(text))
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 174, in write_plain_text
    self.wrapped.write(text[start:end])
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 40, in write
    self.__convertor.write(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 141, in write
    self.write_and_convert(text)
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 169, in write_and_convert
    self.write_plain_text(text, cursor, len(text))
  File "/usr/local/lib/python3.7/site-packages/colorama/ansitowin32.py", line 174, in write_plain_text
    self.wrapped.write(text[start:end])
  File "/usr/local/lib/python3.7/site-packages/_pytest/capture.py", line 358, in write
    self.buffer.write(obj)
ValueError: I/O operation on closed file

Expected behaviour

I wouldn't expect the package to have any impact on these tests that isn't present when running the program.

Steps to recreate

People to notify

manrajgrover commented 5 years ago

@tterb Thanks for reporting. I'll check if I can reproduce this issue on my end and get back to you on this.

tterb commented 5 years ago

@manrajgrover Okay, let me know if more info is needed

manrajgrover commented 5 years ago

@tterb I would need more information here. Could you please create a sample code to reproduce this issue? I tried doing it but couldn't.

theY4Kman commented 5 years ago

Presuming halo runs some cleanup using an atexit func, this sounds more to me like halo writing to what it thinks is sys.stdout, but was really pytest's caplog — which presumably is a StringIO long-since closed by the time halo cleans up.

theY4Kman commented 5 years ago

Here ya go (just hit run): https://repl.it/repls/SorrowfulNaturalDisassembler

manrajgrover commented 5 years ago

@theY4Kman Yes, we do have a clean up function that runs atexit since we would like to stop the thread if it is running and clean up the stream. But since the stream is closed, we should check if the stream is closed before writing anything to it. Is there a better solution?

theY4Kman commented 5 years ago

"Better" in what sense? If the intent of the atexit handler is to cleanup something, and it's already cleaned up, is there anything else to do?