简体   繁体   中英

I'm not sure how to execute this code correctly [using PyInstaller] into a .exe file

I am trying to convert my.py file into a.exe file using PyInstaller. The process works out fine. However, when I try to run the.exe file, the program mentions that it can not locate "client_secret.json".

I am not sure how to include a JSON file correctly in the bundle of files, so I can execute my converted.exe file correctly.

I am quite new to PyInstaller, so please don't judge me too harsh:/

I have tried adding "client_secret.json" into the.spec file of PALSheet.spec, but the.exe file (updated) fails to run [also due to its failure to locate "client_secret.json"].

Here is the code of "PALSheet.py":

import tkinter
import gspread
from oauth2client.service_account import ServiceAccountCredentials


# use creds to create a client to interact with the Google Drive API and Google Sheets API
scope = 'https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'

creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
client = gspread.authorize(creds)

# Find a workbook by name and open the first sheet
# Make sure you use the right name here.
sheet = client.open("PAL Tutoring Data SpreadSheet").sheet1

def ResetData():
    student_entry.delete('0', 'end')
    grade_entry.delete('0', 'end')
    class_entry.delete('0', 'end')
    topic_entry.delete('0', 'end')

def FindNextRow():
    global next_row
    next_row = ((len(sheet.col_values(int(1)))) + 1)

def InputData():
    FindNextRow()

    global next_row
    sheet.update_cell(next_row, 1, student_entry.get())
    sheet.update_cell(next_row, 2, grade_entry.get())
    sheet.update_cell(next_row, 3, class_entry.get())
    sheet.update_cell(next_row, 4, topic_entry.get())

    student_entry.delete('0', 'end')
    grade_entry.delete('0', 'end')
    class_entry.delete('0', 'end')
    topic_entry.delete('0', 'end')

window = tkinter.Tk()
window.title("PAL Data Input")

student_label = tkinter.Label(window, text = " Student Name: ")
student_label.grid(row = "2", column = "1")
student_entry = tkinter.Entry(window)
student_entry.grid(row = "2", column = "2")

grade_label = tkinter.Label(window, text = "Grade Level: ")
grade_label.grid(row = "3", column = "1")
grade_entry = tkinter.Entry(window)
grade_entry.grid(row = "3", column = "2")

class_label = tkinter.Label(window, text = "Math Class: ")
class_label.grid(row = "4", column = "1")
class_entry = tkinter.Entry(window)
class_entry.grid(row = "4", column = "2")

topic_label = tkinter.Label(window, text = " Problem Topic: ")
topic_label.grid(row = "5", column = "1")
topic_entry = tkinter.Entry(window)
topic_entry.grid(row = "5", column = "2")

process_button = tkinter.Button(window, text = "Update Sheet", command = InputData)
process_button.grid(row = "6", column = "2")

reset_button = tkinter.Button(window, text = "Reset Fields", command = ResetData)
reset_button.grid(row = "6", column = "1")

window.mainloop()

After I convert "PALSheet.py" to "PALSheet.exe", the file reads the following error:

Traceback (most recent call last): File "palsheet.py", line 9, in File "site-packages\oauth2client\service_account.py", line 219, in from_json_keyfile_name FileNotFoundError: [Errno 2] No such file or directory: 'client_secret.json' [280] Failed to execute script PALSheet

whenever you build a.exe with

pyinstaller -F foobar.py

pyinstaller will create a temporary directory in your appdata fodler containing the.exe's dependencies. If you build it without the -F flag, theese would be in the same directory as the executable itself. To access this temporary folder, you need to use a function like this:

import sys,os
def resource_path(relative_path: str) -> str:
    """ Get absolute path to resource"""
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

You can then replace "client_secret.json" with ressource_path("client_secret.json") and it will work even with pyinstaller's -F flag (and of cause without -F flag). You will need to append your data to the pyinstaller, so the new build command is:

pyinstaller -F --add-data "client_secret.json;client_secret.json" foobar.py

This is your new "PALSheet.py":

import tkinter
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import sys,os

def resource_path(relative_path: str) -> str:
    """ Get absolute path to resource"""
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

# use creds to create a client to interact with the Google Drive API and Google Sheets API
scope = 'https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'

creds = ServiceAccountCredentials.from_json_keyfile_name(ressource_path("client_secret.json"), scope)
client = gspread.authorize(creds)

# Find a workbook by name and open the first sheet
# Make sure you use the right name here.
sheet = client.open("PAL Tutoring Data SpreadSheet").sheet1

def ResetData():
    student_entry.delete('0', 'end')
    grade_entry.delete('0', 'end')
    class_entry.delete('0', 'end')
    topic_entry.delete('0', 'end')

def FindNextRow():
    global next_row
    next_row = ((len(sheet.col_values(int(1)))) + 1)

def InputData():
    FindNextRow()

    global next_row
    sheet.update_cell(next_row, 1, student_entry.get())
    sheet.update_cell(next_row, 2, grade_entry.get())
    sheet.update_cell(next_row, 3, class_entry.get())
    sheet.update_cell(next_row, 4, topic_entry.get())

    student_entry.delete('0', 'end')
    grade_entry.delete('0', 'end')
    class_entry.delete('0', 'end')
    topic_entry.delete('0', 'end')

window = tkinter.Tk()
window.title("PAL Data Input")

student_label = tkinter.Label(window, text = " Student Name: ")
student_label.grid(row = "2", column = "1")
student_entry = tkinter.Entry(window)
student_entry.grid(row = "2", column = "2")

grade_label = tkinter.Label(window, text = "Grade Level: ")
grade_label.grid(row = "3", column = "1")
grade_entry = tkinter.Entry(window)
grade_entry.grid(row = "3", column = "2")

class_label = tkinter.Label(window, text = "Math Class: ")
class_label.grid(row = "4", column = "1")
class_entry = tkinter.Entry(window)
class_entry.grid(row = "4", column = "2")

topic_label = tkinter.Label(window, text = " Problem Topic: ")
topic_label.grid(row = "5", column = "1")
topic_entry = tkinter.Entry(window)
topic_entry.grid(row = "5", column = "2")

process_button = tkinter.Button(window, text = "Update Sheet", command = InputData)
process_button.grid(row = "6", column = "2")

reset_button = tkinter.Button(window, text = "Reset Fields", command = ResetData)
reset_button.grid(row = "6", column = "1")

window.mainloop()

Now you need to run:

pyinstaller -F --add-data "client_secret.json;client_secret.json" "PALSheet.py"

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