0

I wanted to make an exe file for my little project that I made. But it doesnt run at all.

I tried PyInstaller does not include dependency file But it throws

Traceback (most recent call last):
  File "C:\Program Files\Python37\Scripts\pyinstaller-script.py", line 11, in <module>
    load_entry_point('PyInstaller==3.4', 'console_scripts', 'pyinstaller')()
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\__main__.py", line 111, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\__main__.py", line 63, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\building\build_main.py", line 838, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\building\build_main.py", line 784, in build
    exec(text, spec_namespace)
  File "<string>", line 8, in <module>
IndexError: list index out of range

And if I just do "pyinstaller --clean --onefile Start.py" it says:

  File "Start.py", line 5, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "Modules\HTMLToPDF.py", line 1, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\weasyprint\__init__.py", line 20, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\cssselect2\__init__.py", line 20, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\cssselect2\compiler.py", line 7, in <module>
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "C:\Program Files\Python37\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 627, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\tinycss2\__init__.py", line 10, in <module>
  File "pathlib.py", line 1189, in read_text
  File "pathlib.py", line 1176, in open
  File "pathlib.py", line 1030, in _opener
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Daniel\\AppData\\Local\\Temp\\_MEI100202\\tinycss2\\VERSION'
[12796] Failed to execute script Start

How can I fix it? I just want a nice way to distribute my code.

Daniel K
  • 3
  • 3

2 Answers2

3

For anyone in the future trying to make WeasyPrint work with PyInstaller on WINDOWS 10 SPECIFICALLY; I found the following methods to be very useful:

  • Create a debug script you will build with pyinstaller
import sys,traceback
try:
    import weasyprint
    print(weasyprint.__version__)
except:
    print(sys.exc_info())
    print(traceback.format_exc())
finally:
    input('Press enter to exit the program: ')

Now try and build with:

pyinstaller main.py --name=test --log-level ERROR --clean

It will probably complain about missing modules. This is where I kind of mix and matched methods in my many hours of trial and error, I will provide both solutions of how to include those missing modules and then my final spec sheet and method.

  • hooks: To include those missing modules, create the following 'hooks' folder:
\main.py
\hooks

in this folder you will introduce python files with the following script which you will name as 'hook-{NAMEOFMISSINGMODULE}.py'

from PyInstaller.utils.hooks import collect_data_files


def hook(hook_api):
    hook_api.add_datas(collect_data_files(hook_api.__name__))

therefore:

\main.py
\hooks
  \hook-cssselect2.py
  \...

You will include these files with your PyInstaller command:

pyinstaller main.py --name=test--log-level ERROR --clean --additional-hooks-dir=hooks
  • additional data: I found that when it was complaining about VERSIONs or specific files not being found in specific folders in weasyprint; I would navigate my way to the data missing in my Python installation and then copy the address to it and implement it in the PyInstaller command with a semicolon followed by the name of the folder:
pyinstaller main.py --name=test--log-level ERROR --clean --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\css\html5_ph.css;css --additional-hooks-dir=hooks

Should you run into a complaint of not being able to find VERSION file in your _MEIXXXXX folder; it is looking for the VERSION file in your weasyprint package. The correct --add-data line is as follows:

--add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\VERSION;.

Note the semicolon followed by '.'. This is telling PyInstaller to include that file in the temporary folder made by PyInstaller when you open the exe which is always called _MEI{somerandomnumbers}.

Using these methods you should eventually succeed and be presented with the version number of weasyprint. My final working command line is as follows:

pyinstaller main.py --name=test--log-level ERROR --clean --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pyphen;pyphen\dictionaries --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\css\html5_ph.css;css --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\css\html5_ua.css;css --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\weasyprint\VERSION;. --add-data C:\Users\PC\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\cairocffi;cairocffi  --additional-hooks-dir=hooks

with the following hooks:

\main.py
\hooks
  \hook-cairocffi.py
  \hook-cssselect2.py
  \hook-tinycss2.py

This also works for onefile mode.

I am definitely aware I am probably doing the same thing with the hooks and add-data; like I said I was mixing and matching methods until something eventually worked. I'm fairly confident that the same effect could be achieved using only one of these methods but I don't think its worth wasting the time to investigate when I've already spent too many hours on it.

Thank you to all the other stackoverflow users and weasyprint creator for there answers on multiple posts over the years which I have eventually been able to accumulate into a working version for myself.

If this helps give a +1 or leave a comment as this is the first answer to show up for googling 'Pyinstaller weasyprint'.

cabboose
  • 86
  • 4
2

Honestly, your project is huge and has many complex libraries so PyInstaller can't handle all of them by itself. Here I tell you some tips to work it out.

First, when PyInstaller complains about missing a file, it means that you need to feed that file manually. For example in your error, it complains about missing a file named VERSION that should be exist in C:\\Users\\Daniel\\AppData\\Local\\Temp\\_MEI100202\\tinycss2 but it doesn't. You need to add it as a data file by yourself.

Second, if you need to bring some external dependencies like cairo you need to bring the whole directory of the dependence with Tree function. You can find more about that here.

I built the project and fix some of these dependencies so it no longer shows an error about missing those files, I also added a try/except on the whole project to be able to trace missing files which might be helpful. I just added the missing files and some hiddenimports to the spec file so you need to take care of those.

Start.py:

import traceback
try:
    """
    Whole Start.py script
    """
except Exception:
    traceback.print_exc()
    while(True):
        pass

Start.spec:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['Start.py'],
             pathex=['C:\\Users\\Daniel\\Desktop\\SOAPUIReportingTool-master\\soap'],
             binaries=[],
             datas=[
                 ("C:\\Program Files\\Python37\\Lib\\site-packages\\tinycss2\\VERSION", "tinycss2"),
                 ("C:\\Program Files\\Python37\\Lib\\site-packages\\cairocffi\\VERSION", "cairocffi"),
                 ("C:\\Program Files\\Python37\\Lib\\site-packages\\\weasyprint\\VERSION", ".")
                     ],
             hiddenimports=["tinycss2", "matplotlib", "weasyprint"],
             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='Start',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=False,
          runtime_tmpdir=None,
          console=True )
Masoud Rahimi
  • 5,785
  • 15
  • 39
  • 67
  • 2
    I had to add my config file and some additional libs but it works now. ("C:\\Program Files\\Python37\\Lib\\site-packages\\weasyprint\\css\\html5_ua.css", "css"), ("C:\\Program Files\\Python37\\Lib\\site-packages\\weasyprint\\css\\html5_ph.css", "css") shutil.copyfile('config.cfg', '{0}/config.cfg'.format(DISTPATH)) – Daniel K May 27 '19 at 09:16