Я пытаюсь открыть файл jar и выполнить его основную функцию, но jpype выдает ошибку, которая не имеет смысла для меня. Вот мой код:

jpype.startJVM(jpype.getDefaultJVMPath(), '-Djava.class.path="%s"' % jar)
CommandLine = jpype.JPackage('phylonet').coalescent.CommandLine
CommandLine.main(['-i', input_file, '-o', output_file])
jpype.shutdownJVM()

Я получаю эту ошибку: TypeError: Пакет phylonet.coalescent.CommandLine.main не может быть вызван

Я указал абсолютный путь к файлу jar и получил основную функцию из META-INF / MANIFEST.MF:

cat tmp/META-INF/MANIFEST.MF | grep Main-Class
Main-Class: phylonet.coalescent.CommandLine

Файл jar, который я пытаюсь открыть, называется астральным, отсюда: https://github.com/smirarab/ ASTRAL

Называя это так работает как ожидалось:

java -Djava.class.path="./astral.jar"

Так почему бы и нет, когда я называю это jpype?

3
David Mulder 17 Апр 2019 в 01:33

2 ответа

Лучший ответ

Прежде всего, я проверил ваш код на своем собственном jarfile. Действительно, мне подарили такую ошибку:

TypeError: Package clip.frontend.Start.main is not Callable

Затем, внимательно прочитав документы, я использовал другой метод.

import jpype

# I've used other set of parameters to JVM, and modified a bit your classpath setting.
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=clip.jar")

# Second difference, I decided to use JClass because it was more clear for me.
# Parameter array was kept empty.
jpype.JClass("clip.frontend.Start").main([])
jpype.shutdownJVM()

И вывод был верным:

% python2 main.py
2 2
+>+[<[>>+>+<<<-]>>[<<+>>-]>[[-]>>>>>>+<<<<<<<<<[-]>[-]>>>>>>>>[<<<<<<<<+>+>>>>>>>-]
<<<<<<<[>>>>>>>+<<<<<<<-]>>>>>>>[-]<<<<<<]<<<[>>+>+<<<-]>>[<<+>>-]>[[-]>>>>>>++
[<<<<<+>>>>>>>>>>>>+<<<<<<<-]<<<<<[>>>>>+<<<<<-]>>>>>>>>>>>>>[>>]+<<[<<]>[>[>>]
<+<[<<]>-]<<<<<<<[-]++[<<<<<+>>>>>>>>>>>>+<<<<<<<-]<<<<<[>>>>>+<<<<<-]>>>>>>>>>>>>>
[>>]+<<[<<]>[>[>>]<+<[<<]>-]<<<<<<<[-]#JVM has been shutdown

Теперь я решил перевести свое решение в соответствии с вашей проблемой:

import jpype
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=astral.jar")
jpype.JClass("phylonet.coalescent.CommandLine").main([])
jpype.shutdownJVM()

И код работает правильно. Более важным, чем фактическое решение является тот факт, почему ваш код не работает. Вы использовали неверный набор параметров и указали путь к классу другой .

Заменив JClass на JPackage, код все еще работает.

import jpype
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=astral.jar")
jpype.JPackage('phylonet').coalescent.CommandLine.main([])
jpype.shutdownJVM()

Так как способ извлечения классов из classpath правильный, единственно возможная причина - указание неверного набора параметров. После удаления -ea код все еще работает, поэтому допущенная вами ошибка заключается в этом фрагменте кода.

'-Djava.class.path="%s"' % jar

И на самом деле, я использовал это в противоположность моему ответу, и, бэм, код выдает это:

TypeError: Package phylonet.coalescent.CommandLine.main is not Callable

Это означает, что параметр содержал следующее:

-Djava.class.path="astral.jar"

Вместо следования

-Djava.class.path=astral.jar

Кавычки были неуместны и привели к ошибке в результате.

5
Krzysztof Szewczyk 3 Май 2019 в 20:08

Это была классическая проблема с JPype. Если баночка не может быть загружена, JPackage вернет другой JPackage, который не может быть вызван. Общие причины сбоя загрузки включают

  • Загруженная JVM не поддерживает версию jar (убедитесь, что getDefaultJVMPath () не является старой версией)
  • Jar-зависимость отсутствует.
  • JVM не может найти Jar в качестве указанного пути.

Предыдущее решение заключалось в использовании java.lang.Class.forName, который печатал бы диагностику при загрузке банки. Версия 0.7.0, которая в настоящее время доступна в качестве кандидата на выпуск, решает эту проблему.

Также рекомендуется использовать jpype.imports или JClass, а не JPackage при импорте класса. Это намного безопаснее, так как сообщит о более значимой ошибке. Например:

import jpype
import jpype.imports

jpype.startJVM()
jpype.imports.registerDomain('phylonet')  # This is required as phylonet is not a tld

from phylonet.coalescent import CommandLine

Вы можете пометить пакет как соответствующий (классы начинаются сверху, пакеты ниже), чтобы вызвать ошибку.

2
Karl Nelson 14 Июн 2019 в 03:58