STINNER Victor <vstin...@python.org> added the comment:
On Fedora Rawhide x64-64, I can reproduce the test_ftplib test_makeport() issue in reliable way. On Python 3.9, the test also logs the exception but the test is marked as a success: --- $ ./python -m test -u all test_ftplib -v -m test_makeport (...) test_makeport (test.test_ftplib.TestFTPClass) ... ok test_makeport (test.test_ftplib.TestIPv6Environment) ... ok test_makeport (test.test_ftplib.TestTLS_FTPClassMixin) ... Exception in thread Thread-3: Traceback (most recent call last): File "/home/vstinner/python/3.9/Lib/asyncore.py", line 83, in read obj.handle_read_event() File "/home/vstinner/python/3.9/Lib/test/test_ftplib.py", line 377, in handle_read_event self._do_ssl_handshake() File "/home/vstinner/python/3.9/Lib/test/test_ftplib.py", line 338, in _do_ssl_handshake self.socket.do_handshake() File "/home/vstinner/python/3.9/Lib/ssl.py", line 1309, in do_handshake self._sslobj.do_handshake() ssl.SSLZeroReturnError: TLS/SSL connection has been closed (EOF) (_ssl.c:1129) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/vstinner/python/3.9/Lib/threading.py", line 973, in _bootstrap_inner self.run() File "/home/vstinner/python/3.9/Lib/test/test_ftplib.py", line 291, in run asyncore.loop(timeout=0.1, count=1) File "/home/vstinner/python/3.9/Lib/asyncore.py", line 207, in loop poll_fun(timeout, map) File "/home/vstinner/python/3.9/Lib/asyncore.py", line 150, in poll read(obj) File "/home/vstinner/python/3.9/Lib/asyncore.py", line 87, in read obj.handle_error() File "/home/vstinner/python/3.9/Lib/test/test_ftplib.py", line 414, in handle_error raise Exception Exception ok (...) Tests result: SUCCESS --- make buildbottest uses -W option which hides the test output unless the test failed. In this case, the unhandled threading exception is siently ignored: --- $ ./python -m test -u all test_ftplib -W -m test_makeport -j1 (...) 0:00:00 load avg: 0.75 [1/1] test_ftplib passed (...) Tests result: SUCCESS --- On Python 3.10 and newer, libregrtest sets a threading excepthook to (1) log the exception (2) mark that the note "altered the environmen": mark the test as "ENV CHANGED". I did that to detect unhandled exceptions like this one. In this case, unhandled exceptions come from the four handle_error() method of test_ftplib dispatcher classes, like SSLConnection, which are implemented as: def handle_error(self): raise Exception test_ftplib closes sockets in TestFTPClass.tearDown() method: def tearDown(self): self.client.close() self.server.stop() # Explicitly clear the attribute to prevent dangling thread self.server = None asyncore.close_all(ignore_all=True) The problem is that the code doesn't implement any kind of error handling. If asyncore gets a socket exception, it calls handle_error() which raises an a new Exception instance. That's it. IMO it's not worth it to bother with handling socket errors in test_ftplib. The server is implemented with asyncore which is deprecated since Python 3.6. The FTP protocol itself is legacy. Attached PR simply ignores socket erors rather than logging unhandled threading exceptions. ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue44359> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com