Repository: ManimCommunity/manim

Issue:
[scene caching] partial movie file not found
Here is another scene caching error: running the code

```
from manim import *


class TestZoom1(ZoomedScene):
        CONFIG = {
            "zoomed_camera_frame_starting_position": [0, 0, 0],
            "zoomed_display_corner": [0, 0, 0],
            "zoomed_display_height": config['frame_height'],
            "zoomed_display_width": config['frame_width'],
            "zoom_factor": 0.1,
        }
        def construct(self):
            self.activate_zooming(animate=True)
            d = Dot()
            self.add(d)
```

(one of our examples from the documentation) **twice** raises the following error:

```
[behackl@atreus playground]$ manim test.py TestZoom1 -m
[09/23/20 14:38:04] INFO     Animation 0 : Partial movie file written in {'/home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/partial_movie_files/TestZoom1/2818502609_1974117047_3316235269.mp4'}                       scene_file_writer.py:463
[09/23/20 14:38:05] INFO     Animation 1 : Partial movie file written in {'/home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/partial_movie_files/TestZoom1/1160423895_881011468_1267139589.mp4'}                        scene_file_writer.py:463
                    INFO                                                                                                                                                                                                                        scene_file_writer.py:635
                             File ready at /home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/TestZoom1.mp4                                                                                                                                      
                                                                                                                                                                                                                                                                        
                    INFO     Rendered TestZoom1                                                                                                                                                                                                             scene.py:129
                             Played 2 animations                                                                                                                                                                                                                        
[behackl@atreus playground]$ manim test.py TestZoom1 -m
[09/23/20 14:38:07] INFO     Animation 0 : Using cached data (hash : 2818502609_1974117047_3316235269)                                                                                                                                                      scene.py:823
[09/23/20 14:38:08] INFO     Animation 1 : Partial movie file written in {'/home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/partial_movie_files/TestZoom1/2818502609_1974117047_3316235269.mp4'}                       scene_file_writer.py:463
[concat @ 0x564241a313c0] Impossible to open 'file:/home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/partial_movie_files/TestZoom1/2796914319_881011468_1267139589.mp4'
/home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/partial_movie_files/TestZoom1/partial_movie_file_list.txt: No such file or directory
                    INFO                                                                                                                                                                                                                        scene_file_writer.py:635
                             File ready at /home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/TestZoom1.mp4                                                                                                                                      
                                                                                                                                                                                                                                                                        



Traceback (most recent call last):
  File "/home/behackl/Dokumente/git/etc/manim/manim/__main__.py", line 170, in main
    scene = SceneClass()
  File "/home/behackl/Dokumente/git/etc/manim/manim/scene/scene.py", line 93, in __init__
    self.file_writer.finish()
  File "/home/behackl/Dokumente/git/etc/manim/manim/scene/scene_file_writer.py", line 387, in finish
    self.combine_movie_files()
  File "/home/behackl/Dokumente/git/etc/manim/manim/scene/scene_file_writer.py", line 592, in combine_movie_files
    modify_atime(file_path)
  File "/home/behackl/Dokumente/git/etc/manim/manim/utils/file_ops.py", line 53, in modify_atime
    os.utime(file_path, times=(time.time(), os.path.getmtime(file_path)))
  File "/usr/lib/python3.8/genericpath.py", line 55, in getmtime
    return os.stat(filename).st_mtime
FileNotFoundError: [Errno 2] No such file or directory: '/home/behackl/Dokumente/git/etc/manim/playground/media/videos/test/720p30/partial_movie_files/TestZoom1/2796914319_881011468_1267139589.mp4'
```

