2010-07-15 19 views
6

La aplicación My Python está construida de tal manera que algunas funcionalidades están disponibles como complementos. La arquitectura del complemento actualmente es muy simple: tengo una carpeta/paquete de complementos que contiene algunos módulos de python. Me carga el plugin correspondiente de la siguiente manera:Carga dinámica de complementos python sin compilar en el código de compilación py2exe

plugin_name = blablabla 
try: 
    module = __import__(plugin_name, fromlist='do_something') 
except ImportError: 
    #some error handling ... 

y luego ejecutar:

try: 
    loans = module.do_something(id_t, pin_t) 
except xxx: 
    # error handling 

puedo compilar la aplicación a un binario utilizando py2exe de Windows. Esto funciona bien, excepto por el hecho de que todos los complementos están (y deben estar) incluidos en el binario. Esto no es muy práctico, ya que para cada nuevo complemento, tengo que volver a compilar y lanzar una nueva versión de mi aplicación. Sería mejor si un nuevo complemento (es decir, un archivo de Python) pudiera copiarse en alguna carpeta de complemento de la aplicación, y que el código de Python en el código del archivo sea interpretado sobre la marcha por mi aplicación.

¿Cuál es el mejor enfoque para hacerlo?

(aunque he de leer cada línea del archivo plugin seleccionado, y aplicando un exec statement a ella. Sin embargo, podría haber mejores maneras ...)

Respuesta

0

le sugiero que utilice pkg_resources entry_points características (de setuptools/distributed) para implementar el descubrimiento y creación de instancias de plugins: primero, es una forma estándar de hacerlo; segundo, no sufre el problema que menciona AFAIK. Todo lo que tienes que hacer para extender la aplicación es empaquetar algunos complementos en un huevo que declare algunos puntos de entrada (un huevo puede declarar muchos complementos), y cuando instales ese huevo en tu distribución de Python, todos los complementos que declara pueden ser automáticamente descubierto por su aplicación. También puede empaquetar su aplicación y los complementos de "fábrica" ​​en el mismo huevo, es bastante conveniente.

+1

Gracias por la respuesta. Pero, ¿no sería necesario que alguien tenga Python instalado en su computadora? (La solución que propuse, lo requeriría, ahora que lo pienso) – Rabarberski

+0

Tiene razón, debe ser la misma instalación de python tanto para su aplicación como para los complementos externos. Estoy de acuerdo, esto es bastante molesto. –

0

No estoy seguro de que tenga que poner archivos de complemento en la biblioteca zip. Esto puede deberse a que está utilizando el valor predeterminado para el empaquetado py2exe de su script.

Podría intentar usar compressed = False (como se documentó en py2exe ListOfOptions) que eliminaría el archivo library.zip generado por py2exe, y posiblemente le permitiría tener acceso a los módulos de python (sus complementos son módulos de Python, supongo, del import) de forma "normal", en lugar de forzarlos a empaquetarlos en su zip o binario.

1

PyInstaller le permite importar archivos externos también. Si lo ejecuta sobre su aplicación, no empacará esos archivos dentro del ejecutable. Luego deberá asegurarse de que las rutas sean correctas (es decir, su aplicación pueda encontrar los módulos en el disco en el directorio correcto) y todo debería funcionar.

2

Si no te importa que el complemento se libere como archivos .py, puedes hacer algo como lo siguiente. Pon todos tus complementos bajo un subdirectorio "plugin" y crea un "__init__.py" vacío. Realizando el tiempo de ejecución, importará el paquete junto con todos los módulos en ese directorio. Consulte Dive In Python para una explicación ... pero esto es lo que finalmente uso.

def load_plugin(path): 
    import imp 
    """Load plugin from directory and return list of modules""" 
    files = os.listdir(path) 
    test = re.compile(".py$", re.IGNORECASE)   
    files = filter(test.search, files)      
    filenameToModuleName = lambda f: os.path.splitext(f)[0] 
    moduleNames = sorted(map(filenameToModuleName, files)) 
    f, filename, desc = imp.find_module('plugin') 
    plugin = imp.load_module('plugin', f, filename, desc) 
    modules = [] 

    #print moduleNames 
    for m in moduleNames: 
     # skip any files starting with '__', such as __init__.py 
     if m.startswith('__'): 
      continue 
     try: 
      f, filename, desc = imp.find_module(m, plugin.__path__) 
      modules.append(imp.load_module(m, f, filename, desc)) 
     except ImportError: 
      continue 
    return modules 
+0

¿Sería posible que esos módulos carguen Clases que existen en la versión compilada? –

0

He encontrado la manera de hacer la importación de módulos externos (en la parte superior del ejecutable compilado, en tiempo de ejecución) con PyInstaller. se da cuenta de que originalmente, la ruta del ejecutable se agregó automáticamente a sys.path, pero por razones de seguridad eliminaron esto en algún momento. para volver a habilitar esto, utilice:

sys.path.append(os.path.dirname(sys.executable)) 

Esto permitirá importar archivos .py que se sientan en el mismo camino que el ejecutable. puede agregar esta línea al enlace de tiempo de ejecución o a la aplicación principal.

Cuestiones relacionadas