~sschwarzer/ftputil

80a2fc118393e9a57b50b8294d4cf51ac3e1a31a — Stefan Schwarzer 11 years ago 6d92d66
Removed `FTPHost.__del__` to fix bug #56.

I had _partial_ success with breaking cycles explicitly by setting
several attributes in other classes to `None`. However, in the end I
felt like I was fighting the language and removed the `__del__` method
to make it easier for the garbage collector.

It's ironic: The `__del__` method was supposed to make ftputil more
fault-tolerant by shutting down an `FTPHost` object even if its
`close` method wasn't called. However, it turned out that `__del__`
not only didn't work as intended but also prevented the garbage
collection even _if_ `FTPHost.close` was called.
3 files changed, 20 insertions(+), 10 deletions(-)

M ftp_file.py
M ftputil.py
M test/test_real_ftp.py
M ftp_file.py => ftp_file.py +1 -0
@@ 224,6 224,7 @@ class _FTPFile(object):
        old_timeout = self._session.sock.gettimeout()
        try:
            self._fo.close()
            self._fo = None
            ftp_error._try_with_ioerror(self._conn.close)
            # Set a timeout to prevent waiting until server timeout
            #  if we have a server blocking here like in ticket #51.

M ftputil.py => ftputil.py +0 -9
@@ 254,15 254,6 @@ class FTPHost(object):
            self._children = []
            self.closed = True

    def __del__(self):
        # Don't complain about lazy except clause
        # pylint: disable=W0702, W0704
        try:
            self.close()
        except:
            # We don't want warnings if the constructor failed.
            pass

    #
    # Setting a custom directory parser
    #

M test/test_real_ftp.py => test/test_real_ftp.py +19 -1
@@ 6,6 6,7 @@
# Execute a test on a real FTP server (other tests use a mock server)

import ftplib
import gc
import getpass
import operator
import os


@@ 791,6 792,23 @@ class TestOther(RealFTPTest):
        host.chdir("rootdir1")
        self.assertRaises(ftp_error.TimeShiftError, host.synchronize_times)

    def _make_objects_to_be_garbage_collected(self):
        for i in xrange(10):
            with ftputil.FTPHost(server, user, password) as host:
                for j in xrange(10):
                    stat_result = host.stat("CONTENTS")
                    with host.file("CONTENTS") as fobj:
                        data = fobj.read()
            
    def test_garbage_collection(self):
        """Test whether there are cycles which prevent garbage collection."""
        gc.collect()
        objects_before_test = len(gc.garbage)
        self._make_objects_to_be_garbage_collected()
        gc.collect()
        objects_after_test = len(gc.garbage)
        self.failIf(objects_after_test - objects_before_test)


if __name__ == '__main__':
    print """\


@@ 813,5 831,5 @@ minutes because it has to wait to test the timezone calculation.
    server, user, password = get_login_data()
    unittest.main()
    import __main__
    #unittest.main(__main__, "TestStat.test_cache_auto_resizing")
    #unittest.main(__main__, "TestOther.test_garbage_collection")