(I've noticed this from running `make html && make clean && make html` from `docs`.)
Error on compiling video: partial_movie_file_list.txt: No such file or directory
### If this is a support request:

I encountered this error mulitple times today

```
$ rm -rf /home/cobordism/Documents/renderings/
$ manim --media_dir /home/cobordism/Documents/renderings/ ./examples.py ycombinator -pl --disable_caching -n 30
---
---
[concat @ 0x560c5416b7c0] Impossible to open 'file:/home/cobordism/Documents/renderings/videos/examples/480p15/partial_movie_files/ycombinator/uncached_00031.mp4'
/home/cobordism/Documents/renderings/videos/examples/480p15/partial_movie_files/ycombinator/partial_movie_file_list.txt: No such file or directory
                    INFO                                                                                scene_file_writer.py:635
                             File ready at /home/cobordism/Documents/renderings/videos/examples/480p15/                         
                             ycombinator.mp4                                                                                    
                                                                                                                                



Traceback (most recent call last):
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/__main__.py", line 170, in main
    scene = SceneClass()
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/scene/scene.py", line 93, in __init__
    self.file_writer.finish()
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/scene/scene_file_writer.py", line 387, in finish
    self.combine_movie_files()
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/scene/scene_file_writer.py", line 592, in combine_movie_files
    modify_atime(file_path)
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/utils/file_ops.py", line 53, in modify_atime
    os.utime(file_path, times=(time.time(), os.path.getmtime(file_path)))
  File "/usr/lib/python3.8/genericpath.py", line 55, in getmtime
    return os.stat(filename).st_mtime
FileNotFoundError: [Errno 2] No such file or directory: '/home/cobordism/Documents/renderings/videos/examples/480p15/partial_movie_files/ycombinator/uncached_00031.mp4'
```

I don't know exactly what is triggering it, but running without `-n` (and with an empty media dir and no cache ..). that seems to work. Will post more info if I find it.


Discussion:

Thanks for the report :D 
On second thought I don't think it is related to scene-caching. 
Could you try to run the scene, but without passing `--media_dir`flag and with `-v DEBUG` ? (and post the full logs). 

For me, the issue comes from the directories that are wrongly initialized. The first error message is thrown by FFMPEG and basically says "I can't find the partial movie files there !", and the Expection basically says the same thing, except that it's manim and not FFMEPG. 
It's like partial movie files have been created somewhere else.
 

Status:
`$ manim --media_dir /home/cobordism/Documents/renderings/ ./examples.py ycombinator -pl -v DEBUG`
produces the video, no problem.

`$ manim --media_dir /home/cobordism/Documents/renderings/ ./examples.py ycombinator -pl -v DEBUG -n 30`
produces a strange staccato video up to animation 30 and then proceeds normally.
For example, instead of starting at animation 30, the text that was being written in previous animations just appears. It's as if all the write animations were replaced by scene.add() but all the timings - scene.wait() - remain. 
This odd behavious might lead to the following:

```
$ rm -rf ~/Documents/renderings/*
$ manim --media_dir /home/cobordism/Documents/renderings/ ./examples.py ycombinator -pl -v DEBUG -n 30
```
This causes the error.

```
[concat @ 0x55e90a8d27c0] Impossible to open 'file:/home/cobordism/Documents/renderings/videos/examples/480p15/partial_movie_files/ycombinator/582350547_2_2328097757.mp4'
/home/cobordism/Documents/renderings/videos/examples/480p15/partial_movie_files/ycombinator/partial_movie_file_list.txt: No such file or directory
                    INFO                                                                                                          scene_file_writer.py:635
                             File ready at /home/cobordism/Documents/renderings/videos/examples/480p15/ycombinator.mp4                                    
                                                                                                                                                          



Traceback (most recent call last):
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/__main__.py", line 170, in main
    scene = SceneClass()
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/scene/scene.py", line 93, in __init__
    self.file_writer.finish()
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/scene/scene_file_writer.py", line 387, in finish
    self.combine_movie_files()
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/scene/scene_file_writer.py", line 592, in combine_movie_files
    modify_atime(file_path)
  File "/home/cobordism/.local/lib/python3.8/site-packages/manim/utils/file_ops.py", line 53, in modify_atime
    os.utime(file_path, times=(time.time(), os.path.getmtime(file_path)))
  File "/usr/lib/python3.8/genericpath.py", line 55, in getmtime
    return os.stat(filename).st_mtime
FileNotFoundError: [Errno 2] No such file or directory: '/home/cobordism/Documents/renderings/videos/examples/480p15/partial_movie_files/ycombinator/582350547_2_2328097757.mp4'
```

and for good measure:
```
$ manim ./examples.py ycombinator -pl -v DEBUG -n 30
```
causes the same error - so it is not a media-dir question. It's a problem of starting at `-n 30`



PS the extra debug output is not helpful at all. All it has is stuff like:
```
[09/21/20 19:15:54] DEBUG    Hashing ...                                                                                                    hashing.py:234
[09/21/20 19:15:55] DEBUG    Hashing done in 1.595105 s.                                                                                    hashing.py:249
[09/21/20 19:15:57] INFO     Animation 44 : Partial movie file written in {'/home/cobordism/Documents/manimstuff/mylectures/lambd scene_file_writer.py:463
                             a-manim-ce/media/videos/examples/480p15/partial_movie_files/ycombinator/582350547_2_2387872213.mp4'}                         
                    DEBUG    Hashing ...                                                                                                    hashing.py:280
[09/21/20 19:15:58] DEBUG    Hashing done in 1.582779 s.                                                                                    hashing.py:305
[09/21/20 19:15:59] INFO     Animation 45 : Partial movie file written in {'/home/cobordism/Documents/manimstuff/mylectures/lambd scene_file_writer.py:463
                             a-manim-ce/media/videos/examples/480p15/partial_movie_files/ycombinator/582350547_373238890_42411689                         
                             09.mp4'}                                                                                                                     
                    WARNING  TextMobject has been deprecated (due to its confusing name)in favour of Tex. Please use Tex instead!       tex_mobject.py:349
                    INFO     Writing "\raggedright So now we can define factorial as:\\factorial $\equiv$ (Y factorial')." to       tex_file_writing.py:42
                             media/Tex/be15788f046f08a9.tex                                                                                               
[09/21/20 19:16:00] DEBUG    Hashing ...                                                                                                    hashing.py:234
[09/21/20 19:16:01] DEBUG    Hashing done in 1.660851 s.                                                                                    hashing.py:249
[09/21/20 19:16:02] INFO     Animation 46 : Partial movie file written in {'/home/cobordism/Documents/manimstuff/mylectures/lambd scene_file_writer.py:463
                             a-manim-ce/media/videos/examples/480p15/partial_movie_files/ycombinator/582350547_2_2595929461.mp4'}                         
                    DEBUG    Hashing ...                                                                                                    hashing.py:280
[09/21/20 19:16:04] DEBUG    Hashing done in 1.654192 s.                                                                                    hashing.py:305
[09/21/20 19:16:05] INFO     Animation 47 : Partial movie file written in {'/home/cobordism/Documents/manimstuff/mylectures/lambd scene_file_writer.py:463
                             a-manim-ce/media/videos/examples/480p15/partial_movie_files/ycombinator/582350547_7561646_674770672.                         
                             mp4'} 
```


PPS
I might add that media/videos/examples/480p15/partial_movie_files/ycombinator/partial_movie_file_list.txt contains 34 entries, but 
media/videos/examples/480p15/partial_movie_files/ycombinator/ contains only 18 videos one the txt file.
Intersting. If the bug is reproducible, could you please share (a reduced version, if possible ^^) the code causing the error? 

> produces a strange staccato video up to animation 30 and then proceeds normally.

And, what do you mean by this ? could you share the video ? 

And, maybe you should take a look at the directory where partial movie files are stored; there might be some clues down there. My guess is that it's comes from the scene caching mechanism, which is tricked into thinking that a partial movie file exists but in fact it does not exist. The question is now, why does it think that. 

And last thing, do you think it has something to do with tex generation or/and caching ? 

(And, just to let you know, there is `--flush_cache` flag that can remove all the partial movie files. Can be useful ;) 
so. here is a mimimal version that produces the error message:
```
class test(Scene):
    def write(self, txt, **kwargs):
        self.play(ShowCreation(txt, **kwargs))    
    def construct(self):
        self.write(TextMobject("this is a test"))
        self.wait(1)
        self.write(TextMobject("this is a test 2 ").shift(DOWN))
        self.wait(1)
        self.write(TextMobject("this is a test 3 ").shift(2* DOWN))
        self.wait(1)
        self.write(TextMobject("this is a fourth test").shift(3*DOWN))
        self.wait(1)    
```

run the command `$ manim example.py test -n 3 -pl`
> And, what do you mean by this ? could you share the video ?

I am currently not able to reproduce this. What I meant was that I had added a lot of text with `self.play(ShowCreation(txt))` but I was getting text appearing as if I had been using `self.add(txt)` instead... i.e. the animations were gone but the timings were still there. 
I'll let you know if I can recreate it, until then let's regard it as a fluke.
Update. I have been able to recreate it. 

Try this:
Step 1: empty the data dir. `rm -rf ./media`
Step 2: `$ manim example.py test -pl`  (should work fine)
Step 3:  `$ manim example.py test -pl -n 3` (staccato effect)
Step 4: empty the data dir. `rm -rf ./media`
Step 5:  `$ manim example.py test -pl -n 3` (error message, but video produced ok)
Step 6:  `$ manim example.py test -pl` (error message, but video produced ok)


Resolving patch:
diff --git a/manim/scene/scene.py b/manim/scene/scene.py
--- a/manim/scene/scene.py
+++ b/manim/scene/scene.py
@@ -103,7 +103,7 @@ def __init__(self, **kwargs):
                 self,
                 **file_writer_config,
             )
