使用Jython将我的Python脚本作为JAR文件分发?

时间:2009-08-10 03:11:52

标签: python jython distribution executable-jar

我已经成为一名Python程序员已有近两年了,而且我习惯于编写小脚本来自动化我在办公室必须完成的一些重复性任务。现在,显然我的同事注意到了这一点,他们也想要那些脚本。

其中一些有Mac,有些是Windows;我在windows上做了这些。我调查了使用py2exe甚至py2app制作我的脚本的原生的可能性,但他们从未满足我......

我开始知道他们所有人都在他们的系统上有JVM,所以我可以使用像Jython这样的东西给他们一个可执行的JAR文件吗?

这有多可行......我的意思是,我不知道如何为Jython编写脚本,当我编写它们时我也不关心它...它会给出什么样的问题?

4 个答案:

答案 0 :(得分:66)

本文在Jython的wiki上详细介绍了在jar中分发Python文件的最新技术:http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

对于你的情况,我想你会想要获取安装Jython时获得的jython.jar文件并将Jython Lib目录压缩到其中,然后压缩.py文件,然后添加{{1带有启动逻辑的文件(这个文件由Jython专门处理,将是用“java -jar”调用jar时执行的文件。)

这个过程肯定比应该更复杂,因此我们(Jython开发人员)需要提出一个可以自动执行这些任务的好工具,但是现在这些是最好的方法。下面我复制上面文章底部的配方(略微修改以适合您的问题描述),让您了解解决方案。

创建基本jar:

__run__.py

将其他模块添加到jar:

$ 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

在MS Windows上,设置CLASSPATH环境变量的最后一行看起来像这样:

# 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%

或者,如果您已将启动脚本添加到jar中,请使用以下方法之一:

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

双is有点讨厌,所以如果你想避免这种情况并且更加讨人喜欢:

$ 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

你需要做更多的工作,直到我们得到这样的东西到未来的Jython [更新:JarRunner是Jython 2.5.1的一部分]。下面是一些自动查找$ java -jar myapp.jar arg1 并运行它的Java代码。请注意,这是我在这堂课上的第一次尝试。如果需要改进,请告诉我!

__run__.py

我把这段代码放到了org.python.util包中,因为如果我们决定将它包含在未来的Jython中,它就会发生。要编译它,你需要将jython.jar(或你的myapp.jar)放入类路径中:

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

然后你需要将JarRunner.class添加到你的jar中(类文件需要在org / python / util / JarRunner.class中)在“org”目录下调用jar将获得进入你的整个路径广口瓶中。

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

将此添加到您将用于更新清单的文件中,一个好名称是manifest.txt:

$ jar uf org

然后更新jar的清单:

Main-Class: org.python.util.JarRunner

现在您应该能够像这样运行您的应用程序:

$ jar ufm myapp.jar manifest.txt

答案 1 :(得分:2)

我遇到了类似的问题,因为我希望能够为我的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系统上,它只运行一个大的shell脚本来正确形成java命令行调用。这个jython启动程序似乎依赖于回到jython的核心安装,并且通过某种魔术方式允许正确处理在运行时从.py脚本中添加到sys.path的.jar文件。您可以通过以下方式查看调用内容和阻止执行:

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并运行一个类文件。所以我的目标是能够对我的发行版的lib目录中存在的独立jython.jar进行java调用,这样用户就不需要做任何额外的安装步骤来开始使用我的.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发行版太紧。所以这个想法不会飞。最后,在经过大量搜索后,我在jython.org上遇到了#1776的错误,该错误被列为关键的一年半,但我没有看到jython的最新更新包含修复。尽管如此,如果您遇到让jython包含单独的jar文件的问题,您应该阅读此内容。

http://bugs.jython.org/issue1776

在那里,您将找到此临时解决方法。在我的例子中,我将Apache POI jar文件解压缩到它自己独立的lib目录中,然后修改sys.path条目以指向目录而不是jar:

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

现在,当我通过java运行jython时,引用我的本地jython.jar,该实用程序只运行peachy。现在,我可以创建简单的脚本或批处理文件,为我的.py实用程序提供无缝的命令行体验,用户无需任何额外的安装步骤即可运行。

答案 2 :(得分:1)

'jythonc'命令应该能够将.py源代码编译成JVM字节码,这应该可以移植到任何Java安装。或者我读到:http://hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html

答案 3 :(得分:1)

为了以不需要本机Python安装的方式分发Python脚本,您还可以尝试Nuitka,它基本上将您的Python代码转换为C ++代码,然后将其编译为真正的本机二进制代码

相关问题