English
You're encountering this issue because you're trying to load a .pyd (native extension module) using a SourceLoader, which is intended for .py files (text). Native extensions like .pyd must be loaded using ExtensionFileLoader — otherwise, you’ll get DLL or encoding-related errors.
Assuming you dynamically created this structure:
/a/temp/dir/foo/
__init__.py
bar.pyd
You can correctly import the package and the .pyd module like this:
import sys
import importlib.util
import importlib.machinery
import os
def import_pyd_module(package_name, module_name, path_to_pyd, path_to_init):
# Ensure package is imported first
if package_name not in sys.modules:
spec_pkg = importlib.util.spec_from_file_location(
package_name,
path_to_init,
submodule_search_locations=[os.path.dirname(path_to_init)]
)
module_pkg = importlib.util.module_from_spec(spec_pkg)
sys.modules[package_name] = module_pkg
spec_pkg.loader.exec_module(module_pkg)
# Load the compiled submodule
fullname = f"{package_name}.{module_name}"
loader = importlib.machinery.ExtensionFileLoader(fullname, path_to_pyd)
spec = importlib.util.spec_from_file_location(fullname, path_to_pyd, loader=loader)
module = importlib.util.module_from_spec(spec)
sys.modules[fullname] = module
spec.loader.exec_module(module)
return module
Your MyLoader inherits from SourceLoader, which expects a .py file and calls get_data() expecting text. This cannot be used for .pyd files, which are binary and must be handled using the built-in ExtensionFileLoader.
If you want a custom import system with dynamic .pyd loading, you can still use a MetaPathFinder, but your loader must delegate to ExtensionFileLoader.
Usage:
mod = import_pyd_module(
package_name="foo",
module_name="bar",
path_to_pyd="/a/temp/dir/foo/bar.pyd",
path_to_init="/a/temp/dir/foo/__init__.py"
)
mod.some_method()
Spanish
Estás teniendo este problema porque intentas cargar un módulo compilado .pyd usando un SourceLoader, que está diseñado para archivos .py (texto fuente). Los archivos .pyd (extensiones nativas en Windows) deben cargarse usando ExtensionFileLoader, o de lo contrario recibirás errores como el de carga de DLL o problemas de codificación.
Supongamos que creaste dinámicamente la siguiente estructura:
/a/temp/dir/foo/
__init__.py
bar.pyd
Puedes importar correctamente el paquete y el módulo .pyd con el siguiente código:
import sys
import importlib.util
import importlib.machinery
import os
def importar_pyd_como_modulo(nombre_paquete, nombre_modulo, ruta_pyd, ruta_init):
# Asegurar que el paquete esté importado primero
if nombre_paquete not in sys.modules:
spec_pkg = importlib.util.spec_from_file_location(
nombre_paquete,
ruta_init,
submodule_search_locations=[os.path.dirname(ruta_init)]
)
modulo_pkg = importlib.util.module_from_spec(spec_pkg)
sys.modules[nombre_paquete] = modulo_pkg
spec_pkg.loader.exec_module(modulo_pkg)
# Cargar el submódulo compilado
nombre_completo = f"{nombre_paquete}.{nombre_modulo}"
loader = importlib.machinery.ExtensionFileLoader(nombre_completo, ruta_pyd)
spec = importlib.util.spec_from_file_location(nombre_completo, ruta_pyd, loader=loader)
modulo = importlib.util.module_from_spec(spec)
sys.modules[nombre_completo] = modulo
spec.loader.exec_module(modulo)
return modulo
MyLoaderTu clase MyLoader hereda de SourceLoader, lo cual no sirve para archivos .pyd, porque espera archivos fuente .py y llama a get_data() esperando texto plano. Sin embargo, .pyd es binario, y debe manejarse con el loader nativo de extensiones: ExtensionFileLoader.
Si deseas implementar un sistema de carga personalizado, puedes seguir usando MetaPathFinder, pero el loader debe delegar a ExtensionFileLoader.