commontk / CTK

A set of common support code for medical imaging, surgical navigation, and related purposes.
https://commontk.org
Apache License 2.0
831 stars 483 forks source link

Update QtTesting translator to record python #1081

Open jcfr opened 1 year ago

jcfr commented 1 year ago

Once we are done with Qt4 removal, we should evaluate if the overall of maintaining QtTesting player/translator for both CTK & Slicer is worth it.

We are looking into refreshing/improving QtTesting for recording tutorials that can be replayed in different languages (because we cannot use English language screenshots in non-English tutorials). We would like to generate executable Python code instead of XML. Maybe we'll use the recorder (just fix and extend it as needed) and convert the XML to Python; or maybe we'll change it more significantly to create Python code directly.

Originally posted by @lassoan in https://github.com/commontk/CTK/issues/1080#issuecomment-1504537982

jcfr commented 1 year ago

QtTesting and python

All of that said, we could look into generating python code similar to what is done in Paraview (see here ). The code would be similar to the one posted below:

import QtTesting
import QtTestingImage
object1 = 'MainWindow/menubar/menuFile'
QtTesting.playCommand(object1, 'activate', 'actionFileLoadServerState')
object2 = 'MainWindow/ServerStartupBrowser/connect'
QtTesting.playCommand(object2, 'activate', )
object3 = 'MainWindow/FileLoadServerStateDialog'
QtTesting.playCommand(object3, 'filesSelected', '$PARAVIEW_DATA_ROOT/Data/LoadStateMultiView.pvsm')
snapshotWidget = 'MainWindow/1pqRenderWindowManager0/SplitterFrame/MultiViewSplitter/0/Viewport'
QtTestingImage.compareImage(snapshotWidget, 'LoadStateMultiView.png', 200, 200);

Originally posted by @jcfr in https://discourse.slicer.org/t/macro-xml-to-python/15803/2

jcfr commented 1 year ago

Recording GUI events (button clicks, etc.) has very limited use (only for testing, and even there it is quite fragile). Meaningful workflow automation Python scripts should operate at lower level, by changing properties of MRML nodes and calling module logic functions.

I’ve recently implemented a simple Python script that observes all MRML node changes and generate a list of node property modifications (by comparing MRML node PrintSelf results before and after the node modification). This can be used to generate a runnable, user-editable Python script. This is similar to what Paraview can do. However, this turned out not to be very useful, because it is too low level (for a single user action you get a bunch of node property modification events, but you don’t know why the node ended up being modified like that).

What we would really need is an intermediate level, where a user action is translated to a few high-level method calls. I’m not sure what is the easiest way to achieve this. Maybe we could add a specially formatted log message whenever a logic method is called (and macro recording is enabled), and these could be easily converted to runnable Python code.

Originally posted by @lassoan in https://discourse.slicer.org/t/macro-xml-to-python/15803/3

jcfr commented 1 year ago

implemented a simple Python script that observes all MRML node changes and generate a list of node property modifications

See https://github.com/PerkLab/SlicerSandbox/blob/master/SceneRecorder/SceneRecorder.py

lassoan commented 1 year ago

Recording&replaying GUI events is bad for batch processing (fragile and may require too many low-level steps) but for tutorials it is actually an appropriate level. Ideally, the user could choose the API level.