Repository: ManimCommunity/manim

Issue:
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.
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)

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
@@ -784,7 +784,6 @@ def update_skipping_status(self):
         the number of animations that need to be played, and
         raises an EndSceneEarlyException if they don't correspond.
         """
-
         if file_writer_config["from_animation_number"]:
             if self.num_plays < file_writer_config["from_animation_number"]:
                 file_writer_config["skip_animations"] = True
@@ -848,6 +847,10 @@ def handle_caching_wait(func):
         def wrapper(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
             self.revert_to_original_skipping_status()
             self.update_skipping_status()
+            if file_writer_config["skip_animations"]:
+                logger.debug(f"Skipping wait {self.num_plays}")
+                func(self, duration, stop_condition)
+                return
             if not file_writer_config["disable_caching"]:
                 hash_wait = get_hash_from_wait_call(
                     self, self.camera, duration, stop_condition, self.get_mobjects()


Test patch:
diff --git a/tests/control_data/videos_data/SceneWithMultiplePlayCallsWithNFlag.json b/tests/control_data/videos_data/SceneWithMultiplePlayCallsWithNFlag.json
new file mode 100644
--- /dev/null
+++ b/tests/control_data/videos_data/SceneWithMultiplePlayCallsWithNFlag.json
@@ -0,0 +1,11 @@
+{
+    "name": "SceneWithMultiplePlayCallsWithNFlag",
+    "config": {
+        "codec_name": "h264",
+        "width": 854,
+        "height": 480,
+        "avg_frame_rate": "15/1",
+        "duration": "7.000000",
+        "nb_frames": "105"
+    }
+}
\ No newline at end of file
diff --git a/tests/control_data/videos_data/SceneWithMultipleWaitCallsWithNFlag.json b/tests/control_data/videos_data/SceneWithMultipleWaitCallsWithNFlag.json
new file mode 100644
--- /dev/null
+++ b/tests/control_data/videos_data/SceneWithMultipleWaitCallsWithNFlag.json
@@ -0,0 +1,11 @@
+{
+    "name": "SceneWithMultipleWaitCallsWithNFlag",
+    "config": {
+        "codec_name": "h264",
+        "width": 854,
+        "height": 480,
+        "avg_frame_rate": "15/1",
+        "duration": "5.000000",
+        "nb_frames": "75"
+    }
+}
\ No newline at end of file
diff --git a/tests/test_scene_rendering/simple_scenes.py b/tests/test_scene_rendering/simple_scenes.py
--- a/tests/test_scene_rendering/simple_scenes.py
+++ b/tests/test_scene_rendering/simple_scenes.py
@@ -15,3 +15,15 @@ def construct(self):
         for i in range(10):
             number.become(Integer(i))
             self.play(Animation(number))
+
+
+class SceneWithMultipleWaitCalls(Scene):
+    def construct(self):
+        self.play(ShowCreation(Square()))
+        self.wait(1)
+        self.play(ShowCreation(Square().shift(DOWN)))
+        self.wait(1)
+        self.play(ShowCreation(Square().shift(2 * DOWN)))
+        self.wait(1)
+        self.play(ShowCreation(Square().shift(3 * DOWN)))
+        self.wait(1)
diff --git a/tests/test_scene_rendering/test_caching_relalted.py b/tests/test_scene_rendering/test_caching_relalted.py
new file mode 100644
--- /dev/null
+++ b/tests/test_scene_rendering/test_caching_relalted.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
+
+
+@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