Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Recompress files where dcm2niix failed #803

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions heudiconv/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,19 @@
item_dicoms, prefix, with_prov, bids_options, tmpdir, dcmconfig
)

# try to handle compression failures from dcm2niix
if outtype == 'nii.gz':
converted_files = res.outputs.converted_files
if not isinstance(converted_files, list):
converted_files = [converted_files]
uncompressed = [x for x in converted_files if x.endswith('.nii')]
if len(uncompressed) > 0:
lgr.warning("Conversion returned uncompressed nifti (>4GB?) - "

Check warning on line 640 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L640

Added line #L640 was not covered by tests
"trying to salvage by recompressing ourselves. "
"This might take a while ")
if not recompress_failed(uncompressed):
raise RuntimeError("Error compressing nifti")

Check warning on line 644 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L643-L644

Added lines #L643 - L644 were not covered by tests
Copy link
Member

Choose a reason for hiding this comment

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

why to delay this crash here? this way you are hiding from user information on individual file and corresponding error -- why not just to just call recompress here and let error (if any happens) to bubble up?

I would also just loop here and have recompress to operate on a single file.

FWIW, I think it would be worth adding a test scenario to test this code path. I would have just mock patched the nipype_convert so that I would decompress some output file(s) and thus triggering this code path.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I'll look into it!


bids_outfiles = save_converted_files(
res,
item_dicoms,
Expand Down Expand Up @@ -1099,3 +1112,38 @@

bvals_unique = set(float(b) for b in bvals)
return bvals_unique == {0.0} or bvals_unique == {5.0}


def recompress_failed(niftis: list) -> bool:
"""Tries to recompress nifti files with built-in gzip module

Parameters
----------
niftis : list
list of nifti file paths

Returns
-------
True if all nifits were successfully compressed. False otherwise.
"""

import zlib
import gzip
from nibabel import load as nb_load
from nibabel.filebasedimages import ImageFileError

Check warning on line 1133 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L1130-L1133

Added lines #L1130 - L1133 were not covered by tests

for nifti in niftis:
try:
img = nb_load(nifti)

Check warning on line 1137 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L1135-L1137

Added lines #L1135 - L1137 were not covered by tests
# read everything to catch truncated/corrupted files
_ = img.get_fdata() # type:ignore[attr-defined]
with open(nifti, 'rb') as f_in:
with gzip.open(nifti + '.gz', 'wb', compresslevel=6) as f_out:
shutil.copyfileobj(f_in, f_out)

Check warning on line 1142 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L1139-L1142

Added lines #L1139 - L1142 were not covered by tests
# nipype results still carry uncompressed file names and they will
# be renamed to '.nii.gz' later
os.rename(nifti + '.gz', nifti)
except (OSError, ImageFileError, zlib.error):
return False

Check warning on line 1147 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L1145-L1147

Added lines #L1145 - L1147 were not covered by tests

return True

Check warning on line 1149 in heudiconv/convert.py

View check run for this annotation

Codecov / codecov/patch

heudiconv/convert.py#L1149

Added line #L1149 was not covered by tests