Из 15 кб python файла получается 35мб exe файл

У меня простой python проект, состоит из 1 файла. Используется только библиотека PyQt5. Собираю проект с помощью pyinstaller. Вот = pyinstaller - - onefile my_memory_card.py

Мне этот exe файл нужно на GitHub загрузить. А там ограничение 25мб

Ниже полный код проекта:

from PyQt5.QtWidgets import (QApplication, QWidget, QHBoxLayout, QVBoxLayout, QGroupBox, QButtonGroup, QRadioButton, QPushButton, QLabel)
from random import shuffle,randint


class Question():
    def __init__(self,question,right_answer,wrong1,wrong2,wrong3):
        self.question = question
        self.right_answer = right_answer
        self.wrong1 = wrong1
        self.wrong2 = wrong2
        self.wrong3 = wrong3



questions_list = []
questions_list.append(Question('Где находится город Мали','мальдивы','кипр','фиджи','коморские острова'))
questions_list.append(Question('Пипидастр это?','слово','марка машины','инструмент','одежда'))
questions_list.append(Question('Фамилия создателя Лабаргини','Ламбаргини','Росси','Феррари','Греко'))
questions_list.append(Question('Когда отмечают проваславный Новый год','14 сентября','17 декабря','14 января','29 февраля'))
questions_list.append(Question('Когда выйдет GeometryDash 2.2','Ноябрь 2023','Никогда','Июнь 2031','Февраль 2025'))
questions_list.append(Question('Какой это вопрос?',',безсмысленный','сложный','невероятно сложный','невозможный'))
questions_list.append(Question('Кто такой Наполеон','Император','торт','Презедент Франции','Скалолаз'))
questions_list.append(Question('В каком году расстреляи Магжана Жумабаева','1938','1838','1939','1929'))
questions_list.append(Question('Как раньше называлась Акмола(Астана)','Целиноград','Верный','Каркалинск','Чемкенть'))
questions_list.append(Question('Самые старые горы Африки','Капские','Атлас','Драконьи','Тянь-Шань'))
questions_list.append(Question('Самая последняя версия Maincraft','1.20.2','1.20.40','1.21.8','2.1.0'))
questions_list.append(Question('Какова вероятность найти розовую овцу в Maincraft','0.1558%','5%','1%','49%'))
questions_list.append(Question('На каком месте находится Казахстан в Евро-2023 (29 октября)','3','2','1','4'))
questions_list.append(Question('Это сложный вопрос?','Да','Нет','НЕТ','Не'))
questions_list.append(Question('Рядом с каким местом появился город Верный','Парк Горького(Центеральный Парк Культуры и Отдыха)','Метро Москва','Каток Медео','Аэрапорт'))
questions_list.append(Question('Какая из следующих планет самая близкая к Солнцу?','Венера','Марс','Юпитер','Сатурн'))
questions_list.append(Question('Какой химический элемент обозначается символом H','водород','кислород','сера','барий'))
questions_list.append(Question('Какое животное является символом парижа','Черный кот','Бык','Лев','Обезьян'))
questions_list.append(Question('Какое из озер самое глубокое','Байкал','Виктория','Мичиган','Каспийское'))
questions_list.append(Question('Кто написал роман Война и Мир','Лев Толстой','Эдуард Успенский','Антон Чехов','Абай Кунанбаев'))
questions_list.append(Question('Какой из городов не является столицей страны','Нью-Йорк','Лондон','Копенгаген','Рейкявик'))
questions_list.append(Question('Какой химический элемент состовляет большую часть земной атмосферы','Азот','Углекислый газ','Кислород','Золото'))
questions_list.append(Question('Самый маленький океан','Северно Ледовитый','Тихий','Индийский','Атлантический'))
questions_list.append(Question('Главная функция ядра в клетке','Выроботка белка','Разделение(размножение)','ядро не нужно','незнаю'))
questions_list.append(Question('Какая энергия производится засчет солнечных панелей','Солнечная','Ветрянная','энергия не производится','любая'))
questions_list.append(Question('Корень 3','1.732','6','0.188','0.189'))
questions_list.append(Question('Что производят пауки','Паутину','Молоко','Мед','Ничего, они бесполезные'))
questions_list.append(Question('Сколько раз нужно нажать на shift что бы включить залипание клавиш','5','6','4','10'))
questions_list.append(Question('Главный исполнительный деректор Facebook','Марк Цукербекрг','Илон Маск','Я','ОНО'))
questions_list.append(Question('Сколько есть вариантов ответа','4','3','2','1'))
questions_list.append(Question('Год когда ввели валюту тенге','1993','1995','1991','2000'))
questions_list.append(Question('ВВП Казахстана(в долларах)','197млрд ','200млн','100тысяч','789млрд'))
questions_list.append(Question('Сколько было Пеле когда он умер','82','80','98','102'))
questions_list.append(Question('Самый популярный блогер','MrBeast','Dream','JackSuksAtLive','EdisonPts'))
questions_list.append(Question('Какая команда выводит текст','print','import','while','RadioGroupBox.setLayout(layout_ans1)'))
questions_list.append(Question('Как сейчас называется FIFA Mobile','FC Mobile','Footbal','Socer','Not FIFA Mobile'))
questions_list.append(Question('Какой матч был 26 марта','Казхсатан(3) - Дания(2)','Казахстан(1) - Словения(2)','Казахстан(3) - Сан-Марино(0)','Небыло игр'))
questions_list.append(Question('Устал отвечать на вопросы?','да','нет','нет','нет'))
questions_list.append(Question('В какой версии маинкрафта был добавлен рыхлый снег','1.17',"1.19.5",'1.14','1.16.5'))
questions_list.append(Question('Високосный год','2020','2021','2022','2033'))
questions_list.append(Question('Где находится офис Facebook','Сингапур','Алма-Ата','Каскелен','Сан-Франциско'))
questions_list.append(Question('Курс доллара к тенге(в среднем)','460тг','500тг','5тг','141тг'))
questions_list.append(Question('Для чего нужен HTML','для написания web-сайтов','он не нужен','незнаю','для создания модов на маинкрафт'))
questions_list.append(Question('Самый популярный язык в мире','Англиский','Испанский','Португальский','Русский'))
questions_list.append(Question('Страна восходящего солнца это','Китай','Индия','Тайланд','Австралия'))
questions_list.append(Question('Самая популярная версия маинкрафта','1.12.2','1.16.5','1.20.2','1.7'))
questions_list.append(Question('Как переводится Алма-Ата','Дедушка яблок','Город гор','река','город тысячи красок'))
questions_list.append(Question('Где проходил ВШП','Туркестан','Москва','Пекин','Вашингтон'))
questions_list.append(Question('Ценна BMW i8 в тг','55млн','30млн','10млн','110млн'))
questions_list.append(Question('Столица Панамы','Панама','Пекин','Санкт-Петербург','Монте-Видео'))



