pythonpathlibpyfakefs

Why FileNotFoundError on Path.rename while using Pyfakefs?


I wrote a test for a function that renames files from e.g. /videos/vid_youtube.mp4 to /videos/youtube/vid.mp4. The test patches the fs with Pyfakefs.

When the code actually renames the file, I get this error.

FileNotFoundError: [Errno 2] No such file or directory: '/home/user/code/project/test/DLV/videos/vid_youtube.mp4' -> '/home/user/code/project/test/DLV/videos/youtube/vid.mp4'

This is how I set up fakefs

def setUp(self) -> None:
    self.setUpPyfakefs()
    self.fs.create_dir(Path(Dirs.VIDEOS))  # /home/user/code/project/test/DLV/videos
    self.fs.create_file(Path(Dirs.VIDEOS / "vid_youtube.mp4"))

The code under test.

class Files:
    @staticmethod
    def rename_video_files():
        all_files = Collect.video_files()

        for files_for_type in all_files:
            for file in all_files[files_for_type]:
                path = Path(file)
                platform = Files.detect_platform(path)
                platform_dir = Path(Dirs.VIDEOS, platform)
                platform_dir.mkdir(exist_ok=True)

                new_name = path.stem.replace(f'_{platform}', '')
                new_path = Dirs.VIDEOS / platform / f'{new_name}{path.suffix}'

                old_path = Dirs.VIDEOS / path
                old_path.rename(new_path)   # throws FileNotFoundError

I debugged the test and the method under test and even passed the fake fs to rename_video_files(fakefs) to inspect the files and directories. All files and directories look correct.

What is going wrong here?


Solution

  • The problem here is most likely the static initialization of Dirs.VIDEOS. This is initialized at load time as a pathlib.Path, and won't be patched later at the time you setup pyfakefs (the same problem would happen if you where to use unittest.patch for patching).

    There are two ways to fix this:

    from pyfakefs.fake_filesystem_unittest import TestCase
    
    from my_module import video_files
    from my_module.video_files import Dirs, Files
    
    
    class MyTest(TestCase):
        def setUp(self) -> None:
            self.setUpPyfakefs(modules_to_reload=[video_files])
            self.fs.create_dir(
                Path(Dirs.VIDEOS))  # /home/user/code/project/test/DLV/videos
            self.fs.create_file(Path(Dirs.VIDEOS / "vid_youtube.mp4"))
    

    (under the assumption, that your code under test is located in my_module.video_files.py)

    Disclaimer:
    I'm a contributor to pyfakefs.