diff --git a/cx_Freeze/hooks/_libs.py b/cx_Freeze/hooks/_libs.py new file mode 100644 index 000000000..ee72b7e9b --- /dev/null +++ b/cx_Freeze/hooks/_libs.py @@ -0,0 +1,43 @@ +"""Helper functions for hooks.""" + +from __future__ import annotations + +from types import CodeType + +from ..common import code_object_replace_function +from ..module import Module + + +def replace_delvewheel_patch(module: Module) -> None: + """Replace delvewheel injections of code to not find for module.libs + directory. + """ + code = module.code + if code is None: + return + + delvewheel_func = "_delvewheel_init_patch_" + consts = list(code.co_consts) + for constant in consts: + if isinstance(constant, CodeType): + name = constant.co_name + if name.startswith(delvewheel_func): + source = f"""\ + def {name}(): + import os, sys + + libs_path = os.path.join( + sys.frozen_dir, "lib", "{module.name}.libs" + ) + try: + os.add_dll_directory(libs_path) + except (OSError, AttributeError): + pass + env_path = os.environ.get("PATH", "").split(os.pathsep) + if libs_path not in env_path: + env_path.insert(0, libs_path) + os.environ["PATH"] = os.pathsep.join(env_path) + """ + code = code_object_replace_function(code, name, source) + break + module.code = code diff --git a/cx_Freeze/hooks/matplotlib.py b/cx_Freeze/hooks/matplotlib.py index 66d8fc980..9a8c34957 100644 --- a/cx_Freeze/hooks/matplotlib.py +++ b/cx_Freeze/hooks/matplotlib.py @@ -6,11 +6,11 @@ from contextlib import suppress from pathlib import Path -from types import CodeType from ..common import code_object_replace_function from ..finder import ModuleFinder from ..module import Module +from ._libs import replace_delvewheel_patch def load_matplotlib(finder: ModuleFinder, module: Module) -> None: @@ -33,10 +33,10 @@ def load_matplotlib(finder: ModuleFinder, module: Module) -> None: source_dir = module_path.parent / module_libs_name if source_dir.exists(): finder.include_files(source_dir, f"lib/{module_libs_name}") - _replace_delvewheel_patch(module) + replace_delvewheel_patch(module) with suppress(ImportError): mpl_toolkits = finder.include_module("mpl_toolkits") - _replace_delvewheel_patch(mpl_toolkits) + replace_delvewheel_patch(mpl_toolkits) def _patch_data_path(module: Module, data_path: Path) -> None: @@ -54,35 +54,3 @@ def {name}(): # patch if the name (_get_data_path and/or get_data_path) is found code = code_object_replace_function(code, name, source) module.code = code - - -def _replace_delvewheel_patch(module: Module) -> None: - # remove delvewheel injections of code to not find for .libs directory - code = module.code - if code is None: - return - delvewheel_func = "_delvewheel_init_patch_" - consts = list(code.co_consts) - for constant in consts: - if isinstance(constant, CodeType): - name = constant.co_name - if name.startswith(delvewheel_func): - source = f"""\ - def {name}(): - import os, sys - - libs_path = os.path.join( - sys.frozen_dir, "lib", "matplotlib.libs" - ) - try: - os.add_dll_directory(libs_path) - except (OSError, AttributeError): - pass - env_path = os.environ.get("PATH", "").split(os.pathsep) - if libs_path not in env_path: - env_path.insert(0, libs_path) - os.environ["PATH"] = os.pathsep.join(env_path) - """ - code = code_object_replace_function(code, name, source) - break - module.code = code diff --git a/cx_Freeze/hooks/scipy.py b/cx_Freeze/hooks/scipy.py index 93b612806..d6b384b60 100644 --- a/cx_Freeze/hooks/scipy.py +++ b/cx_Freeze/hooks/scipy.py @@ -4,26 +4,46 @@ from __future__ import annotations +import os + from .._compat import IS_MINGW, IS_WINDOWS from ..finder import ModuleFinder from ..module import Module +from ._libs import replace_delvewheel_patch def load_scipy(finder: ModuleFinder, module: Module) -> None: """The scipy module loads items within itself in a way that causes problems without libs and a number of subpackages being present. """ - libs_name = f"{module.name}.libs" - source_dir = module.path[0].parent / libs_name + source_dir = module.file.parent.parent / f"{module.name}.libs" if source_dir.exists(): - finder.include_files(source_dir, f"lib/{libs_name}") - + finder.include_files(source_dir, f"lib/{source_dir.name}") + replace_delvewheel_patch(module) finder.include_package("scipy.integrate") finder.include_package("scipy._lib") finder.include_package("scipy.misc") finder.include_package("scipy.optimize") +def load_scipy__distributor_init( + finder: ModuleFinder, module: Module # noqa: ARG001 +) -> None: + """Fix the location of dependent files in Windows.""" + if not (IS_WINDOWS or IS_MINGW): + # In Linux and macOS it is detected correctly. + return + + if module.in_file_system != 0: # not in zip_include_packages + return + + # patch the code + code_string = module.file.read_text(encoding="utf-8").replace( + "__file__", "__file__.replace('library.zip/', '')" + ) + module.code = compile(code_string, os.fspath(module.file), "exec") + + def load_scipy_interpolate( finder: ModuleFinder, module: Module # noqa: ARG001 ) -> None: @@ -57,6 +77,14 @@ def load_scipy_ndimage( finder.include_package("scipy.ndimage") +def load_scipy_sparse( + finder: ModuleFinder, module: Module # noqa: ARG001 +) -> None: + """The scipy.sparse must be loaded as a package.""" + finder.exclude_module("scipy.sparse.tests") + finder.include_package("scipy.sparse") + + def load_scipy_sparse_csgraph( finder: ModuleFinder, module: Module # noqa: ARG001 ) -> None: @@ -65,10 +93,12 @@ def load_scipy_sparse_csgraph( finder.include_package("scipy.sparse.csgraph") -def load_scipy_sparse_linalg_dsolve_linsolve( +def load_scipy_sparse_linalg__dsolve_linsolve( finder: ModuleFinder, module: Module # noqa: ARG001 ) -> None: - """The scipy.linalg.dsolve.linsolve optionally loads scikits.umfpack.""" + """The scipy.sparse.linalg._dsolve.linsolve optionally loads + scikits.umfpack. + """ module.ignore_names.add("scikits.umfpack")