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

Building an executable with PyInstaller #263

Closed
domantascibas opened this issue Feb 11, 2016 · 15 comments
Closed

Building an executable with PyInstaller #263

domantascibas opened this issue Feb 11, 2016 · 15 comments
Labels
environment Using moviepy with, or issues possibly stemming from specific OS/platforms/environments. lib-FFmpeg Issues pertaining to dependency FFmpeg.

Comments

@domantascibas
Copy link

domantascibas commented Feb 11, 2016

Hi,

I've been using the MoviePy library (which is very awesome) to generate some teaching videos. Now, to make my video script easier to use for my colleagues, I want to turn the python script into a single executable using PyInstaller.

PyInstaller runs fine, and does it's thing - creates the executable, but when I try to run it, i get the following error:

C:\Users\domcib01\Documents\Lab Videos\Python\LAB_NAME\OS\LabTemplates\Python\LAB1>dist\lab1script\lab1script.exe
Traceback (most recent call last):
  File "<string>", line 7, in <module>
  File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 389, in load_module    exec(bytecode, module.__dict__)
  File "moviepy\editor.py", line 34, in <module>
  File "C:\Python27\Lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 389, in load_module    exec(bytecode, module.__dict__)
  File "moviepy\video\fx\all\__init__.py", line 16, in <module>
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\Users\\domcib01\\DOCUME~1\\LABVID~1\\Python\\LAB_NAME\\OS\\LABTEM~1\\Python\\LAB1\\dist\\LAB1SC~1\\moviepy\\video\\fx/*.*'
lab1script returned -1

I've tried creating other exec files too, but when I add a from moviepy.editor import * or any other import from MoviePy I keep getting the same error.

I'm running Python 2.7 on a 64-bit Windows 7 PC.

@pratikone
Copy link

Maybe it is due to the fact that ffmpeg is not bundled and is downloaded on trying to execute the moviepy imported code for the first time. Hence, because of that, it is not explicitly defined as a dependency and pyinstaller is unable to bundle that together leading to the following error. I am getting the same error.

@domantascibas
Copy link
Author

Thanks for confirming this issue.
So do you think this is an ImageIO problem, rather than a MoviePy problem?

@pratikone
Copy link

Last week I got a chance to go dirty with moviepy module source in <PYTHON_DIR>/lib/site-packages to find root of the problem.
I found it at this place.

for _name in __all__:
    exec("from ..%s import %s"%(_name,_name))

Moviepy uses a neat "exec" trick to dynamically import all the modules at fx level. Pyinstaller fails to recognise that and hence, it throws up the following error.
It is the same case with audio/fx/all

Solution

It is more of a hack. Replace the for loop and exec statement with actual import statements.
Thus , it should look like this

from moviepy.video.fx.accel_decel import accel_decel
from moviepy.video.fx.blackwhite import blackwhite

Do the same for audio/fx/all/__init__.py

I suggest copying moviepy folder to your local project and modify it there so that original module remains unchanged for rest of the projects.

Build your application once to generate pyc of your changes in moviepy folder too.

Then, build the executable with pyinstaller in the usual way and try to run it. It will throw the same error as above. Then, you should go to the respective folder (C:\\Users\\domcib01\\DOCUME~1\\LABVID~1\\Python\\LAB_NAME\\OS\\LABTEM~1\\Python\\LAB1\\dist\\LAB1SC~1 in this case), and copy the modified moviepy folder there.

Try running the executable once again and it will work.

@Zulko
Copy link
Owner

Zulko commented Mar 31, 2016

I don't have much time to look into this but someone seems to have fixed my very hackish code for fx.all in this in pull request: #275 because they had apparently the same problem but with pyfreeze. Can you guys try Pyinstaller on his version and report back ?

@htgoebel
Copy link

@pratikone
Copy link

@Zulko I can confirm that it does not work. Pyinstaller, still, is not able to bundle the changes , probably due to exec still being there.

@hassaanalansary
Copy link

thank you very much @pratikone for your solution, it worked for me, even that i dont understand it fully.
but I cant use --onefile?? because moviepy look for fx at temp.
thank you again

@bw4sz
Copy link

bw4sz commented Apr 10, 2018

Just pinging here, any updates? I have the same issue. It seems like the relative app directory. If you open the app from the package contents, it runs, but double clicking on the icon from /Applications fails.

Is the suggested change the moviepy source still best practice?

@bw4sz
Copy link

bw4sz commented Apr 11, 2018

Okay, I've tried the suggested fix but no luck. Let me document my work here.

The problem

My app successful runs in the following conditions.

  1. When running from source.

  2. After pyinstaller build, in the dist folder

MacBook-Pro:dist ben$ pwd
/Users/ben/Documents/DeepMeerkat/Installer/Mac/dist
MacBook-Pro:dist ben$ ./DeepMeerkat.app/Contents/MacOS/main --help
['./DeepMeerkat.app/Contents/MacOS/main', '--help']
usage: main [-h] [--input INPUT] [--draw_size DRAW_SIZE] [--size SIZE]
            [--tensorflow_threshold TENSORFLOW_THRESHOLD]
            [--moglearning MOGLEARNING] [--mogvariance MOGVARIANCE] [--crop]
            [--draw_box] [--show] [--threaded] [--tensorflow] [--write_text]
            [--training] [--output_video] [--resize]
            [--path_to_model PATH_TO_MODEL] [--output OUTPUT]
  1. After copying to /Applications folder, it runs as alias
MacBook-Pro:~ ben$ open -a "DeepMeerkat"

but, it cannot open on double click of icon. No error message. No system log on console, nothing. The error only occurred after moviepy. Removing moviepy fixes the error.

Attempts

  1. Found the source of moviepy
import moviepy
moviepy.__path__
['/Library/Python/2.7/site-packages/moviepy']

went to that dir, deleted the .pyc and changed the init to do direct imports as noted above.

MacBook-Pro:all ben$ cat __init__.py 
"""
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 os


_directory = os.path.dirname(
	            os.path.dirname(
	            	os.path.realpath(__file__)))

_files = os.listdir(_directory)
_fx_list = [_f for _f in _files if ( _f.endswith('.py') and
	                            not _f.startswith('_'))]

__all__ = [_c[:-3] for _c in _fx_list]

#for _name in __all__:
    #exec("from ..%s import %s"%(_name,_name))

from moviepy.video.fx.accel_decel import accel_decel
from moviepy.video.fx.blackwhite import blackwhite
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.even_size import even_size
from moviepy.video.fx.fadein import fadein
from moviepy.video.fx.fadeout import fadeout
from moviepy.video.fx.freeze import freeze
from moviepy.video.fx.freeze_region import freeze_region
from moviepy.video.fx.gamma_corr import gamma_corr
from moviepy.video.fx.headblur import headblur
from moviepy.video.fx.invert_colors import invert_colors
from moviepy.video.fx.loop import loop
from moviepy.video.fx.lum_contrast import lum_contrast
from moviepy.video.fx.make_loopable import make_loopable
from moviepy.video.fx.margin import margin
from moviepy.video.fx.mask_and import mask_and
from moviepy.video.fx.mask_color import mask_color
from moviepy.video.fx.mask_or import mask_or
from moviepy.video.fx.mirror_x import mirror_x
from moviepy.video.fx.mirror_y import mirror_y
from moviepy.video.fx.painting import painting
from moviepy.video.fx.resize import resize
from moviepy.video.fx.rotate import rotate
from moviepy.video.fx.scroll import scroll
from moviepy.video.fx.speedx import speedx
from moviepy.video.fx.supersample import supersample
from moviepy.video.fx.time_mirror import time_mirror
from moviepy.video.fx.time_symmetrize import time_symmetrize

print "DONE"

I did this for both the /video/fx/all and the audio/fx/all modules. I ran my app a couple times, but i did notice that the .pyc are not recreated. Could this be an issue? I deleted them initially.

  1. Rebuilt my app using pyinstaller
pyinstaller  --windowed --onedir DeepMeerkat.spec
  1. Copy the .app to /Applications folder.

Double click fails, but from terminal

open ./DeepMeerkat.app

works fine.

I'm struggling with debugging avenues. Suggestions?

@bw4sz
Copy link

bw4sz commented Apr 11, 2018

Add on here. I added

try:
    from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
except Exception as e:
        with open('/Users/ben/Desktop/error.txt',mode="w+") as f:
            f.write(str(e))

and rebuilt with pyinstaller. I got

Need ffmpeg exe. You can download it by calling:
  imageio.plugins.ffmpeg.download()

but I do have ffmpeg in my path!

MacBook-Pro:dist ben$ ffmpeg
ffmpeg version 3.3.4 Copyright (c) 2000-2017 the FFmpeg developers
  built with Apple LLVM version 8.1.0 (clang-802.0.42)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/3.3.4 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-libmp3lame --enable-libx264 --enable-libxvid --enable-opencl --enable-videotoolbox --disable-lzma --enable-vda
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libavresample   3.  5.  0 /  3.  5.  0
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
  libpostproc    54.  5.100 / 54.  5.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Not only that, what is more curious is that my .App has been using ffmpeg through opencv video capture for years. If not, I would have never been able to read video. Its bundled in, and never before has it had problems finding it. I'm now looking to see if moviepy has changed the env variables in some way.

Edit #1

Perhaps I was a little hasty in saying that I had ffmpeg from opencv. What opencv has is the ffmpeg .dll, so it is different. I'm now going down the route of editing pyinstaller to include the ffmpeg binary in the build and then editing the moviepy defaults config.

@keikoro keikoro added environment Using moviepy with, or issues possibly stemming from specific OS/platforms/environments. lib-FFmpeg Issues pertaining to dependency FFmpeg. labels Oct 8, 2020
@dmtzs
Copy link

dmtzs commented Sep 28, 2021

I hope I am commenting in the right way but at trying to create an exe file with pyinstaller and after following all the steps presented in this issue and also modifying the moviepy library and doing my own local copy changing the moviepy/video/fx/all/init.py and moviepy/audio/fx/all/init.py now I have the error below:

Exception in Tkinter callback
Traceback (most recent call last):
File "tkinter_init_.py", line 1884, in call
File "youtube.py", line 99, in DescargarVideo
File "youtube.py", line 121, in VideoAudioConverter
File "moviepy\video\io\VideoFileClip.py", line 88, in init
self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt,
File "moviepy\video\io\ffmpeg_reader.py", line 35, in init
infos = ffmpeg_parse_infos(filename, print_infos, check_duration,
File "moviepy\video\io\ffmpeg_reader.py", line 257, in ffmpeg_parse_infos
proc = sp.Popen(cmd, **popen_params)
File "subprocess.py", line 947, in init
File "subprocess.py", line 1416, in _execute_child
FileNotFoundError: [WinError 2] The system cannot find the file specified

Someone has a suggestion about this? or I´m doing something wrong?
Thank you in advance for the help

@Zenahr
Copy link

Zenahr commented Dec 5, 2021

Actually you don't strictly have to edit the library source before bundling up.
Instead of doing that, just import all moviepy modules in one of your scripts like so (source):

from moviepy.video.io.VideoFileClip import VideoFileClip
from moviepy.video.VideoClip import ImageClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
from moviepy.audio.io.AudioFileClip import AudioFileClip
from moviepy.audio.AudioClip import AudioClip
from moviepy.editor import concatenate_videoclips,concatenate_audioclips,TextClip,CompositeVideoClip
from moviepy.video.fx.accel_decel import accel_decel
from moviepy.video.fx.blackwhite import blackwhite
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.even_size import even_size
from moviepy.video.fx.fadein import fadein
from moviepy.video.fx.fadeout import fadeout
from moviepy.video.fx.freeze import freeze
from moviepy.video.fx.freeze_region import freeze_region
from moviepy.video.fx.gamma_corr import gamma_corr
from moviepy.video.fx.headblur import headblur
from moviepy.video.fx.invert_colors import invert_colors
from moviepy.video.fx.loop import loop
from moviepy.video.fx.lum_contrast import lum_contrast
from moviepy.video.fx.make_loopable import make_loopable
from moviepy.video.fx.margin import margin
from moviepy.video.fx.mask_and import mask_and
from moviepy.video.fx.mask_color import mask_color
from moviepy.video.fx.mask_or import mask_or
from moviepy.video.fx.mirror_x import mirror_x
from moviepy.video.fx.mirror_y import mirror_y
from moviepy.video.fx.painting import painting
from moviepy.video.fx.resize import resize
from moviepy.video.fx.rotate import rotate
from moviepy.video.fx.scroll import scroll
from moviepy.video.fx.speedx import speedx
from moviepy.video.fx.supersample import supersample
from moviepy.video.fx.time_mirror import time_mirror
from moviepy.video.fx.time_symmetrize import time_symmetrize

from moviepy.audio.fx.audio_fadein import audio_fadein
from moviepy.audio.fx.audio_fadeout import audio_fadeout
from moviepy.audio.fx.audio_left_right import audio_left_right
from moviepy.audio.fx.audio_loop import audio_loop
from moviepy.audio.fx.audio_normalize import audio_normalize
from moviepy.audio.fx.volumex import volumex

even though this is still not desirable, it is a working hack for the time being.

@quimnuss
Copy link

from moviepy.editor import

has

for method in [
    "afx.audio_fadein",
    "afx.audio_fadeout",
   [...]
    "vfx.speedx",
]:

    exec("VideoClip.%s = %s" % (method.split(".")[1], method))

So importing the editor module has the same problem. It also means you can't chain commands (e.g. Videoclip().resize())

@keikoro
Copy link
Collaborator

keikoro commented Oct 11, 2022

Closing this issue as it's old and references an older Python version we no longer support.

Do report back – following our issue template – if the problem persists when you try with the latest master (not the last PyPI release). Ideally, you'd open a new issue for that.

@keikoro keikoro closed this as completed Oct 11, 2022
@Jefferson-Lopes
Copy link

I had the same problem with python 3.10.5 on windows 10 with moviepy 1.0.3 and pyinstaller 5.7.0. The @Zenahr answer fixed my problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
environment Using moviepy with, or issues possibly stemming from specific OS/platforms/environments. lib-FFmpeg Issues pertaining to dependency FFmpeg.
Projects
None yet
Development

No branches or pull requests