-        self.play_hashes_list = []
+        self.animations_hashes = []
 
         self.mobjects = []
         self.original_skipping_status = file_writer_config["skip_animations"]
@@ -852,13 +852,16 @@ def wrapper(self, *args, **kwargs):
             if file_writer_config["skip_animations"]:
                 logger.debug(f"Skipping animation {self.num_plays}")
                 func(self, *args, **kwargs)
+                # If the animation is skipped, we mark its hash as None.
+                # When sceneFileWriter will start combining partial movie files, it won't take into account None hashes.
+                self.animations_hashes.append(None)
+                self.file_writer.add_partial_movie_file(None)
                 return
             if not file_writer_config["disable_caching"]:
                 mobjects_on_scene = self.get_mobjects()
                 hash_play = get_hash_from_play_call(
                     self, self.camera, animations, mobjects_on_scene
                 )
-                self.play_hashes_list.append(hash_play)
                 if self.file_writer.is_already_cached(hash_play):
                     logger.info(
                         f"Animation {self.num_plays} : Using cached data (hash : %(hash_play)s)",
@@ -867,7 +870,12 @@ def wrapper(self, *args, **kwargs):
                     file_writer_config["skip_animations"] = True
             else:
                 hash_play = "uncached_{:05}".format(self.num_plays)
-                self.play_hashes_list.append(hash_play)
+            self.animations_hashes.append(hash_play)
+            self.file_writer.add_partial_movie_file(hash_play)
+            logger.debug(
+                "List of the first few animation hashes of the scene: %(h)s",
+                {"h": str(self.animations_hashes[:5])},
+            )
             func(self, *args, **kwargs)
 
         return wrapper
@@ -890,12 +898,15 @@ def wrapper(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
             if file_writer_config["skip_animations"]:
                 logger.debug(f"Skipping wait {self.num_plays}")
                 func(self, duration, stop_condition)
+                # If the animation is skipped, we mark its hash as None.
+                # When sceneFileWriter will start combining partial movie files, it won't take into account None hashes.
+                self.animations_hashes.append(None)
+                self.file_writer.add_partial_movie_file(None)
                 return
             if not file_writer_config["disable_caching"]:
                 hash_wait = get_hash_from_wait_call(
                     self, self.camera, duration, stop_condition, self.get_mobjects()
                 )
-                self.play_hashes_list.append(hash_wait)
                 if self.file_writer.is_already_cached(hash_wait):
                     logger.info(
                         f"Wait {self.num_plays} : Using cached data (hash : {hash_wait})"
@@ -903,7 +914,12 @@ def wrapper(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
                     file_writer_config["skip_animations"] = True
             else:
                 hash_wait = "uncached_{:05}".format(self.num_plays)
-                self.play_hashes_list.append(hash_wait)
+            self.animations_hashes.append(hash_wait)
+            self.file_writer.add_partial_movie_file(hash_wait)
+            logger.debug(
+                "Animations hashes list of the scene : (concatened to 5) %(h)s",
+                {"h": str(self.animations_hashes[:5])},
+            )
             func(self, duration, stop_condition)
 
         return wrapper
diff --git a/manim/scene/scene_file_writer.py b/manim/scene/scene_file_writer.py
--- a/manim/scene/scene_file_writer.py
+++ b/manim/scene/scene_file_writer.py
@@ -37,6 +37,9 @@ class SceneFileWriter(object):
             The PIL image mode to use when outputting PNGs
         "movie_file_extension" (str=".mp4")
             The file-type extension of the outputted video.
+        "partial_movie_files"
+            List of all the partial-movie files.
+
     """
 
     def __init__(self, scene, **kwargs):
@@ -46,7 +49,7 @@ def __init__(self, scene, **kwargs):
         self.init_output_directories()
         self.init_audio()
         self.frame_count = 0
-        self.index_partial_movie_file = 0
+        self.partial_movie_files = []
 
     # Output directories and files
     def init_output_directories(self):
@@ -113,6 +116,29 @@ def init_output_directories(self):
                     )
                 )
 
+    def add_partial_movie_file(self, hash_animation):
+        """Adds a new partial movie file path to scene.partial_movie_files from an hash. This method will compute the path from the hash.
+
+        Parameters
+        ----------
+        hash_animation : str
+            Hash of the animation.
+        """
+
+        # None has to be added to partial_movie_files to keep the right index with scene.num_plays.
+        # i.e if an animation is skipped, scene.num_plays is still incremented and we add an element to partial_movie_file be even with num_plays.
+        if hash_animation is None:
+            self.partial_movie_files.append(None)
+            return
+        new_partial_movie_file = os.path.join(
+            self.partial_movie_directory,
+            "{}{}".format(
+                hash_animation,
+                file_writer_config["movie_file_extension"],
+            ),
+        )
+        self.partial_movie_files.append(new_partial_movie_file)
+
     def get_default_module_directory(self):
         """
         This method gets the name of the directory containing
@@ -149,7 +175,7 @@ def get_resolution_directory(self):
         This method gets the name of the directory that immediately contains the
         video file. This name is ``<height_in_pixels_of_video>p<frame_rate>``.
         For example, if you are rendering an 854x480 px animation at 15fps,
-        the name of the directory that immediately contains the video file
+        the name of the directory that immediately contains the video,  file
         will be ``480p15``.
 
         The file structure should look something like::
@@ -186,29 +212,6 @@ def get_image_file_path(self):
         """
         return self.image_file_path
 
-    def get_next_partial_movie_path(self):
-        """
-        Manim renders each play-like call in a short partial
-        video file. All such files are then concatenated with
-        the help of FFMPEG.
-
-        This method returns the path of the next partial movie.
-
-        Returns
-        -------
-        str
-            The path of the next partial movie.
-        """
-        result = os.path.join(
-            self.partial_movie_directory,
-            "{}{}".format(
-                self.scene.play_hashes_list[self.index_partial_movie_file],
-                file_writer_config["movie_file_extension"],
-            ),
-        )
-        self.index_partial_movie_file += 1
-        return result
-
     def get_movie_file_path(self):
         """
         Returns the final path of the written video file.
@@ -399,7 +402,9 @@ def open_movie_pipe(self):
         FFMPEG and begin writing to FFMPEG's input
         buffer.
         """
-        file_path = self.get_next_partial_movie_path()
+        file_path = self.partial_movie_files[self.scene.num_plays]
+
+        # TODO #486 Why does ffmpeg need temp files ?
         temp_file_path = (
             os.path.splitext(file_path)[0]
             + "_temp"
@@ -497,21 +502,20 @@ def combine_movie_files(self):
         # cuts at all the places you might want.  But for viewing
         # the scene as a whole, one of course wants to see it as a
         # single piece.
-        partial_movie_files = [
-            os.path.join(
-                self.partial_movie_directory,
-                "{}{}".format(hash_play, file_writer_config["movie_file_extension"]),
-            )
-            for hash_play in self.scene.play_hashes_list
-        ]
-        if len(partial_movie_files) == 0:
-            logger.error("No animations in this scene")
-            return
+        partial_movie_files = [el for el in self.partial_movie_files if el is not None]
+        # NOTE : Here we should do a check and raise an exeption if partial movie file is empty.
+        # We can't, as a lot of stuff (in particular, in tests) use scene initialization, and this error would be raised as it's just
+        # an empty scene initialized.
+
         # Write a file partial_file_list.txt containing all
         # partial movie files. This is used by FFMPEG.
         file_list = os.path.join(
             self.partial_movie_directory, "partial_movie_file_list.txt"
         )
+        logger.debug(
+            f"Partial movie files to combine ({len(partial_movie_files)} files): %(p)s",
+            {"p": partial_movie_files[:5]},
+        )
         with open(file_list, "w") as fp:
             fp.write("# This file is used internally by FFMPEG.\n")
             for pf_path in partial_movie_files:
diff --git a/manim/utils/hashing.py b/manim/utils/hashing.py
--- a/manim/utils/hashing.py
+++ b/manim/utils/hashing.py
@@ -252,9 +252,11 @@ def get_hash_from_play_call(
     ]
     t_end = perf_counter()
     logger.debug("Hashing done in %(time)s s.", {"time": str(t_end - t_start)[:8]})
+    hash_complete = f"{hash_camera}_{hash_animations}_{hash_current_mobjects}"
     # This will reset ALREADY_PROCESSED_ID as all the hashing processus is finished.
     ALREADY_PROCESSED_ID = {}
-    return "{}_{}_{}".format(hash_camera, hash_animations, hash_current_mobjects)
+    logger.debug("Hash generated :  %(h)s", {"h": hash_complete})
+    return hash_complete
 
 
 def get_hash_from_wait_call(
@@ -299,15 +301,15 @@ def get_hash_from_wait_call(
         ALREADY_PROCESSED_ID = {}
         t_end = perf_counter()
         logger.debug("Hashing done in %(time)s s.", {"time": str(t_end - t_start)[:8]})
-        return "{}_{}{}_{}".format(
-            hash_camera,
-            str(wait_time).replace(".", "-"),
-            hash_function,
-            hash_current_mobjects,
-        )
+        hash_complete = f"{hash_camera}_{str(wait_time).replace('.', '-')}{hash_function}_{hash_current_mobjects}"
+        logger.debug("Hash generated :  %(h)s", {"h": hash_complete})
+        return hash_complete
     ALREADY_PROCESSED_ID = {}
     t_end = perf_counter()
     logger.debug("Hashing done in %(time)s s.", {"time": str(t_end - t_start)[:8]})
-    return "{}_{}_{}".format(
-        hash_camera, str(wait_time).replace(".", "-"), hash_current_mobjects
+    hash_complete = (
+        f"{hash_camera}_{str(wait_time).replace('.', '-')}_{hash_current_mobjects}"
     )
+
+    logger.debug("Hash generated :  %(h)s", {"h": hash_complete})
+    return hash_complete


Test patch:
diff --git a/tests/control_data/logs_data/BasicSceneLoggingTest.txt b/tests/control_data/logs_data/BasicSceneLoggingTest.txt
--- a/tests/control_data/logs_data/BasicSceneLoggingTest.txt
+++ b/tests/control_data/logs_data/BasicSceneLoggingTest.txt
@@ -1,6 +1,9 @@
 {"levelname": "INFO", "module": "config", "message": "Log file will be saved in <>"}
 {"levelname": "DEBUG", "module": "hashing", "message": "Hashing ..."}
 {"levelname": "DEBUG", "module": "hashing", "message": "Hashing done in <> s."}
+{"levelname": "DEBUG", "module": "hashing", "message": "Hash generated :  <>"}
+{"levelname": "DEBUG", "module": "scene", "message": "List of the first few animation hashes of the scene: <>"}
 {"levelname": "INFO", "module": "scene_file_writer", "message": "Animation 0 : Partial movie file written in <>"}
+{"levelname": "DEBUG", "module": "scene_file_writer", "message": "Partial movie files to combine (1 files): <>"}
 {"levelname": "INFO", "module": "scene_file_writer", "message": "\nFile ready at <>\n"}
 {"levelname": "INFO", "module": "scene", "message": "Rendered SquareToCircle\nPlayed 1 animations"}
diff --git a/tests/test_scene_rendering/test_caching_related.py b/tests/test_scene_rendering/test_caching_related.py
new file mode 100644
--- /dev/null
+++ b/tests/test_scene_rendering/test_caching_related.py
@@ -0,0 +1,53 @@
+import os
+import pytest
+import subprocess
+from manim import file_writer_config
+
+from ..utils.commands import capture
+from ..utils.video_tester import *
+
+
+@video_comparison(
+    "SceneWithMultipleWaitCallsWithNFlag.json",
+    "videos/simple_scenes/480p15/SceneWithMultipleWaitCalls.mp4",
+)
+def test_wait_skip(tmp_path, manim_cfg_file, simple_scenes_path):
+    # Test for PR #468. Intended to test if wait calls are correctly skipped.
+    scene_name = "SceneWithMultipleWaitCalls"
+    command = [
+        "python",
+        "-m",
+        "manim",
+        simple_scenes_path,
+        scene_name,
+        "-l",
+        "--media_dir",
+        str(tmp_path),
+        "-n",
+        "3",
+    ]
+    out, err, exit_code = capture(command)
+    assert exit_code == 0, err
+
+
+@video_comparison(
+    "SceneWithMultiplePlayCallsWithNFlag.json",
+    "videos/simple_scenes/480p15/SceneWithMultipleCalls.mp4",
+)
+def test_play_skip(tmp_path, manim_cfg_file, simple_scenes_path):
+    # Intended to test if play calls are correctly skipped.
+    scene_name = "SceneWithMultipleCalls"
+    command = [
+        "python",
+        "-m",
+        "manim",
+        simple_scenes_path,
+        scene_name,
+        "-l",
+        "--media_dir",
+        str(tmp_path),
+        "-n",
+        "3",
+    ]
+    out, err, exit_code = capture(command)
+    assert exit_code == 0, err