Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor Pythonic sake #1077

Merged
merged 61 commits into from
Mar 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
7e8f88d
simplify max fps pattern
mgaitan Feb 9, 2020
565a339
use all instead not any and non-empty list checking
mgaitan Feb 9, 2020
33da2ea
dont need to be lists to iterate
mgaitan Feb 9, 2020
a2a700b
replace hasattr by getattr
mgaitan Feb 9, 2020
328b765
give a generator instead a list
mgaitan Feb 9, 2020
a338db1
simple conditional assignation
mgaitan Feb 9, 2020
3a0d74f
set booleans to add readabiity
mgaitan Feb 9, 2020
bfbcb82
unsloppy code
mgaitan Feb 9, 2020
65914d0
use ternary expressions and flatten if/elif
mgaitan Feb 9, 2020
a8b0f8c
truthy object
mgaitan Feb 9, 2020
6deed31
simplify find_extension usage
mgaitan Feb 9, 2020
f276997
remove not used variable
mgaitan Feb 9, 2020
27dfd95
ternary expression
mgaitan Feb 9, 2020
dd58a6c
more on conditions
mgaitan Feb 9, 2020
678471c
reverse condition in a sake of readability
mgaitan Feb 9, 2020
4c365bf
etattr with default instead hasattr (flatten code)
mgaitan Feb 9, 2020
83420bc
simple credits parsing
mgaitan Feb 9, 2020
878c86c
space after operators
mgaitan Feb 9, 2020
8bede70
use iter
mgaitan Feb 9, 2020
1381c4e
pass generators instead list
mgaitan Feb 9, 2020
fb8c956
indenting
mgaitan Feb 9, 2020
d042b5b
indentation
mgaitan Feb 9, 2020
9e89197
more indention
mgaitan Feb 9, 2020
f7115dc
truthy check
mgaitan Feb 9, 2020
e92d86d
clean offset calculation
mgaitan Feb 9, 2020
b876f6d
explicit filter condition in a loop
mgaitan Feb 9, 2020
725ebb2
useless import
mgaitan Feb 9, 2020
346875f
use super
mgaitan Feb 9, 2020
f9b1c60
not explicity empty list checking
mgaitan Feb 9, 2020
c22f12a
bool condition
mgaitan Feb 9, 2020
c918082
use iter function
mgaitan Feb 9, 2020
f5fc14b
use cvsecs function
mgaitan Feb 9, 2020
eae4cd8
iter file directly
mgaitan Feb 9, 2020
31dbaeb
remove not used import
mgaitan Feb 9, 2020
ef752f7
documentation
mgaitan Feb 9, 2020
10acb50
reverted change on if condition
mgaitan Feb 9, 2020
dfed921
fix regression on blit_on
mgaitan Feb 10, 2020
905de12
fix test_setopacity
mgaitan Feb 10, 2020
346570b
fix bug in hill helper function
mgaitan Feb 10, 2020
83a4459
fix credits
mgaitan Feb 10, 2020
77a6768
remove pdb. shame on you
mgaitan Feb 10, 2020
7f2b6d2
safer check
mgaitan Feb 10, 2020
f3c1009
simplify comprenhension using a generator expression
mgaitan Feb 15, 2020
1f0a2ac
improved version of cvsecs function
mgaitan Feb 15, 2020
30567ff
refactor test_tools module using parametrize
mgaitan Feb 15, 2020
bbc65be
factorize skip as a decorator
mgaitan Feb 15, 2020
fe77e6d
fix regression in cvsecs
mgaitan Feb 15, 2020
0d66739
restore matplotlib test
mgaitan Feb 15, 2020
fc90b13
use a listcomp directly
mgaitan Feb 15, 2020
f3182d8
useless import
mgaitan Feb 15, 2020
ecc312e
correct skipif usage
mgaitan Feb 15, 2020
38a5671
Merge branch 'master' into pythonic
tburrows13 Feb 22, 2020
a535d93
Fix merge error
tburrows13 Feb 22, 2020
274daef
Merge branch 'master' into pythonic
tburrows13 Feb 26, 2020
9323f2f
zero could be a valid value
mgaitan Mar 5, 2020
09a076b
more valid value zero cases
mgaitan Mar 5, 2020
aac2b85
black code
mgaitan Mar 5, 2020
b46dc7d
correct set intersection
mgaitan Mar 5, 2020
bba1de3
r could be 0
mgaitan Mar 5, 2020
c8be628
explicit comparisons
mgaitan Mar 5, 2020
35649d9
fix regression on py2
mgaitan Mar 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

