From a3efe9f83cf0eb822c2c279d6c47f44b44436bc3 Mon Sep 17 00:00:00 2001 From: Mark Beacom Date: Mon, 17 Apr 2017 07:33:26 -0400 Subject: [PATCH 01/15] General tests cleanup --- tests/test_ImageSequenceClip.py | 13 ++-- tests/test_examples.py | 16 ++--- tests/test_ffmpeg_reader.py | 10 +-- tests/test_fx.py | 29 ++++---- tests/test_helper.py | 1 - tests/test_issues.py | 124 +++++++++++++++++++++----------- tests/test_misc.py | 21 +++--- 7 files changed, 130 insertions(+), 84 deletions(-) diff --git a/tests/test_ImageSequenceClip.py b/tests/test_ImageSequenceClip.py index 79473f330..b74a63bec 100644 --- a/tests/test_ImageSequenceClip.py +++ b/tests/test_ImageSequenceClip.py @@ -1,11 +1,14 @@ +"""Image sequencing clip tests meant to be run with pytest.""" +import sys + import pytest -from moviepy.editor import * +from moviepy.video.io import ImageSequenceClip -# must have to work on travis-ci -import sys -sys.path.append("tests") import download_media +sys.path.append("tests") + + def test_download_media(capsys): with capsys.disabled(): download_media.download() @@ -19,7 +22,7 @@ def test_1(): durations.append(i) images.append("media/matplotlib_demo1.png") - clip=ImageSequenceClip(images, durations=durations) + clip = ImageSequenceClip(images, durations=durations) assert clip.duration == sum(durations) clip.write_videofile("/tmp/ImageSequenceClip1.mp4", fps=30) diff --git a/tests/test_examples.py b/tests/test_examples.py index 3b81101b7..b9bc52355 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,24 +1,22 @@ -import pytest -from moviepy.editor import * -import moviepy.video.tools.cuts as cuts - import os import sys -sys.path.append("tests") + +import pytest + import download_media from test_helper import PYTHON_VERSION, TMP_DIR, TRAVIS +sys.path.append("tests") + + def test_download_media(capsys): with capsys.disabled(): download_media.download() def test_matplotlib(): - if PYTHON_VERSION in ('2.7', '3.3'): - return - #for now, python 3.5 installs a version of matplotlib that complains #about $DISPLAY variable, so lets just ignore for now. - if PYTHON_VERSION == '3.5' and TRAVIS: + if PYTHON_VERSION in ('2.7', '3.3') or (PYTHON_VERSION == '3.5' and TRAVIS): return import matplotlib.pyplot as plt diff --git a/tests/test_ffmpeg_reader.py b/tests/test_ffmpeg_reader.py index d7ac41d5f..9b8c64968 100644 --- a/tests/test_ffmpeg_reader.py +++ b/tests/test_ffmpeg_reader.py @@ -1,12 +1,14 @@ -import pytest -from moviepy.editor import * +"""FFmpeg reader tests meant to be run with pytest.""" +import sys +import pytest from moviepy.video.io.ffmpeg_reader import ffmpeg_parse_infos -import sys -sys.path.append("tests") import download_media +sys.path.append("tests") + + def test_download_media(capsys): with capsys.disabled(): download_media.download() diff --git a/tests/test_fx.py b/tests/test_fx.py index 6e29d0576..4a82d19ca 100644 --- a/tests/test_fx.py +++ b/tests/test_fx.py @@ -1,18 +1,19 @@ -import pytest -from moviepy.editor import * +import os +import sys -from moviepy.video.fx.crop import crop +import pytest from moviepy.video.fx.blackwhite import blackwhite -from moviepy.video.fx.blink import blink +# from moviepy.video.fx.blink import blink from moviepy.video.fx.colorx import colorx +from moviepy.video.fx.crop import crop from moviepy.video.fx.fadein import fadein from moviepy.video.fx.fadeout import fadeout +from moviepy.video.VideoClip import VideoFileClip -import os -import sys -sys.path.append("tests") import download_media -from test_helper import TRAVIS, TMP_DIR +from test_helper import TMP_DIR + +sys.path.append("tests") def test_download_media(capsys): @@ -24,19 +25,17 @@ def test_blackwhite(): clip1 = blackwhite(clip) clip1.write_videofile(os.path.join(TMP_DIR,"blackwhite1.webm")) -def test_blink(): - #this currently fails with a with_mask error! - return - clip = VideoFileClip("media/big_buck_bunny_0_30.webm").subclip(0,10) - clip1 = blink(clip, 1, 1) - clip1.write_videofile(os.path.join(TMP_DIR,"blink1.webm")) +# This currently fails with a with_mask error! +# def test_blink(): +# clip = VideoFileClip("media/big_buck_bunny_0_30.webm").subclip(0,10) +# clip1 = blink(clip, 1, 1) +# clip1.write_videofile(os.path.join(TMP_DIR,"blink1.webm")) def test_colorx(): clip = VideoFileClip("media/big_buck_bunny_432_433.webm") clip1 = colorx(clip, 2) clip1.write_videofile(os.path.join(TMP_DIR,"colorx1.webm")) - def test_crop(): clip = VideoFileClip("media/big_buck_bunny_432_433.webm") diff --git a/tests/test_helper.py b/tests/test_helper.py index de0765938..9b6f33c18 100644 --- a/tests/test_helper.py +++ b/tests/test_helper.py @@ -4,4 +4,3 @@ TRAVIS=os.getenv("TRAVIS_PYTHON_VERSION") is not None PYTHON_VERSION = "%s.%s" % (sys.version_info.major, sys.version_info.minor) TMP_DIR="/tmp" - diff --git a/tests/test_issues.py b/tests/test_issues.py index a854d9c40..b804e8304 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -1,25 +1,29 @@ -""" -Tests meant to be run with pytest -""" - +"""Issue tests meant to be run with pytest.""" import os -import pytest +import sys -from moviepy.editor import * +import pytest +from moviepy.audio.io.AudioFileClip import AudioFileClip +from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip +from moviepy.video.compositing.concatenate import concatenate_videoclips +from moviepy.video.fx import blink, resize +from moviepy.video.io.VideoFileClip import VideoFileClip +from moviepy.video.VideoClip import ColorClip, ImageClip, VideoClip -import sys -sys.path.append("tests") import download_media from test_helper import PYTHON_VERSION, TMP_DIR, TRAVIS +sys.path.append("tests") + + def test_download_media(capsys): with capsys.disabled(): download_media.download() def test_issue_145(): video = ColorClip((800, 600), color=(255,0,0)).set_duration(5) - with pytest.raises(Exception, message="Expecting Exception"): - final = concatenate_videoclips([video], method = 'composite') + with pytest.raises(Exception, message='Expecting Exception'): + concatenate_videoclips([video], method='composite') def test_issue_285(): clip_1 = ImageClip('media/python_logo.png', duration=10) @@ -29,15 +33,55 @@ def test_issue_285(): merged_clip = concatenate_videoclips([clip_1, clip_2, clip_3]) assert merged_clip.duration == 30 - def test_issue_334(): last_move = None last_move1 = None - lis = [(0.0, 113, 167, 47), (0.32, 138, 159, 47), (0.44, 152, 144, 47), (0.48, 193, 148, 47), (0.6, 193, 148, 47), (0.76, 205, 138, 55), (0.88, 204, 121, 63), (0.92, 190, 31, 127), (1.2, 183, 59, 127), (1.4, 137, 22, 127), (1.52, 137, 22, 127), (1.72, 129, 67, 127), (1.88, 123, 69, 127), (2.04, 131, 123, 63), (2.24, 130, 148, 63), (2.48, 130, 148, 63), (2.8, 138, 180, 63), (3.0, 138, 180, 63), (3.2, 146, 192, 63), (3.28, 105, 91, 151), (3.44, 105, 91, 151), (3.72, 11, 48, 151), (3.96, 5, 78, 151), (4.32, 4, 134, 1), (4.6, 149, 184, 48), (4.8, 145, 188, 48), (5.0, 154, 217, 48), (5.08, 163, 199, 48), (5.2, 163, 199, 48), (5.32, 164, 187, 48), (5.48, 163, 200, 48), (5.76, 163, 200, 48), (5.96, 173, 199, 48), (6.0, 133, 172, 48), (6.04, 128, 165, 48), (6.28, 128, 165, 48), (6.4, 129, 180, 48), (6.52, 133, 166, 48), (6.64, 133, 166, 48), (6.88, 144, 183, 48), (7.0, 153, 174, 48), (7.16, 153, 174, 48), (7.24, 153, 174, 48), (7.28, 253, 65, 104), (7.64, 253, 65, 104), (7.8, 279, 116, 80), (8.0, 290, 105, 80), (8.24, 288, 124, 80), (8.44, 243, 102, 80), (8.56, 243, 102, 80), (8.8, 202, 107, 80), (8.84, 164, 27, 104), (9.0, 164, 27, 104), (9.12, 121, 9, 104), (9.28, 77, 33, 104), (9.32, 52, 23, 104), (9.48, 52, 23, 104), (9.64, 33, 46, 104), (9.8, 93, 49, 104), (9.92, 93, 49, 104), (10.16, 173, 19, 104), (10.2, 226, 173, 48), (10.36, 226, 173, 48), (10.48, 211, 172, 48), (10.64, 208, 162, 48), (10.92, 220, 171, 48)] - - lis1 = [(0.0, 113, 167, 47), (0.32, 138, 159, 47), (0.44, 152, 144, 47), (0.48, 193, 148, 47), (0.6, 193, 148, 47), (0.76, 205, 138, 55), (0.88, 204, 121, 63), (0.92, 190, 31, 127), (1.2, 183, 59, 127), (1.4, 137, 22, 127), (1.52, 137, 22, 127), (1.72, 129, 67, 127), (1.88, 123, 69, 127), (2.04, 131, 123, 63), (2.24, 130, 148, 63), (2.48, 130, 148, 63), (2.8, 138, 180, 63), (3.0, 138, 180, 63), (3.2, 146, 192, 63), (3.28, 105, 91, 151), (3.44, 105, 91, 151), (3.72, 11, 48, 151), (3.96, 5, 78, 151), (4.32, 4, 134, 1), (4.6, 149, 184, 48), (4.8, 145, 188, 48), (5.0, 154, 217, 48), (5.08, 163, 199, 48), (5.2, 163, 199, 48), (5.32, 164, 187, 48), (5.48, 163, 200, 48), (5.76, 163, 200, 48), (5.96, 173, 199, 48), (6.0, 133, 172, 48), (6.04, 128, 165, 48), (6.28, 128, 165, 48), (6.4, 129, 180, 48), (6.52, 133, 166, 48), (6.64, 133, 166, 48), (6.88, 144, 183, 48), (7.0, 153, 174, 48), (7.16, 153, 174, 48), (7.24, 153, 174, 48), (7.28, 253, 65, 104), (7.64, 253, 65, 104), (7.8, 279, 116, 80), (8.0, 290, 105, 80), (8.24, 288, 124, 80), (8.44, 243, 102, 80), (8.56, 243, 102, 80), (8.8, 202, 107, 80), (8.84, 164, 27, 104), (9.0, 164, 27, 104), (9.12, 121, 9, 104), (9.28, 77, 33, 104), (9.32, 52, 23, 104), (9.48, 52, 23, 104), (9.64, 33, 46, 104), (9.8, 93, 49, 104), (9.92, 93, 49, 104), (10.16, 173, 19, 104), (10.2, 226, 173, 48), (10.36, 226, 173, 48), (10.48, 211, 172, 48), (10.64, 208, 162, 48), (10.92, 220, 171, 48)] - + lis = [(0.0, 113, 167, 47), (0.32, 138, 159, 47), (0.44, 152, 144, 47), + (0.48, 193, 148, 47), (0.6, 193, 148, 47), (0.76, 205, 138, 55), + (0.88, 204, 121, 63), (0.92, 190, 31, 127), (1.2, 183, 59, 127), + (1.4, 137, 22, 127), (1.52, 137, 22, 127), (1.72, 129, 67, 127), + (1.88, 123, 69, 127), (2.04, 131, 123, 63), (2.24, 130, 148, 63), + (2.48, 130, 148, 63), (2.8, 138, 180, 63), (3.0, 138, 180, 63), + (3.2, 146, 192, 63), (3.28, 105, 91, 151), (3.44, 105, 91, 151), + (3.72, 11, 48, 151), (3.96, 5, 78, 151), (4.32, 4, 134, 1), + (4.6, 149, 184, 48), (4.8, 145, 188, 48), (5.0, 154, 217, 48), + (5.08, 163, 199, 48), (5.2, 163, 199, 48), (5.32, 164, 187, 48), + (5.48, 163, 200, 48), (5.76, 163, 200, 48), (5.96, 173, 199, 48), + (6.0, 133, 172, 48), (6.04, 128, 165, 48), (6.28, 128, 165, 48), + (6.4, 129, 180, 48), (6.52, 133, 166, 48), (6.64, 133, 166, 48), + (6.88, 144, 183, 48), (7.0, 153, 174, 48), (7.16, 153, 174, 48), + (7.24, 153, 174, 48), (7.28, 253, 65, 104), (7.64, 253, 65, 104), + (7.8, 279, 116, 80), (8.0, 290, 105, 80), (8.24, 288, 124, 80), + (8.44, 243, 102, 80), (8.56, 243, 102, 80), (8.8, 202, 107, 80), + (8.84, 164, 27, 104), (9.0, 164, 27, 104), (9.12, 121, 9, 104), + (9.28, 77, 33, 104), (9.32, 52, 23, 104), (9.48, 52, 23, 104), + (9.64, 33, 46, 104), (9.8, 93, 49, 104), (9.92, 93, 49, 104), + (10.16, 173, 19, 104), (10.2, 226, 173, 48), (10.36, 226, 173, 48), + (10.48, 211, 172, 48), (10.64, 208, 162, 48), (10.92, 220, 171, 48)] + + lis1 = [(0.0, 113, 167, 47), (0.32, 138, 159, 47), (0.44, 152, 144, 47), + (0.48, 193, 148, 47), (0.6, 193, 148, 47), (0.76, 205, 138, 55), + (0.88, 204, 121, 63), (0.92, 190, 31, 127), (1.2, 183, 59, 127), + (1.4, 137, 22, 127), (1.52, 137, 22, 127), (1.72, 129, 67, 127), + (1.88, 123, 69, 127), (2.04, 131, 123, 63), (2.24, 130, 148, 63), + (2.48, 130, 148, 63), (2.8, 138, 180, 63), (3.0, 138, 180, 63), + (3.2, 146, 192, 63), (3.28, 105, 91, 151), (3.44, 105, 91, 151), + (3.72, 11, 48, 151), (3.96, 5, 78, 151), (4.32, 4, 134, 1), + (4.6, 149, 184, 48), (4.8, 145, 188, 48), (5.0, 154, 217, 48), + (5.08, 163, 199, 48), (5.2, 163, 199, 48), (5.32, 164, 187, 48), + (5.48, 163, 200, 48), (5.76, 163, 200, 48), (5.96, 173, 199, 48), + (6.0, 133, 172, 48), (6.04, 128, 165, 48), (6.28, 128, 165, 48), + (6.4, 129, 180, 48), (6.52, 133, 166, 48), (6.64, 133, 166, 48), + (6.88, 144, 183, 48), (7.0, 153, 174, 48), (7.16, 153, 174, 48), + (7.24, 153, 174, 48), (7.28, 253, 65, 104), (7.64, 253, 65, 104), + (7.8, 279, 116, 80), (8.0, 290, 105, 80), (8.24, 288, 124, 80), + (8.44, 243, 102, 80), (8.56, 243, 102, 80), (8.8, 202, 107, 80), + (8.84, 164, 27, 104), (9.0, 164, 27, 104), (9.12, 121, 9, 104), + (9.28, 77, 33, 104), (9.32, 52, 23, 104), (9.48, 52, 23, 104), + (9.64, 33, 46, 104), (9.8, 93, 49, 104), (9.92, 93, 49, 104), + (10.16, 173, 19, 104), (10.2, 226, 173, 48), (10.36, 226, 173, 48), + (10.48, 211, 172, 48), (10.64, 208, 162, 48), (10.92, 220, 171, 48)] def posi(t): global last_move @@ -74,17 +118,15 @@ def size(t): return (nsw, nsh) return (last_move1[3], last_move1[3] * 1.33) - avatar = VideoFileClip("media/big_buck_bunny_432_433.webm", has_mask=True) avatar.audio=None maskclip = ImageClip("media/afterimage.png", ismask=True, transparent=True) avatar.set_mask(maskclip) #must set maskclip here.. - avatar = concatenate([avatar]*11) + avatar = concatenate_videoclips([avatar]*11) tt = VideoFileClip("media/big_buck_bunny_0_30.webm").subclip(0,11) - #setting mask here does not work. - #final = CompositeVideoClip([tt, avatar.set_position(posi).set_mask(maskclip).resize(size)]) + # TODO: Setting mask here does not work: .set_mask(maskclip).resize(size)]) final = CompositeVideoClip([tt, avatar.set_position(posi).resize(size)]) final.duration = tt.duration final.write_videofile(os.path.join(TMP_DIR, 'issue_334.mp4'), fps=24) @@ -95,10 +137,16 @@ def test_issue_354(): clip.duration = 10 crosstime = 1 - #caption = editor.TextClip("test text", font="Liberation-Sans-Bold", color='white', stroke_color='gray', stroke_width=2, method='caption', size=(1280, 720), fontsize=60, align='South-East') + # TODO: Should this be removed? + # caption = editor.TextClip("test text", font="Liberation-Sans-Bold", + # color='white', stroke_color='gray', + # stroke_width=2, method='caption', + # size=(1280, 720), fontsize=60, + # align='South-East') #caption.duration = clip.duration + fadecaption = clip.crossfadein(crosstime).crossfadeout(crosstime) - ret = CompositeVideoClip([clip, fadecaption]) + CompositeVideoClip([clip, fadecaption]) def test_issue_359(): video = ColorClip((800, 600), color=(255,0,0)).set_duration(5) @@ -107,12 +155,8 @@ def test_issue_359(): tempfiles=True) def test_issue_368(): - import sys - if PYTHON_VERSION in ('2.7', '3.3'): #matplotlib only supported in python >= 3.4 - return - - #travis, python 3.5 matplotlib version has problems.. - if PYTHON_VERSION == '3.5' and TRAVIS: + # Matplotlib only supported in python >= 3.4 and Travis/3.5 fails. + if PYTHON_VERSION in ('2.7', '3.3') or (PYTHON_VERSION == '3.5' and TRAVIS): return import numpy as np @@ -120,7 +164,6 @@ def test_issue_368(): from sklearn import svm from sklearn.datasets import make_moons from moviepy.video.io.bindings import mplfig_to_npimage - import imageio X, Y = make_moons(50, noise=0.1, random_state=2) # semi-random data @@ -145,20 +188,21 @@ def make_frame(t): return mplfig_to_npimage(fig) - animation = VideoClip(make_frame,duration=2) - animation.write_gif(os.path.join(TMP_DIR, "svm.gif"),fps=20) + animation = VideoClip(make_frame, duration=2) + animation.write_gif(os.path.join(TMP_DIR, "svm.gif"), fps=20) def test_issue_407(): red = ColorClip((800, 600), color=(255,0,0)).set_duration(5) - red.fps=30 + red.fps = 30 + assert red.fps == 30 assert red.w == 800 assert red.h == 600 assert red.size == (800, 600) - #ColorClip has no fps attribute - green=ColorClip((640, 480), color=(0,255,0)).set_duration(2) - blue=ColorClip((640, 480), color=(0,0,255)).set_duration(2) + # ColorClip has no fps attribute. + green = ColorClip((640, 480), color=(0,255,0)).set_duration(2) + blue = ColorClip((640, 480), color=(0,0,255)).set_duration(2) assert green.w == blue.w == 640 assert green.h == blue.h == 480 @@ -174,16 +218,16 @@ def test_issue_407(): assert video.fps == red.fps def test_issue_416(): - green=ColorClip((640, 480), color=(0,255,0)).set_duration(2) #ColorClip has no fps attribute - video1=concatenate_videoclips([green]) + # ColorClip has no fps attribute. + green = ColorClip((640, 480), color=(0,255,0)).set_duration(2) + video1 = concatenate_videoclips([green]) assert video1.fps == None def test_issue_417(): # failed in python2 - cad = u'media/python_logo.png' - myclip = ImageClip(cad).fx(vfx.resize, newsize=[1280, 660]) - final = CompositeVideoClip([myclip], size=(1280, 720)) + myclip = ImageClip(cad).fx(resize, newsize=[1280, 660]) + CompositeVideoClip([myclip], size=(1280, 720)) #final.set_duration(7).write_videofile("test.mp4", fps=30) def test_issue_467(): @@ -191,7 +235,7 @@ def test_issue_467(): clip = ImageClip(cad) #caused an error, NameError: global name 'copy' is not defined - clip = clip.fx(vfx.blink, d_on=1, d_off=1) + clip = clip.fx(blink, d_on=1, d_off=1) def test_issue_470(): audio_clip = AudioFileClip('media/crunching.mp3') diff --git a/tests/test_misc.py b/tests/test_misc.py index dfeee7cb2..b52e4fe60 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1,12 +1,17 @@ -import pytest -from moviepy.editor import * -import moviepy.video.tools.cuts as cuts - import os import sys -sys.path.append("tests") + +import moviepy.video.tools.cuts as cuts +import pytest +from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip +from moviepy.video.compositing.concatenate import concatenate_videoclips +from moviepy.video.tools.subtitles import SubtitlesClip, file_to_subtitles +from moviepy.video.VideoClip import ColorClip, TextClip, VideoFileClip + import download_media -from test_helper import TRAVIS, TMP_DIR +from test_helper import TMP_DIR, TRAVIS + +sys.path.append("tests") def test_download_media(capsys): @@ -18,8 +23,6 @@ def test_cuts1(): cuts.find_video_period(clip) == pytest.approx(0.966666666667, 0.0001) def test_subtitles(): - from moviepy.video.tools.subtitles import SubtitlesClip - red = ColorClip((800, 600), color=(255,0,0)).set_duration(10) green = ColorClip((800, 600), color=(0,255,0)).set_duration(10) blue = ColorClip((800, 600), color=(0,0,255)).set_duration(10) @@ -50,8 +53,6 @@ def test_subtitles(): assert subtitles.subtitles == data def test_file_to_subtitles(): - from moviepy.video.tools.subtitles import file_to_subtitles - data = [([0.0, 4.0], 'Red!'), ([5.0, 9.0], 'More Red!'), ([10.0, 14.0], 'Green!'), ([15.0, 19.0], 'More Green!'), ([20.0, 24.0], 'Blue'), ([25.0, 29.0], 'More Blue!')] From b0be36b0f41ff910868f021a3e0bb1aea6ac1407 Mon Sep 17 00:00:00 2001 From: Mark Beacom Date: Mon, 17 Apr 2017 07:41:27 -0400 Subject: [PATCH 02/15] More tests cleanup --- .gitignore | 1 + moviepy/video/VideoClip.py | 144 +++++++++---------------------------- tests/download_media.py | 71 ++++++++---------- tests/test_PR.py | 77 +++++++++++--------- tests/test_compositing.py | 9 ++- tests/test_examples.py | 4 +- 6 files changed, 117 insertions(+), 189 deletions(-) diff --git a/.gitignore b/.gitignore index 805b40e9e..9f7132ca8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ develop-eggs lib lib64 __pycache__ +.cache/ # Sublime .sublime-project diff --git a/moviepy/video/VideoClip.py b/moviepy/video/VideoClip.py index 5b0f6626a..bd231e219 100644 --- a/moviepy/video/VideoClip.py +++ b/moviepy/video/VideoClip.py @@ -4,44 +4,27 @@ - Animated clips: VideofileClip, ImageSequenceClip - Static image clips: ImageClip, ColorClip, TextClip, """ - import os import subprocess as sp -import multiprocessing import tempfile -from copy import copy import warnings -from tqdm import tqdm import numpy as np - from imageio import imread, imsave +from tqdm import tqdm -import moviepy.audio.io as aio -from .io.ffmpeg_writer import ffmpeg_write_image, ffmpeg_write_video -from .io.ffmpeg_tools import ffmpeg_merge_video_audio -from .io.gif_writers import (write_gif, - write_gif_with_tempfiles, - write_gif_with_image_io) -from .tools.drawing import blit from ..Clip import Clip +from ..compat import DEVNULL, PY3 from ..config import get_setting - -from ..tools import (subprocess_call, - verbose_print, - is_string, - deprecated_version_of, - extensions_dict, find_extension) - -from ..decorators import (apply_to_mask, - requires_duration, - outplace, - add_mask_if_none, - convert_to_seconds, - convert_masks_to_RGB, - use_clip_fps_by_default) - -from ..compat import PY3, DEVNULL +from ..decorators import (add_mask_if_none, apply_to_mask, + convert_masks_to_RGB, convert_to_seconds, outplace, + requires_duration, use_clip_fps_by_default) +from ..tools import (deprecated_version_of, extensions_dict, find_extension, + is_string, subprocess_call, verbose_print) +from .io.ffmpeg_writer import ffmpeg_write_video +from .io.gif_writers import (write_gif, write_gif_with_image_io, + write_gif_with_tempfiles) +from .tools.drawing import blit class VideoClip(Clip): @@ -107,26 +90,21 @@ def __init__(self, make_frame=None, ismask=False, duration=None, self.duration = duration self.end = duration - @property def w(self): return self.size[0] - @property def h(self): return self.size[1] - @property def aspect_ratio(self): return self.w / float(self.h) - # =============================================================== # EXPORT OPERATIONS - @convert_to_seconds(['t']) @convert_masks_to_RGB def save_frame(self, filename, t=0, withmask=True): @@ -151,7 +129,6 @@ def save_frame(self, filename, t=0, withmask=True): imsave(filename, im) - @requires_duration @use_clip_fps_by_default @convert_masks_to_RGB @@ -165,7 +142,6 @@ def write_videofile(self, filename, fps=None, codec=None, write_logfile=False, verbose=True, threads=None, ffmpeg_params=None, progress_bar=True): - """Write the clip to a videofile. Parameters @@ -261,7 +237,7 @@ def write_videofile(self, filename, fps=None, codec=None, If true, will write log files for the audio and the video. These will be files ending with '.log' with the name of the output file in them. - + verbose Boolean indicating whether to print infomation @@ -276,7 +252,6 @@ def write_videofile(self, filename, fps=None, codec=None, >>> clip.write_videofile("my_new_video.mp4") """ - name, ext = os.path.splitext(os.path.basename(filename)) ext = ext[1:].lower() @@ -353,7 +328,6 @@ def write_videofile(self, filename, fps=None, codec=None, verbose_print(verbose, "[MoviePy] >>>> Video ready: %s \n\n"%filename) - @requires_duration @use_clip_fps_by_default @convert_masks_to_RGB @@ -361,7 +335,6 @@ def write_images_sequence(self, nameformat, fps=None, verbose=True, withmask=True, progress_bar=True): """ Writes the videoclip to a sequence of image files. - Parameters ----------- @@ -399,7 +372,6 @@ def write_images_sequence(self, nameformat, fps=None, verbose=True, ``ImageSequenceClip``. """ - verbose_print(verbose, "[MoviePy] Writing frames %s." % (nameformat)) tt = np.arange(0, self.duration, 1.0 / fps) @@ -416,8 +388,6 @@ def write_images_sequence(self, nameformat, fps=None, verbose=True, return filenames - - @requires_duration @convert_masks_to_RGB def write_gif(self, filename, fps=None, program='imageio', @@ -428,7 +398,6 @@ def write_gif(self, filename, fps=None, program='imageio', Converts a VideoClip into an animated GIF using ImageMagick or ffmpeg. - Parameters ----------- @@ -466,7 +435,6 @@ def write_gif(self, filename, fps=None, program='imageio', >>> myClip.speedx(0.5).to_gif('myClip.gif') """ - # A little sketchy at the moment, maybe move all that in write_gif, # refactor a little... we will see. @@ -493,10 +461,8 @@ def write_gif(self, filename, fps=None, program='imageio', # ----------------------------------------------------------------- # F I L T E R I N G - - def subfx(self, fx, ta=0, tb=None, **kwargs): - """ Apply a transformation to a part of the clip. + """Apply a transformation to a part of the clip. Returns a new clip in which the function ``fun`` (clip->clip) has been applied to the subclip between times `ta` and `tb` @@ -510,7 +476,6 @@ def subfx(self, fx, ta=0, tb=None, **kwargs): >>> newclip = clip.subapply(lambda c:c.speedx(0.5) , 3,6) """ - left = None if (ta == 0) else self.subclip(0, ta) center = self.subclip(ta, tb).fx(fx, **kwargs) right = None if (tb is None) else self.subclip(t_start=tb) @@ -524,7 +489,6 @@ def subfx(self, fx, ta=0, tb=None, **kwargs): # IMAGE FILTERS - def fl_image(self, image_func, apply_to=[]): """ Modifies the images of a clip by replacing the frame @@ -535,7 +499,6 @@ def fl_image(self, image_func, apply_to=[]): # -------------------------------------------------------------- # C O M P O S I T I N G - def fill_array(self, pre_array, shape=(0, 0)): pre_shape = pre_array.shape dx = shape[0] - pre_shape[0] @@ -553,14 +516,12 @@ def fill_array(self, pre_array, shape=(0, 0)): post_array = np.hstack((post_array, x_1)) return post_array - def blit_on(self, picture, t): """ Returns the result of the blit of the clip's frame at time `t` on the given `picture`, the position of the clip being given by the clip's ``pos`` attribute. Meant for compositing. """ - hf, wf = framesize = picture.shape[:2] if self.ismask and picture.max() != 0: @@ -610,9 +571,8 @@ def blit_on(self, picture, t): return blit(img, picture, pos, mask=mask, ismask=self.ismask) - def add_mask(self): - """ Add a mask VideoClip to the VideoClip. + """Add a mask VideoClip to the VideoClip. Returns a copy of the clip with a completely opaque mask (made of ones). This makes computations slower compared to @@ -629,10 +589,9 @@ def add_mask(self): mask = VideoClip(ismask=True, make_frame=make_frame) return self.set_mask(mask.set_duration(self.duration)) - def on_color(self, size=None, color=(0, 0, 0), pos=None, col_opacity=None): - """ Place the clip on a colored background. + """Place the clip on a colored background. Returns a clip made of the current clip overlaid on a color clip of a possibly bigger size. Can serve to flatten transparent @@ -682,10 +641,9 @@ def on_color(self, size=None, color=(0, 0, 0), pos=None, return result - @outplace def set_make_frame(self, mf): - """ Change the clip's ``get_frame``. + """Change the clip's ``get_frame``. Returns a copy of the VideoClip instance, with the make_frame attribute set to `mf`. @@ -693,43 +651,39 @@ def set_make_frame(self, mf): self.make_frame = mf self.size = self.get_frame(0).shape[:2][::-1] - @outplace def set_audio(self, audioclip): - """ Attach an AudioClip to the VideoClip. + """Attach an AudioClip to the VideoClip. Returns a copy of the VideoClip instance, with the `audio` attribute set to ``audio``, which must be an AudioClip instance. """ self.audio = audioclip - @outplace def set_mask(self, mask): - """ Set the clip's mask. + """Set the clip's mask. Returns a copy of the VideoClip with the mask attribute set to ``mask``, which must be a greyscale (values in 0-1) VideoClip""" assert ( (mask is None) or mask.ismask ) self.mask = mask - @add_mask_if_none @outplace def set_opacity(self, op): - """ Set the opacity/transparency level of the clip. + """Set the opacity/transparency level of the clip. Returns a semi-transparent copy of the clip where the mask is multiplied by ``op`` (any float, normally between 0 and 1). """ - self.mask = self.mask.fl_image(lambda pic: op * pic) @apply_to_mask @outplace def set_position(self, pos, relative=False): - """ Set the clip's position in compositions. + """Set the clip's position in compositions. Sets the position that the clip will have when included in compositions. The argument ``pos`` can be either a couple @@ -752,19 +706,15 @@ def set_position(self, pos, relative=False): >>> clip.set_pos(lambda t: ('center', 50+t) ) """ - self.relative_pos = relative if hasattr(pos, '__call__'): self.pos = pos else: self.pos = lambda t: pos - #-------------------------------------------------------------- # CONVERSIONS TO OTHER TYPES - - @convert_to_seconds(['t']) def to_ImageClip(self, t=0, with_mask=True): """ @@ -779,9 +729,7 @@ def to_ImageClip(self, t=0, with_mask=True): def to_mask(self, canal=0): - """ - Returns a mask a video clip made from the clip. - """ + """Return a mask a video clip made from the clip.""" if self.ismask: return self else: @@ -790,11 +738,8 @@ def to_mask(self, canal=0): newclip.ismask = True return newclip - def to_RGB(self): - """ - Returns a non-mask video clip made from the mask video clip. - """ + """Return a non-mask video clip made from the mask video clip.""" if self.ismask: f = lambda pic: np.dstack(3 * [255 * pic]).astype('uint8') newclip = self.fl_image(f) @@ -806,20 +751,18 @@ def to_RGB(self): #---------------------------------------------------------------- # Audio - @outplace def without_audio(self): - """ Remove the clip's audio. + """Remove the clip's audio. Return a copy of the clip with audio set to None. """ self.audio = None - @outplace def afx(self, fun, *a, **k): - """ Transform the clip's audio. + """Transform the clip's audio. Return a new clip whose audio has been transformed by ``fun``. @@ -827,7 +770,6 @@ def afx(self, fun, *a, **k): self.audio = self.audio.fx(fun, *a, **k) - class DataVideoClip(VideoClip): """ Class of video clips whose successive frames are functions @@ -858,11 +800,8 @@ def __init__(self, data, data_to_frame, fps, ismask=False, duration=1.0*len(data)/fps, has_constant_size=has_constant_size) - - class UpdatedVideoClip(VideoClip): """ - Class of clips whose make_frame requires some objects to be updated. Particularly practical in science where some algorithm needs to make some steps before a new frame can @@ -894,9 +833,7 @@ class UpdatedVideoClip(VideoClip): """ - def __init__(self, world, ismask=False, duration=None): - self.world = world def make_frame(t): while self.world.clip_t < t: @@ -906,10 +843,6 @@ def make_frame(t): ismask=ismask, duration=duration) - - - - """--------------------------------------------------------------------- ImageClip (base class for all 'static clips') and its subclasses @@ -921,7 +854,7 @@ def make_frame(t): class ImageClip(VideoClip): - """ Class for non-moving VideoClips. + """Class for non-moving VideoClips. A video clip originating from a picture. This clip will simply display the given picture at all times. @@ -954,10 +887,8 @@ class ImageClip(VideoClip): """ - def __init__(self, img, ismask=False, transparent=True, fromalpha=False, duration=None): - VideoClip.__init__(self, ismask=ismask, duration=duration) if PY3: @@ -987,14 +918,12 @@ def __init__(self, img, ismask=False, transparent=True, self.size = img.shape[:2][::-1] self.img = img - def fl(self, fl, apply_to=[], keep_duration=True): - """ General transformation filter. + """General transformation filter. Equivalent to VideoClip.fl . The result is no more an ImageClip, it has the class VideoClip (since it may be animated) """ - # When we use fl on an image clip it may become animated. # Therefore the result is not an ImageClip, just a VideoClip. newclip = VideoClip.fl(self, fl, apply_to=apply_to, @@ -1002,16 +931,14 @@ def fl(self, fl, apply_to=[], keep_duration=True): newclip.__class__ = VideoClip return newclip - @outplace def fl_image(self, image_func, apply_to=[]): - """ Image-transformation filter. + """Image-transformation filter. Does the same as VideoClip.fl_image, but for ImageClip the tranformed clip is computed once and for all at the beginning, and not for each 'frame'. """ - arr = image_func(self.get_frame(0)) self.size = arr.shape[:2][::-1] self.make_frame = lambda t: arr @@ -1024,11 +951,10 @@ def fl_image(self, image_func, apply_to=[]): new_a = a.fl_image(image_func) setattr(self, attr, new_a) - @outplace def fl_time(self, time_func, apply_to=['mask', 'audio'], keep_duration=False): - """ Time-transformation filter. + """Time-transformation filter. Applies a transformation to the clip's timeline (see Clip.fl_time). @@ -1036,7 +962,6 @@ def fl_time(self, time_func, apply_to=['mask', 'audio'], This method does nothing for ImageClips (but it may affect their masks or their audios). The result is still an ImageClip. """ - for attr in apply_to: if hasattr(self, attr): a = getattr(self, attr) @@ -1060,7 +985,7 @@ def fl_time(self, time_func, apply_to=['mask', 'audio'], class ColorClip(ImageClip): - """ An ImageClip showing just one color. + """An ImageClip showing just one color. Parameters ----------- @@ -1083,7 +1008,7 @@ class ColorClip(ImageClip): def __init__(self, size, color=None, ismask=False, duration=None, col=None): if col is not None: warnings.warn("The `ColorClip` parameter `col` has been deprecated." - " Please use `color` instead", DeprecationWarning) + " Please use `color` instead.", DeprecationWarning) if color is not None: warnings.warn("The arguments `color` and `col` have both been " "passed to `ColorClip` so `col` has been ignored.", @@ -1097,7 +1022,7 @@ def __init__(self, size, color=None, ismask=False, duration=None, col=None): class TextClip(ImageClip): - """ Class for autogenerated text clips. + """Class for autogenerated text clips. Creates an ImageClip originating from a script-generated text image. Requires ImageMagick. @@ -1160,7 +1085,6 @@ class TextClip(ImageClip): """ - def __init__(self, txt=None, filename=None, size=None, color='black', bg_color='transparent', fontsize=None, font='Courier', stroke_color=None, stroke_width=1, method='label', @@ -1169,7 +1093,6 @@ def __init__(self, txt=None, filename=None, size=None, color='black', transparent=True, remove_temp=True, print_cmd=False): - if txt is not None: if temptxt is None: temptxt_fd, temptxt = tempfile.mkstemp(suffix='.txt') @@ -1239,10 +1162,9 @@ def __init__(self, txt=None, filename=None, size=None, color='black', if os.path.exists(temptxt): os.remove(temptxt) - @staticmethod def list(arg): - """ Returns the list of all valid entries for the argument of + """Returns the list of all valid entries for the argument of ``TextClip`` given (can be ``font``, ``color``, etc...) """ popen_params = {"stdout": sp.PIPE, @@ -1267,7 +1189,7 @@ def list(arg): @staticmethod def search(string, arg): - """ Returns the of all valid entries which contain ``string`` for the + """Returns the of all valid entries which contain ``string`` for the argument ``arg`` of ``TextClip``, for instance >>> # Find all the available fonts which contain "Courier" diff --git a/tests/download_media.py b/tests/download_media.py index 0cc75d291..a9a109816 100644 --- a/tests/download_media.py +++ b/tests/download_media.py @@ -1,53 +1,42 @@ +# -*- coding: utf-8 -*- +"""Handle retrieving media assets for testing.""" import os -from moviepy.editor import * +from moviepy.video.io.downloader import download_webfile + def download_url(url, filename): + """Download a file.""" if not os.path.exists(filename): - print("\nDownloading %s\n" % filename) + print('\nDownloading {}\n'.format(filename)) download_webfile(url, filename) - print("Downloading complete...\n") + print('Downloading complete...\n') def download_youtube_video(youtube_id, filename): + """Download a video from youtube.""" # FYI.. travis-ci doesn't like youtube-dl download_url(youtube_id, filename) def download(): - if not os.path.exists("media"): - os.mkdir("media") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/images/python_logo.png", - "media/python_logo.png") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/images/matplotlib_demo1.png", - "media/matplotlib_demo1.png") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/images/afterimage.png", - "media/afterimage.png") - - download_url("https://github.com/earney/moviepy_media/blob/master/tests/videos/big_buck_bunny_0_30.webm?raw=true", - "media/big_buck_bunny_0_30.webm") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/videos/big_buck_bunny_432_433.webm", - "media/big_buck_bunny_432_433.webm") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/sounds/crunching.mp3", - "media/crunching.mp3") - - download_url("https://raw.githubusercontent.com/earney/moviepy_media/master/tests/subtitles/subtitles1.srt", - "media/subtitles1.srt") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/images/pigs_in_a_polka.gif", - "media/pigs_in_a_polka.gif") - - download_url("https://data.vision.ee.ethz.ch/cvl/video2gif/kAKZeIzs0Ag.mp4", - "media/video_with_failing_audio.mp4") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/videos/fire2.mp4", - "media/fire2.mp4") - - download_url("https://raw.githubusercontent.com/earney/moviepy_media/master/tests/misc/traj.txt", - "media/traj.txt") - - download_url("https://github.com/earney/moviepy_media/raw/master/tests/images/vacation_2017.jpg", - "media/vacation_2017.jpg") \ No newline at end of file + """Initiate the media asset downloads.""" + if not os.path.exists('media'): + os.mkdir('media') + + # Define url prefix and path for all media assets. + github_prefix = 'https://github.com/earney/moviepy_media/raw/master/tests/' + output = 'media/{}' + urls = ['/images/python_logo.png', '/images/matplotlib_demo1.png', + '/images/afterimage.png', '/videos/big_buck_bunny_432_433.webm', + '/sounds/crunching.mp3', '/images/pigs_in_a_polka.gif', + '/videos/fire2.mp4', '/videos/big_buck_bunny_0_30.webm', + '/subtitles/subtitles1.srt', '/misc/traj.txt', + '/images/vacation_2017.jpg'] + + # Loop through download url strings, build out path, and download the asset. + for url in urls: + _, tail = os.path.split(url) + download_url('{}/{}'.format(github_prefix, url), output.format(tail)) + + # Download remaining asset. + download_url('https://data.vision.ee.ethz.ch/cvl/video2gif/kAKZeIzs0Ag.mp4', + 'media/video_with_failing_audio.mp4') diff --git a/tests/test_PR.py b/tests/test_PR.py index aba1c3e5b..668161b3b 100644 --- a/tests/test_PR.py +++ b/tests/test_PR.py @@ -1,21 +1,22 @@ -""" -Tests meant to be run with pytest -""" - -import sys +# -*- coding: utf-8 -*- +"""Pull request tests meant to be run with pytest.""" import os -import pytest - -from moviepy.editor import * +import sys +import pytest +from moviepy.video.fx.scroll import scroll +from moviepy.video.io.VideoFileClip import VideoFileClip from moviepy.video.tools.interpolators import Trajectory +from moviepy.video.VideoClip import ColorClip, ImageClip, TextClip + +from test_helper import TMP_DIR, TRAVIS -import sys sys.path.append("tests") -import download_media -from test_helper import PYTHON_VERSION, TMP_DIR, TRAVIS + def test_download_media(capsys): + """Test downloading.""" + import download_media with capsys.disabled(): download_media.download() @@ -30,22 +31,16 @@ def test_PR_306(): with pytest.raises(Exception, message="Expecting Exception"): TextClip.list('blah') - def test_PR_339(): if TRAVIS: return - #in caption mode - overlay = TextClip(txt='foo', - color='white', font="Liberation-Mono", - size=(640, 480), - method='caption', - align='center', - fontsize=25) - - #in_label_mode - overlay = TextClip(txt='foo', font="Liberation-Mono", method='label') + # In caption mode. + TextClip(txt='foo', color='white', font="Liberation-Mono", size=(640, 480), + method='caption', align='center', fontsize=25) + # In label mode. + TextClip(txt='foo', font="Liberation-Mono", method='label') def test_PR_373(): result = Trajectory.load_list("media/traj.txt") @@ -66,22 +61,38 @@ def test_PR_373(): for i in range(len(result[0].yy)): assert result[0].yy[i] == result1[0].yy[i] - def test_PR_424(): + """Ensure deprecation and user warnings are triggered.""" + import warnings + warnings.simplefilter('always') # Alert us of deprecation warnings. + # Recommended use - clip = ColorClip([1000, 600], color=(60, 60, 60), duration=10) - # Uses `col` so should work the same as above, but give warning - clip = ColorClip([1000, 600], col=(60, 60, 60), duration=10) - # Should give 2 warnings and use `color`, not `col` - clip = ColorClip([1000, 600], color=(60, 60, 60), duration=10, col=(2,2,2)) + ColorClip([1000, 600], color=(60, 60, 60), duration=10) + + with pytest.warns(DeprecationWarning): + # Uses `col` so should work the same as above, but give warning. + ColorClip([1000, 600], col=(60, 60, 60), duration=10) + # Catch all warnings as record. + with pytest.warns(None) as record: + # Should give 2 warnings and use `color`, not `col` + ColorClip([1000, 600], color=(60, 60, 60), duration=10, col=(2,2,2)) + + message1 = 'The `ColorClip` parameter `col` has been deprecated. ' + \ + 'Please use `color` instead.' + message2 = 'The arguments `color` and `col` have both been passed to ' + \ + '`ColorClip` so `col` has been ignored.' + + # Assert that two warnings popped and validate the message text. + assert len(record) == 2 + assert str(record[0].message) == message1 + assert str(record[1].message) == message2 def test_PR_458(): clip = ColorClip([1000, 600], color=(60, 60, 60), duration=10) clip.write_videofile(os.path.join(TMP_DIR, "test.mp4"), progress_bar=False, fps=30) - def test_PR_515(): # Won't actually work until video is in download_media clip = VideoFileClip("media/fire2.mp4", fps_source='tbr') @@ -89,18 +100,18 @@ def test_PR_515(): clip = VideoFileClip("media/fire2.mp4", fps_source='fps') assert clip.fps == 10.51 - + def test_PR_528(): clip = ImageClip("media/vacation_2017.jpg") - new_clip = vfx.scroll(clip, w=1000, x_speed=50) + new_clip = scroll(clip, w=1000, x_speed=50) new_clip = new_clip.set_duration(20) new_clip.fps = 24 new_clip.write_videofile(os.path.join(TMP_DIR, "pano.mp4")) - + def test_PR_529(): video_clip = VideoFileClip("media/fire2.mp4") - assert video_clip.rotation ==180 + assert video_clip.rotation == 180 if __name__ == '__main__': diff --git a/tests/test_compositing.py b/tests/test_compositing.py index a1f4bd527..49504ca7d 100644 --- a/tests/test_compositing.py +++ b/tests/test_compositing.py @@ -1,5 +1,9 @@ +# -*- coding: utf-8 -*- +"""Compositing tests for use with pytest.""" import pytest -from moviepy.editor import * +from moviepy.video.compositing.CompositeVideoClip import clips_array +from moviepy.video.VideoClip import ColorClip + def test_clips_array(): red = ColorClip((1024,800), color=(255,0,0)) @@ -12,8 +16,7 @@ def test_clips_array(): message="Expecting ValueError (duration not set)"): video.resize(width=480).write_videofile("/tmp/test_clips_array.mp4") - -def test_clips_array(): +def test_clips_array_duration(): red = ColorClip((1024,800), color=(255,0,0)) green = ColorClip((1024,800), color=(0,255,0)) blue = ColorClip((1024,800), color=(0,0,255)) diff --git a/tests/test_examples.py b/tests/test_examples.py index b9bc52355..87ee3cf6b 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +"""Example tests for use with pytest.""" import os import sys @@ -21,8 +23,8 @@ def test_matplotlib(): import matplotlib.pyplot as plt import numpy as np - from moviepy.editor import VideoClip from moviepy.video.io.bindings import mplfig_to_npimage + from moviepy.video.VideoClip import VideoClip x = np.linspace(-2, 2, 200) From 4038b8b54d15cbc8b014a37b5aa11d97f6a4ed6b Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:00:19 -0500 Subject: [PATCH 03/15] add path tests before importing download_media --- tests/test_ImageSequenceClip.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_ImageSequenceClip.py b/tests/test_ImageSequenceClip.py index b74a63bec..caef3dbd7 100644 --- a/tests/test_ImageSequenceClip.py +++ b/tests/test_ImageSequenceClip.py @@ -4,10 +4,8 @@ import pytest from moviepy.video.io import ImageSequenceClip -import download_media - sys.path.append("tests") - +import download_media def test_download_media(capsys): with capsys.disabled(): From 0f2b3237f5da8159b63fcff2d2b493b211976076 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:07:35 -0500 Subject: [PATCH 04/15] sys.path.append("tests") must occur before import from test_helper. --- tests/test_PR.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_PR.py b/tests/test_PR.py index 668161b3b..0c4e2849d 100644 --- a/tests/test_PR.py +++ b/tests/test_PR.py @@ -9,10 +9,8 @@ from moviepy.video.tools.interpolators import Trajectory from moviepy.video.VideoClip import ColorClip, ImageClip, TextClip -from test_helper import TMP_DIR, TRAVIS - sys.path.append("tests") - +from test_helper import TMP_DIR, TRAVIS def test_download_media(capsys): """Test downloading.""" From 50d9d51757989f0a18774c0a7fcf57953ac067ea Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:15:46 -0500 Subject: [PATCH 05/15] fix import of VideoFileClip --- tests/test_fx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_fx.py b/tests/test_fx.py index 4a82d19ca..7e400148a 100644 --- a/tests/test_fx.py +++ b/tests/test_fx.py @@ -8,7 +8,7 @@ from moviepy.video.fx.crop import crop from moviepy.video.fx.fadein import fadein from moviepy.video.fx.fadeout import fadeout -from moviepy.video.VideoClip import VideoFileClip +from moviepy.video.io.VideoFileClip import VideoFileClip import download_media from test_helper import TMP_DIR From 7ea41b429ef6970203c1c181644da55dcd70ccb2 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:16:34 -0500 Subject: [PATCH 06/15] fix VideoFileClip import --- tests/test_misc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_misc.py b/tests/test_misc.py index b52e4fe60..a375900ad 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -6,7 +6,8 @@ from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip from moviepy.video.compositing.concatenate import concatenate_videoclips from moviepy.video.tools.subtitles import SubtitlesClip, file_to_subtitles -from moviepy.video.VideoClip import ColorClip, TextClip, VideoFileClip +from moviepy.video.VideoClip import ColorClip, TextClip +from moviepy.video.io.VideoFileClip import VideoFileClip import download_media from test_helper import TMP_DIR, TRAVIS From e8bf1456c78a9954ca2f17784b1b087c536c0a8b Mon Sep 17 00:00:00 2001 From: Mark Beacom Date: Mon, 17 Apr 2017 08:20:40 -0400 Subject: [PATCH 07/15] Additional tests cleanup --- tests/README.rst | 4 +++- tests/test_ImageSequenceClip.py | 1 + tests/test_TextClip.py | 18 +++++++++++---- tests/test_VideoFileClip.py | 26 +++++++++++++-------- tests/test_Videos.py | 20 ++++++++++------ tests/test_ffmpeg_reader.py | 1 + tests/test_helper.py | 2 ++ tests/test_issues.py | 7 +++--- tests/test_tools.py | 41 ++++++++++++++++++--------------- tests/tests.py | 18 --------------- 10 files changed, 77 insertions(+), 61 deletions(-) delete mode 100644 tests/tests.py diff --git a/tests/README.rst b/tests/README.rst index 5ff501790..6a696a7ce 100644 --- a/tests/README.rst +++ b/tests/README.rst @@ -1 +1,3 @@ -No official test suite for the moment. Coming soon. \ No newline at end of file +Install testing dependencies: `pip install moviepy[test]` + +Run tests: `python setup.py test` diff --git a/tests/test_ImageSequenceClip.py b/tests/test_ImageSequenceClip.py index caef3dbd7..b81ee77fe 100644 --- a/tests/test_ImageSequenceClip.py +++ b/tests/test_ImageSequenceClip.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """Image sequencing clip tests meant to be run with pytest.""" import sys diff --git a/tests/test_TextClip.py b/tests/test_TextClip.py index 58858e289..cab3a97e1 100644 --- a/tests/test_TextClip.py +++ b/tests/test_TextClip.py @@ -1,9 +1,10 @@ +import sys + import pytest -from moviepy.editor import * +from moviepy.video.fx.blink import blink +from moviepy.video.VideoClip import TextClip -import sys sys.path.append("tests") -import download_media def test_duration(): return @@ -15,9 +16,18 @@ def test_duration(): clip.set_duration(5) assert clip.duration == 5 - clip2 = clip.fx(vfx.blink, d_on=1, d_off=1) + clip2 = clip.fx(blink, d_on=1, d_off=1) clip2.set_duration(5) assert clip2.duration == 5 +# Moved from tests.py. Maybe we can remove these? +def test_if_textclip_crashes_in_caption_mode(): + TextClip(txt='foo', color='white', size=(640, 480), method='caption', + align='center', fontsize=25) + +def test_if_textclip_crashes_in_label_mode(): + TextClip(txt='foo', method='label') + + if __name__ == '__main__': pytest.main() diff --git a/tests/test_VideoFileClip.py b/tests/test_VideoFileClip.py index 23bb309ee..a807bc80d 100644 --- a/tests/test_VideoFileClip.py +++ b/tests/test_VideoFileClip.py @@ -1,13 +1,20 @@ -import pytest -from moviepy.editor import * +# -*- coding: utf-8 -*- +"""Video file clip tests meant to be run with pytest.""" import os +import pytest +from moviepy.video.compositing.CompositeVideoClip import clips_array +from moviepy.video.VideoClip import ColorClip +from moviepy.video.VideoFileClip import VideoFileClip + + def test_setup(): + """Test VideoFileClip setup.""" red = ColorClip((1024,800), color=(255,0,0)) green = ColorClip((1024,800), color=(0,255,0)) blue = ColorClip((1024,800), color=(0,0,255)) - red.fps=green.fps=blue.fps=30 + red.fps = green.fps = blue.fps = 30 video = clips_array([[red, green, blue]]).set_duration(5) video.write_videofile("/tmp/test.mp4") @@ -19,25 +26,26 @@ def test_setup(): assert clip.size == [1024*3, 800] def test_ffmpeg_resizing(): - # Test downscaling - target_resolution = (128,128) - video = VideoFileClip("media/big_buck_bunny_432_433.webm", target_resolution=target_resolution) + """Test FFmpeg resizing, to include downscaling.""" + video_file = 'media/big_buck_bunny_432_433.webm' + target_resolution = (128, 128) + video = VideoFileClip(video_file, target_resolution=target_resolution) frame = video.get_frame(0) assert frame.shape[0:2] == target_resolution target_resolution = (128, None) - video = VideoFileClip("media/big_buck_bunny_432_433.webm", target_resolution=target_resolution) + video = VideoFileClip(video_file, target_resolution=target_resolution) frame = video.get_frame(0) assert frame.shape[0] == target_resolution[0] target_resolution = (None, 128) - video = VideoFileClip("media/big_buck_bunny_432_433.webm", target_resolution=target_resolution) + video = VideoFileClip(video_file, target_resolution=target_resolution) frame = video.get_frame(0) assert frame.shape[1] == target_resolution[1] # Test upscaling target_resolution = (None, 2048) - video = VideoFileClip("media/big_buck_bunny_432_433.webm", target_resolution=target_resolution) + video = VideoFileClip(video_file, target_resolution=target_resolution) frame = video.get_frame(0) assert frame.shape[1] == target_resolution[1] diff --git a/tests/test_Videos.py b/tests/test_Videos.py index 451a38e29..bd001a602 100644 --- a/tests/test_Videos.py +++ b/tests/test_Videos.py @@ -1,24 +1,30 @@ +# -*- coding: utf-8 -*- +"""Video tests meant to be run with pytest.""" +import sys + import pytest -from moviepy.editor import * +from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip +from moviepy.video.fx.mask_color import mask_color +from moviepy.video.VideoClip import ColorClip, ImageClip -# must have to work on travis-ci -import sys -sys.path.append("tests") import download_media +sys.path.append("tests") + + def test_download_media(capsys): with capsys.disabled(): download_media.download() def test_afterimage(): - ai=ImageClip("media/afterimage.png") - masked_clip = vfx.mask_color(ai, color=[0,255,1]) # for green + ai = ImageClip("media/afterimage.png") + masked_clip = mask_color(ai, color=[0,255,1]) # for green some_background_clip = ColorClip((800,600), color=(255,255,255)) final_clip = CompositeVideoClip([some_background_clip, masked_clip], use_bgclip=True) - final_clip.duration=5 + final_clip.duration = 5 final_clip.write_videofile("/tmp/afterimage.mp4", fps=30) if __name__ == '__main__': diff --git a/tests/test_ffmpeg_reader.py b/tests/test_ffmpeg_reader.py index 9b8c64968..5f0d381e0 100644 --- a/tests/test_ffmpeg_reader.py +++ b/tests/test_ffmpeg_reader.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """FFmpeg reader tests meant to be run with pytest.""" import sys diff --git a/tests/test_helper.py b/tests/test_helper.py index 9b6f33c18..7913b44e9 100644 --- a/tests/test_helper.py +++ b/tests/test_helper.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +"""Define general test helper attributes and utilities.""" import os import sys diff --git a/tests/test_issues.py b/tests/test_issues.py index b804e8304..f226e78e1 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """Issue tests meant to be run with pytest.""" import os import sys @@ -26,10 +27,10 @@ def test_issue_145(): concatenate_videoclips([video], method='composite') def test_issue_285(): - clip_1 = ImageClip('media/python_logo.png', duration=10) - clip_2 = ImageClip('media/python_logo.png', duration=10) - clip_3 = ImageClip('media/python_logo.png', duration=10) + clip_1, clip_2, clip_3 = ImageClip('media/python_logo.png', duration=10), \ + ImageClip('media/python_logo.png', duration=10), \ + ImageClip('media/python_logo.png', duration=10) merged_clip = concatenate_videoclips([clip_1, clip_2, clip_3]) assert merged_clip.duration == 30 diff --git a/tests/test_tools.py b/tests/test_tools.py index 31cde521e..b1510bb6c 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -1,13 +1,14 @@ -import pytest -import moviepy.tools as tools +# -*- coding: utf-8 -*- +"""Tool tests meant to be run with pytest. Taken from PR #121 (grimley517).""" import sys import time -## taken from PR #121 (grimley517) +import moviepy.tools as tools +import pytest def test_ext(): - '''Test for find_extension function''' + """Test for find_extension function.""" lefts = ['libx264', 'libmpeg4', 'libtheora', 'libvpx'] rights = ['mp4', 'mp4', 'ogv', 'webm'] for i in range(len(lefts)): @@ -17,14 +18,13 @@ def test_ext(): assert left == right, message def test_2(): - '''Tests for raising erre if codec not in dictionaries''' + """Test for raising erre if codec not in dictionaries.""" message = "asking for a silly video format did not Raise a Value Error" with pytest.raises(ValueError, message=message): tools.find_extension('flashvideo') def test_3(): - '''tests the cvsecs funtion outputs the correct times - as per the docstring''' + """Test the cvsecs funtion outputs correct times as per the docstring.""" lefts = [15.4, (1,21.5), (1,1,2), '01:01:33.5', '01:01:33.045' ] rights = [15.4, 81.5, 3662, 3693.5, 3693.045] for i in range(len(lefts)): @@ -35,7 +35,7 @@ def test_3(): assert left == right, message def test_4(): - '''tests the is_string function in tools''' + """Test the is_string function in tools.""" lefts = ["hello straight string", r'hello raw string',42, True ] rights = [True, True, False, False] for i in range(len(lefts)): @@ -46,8 +46,7 @@ def test_4(): assert left == right, message def test_4a(): - '''as for test 4 - but tests for the different behaviour of byte strings - between python 2 and 3''' + """Test for the different behaviour of byte strings between python 2/3.""" version = sys.version_info[0] answer = version < 3 #True for py2, else False left = tools.is_string(b'hello bytes') @@ -57,10 +56,12 @@ def test_4a(): assert left == right, message def test_5(): - '''Tests for sys_write-flush function - 1) checks that this works quickly, - 2) checks that stdout has no content after flushing - ''' + """Test for sys_write-flush function. + + 1) Check that this works quickly. + 2) Check that stdout has no content after flushing. + + """ start = time.time() tools.sys_write_flush("hello world") myTime = time.time() - start @@ -69,11 +70,13 @@ def test_5(): assert file == b"" def test_6(): - ''' - Tests subprocess_call for operation. the process sleep should run for - a given time in seconds. This checks that the process has - deallocated from the stack on completion of the called process - ''' + """Test subprocess_call for operation. + + The process sleep should run for a given time in seconds. + This checks that the process has deallocated from the stack on + completion of the called process. + + """ process = tools.subprocess_call(["sleep" , '1']) time.sleep(1) assert process is None diff --git a/tests/tests.py b/tests/tests.py deleted file mode 100644 index 3cd55af83..000000000 --- a/tests/tests.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -To run the tests: - py.test tests.py -""" - -from moviepy.editor import * - -#@pytest.fixture -def test_if_TextClip_crashes_in_caption_mode(): - overlay = TextClip(txt='foo', - color='white', - size=(640, 480), - method='caption', - align='center', - fontsize=25) - -def test_if_TextClip_crashes_in_label_mode(): - overlay = TextClip(txt='foo', method='label') From 1bd8668db9153957cc5f4f8d67b548b44d2f9fea Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:27:19 -0500 Subject: [PATCH 08/15] fix import of VideoFileClip --- tests/test_VideoFileClip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_VideoFileClip.py b/tests/test_VideoFileClip.py index a807bc80d..a8ec83e2a 100644 --- a/tests/test_VideoFileClip.py +++ b/tests/test_VideoFileClip.py @@ -5,7 +5,7 @@ import pytest from moviepy.video.compositing.CompositeVideoClip import clips_array from moviepy.video.VideoClip import ColorClip -from moviepy.video.VideoFileClip import VideoFileClip +from moviepy.video.io.VideoFileClip import VideoFileClip def test_setup(): From ea8904510e7af658536933117b0e17cebfddeb28 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:35:16 -0500 Subject: [PATCH 09/15] fix ImageSequenceClip import --- tests/test_ImageSequenceClip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ImageSequenceClip.py b/tests/test_ImageSequenceClip.py index b81ee77fe..854585579 100644 --- a/tests/test_ImageSequenceClip.py +++ b/tests/test_ImageSequenceClip.py @@ -3,7 +3,7 @@ import sys import pytest -from moviepy.video.io import ImageSequenceClip +from moviepy.video.io.ImageSequenceClip import ImageSequenceClip sys.path.append("tests") import download_media From 8f0f2b903fc1fe31a6ef619fe029b3d0648f9375 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 07:45:24 -0500 Subject: [PATCH 10/15] do not run TextClip tests if running on TRAVIS. --- tests/test_TextClip.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/test_TextClip.py b/tests/test_TextClip.py index cab3a97e1..b07605c7b 100644 --- a/tests/test_TextClip.py +++ b/tests/test_TextClip.py @@ -3,15 +3,17 @@ import pytest from moviepy.video.fx.blink import blink from moviepy.video.VideoClip import TextClip +from test_helper import TMP_DIR, TRAVIS sys.path.append("tests") def test_duration(): - return #TextClip returns the following error under Travis (issue with Imagemagick) #convert.im6: not authorized `@/tmp/tmpWL7I3M.txt' @ error/property.c/InterpretImageProperties/3057. #convert.im6: no images defined `PNG32:/tmp/tmpRZVqGQ.png' @ error/convert.c/ConvertImageCommand/3044. - + if TRAVIS: + return + clip = TextClip('hello world', size=(1280,720), color='white') clip.set_duration(5) assert clip.duration == 5 @@ -22,12 +24,17 @@ def test_duration(): # Moved from tests.py. Maybe we can remove these? def test_if_textclip_crashes_in_caption_mode(): + if TRAVIS: + return + TextClip(txt='foo', color='white', size=(640, 480), method='caption', align='center', fontsize=25) def test_if_textclip_crashes_in_label_mode(): + if TRAVIS: + return + TextClip(txt='foo', method='label') - if __name__ == '__main__': pytest.main() From acdf0e3fba0b07b9269002de99efb3c97d63ac74 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 08:14:20 -0500 Subject: [PATCH 11/15] fix fx imports --- tests/test_issues.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_issues.py b/tests/test_issues.py index f226e78e1..5ceef91a7 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -7,7 +7,8 @@ from moviepy.audio.io.AudioFileClip import AudioFileClip from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip from moviepy.video.compositing.concatenate import concatenate_videoclips -from moviepy.video.fx import blink, resize +from moviepy.video.fx.blink import blink +from moviepy.video.fx.resize import resize from moviepy.video.io.VideoFileClip import VideoFileClip from moviepy.video.VideoClip import ColorClip, ImageClip, VideoClip From 0f758f0efae0d0de0807449c8b123931f8fe8461 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 08:24:38 -0500 Subject: [PATCH 12/15] fix resize not in object x found errors. --- tests/test_compositing.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_compositing.py b/tests/test_compositing.py index 49504ca7d..4b2db7a41 100644 --- a/tests/test_compositing.py +++ b/tests/test_compositing.py @@ -1,9 +1,7 @@ # -*- coding: utf-8 -*- """Compositing tests for use with pytest.""" import pytest -from moviepy.video.compositing.CompositeVideoClip import clips_array -from moviepy.video.VideoClip import ColorClip - +from moviepy.editor import * def test_clips_array(): red = ColorClip((1024,800), color=(255,0,0)) From d8652bf417fe72823348c0554b384fb0e7a70804 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 08:25:39 -0500 Subject: [PATCH 13/15] fix resize not found in object x errors --- tests/test_issues.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/tests/test_issues.py b/tests/test_issues.py index 5ceef91a7..cc5c6316f 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -4,13 +4,7 @@ import sys import pytest -from moviepy.audio.io.AudioFileClip import AudioFileClip -from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip -from moviepy.video.compositing.concatenate import concatenate_videoclips -from moviepy.video.fx.blink import blink -from moviepy.video.fx.resize import resize -from moviepy.video.io.VideoFileClip import VideoFileClip -from moviepy.video.VideoClip import ColorClip, ImageClip, VideoClip +from moviepy.editor import * import download_media from test_helper import PYTHON_VERSION, TMP_DIR, TRAVIS From a4fadae9d91f3eaebd0784f822863bf5bb1e6318 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 08:48:21 -0500 Subject: [PATCH 14/15] fix resize and blink error. --- tests/test_issues.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_issues.py b/tests/test_issues.py index cc5c6316f..f5c823917 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -6,12 +6,10 @@ import pytest from moviepy.editor import * +sys.path.append("tests") import download_media from test_helper import PYTHON_VERSION, TMP_DIR, TRAVIS -sys.path.append("tests") - - def test_download_media(capsys): with capsys.disabled(): download_media.download() From b579a06a2b2f505e7b19e4aeeba0e75c74bb3086 Mon Sep 17 00:00:00 2001 From: Billy Earney Date: Mon, 17 Apr 2017 08:56:36 -0500 Subject: [PATCH 15/15] fix blink, resize error --- tests/test_issues.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_issues.py b/tests/test_issues.py index f5c823917..5c5c4ebe4 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -1,15 +1,18 @@ # -*- coding: utf-8 -*- """Issue tests meant to be run with pytest.""" import os -import sys +#import sys import pytest from moviepy.editor import * -sys.path.append("tests") +#sys.path.append("tests") import download_media from test_helper import PYTHON_VERSION, TMP_DIR, TRAVIS +from moviepy.video.fx.blink import blink +from moviepy.video.fx.resize import resize + def test_download_media(capsys): with capsys.disabled(): download_media.download()