62e7f2ec5e66e58c0fa83404db459eab01c7eb37 — Stefan Schwarzer 9 years ago fb0e57d
Use `LIST -a` by default, without probing (see comments in ticket #65).

The probe method `_check_list_a_option` is gone, but there's now a
public flag `use_list_a_option` which is set to `True` by default.
A user can switch this off by setting the attribute to `False`.
However, this should very rarely be necessary. I expect that most
servers will either show hidden files if `-a` is used or ignore
the option altogether.
2 files changed, 15 insertions(+), 33 deletions(-)

M ftputil/__init__.py
M test/test_real_ftp.py
M ftputil/__init__.py => ftputil/__init__.py +7 -30
@@ 111,24 111,21 @@ class FTPHost(object):
        # Associated `FTPHost` objects for data transfer.
        self._children = []
        # This is only set to something else than `None` if this instance
        # represents an `_FTPFile`.
        # This is only set to something else than `None` if this
        # instance represents an `_FTPFile`.
        self._file = None
        # Now opened.
        self.closed = False
        # Set curdir, pardir etc. for the remote host. RFC 959 states
        # that this is, strictly speaking, dependent on the server OS
        # but it seems to work at least with Unix and Windows
        # servers.
        # but it seems to work at least with Unix and Windows servers.
        self.curdir, self.pardir, self.sep = '.', '..', '/'
        # Set default time shift (used in `upload_if_newer` and
        # `download_if_newer`).
        # Check if the server accepts the `-a` option for the `LIST`
        # command. If yes, always use it to tell the server to show
        # directory and file names with a leading dot.
        self._accepts_list_a_option = False
        # Use `LIST -a` option by default. If this causes problems,
        # the user can set the attribute to `False`.
        self.use_list_a_option = True

    def keep_alive(self):

@@ 803,26 800,6 @@ class FTPHost(object):
            # Use straightforward command.
            ftp_error._try_with_oserror(self._session.rename, source, target)

    def _check_list_a_option(self):
        """Check for support of the `-a` option for the `LIST` command.
        If the option is available, use it for all further directory
        listing requests.
        def callback(line):
            """Directory listing callback."""
        # It seems that most servers just ignore unknown `LIST`
        # options instead of reacting with an error status.
        # In such a case, ftputil will subsequently use the `-a`
        # option even if it doesn't have any apparent effect.
            ftp_error._try_with_oserror(self._session.dir, u"-a", self.curdir,
        except ftp_error.PermanentError:
            self._accepts_list_a_option = False
            self._accepts_list_a_option = True

    #XXX One could argue to put this method into the `_Stat` class, but
    # I refrained from that because then `_Stat` would have to know
    # about `FTPHost`'s `_session` attribute and in turn about

@@ 838,7 815,7 @@ class FTPHost(object):
            def callback(line):
                """Callback function."""
            if self._accepts_list_a_option:
            if self.use_list_a_option:
                args = (self._session.dir, u"-a", path, callback)
                args = (self._session.dir, path, callback)

M test/test_real_ftp.py => test/test_real_ftp.py +8 -3
@@ 803,12 803,17 @@ class TestOther(RealFTPTest):
        self.assertRaises(ftp_error.TimeShiftError, host.synchronize_times)

    def test_probing_of_list_a_option(self):
        # Test probing of `LIST -a` option (ticket #63, comment 12).
    def test_list_a_option(self):
        # For this test to pass, the server must _not_ list "hidden"
        # files by default but instead only when the `LIST` `-a`
        # option is used.
        host = self.host
        directory_entries = host.listdir(host.curdir)
        self.assertTrue(".hidden" in directory_entries)
        host.use_list_a_option = False
        directory_entries = host.listdir(host.curdir)
        self.assertFalse(".hidden" in directory_entries)

    def _make_objects_to_be_garbage_collected(self):
        for i in xrange(10):