Skip to content

Conversation

@SomeoneInParticular
Copy link
Collaborator

@SomeoneInParticular SomeoneInParticular commented Jun 9, 2025

As the title suggests, this refactor should fix the need to install anything externally if its provided by 3D Slicer itself. This PR also resolves some poor PEP8 coding practices (namely relying on Python import order to ensure things are imported before we call them) to avoid similar bugs cropping up again in the future.

Next step is digging into how to expose everything to the IDE for development purposes; this will be in a follow-up PR

SomeoneInParticular and others added 20 commits June 6, 2025 16:17
…d first to run (though its dependencies still do...)
@SomeoneInParticular SomeoneInParticular changed the title Fix QT import dependancy bug Lock in QT import dependancy bug + PEP8 Import Compliance Jun 9, 2025
@SomeoneInParticular SomeoneInParticular marked this pull request as draft June 13, 2025 06:32
@AcastaPaloma AcastaPaloma marked this pull request as ready for review June 13, 2025 15:40
@SomeoneInParticular SomeoneInParticular marked this pull request as draft June 13, 2025 19:46
@AcastaPaloma
Copy link
Collaborator

Haven't gotten any issues yet while testing! Imports all make sense.

@maxradx
Copy link
Member

maxradx commented Jun 16, 2025

Hey @SomeoneInParticular ! When clicking on Load segmentation button and trying to load a previous version, there is an import error (which was not previously present). Can you fix it?

if "nii" in ConfigPath.INPUT_FILE_EXTENSION:

image

…re respect of 08 columns (there are still remaining paragraph of code to consider, however). Please address the comments so this branch can be ready for merge. A bug has been disclosed in the comments. Thanks
Copy link
Member

@maxradx maxradx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Interesting to see how much faster SlicerCART is loading!
Left few comments, including some questions.
There is a bug that has been introduced (see comments). Please fix it so it can be ready for PR. Thanks!

edit_button = qt.QPushButton('Edit')
edit_button.clicked.connect(
lambda state, label=label: self.push_edit_button(label))
lambda _, l=label: self.push_edit_button(l))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely a detail, but why did the variable names changed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ is shorthand for "variable we are not going to use"; this just makes is trivial for Python programmers to "at a glance" understand that they can safely ignore it for debugging purposes.

Likewise, its common for lambda functions to use single-character variables to keep it short. This very much a preference, though; if we prefer to keep "full" variable names, I have no qualms reverting this.

import slicer

from importlib import import_module
from importlib.util import find_spec
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why find_spec instead of import_module?

Copy link
Collaborator Author

@SomeoneInParticular SomeoneInParticular Jun 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find_spec won't import the module into memory, and by extension won't run any initialization code required to import said module. This is part of why SlicerCART boots so much faster now.

Instead, SlicerCART will now only import the package when is first used (so if pandas never gets used, it will never be imported, saving the time it would have taken to do so!)

