Changeset 997:7ee81a2ca43a


Ignore:
Timestamp:
Nov 14, 2010, 10:38:40 PM (10 years ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
Message:
Fail as early as possible if a method gets a non-ASCII unicode path.

See ticket #53 at http://ftputil.sschwarzer.net/trac/ticket/53 and
the long comment in `test_real_ftp.TestUnicodePaths` for the
motivation for this change.
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • ftputil.py

    r986 r997  
    201201        if none is available.
    202202        """
     203        # Fail early if we get a unicode path which can't be encoded.
     204        path = str(path)
    203205        host = self._available_child()
    204206        if host is None:
     
    461463        text copies, or 'b' for binary copies.
    462464        """
     465        # Fail early if we get a unicode path which can't be encoded.
     466        # Only attempt to convert the remote `target` name to a
     467        # bytestring. We leave it to the local filesystem whether it
     468        # wants to support unicode filenames or not.
     469        target = str(target)
    463470        source_file, target_file = self._upload_files(source, target, mode)
    464471        file_transfer.copy_file(source_file, target_file,
     
    474481        `False`.
    475482        """
     483        # See comment in `upload`.
     484        target = str(target)
    476485        source_file, target_file = self._upload_files(source, target, mode)
    477486        return file_transfer.copy_file(source_file, target_file,
     
    494503        text copies, or 'b' for binary copies.
    495504        """
     505        # Fail early if we get a unicode path which can't be encoded.
     506        # Only attempt to convert the remote `source` name to a
     507        # bytestring. We leave it to the local filesystem whether it
     508        # wants to support unicode filenames or not.
     509        source = str(source)
    496510        source_file, target_file = self._download_files(source, target, mode)
    497511        file_transfer.copy_file(source_file, target_file,
     
    507521        `False`.
    508522        """
     523        # See comment in `download`.
     524        source = str(source)
    509525        source_file, target_file = self._download_files(source, target, mode)
    510526        return file_transfer.copy_file(source_file, target_file,
     
    575591    def chdir(self, path):
    576592        """Change the directory on the host."""
     593        # Fail early if we get a unicode path which can't be encoded.
     594        path = str(path)
    577595        ftp_error._try_with_oserror(self._session.cwd, path)
    578596        # The path given as the argument is relative to the old current
     
    587605        `os.mkdir`.
    588606        """
     607        # Fail early if we get a unicode path which can't be encoded.
     608        path = str(path)
    589609        # Ignore unused argument `mode`
    590610        # pylint: disable=W0613
     
    601621        `os.makedirs` but otherwise ignored.
    602622        """
     623        # Fail early if we get a unicode path which can't be encoded.
     624        path = str(path)
    603625        # Ignore unused argument `mode`
    604626        # pylint: disable=W0613
     
    630652        is no longer supported.
    631653        """
     654        # Fail early if we get a unicode path which can't be encoded.
     655        path = str(path)
    632656        path = self.path.abspath(path)
    633657        if self.listdir(path):
     
    642666    def remove(self, path):
    643667        """Remove the given file or link."""
     668        # Fail early if we get a unicode path which can't be encoded.
     669        path = str(path)
    644670        path = self.path.abspath(path)
    645671        # Though `isfile` includes also links to files, `islink`
     
    691717        in Python 2.4 and adapted to ftputil.
    692718        """
     719        # Fail early if we get a unicode path which can't be encoded.
     720        path = str(path)
    693721        # The following code is an adapted version of Python 2.4's
    694722        #  `shutil.rmtree` function.
     
    732760    def rename(self, source, target):
    733761        """Rename the source on the FTP host to target."""
     762        # Fail early if we get a unicode path which can't be encoded.
     763        source = str(source)
     764        target = str(target)
    734765        # The following code is in spirit similar to the code in the
    735766        #  method `_robust_ftp_command`, though we do _not_ do
     
    784815        any of the available parsers raise a `ParserError`.
    785816        """
     817        # Fail early if we get a unicode path which can't be encoded.
     818        path = str(path)
    786819        return self._stat.listdir(path)
    787820
     
    798831        _not_ intended for use by ftputil clients.)
    799832        """
     833        # Fail early if we get a unicode path which can't be encoded.
     834        path = str(path)
    800835        return self._stat.lstat(path, _exception_for_missing_path)
    801836
     
    813848        _not_ intended for use by ftputil clients.)
    814849        """
     850        # Fail early if we get a unicode path which can't be encoded.
     851        path = str(path)
    815852        return self._stat.stat(path, _exception_for_missing_path)
    816853
     
    821858        function (see http://docs.python.org/lib/os-file-dir.html ).
    822859        """
     860        # Fail early if we get a unicode path which can't be encoded.
     861        top = str(top)
    823862        # The following code is copied from `os.walk` in Python 2.4
    824863        #  and adapted to ftputil.
     
    856895        causes a `PermanentError`.
    857896        """
     897        # Fail early if we get a unicode path which can't be encoded.
     898        path = str(path)
    858899        path = self.path.abspath(path)
    859900        def command(self, path):
  • test/test_real_ftp.py

    r949 r997  
     1# encoding: UTF-8
     2
    13# Copyright (C) 2003-2010, Stefan Schwarzer <sschwarzer@sschwarzer.net>
    24# See the file LICENSE for licensing terms.
     
    639641
    640642
     643class TestUnicodePaths(RealFTPTest):
     644    """Test if using unicode paths fails if they contain non-ASCII
     645    characters (see ticket #53).
     646    """
     647
     648    # Actually, all of these methods will raise a `UnicodeEncodeError`
     649    #  at some point, at the latest when a unicode string is tried to
     650    #  be sent over a socket. However, it can be rather confusing to
     651    #  get an encoding error from deep inside of ftputil or even
     652    #  modules used by it (see ticket #53). Therefore, I added tests
     653    #  to fail as early as possible if a path is a unicode path that
     654    #  can't be converted to ASCII. Moreover, the code won't try to
     655    #  use unicode strings which come into existence intermediately.
     656 
     657    def assert_non_unicode(self, s):
     658        self.assertFalse(isinstance(s, unicode))
     659
     660    def assert_unicode_error(self, function, *args):
     661        self.assertRaises(UnicodeEncodeError, function, *args)
     662
     663    def test_open(self):
     664        host = self.host
     665        # Check if the name attribute is a bytestring, no matter if we
     666        #  passed in a bytestring or not beforehand.
     667        fobj = host.file("CONTENTS")
     668        try:
     669            self.assert_non_unicode(fobj.name)
     670        finally:
     671            fobj.close()
     672        fobj = host.file(u"CONTENTS")
     673        try:
     674            self.assert_non_unicode(fobj.name)
     675        finally:
     676            fobj.close()
     677        # Check if non-encodable unicode strings are refused.
     678        self.assert_unicode_error(host.file, u"ä")
     679
     680    def test_upload(self):
     681        self.assert_unicode_error(self.host.upload, "ftputil.py", u"ä")
     682
     683    def test_upload_if_newer(self):
     684        self.assert_unicode_error(self.host.upload_if_newer,
     685                                  "ftputil.py", u"ä")
     686
     687    def test_download(self):
     688        self.assert_unicode_error(self.host.download, u"ä", "ok")
     689
     690    def test_download_if_newer(self):
     691        self.assert_unicode_error(self.host.download_if_newer, u"ä", "ok")
     692
     693    def test_chdir(self):
     694        # Unicode strings are ok if they can be encoded to ASCII.
     695        host = self.host
     696        host.chdir(".")
     697        self.assert_non_unicode(host.getcwd())
     698        host.chdir(u".")
     699        self.assert_non_unicode(host.getcwd())
     700        # Fail early if string can't be encoded to ASCII.
     701        self.assert_unicode_error(host.chdir, u"ä")
     702
     703    def test_mkdir(self):
     704        self.assert_unicode_error(self.host.mkdir, u"ä")
     705
     706    def test_makedirs(self):
     707        self.assert_unicode_error(self.host.makedirs, u"b/ä")
     708
     709    def test_rmdir(self):
     710        self.assert_unicode_error(self.host.rmdir, u"ä")
     711
     712    def test_remove(self):
     713        self.assert_unicode_error(self.host.remove, u"ä")
     714
     715    def test_rmtree(self):
     716        self.assert_unicode_error(self.host.rmtree, u"ä")
     717
     718    def test_rename(self):
     719        self.assert_unicode_error(self.host.rename, u"ä", "b")
     720        self.assert_unicode_error(self.host.rename, "b", u"ä")
     721
     722    def test_listdir(self):
     723        self.assert_unicode_error(self.host.listdir, u"ä")
     724
     725    def test_lstat(self):
     726        self.assert_unicode_error(self.host.lstat, u"ä")
     727
     728    def test_stat(self):
     729        self.assert_unicode_error(self.host.stat, u"ä")
     730
     731    def test_walk(self):
     732        generator = self.host.walk(u"ä")
     733        # The string test is only executed when the first item is
     734        #  requested from the generator.
     735        self.assert_unicode_error(generator.next)
     736
     737    def test_chmod(self):
     738        self.assert_unicode_error(self.host.chmod, u"ä", 0644)
     739
     740
    641741class TestOther(RealFTPTest):
    642742
     
    701801    unittest.main()
    702802    import __main__
    703     #unittest.main(__main__,
    704     #              "TestFTPFiles.test_no_timed_out_children")
    705 
     803    #unittest.main(__main__, "TestUnicodePaths")
     804
Note: See TracChangeset for help on using the changeset viewer.