Hi All,

I have an application that requires a folder of files that is effectively 
an external "SDK" that can change independent of my app, and there is a 
Python binding for that SDK in the form of a compiled C extension (sd.pyd).

I have written my script to dynamically resolve and import this module at 
runtime and it all works great from Python. I can point it to a folder 
somewhere via a command line argument and it will augment sys.path and PATH 
accordingly, and successfully import the module.

When I turn my script into and executable with pyInstaller, it fails to 
import my module with:

ImportError: DLL load failed while importing sd: The specified module could 
not be found

I have tried manually setting the PATH and PYTHONPATH in the console and 
even copying the .pyd file to be alongside the .exe itself, but nothing 
works. Now the weird part. If I re-run the pyInstaller build with my 
PYTHONPATH set to the location where my .pyd file resides, it creates an 
executable that *does* work. So it appears that pyInstaller has its own 
notion of a PYTHONPATH that can be augmented at build time but not runtime??

I do not want to bake this path into the executable, nor do I want to build 
the binary file into the .exe itself because it depends on the external SDK 
version I am referencing and I would like this to be dynamic. But how to I 
tell a pyInstaller'd .exe about it at runtime?? Here is the code that is 
doing the dynamic import in my Python module:

_WIN_SAMPLES_PATH = 'samples/win/bin'

def __get_run_path():
    """Returns the directory of this script"""

    if getattr(sys, 'frozen', False):
        # we are running in a bundle
        #bundle_dir = sys._MEIPASS
        return os.path.abspath(os.path.dirname(sys.executable))

    # we are running in a normal Python environment
    #bundle_dir = os.path.dirname(os.path.abspath(__file__))
    return os.path.abspath(os.path.dirname(__file__))


def __resolve_sdk():
    """Sets the SDK environment variables and imports the sd module"""
    sdk_root = pathlib.Path(os.environ.get('SD_SDK_ROOT', __get_run_path()))
    if not sdk_root.exists() or not sdk_root.is_dir():
        raise ImportError(f'{str(sdk_root)} is not a valid location. Make 
sure you set %SD_SDK_ROOT% appropriately in your environment.')

    # We'll fall back to this if we can't find sd.pyd in SD_SDK_ROOT
    sdk_module_folder = sdk_root / _WIN_SAMPLES_PATH

    # Try to find the sd.pyd file in sdk_root
    try_sd_pyd = sdk_root / 'sd.pyd'
    if try_sd_pyd.exists() and try_sd_pyd.is_file():
        logging.debug(f"Found 'sd.pyd' in {str(sdk_root)}")
        sdk_module_folder = sdk_root
    else:
        logging.debug(f"Failed to find 'sd.pyd' in {str(sdk_root)}. Using {
str(sdk_module_folder)} instead.")

    sdk_module = sdk_module_folder / 'sd.pyd'
    sdk_config = sdk_module_folder / 'sd.config'

    if not sdk_module.exists() or not sdk_module.is_file():
        raise ImportError(f"Failed to find 'sd.pyd' in {str(
sdk_module_folder)}! Make sure you set %SD_SDK_ROOT% appropriately in your 
environment.")

    # Set the SDK environment variables BEFORE attempting to import from sd
    # Note that the trailing separator is required for the SDK to work
    os.environ['SD_MODULE_PATH'] = str(sdk_module.parent) + '\\'
    os.environ['SD_CONFIG_PATH'] = str(sdk_config)
    os.environ["PATH"] += os.pathsep + str(sdk_module.parent)

    module_name = 'sd'
    sys.path.append(str(sdk_module.parent))
    spec = importlib.util.find_spec(module_name)
    if spec is not None:
        module = importlib.util.module_from_spec(spec)
        sys.modules[module_name] = module
        spec.loader.exec_module(module)
    else:
        raise ImportError(f"Failed to find module {module_name}")


__resolve_sdk()

import sd

It finds the sd.pyd file dynamically and sets everything up properly, but 
fails to load the .dll for some reason when turned into an .exe without the 
path "baked into" the executable via PYTHONPATH. 

Is there a way I can make this work with pyInstaller's heavily customized 
import mechanism?

Thanks,
Mark

-- 
You received this message because you are subscribed to the Google Groups 
"PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pyinstaller/8b3f9a2f-c4dd-41f5-afe7-38d2696de7b3n%40googlegroups.com.

Reply via email to