简体   繁体   中英

Best way to call subprocess scripts in a Python exe

I'm currently trying to make a cross-platform Python exe file that relies on calling other Python and R scripts. One issue I was facing was that my exe file expected my script files to be in the root directory as opposed to the directory where my exe file is. I've managed to fix this by doing the following

   if getattr(sys, 'frozen', False):
        PROJECT_ROOT = sys.executable
   else:
        PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))

   pwd = os.path.dirname(PROJECT_ROOT)

   # messagebox is for the tkinter based GUI

   messagebox.showinfo('Info', 'Please wait a moment')
   subprocess.call(['python', pwd + '/Customs.py'], shell = False)
   subprocess.call(['Rscript', pwd + '/r_script.R'], shell=False)
   subprocess.call(['python', pwd + '/by_month.py'], shell = False)
   messagebox.showinfo('Info', 'Processing completed)

I'm wondering if there is a cleaner/ more reliable way of doing this to decrease the potential of an error occurring that might break the software.

I should also mention that I've read something about turning the other scripts into an exe file first and I would like to hear your opinion on this.

Thanks

First I suggest you use a function that returns the current path of your file when it is running as a frozen script or running normally to make testing of your code easy.

Second, if you want to bundle your script files you need to first bundle your files with executable as a DATA file . Next prepare the path for that file when using them with the said function.

def app_path():
    if getattr(sys, 'frozen', False):
        app_path = os.path.dirname(sys.executable)
    elif __file__:
        app_path = os.path.dirname(__file__)
    return app_path


def resource_path(relative_path):
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath("."), relative_path)


# messagebox is for the tkinter based GUI
messagebox.showinfo('Info', 'Please wait a moment')
subprocess.call(['python', resource_path('Customs.py')], shell=False)
subprocess.call(['Rscript', resource_path('r_script.R')], shell=False)
subprocess.call(['python', resource_path('by_month.py')], shell=False)

messagebox.showinfo('Info', 'Processing completed)

And your command to build your app would be something like this:

pyinstaller -F --add-data "Customs.py;." --add-data "r_script.R;." --add-data "by_month.py;." myscript.py

When your app runs, the data files Customs.py , r_script.R , etc would be extracted to a temp folder and resource_path would return the exact path for each file. But remember that if you want to load some files from your current directory (Where the exe file located) you can use app_path function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM