web-dev-qa-db-fra.com

Distribuer mes Python sous forme de fichiers JAR avec Jython?

Je suis un programmeur Python depuis près de deux ans, et j'ai l'habitude d'écrire de petits scripts pour automatiser certaines tâches répétitives que je devais faire au bureau. Maintenant, apparemment, mes collègues l'ont remarqué, et ils veulent aussi ces scripts.

Certains d'entre eux ont des Mac, d'autres Windows; Je les ai faites sur des fenêtres. J'ai étudié la possibilité d'utiliser py2exe ou même py2app pour créer des natifs de mon script, mais ils ne m'ont jamais satisfait ...

J'ai appris que tous ont JVM sur leurs systèmes, alors puis-je leur donner un seul fichier JAR exécutable de mon script en utilisant quelque chose comme Jython?

Dans quelle mesure est-ce possible ... Je veux dire, je n'avais aucune idée de comment écrire des scripts pour Jython, je m'en fichais quand je les ai écrits ... quel genre de problèmes cela va-t-il poser?

55
Shrikant Sharat

Les meilleures techniques actuelles pour distribuer vos Python dans un bocal sont détaillées dans cet article sur le wiki de Jython: http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

Pour votre cas, je pense que vous voudriez prendre le fichier jython.jar que vous obtenez lorsque vous installez Jython et zippez le répertoire Jython Lib dedans, puis zippez vos fichiers .py, puis ajoutez un __run__.py fichier avec votre logique de démarrage (ce fichier est traité spécialement par Jython et sera le fichier exécuté lorsque vous appelez le pot avec "Java -jar").

Ce processus est certainement plus compliqué qu'il ne devrait l'être, et nous (les développeurs Jython) devons donc trouver un outil agréable qui automatisera ces tâches, mais pour l'instant ce sont les meilleures méthodes. Ci-dessous, je copie la recette au bas de l'article ci-dessus (légèrement modifiée pour correspondre à la description de votre problème) pour vous donner une idée de la solution.

Créez le pot de base:

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

Ajoutez d'autres modules dans le pot:

$ 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

Ajouter le __run__.py module:

# Copy or rename your start-up script, removing the "__ == '__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

Sur MS Windows, cette dernière ligne, définissant la variable d'environnement CLASSPATH, ressemblerait à ceci:

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

Ou, encore une fois sur MS Windows, utilisez le Panneau de configuration et les propriétés système pour définir la variable d'environnement CLASSPATH.

Exécutez l'application:

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

Ou, si vous avez ajouté votre script de démarrage au bocal, utilisez l'une des méthodes suivantes:

$ 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

Le double -jar est un peu ennuyeux, donc si vous voulez éviter cela et être plus agréable:

$ Java -jar myapp.jar arg1

Vous devrez faire un peu plus de travail jusqu'à ce que nous obtenions quelque chose comme ça dans un futur Jython [Mise à jour: JarRunner fait partie de Jython 2.5.1]. Voici un code Java qui recherche le __run__.py automatiquement et l'exécute. Notez que c'est mon premier essai dans cette classe. Faites-moi savoir si elle doit être améliorée!

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

J'ai mis ce code dans le package org.python.util, car c'est là qu'il irait si nous décidions de l'inclure dans un futur Jython. Pour le compiler, vous devrez mettre jython.jar (ou votre myapp.jar) dans le chemin de classe comme:

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

Ensuite, vous devrez ajouter JarRunner.class à votre jar (le fichier de classe devra être dans org/python/util/JarRunner.class) en appelant jar dans le répertoire "org", vous obtiendrez le chemin complet dans votre jar.

$ jar uf org

Ajoutez ceci à un fichier que vous utiliserez pour mettre à jour le manifeste, un bon nom est manifest.txt:

Main-Class: org.python.util.JarRunner

Mettez ensuite à jour le manifeste du pot:

$ jar ufm myapp.jar manifest.txt

Vous devriez maintenant pouvoir exécuter votre application comme ceci:

$ Java -jar myapp.jar
66
Frank Wierzbicki

J'ai rencontré un problème similaire en ce sens que je veux pouvoir créer des appels de ligne de commande simples pour mes applications jython, ne pas exiger que l'utilisateur passe par le processus d'installation de jython et pouvoir demander aux scripts jython d'ajouter les dépendances de bibliothèque au moment de l'exécution à sys .path afin d'inclure le noyau Java code.

# 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"))

Lors de l'exécution explicite du lanceur 'jython' sur la ligne de commande, sur les systèmes Unix, il exécute simplement un gros script Shell pour former correctement un appel de ligne de commande Java. Ce lanceur jython semble avoir une dépendance sur revenir à une installation de base de jython, et par une certaine manière magique permet la bonne gestion des fichiers .jar ajoutés au sys.path lors de l'exécution à partir de mes scripts .py. Vous pouvez voir ce qu'est l'appel et bloquer l'exécution par ce qui suit:

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

Mais il s'agit toujours de lancer une JVM et d'exécuter un fichier de classe. Mon objectif était donc de pouvoir faire cet appel Java à un jython.jar autonome présent dans le répertoire lib de ma distribution afin que les utilisateurs n'aient pas besoin de faire des étapes d'installation supplémentaires pour commencer à utiliser mon .py utilitaires scriptés.

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

Le problème est que le comportement est suffisamment différent pour que j'obtienne des réponses comme ceci:

  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

Maintenant, vous pourriez dire que je devrais simplement ajouter les fichiers jar au -classpath, que j'ai en fait essayé, mais j'obtiendrais le même résultat.

La suggestion de regrouper tous vos fichiers .class dans un fichier jython.jar ne me semblait pas du tout attrayante. Ce serait un gâchis et lierait trop étroitement l'application hybride Java/Python à la distribution jython. Donc, cette idée n'allait pas voler. Enfin, après de nombreuses recherches, j'ai rencontré le bogue # 1776 sur jython.org, qui est répertorié comme critique depuis un an et demi, mais je ne vois pas que les dernières mises à jour de jython intègrent un correctif. Néanmoins, si vous rencontrez des problèmes pour que jython inclue vos fichiers jar séparés, vous devriez lire ceci.

http://bugs.jython.org/issue1776

Vous y trouverez la solution de contournement temporaire. Dans mon cas, j'ai pris le fichier jar Apache POI et je l'ai décompressé dans son propre répertoire lib distinct, puis j'ai modifié l'entrée sys.path pour pointer vers le répertoire au lieu du jar:

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

Maintenant, lorsque j'exécute jython par le biais de Java, en référençant mon jython.jar local, l'utilitaire s'exécute simplement pêche. Maintenant, je peux créer des scripts simples ou des fichiers batch pour créer une expérience de ligne de commande transparente pour mes utilitaires .py, que l'utilisateur peut exécuter sans aucune étape d'installation supplémentaire.

2
Robert Casey

La commande 'jythonc' devrait être capable de compiler votre source .py en bytecode JVM, ce qui devrait le rendre portable pour toute installation Java. Ou alors je lis sur: http://hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html

1
Yancy

Pour distribuer vos scripts Python d'une manière qui ne nécessite pas d'installation native Python, vous pouvez également essayer Nuitka , qui traduit essentiellement votre code Python en code C++, qui est ensuite compilé en un véritable binaire natif.

1
Tobias Kienzler