Python unit test: no startupCompleted signal

I’m updating my python extension from Slicer 4.6 to the master and already fixed it to only use the DICOM database after slicer.app has sent the startupCompleted signal (Modules/Scripted/DICOM/DICOM.py initializes slicer.dicomDatabase after it gets this signal). But my python unit tests that check the DICOM functionality are all failing because that signal is not being sent/caught and the slicer.dicomDatabase isn’t initialized before my test starts running. My extension module also doesn’t finish set up before the test starts running.

I tried setting up my test to wait for the signal, but it’s not getting it either. I looked through the Slicer application tests and didn’t find a test that accesses slicer.dicomDatabase in a similar way. The DICOMReaders.py is a ScriptedLoadableModule rather than a unitTest.TestCase and does throw up some errors when I run it locally but still reports as passing (the Preview dashboard for the windows nightly package only says “no leaks”).

618: Could not load  "C:/Users/Nicole Aucoin/AppData/Local/Temp/Slicer-tmp/tempDICOMDatabase/dicom/1.3.6.1.4.1.9590.100.1.2.217975813113576534408907137883645586330/1.3.6.1.4.1.9590.100.1.2.366426457713813178933224342280246227461/1.3.6.1.4.1.9590.100.1.2.311244454913801066106129755371102910260"
618: DCMTK says:  No such file or directory
618: Mouse-MR-example-where-GDCM_fails Test caused exception!
618: std::logic_error: Calling methods on uninitialized ctkDICOMItem

The tests that are derived just from unittest.TestCase (like RSNAVisTutorialTest) create their own temporary DICOM database rather than using the default slicer.dicomDatabase.

Has anyone else encountered and fixed this problem yet?

Nicole

Working with it some more, it looks like slicer.dicomDatabase was set up but any signal was sent after I connected to it during the test in either my module or my unit test.

Do you mean that the database is initialized, but too late (because your module is notified about startupCompleted earlier than the database is initialized)?

Maybe instead of processing startupCompleted events in random order, we should add a method to the module interface similar to qSlicerAbstractCoreModule::initialize, which would be called in the same order as initialize (respecting module dependencies), after application startup is completed.

Yes, providing a way to define module dependencies for startupCompleted tasks makes sense.

I’ve added https://issues.slicer.org/view.php?id=4582 issue to track this.

Apologies, I wrote that incorrectly. When I run my test, the database is initialized but neither my module nor my test script get notified via the startup complete signal. The startup complete signal is either not sent due to the way the test is starting Slicer, or it’s sent before my module or my test script connect to listen for the signal.
If I modify my module to check if slicer.dicomDatabase is set right before I need it, on regular start up, it’s set and I’ve received the startup complete signal, but when I run the test, the database is set but I’ve not received the start up completed signal. But if I try to use the database at that point, I’m getting the warnings about an uninitialized ctkDICOMItem.

My module definitely needs to do it’s start up completed tasks after the DICOM module has finished processing on start up complete, but it’s still odd that I’m not getting the start up completed signal at all when I run my test.

Nicole

@Nicole_Aucoin would it be possible for you to write a small example test/module to replicate the issue?

@pieper Here you go:

Notes:
When I run slicer and go to my example module:
The connected slot that I set up on my scripted loadable module in init is triggered (and slicer.dicomDatabase is set), but not the one that I set up in the widget representation setup.

When I run the test:

ctest -C Release -R CheckDB -VV

The slot on my module is triggered, but slicer.dicomDatabase is None at that point. The slots on my widget and on my test that are connected to the start up signal are not triggered. At the start of my test function, slicer.dicomDatabase is still None.

Nicole

As a workaround, you could try adding this call to your test function:

slicer.modules.DICOMInstance.performPostModuleDiscoveryTasks()