app = QApplication([])
btn_OK = QPushButton('Ответить') 
lb_Question = QLabel('Самый сложный вопрос в мире!')


RadioGroupBox = QGroupBox("Варианты ответов") 
rbtn_1 = QRadioButton('Вариант 1')
rbtn_2 = QRadioButton('Вариант 2')
rbtn_3 = QRadioButton('Вариант 3')
rbtn_4 = QRadioButton('Вариант 4')


RadioGroup = QButtonGroup()
RadioGroup.addButton(rbtn_1)
RadioGroup.addButton(rbtn_2)
RadioGroup.addButton(rbtn_3)
RadioGroup.addButton(rbtn_4)
layout_ans1 = QHBoxLayout()   
layout_ans2 = QVBoxLayout() 
layout_ans3 = QVBoxLayout()
layout_ans2.addWidget(rbtn_1)
layout_ans2.addWidget(rbtn_2)
layout_ans3.addWidget(rbtn_3) 
layout_ans3.addWidget(rbtn_4)


layout_ans1.addLayout(layout_ans2)
layout_ans1.addLayout(layout_ans3) 


RadioGroupBox.setLayout(layout_ans1) 


AnsGroupBox = QGroupBox("Результат теста")
lb_Result = QLabel('прав ты или нет?')
lb_Correct = QLabel('ответ будет тут!')


layout_res = QVBoxLayout()
layout_res.addWidget(lb_Result, alignment=(Qt.AlignLeft | Qt.AlignTop))
layout_res.addWidget(lb_Correct, alignment=Qt.AlignHCenter, stretch=2)
AnsGroupBox.setLayout(layout_res)


layout_line1 = QHBoxLayout()
layout_line2 = QHBoxLayout()
layout_line3 = QHBoxLayout()


layout_line1.addWidget(lb_Question, alignment=(Qt.AlignHCenter | Qt.AlignVCenter))
layout_line2.addWidget(RadioGroupBox)   
layout_line2.addWidget(AnsGroupBox)  
AnsGroupBox.hide() 


layout_line3.addStretch(1)
layout_line3.addWidget(btn_OK, stretch=2) 
layout_line3.addStretch(1)


