Changeset 1937:f16e9b5084b3


Ignore:
Timestamp:
May 24, 2020, 11:37:44 PM (15 months ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
Message:
Have `FTPHost.makedirs` handle `exist_ok`

If `exist_ok` is `False`, which is the default, raise an exception if
the leaf directory exists. Before, the exception wrongly wasn't
raised.

ticket: 117
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • ftputil/host.py

    r1935 r1937  
    665665        """
    666666        Make the directory `path`, but also make not yet existing intermediate
    667         directories, like `os.makedirs`. The value of `mode` is only accepted
    668         for compatibility with `os.makedirs` but otherwise ignored.
     667        directories, like `os.makedirs`.
     668
     669        The value of `mode` is only accepted for compatibility with
     670        `os.makedirs` but otherwise ignored.
     671
     672        If `exist_ok` is `False` (the default) and the leaf directory exists,
     673        raise a `PermanentError` with `errno` 17.
    669674        """
    670675        path = ftputil.tool.as_str_path(path)
     
    684689                    self.chdir(next_directory)
    685690                except ftputil.error.PermanentError:
     691                    # Directory presumably doesn't exist.
    686692                    try:
    687693                        self.mkdir(next_directory)
     
    693699                        if not self.path.isdir(next_directory):
    694700                            raise
     701                else:
     702                    # Directory exists. If we are at the last directory
     703                    # component and `exist_ok` is `False`, this is an error.
     704                    if (index == len(directories) - 1) and (not exist_ok):
     705                        # Before PEP 3151, if `exist_ok` is `False`, trying to
     706                        # create an existing directory in the local file system
     707                        # results in an `OSError` with `errno` 17, so emulate
     708                        # this also for FTP.
     709                        ftp_os_error = ftputil.error.PermanentError(
     710                            "path {!r} exists".format(path)
     711                        )
     712                        ftp_os_error.errno = 17
     713                        raise ftp_os_error
    695714        finally:
    696715            self.chdir(old_dir)
  • test/test_host.py

    r1936 r1937  
    689689
    690690
     691class TestMakedirs:
     692    def test_exist_ok_false(self):
     693        """
     694        If `exist_ok` is `False` or not specified, an existing leaf directory
     695        should lead to a `PermanentError` with `errno` set to 17.
     696        """
     697        # No `exist_ok` specified
     698        script = [
     699            Call("__init__"),
     700            Call("pwd", result="/"),
     701            Call("cwd", args=("/part1",)),
     702            Call("cwd", args=("/part1/part2",)),
     703            Call("cwd", args=("/",)),
     704            Call("close"),
     705        ]
     706        multisession_factory = scripted_session.factory(script)
     707        with test_base.ftp_host_factory(session_factory=multisession_factory) as host:
     708            with pytest.raises(ftputil.error.PermanentError) as exc_info:
     709                host.makedirs("/part1/part2")
     710            assert isinstance(exc_info.value, ftputil.error.PermanentError)
     711            assert exc_info.value.errno == 17
     712        # `exist_ok` explicitly set to `False`
     713        script = [
     714            Call("__init__"),
     715            Call("pwd", result="/"),
     716            Call("cwd", args=("/part1",)),
     717            Call("cwd", args=("/part1/part2",)),
     718            Call("cwd", args=("/",)),
     719            Call("close"),
     720        ]
     721        multisession_factory = scripted_session.factory(script)
     722        with test_base.ftp_host_factory(session_factory=multisession_factory) as host:
     723            with pytest.raises(ftputil.error.PermanentError) as exc_info:
     724                host.makedirs("/part1/part2", exist_ok=False)
     725            assert isinstance(exc_info.value, ftputil.error.PermanentError)
     726            assert exc_info.value.errno == 17
     727
     728    def test_exist_ok_true(self):
     729        """
     730        If `exist_ok` is `True`, an existing leaf directory should _not_ lead
     731        to an exception.
     732        """
     733        script = [
     734            Call("__init__"),
     735            Call("pwd", result="/"),
     736            Call("cwd", args=("/part1",)),
     737            Call("cwd", args=("/part1/part2",)),
     738            Call("cwd", args=("/",)),
     739            Call("close"),
     740        ]
     741        multisession_factory = scripted_session.factory(script)
     742        with test_base.ftp_host_factory(session_factory=multisession_factory) as host:
     743            host.makedirs("/part1/part2", exist_ok=True)
     744
     745
    691746class TestAcceptEitherUnicodeOrBytes:
    692747    """
     
    881936            # `makedirs` call.
    882937            Call("cwd", args=("/ä",)),
    883             Call("cwd", args=("/ä/ö",)),
     938            # If `exist_ok` is `False` (which is the default), the leaf
     939            # directory to make must not exist. In other words, the `chdir`
     940            # call is `makedirs` must fail with a permanent error.
     941            Call("cwd", args=("/ä/ö",), result=ftplib.error_perm),
     942            Call("cwd", args=("/ä",)),
     943            Call("cwd", args=("/ä",)),
     944            Call("mkd", args=("ö",)),
     945            # From `isdir` call
     946            Call("cwd", args=("/ä",)),
    884947            Call("cwd", args=("/",)),
    885948            Call("close"),
  • test/test_real_ftp.py

    r1935 r1937  
    207207        host = self.host
    208208        # The (chrooted) login directory
    209         host.makedirs("/")
     209        host.makedirs("/", exist_ok=True)
    210210
    211211    def test_makedirs_with_file_in_the_way(self):
     
    240240        # Preparation: `rootdir2` exists but is only writable by root. `dir2`
    241241        # is writable by regular ftp users. Both directories below should work.
    242         host.makedirs("rootdir2/dir2")
     242        host.makedirs("rootdir2/dir2", exist_ok=True)
    243243        host.makedirs("rootdir2/dir2/dir3")
    244244
Note: See TracChangeset for help on using the changeset viewer.