Skip to content

Commit

Permalink
hooks: fix scipy hooks used in zip_include_packages (#1903)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelotduarte committed Jun 6, 2023
1 parent ff2a551 commit f3cdbfd
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 41 deletions.
43 changes: 43 additions & 0 deletions 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
38 changes: 3 additions & 35 deletions cx_Freeze/hooks/matplotlib.py
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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
42 changes: 36 additions & 6 deletions cx_Freeze/hooks/scipy.py
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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")


Expand Down

0 comments on commit f3cdbfd

Please sign in to comment.