Organizing imports in python extensions that rely on other slicer extensions

I have a file in my scripted python extension that interacts with another extension (SlicerIGT Watchdog specifically). I want to import vtkMRMLWatchdogNode in my python code to use it for type hints. When I add it to the import statements like

from slicer import vtkMRMLLinearTransformNode, vtkMRMLWatchdogNode

the application launches and my module is loaded before SlicerIGT, thus before vtkMRMLWatchdogNode is available in the slicer namespace. This leads to an import error and a failure to load my python extension.

Is there a way to specify a dependency for a slicer python extension or any other way to get around the extension loading order which if I understand correctly is random?

MRML nodes are imported into the Slicer namespace automatically, you should not attempt to import them manually, as it is either unnecessary or premature.

You must not import any Python modules (other than built-in ones) in the body of the .py file, because order of module discovery is random. The application determines dependencies during module discovery and module loading is ordered based on dependencies that each module declares about itself.

Thr simplest is to observe the startup completed signal and perform actions that you want to do at startup but rely on existence of other modules in the callback function.

Thanks. You are right, that import is unnecessary to have working code.

In my case the sole purpose of having that import is to enable certain functionality of my text editor (VSCode) that makes the development process faster and more pleasant in general. When I link the VSCode workspace to the PythonSlicer executable using the python.defaultInterpreterPath setting I get python related tooling (language server and linters) running from slicer.

The workaround is not worth the time in this case.

On the other note, can you please explain a bit what you mean by “must not import any Python modules (other than built-in ones) in the body of the .py file”. Are you referring to slicer python modules (like importing a logic class of another slicer extension) or generic python modules (numpy, torch, etc.)?

You should not import numpy, torch, etc. either in the .py file body.

Pip-installed modules cannot be added there because the first time the module is discovered, the module is not available yet, so you cannot import it. If you added pip_install in the .py file body then it would cause long delays at application startup (in case of torch, it could be several minutes - so users would assume the application is crashed).

Importing Python modules that are bundled with Slicer, such as numpy, used to be acceptable, but in Python-3.9 and Windows11 we ran into issues (Slicer hung during startup due to incorrect stdin/stdout usage in OpenBLAS), so now we don’t recommend importing anything.

Time to time I test if I can get anything useful from this, but so far auto-completion, method documentation, syntax highlighting, linting, etc. have all mostly failed for Slicer scripted modules. Could you describe what IDE features work you?

1 Like

I can’t get docstrings for bundled slicer python modules if i’m not using a jupyter kernel.

I run some linting on save. If I link to PythonSlicer the linters don’t yell at me with false-positives like qt or slicer namespaces, thus checking only the code available in the workspace.

I have tried mypy, pylint, flake8 and pycodestyle and all of them worked to the extent of testing my code and not raising false-flags about the things that are expected from the slicer runtime.

This is very important information. Thanks a lot