Saltar al contenido

¿Distribuir mis scripts de Python como archivos JAR con Jython?

Solución:

Las mejores técnicas actuales para distribuir sus archivos de Python en un jar se detallan en este artículo en la wiki de Jython: http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

Para su caso, creo que querrá tomar el archivo jython.jar que obtiene cuando instala Jython y comprimir el directorio Jython Lib en él, luego comprimir sus archivos .py y luego agregar un __run__.py archivo con su lógica de inicio (este archivo es tratado especialmente por Jython y será el archivo ejecutado cuando llame al jar con “java -jar”).

Este proceso es definitivamente más complicado de lo que debería ser, por lo que nosotros (los desarrolladores de Jython) necesitamos crear una buena herramienta que automatice estas tareas, pero por ahora estos son los mejores métodos. A continuación, estoy copiando la receta al final del artículo anterior (modificada ligeramente para que se ajuste a la descripción de su problema) para darle una idea de la solución.

Crea el frasco básico:

$ cd $JYTHON_HOME
$ cp jython.jar jythonlib.jar
$ zip -r jythonlib.jar Lib

Agregue otros módulos al frasco:

$ cd $MY_APP_DIRECTORY
$ cp $JYTHON_HOME/jythonlib.jar myapp.jar
$ zip myapp.jar Lib/showobjs.py
# Add path to additional jar file.
$ jar ufm myapp.jar othermanifest.mf

Añade el __run__.py módulo:

# Copy or rename your start-up script, removing the "__name__  == '__main__'" check.
$ cp mymainscript.py __run__.py
# Add your start-up script (__run__.py) to the jar.
$ zip myapp.jar __run__.py
# Add path to main jar to the CLASSPATH environment variable.
$ export CLASSPATH=/path/to/my/app/myapp.jar:$CLASSPATH

En MS Windows, esa última línea, configurando la variable de entorno CLASSPATH, se vería así:

set CLASSPATH=C:pathtomyappmyapp.jar;%CLASSPATH%

O, nuevamente en MS Windows, use el Panel de control y las Propiedades del sistema para configurar la variable de entorno CLASSPATH.

Ejecute la aplicación:

$ java -jar myapp.jar mymainscript.py arg1 arg2

O, si ha agregado su secuencia de comandos de inicio al jar, use uno de los siguientes:

$ java org.python.util.jython -jar myapp.jar arg1 arg2
$ java -cp myapp.jar org.python.util.jython -jar myapp.jar arg1 arg2
$ java -jar myapp.jar -jar myapp.jar arg1 arg2

El doble frasco es un poco molesto, así que si quieres evitarlo y ser más agradable:

$ java -jar myapp.jar arg1

Tendrás que trabajar un poco más hasta que consigamos algo como esto en un futuro Jython [Update: JarRunner is part of Jython 2.5.1]. Aquí hay un código Java que busca el __run__.py automáticamente y lo ejecuta. Tenga en cuenta que este es mi primer intento en esta clase. ¡Avísame si necesita mejorar!

package org.python.util;

import org.python.core.imp;
import org.python.core.PySystemState;

public class JarRunner {

    public static void run(String[] args) {
        final String runner = "__run__";
        String[] argv = new String[args.length + 1];
        argv[0] = runner;
        System.arraycopy(args, 0, argv, 1, args.length);
        PySystemState.initialize(PySystemState.getBaseProperties(), null, argv);
        imp.load(runner);
    }

    public static void main(String[] args) {
        run(args);
    }
}

Puse este código en el paquete org.python.util, ya que ahí es donde iría si decidimos incluirlo en un futuro Jython. Para compilarlo, deberá poner jython.jar (o su myapp.jar) en el classpath como:

$ javac -classpath myapp.jar org/python/util/JarRunner.java

Luego, deberá agregar JarRunner.class a su jar (el archivo de clase deberá estar en org / python / util / JarRunner.class). Al llamar a jar en el directorio “org” obtendrá la ruta completa en su jar.

$ jar uf org

Agregue esto a un archivo que usará para actualizar el manifiesto, un buen nombre es manifest.txt:

Main-Class: org.python.util.JarRunner

Luego actualice el manifiesto del jar:

$ jar ufm myapp.jar manifest.txt

Ahora debería poder ejecutar su aplicación de esta manera:

$ java -jar myapp.jar

Experimenté un problema similar en el sentido de que quiero poder crear llamadas de línea de comando simples para mis aplicaciones jython, no requerir que el usuario pase por el proceso de instalación de jython y poder hacer que los scripts de jython agreguen las dependencias de la biblioteca en tiempo de ejecución a sys .path para incluir el código central de Java.

# append Java library elements to path
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "lib", "poi-3.8-20120326.jar"))

Cuando se ejecuta el lanzador ‘jython’ explícitamente en la línea de comandos, en sistemas Unix, simplemente ejecuta un gran script de shell para formar correctamente una llamada de línea de comandos de Java. Este lanzador de jython parece depender de volver a una instalación central de jython y, de alguna manera mágica, permite el manejo adecuado de los archivos .jar que se agregan a sys.path en tiempo de ejecución desde mis scripts .py. Puede ver cuál es la llamada y bloquear la ejecución de la siguiente manera:

jython --print run_form.py
java -Xmx512m -Xss1024k -Dfile.encoding=UTF-8 -classpath /Applications/jython2.5.2/jython.jar: -Dpython.home=/Applications/jython2.5.2 -Dpython.executable=/Applications/jython2.5.2/bin/jython org.python.util.jython run_form.py

Pero todavía está iniciando una JVM y ejecutando un archivo de clase. Entonces, mi objetivo era poder hacer esta llamada java a un jython.jar independiente presente en el directorio lib de mi distribución para que los usuarios no tuvieran que realizar ningún paso de instalación adicional para comenzar a usar mis utilidades con secuencias de comandos .py.

java -Xmx512m -Xss1024k -classpath ../../lib/jython.jar org.python.util.jython run_form.py

El problema es que el comportamiento es lo suficientemente diferente como para obtener respuestas como esta:

  File "run_form.py", line 14, in <module>
    import xls_mgr
  File "/Users/test/Eclipse/workspace/test_code/py/test/xls_mgr.py", line 17, in <module>
    import org.apache.poi.hssf.extractor as xls_extractor
ImportError: No module named apache

Ahora podría decir que debería agregar los archivos jar a -classpath, que de hecho intenté, pero obtendría el mismo resultado.

La sugerencia de agrupar todos sus archivos .class en un jython.jar no me pareció nada atractiva. Sería un desastre y vincularía la aplicación híbrida Java / Python con demasiada fuerza a la distribución jython. Entonces esa idea no iba a volar. Finalmente, después de muchas búsquedas, encontré el error # 1776 en jython.org, que ha sido catalogado como crítico durante un año y medio, pero no veo que las últimas actualizaciones de jython incorporen una solución. Aún así, si tiene problemas para que jython incluya sus archivos jar separados, debe leer esto.

http://bugs.jython.org/issue1776

Allí, encontrará la solución temporal para esto. En mi caso, tomé el archivo jar de Apache POI y lo abrí en su propio directorio lib separado y luego modifiqué la entrada sys.path para apuntar al directorio en lugar del jar:

sys.path.append('/Users/test/Eclipse/workspace/test_code/lib/poi_lib')

Ahora, cuando ejecuto jython a través de java, haciendo referencia a mi jython.jar local, la utilidad se ejecuta simplemente. Ahora puedo crear scripts simples o archivos por lotes para crear una experiencia de línea de comandos perfecta para mis utilidades .py, que el usuario puede ejecutar sin ningún paso de instalación adicional.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *