2025, Oct 22 08:03

Как исправить ошибку No module named matplotlib при сборке PyInstaller с PyQt6

Почему PyInstaller не включает matplotlib: ошибка No module named matplotlib при сборке .exe для PyQt6 на Windows и как решить её установкой зависимости.

Упаковка небольшого настольного приложения на PyQt6 в один исполняемый файл для Windows нередко спотыкается о на удивление простую проблему: отсутствующую зависимость на этапе сборки. Даже если прописать скрытые импорты и флаги collect-all, PyInstaller не сможет включить библиотеки, которых нет в текущем окружении. Итог — ошибка при запуске с понятным сообщением: No module named matplotlib.

Как воспроизвести окружение и сбой сборки

Приложение собирается в единый .exe с PyInstaller и следующими зависимостями:

PyQt6==6.9.1
PyQt6-Qt6==6.9.1
PyQt6_sip==13.10.2
qt-material==2.17
pyinstaller==6.14.2

В файле spec для PyInstaller добавлены скрытые импорты для matplotlib и его бэкендов:

# -*- mode: python ; coding: utf-8 -*-

graph = Analysis(
    ['DSS.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=['matplotlib', 'matplotlib.backends.backend_tkagg', 'matplotlib.backends.backend_pdf'],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=['PyQt5'],
    noarchive=False,
    optimize=0,
)
archive = PYZ(graph.pure)

app_exe = EXE(
    archive,
    graph.scripts,
    graph.binaries,
    graph.datas,
    [],
    name='DNA_Sequence_Similarities',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon=['icon.ico'],
)

bundle_collect = COLLECT(
    app_exe,
    graph.binaries,
    graph.zipfiles,
    graph.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='DNA_Sequence_Similarities',
)

Команда сборки дополнительно указывает скрытые импорты и пытается собрать пакеты:

pyinstaller DSS.py 
  --name DNA_Sequence_Similarities 
  --onefile 
  --windowed 
  --icon=icon.ico 
  --hidden-import=matplotlib 
  --hidden-import=matplotlib.backends.backend_tkagg 
  --hidden-import=matplotlib.backends.backend_pdf 
  --collect-all matplotlib 
  --collect-all qt_material 
  --collect-all PyQt6

Несмотря на это, исполняемый файл на целевых машинах падает с No module named matplotlib. Лог сборки подтверждает проблему: Hidden import 'matplotlib.backends.backend_tkagg' not found и Hidden import 'matplotlib.backends.backend_pdf' not found.

В чём реальная причина

PyInstaller анализирует текущее окружение Python и «замораживает» только те импорты, которые удаётся разрешить. Если библиотека не установлена на момент сборки, включать попросту нечего. В показанной конфигурации matplotlib отсутствует в списке зависимостей и, следовательно, не установлен в окружении сборки. Поэтому флаги hidden-import не срабатывают: PyInstaller не может найти модули, которых локально нет.

Во время выполнения сообщение максимально прямое, а на этапе анализа повторяется то же самое: скрытые импорты бэкендов matplotlib обнаружить не удаётся.

Решение

Установите matplotlib в окружение сборки и добавьте его в зависимости проекта. Как только библиотека появится, текущий spec и настройки hidden-import позволят PyInstaller найти и упаковать её вместе с исполняемым файлом.

pip install matplotlib

В итоге набор зависимостей будет таким:

PyQt6==6.9.1
PyQt6-Qt6==6.9.1
PyQt6_sip==13.10.2
qt-material==2.17
pyinstaller==6.14.2
matplotlib

Пересоберите приложение той же командой — в исполняемый файл попадёт matplotlib. Предыдущие ошибки лога о недостающих бэкендах matplotlib исчезнут, как только пакет будет доступен.

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

При поставке автономного десктопного приложения любой импорт, выполняемый во время работы, должен присутствовать в окружении уже на этапе сборки. Иначе PyInstaller не сможет его «заморозить», и финальный бинарник упадёт на машинах без установленной зависимости. Это особенно критично для GUI-стеков вроде PyQt6, которые часто интегрируются с библиотеками визуализации. Сборка должна быть самодостаточной, а начинается это с полного списка зависимостей.

Стоит прислушиваться и к сообщениям, которые выдаёт сборка. Например, в логе отмечено, что qt_material следует импортировать после PySide или PyQt. Подобные подсказки помогают заранее проверить порядок импортов и ожидания упаковки ещё до распространения.

Выводы

Держите окружение сборки в соответствии с реальными импортами приложения, убедитесь, что все нужные библиотеки перечислены и установлены — дальше PyInstaller справится сам. Если в логе появляется сообщение, что скрытый импорт не найден, самый прямой путь к решению — сделать модуль доступным в окружении, как показано на примере с matplotlib.

Статья основана на вопросе на StackOverflow от Maifee Ul Asad и ответе Pratik Pathak.