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

发布于 2024-07-30 03:24:24 字数 347 浏览 3 评论 0原文

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

他们中有些人有 Mac,有些人有 Windows; 我在窗户上做了这些。 我研究了使用 py2exe 甚至 py2app 来制作我的脚本的本机的可能性,但他们从来没有让我满意......

我开始知道他们所有人的系统上都有 JVM,所以我可以给他们一个单一的可执行 JAR 文件吗我的脚本可能使用 Jython 之类的东西?

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

I have been a Python programmer for almost two years, and I am used to writing small scripts to automate some repetitive tasks I had to do at the office. Now, apparently my colleagues noticed this, and they want those scripts too.

Some of them have Macs, some Windows; I made these on windows. I investigated the possibility of using py2exe or even py2app to make natives of my script, but they never satisfied me...

I came to know that all of them have JVM on their systems, so can I give them one single executable JAR file of my script using something like Jython may be?

How feasible is this... I mean, I had no idea how to write scripts for Jython, neither did I care about it when I wrote them... what kind of problems will it give?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

兲鉂ぱ嘚淚 2024-08-06 03:24:24

我遇到了类似的问题,因为我希望能够为我的 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"))

当在 Unix 系统上的命令行上显式运行“jython”启动器时,它只运行一个大的 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,该实用程序运行得非常顺利。 现在,我可以创建简单的脚本或批处理文件,为我的 .py 实用程序提供无缝的命令行体验,用户无需任何额外的安装步骤即可运行。

I experienced a similar issue in that I want to be able to create simple command line calls for my jython apps, not require that the user go through the jython installation process, and be able to have the jython scripts append library dependencies at runtime to sys.path so as to include core 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"))

When running the 'jython' launcher explicitly on the command line, on Unix systems, it just runs a big shell script to properly form a java command line call. This jython launcher seems to have a dependency on reaching back to a core install of jython, and by some way of magic allows the proper handling of .jar files being added to the sys.path at runtime from within my .py scripts. You can see what the call is and block execution by the following:

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

But it's still just firing up a JVM and running a class file. So my goal was to be able to make this java call to a standalone jython.jar present in my distribution's lib directory so users would not need to do any additional installation steps to start using my .py scripted utilities.

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

Trouble is that the behavior is enough different that I would get responses like this:

  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

Now you might say that I should just add the jar files to the -classpath, which in fact I tried, but I would get the same result.

The suggestion of bundling all of your .class files in a jython.jar did not sound appealing to me at all. It would be a mess and would bind the Java/Python hybrid application too tightly to the jython distribution. So that idea was not going to fly. Finally, after lots of searching, I ran across bug #1776 at jython.org, which has been listed as critical for a year and a half, but I don't see that the latest updates to jython incorporate a fix. Still, if you're having problems with having jython include your separate jar files, you should read this.

http://bugs.jython.org/issue1776

In there, you will find the temporary workaround for this. In my case, I took the Apache POI jar file and unjar'ed it into its own separate lib directory and then modified the sys.path entry to point to the directory instead of the jar:

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

Now, when I run jython by way of java, referencing my local jython.jar, the utility runs just peachy. Now I can create simple scripts or batch files to make a seamless command line experience for my .py utilities, which the user can run without any additional installation steps.

全部不再 2024-08-06 03:24:24

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

The 'jythonc' command should be able to compile your .py source into JVM bytecode, which should make it portable to any Java install. Or so I read at: http://hell.org.ua/Docs/oreilly/other2/python/0596001886_pythonian-chp-25-sect-3.html

伴随着你 2024-08-06 03:24:24

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

For distributing your Python scripts in a way that doesn't require a native Python installation, you could also try Nuitka, which basically translates your Python code to C++ code, which is then compiled to a true native binary.

简单 2024-08-06 03:24:24

Jython wiki 上的这篇文章详细介绍了当前在 jar 中分发 Python 文件的最佳技术:http: //wiki.python.org/jython/JythonFaq/DistributingJythonScripts

对于您的情况,我认为您需要获取安装 Jython 时获得的 jython.jar 文件并将 Jython Lib 目录压缩到其中,然后压缩您的 .py 文件,然后添加一个包含启动逻辑的 __run__.py 文件(该文件由 Jython 特殊处理,并且将是您使用“java -jar”调用 jar 时执行的文件”)。

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

创建基本 jar:

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

将其他模块添加到 jar:

$ 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

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

$ 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

双 jar 有点烦人,因此如果您想避免这种情况并获得更令人愉悦的效果:

$ java -jar myapp.jar arg1

您将必须做更多的工作,直到我们将类似的东西纳入未来的 Jython [更新:JarRunner 是 Jython 2.5.1 的一部分]。 下面是一些自动查找 __run__.py 并运行它的 Java 代码。 请注意,这是我第一次尝试这门课。 如果需要改进请告诉我!

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) 在“org”目录中调用 jar 将获取 jar 的整个路径。

$ jar uf org

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

Main-Class: org.python.util.JarRunner

然后更新jar的清单:

$ jar ufm myapp.jar manifest.txt

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

$ java -jar myapp.jar

The best current techniques for distributing your Python files in a jar are detailed in this article on Jython's wiki: http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts

For your case, I think you would want to take the jython.jar file that you get when you install Jython and zip the Jython Lib directory into it, then zip your .py files in, and then add a __run__.py file with your startup logic (this file is treated specially by Jython and will be the file executed when you call the jar with "java -jar").

This process is definitely more complicated then in ought to be, and so we (the Jython developers) need to come up with a nice tool that will automate these tasks, but for now these are the best methods. Below I'm copying the recipe at the bottom of the above article (modified slightly to fit your problem description) to give you a sense of the solution.

Create the basic jar:

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

Add other modules to the jar:

$ 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

Add the __run__.py module:

# 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

On MS Windows, that last line, setting the CLASSPATH environment variable, would look something like this:

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

Or, again on MS Windows, use the Control Panel and the System properties to set the CLASSPATH environment variable.

Run the application:

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

Or, if you have added your start-up script to the jar, use one of the following:

$ 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 is kind of annoying, so if you want to avoid that and get the more pleasing:

$ java -jar myapp.jar arg1

You'll have to do a bit more work until we get something like this into a future Jython [Update: JarRunner is part of Jython 2.5.1]. Here is some Java code that looks for the __run__.py automatically, and runs it. Note that this is my first try at this class. Let me know if it needs improvement!

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

I put this code into the org.python.util package, since that's where it would go if we decide to include it in a future Jython. To compile it, you'll need to put jython.jar (or your myapp.jar) into the classpath like:

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

Then you'll need to add JarRunner.class to your jar (the class file will need to be in org/python/util/JarRunner.class) calling jar on the "org" directory will get the whole path into your jar.

$ jar uf org

Add this to a file that you will use to update the manifest, a good name is manifest.txt:

Main-Class: org.python.util.JarRunner

Then update the jar's manifest:

$ jar ufm myapp.jar manifest.txt

Now you should be able to run your app like this:

$ java -jar myapp.jar
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文