Search code examples
pythonpyinstallerweasyprint

How to make an exe for python script that uses weasyprint?


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.


Solution

  • 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 )