scijava/scripting-jython

Jython does not call the expected ScriptService.run method

haesleinhuepf opened this issue · 5 comments

Hey guys,

as the discussion on the ImageJ forum did not lead to a solution, I'm opening an issue here now. I'm trying to run one script file from another by calling scriptService.run(File ("/Users/rhaase/temp/test.py"), True, parameterMap). However, the parameters in the map are ignored as stated by log messages like
[ERROR] Ignoring extraneous argument: {'var': 'world'}
and
[ERROR] Ignoring extraneous argument: {var=world}
depending on the type of the map.

http://forum.imagej.net/t/jython-scriptservice-issue/3462/3

There's no hurry, but it would be nice if this would work.

Thanks in advance!

Cheers,
Robert

If you grep the SJC codebase, you will find the relevant error message here. And you will see that it is only issued when converting a list of values (Object[]) into a new map (Map<String, Object>), which only happens when one of the run signatures with Object... inputs is called. Which means that your code above is not matching a run signature with Map<String, Object> inputMap, but rather Object... inputs. This is a limitation of the Jython script engine's method overloading capabilities. In my experience (especially from Ops), Jython tends to get confused when varargs are involved.

As a workaround, you can pass the arguments in list form instead of map form; e.g.:

#@ScriptService scriptService
from java.io import File
scriptService.run(File ("/Users/rhaase/temp/test.py"), True, "var", "world")

Or maybe:

#@ScriptService scriptService
from java.io import File
scriptService.run(File ("/Users/rhaase/temp/test.py"), True, ["var", "world"])

I also wonder about what @hadim wrote:

Try to replace your dict parameters by a Java HashMap as in your first script.

If your types match, then Jython should do the right thing... from the "Overloaded Java Method Signatures" section of the Jython docs:

If you need to call a Java method with a particular signature and this is not happening in the easy way, you can use the following workaround:

Assume that foo has two methods, "void foo(int x); void foo(byte x);". To call the second method you could write the following:

from java.lang import Byte
foo(Byte(10))

I'm not convinced that any better solution to this problem is possible.

One solution could be to move or copy the run methods to something like runWithList and runWithMap, to make languages like Jython behave better here, by removing some of the ambiguity. Feel free to try this, and report back whether it makes things easier.

Ha!

#@ScriptService scriptService
from java.io import File
scriptService.run(File ("/Users/rhaase/temp/test.py"), True, ["var", "world"])

with and without [ ] works and it's actually a nice workaround. Thanks a lot for that so far! I could just encapsulate that and transform my maps to lists.

However,

#@ScriptService scriptService

from java.util import HashMap
from java.io import File

parameterMap = HashMap()
parameterMap.put("var", "world")

scriptService.run(File ("/Users/rhaase/temp/test.py"), True, parameterMap)

... is not working with the error message as discussed above. By adding

print(type(parameterMap))

I get this output:

<type 'java.util.HashMap'>

:-/

I hope that helps

I hope that helps

Not much. But thanks for verifying that Jython still chooses the wrong method signature.

By the way: are you running with Jython 2.7.0? Or Jython 2.5.3? If the latter, can you please try upgrading to the former? It should be as simple as replacing the jython-shaded-2.5.3.jar with the 2.7.0 version (download from here). It would be excellent if 2.7.0 magically fixes this. Otherwise, we'll have to debate whether to:

  1. Use different method signatures in SciJava Common to avoid the issue; or
  2. Investigate in the Jython source, make a patch, and submit upstream.

While (2) would be nice if successful, it could potentially be a lengthy community process that ends in failure.

I just tried jython 2.7. Unfortunately, it does not solve the issue. But I see a relatively simple alternative: It may not the best place to fix the issue. But what about fixing it, where it becomes apparent?

https://github.com/haesleinhuepf/scijava-common/blob/master/src/main/java/org/scijava/module/DefaultModuleService.java#L415-L426

This solves the issue technically. But I'm not 100%ly sure about side effects...

This solves the issue technically. But I'm not 100%ly sure about side effects...

Nice idea. I think it will work. I had considered something like that, but was worried it would make Map parameters ambiguous... but actually it doesn't because you always need to pass key then value as two arguments. So if there is only a single argument, something is already "wrong" and we can make a best effort as you propose to handle the situation.