This works find in PyCharm, but when I produce a Windows exe using PyInstaller it errors at runtime:
.\pyinst_excel.exe Traceback (most recent call last): File "pyinst_excel.py", line 31, in <module> File "pyinst_excel.py", line 25, in add_generated_files_row File "site-packages\pandas\io\excel\_openpyxl.py", line 18, in __init__ ModuleNotFoundError: No module named 'openpyxl' [11408] Failed to execute script pyinst_excel
I have tried explicitly importing openpyxl and that didn't work and I have also used
--hidden-import
:call venv\Scripts\activate pyinstaller --onefile --hidden-import _openpyxl --hidden-import openpyxl --clean pyinst_excel.py
The generated spec file looks like this:# -*- mode: python ; coding: utf-8 -*- block_cipher = None a = Analysis(['pyinst_excel.py'], pathex=['D:\\Development\\OEM-SR-Rules'], binaries=[], datas=[], hiddenimports=['_openpyxl', 'openpyxl'], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='pyinst_excel', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=True )
However this doesn't fix the problem. From the build/warnings file I see:
... missing module named openpyxl - imported by pandas.io.excel._openpyxl (delayed, conditional), D:\Development\OEM-SR-Rules\pyinst_excel.py (top-level) ... missing module named 'openpyxl.styles' - imported by pandas.io.excel._openpyxl (delayed) missing module named 'openpyxl.style' - imported by pandas.io.excel._openpyxl (delayed)
Program code:import argparse from operator import attrgetter import os import sys import json import pandas as pd import numpy as np from pathlib import Path import glob import re import time from sys import exit from shutil import copyfile REPORT_DATE_FMT = '%d-%m-%Y %H.%M' def add_generated_files_row(generated_excel, sequence: int, date_generated): # gen_files_df = pd.read_excel(generated_files_excel, index_col=0) gen_files_df = pd.DataFrame(columns=['Sequence', 'Date Generated']) new_row = {'Sequence': sequence, 'Date Generated': date_generated} gen_files_df = gen_files_df.append(new_row, ignore_index=True, sort=False) writer = pd.ExcelWriter(generated_excel) gen_files_df.to_excel(writer) generated_files_excel = Path('D:\temp\test.xlsx') date_generated = time.strftime(f"{REPORT_DATE_FMT}") add_generated_files_row(generated_files_excel, 1, date_generated)
I am using Windows10, Python 3.8 and PyInstaller 3.6. Having read that Pyinstaller is not supported under 3.8, I also reproduced the problem with Python 3.7.6.
I am out of ideas. Any help would be much appreciated.
Thanks,
Clive
Do you have openpyxl
installed (i.e. does import openpyxl
work normally)? Pandas tries a range of backends to read and write xlsx files - you need to ensure that the one you tell PyInstaller to include is the one that you actually have. For reading it’s usually xlrd
and writing either xlsxwriter
or xlwt
. Whichever one(s) you have you should mark as hidden imports.
If that isn’t the problem then navigate to build/pyinst_excel/xref-pyinst_excel.html
and find openpyxl
in it. It should say if it could find it and why it didn’t include it there.
Brénainn
Hi,
I am using a BAT file to generate the executable
Grr, why does everyone instantly go for this. The spec file contains all your input parameters. Once you’ve called pyinstaller --onefile --hidden-import _openpyxl --hidden-import xlsxwriter --hidden-import openpyxl --hidden-import xlwt --clean pyinst_excel.py
once, in future you can just call PyInstaller pyinst_excel.spec
.
But that doesn’t matter - it should still work.
openpyxl.style' MissingModule
imported by: pandas.io.excel._openpyxl
'openpyxl.styles' MissingModule
imported by: pandas.io.excel._openpyxl
This tells us that PyInstaller is aware of the openpyxl
dependencies (even before we explicitly told it with the --hidden-import
s) but can’t find them. This usually boils down to venvs getting mixed up. Could you run it as python -m PyInstaller [rest of the command here]
?
Brénainn
If python -m PyInstaller
gives a No module named PyInstaller
error then your venv is a mess and PyInstaller is not in the correct environment. Using python -m ...
forces it to use the correct PyInstaller (which doesn’t exist). The PyInstaller in your PATH
presumably is left over from some other old environment (use where PyInstaller
to find out which) or your root environment.
The fix is just to install PyInstaller in your venv using:
venv\Scripts\activate
pip install PyInstaller
Verify that the 1st (or only) output from where PyInstaller
now points inside your venv/Scripts
.
Under the hood PyInstaller always uses a spec file. If you use PyInstaller --[some options] script.py
it will generate script.spec
(overwriting it if one already exists) that contains all your options, then call automatically PyInstaller script.spec
.
If you want to use the spec to avoid having to list all your options every time (strongly recommended) then just call PyInstaller script.spec
which will run it without modifying it. If you want to change your options then you modify the spec (it’s just a Python script).