最近有博友在博文《 https://blog.csdn.net/LaoYuanPython/article/details/105346224 moviepy应用pyinstaller打包后执行报错AttributeError: module audio/video.fx.all has no attribute ‘fadein’、crop》评论区留言,反映使用该文以及《https://blog.csdn.net/LaoYuanPython/article/details/106133649 关于moviepy打包报错AttributeError: module audio/video.fx.all has no attribute fadein、crop文章的纠错和抄袭》介绍的解决方案后执行resize函数报错:
老猿进行测试,发现以前执行通过的老代码(在Python3.7.4)在现在Python3.8.5环境下确实存在问题,不只是resize,所有通过上文中介绍的方式导入的函数都有问题,如执行crop:
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>> from moviepy.editor import *
>>> clipVideo = VideoFileClip(r"F:\video\WinBasedWorkHard_src.mp4")
>>> clipVideo.crop(0,260)
Traceback (most recent call last):
File "" , line 1, in <module>
clipVideo.crop(0,260)
TypeError: 'module' object is not callable
>>>
相关错是因为moviepy包下子包audio.fx.all、video.fx.all对应的目录moviepy\audio\fx\all、moviepy\video\fx\all下的包文件__init__.py中,分别使用了如下的方式import模块:
audio.fx.all子包:
import pkgutil
import moviepy.audio.fx as fx
__all__ = [name for _, name, _ in pkgutil.iter_modules(
fx.__path__) if name != "all"]
for name in __all__:
exec("from ..%s import %s" % (name, name))
video.fx.all子包:
import pkgutil
import moviepy.video.fx as fx
__all__ = [name for _, name, _ in pkgutil.iter_modules(
fx.__path__) if name != "all"]
for name in __all__:
exec("from ..%s import %s" % (name, name))
可以看到这两个子包使用的是一种动态加载模块的模式加载包下的模块的,pyinstaller对这种模式不能处理。
解决办法:
1、将这2个__init__.py文件的上面所列最后两行注释掉;
2、在Python中将上述注释掉两行代码后前面的内容复制后加一个如下输出语句的代码:
for name in __all__:
print("from ..%s import %s" % (name, name))
如针对video.fx.all,在Python中手工执行如下代码:
import pkgutil
import moviepy.video.fx as fx
__all__ = [name for _, name, _ in pkgutil.iter_modules(
fx.__path__) if name != "all"]
for name in __all__:
print("from ..%s import %s" % (name, name))
将下面的输出语句拷贝到video.fx.all的__init__.py
,替换被注释的2行代码即可,最后完整的文件内容如下:
"""
Loads all the fx !
Usage:
import moviepy.video.fx.all as vfx
clip = vfx.resize(some_clip, width=400)
clip = vfx.mirror_x(some_clip)
"""
import pkgutil
import moviepy.video.fx as fx
__all__ = [name for _, name, _ in pkgutil.iter_modules(
fx.__path__) if name != "all"]
#for name in __all__:
# exec("from ..%s import %s" % (name, name))
#for name in __all__:
#print("from moviepy.video.fx import %s" % (name))
#print(("from ..%s import %s" % (name, name)))
from ..accel_decel import accel_decel
from ..blackwhite import blackwhite
from ..blink import blink
from ..colorx import colorx
from ..crop import crop
from ..even_size import even_size
from ..fadein import fadein
from ..fadeout import fadeout
from ..freeze import freeze
from ..freeze_region import freeze_region
from ..gamma_corr import gamma_corr
from ..headblur import headblur
from ..invert_colors import invert_colors
from ..loop import loop
from ..lum_contrast import lum_contrast
from ..make_loopable import make_loopable
from ..margin import margin
from ..mask_and import mask_and
from ..mask_color import mask_color
from ..mask_or import mask_or
from ..mirror_x import mirror_x
from ..mirror_y import mirror_y
from ..painting import painting
from ..resize import resize
from ..rotate import rotate
from ..scroll import scroll
from ..speedx import speedx
from ..supersample import supersample
from ..time_mirror import time_mirror
from ..time_symmetrize import time_symmetrize
同样对moviepy\audio\fx\all下的包文件__init__.py进行类似处理。这样处理后,再重新打包就可以解决掉该问题。
上述处理过程如果担心破坏原始的moviepy包,可以将python目录下的moviepy包拷贝一份到对应代码目录下再修改更好。
同样方式修改audio.fx.all的__init__.py
,最后得到的__init__.py
文件内容如下:
"""
Loads all the fx !
Usage:
import moviepy.audio.fx.all as afx
audio_clip = afx.volume_x(some_clip, .5)
"""
import pkgutil
import moviepy.audio.fx as fx
__all__ = [name for _, name, _ in pkgutil.iter_modules(
fx.__path__) if name != "all"]
#for name in __all__:
# exec("from ..%s import %s" % (name, name))
#for name in __all__:
#print("from moviepy.audio.fx import %s" % (name))
#print("from ..%s import %s" % (name, name))
from ..audio_fadein import audio_fadein
from ..audio_fadeout import audio_fadeout
from ..audio_left_right import audio_left_right
from ..audio_loop import audio_loop
from ..audio_normalize import audio_normalize
from ..volumex import volumex
问题即可解决。
虽然通过这种方式解决了问题,但老猿目前并没有想明白这其中的原因,原方式在Python3.7.4的版本中没有问题,且在3.8.5环境下加载没有报错,手工执行相关代码函数能正常导入,具体原因有时间再深入分析。
本节介绍了moviepy打包报错原有《 https://blog.csdn.net/LaoYuanPython/article/details/105346224 moviepy应用pyinstaller打包后执行报错AttributeError: module audio/video.fx.all has no attribute ‘fadein’、crop》中的解决办法存在Python3.8.5的环境下的TypeError: 'module' object is not callable
问题,以及更新的解决办法。
更多moviepy的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《moviepy音视频开发专栏》。
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
如果对文章内容存在疑问,可以在博客评论区留言,或关注:老猿Python 微信公号发消息咨询。
前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。