3

I am facing a quite simple problem to reproduce but I am not understanding at all what is happening.

I try to compile a Python script, which uses the fastparquet dependency, with cx_Freeze. I am able to execute my script when I launch it directly with python script.py. But if I compile it with cx_Freeze, I am getting a circular dependency error on the fastparquet import. Below is a very simple case that reproduces the issue:

script.py:

import fastparquet

setup.py:

#!/usr/bin/env python3
from cx_Freeze import setup, Executable

setup(
    name="test",
    executables=[Executable("script.py", base="Console", target_name="test.exe")],
)

If I launch python script.py directly, I get:

(test) O:\Temp\Tests\python\test_cx_Freeze>python script.py

(test) O:\Temp\Tests\python\test_cx_Freeze>

So nothing (no error either) since the script only makes an import.

If I compile the same script with cx_Freeze using the command python setup.py build, and then I launch the text.exe result, I am getting the following circular dependency error:

(test) O:\Temp\Tests\python\test_cx_Freeze\build\exe.win32-3.8>test.exe
Traceback (most recent call last):
  File "C:\Users\alexa\Envs\test\lib\site-packages\cx_Freeze\initscripts\__startup__.py", line 74, in run
    module.run()
  File "C:\Users\alexa\Envs\test\lib\site-packages\cx_Freeze\initscripts\Console.py", line 36, in run
    exec(code, m.__dict__)
  File "script.py", line 1, in <module>
  File "C:\Users\alexa\Envs\test\lib\site-packages\fastparquet\__init__.py", line 5, in <module>
    from .core import read_thrift
  File "C:\Users\alexa\Envs\test\lib\site-packages\fastparquet\core.py", line 9, in <module>
    from . import encoding
  File "C:\Users\alexa\Envs\test\lib\site-packages\fastparquet\encoding.py", line 11, in <module>
    import numba
  File "C:\Users\alexa\Envs\test\lib\site-packages\numba\__init__.py", line 19, in <module>
    from numba.core import config
  File "C:\Users\alexa\Envs\test\lib\site-packages\numba\core\config.py", line 16, in <module>
    import llvmlite.binding as ll
  File "C:\Users\alexa\Envs\test\lib\site-packages\llvmlite\binding\__init__.py", line 4, in <module>
    from .dylib import *
  File "C:\Users\alexa\Envs\test\lib\site-packages\llvmlite\binding\dylib.py", line 3, in <module>
    from llvmlite.binding import ffi
ImportError: cannot import name 'ffi' from partially initialized module 'llvmlite.binding' (most likely due to a circular import) (O:\Temp\Tests\python\test_cx_Freeze\build\exe.win32-3.8\lib\llvmlite\binding\__init__.pyc)

I checked what seems to be a problem for it:

  • llvmlite.binding module is imported by numba
  • then, one of the file inside llvmlite.binding, try to import submodule ffi by using from llvmlite.binding import ffi

For me, this is not a circular dependency since the second import is not importing all the llvmlite.binding module but only llvmlite.binding.ffi.

I don't understand:

  • Why is this second import considered as a circular dependency?
  • Why is there a difference between calling my script using python command line and the cx_Freeze result? Is it because of the method a cx_Freeze result is using to handle dependencies?
Alexandre D.
  • 711
  • 1
  • 9
  • 28
  • [Similar problem including circular import with numba and llvmlite](https://stackoverflow.com/questions/66898490/cx-freeze-isnt-allowing-me-to-make-a-gui-with-librosa-python3). It might be related to non-matching versions, such as in this numba comment: [Your llvmlite<... dependencies introduce circular dependency issues on upgrade. The old numba requires llmvmlite<0.34.0, therefore llvmlite is not upgraded, while the upgrade is necessary to upgrade numba. Always have to force the upgrades with ...](https://aur.archlinux.org/packages/python-numba/?comments=all&O=10&PP=10). – Lenka Čížková Apr 02 '21 at 22:47
  • Thanks @lenka_cizkova for your comment. I already saw the first link and I made several tests by switching `fastparquet` and `numba` versions but I did not succeed in making it work... Concerning the second link, it seems, indeed, to be linked. Unfortunately, the OP switch from cx_Freeze to PyInstaller to make it work... – Alexandre D. Apr 08 '21 at 09:47

1 Answers1

2

packages = ["llvmlite.binding"] should solve this.

https://cx-freeze.readthedocs.io/en/latest/distutils.html#build-exe

EDIT: cx_Freeze 6.6 has just been released and has hooks for this issue.

  • Thanks Marcelo ! It seems to work since I don't have the error message anymore. Do you have any explanation about why I need to add this line to remove the "circular import" error? – Alexandre D. Apr 15 '21 at 13:41
  • The answer is a bit longer than I can do, but, basically, this occurs because of optimization: A package has many modules, and some modules can be loaded dynamically. cx_Freeze copy only the modules detected to optimize the final executable. When this cannot be done, we create hooks to avoid this behavior. – Marcelo Duarte Apr 16 '21 at 14:24
  • More: https://cx-freeze.readthedocs.io/en/latest/faq.html#problems-with-running-frozen-programs – Marcelo Duarte Apr 16 '21 at 14:26