Skip to content

Commit

Permalink
winutils: remove import_pywin32_module helper
Browse files Browse the repository at this point in the history
There is little point in trying to work around broken pywin32
installations on our side; if pythoncom/pywintypes cannot be
imported in the given python environment as-is, the user cannot
run and test their unfrozen program, either.

Remove the `PyInstaller.utils.hooks.win32` module and move its
only function, `get_pywin32_module_file_attribute` into
`PyInstaller.utils.hooks`. The two hooks in contributed hooks
repository that make use of this function are importing it from
this package, anyway. Reduce the implementation into simple
`get_module_attribute(name, '__file__')` call.
  • Loading branch information
rokm committed Jul 24, 2023
1 parent 5fd6a3b commit 88e82e6
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 124 deletions.
21 changes: 19 additions & 2 deletions PyInstaller/utils/hooks/__init__.py
Expand Up @@ -26,8 +26,6 @@
from PyInstaller import log as logging
from PyInstaller.depend.imphookapi import PostGraphAPI
from PyInstaller.exceptions import ExecCommandFailed
from PyInstaller.utils.hooks.win32 import \
get_pywin32_module_file_attribute # noqa: F401
from PyInstaller import isolated

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -348,6 +346,25 @@ def _get_module_file_attribute(package):
return filename


def get_pywin32_module_file_attribute(module_name):
"""
Get the absolute path of the PyWin32 DLL specific to the PyWin32 module with the passed name (`pythoncom`
or `pywintypes`).
On import, each PyWin32 module:
* Imports a DLL specific to that module.
* Overwrites the values of all module attributes with values specific to that DLL. This includes that module's
`__file__` attribute, which then provides the absolute path of that DLL.
This function imports the module in isolated subprocess and retrieves its `__file__` attribute.
"""

# NOTE: we cannot use `get_module_file_attribute` as it does not account for the __file__ rewriting magic
# done by the module. Use `get_module_attribute` instead.
return get_module_attribute(module_name, '__file__')


def is_module_satisfies(
requirements: list | pkg_resources.Requirement,
version: str | pkg_resources.Distribution | None = None,
Expand Down
46 changes: 0 additions & 46 deletions PyInstaller/utils/hooks/win32.py

This file was deleted.

76 changes: 0 additions & 76 deletions PyInstaller/utils/win32/winutils.py
Expand Up @@ -12,14 +12,8 @@
Utilities for Windows platform.
"""

import os
import sys

import PyInstaller.log as logging
from PyInstaller import compat

logger = logging.getLogger(__name__)


def get_windows_dir():
"""
Expand All @@ -43,76 +37,6 @@ def get_system_path():
return [sys_dir, get_windows_dir()]


def import_pywin32_module(module_name):
"""
Import and return the PyWin32 module with the passed name.
When imported, the `pywintypes` and `pythoncom` modules both internally import dynamic libraries
(e.g., `pywintypes.py` imports `pywintypes34.dll` under Python 3.4). The Anaconda Python distribution for Windows
installs these libraries to non-standard directories, resulting in
`"ImportError: No system module 'pywintypes' (pywintypes34.dll)"`
exceptions. This function catches these exceptions, searches for these libraries, adds their directories to
`sys.path`, and retries.
Parameters
----------
module_name : str
Fully-qualified name of this module.
Returns
----------
types.ModuleType
The desired module.
"""
module = None

try:
module = __import__(module_name, globals={}, locals={}, fromlist=[''])
except ImportError as exc:
if str(exc).startswith('No system module'):
# True if "sys.frozen" is currently set.
is_sys_frozen = hasattr(sys, 'frozen')

# Current value of "sys.frozen" if any.
sys_frozen = getattr(sys, 'frozen', None)

# Force PyWin32 to search "sys.path" for DLLs. By default, PyWin32 only searches "site-packages\win32\lib",
# "sys.prefix", and Windows system directories (e.g., "C:\Windows\System32"). This is an ugly hack, but
# there is no other way.
sys.frozen = '|_|GLYH@CK'

# If isolated to a venv, the preferred site.getsitepackages() function is unreliable. Fall back to searching
# "sys.path" instead.
if compat.is_venv:
sys_paths = sys.path
else:
sys_paths = compat.getsitepackages()

for sys_path in sys_paths:
# Absolute path of the directory containing PyWin32 DLLs.
pywin32_dll_dir = os.path.join(sys_path, 'pywin32_system32')
if os.path.isdir(pywin32_dll_dir):
sys.path.append(pywin32_dll_dir)
try:
module = __import__(name=module_name, globals={}, locals={}, fromlist=[''])
break
except ImportError:
pass

# If "sys.frozen" was previously set, restore its prior value.
if is_sys_frozen:
sys.frozen = sys_frozen
# Else, undo this hack entirely.
else:
del sys.frozen

# If this module remains unimportable, PyWin32 is not installed. Fail.
if module is None:
raise

return module


def get_pe_file_machine_type(filename):
"""
Return the machine type code from the header of the given PE file.
Expand Down

0 comments on commit 88e82e6

Please sign in to comment.