Создание exe из python проекта
Написал счетчик даты, с сохранением данных в google sheets. Теперь хочу сделать .exe файл из своего проекта. Использовал pyinstaller, проект компилируется, но после не открывается. Мне кажется, что проблема в том, что я использую google drive api и (или) pyQT. В чем может быть проблема? Код проекта по классам ниже.
Проект в первую очередь обучающий, поэтому код тут далеко непрофессиональный, компилирую в exe тоже только ради обучения
Класс sheets - отправляет и принимает данные из таблицы.
import httplib2
import apiclient.discovery
from oauth2client.service_account import ServiceAccountCredentials
class GoogleSheet:
def __init__(self):
self.CREDENTIALS_FILE = 'files/clock-project-271214-6f2207203513.json'
self.credentials = ServiceAccountCredentials.from_json_keyfile_name(
self.CREDENTIALS_FILE,
['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive']
)
self.http_auth = self.credentials.authorize(httplib2.Http())
self.service = apiclient.discovery.build('sheets', 'v4', http=self.http_auth)
self.spreadsheetId = '1FGyQ_oxEUu1V_2rnbz5Fb5apSZzt0c9XIuaExF0ANhA'
self.sheetId = 0
def read_data(self, start_cell, end_cell):
"""
Читает данные из таблицы
:param start_cell: Индекс верхней левой клетки
:param end_cell: Индекс нижней правой клетки
"""
ranges = ["Лист номер один!{0}:{1}".format(start_cell, end_cell)]
results = self.service.spreadsheets().values().\
batchGet(
spreadsheetId=self.spreadsheetId,
ranges=ranges,
valueRenderOption='UNFORMATTED_VALUE',
dateTimeRenderOption='FORMATTED_STRING'
).execute()
sheet_values = results['valueRanges'][0]['values']
c = -1
for i in range(len(sheet_values[0])):
if len(sheet_values[0][i]) < 2:
while len(sheet_values[0][i]) < 2:
sheet_values[0][i] = '0' + str(sheet_values[0][i])
c += 1
if c != -1:
self.send_data(start_cell, end_cell, sheet_values)
return sheet_values
def send_data(self, cell_start, cell_end, data):
"""
Записывает данные в таблицу
:param cell_start: Индекс верхней левой клетки
:param cell_end: Индекс нижней правой клетки
:param data: Массив данных
"""
self.service.spreadsheets().values().batchUpdate(spreadsheetId=self.spreadsheetId, body={
"valueInputOption": "USER_ENTERED",
"data": [
{"range": "Лист номер один!{0}:{1}".format(cell_start, cell_end),
"majorDimension": "ROWS",
"values": data}
]
}).execute()
Класс clock - занимается работой с датой и временем в счетчике.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QLCDNumber, QPushButton
from PyQt5.QtCore import QTimer, QTime, QDateTime
import design
import sheet
import webbrowser
class Clock(QtWidgets.QMainWindow, design.Ui_MainWindow, QLCDNumber):
text = ''
max_delta = 0
def __init__(self):
super().__init__()
self.setupUi(self)
self.gsheet = sheet.GoogleSheet()
title = "Days without coronavirus..."
self.setWindowTitle(title)
self.lcdNumber.setSegmentStyle(QLCDNumber.Filled)
self.btnReset.clicked.connect(self.to_null)
self.btnOpenData.clicked.connect(self.open_data)
timer = QTimer(self)
timer.timeout.connect(self.show_time)
timer.start(1000)
timer_send = QTimer(self)
timer_send.timeout.connect(self.send_delta_max)
timer_send.start(10000)
self.last_date = self.get_date()
self.sec_start = QDateTime.currentSecsSinceEpoch()
self.sec_last = self.sec_start
self.delta = 0
self.set_delta(self.sec_start, self.sec_last)
self.max_delta = self.delta
self.was_null = False
self.new_max = False
def to_null(self):
"""
Обнуляет счетчик и отправляет данные в таблиц
"""
self.was_null = True
self.last_date = self.get_date()
self.sec_last = self.sec_start
self.gsheet.send_data('A5', 'F5', [list(self.last_date.values())])
self.gsheet.send_data('A3', 'F3', [list(self.get_values(self.delta).values())])
def open_data(self):
"""
Вызывается при нажатии кнопки и открывает таблицу с данными в браузере
"""
url = 'https://docs.google.com/spreadsheets/d/' + self.gsheet.spreadsheetId
webbrowser.open(url)
def format_date(self, yrs, mns, days, hrs, mints, secs):
"""
Форматирует дату, убирая оттуда нулевые значения для нормального отображения в приложении
:param yrs: количество лет
:param mns: количество месяцев
:param days: количество дней
:param hrs: количество часов
:param mints: количество минут
:param secs: количество секунд
:return: Отформатированная строка с данными
"""
if int(yrs) != 0:
res = yrs + ' ' + mns + ' ' + days + ' ' + hrs \
+ ':' + mints + ':' + secs
if int(yrs) < 10:
digit_count = 16
else:
if int(yrs) < 100:
digit_count = 17
else:
digit_count = 19
else:
if int(mns) != 0:
res = mns + ' ' + days + ' ' + hrs \
+ ':' + mints + ':' + secs
digit_count = 14
else:
if int(days) != 0:
res = days + ' ' + hrs \
+ ':' + mints + ':' + secs
digit_count = 11
else:
if int(hrs) != 0:
res = hrs + ':' + mints + ':' + secs
digit_count = 8
else:
res = mints + ':' + secs
digit_count = 5
self.lcdNumber.setDigitCount(digit_count)
return res
def send_delta_max(self):
"""
Записывает в таблицу максимум счетчика за все время
"""
self.gsheet.send_data('A3', 'F3', [list(self.get_values(self.delta).values())])
if self.new_max:
self.gsheet.send_data('A8', 'F8', [list(self.get_values(self.max_delta).values())])
self.new_max = False
def check_max(self):
"""
Обновляет значение максимума
"""
if self.delta > self.max_delta:
self.max_delta = self.delta
self.new_max = True
def set_delta(self, now_time, last_time):
"""
Высчитвает разницу между now_time и last_time и записывает ее в self.delta
:param now_time: настоящее время
:param last_time: время последнего обнуления счетчика
"""
self.delta = now_time - last_time
self.check_max()
def show_time(self):
"""
Отображает self.delta в приложении
"""
self.sec_start = QDateTime.currentSecsSinceEpoch()
self.set_delta(self.sec_start, self.sec_last)
res = self.format_date(
self.get_values(self.delta).get('Year'),
self.get_values(self.delta).get('Month'),
self.get_values(self.delta).get('Day'),
self.get_values(self.delta).get('Hours'),
self.get_values(self.delta).get('Minutes'),
self.get_values(self.delta).get('Seconds')
)
self.lcdNumber.display(res)
def get_values(self, value):
"""
переводит время из секунд с начала эпохи в обычный формат
:param value: время для перевода в секундах
"""
v_secs = str(value % 60)
v_mints = str(value % 3600 // 60)
v_hrs = str(value % (3600 * 24) // 3600)
v_days = str((value % (3600 * 24 * 12) // (3600 * 24)))
v_mons = str((value % (3600 * 24 * 365) // (3600 * 24 * 12)))
v_yrs = str(value // (3600 * 24 * 365))
return {
'Year': v_yrs,
'Month': v_mons,
'Day': v_days,
'Hours': v_hrs,
'Minutes': v_mints,
'Seconds': v_secs,
}
def make_sec_from_list(self, gs_data):
"""
Переводит время из строки в секунды с начала эпохи
:param gs_data: массив данных из таблицы
"""
row = gs_data[0]
date_time = QDateTime.fromString(' '.join(row), "yyyy MM dd hh mm ss")
return QDateTime.toSecsSinceEpoch(date_time)
@staticmethod
def get_date():
"""
Получает текущуие дату и время
:return:
"""
return {
'Year': QDateTime.currentDateTime().toString("yyyy"),
'Month': QDateTime.currentDateTime().toString("MM"),
'Day': QDateTime.currentDateTime().toString("dd"),
'Hours': QDateTime.currentDateTime().toString("hh"),
'Minutes': QDateTime.currentDateTime().toString("mm"),
'Seconds': QDateTime.currentDateTime().toString("ss"),
}
И, собственно, main файл
from PyQt5.QtWidgets import QApplication
import sheet
import clock
import sys
try:
app = QApplication(sys.argv)
watch = clock.Clock()
watch.show()
gsheet = sheet.GoogleSheet()
watch.sec_last = watch.make_sec_from_list(gsheet.read_data('A5', 'F5'))
app.exec()
gsheet.send_data('A3', 'F3', [list(watch.get_values(watch.delta).values())])
gsheet.send_data('A8', 'F8', [list(watch.get_values(watch.max_delta).values())])
except BaseException as error:
print(error)
Ответы (1 шт):
Автор решения: Maks Nikolaev
→ Ссылка
Можно попробовать упаковать с помощью cx_Freeze
- Ставим cx_Freeze (В командной строке
pip install cx_Freeze) - Создаем файл
setup.pyрядом с исходниками (содержимое опишу ниже) - Заполнить метаданные сборки в коде
setup.py - Открываем командную строку в директории с исходниками и запускаем сборку
python setup.py build - Собранная программа будет находится в директории
build
Содержимое setup.py:
import sys
from cx_Freeze import setup, Executable
build_exe_options = {
"packages": ["os"],
'include_files': [], # (2)
'includes': [],
'zip_include_packages': ['sheet', 'clock', 'sys', 'design', 'webbrowser', 'PyQt5',
'httplib2', 'apiclient', 'oauth2client'], # (1)
'excludes': [], # (3)
"include_msvcr": True,
"optimize": 2,
} # зависимости
base = None
if sys.platform == "win32":
base = "Console"
setup(
name='<APP_NAME>', # (4)
version='1.0',
description="",
author='<AUTHOR>',
author_email='<EMAIL>',
options={"build_exe": build_exe_options},
executables=[Executable("<EXECUTABLE_FILE_NAME>.py", base=base,
targetName="<TARGET_NAME>.exe")]
)
- (1) Список зависимостей проекта
- (2) Список файлов, которые необходимо добавить в директорию программы. Например, readme.txt
- (3) Список зависимостей, которые необходимо исключить из проекта
- (4) Метаданные сборки