Распространять мои скрипты Python как файлы JAR с помощью Jython? - PullRequest
54 голосов
/ 10 августа 2009

Я работаю программистом на Python почти два года, и я привык писать небольшие сценарии для автоматизации некоторых повторяющихся задач, которые мне приходилось выполнять в офисе. Теперь, видимо, мои коллеги это заметили, и им тоже нужны эти сценарии.

Некоторые из них имеют Mac, некоторые Windows; Я сделал это на окнах. Я исследовал возможность использования py2exe или даже py2app для создания нативов моего скрипта, но они меня никогда не удовлетворяли ...

Я узнал, что все они имеют JVM в своих системах, так что я могу дать им один исполняемый файл JAR моего скрипта, используя что-то вроде Jython?

Насколько это возможно ... Я имею в виду, я не знал, как писать сценарии для Jython, и мне было все равно, когда я их писал ... какие проблемы это вызовет?

Ответы [ 4 ]

66 голосов
/ 10 августа 2009

Лучшие современные методы распространения ваших файлов Python в банке подробно описаны в этой статье на вики Jython: http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

В вашем случае, я думаю, вы захотите взять файл jython.jar, который вы получите при установке Jython и заархивировать в него каталог Jython Lib, затем сжать ваши файлы .py и добавить __run__.py файл с логикой запуска (этот файл обрабатывается Jython специально, и он будет выполняться при вызове jar с помощью "java -jar").

Этот процесс определенно более сложный, чем должен, и поэтому нам (разработчикам Jython) нужно придумать хороший инструмент, который автоматизирует эти задачи, но на данный момент это лучшие методы. Ниже я копирую рецепт внизу вышеприведенной статьи (слегка измененный в соответствии с описанием вашей проблемы), чтобы дать вам представление о решении.

Создание основной банки:

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

Добавить другие модули в банку:

$ 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

Добавьте модуль __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

В MS Windows последняя строка, задающая переменную среды CLASSPATH, будет выглядеть примерно так:

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

Или, опять же, в MS Windows, используйте Панель управления и Свойства системы, чтобы установить переменную среды CLASSPATH.

Запустите приложение:

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

Или, если вы добавили сценарий запуска в банку, используйте одно из следующих действий:

$ 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

Двойной сосуд раздражает, поэтому, если вы хотите избежать этого и получить более приятное:

$ java -jar myapp.jar arg1

Вам придется проделать немного больше работы, пока мы не получим нечто подобное в будущем Jython [Обновление: JarRunner является частью Jython 2.5.1]. Вот некоторый код Java, который автоматически ищет __run__.py и запускает его. Обратите внимание, что это моя первая попытка в этом классе. Дайте мне знать, если это нужно улучшить!

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

Я поместил этот код в пакет org.python.util, так как он пойдет туда, если мы решим включить его в будущий Jython. Чтобы скомпилировать его, вам нужно поместить jython.jar (или ваш myapp.jar) в путь к классам, например:

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

Затем вам нужно добавить JarRunner.class в ваш jar (файл класса должен находиться в org / python / util / JarRunner.class), вызвав jar в каталоге "org", вы получите полный путь к вашему файлу. баночка.

$ jar uf org

Добавьте это в файл, который вы будете использовать для обновления манифеста, хорошее имя - manifest.txt:

Main-Class: org.python.util.JarRunner

Затем обновите манифест банки:

$ jar ufm myapp.jar manifest.txt

Теперь вы сможете запускать свое приложение так:

$ java -jar myapp.jar
2 голосов
/ 15 февраля 2013

У меня возникла похожая проблема: я хочу иметь возможность создавать простые вызовы командной строки для своих приложений jython, не требовать, чтобы пользователь проходил процесс установки jython, и чтобы скрипты jython могли добавлять зависимости библиотеки в время выполнения до sys.path, чтобы включить основной код 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"))

При явном запуске средства запуска jython из командной строки в системах Unix он просто запускает большой сценарий оболочки, чтобы правильно сформировать вызов командной строки java. Этот пусковой механизм jython, похоже, зависит от возврата к базовой установке jython и каким-то волшебным образом позволяет правильно обрабатывать файлы .jar, добавляемые в sys.path во время выполнения из моих скриптов .py. Вы можете увидеть, что это за вызов, и заблокировать его выполнение следующим образом:

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

Но это все еще просто запуск JVM и запуск файла класса. Поэтому моя цель состояла в том, чтобы сделать этот java-вызов автономным jython.jar, присутствующим в каталоге lib моего дистрибутива, чтобы пользователям не нужно было выполнять какие-либо дополнительные шаги по установке, чтобы начать использовать мои скриптовые утилиты .py.

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

Беда в том, что поведение достаточно разное, чтобы я мог получить такие ответы:

  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

Теперь вы можете сказать, что я должен просто добавить файлы jar в -classpath, что я и пытался, но я получил бы тот же результат.

Предложение объединить все ваши файлы .class в jython.jar не звучало для меня вообще привлекательным. Это было бы беспорядком и слишком тесно связывало бы гибридное приложение Java / Python с дистрибутивом jython. Так что эта идея не собиралась летать. Наконец, после долгих поисков я наткнулся на ошибку # 1776 на jython.org, которая была признана критической в ​​течение полутора лет, но я не вижу, чтобы последние обновления в jython содержали исправление. Тем не менее, если у вас есть проблемы с включением jython ваших отдельных файлов jar, вам следует прочитать это.

http://bugs.jython.org/issue1776

Там вы найдете временный обходной путь для этого. В моем случае я взял jar-файл Apache POI и распаковал его в отдельный каталог lib, а затем изменил запись sys.path, указав каталог вместо jar:

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

Теперь, когда я запускаю jython посредством java, ссылаясь на мой локальный jython.jar, утилита запускается просто замечательно. Теперь я могу создавать простые сценарии или командные файлы для беспроблемного использования командной строки для моих утилит .py, которые пользователь может запускать без каких-либо дополнительных шагов установки.

1 голос
/ 08 апреля 2015

Для распространения ваших скриптов Python таким образом, чтобы не требовалась нативная установка Python, вы также можете попробовать Nuitka , которая в основном переводит ваш код Python в код C ++, который затем компилируется в истинный родной двоичный файл.

1 голос
/ 10 августа 2009

Команда 'jythonc' должна быть в состоянии скомпилировать ваш источник .py в байт-код JVM, что должно сделать его переносимым для любой установки Java. Или так я читаю по адресу: http://hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html

...