8

I have a strange problem with a Python3/PyQT5 app, frozen using PyInstaller. On macOS the code runs fine from a CLI. The version frozen using PyInstaller also runs successfully but creates new copies of itself every couple of seconds in what looks like an infinite loop. What could possibly cause this behaviour?

By way of background I have successfully frozen this app on Ubuntu 18.05 and Windows 10 without seeing this problem.

I am running Python 3.7.2 with PyInstaller 3.4 and PyQT5 5.12, on macOS Mojave 10.14.3.

Given the Python code runs perfectly from the CLI and from PyCharm, and the frozen package runs (but with multiple copies of itself) it looks like the problem is somewhere in the freezing process.

The PyInstaller .spec file I am using is here:

# -*- mode: python -*-
import sys
import os
block_cipher = None

def get_assets():
    data_files = []
    for file_name in os.listdir('/Users/xxx/PycharmProjects/jbrd2/jbrd/assets'):
        data_files.append((os.path.join('jbrd/assets', file_name), 'assets'))
    data_files.append(('/Users/xxx/PycharmProjects/jbrd2/jbrd/jbrdclasses.py', '.'))
    data_files.append(('/Users/xxx/PycharmProjects/jbrd2/jbrd/assets/config.ini', 'assets'))
    data_files.append(('/Users/xxx/PycharmProjects/jbrd2/jbrd/python_mysql_connect2.py', '.'))
    data_files.append(('/Users/xxx/PycharmProjects/jbrd2/jbrd/python_mysql_dbconfig.py', '.'))
    return data_files

a = Analysis(['jbrd/main.py'],
             pathex=['/Users/xxx/PycharmProjects/jbrd2'],
             binaries=[],
             datas=get_assets(),
             hiddenimports=['sklearn.naive_bayes','simpleeval', 'configparser', 'mysql.connector'],
             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='jbrd',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=False,
          icon='/jbrd.ico')

# Build a .app if on OS X
if sys.platform == 'darwin':
   app = BUNDLE(exe,
                name='jbrd.app',
                icon=None,
                bundle_identifier=None,
                info_plist={
                'NSHighResolutionCapable': 'True'
                },
                )

I am at a loss as to what could cause an app to run multiple copies of itself. Any suggestion please?

Thanks to some help here 1 I have now narrowed down the cause of this problem. I can confirm that running a 1-line script:

import sklearn

frozen with PyInstaller causes an infinite loop. Adding an exclusion to the PyInstaller .spec file:

excludes=['sklearn.externals.joblib']

fixes the problem. The underlying problem is that freezing an app that calls joblib causes an infinite loop. You can prove this by freezing a 1-line script

import joblib

and you will see that this causes an infinite loop. My app does NOT call joblib directly, but uses the machine learning features in sklearn. Unfortunately, sklearn calls joblib and this is what is causing my app to loop when frozen. This appears to be a bug in PyInstaller. Can anyone suggest a workaround?

Mitch
  • 111
  • 10

0 Answers0