spinalcordtoolbox / spinalcordtoolbox

Comprehensive and open-source library of analysis tools for MRI of the spinal cord.
https://spinalcordtoolbox.com
GNU Lesser General Public License v3.0
201 stars 102 forks source link

`dipy` is lazy-loaded incorrectly, causing an `AttributeError` when running `sct_maths -denoise` #4636

Closed hazedine closed 1 month ago

hazedine commented 1 month ago

Description

LazyLoader seems to cause issues in my system, previously working with SCT version 6.1.

Steps to Reproduce

  1. Install SCT <release or git revision and platform, you can use the first lines of output of sct_check_dependencies>

    SCT info:
    - version: 6.4
    - path: /scratch/01/user/workspace/src/projects/sct
    OS: linux (Linux-5.15.0-122-generic-x86_64-with-glibc2.35)
  2. sct_maths -i image.nii.gz -denoise 2 -o denoised_image.nii.gz

Expected behavior: Command executes without error

Actual behavior:

Traceback (most recent call last):
  File "/scratch/01/user/workspace/src/projects/sct/spinalcordtoolbox/scripts/sct_maths.py", line 621, in <module>
    main(sys.argv[1:])
  File "/scratch/01/user/workspace/src/projects/sct/spinalcordtoolbox/scripts/sct_maths.py", line 553, in main
    data = sct_math.denoise_nlmeans(data, patch_radius, block_radius)
  File "/scratch/01/user/workspace/src/projects/sct/spinalcordtoolbox/math.py", line 316, in denoise_nlmeans
    sigma = dipy.denoise.noise_estimate.estimate_sigma(data_in)
  File "/scratch/01/user/workspace/src/projects/sct/contrib/tensorflow/lazy_loader.py", line 82, in __getattr__
    return getattr(module, item)
AttributeError: module 'dipy' has no attribute 'denoise'
joshuacwnewton commented 1 month ago

I can reproduce this error on my local machine:

dot|joshua@monarch:~/data/sct_example_data/t2$ sct_maths -i t2.nii.gz -denoise 2 -o denoised_image.nii.gz

--
Spinal Cord Toolbox (git-jn/4318-sct_deepseg_subcommands-cd84b1ddd5b79dde7887a6dafc7f28b781beb573)

sct_maths -i t2.nii.gz -denoise 2 -o denoised_image.nii.gz
--

Traceback (most recent call last):
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/scripts/sct_maths.py", line 640, in <module>
    main(sys.argv[1:])
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/scripts/sct_maths.py", line 572, in main
    data = sct_math.denoise_nlmeans(data, patch_radius, block_radius)
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/math.py", line 316, in denoise_nlmeans
    sigma = dipy.denoise.noise_estimate.estimate_sigma(data_in)
  File "/home/joshua/repos/spinalcordtoolbox/contrib/tensorflow/lazy_loader.py", line 82, in __getattr__
    return getattr(module, item)
AttributeError: module 'dipy' has no attribute 'denoise'

The LazyLoader solution requires accessing functions from modules, and does not work if you try to access submodules from modules.

So, the following changes are necessary:

# before
dipy = LazyLoader("dipy", globals(), "dipy")
sigma = dipy.denoise.noise_estimate.estimate_sigma(data_in)
denoised = dipy.denoise.nlmeans.nlmeans(data_in, sigma, patch_radius=patch_radius, block_radius=block_radius)

# after
dipy_noise = LazyLoader("dipy_noise", globals(), "dipy.denoise.noise_estimate")
dipy_nlmeans = LazyLoader("dipy_nlmeans", globals(), "dipy.denoise.nlmeans")
sigma = dipy_noise.estimate_sigma(data_in)
denoised = dipy_nlmeans.nlmeans(data_in, sigma, patch_radius=patch_radius, block_radius=block_radius)

After making these changes, the function runs without error. My apologies for the inconvenience, I will fix this ASAP and backport the fix to v6.4.