Video editing with Python
This report summarizes scanner evidence for Zulko/moviepy, a Python project with 14,968 GitHub stars. SynthScan examined 21,566 lines of code across 162 source files, recording 253 pattern matches distributed across 14 syntactic categories. The legacy adjusted pattern signal is 15.2 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 134 finding(s).
Are imports declared and package/API names verified? 87 finding(s).
Are wrappers, guards, and repeated structures necessary? 112 finding(s).
Which changes need focused human review? 253 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 253 distinct pattern matches across 14 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_VideoClip.py | 11 | CODE | |
| LOW | tests/test_videotools.py | 13 | CODE | |
| LOW | tests/test_compositing.py | 9 | CODE | |
| LOW | tests/test_TextClip.py | 9 | CODE | |
| LOW | tests/test_ffmpeg_writer.py | 10 | CODE | |
| LOW | tests/test_issues.py | 9 | CODE | |
| LOW | tests/test_PR.py | 8 | CODE | |
| LOW | tests/test_fx.py | 14 | CODE | |
| LOW | moviepy/__init__.py | 5 | CODE | |
| LOW | moviepy/__init__.py | 6 | CODE | |
| LOW | moviepy/__init__.py | 6 | CODE | |
| LOW | moviepy/__init__.py | 6 | CODE | |
| LOW | moviepy/__init__.py | 12 | CODE | |
| LOW | moviepy/__init__.py | 13 | CODE | |
| LOW | moviepy/__init__.py | 14 | CODE | |
| LOW | moviepy/__init__.py | 15 | CODE | |
| LOW | moviepy/__init__.py | 16 | CODE | |
| LOW | moviepy/__init__.py | 16 | CODE | |
| LOW | moviepy/__init__.py | 17 | CODE | |
| LOW | moviepy/__init__.py | 17 | CODE | |
| LOW | moviepy/__init__.py | 17 | CODE | |
| LOW | moviepy/__init__.py | 22 | CODE | |
| LOW | moviepy/__init__.py | 24 | CODE | |
| LOW | moviepy/__init__.py | 25 | CODE | |
| LOW | moviepy/__init__.py | 26 | CODE | |
| LOW | moviepy/__init__.py | 26 | CODE | |
| LOW | moviepy/__init__.py | 26 | CODE | |
| LOW | moviepy/__init__.py | 26 | CODE | |
| LOW | moviepy/__init__.py | 26 | CODE | |
| LOW | moviepy/__init__.py | 26 | CODE | |
| LOW | moviepy/Clip.py | 16 | CODE | |
| LOW | moviepy/video/VideoClip.py | 23 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 5 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 6 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 7 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 8 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 9 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 10 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 11 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 12 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 13 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 14 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 15 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 16 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 17 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 18 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 19 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 20 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 21 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 22 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 23 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 24 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 25 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 26 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 27 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 28 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 29 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 30 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 31 | CODE | |
| LOW | moviepy/video/fx/__init__.py | 32 | CODE | |
| 26 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_VideoClip.py | 77 | def test_write_frame_errors_with_redirected_logs(util, video): | CODE |
| LOW | tests/test_VideoClip.py | 97 | def test_write_videofiles_with_temp_audiofile_path(util): | CODE |
| LOW | tests/test_VideoClip.py | 109 | def test_write_videofiles_audio_codec_error(util, video): | CODE |
| LOW | tests/test_VideoClip.py | 189 | def test_write_image_sequence(util, video): | CODE |
| LOW | tests/test_VideoClip.py | 245 | def test_setaudio_with_audiofile(util): | CODE |
| LOW | tests/test_VideoClip.py | 281 | def test_compositing_with_same_layers(): | CODE |
| LOW | tests/test_VideoClip.py | 306 | def test_setfps_withoutchangeduration(video): | CODE |
| LOW | tests/test_VideoClip.py | 318 | def test_setfps_withchangeduration(video): | CODE |
| LOW | tests/test_VideoClip.py | 330 | def test_copied_videoclip_write_videofile(util): | CODE |
| LOW | tests/test_videotools.py | 1077 | def test_ipython_display_not_available(): | STRING |
| LOW | tests/conftest.py | 81 | def get_functions_with_decorator_defined(code, decorator_name): | CODE |
| LOW | tests/conftest.py | 178 | def functions_with_decorator_defined(): | CODE |
| LOW | tests/test_compositing.py | 47 | def test_clips_array_duration(util): | CODE |
| LOW | tests/test_compositing.py | 78 | def test_concatenate_floating_point(util): | CODE |
| LOW | tests/test_compositing.py | 142 | def test_compositing_with_transparency_colors(util): | CODE |
| LOW | tests/test_compositing.py | 300 | def test_concatenate_with_masks(util): | CODE |
| LOW | tests/test_SubtitlesClip.py | 63 | def test_file_to_subtitles_unicode(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 52 | def test_ffmpeg_parse_infos_video_nframes(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 60 | def test_ffmpeg_parse_infos_no_default_stream(util): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 103 | def test_ffmpeg_parse_infos_decode_file(decode_file, expected_duration): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 136 | def test_ffmpeg_parse_infos_multiple_audio_streams(util, mono_wave): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 204 | def test_ffmpeg_parse_infos_metadata(util, mono_wave): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 258 | def get_value_from_dict_using_lower_key(field, dictionary): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 292 | def test_ffmpeg_parse_infos_chapters(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 309 | def test_ffmpeg_parse_infos_metadata_with_attached_pic(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 330 | def test_ffmpeg_parse_video_rotation(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 336 | def test_correct_video_rotation(util): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 351 | def test_ffmpeg_parse_infos_multiline_metadata(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 520 | def test_not_default_audio_stream_audio_bitrate(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 557 | def test_stream_square_brackets(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 573 | def test_stream_square_brackets_and_language(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 589 | def test_stream_missing_audio_bitrate(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 605 | def test_sequential_frame_pos(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 634 | def test_unusual_order_frame_pos(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 659 | def test_large_skip_frame_pos(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 675 | def test_large_small_skip_equal(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 704 | def test_seeking_beyond_file_end(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 724 | def test_release_of_file_via_close(util): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 759 | def test_failure_to_release_file(util): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 817 | def test_read_transparent_video(): | CODE |
| LOW | tests/test_ffmpeg_reader.py | 533 | def test_stream_deidentation_not_raises_error(): | STRING |
| LOW | tests/test_TextClip.py | 23 | def test_text_filename_arguments_consistence(util): | CODE |
| LOW | tests/test_TextClip.py | 64 | def test_no_text_nor_filename_arguments(method, util): | CODE |
| LOW | tests/test_ffmpeg_writer.py | 258 | def test_write_file_with_spaces(util): | CODE |
| LOW | tests/test_VideoFileClip.py | 50 | def test_copied_videofileclip_write_videofile(util): | CODE |
| LOW | tests/test_VideoFileClip.py | 71 | def test_videofileclip_safe_deepcopy(monkeypatch): | CODE |
| LOW | tests/test_VideoFileClip.py | 89 | def test_ffmpeg_transparency_mask(util): | CODE |
| LOW | tests/test_VideoFileClip.py | 104 | def test_no_duration_raise_io_error(): | CODE |
| LOW | tests/test_VideoFileClip.py | 112 | def test_no_duration_re_encode_can_be_opened(util): | CODE |
| LOW | tests/test_ffmpeg_tools.py | 17 | def test_ffmpeg_extract_subclip(util): | CODE |
| LOW | tests/test_ffmpeg_tools.py | 77 | def test_ffmpeg_stabilize_video(util): | CODE |
| LOW | tests/test_tools.py | 30 | def test_find_extensions_not_found(): | CODE |
| LOW⚡ | tests/test_tools.py | 78 | def test_ffmpeg_escape_filename(given, expected): | CODE |
| LOW⚡ | tests/test_tools.py | 86 | def test_cross_platform_popen_params(os_name, monkeypatch): | CODE |
| LOW⚡ | tests/test_tools.py | 95 | def test_deprecated_version_of(old_name): | CODE |
| LOW | tests/test_tools.py | 189 | def test_decorators_argument_converters_consistency( | CODE |
| LOW | tests/test_AudioClips.py | 54 | def test_concatenate_audioclips_render(util, mono_wave): | CODE |
| LOW | tests/test_AudioClips.py | 147 | def test_concatenate_audioclip_with_audiofileclip(util, stereo_wave): | CODE |
| LOW | tests/test_AudioClips.py | 164 | def test_concatenate_audiofileclips(util): | CODE |
| LOW | tests/test_AudioClips.py | 179 | def test_audioclip_mono_max_volume(mono_wave): | CODE |
| 11 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/test_VideoClip.py | 152 | except PermissionError: | CODE |
| HIGH | tests/test_videotools.py | 361 | except PermissionError: | CODE |
| HIGH | tests/test_videotools.py | 908 | except PermissionError: | CODE |
| HIGH | tests/test_ffmpeg_writer.py | 61 | except PermissionError: | CODE |
| HIGH | tests/test_ffmpeg_writer.py | 141 | except PermissionError: | CODE |
| HIGH | tests/test_ffmpeg_writer.py | 192 | except PermissionError: | CODE |
| HIGH | tests/test_ffmpeg_tools.py | 47 | except PermissionError: | CODE |
| HIGH | tests/test_ffmpeg_tools.py | 73 | except PermissionError: | CODE |
| HIGH | tests/test_ffmpeg_tools.py | 117 | except PermissionError: | CODE |
| HIGH | moviepy/video/io/VideoFileClip.py | 179 | except AttributeError: # pragma: no cover | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/conftest.py | 81 | CODE | |
| LOW | tests/conftest.py | 101 | CODE | |
| LOW | tests/test_compositing.py | 182 | CODE | |
| LOW | tests/test_compositing.py | 244 | CODE | |
| LOW | tests/test_tools.py | 189 | CODE | |
| LOW | tests/test_fx.py | 22 | CODE | |
| LOW | tests/test_fx.py | 738 | CODE | |
| LOW | moviepy/video/VideoClip.py | 1436 | CODE | |
| LOW | moviepy/video/VideoClip.py | 1534 | CODE | |
| LOW | moviepy/video/tools/subtitles.py | 177 | CODE | |
| LOW | moviepy/video/tools/drawing.py | 177 | CODE | |
| LOW | moviepy/video/tools/credits.py | 79 | CODE | |
| LOW | moviepy/video/tools/cuts.py | 201 | CODE | |
| LOW | moviepy/video/fx/Resize.py | 58 | CODE | |
| LOW | moviepy/video/fx/Rotate.py | 162 | CODE | |
| LOW | moviepy/video/fx/Rotate.py | 180 | CODE | |
| LOW | moviepy/video/io/ffplay_previewer.py | 91 | CODE | |
| LOW | moviepy/video/io/ffmpeg_writer.py | 262 | CODE | |
| LOW | moviepy/video/io/ffmpeg_writer.py | 181 | CODE | |
| LOW | moviepy/video/io/ffmpeg_reader.py | 23 | CODE | |
| LOW | moviepy/video/io/ffmpeg_reader.py | 411 | CODE | |
| LOW | moviepy/video/io/ffmpeg_reader.py | 464 | CODE | |
| LOW | moviepy/video/io/ffmpeg_reader.py | 676 | CODE | |
| LOW | moviepy/video/io/ffmpeg_reader.py | 739 | CODE | |
| LOW | moviepy/video/io/display_in_notebook.py | 54 | CODE | |
| LOW | moviepy/audio/io/ffplay_audiopreviewer.py | 113 | CODE | |
| LOW | moviepy/audio/io/ffmpeg_audiowriter.py | 108 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | moviepy/video/io/ffplay_previewer.py | 0 | closes the writer, terminating the subprocess if is still alive. | STRING |
| HIGH | moviepy/video/io/ffmpeg_writer.py | 0 | closes the writer, terminating the subprocess if is still alive. | STRING |
| HIGH | moviepy/audio/io/ffplay_audiopreviewer.py | 0 | closes the writer, terminating the subprocess if is still alive. | STRING |
| HIGH | moviepy/audio/io/ffmpeg_audiowriter.py | 0 | closes the writer, terminating the subprocess if is still alive. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | moviepy/video/VideoClip.py | 169 | # =============================================================== | COMMENT |
| MEDIUM | moviepy/video/VideoClip.py | 527 | # =============================================================== | COMMENT |
| MEDIUM | moviepy/video/VideoClip.py | 640 | # ----------------------------------------------------------------- | COMMENT |
| MEDIUM | moviepy/video/VideoClip.py | 682 | # -------------------------------------------------------------- | COMMENT |
| MEDIUM | moviepy/video/VideoClip.py | 1208 | # -------------------------------------------------------------- | COMMENT |
| MEDIUM | moviepy/video/VideoClip.py | 1243 | # ---------------------------------------------------------------- | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | moviepy/video/VideoClip.py | 861 | # Again to understand the math, consider the following to calculate the final mask | COMMENT |
| LOW | moviepy/video/VideoClip.py | 941 | x1_clip = max(-x_start, 0) | COMMENT |
| LOW | docs/conf.py | 41 | COMMENT | |
| LOW | docs/conf.py | 61 | COMMENT | |
| LOW | docs/conf.py | 81 | COMMENT | |
| LOW | docs/conf.py | 141 | COMMENT | |
| LOW | docs/conf.py | 161 | ] | COMMENT |
| LOW | docs/conf.py | 181 | # If false, no index is generated. | COMMENT |
| LOW | docs/conf.py | 201 | # This is the file name suffix for HTML files (e.g. ".xhtml"). | COMMENT |
| LOW | docs/conf.py | 221 | latex_documents = [ | COMMENT |
| LOW | docs/conf.py | 241 | COMMENT | |
| LOW | docs/conf.py | 301 | # The unique identifier of the text. This can be a ISBN number | COMMENT |
| LOW | docs/conf.py | 321 | COMMENT | |
| LOW | …_static/code/user_guide/effects/modify_copy_example.py | 1 | # Import everything needed to edit video clips | COMMENT |
| LOW | …tic/code/getting_started/moviepy_10_minutes/trailer.py | 41 | COMMENT | |
| LOW | …tic/code/getting_started/moviepy_10_minutes/trailer.py | 261 | # Lets finish by modifying our rambo clip to make it sepia | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_ffmpeg_reader.py | 725 | # Create a random video file. | COMMENT |
| MEDIUM | tests/test_ffmpeg_reader.py | 774 | # Create a random video file. | COMMENT |
| MEDIUM | moviepy/video/fx/HeadBlur.py | 32 | # Create a mask for the blur area | COMMENT |
| MEDIUM | moviepy/video/fx/Painting.py | 45 | # Create the darkening effect | COMMENT |
| MEDIUM | docs/_static/code/user_guide/loading/AudioArrayClip.py | 31 | # Create an AudioArrayClip from the audio samples | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | moviepy/config.py | 32 | except Exception as err: | CODE |
| LOW | moviepy/version.py | 5 | except Exception: | CODE |
| LOW | moviepy/video/tools/subtitles.py | 134 | except Exception: | CODE |
| LOW | moviepy/video/tools/subtitles.py | 140 | except Exception: | CODE |
| MEDIUM | moviepy/video/tools/subtitles.py | 131 | def is_in_subclip(t1, t2): | CODE |
| MEDIUM | moviepy/video/tools/subtitles.py | 137 | def try_cropping(t1, t2): | CODE |
| LOW | moviepy/video/io/ffmpeg_reader.py | 523 | except Exception: | CODE |
| LOW | moviepy/video/io/ffmpeg_reader.py | 592 | except Exception: | CODE |
| LOW | moviepy/video/io/ffmpeg_reader.py | 924 | except Exception as exc: | CODE |
| LOW | moviepy/video/io/display_in_notebook.py | 163 | except Exception: | CODE |
| LOW | docs/_static/code/user_guide/loading/closing.py | 8 | except Exception as e: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | moviepy/video/VideoClip.py | 208 | CODE | |
| LOW | moviepy/video/VideoClip.py | 1176 | CODE | |
| LOW | moviepy/video/VideoClip.py | 1666 | CODE | |
| LOW | moviepy/video/tools/drawing.py | 177 | CODE | |
| LOW | moviepy/video/io/ffmpeg_writer.py | 262 | CODE | |
| LOW | moviepy/video/io/ffmpeg_writer.py | 85 | CODE | |
| LOW | moviepy/video/io/ffmpeg_reader.py | 23 | CODE | |
| LOW | moviepy/video/io/VideoFileClip.py | 91 | CODE | |
| LOW | moviepy/audio/AudioClip.py | 184 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_fx.py | 943 | # Check if the pixel at the specified position matches the expected color | COMMENT |
| LOW | moviepy/video/VideoClip.py | 2102 | # Check if the last font size tested fits within the given width and height | COMMENT |
| LOW | moviepy/video/io/ffmpeg_tools.py | 234 | # Check if the input file exists | COMMENT |
| LOW | moviepy/video/io/ffmpeg_reader.py | 889 | # Open the file in a pipe, read output | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | moviepy/video/io/ffmpeg_reader.py | 275 | # go to the previous integer. This makes the fetching more robust when you | COMMENT |
| LOW | docs/_static/code/user_guide/loading/masks.py | 9 | # To define the VideoClip as a mask, just pass parameter is_mask as True | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | moviepy/__init__.py | 43 | __all__ = [ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | media/doc_medias/example.txt | 1 | Lorem ipsum | CODE |