在python exe中调用子流程脚本的最佳方法

时间:2019-06-12 14:22:23

标签: python directory subprocess pyinstaller

我目前正在尝试制作一个依赖于调用其他Python和R脚本的跨平台Python exe文件。我面临的一个问题是我的exe文件期望我的脚本文件位于根目录中,而不是我的exe文件所在的目录中。我已经通过执行以下操作来解决此问题

   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)

我想知道是否有一种更清洁/更可靠的方法来减少可能导致软件损坏的错误的发生。

我还应该提到,我已经阅读了一些有关将其他脚本首先转换为exe文件的内容,并且我想听听您对此的看法。

谢谢

1 个答案:

答案 0 :(得分:0)

首先,我建议您使用一个函数来以静态脚本运行或正常运行时返回文件的当前路径,以简化对代码的测试。

第二,如果要捆绑脚本文件,则需要先将文件和可执行文件捆绑为DATA file。接下来,将其与所述功能结合使用时,为该文件准备路径。

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)

构建应用的命令如下:

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

运行应用程序时,数据文件Customs.pyr_script.R等将被提取到临时文件夹中,而resource_path将返回每个文件的确切路径。但是请记住,如果要从当前目录(exe文件所在的位置)加载某些文件,则可以使用app_path函数。