Dystrybuowanie skryptów Pythona jako plików JAR za pomocą Jython?

Jestem programistą Pythona od prawie dwóch lat i jestem przyzwyczajony do pisania małych skryptów do automatyzacji niektórych powtarzalnych zadań, które musiałem wykonać w biurze. Widocznie moi koledzy to zauważyli i też chcą te scenariusze.

Niektóre z nich mają Mac, niektóre Windows; zrobiłem je na windows. Zbadałem możliwość korzystania z py2exe lub nawet py2app do tworzenia mojego skryptu, ale nigdy mnie nie zadowoliły...

Dowiedziałem się, że wszyscy mają JVM na swoich systemów, więc Czy Mogę dać im jeden plik wykonywalny jar mojego skryptu używając czegoś takiego jak Jython może być?

Jak to możliwe... Nie miałem pojęcia, jak pisać scenariusze do Jythona, nie przejmowałem się tym, kiedy je pisałem... co to za problemy?

Author: Peter Mortensen, 2009-08-10

4 answers

Najlepsze techniki dystrybucji plików Pythona w jar są opisane w tym artykule na wiki Jython: http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

Dla twojej sprawy, myślę, że chciałbyś wziąć jython.plik jar, który otrzymujesz po zainstalowaniu Jython i spakowaniu do niego katalogu Jython Lib, a następnie spakowaniu plików .py, a następnie dodaniu pliku __run__.py z logiką startową (plik ten jest traktowany specjalnie przez Jython i będzie plik wykonywany po wywołaniu jar za pomocą "java-jar").

Ten proces jest zdecydowanie bardziej skomplikowany niż w ought to be, więc my (programiści Jython) musimy wymyślić ładne narzędzie, które zautomatyzuje te zadania, ale na razie są to najlepsze metody. Poniżej kopiuję przepis na dole powyższego artykułu (lekko zmodyfikowany, aby pasował do opisu problemu), aby dać poczucie rozwiązania.

Utwórz podstawowy jar:

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

Dodaj inne moduły do słoika:

$ 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

Dodaj moduł __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

W MS Windows ostatnia linia, ustawiająca zmienną środowiskową CLASSPATH, wyglądałaby mniej więcej tak:

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

Lub, ponownie w MS Windows, użyj panelu sterowania i właściwości systemu, aby ustawić zmienną środowiskową CLASSPATH.

Uruchom aplikację:

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

Lub, jeśli dodałeś skrypt startowy do jar, użyj jednej z następujących opcji:

$ 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

The double-jar jest trochę irytujące, więc jeśli chcesz tego uniknąć i uzyskać bardziej przyjemne: {]}

$ java -jar myapp.jar arg1

Będziesz musiał wykonać trochę więcej pracy, dopóki nie wprowadzimy czegoś takiego do przyszłego Jythona [aktualizacja: JarRunner jest częścią Jython 2.5.1]. Oto kod Javy, który szuka __run__.py automatycznie i uruchamia go. Zauważ, że to moja pierwsza próba na tych zajęciach. Daj mi znać, jeśli wymaga poprawy!

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

Umieściłem ten kod w org.python.pakiet util, bo tam by poszedł, gdyby decydujemy się na włączenie go do przyszłego Jythonu. Aby go skompilować, musisz umieścić jython.jar (lub your myapp.jar) do klasy jak:

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

Następnie musisz dodać JarRunner.klasy do twojego jar (plik klasy musi znajdować się w org/python/util/JarRunner.class) wywołanie jar w katalogu " org " przeniesie całą ścieżkę do twojego jar.

$ jar uf org

Dodaj to do pliku, który będzie używany do aktualizacji manifestu, dobra nazwa to manifest.txt:

Main-Class: org.python.util.JarRunner

Następnie zaktualizuj manifest Jara:

$ jar ufm myapp.jar manifest.txt

Teraz powinieneś móc uruchomić swoją aplikację w następujący sposób:

$ java -jar myapp.jar
 65
