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
MyLoader
Tu 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
.