layout_card = QVBoxLayout()


layout_card.addLayout(layout_line1, stretch=2)
layout_card.addLayout(layout_line2, stretch=8)
layout_card.addStretch(1)
layout_card.addLayout(layout_line3, stretch=1)
layout_card.addStretch(1)
layout_card.setSpacing(5)


def show_result():
    ''' показать панель ответов '''
    RadioGroupBox.hide()
    AnsGroupBox.show()
    btn_OK.setText('Следующий вопрос')
    


def show_question():
    ''' показать панель вопросов '''
    RadioGroupBox.show()
    AnsGroupBox.hide()
    btn_OK.setText('Ответить')
    RadioGroup.setExclusive(False) 
    rbtn_1.setChecked(False)
    rbtn_2.setChecked(False)
    rbtn_3.setChecked(False)
    rbtn_4.setChecked(False)
    RadioGroup.setExclusive(True) 


answers = [rbtn_1, rbtn_2, rbtn_3, rbtn_4]


def ask(q: Question):
    ''' функция записывает значения вопроса и ответов в соответствующие виджеты, 
    при этом варианты ответов распределяются случайным образом'''
    shuffle(answers) # перемешали список из кнопок, теперь на первом месте списка какая-то непредсказуемая кнопка
    answers[0].setText(q.right_answer) # первый элемент списка заполним правильным ответом, остальные - неверными
    answers[1].setText(q.wrong1)
    answers[2].setText(q.wrong2)
    answers[3].setText(q.wrong3)
    lb_Question.setText(q.question) # вопрос
    lb_Correct.setText(q.right_answer) # ответ 
    show_question() # показываем панель вопросов 

def show_correct(res):
    ''' показать результат - установим переданный текст в надпись "результат" и покажем нужную панель '''
    lb_Result.setText(res)
    show_result()


def check_answer():
    ''' если выбран какой-то вариант ответа, то надо проверить и показать панель ответов'''
    if answers[0].isChecked():
        # правильный ответ!
        show_correct('Правильно!')
        window.score += 1
        print('Статистика\n-Всего вопросов: ', window.total, '\n-Правильных ответов: ', window.score)
        print('Рейтинг: ', (window.score/window.total*100), '%')
    else:
        if answers[1].isChecked() or answers[2].isChecked() or answers[3].isChecked():
            # неправильный ответ!
            show_correct('Неверно!')
            print('Рейтинг: ', (window.score/window.total*100), '%')


def next_question():
    ''' задает случайный вопрос из списка '''
    window.total += 1
    print('Статистика\n-Всего вопросов: ', window.total, '\n-Правильных ответов: ', window.score)
    cur_question = randint(0, len(questions_list) - 1)  # нам не нужно старое значение, 
                                                        # поэтому можно использовать локальную переменную! 
            # случайно взяли вопрос в пределах списка
            # если внести около сотни слов, то редко будет повторяться
    q = questions_list[cur_question] # взяли вопрос
    ask(q) # спросили


def click_OK():
    ''' определяет, надо ли показывать другой вопрос либо проверить ответ на этот '''
    if btn_OK.text() == 'Ответить':
        check_answer() # проверка ответа
    else:
        next_question() # следующий вопрос



window = QWidget()
window.setLayout(layout_card)
window.setWindowTitle('Memo Card')

btn_OK.clicked.connect(click_OK) 


window.score = 0
window.total = 0
next_question()
window.resize(400, 300)
window.show()
app.exec()```

Ответы (2 шт):

Автор решения: n1tr0xs

Для загрузки больших релизов следует использовать GitHub CLI.

Если вы уже сделали релиз и осталось только загрузить ваш файл, то вам достаточно воспользоваться командой gh release upload.

Пример: У релиза стоит тег v1.0, нужно загрузить файл r1.zip:

gh release upload v1.0 r1.zip
→ Ссылка
Автор решения: IvanProkshin

Когда вы используйте pyinstaller или его графическое представление auto-py-to-exe, то вы создаете самораспаковывающийся архив со вложеным python и вашим файлом.

Т.к. ваш файл весит всего 15кб, бОльшую часть этого самого архива занимает python.

Чтобы такого не происходило, можете установить nuitka и воспользоваться командой:

nuitka --module --follow-imports --static-libpython=no --remove-output --no-pyi-file --output-dir=so --jobs=4 ваш_файл.py

nuitka "переписывает" код на c (или c++, точно не помню), и потом уже с-файлы компилирует напрямую в exe. Если вам это интересно, можете прочитать больше здесь.

→ Ссылка