Author: Frank Wierzbicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-28 10:24:59

Doświadczyłem podobnego problemu w tym, że chcę być w stanie tworzyć proste wywołania linii poleceń dla moich aplikacji jython, nie wymagając, aby użytkownik przeszedł proces instalacji jython i mógł mieć Skrypty jython dołączać zależności bibliotek w czasie wykonywania do sys.ścieżka tak, aby zawierać rdzeń kodu 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"))

Podczas uruchamiania programu uruchamiającego' jython ' jawnie w linii poleceń, w systemach uniksowych, uruchamia on po prostu duży skrypt powłoki, aby poprawnie utworzyć wywołanie linii poleceń Javy. To Jython launcher wydaje się być uzależniony od sięgnięcia do podstawowej instalacji jythona, a w jakiś sposób Magia pozwala na właściwą obsługę .pliki jar dodawane do sys.ścieżka w czasie wykonywania z poziomu skryptów my. py. Możesz zobaczyć, co to jest wywołanie i zablokować wykonanie w następujący sposób:

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
Ale wciąż odpala JVM i uruchamia plik klasowy. Więc moim celem było być w stanie wykonać to połączenie java do samodzielnego jython.jar obecny w katalogu mojej dystrybucji lib więc użytkownicy nie trzeba wykonywać żadnych dodatkowych kroków instalacji, aby rozpocząć korzystanie z narzędzi skryptowych .py.
java -Xmx512m -Xss1024k -classpath ../../lib/jython.jar org.python.util.jython run_form.py

Problem polega na tym, że zachowanie jest na tyle inne, że otrzymywałbym takie odpowiedzi:

  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

Teraz można powiedzieć, że powinienem po prostu dodać pliki jar do-classpath, co w rzeczywistości próbowałem, ale uzyskałbym ten sam wynik.

Sugestia połączenia wszystkich swoich .pliki klas w jythonie.jar wcale mi nie przemawiał. To byłby bałagan i powiązać aplikację hybrydową Java / Python zbyt mocno z dystrybucją jython. Więc ten pomysł nie miał się udać. W końcu po wielu poszukiwaniach natknąłem się na bug #1776 Na jython.org, który został wymieniony jako krytyczny przez półtora roku, ale nie widzę, aby najnowsze aktualizacje jythona zawierały poprawkę. Mimo to, jeśli masz problemy z dołączeniem oddzielnych plików jar przez jython, powinieneś to przeczytać.

Http://bugs.jython.org/issue1776

W tam znajdziesz tymczasowe obejście tego problemu. W moim przypadku wziąłem plik Apache POI jar i rozpakowałem go do osobnego katalogu lib, a następnie zmodyfikowałem sys.wejście ścieżki do katalogu zamiast jar:

sys.path.append('/Users/test/Eclipse/workspace/test_code/lib/poi_lib')
Teraz, kiedy uruchamiam jython poprzez Javę, odwołując się do mojego lokalnego jythona.jar, narzędzie działa po prostu brzoskwiniowo. Teraz mogę tworzyć proste skrypty lub pliki wsadowe, aby zapewnić bezproblemową obsługę wiersza poleceń dla moich narzędzi. py, które użytkownik może uruchomić bez wszelkie dodatkowe kroki instalacji.
 2
Author: Robert Casey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-15 18:04:39

Polecenie 'jythonc' powinno być w stanie skompilować twoje źródło .py do kodu bajtowego JVM, co powinno sprawić, że będzie ono przenośne do dowolnej instalacji Javy. A tak czytam na: http://hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html

 1
Author: Yancy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-10 05:47:00

Aby rozpowszechniać Skrypty Pythona w sposób, który nie wymaga natywnej instalacji Pythona, możesz również spróbować Nuitka , która zasadniczo tłumaczy Twój kod Pythona na kod C++, który jest następnie kompilowany do prawdziwej natywnej binarnej.

 0
Author: Tobias Kienzler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-11 09:36:11