QuPath Script Debugging in Eclipse

Scripting in QuPath is very essential.
An opportunity to debug QuPath scripts at runtime would be a big advantage.

Here I would like to share and discuss the following approach to debug QuPath scripts in an Eclipse environment.
It delivers the great advantage to use breakpoints inside QuPath scripts, to execute the script code line-wise (Step over, Step into) and to access the content of objects during script execution.

The approach requires:

  • QuPath project in Eclipse
  • Modification of qupath.lib.gui.scripting.DefaultScriptEditor.java
  • Eclipse Groovy Development Tools installed in Eclipse
  • QuPath script in Groovy project
    (see Setup Details below)

Note:
This approach is currently a first and minimum version. Probably not all options are fully exhausted yet and not all problems are fixed.

The core of the approach is to evaluate the script code directly from the script file with a GroovyShell instead of utilizing the ScriptEngine (as QuPath currently does).
This is necessary to link the script to the debugger.

Therefore I have implemented an additional function in the QuPath ScriptEditor in the menu Run:

  • Run Debug (experimental)

The modified version of the DefaultScriptEditor.java is attached here :DefaultScriptEditor.zip (18.5 KB) My changes are marked in the code.

Setup Details

Script file in Eclipse Groovy Project

  • Create a Groovy project for the QuPath scripts (my name: qp_scripts)
  • Configure the script project settings:
    – Groovy Project>Properties>Java Build Path>Projects> Add all qupath projects to the build path (this is used for code auto completion)
    – Groovy Project>Properties>Java Build Path>Libraries> If necessary, add other jars to the build path, e.g. gson-2.8.6.jar (this is used for code auto completion)
    – Groovy Project>Properties>Groovy Compiler>Enable script folder support = true
    **/*.groovy inserted AND selected in pattern list (see image below)

QuPath Project in Eclipse

  • Use the modified DefaultScriptEditor.java in the QuPath project. (groovy-3.03.jar, groovy-jsr223-3.03.jar and groovy-xml-3.03.jar have to be added to the class path of the qupath-gui-fx project)
  • Configure the QuPath project settings:
    – Project>Properties>Run/Debug Settings>QuPath (Launch configuration)>Edit>Source>Add>Workspace Folder> qp_scripts\bin (Class folder of the groovy script project)
    – Project>Properties>Project References> Select the Groovy Script project (to build the script project when starting QuPath from Eclipse)


Groovy Project>Properties>Groovy Compiler>Enable script folder support

Usage

  • Create a new groovy class file in the source folder of your script project (Right click to src folder>New>Other>Groovy>Groovy Type). The new groovy file MUST be located in the default package!
  • Type a simple test script, e.g.
import qupath.lib.scripting.QP
import qupath.lib.projects.Project
import qupath.lib.projects.ProjectImageEntry

print '*****      INFO         ********\n'
print '***   QuPath Script Debugging Test   ***\n'
print 'QuPath script created AND build(!) in Eclipse Groovy project\n'
print 'Debug breakpoints defined in the script\n'
print 'Start QuPath from Eclipse in Debug mode\n'
print 'Open Project in QuPath\n'
print 'Open ScriptEditor and open script file\n'
print 'Run script with function *Run Debug*\n'
print 'Code execution is stopped at script breakpoint\n'
print 'Object content is accessible in the script code\n'
print '*****      INFO END      ********\n'


def Project project = QP.getProject()

if (project != null) {
	for (entry1 in project.getImageList()) {
		def name1 = entry1.getImageName()
		print name1 +'\n'
	}
}


  • Save and build the script file (During the build process the script file should have been copied as uncompiled groovy file (AsIs) to the script project class folder, in my case: qp_scripts\bin !)
  • Set some debug breakpoints inside the script code
  • Start QuPath from Eclipse in Debug mode
  • Open the ScriptEditor and load the script file from qp_scripts\src
  • Run script in QuPath in Debug mode with new function Run>Run Debug (experimental)

The code execution should be halted at the breakpoint inside the script and you should be able to use the Eclipse debug functions (see first image in this post).

I hope I have not forgotten important setup steps.
Pls reply with questions, problems or feedback.
:slightly_smiling_face:

Limitations
There is always a price.

- In QuPath important default libs are automatically added to the scripts when they are started with ‘Run’. This is NOT done in the ‘Run Debug’. The script file is evaluated as it is. The user is responsible for the imports.

- In ‘Run Debug’ the script output is not send to the QuPath ScriptEditor but to the Eclipse Console and it is send to the Eclipse Console without additional format steps such as adding ‘\n’. The user should add ‘\n’ wherever it is helpful.

- Complex processes are slower in Debug mode.

4 Likes

For those who are developing QuPath scripts inside IntelliJ …

I have packed a DebugScriptEditor (a modified version of the DefaultScriptEditor) into a QuPath extension.
It can be used to debug QuPath scripts inside IntelliJ without having a full QuPath development project.

If you have a scripting setup according to this instructions:

you just need to drag&drop the extension jar file ( qupath-extension-debugscripteditor-0.2.3.jar (78.6 KB), src inside) onto your running QuPath app to install the DebugScriptEditor.

The DebugScriptEditor is available as a new entry in the menu Automate.

In IntelliJ you have to create a Run/Debug configuration like the this one:

Start QuPath in Debug mode from IntelliJ menu Run>Debug…
and select ‘Debug’ for your Run/Debug configuration:

RunDebug

If you now execute scripts with the DebugScriptEditor you can force IntelliJ to stop execution at breakpoints inside your scripts and you can access the object content.

If you like give it a try.

3 Likes

Really cool, thanks!

1 Like

Hi Pete @petebankhead,

for your information:

The following error message is displayed when using QuPath>Help>Installed extensions
while my extension jar file is placed in the QuPath extension folder:

ERROR: QuPath exception
    at qupath.lib.gui.commands.ShowInstalledExtensionsCommand$QuPathExtensionEntry.getVersion(ShowInstalledExtensionsCommand.java:234)
    at qupath.lib.gui.commands.ShowInstalledExtensionsCommand.addEntry(ShowInstalledExtensionsCommand.java:150)
    at qupath.lib.gui.commands.ShowInstalledExtensionsCommand.showInstalledExtensions(ShowInstalledExtensionsCommand.java:83)
    at qupath.lib.gui.commands.Commands.showInstalledExtensions(Commands.java:457)
...

The extension jar file contains a MANIFEST.MF file and the line Implementation-Version: 0.2.3.

It seems as if in the function getVersion() in qupath.lib.gui.commands.ShowInstalledExtensionsCommand$QuPathExtensionEntry
the manifest is not found in the jar file.

Thanks @phaub, it’s very mysterious that JarInputStream isn’t finding the manifest file.

But certainly QuPath should recover. I’ve created an issue at Error displayed when manifest can't be found in ShowInstalledExtensionsCommand · Issue #664 · qupath/qupath · GitHub and will merge the fix before the next release. That will at least prevent the error causing problems for the user.

1 Like

Thank you @petebankhead for looking at the ‘manifest issue’ even if it surely has no high priority.

As you sais, it’s mysterious.
Therefore I search the web and found a hint in Bug ID: JDK-5046178 JarInputStream doesn't return Manifest object .

Probably I mixed up the organization of the jar file by adding the source code folder to the jar.

The original jar file (created by gradle build) works and delivers the extected output without throwing an exception in QuPath.

Here is the ‘original’ jar file:
qupath-extension-debugscripteditor-0.2.3.jar (52.9 KB)

1 Like

There is one more hint for those who want to debug QuPath grooyv scripts.

QuPath scripts can (partly) be debugged even without using the DebugScriptEditor extension mentioned above.

The trick is to move the relevant code into a class definition inside the groovy script.

Breakpoints inside the class can be reached when QuPath is started from IntelliJ in debug mode.

The debugging behavior is a bit limited but in some cases this option might be of help especially because QuPath can be used without any modification.

Here is an example script:

import qupath.lib.scripting.QP
import qupath.lib.projects.Project

print '***   QuPath Script Debugging Test   ***\n'

DebugTest.test()

// Class definition
class DebugTest {

    public static void test(){
        def Project project = QP.getProject()

        if (project != null) {
            for (entry in project.getImageList()) {
                String name = entry.getImageName()
                print name + '\n'
            }
        }
    }
}
1 Like