Args:
path: Description of path.
"""
from bids_validator import BIDSValidator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basic question, but just to make sure I understand it correctly: why this one is only imported here and other imports are done at the beginning? If this module is not installed then Slicer should not fail since BIDSValidator has been pip installed through install_python_packages.py check and install package function?

Copy link
Collaborator Author

@SomeoneInParticular SomeoneInParticular Jun 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question!

So, this is a "half-way" implementation of how Slicer expects us to handle external dependencies (that is, packages that neither Python nor Slicer provide for us). Their justification for this is detailed here.

The reason this is "half-way" is to avoid having that try-catch check copied in literally every function that calls an external dependency. Instead we instead have it so that it prompts the user to install any missing dependencies during SlicerCART initialization, managed by install_python_packages.py.

This also technically breaks Slicer best practices (specifically this one), but the alternative solutions are likely to introduce even more developer headache:

  1. Copy-pasting the try-catch install check will bloat the repository, as well as make future development far more tedious.
  2. Wrapping the try-catch in a boilerplate function, which we then import and call, would make IDE development even more painful.
  3. We could also monkey-patch Python's import statement to mediate this for our use; this would preserve IDE compatibility, and save a large amount of boilerplate code. However, its monkey-patching, the joke answer to "how do we solve a problem?"; such a solution would be unstable at best, and risk breaking other Slicer modules if they rely on the default behavior of import.

@SomeoneInParticular
Copy link
Collaborator Author

Hey @SomeoneInParticular ! When clicking on Load segmentation button and trying to load a previous version, there is an import error (which was not previously present). Can you fix it?

Good catch! Yes, I mistakenly imported the file rather than the class within it; should be fixed with 3cb36e0

@maxradx
Copy link
Member

maxradx commented Jun 17, 2025

Ok So @SomeoneInParticular is the PR ready to be reviewed again so I can merge it if ok?

@SomeoneInParticular
Copy link
Collaborator Author

SomeoneInParticular commented Jun 17, 2025

Almost @maxradx; just need to run everything through a linter to confirm the "80 characters" test, then should be good to go. WIll do so after my meeting at 2pm.

@maxradx
Copy link
Member

maxradx commented Jun 17, 2025

@SomeoneInParticular ok great! please feel free to advise me when ready!

SomeoneInParticular added 2 commits June 17, 2025 17:12
@SomeoneInParticular
Copy link
Collaborator Author

@maxradx Should be ready now!

@maxradx
Copy link
Member

maxradx commented Jun 21, 2025

@SomeoneInParticular I retried again the load segmentation and using your branch I get this:
image
(it is a different error than before) Note that the bug is not reproduced using the current main. (when I click on LoadSegmentation) Hint: maybe look in the LoadSegmentationWindow.py file? Thanks!

@SomeoneInParticular
Copy link
Collaborator Author

@maxradx what version of Slicer are you running? I just tested it myself with Slicer 5.8.1, and didn't see the same error.

@SomeoneInParticular
Copy link
Collaborator Author

SomeoneInParticular commented Jun 21, 2025

Update: so, turns out the VTK implementation provided by Slicer simply doesn't provide access to vtkSegment through Python bindings. My suspicion is that you managed to get access to it through installing QT creator previously; the mass install on the main branch can access a global qt install I believe, while the PEP8 compliant install uses only the qt bindings provided by Slicer...

I'm looking into a workaround now, but due to the bug documented in #247, its incredibly difficult to test right now. Will post an update as soon as I can.

@maxradx
Copy link
Member

maxradx commented Jun 21, 2025

@SomeoneInParticular version 5.8.1
To reproduce:

  1. Open Slicer - New Configuration - Next - Apply
  2. Select Volume folder
  3. Select Output folder
  4. Enter annotator degree, name etc.
  5. Do a segmentation on MRI (ensure MRI is selected when pushing apply in the configuration window in 1)
  6. Save it, go on next case. Then, go back to the current case, do a segmentation (to have more than one version)
  7. Click on load Segmentation
  8. Select version 1
  9. Click on load segmentation
  10. See error:
image

It currently works in the main branch, so before merging, it should work.
Yes i think in Slicer v5.8.1 they handle segmentation differently in vtk.. but this works in the main so clear it is related to an import issue? maybe missing some mrmrlnode or vtk segment import?

just tried again the steps mentioned above, and it reproduces the error!

@SomeoneInParticular
Copy link
Collaborator Author

SomeoneInParticular commented Jun 22, 2025

So, as it turns out, this was actually an easy fix (though tricky to figure out how to do it). As the loading operation doesn't need to "keep" the old segmentation, we can just modify the prior vtkSegment instance without needing to know its "true" class. @maxradx the bug you mentioned should be fixed in commit 695e0cb

@SomeoneInParticular
Copy link
Collaborator Author

SomeoneInParticular commented Jun 25, 2025

@maxradx I replaced your @enter_function decorate in commit 6e8a415; now that decorator is implicit on all functions within SlicerCART, not just those we remember to decorate. Doing this has also allowed us to avoid a potential cyclical loop if we want to debug configuration loading.

@AcastaPaloma give it a spin as well; I think it will help with debugging quite a bit.

UPDATE: There was exactly 1 errant leftover use of the function that could crash the program: this has been fixed in 6dcb390

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants