Using command-line parameters with a groovy script in QuPath

Is it possible to pass command-line parameters to a QuPath groovy script? Something like:

QuPath-0.2.3 script -i image.tif myscript.groovy param1 param2 param3 --param4=small

Thanks!

1 Like

'Fraid not. If really needed it you could write them to a text file and then read that from the script.

3 Likes

Thanks @petebankhead!

1 Like

Hey @petebankhead,

I’d also be interested in this, so I had a look at your code and had a go at hacking something together.

My thinking is that we pass the arguments as a string with the -a / --args option, which will be split into appropriate chunks and pass them on to the groovy script as a global variable named “args” containing an array of strings, one for each argument. This is already kind of how groovy is expected to behave, and I was lucky that in the QuPath Groovy, the global variable args (or this.args) isn’t defined.

So first, I added the “-a / --args” option to src/main/qupath/QuPath.java:

@Option(names = {"-a", "--args"}, description = "Arguments passed to the Groovy script as a string", paramLabel = "arguments")
private String scriptArgument;

I then split the scriptArgument string into chunks using this stack overflow answer – The appropriate method was just pasted into the ScriptCommand class.

Then I added an attribute named “args” to the context of the engine running the script:

        // Define "args" as a global Groovy variable
        String[] argsArray = translateCommandline(argsString);
        context.setAttribute("args", argsArray, ScriptContext.ENGINE_SCOPE);

That’s all! When you need to run a script with arguments, do it this way:

>".\build\dist\QuPath-0.2.3\QuPath-0.2.3 (console).exe" script myscript.groovy -a "tata \"toto titi\" tutu"
23:54:31.178 [main] [INFO ] qupath.ScriptCommand - Setting tile cache size to 8180.00 MB (25.0% max memory)
23:54:31.372 [main] [INFO ] qupath.lib.scripting.QP - Initializing type adapters
Showing args:
[tata, toto titi, tutu]

myscript.groovy is just this:

println "Showing args:"
println args

As you can see, escaping strings seems to work just fine (\“toto titi\” in my example above). And I personally don’t need more to pass a path to a script.

I also modified executeScript() in DefaultScriptEditor.java for consistency:

	private void executeScript(final ScriptTab tab, final String script, final Project<BufferedImage> project, final ImageData<BufferedImage> imageData) {
		ScriptEditorControl console = tab.getConsoleComponent();
		
		ScriptContext context = new SimpleScriptContext();
		var writer = new ScriptConsoleWriter(console, false);
		context.setWriter(writer);
        String[] argsArray = new String[0];
        context.setAttribute("args", argsArray, ScriptContext.ENGINE_SCOPE);

… and args is just an empty array in the Script Editor:
image

My two modified files are attached, let me know if there’s any mileage in this :slight_smile:

Cheers,
Egor

QuPath.java.txt (16.8 KB) DefaultScriptEditor.java.txt (75.2 KB)

4 Likes

Thanks Egor, that’s fantastic! It works perfectly!

1 Like

I just wanted to, um, third this I guess, as it would be very useful to pass strings from the CLI :slight_smile: In case it can be worked into 0.3.0 somehow.

Hello,

After a bit of fumbling, I did manage to package my changes as a pull request. And we also have @melvingelbard implementation, which is short and sweet.

My pull request isolates the “command parameters for QuPath” from the “command parameters for groovy”, but to do this, I had to paste the translateCommandline() method into the ScriptCommand class. That’s a lot of code I dumped into QuPath just for this one added benefit. Maybe there is a way to do this with the existing libraries already in the QuPath code, but unfortunately, I haven’t found it yet. Is this isolation really necessary? My gut feeling says yes, but if we’re at an impasse, then I’ll take Melvin’s implementation over not having an implementation at all :slight_smile:

Cheers,
Egor