2025, Oct 15 15:46

PyInstaller: почему exe с psycopg2 ничего не печатает и как помогает pg8000

Почему exe, собранный PyInstaller, молчит при работе с PostgreSQL и psycopg2. Покажем минимальную диагностику и решение: переход на драйвер pg8000. Без правок.

Упаковать простой клиентский скрипт PostgreSQL с помощью PyInstaller вроде бы нетрудно. Но часто попадается такая ловушка: .py запускается без проблем, сборка PyInstaller проходит без ошибок, исполняемый файл стартует… и вообще ничего не выводит. Если вы обращаетесь к базе данных и просто ждёте увидеть строки в консоли, такая тишина особенно сбивает с толку.

Постановка задачи

Скрипт ниже подключается к PostgreSQL, выбирает emails и печатает результат. В виде Python-файла он работает корректно; а собранный PyInstaller .exe не показывает ни результата, ни ошибки.

import psycopg2

try:
    db_link = psycopg2.connect(
        dbname="xxxx",
        user="xxxx",
        password="xxxx",
        host="postgresql-xxxx-xxxx.xxxx.xxxx",
        port="xxxx"
    )

    cur = db_link.cursor()

    cur.execute("SELECT email FROM membre")

    result_rows = cur.fetchall()

    for rec in result_rows:
        print(rec)

except Exception as err:
    print(f"Une erreur est survenue : {err}")

finally:
    if cur:
        cur.close()

    if db_link:
        db_link.close()

Команда упаковки пыталась явно подтянуть связанные модули. Сборка завершилась без ошибок, но исполняемый файл по-прежнему ничего не выводил.

pyinstaller --onefile --hidden-import=psycopg2 --hidden-import=psycopg2._psycopg --hidden-import=psycopg2.extensions --hidden-import=psycopg2.extras --hidden-import=sqlalchemy.dialects.postgresql --hidden-import=sqlalchemy.dialects.postgresql.psycopg2 creation_userform_sans_sql.py

Что происходит на самом деле

Ошибок на этапе сборки нет, исполняемый файл стартует, но ничего не печатает. Запуск из терминала ведёт себя так же: ни трассировки, ни вывода. В таких ситуациях легко перепутать причины, но единственно подтверждённое наблюдение здесь — отсутствие вывода во время выполнения после упаковки PyInstaller, тогда как тот же скрипт как обычный Python работает корректно.

Если исполняемый файл выглядит «тихим», полезно проверить, где именно останавливается поток выполнения и какие значения участвуют. Простой способ — добавить лёгкую «инструментацию» с помощью print() и ненадолго задержать завершение, чтобы окно консоли не закрывалось раньше, чем вы успеете увидеть вывод. Также стоит учесть, что запрос может возвращать ноль строк, и первым делом проверить их количество. Включение опций отладки PyInstaller или изменение уровня оптимизации, как советуют другие, тоже помогает понять, влияет ли упаковщик на поведение во время выполнения. Эти проверки не меняют логику программы, но показывают, выполнилась ли она как ожидалось.

Минимальная диагностика для подтверждения хода выполнения

Ниже — вариант с той же логикой и несколькими метками, чтобы наблюдать выполнение в упакованном виде. Это не исправляет проблему упаковки; цель — зафиксировать, что именно происходит при запуске .exe.

import psycopg2
import time

try:
    print("start: connecting")
    db_link = psycopg2.connect(
        dbname="xxxx",
        user="xxxx",
        password="xxxx",
        host="postgresql-xxxx-xxxx.xxxx.xxxx",
        port="xxxx"
    )
    print("connected: opening cursor")
    cur = db_link.cursor()

    print("executing query")
    cur.execute("SELECT email FROM membre")

    print("fetching rows")
    result_rows = cur.fetchall()
    print(f"row count: {len(result_rows)}")

    for rec in result_rows:
        print(rec)

    print("done; sleeping briefly to keep console visible")
    time.sleep(10)

except Exception as err:
    print(f"Une erreur est survenue : {err}")
    time.sleep(10)

finally:
    if cur:
        cur.close()

    if db_link:
        db_link.close()

Рабочее решение

Проблему упаковки решила замена драйвера PostgreSQL: вместо psycopg2 использован pg8000 — и .exe стал вести себя так же, как .py, с ожидаемым выводом. Никаких дополнительных изменений в логике приложения для этого не потребовалось. Сборка прошла без ошибок, а упакованный исполняемый файл корректно напечатал результаты.

Почему это важно

«Тихие» сбои после упаковки отнимают массу времени: почти нет сигналов, что именно пошло не так. Когда приложение упирается во ввод-вывод (доступ к базе, сетевые вызовы), достаточно тонкости в драйвере или самом процессе упаковки, чтобы подавить видимый вывод. Знание, что в данном сценарии замена модуля PostgreSQL исправила поведение, даёт вам конкретный выход, если встретите те же симптомы: .py работает, сборка PyInstaller без ошибок, .exe запускается, но ничего не печатает.

Практические выводы

Если собранный PyInstaller исполняемый файл «ничего не делает», а чистый скрипт работает, проверьте ход выполнения через print() и короткие паузы — так вы исключите исчезающее консольное окно и пустой набор результатов. Если запуск остаётся «немым», попробуйте заменить модуль клиента PostgreSQL. В этом случае переход с psycopg2 на pg8000 сделал поведение .exe идентичным .py. При необходимости изучите настройки отладки PyInstaller и поэкспериментируйте с уровнями оптимизации, чтобы понять, влияет ли упаковщик на рантайм, но сохраняйте основной скрипт неизменным во время расследования.

Главная рекомендация проста: изолируйте, в чём проблема — в вашем коде или в среде выполнения, созданной упаковщиком. Если логика корректна и тот же код без изменений работает после упаковки с другим модулем PostgreSQL, у вас есть рабочий путь вперёд без переработки приложения.

Статья основана на вопросе на StackOverflow от seblenor и ответе от seblenor.