- New version of imageio with imageio\_ffmpeg for python 3.4+ [\#907](/~https://github.com/Zulko/moviepy/pull/907) ([Zulko](/~https://github.com/Zulko))
- fix typo that introduces audio regression [\#894](/~https://github.com/Zulko/moviepy/pull/894) ([chrox](/~https://github.com/chrox))
- fixing the git remote syntax in documentions [\#887](/~https://github.com/Zulko/moviepy/pull/887) ([ishandutta2007](/~https://github.com/ishandutta2007))
- fixing the git remote syntax in documentations [\#887](/~https://github.com/Zulko/moviepy/pull/887) ([ishandutta2007](/~https://github.com/ishandutta2007))
- modified max duration error for better understanding [\#875](/~https://github.com/Zulko/moviepy/pull/875) ([kapilkd13](/~https://github.com/kapilkd13))
- Fixed typo in docstring for VideoClip class [\#871](/~https://github.com/Zulko/moviepy/pull/871) ([Armcollector](/~https://github.com/Armcollector))
- Fix a small typing error [\#845](/~https://github.com/Zulko/moviepy/pull/845) ([yuvallanger](/~https://github.com/yuvallanger))
Expand Down
9 changes: 4 additions & 5 deletions moviepy/Clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,10 @@ def fl(self, fun, apply_to=None, keep_duration=True):
apply_to = [apply_to]

for attr in apply_to:
if hasattr(newclip, attr):
a = getattr(newclip, attr)
if a is not None:
new_a = a.fl(fun, keep_duration=keep_duration)
setattr(newclip, attr, new_a)
a = getattr(newclip, attr, None)
if a is not None:
new_a = a.fl(fun, keep_duration=keep_duration)
setattr(newclip, attr, new_a)

return newclip

Expand Down
8 changes: 2 additions & 6 deletions moviepy/audio/AudioClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,6 @@ def concatenate_audioclips(clips):

result = CompositeAudioClip(newclips).set_duration(tt[-1])

fpss = [c.fps for c in clips if hasattr(c, 'fps') and c.fps is not None]
if len(fpss) == 0:
result.fps = None
else:
result.fps = max(fpss)

fpss = [c.fps for c in clips if getattr(c, 'fps', None)]
result.fps = max(fpss) if fpss else None
return result
14 changes: 6 additions & 8 deletions moviepy/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def apply_to_mask(f, clip, *a, **k):
the clip created with f """

newclip = f(clip, *a, **k)
if hasattr(newclip, 'mask') and (newclip.mask is not None):
if getattr(newclip, 'mask', None):
newclip.mask = f(newclip.mask, *a, **k)
return newclip

Expand All @@ -39,7 +39,7 @@ def apply_to_audio(f, clip, *a, **k):
the clip created with f """

newclip = f(clip, *a, **k)
if hasattr(newclip, 'audio') and (newclip.audio is not None):
if getattr(newclip, 'audio', None):
newclip.audio = f(newclip.audio, *a, **k)
return newclip

Expand Down Expand Up @@ -112,14 +112,12 @@ def use_clip_fps_by_default(f, clip, *a, **k):
def fun(fps):
if fps is not None:
return fps
else:
if hasattr(clip, 'fps') and clip.fps is not None:
return clip.fps
else:
raise AttributeError("No 'fps' (frames per second) attribute specified"
elif getattr(clip, 'fps', None):
return clip.fps
raise AttributeError("No 'fps' (frames per second) attribute specified"
" for function %s and the clip has no 'fps' attribute. Either"
" provide e.g. fps=24 in the arguments of the function, or define"
" the clip's fps with `clip.fps=24`"%f.__name__)
" the clip's fps with `clip.fps=24`" % f.__name__)


if hasattr(f, "func_code"):
Expand Down
75 changes: 43 additions & 32 deletions moviepy/tools.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
"""
Misc. useful functions that can be used at many places in the program.
"""

import os
import re
import subprocess as sp
import sys
import warnings
Expand All @@ -13,6 +11,7 @@
from .compat import DEVNULL



def sys_write_flush(s):
""" Writes and flushes without delay a text in the console """
# Reason for not using `print` is that in some consoles "print"
Expand Down Expand Up @@ -66,39 +65,41 @@ def is_string(obj):
except NameError:
return isinstance(obj, str)


def cvsecs(time):
""" Will convert any time into seconds.
Here are the accepted formats:

>>> cvsecs(15.4) -> 15.4 # seconds
>>> cvsecs( (1,21.5) ) -> 81.5 # (min,sec)
>>> cvsecs( (1,1,2) ) -> 3662 # (hr, min, sec)
>>> cvsecs('01:01:33.5') -> 3693.5 #(hr,min,sec)
>>> cvsecs('01:01:33.045') -> 3693.045
>>> cvsecs('01:01:33,5') #coma works too
""" Will convert any time into seconds.

If the type of `time` is not valid,
it's returned as is.

Here are the accepted formats::

>>> cvsecs(15.4) # seconds
15.4
>>> cvsecs((1, 21.5)) # (min,sec)
81.5
>>> cvsecs((1, 1, 2)) # (hr, min, sec)
3662
>>> cvsecs('01:01:33.045')
3693.045
>>> cvsecs('01:01:33,5') # coma works too
3693.5
>>> cvsecs('1:33,5') # only minutes and secs
Copy link
Collaborator Author

@mgaitan mgaitan Feb 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a new format supported. It's ok, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me

99.5
>>> cvsecs('33.5') # only secs
33.5
"""
factors = (1, 60, 3600)

if is_string(time):
time = [float(f.replace(',', '.')) for f in time.split(':')]

if is_string(time):
if (',' not in time) and ('.' not in time):
time = time + '.0'
expr = r"(\d+):(\d+):(\d+)[,|.](\d+)"
finds = re.findall(expr, time)[0]
nums = list( map(float, finds) )
return ( 3600*int(finds[0])
+ 60*int(finds[1])
+ int(finds[2])
+ nums[3]/(10**len(finds[3])))

elif isinstance(time, tuple):
if len(time)== 3:
hr, mn, sec = time
elif len(time)== 2:
hr, mn, sec = 0, time[0], time[1]
return 3600*hr + 60*mn + sec

else:
if not isinstance(time, (tuple, list)):
return time

return sum(mult * part for mult, part in zip(factors, reversed(time)))


def deprecated_version_of(f, oldname, newname=None):
""" Indicates that a function is deprecated and has a new name.

Expand Down Expand Up @@ -159,8 +160,18 @@ def fdepr(*a, **kw):
for ext in ["jpg", "jpeg", "png", "bmp", "tiff"]:
extensions_dict[ext] = {'type':'image'}


def find_extension(codec):
if codec in extensions_dict:
# codec is already the extension
return codec

for ext,infos in extensions_dict.items():
if ('codec' in infos) and codec in infos['codec']:
if codec in infos.get('codec', []):
return ext
raise ValueError
raise ValueError(
"The audio_codec you chose is unknown by MoviePy. "
"You should report this. In the meantime, you can "
"specify a temp_audiofile with the right extension "
"in write_videofile."
)
13 changes: 7 additions & 6 deletions moviepy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
from moviepy.video.VideoClip import ImageClip


CLIP_TYPES = {
'audio': AudioFileClip,
'video': VideoFileClip,
'image': ImageClip,
}

def close_all_clips(objects='globals', types=('audio', 'video', 'image')):
if objects == 'globals':
objects = globals()
if hasattr(objects, 'values'):
objects = objects.values()
types_tuple = tuple([
{'audio': AudioFileClip,
'video': VideoFileClip,
'image': ImageClip}[t]
for t in types
])
types_tuple = tuple(CLIP_TYPES[key] for key in types)
for obj in objects:
if isinstance(obj, types_tuple):
obj.close()
92 changes: 30 additions & 62 deletions moviepy/video/VideoClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(self, make_frame=None, ismask=False, duration=None,
self.audio = None
self.pos = lambda t: (0, 0)
self.relative_pos = False
if make_frame is not None:
if make_frame:
self.make_frame = make_frame
self.size = self.get_frame(0).shape[:2][::-1]
self.ismask = ismask
Expand Down Expand Up @@ -120,7 +120,6 @@ def save_frame(self, filename, t=0, withmask=True):
"""

im = self.get_frame(t)

if withmask and self.mask is not None:
mask = 255 * self.mask.get_frame(t)
im = np.dstack([im, mask]).astype('uint8')
Expand Down Expand Up @@ -280,30 +279,12 @@ def write_videofile(self, filename, fps=None, codec=None,
make_audio = ((audiofile is None) and (audio == True) and
(self.audio is not None))

if make_audio:
if make_audio and temp_audiofile:
# The audio will be the clip's audio
if temp_audiofile is not None:
audiofile = temp_audiofile

else:

# make a name for the temporary audio file

if audio_codec in extensions_dict:
audio_ext = audio_codec
else:
try:
audio_ext = find_extension(audio_codec)
except ValueError:

raise ValueError(
"The audio_codec you chose is unknown by MoviePy. "
"You should report this. In the meantime, you can "
"specify a temp_audiofile with the right extension "
"in write_videofile.")

audiofile = (name + Clip._TEMP_FILES_PREFIX +
"wvf_snd.%s" % audio_ext)
audiofile = temp_audiofile
elif make_audio:
audio_ext = find_extension(audio_codec)
audiofile = (name + Clip._TEMP_FILES_PREFIX + "wvf_snd.%s" % audio_ext)

# enough cpu for multiprocessing ? USELESS RIGHT NOW, WILL COME AGAIN
# enough_cpu = (multiprocessing.cpu_count() > 1)
Expand Down Expand Up @@ -379,7 +360,6 @@ def write_images_sequence(self, nameformat, fps=None, verbose=True,
tt = np.arange(0, self.duration, 1.0 / fps)

filenames = []
total = int(self.duration / fps) + 1
for i, t in logger.iter_bar(t=list(enumerate(tt))):
name = nameformat % i
filenames.append(name)
Expand Down Expand Up @@ -454,26 +434,18 @@ def write_gif(self, filename, fps=None, program='imageio',
elif tempfiles:
# convert imageio opt variable to something that can be used with
# ImageMagick
opt1 = opt
if opt1 == 'nq':
opt1 ='optimizeplus'
else:
opt1 ='OptimizeTransparency'
opt = 'optimizeplus' if opt == 'nq' else 'OptimizeTransparency'
write_gif_with_tempfiles(self, filename, fps=fps,
program=program, opt=opt1, fuzz=fuzz,
program=program, opt=opt, fuzz=fuzz,
verbose=verbose, loop=loop,
dispose=dispose, colors=colors,
logger=logger)
else:
# convert imageio opt variable to something that can be used with
# ImageMagick
opt1 = opt
if opt1 == 'nq':
opt1 ='optimizeplus'
else:
opt1 ='OptimizeTransparency'
opt = 'optimizeplus' if opt == 'nq' else 'OptimizeTransparency'
write_gif(self, filename, fps=fps, program=program,
opt=opt1, fuzz=fuzz, verbose=verbose, loop=loop,
opt=opt, fuzz=fuzz, verbose=verbose, loop=loop,
dispose=dispose, colors=colors,
logger=logger)

Expand All @@ -495,11 +467,11 @@ 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)
left = self.subclip(0, ta) if ta else None
center = self.subclip(ta, tb).fx(fx, **kwargs)
right = None if (tb is None) else self.subclip(t_start=tb)
right = self.subclip(t_start=tb) if tb else None

clips = [c for c in [left, center, right] if c is not None]
clips = [c for c in (left, center, right) if c]

# beurk, have to find other solution
from moviepy.video.compositing.concatenate import concatenate_videoclips
Expand All @@ -513,8 +485,7 @@ def fl_image(self, image_func, apply_to=None):
Modifies the images of a clip by replacing the frame
`get_frame(t)` by another frame, `image_func(get_frame(t))`
"""
if apply_to is None:
apply_to = []
apply_to = apply_to or []
return self.fl(lambda gf, t: image_func(gf(t)), apply_to)

# --------------------------------------------------------------
Expand Down Expand Up @@ -545,23 +516,22 @@ def blit_on(self, picture, t):
"""
hf, wf = framesize = picture.shape[:2]

if self.ismask and picture.max() != 0:
if self.ismask and picture.max():
return np.minimum(1, picture + self.blit_on(np.zeros(framesize), t))

ct = t - self.start # clip time

# GET IMAGE AND MASK IF ANY

img = self.get_frame(ct)
mask = (None if (self.mask is None) else
self.mask.get_frame(ct))
if mask is not None:
if (img.shape[0] != mask.shape[0]) or (img.shape[1] != mask.shape[1]):
img = self.fill_array(img, mask.shape)
mask = self.mask.get_frame(ct) if self.mask else None

if mask is not None and ((img.shape[0] != mask.shape[0]) or (img.shape[1] != mask.shape[1])):
img = self.fill_array(img, mask.shape)

hi, wi = img.shape[:2]

# SET POSITION

pos = self.pos(ct)

# preprocess short writings of the position
Expand Down Expand Up @@ -687,7 +657,7 @@ def set_mask(self, 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 )
assert mask is None or mask.ismask
self.mask = mask

@add_mask_if_none
Expand Down Expand Up @@ -968,11 +938,10 @@ def fl_image(self, image_func, apply_to=None):
self.img = arr

for attr in apply_to:
if hasattr(self, attr):
a = getattr(self, attr)
if a is not None:
new_a = a.fl_image(image_func)
setattr(self, attr, new_a)
a = getattr(self, attr, None)
if a is not None:
new_a = a.fl_image(image_func)
setattr(self, attr, new_a)

@outplace
def fl_time(self, time_func, apply_to=None,
Expand All @@ -986,13 +955,12 @@ def fl_time(self, time_func, apply_to=None,
masks or their audios). The result is still an ImageClip.
"""
if apply_to is None:
apply_to = ['mask', 'audio']
apply_to = ['mask', 'audio']
for attr in apply_to:
if hasattr(self, attr):
a = getattr(self, attr)
if a is not None:
new_a = a.fl_time(time_func)
setattr(self, attr, new_a)
a = getattr(self, attr, None)
if a is not None:
new_a = a.fl_time(time_func)
setattr(self, attr, new_a)


# ##
Expand Down
Loading