Google Groups

Re: [PyInstaller] Use PyInstaller to pack a python program with subprocess


Zak Dec 25, 2012 3:17 PM
Posted in group: PyInstaller
Hello,

Sorry I can't run experiments at the moment, I will try to be helpful anyways.

1. Do you want cam.exe to be included by PyInstaller in the bundle that PyInstaller makes, or do you want cam.exe to be distributed and installed separately? If you want cam.exe to be included by PyInstaller, then you have to tell PyInstaller about this. You can do this by modifying the .spec file. Where the .spec file says a.binaries, you want to replace that with:

a.binaries + [('cam.exe', 'C:\\path\\to\\cam.exe', 'BINARY')]

Alternatively, if you are using --onedir, you can manually copy and paste cam.exe into the dist directory. ('BINARY' may not be the right type, you can experiment.)

2. If you are using --onedir mode, then subprocess.call("cam.exe --options") should work. If you are using --onefile mode, then that will not work because subprocess will not know where to find cam.exe. You will need something like this:

import sys
import os.path

temp_dir_path = sys._MEIPASS
path_to_cam_exe = os.path.join(temp_dir_path, "cam.exe")
subprocess.call("%s --options" % path_to_cam_exe)

In this code, temp_dir_path is the path to the temporary directory created by launching your application. temp_dir_path will have a value like "C:\\Users\\yourname\\AppData\\temp\\MEI4872". That is where all of your application's code will live. That temp dir is created when your --onefile application is launched, and it is destroyed soon after you close the application.

3. You use "if __name__ == '__main__'" - that is a common Python idiom, but I think it may not work with PyInstaller. After packaging with PyInstaller, that statement probably evaluates to False and all the code under it will not be executed. I can't run experiments to test this, at the moment. I suspect this is actually why you are observing the current behavior ("nothing happens") rather than an error message.

4. You say "global CamStudioProc" toward the top of the file as if you were declaring a variable, but that isn't really correct in Python. I suspect you are thinking of a different programming language, it is understandable. I recommend reorganizing your source code, perhaps like this:

def start_cam_studio():
    CamStudioProcess = subprocess.Popen("cam.exe --options")
    return CamStudioProcess

def end_cam_studio(CamStudioProcess):
    CamStudioProcess.kill()

def main():
    CamStudioProcess = start_cam_studio()
    # do stuff
    end_cam_studio(CamStudioProcess)

This avoids global variables entirely, and is better style in my opinion.

5. It looks like cam.exe creates an output file. This gets a little tricky with PyInstaller, because you don't want to create output files (that the user is interested in keeping) in the application directory. For testing, you should probably put the output file in "C:\\Users\\yourname\\test_data\\" or something like that. For deployment, you should probably ask the user where they want the output files to be saved. In either case, you cannot use a relative path for the output file, you should use an absolute path (something starting with "C:\\", in general).

Zak Fallows

On 12/24/12 12:51 AM, He Jibo wrote:
Hello, my friends,

I am using python's subprocess to call a cam.exe to record the computer screen. Cam.exe is revised based on CamStudio. It is available at http://hejibo.info/download/cam.exe 
My source code is below. I can run this python code to record my computer screen. But after I pack it with PyInstaller, the generated .exe file cannot call cam.exe to record the screen anymore. There is no error message. Just nothing happens.

Please help me how to use PyInstaller to pack a python program, which uses subprocess to call another program
. Thanks! Merry Christmas!

import os
from time import strftime,localtime
import time
from thread import start_new_thread
import subprocess
global CamStudioProc



def CloseVideoRecording():
    print 'destroy'
    CamStudioProc.communicate('\tstdin: to stdin\n')

    print 'communicate'
    CamStudioProc.stdin.close()

    print 'stdin close'

def Start_CamStudio(timestamp):
    import subprocess
    global CamStudioProc
    outfilename = 'VideoRecording-%s.avi'%timestamp
    CamStudioProc = subprocess.Popen("cam.exe -outfile %s"%outfilename,stdin=subprocess.PIPE,shell=False)


if __name__ == '__main__':
    timestamp = str(time.time())


    print "timestamp:",timestamp

    start_new_thread(Start_CamStudio,(timestamp,))



---------------------------
He Jibo
Assistant Professor
Department of Psychology,
Wichita State University
website: www.hejibo.info

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To view this discussion on the web visit https://groups.google.com/d/msg/pyinstaller/-/G-vgDx4nXTAJ.
To post to this group, send email to pyins...@googlegroups.com.
To unsubscribe from this group, send email to pyinstaller...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pyinstaller?hl=en.