2009-08-10 24 views
53

He sido programador de Python durante casi dos años, y estoy acostumbrado a escribir pequeños guiones para automatizar algunas tareas repetitivas que tenía que hacer en la oficina. Ahora, aparentemente mis colegas notaron esto, y quieren esos guiones también.¿Distribuir mis scripts de Python como archivos JAR con Jython?

Algunos de ellos tienen Mac, algunos Windows; Hice estos en Windows. Investigué la posibilidad de utilizar py2exe o incluso py2app para hacer nativos de mi script, pero nunca me satisfizo ...

Me enteré de que todos ellos tienen JVM en sus sistemas, así que puedo darles un solo ejecutable archivo JAR de mi script usando algo como Jython puede ser?

¿Qué tan factible es esto ... Quiero decir, no tenía idea de cómo escribir guiones para Jython, tampoco me importó cuando los escribí ... ¿qué tipo de problemas le dará?

Respuesta

65

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

Para su caso, pienso que usted quiere tomar la jython archivo .jar que se obtiene cuando instala Jython y comprime el directorio Jython Lib, luego comprime tus archivos .py y luego agrega un archivo __run__.py con tu lógica de inicio (este archivo es tratado especialmente por Jython y será el archivo ejecutado cuando llamas al jar con "java -jar").

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

Crear el frasco básica:

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

añadir otros módulos a la jarra:

$ 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ñadir el módulo __run__.py:

# 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, la última línea, establecer la variable de entorno CLASSPATH se vería así:

set CLASSPATH=C:\path\to\my\app\myapp.jar;%CLASSPATH% 

O, de nuevo en MS Windows, utilice el Panel de control y las propiedades del sistema para establecer la variable de entorno CLASSPATH.

ejecutar la aplicación:

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

O, si ha añadido el script de arranque para el frasco, utilice 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 

La doble-jar es una especie de molesto, por lo que si se quiere evitar eso y conseguir el más agradable:

$ java -jar myapp.jar arg1 

Vas a tener que hacer un poco más trabajo unt Si obtenemos algo como esto en un futuro Jython [Actualización: JarRunner es parte de 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íseme si necesita una mejora!

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); 
    } 
} 

pongo este código en el paquete org.python.util, ya que es donde iría si decidimos incluirlo en un futuro Jython. Para compilarlo, tendrá que poner jython.jar (o su myapp.jar) en la ruta de clases como:

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

A continuación, tendrá que añadir JarRunner.class a su frasco (el archivo de clase se necesita estar en org/python/util/JarRunner.class) jar llamada en el directorio "org" obtendrá la ruta completa en su jar.

$ jar uf org 

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

Main-Class: org.python.util.JarRunner 

Entonces manifiesto de actualización de la jarra:

$ jar ufm myapp.jar manifest.txt 

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

$ java -jar myapp.jar 
+0

hey Frank, gracias por la información, en realidad ... una cosa, estoy recibiendo un error al comando "zip myapp .jar Lib/showobjs.py "... ¿qué se supone que debe hacer? –

+0

Aparentemente, el intérprete jython debe invocarse antes de que mi script pueda hacer algo ... lo que me dice que "java -jar MyScript.jar" para ejecutar mi script python no es posible. ¡Muchas gracias, Frank! –

+0

Debería poder configurar las cosas para que "java -jar MyScript.jar" funcione. Más tarde hoy editaré mis pasos para hacer un ejemplo más concreto. –

1

El comando 'jythonc' debería ser capaz de compilar su fuente .py en código de byte JVM, lo que debería hacer que sea portátil para cualquier instalación de Java. O eso es lo que leí en: http://hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html

+3

Gracias por el enlace .. No sabía acerca de jythonc, pero me enteré de que jythonc ya no se mantiene ... http://www.jython.org/archive/22/jythonc.html I no pude encontrar ninguna ayuda en cuanto a cómo usar el comando jython para hacer jarras ... cualquier ayuda en eso apreciado –

2

Tuve un problema similar al querer crear simples llamadas de línea de comandos para mis aplicaciones jython, no requerir que el usuario pase por el proceso de instalación de jython, y poder hacer que las secuencias de comandos jython anexen dependencias de biblioteca en tiempo de ejecución a sys.path para incluir código core 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 los sistemas Unix, que sólo se ejecuta un script de shell grande como para formar adecuadamente una llamada de línea de comandos de Java. Este lanzador de jython parece tener una dependencia en llegar a una instalación central de jython, y de alguna forma de magia permite el manejo apropiado de los archivos .jar agregados a sys.path en tiempo de ejecución desde mis scripts .py. Se puede ver lo que es la llamada y la ejecución del bloque por la siguiente:

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 aún así es simplemente encendiendo una JVM y la ejecución de un archivo de clase. Así que 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 tengan que hacer ningún paso de instalación adicional para comenzar a usar mis utilidades con scripts .py.

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

El problema es que el comportamiento es bastante diferente que iba a 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 se podría decir que yo debería agregar los archivos jar a la -classpath, que de hecho Lo intenté, pero obtendría el mismo resultado.

La sugerencia de agrupar todos tus archivos .class en jython.jar no me pareció nada atractiva. Sería un desastre y uniría la aplicación híbrida de Java/Python con la distribución de jython. Entonces esa idea no iba a volar. Finalmente, después de muchas búsquedas, me encontré con 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 por separado, debe leer esto.

http://bugs.jython.org/issue1776

En allí, se encuentra la solución temporal para esto. En mi caso, tomé el archivo jar Apache POI y unjar'ed en su propio directorio lib separada y luego modifiqué la entrada sys.path a punto para el directorio en lugar de la jarra:

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

Ahora, cuando Ejecuto jython por medio de java, haciendo referencia a mi jython.jar local, la utilidad se ejecuta solo en color melocotón. Ahora puedo crear scripts simples o archivos por lotes para hacer una experiencia de línea de comandos perfecta para mis utilidades .py, que el usuario puede ejecutar sin ningún otro paso de instalación.

+0

Esta es una buena publicación, gracias por compartir su experiencia y conocimiento. También he estado trabajando con jython y experimentando los mismos problemas que tú. (+1) – Eder

0

Para distribuir sus scripts Python de una manera que no requiera una instalación nativa de Python, también puede intentar Nuitka, que básicamente traduce su código Python a código C++, que luego se compila en un binario verdadero nativo.

Cuestiones relacionadas