From 547ff7b60c0e67e598e4803a06e46a77c65364ff Mon Sep 17 00:00:00 2001 From: Rok Mandeljc Date: Thu, 11 Jul 2024 23:15:22 +0200 Subject: [PATCH] hooks: hydra: add work-around for python < 3.10 and PyInstaller >= 5.8 Under python < 3.10, `hydra`'s plugin manager continues to use deprecated PEP-302 functionality that was removed from PyInstaller's `PyiFrozenImporter` in PyInstaller 5.8 (pyinstaller/pyinstaller#7344.). At run-time, this results in `AttributeError: 'PyiFrozenImporter' object has no attribute 'find_module'`. As a work-around, check python version and PyInstaller version, and if using python < 3.10 and PyInstaller >= 5.8, set module collection mode for `hydra._internal.core_plugins` and `hydra_plugins` packages to `py` to collect their modules as source .py files only. This way, they end up handled by python's built-in finder/importer, instead of PyInstaller's `PyiFrozenImporter`. --- news/760.update.rst | 8 ++++++++ .../hooks/stdhooks/hook-hydra.py | 19 ++++++++++++++++++- .../tests/test_libraries.py | 4 ---- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 news/760.update.rst diff --git a/news/760.update.rst b/news/760.update.rst new file mode 100644 index 000000000..1786fde14 --- /dev/null +++ b/news/760.update.rst @@ -0,0 +1,8 @@ +Update ``hydra`` hook to include work-around for ``hydra``'s plugin +manager, which under python < 3.10 (still) uses deprecated PEP-302 +that was removed from PyInstaller's ``PyiFrozenImporter`` in +PyInstaller 5.8. When building using python < 3.10 and PyInstaller >= 5.8, +the modules collected from ``hydra._internal.core_plugins`` and +``hydra_plugins`` packages are now collected as source .py files only; +this way, they are handled by built-in python's finder/importer instead +of PyInstaller's ``PyiFrozenImporter``. diff --git a/src/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py b/src/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py index 58e7673fb..0c6197788 100644 --- a/src/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py +++ b/src/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py @@ -10,10 +10,27 @@ # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ -from PyInstaller.utils.hooks import collect_submodules, collect_data_files +from PyInstaller.compat import is_py310 +from PyInstaller.utils.hooks import collect_submodules, collect_data_files, is_module_satisfies # Collect core plugins. hiddenimports = collect_submodules('hydra._internal.core_plugins') +# Hydra's plugin manager (`hydra.core.plugins.Plugins`) uses PEP-302 `find_module` / `load_module`, which has been +# deprecated since python 3.4, and has been removed from PyInstaller's frozen importer in PyInstaller 5.8. For python +# 3.10 and newer, they implemented new codepath that uses `find_spec`, but for earlier python versions, they opted to +# keep using the old codepath. +# +# See: https://github.com/facebookresearch/hydra/pull/2531 +# +# To work around the incompatibility with PyInstaller >= 5.8 when using python < 3.10, force collection of plugins as +# source .py files. This way, they end up handled by python's built-in finder/importer instead of PyInstaller's +# frozen importer. +if not is_py310 and is_module_satisfies("PyInstaller >= 5.8"): + module_collection_mode = { + 'hydra._internal.core_plugins': 'py', + 'hydra_plugins': 'py', + } + # Collect package's data files, such as default configuration files. datas = collect_data_files('hydra') diff --git a/src/_pyinstaller_hooks_contrib/tests/test_libraries.py b/src/_pyinstaller_hooks_contrib/tests/test_libraries.py index e37768440..4f746b624 100644 --- a/src/_pyinstaller_hooks_contrib/tests/test_libraries.py +++ b/src/_pyinstaller_hooks_contrib/tests/test_libraries.py @@ -1309,11 +1309,7 @@ def test_pyqtgraph_remote_graphics_view(pyi_builder): ) -# Remove xfail once facebookresearch/hydra#2531 is merged. @importorskip('hydra') -@xfail( - is_module_satisfies('PyInstaller >= 5.8'), - reason="uses deprecated PEP-302 functionality that was removed from PyInstaller's FrozenImporter.") def test_hydra(pyi_builder, tmpdir): config_file = str((Path(__file__) / '../data/test_hydra/config.yaml').resolve(strict=True).as_posix())