Skip to content

Commit beef8eb

Browse files
authored
apply changes requested from PR #353 (#357)
Allows for additional option to be set for dcm2niix Small fix for reconstruction field being cast as float. * apply changes requested from PR #353 * bump version
1 parent dbd3b55 commit beef8eb

File tree

4 files changed

+213
-10
lines changed

4 files changed

+213
-10
lines changed

.blackignore

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Virtual environments
2+
.venv/
3+
venv/
4+
env/
5+
ENV/
6+
env.bak/
7+
venv.bak/
8+
9+
# Python cache
10+
__pycache__/
11+
*.py[cod]
12+
*$py.class
13+
*.so
14+
.Python
15+
.pytest_cache/
16+
17+
# Distribution / packaging
18+
.Python
19+
build/
20+
develop-eggs/
21+
dist/
22+
downloads/
23+
eggs/
24+
.eggs/
25+
lib/
26+
lib64/
27+
parts/
28+
sdist/
29+
var/
30+
wheels/
31+
*.egg-info/
32+
.installed.cfg
33+
*.egg
34+
35+
# PyInstaller
36+
*.manifest
37+
*.spec
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.coverage
43+
.coverage.*
44+
.cache
45+
nosetests.xml
46+
coverage.xml
47+
*.cover
48+
.hypothesis/
49+
.pytest_cache/
50+
51+
# Jupyter Notebook
52+
.ipynb_checkpoints
53+
54+
# pyenv
55+
.python-version
56+
57+
# celery beat schedule file
58+
celerybeat-schedule
59+
60+
# SageMath parsed files
61+
*.sage.py
62+
63+
# Environments
64+
.env
65+
.venv
66+
env/
67+
venv/
68+
ENV/
69+
env.bak/
70+
venv.bak/
71+
72+
# Spyder project settings
73+
.spyderproject
74+
.spyproject
75+
76+
# Rope project settings
77+
.ropeproject
78+
79+
# mkdocs documentation
80+
/site
81+
82+
# mypy
83+
.mypy_cache/
84+
.dmypy.json
85+
dmypy.json
86+
87+
# IDE
88+
.vscode/
89+
.idea/
90+
*.swp
91+
*.swo
92+
*~
93+
94+
# OS
95+
.DS_Store
96+
.DS_Store?
97+
._*
98+
.Spotlight-V100
99+
.Trashes
100+
ehthumbs.db
101+
Thumbs.db
102+
103+
# Project specific
104+
__MACOSX/
105+
*.zip
106+
*.mat
107+
*.v
108+
*.v.gz
109+
*.avi
110+
*.jpg
111+
*.bytes

Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,4 @@ pythongithubworkflow: installdependencies collectphantoms decompressphantoms tes
8787
@echo finished running python tests
8888

8989
black:
90-
@for file in `find pypet2bids/ -name "*.py"`; do \
91-
black $$file; \
92-
done
90+
@black pypet2bids/

pypet2bids/pypet2bids/dcm2niix4pet.py

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ def __init__(
172172
metadata_path=None,
173173
metadata_translation_script=None,
174174
additional_arguments={},
175+
dcm2niix_options="",
175176
file_format="%p_%i_%t_%s",
176177
silent=False,
177178
tempdir_location=None,
@@ -364,6 +365,42 @@ def __init__(
364365
load_spreadsheet_data["blood_json"]
365366
)
366367

368+
# we default to these options, a user may supply their own combination, this will allow full customization of all
369+
# but the file arguments for dcm2niix
370+
if dcm2niix_options:
371+
# Filter out -f flag and its value from custom options since file format is handled separately
372+
options_list = dcm2niix_options.split()
373+
filtered_options = []
374+
i = 0
375+
while i < len(options_list):
376+
if options_list[i] == "-f" and i + 1 < len(options_list):
377+
# Skip -f and its value
378+
i += 2
379+
else:
380+
filtered_options.append(options_list[i])
381+
i += 1
382+
self.dcm2niix_options = " ".join(filtered_options)
383+
else:
384+
# Check for dcm2niix options in config file and environment variable
385+
config_options = helper_functions.check_pet2bids_config(
386+
"PET2BIDS_DCM2NIIX_OPTIONS"
387+
)
388+
env_options = environ.get("PET2BIDS_DCM2NIIX_OPTIONS")
389+
390+
# Priority: command line > environment variable > config file > default
391+
if env_options:
392+
self.dcm2niix_options = env_options
393+
logger.info(
394+
f"Using dcm2niix options from environment variable: {env_options}"
395+
)
396+
elif config_options:
397+
self.dcm2niix_options = config_options
398+
logger.info(
399+
f"Using dcm2niix options from config file: {config_options}"
400+
)
401+
else:
402+
self.dcm2niix_options = "-b y -w 1 -z y"
403+
logger.debug("Using default dcm2niix options: -b y -w 1 -z y")
367404
self.file_format = file_format
368405
# we may want to include additional information to the sidecar, tsv, or json files generated after conversion
369406
# this variable stores the mapping between output files and a single dicom header used to generate those files
@@ -480,7 +517,7 @@ def run_dcm2niix(self):
480517
self.tempdir_location = tempdir_pathlike
481518
# people use screwy paths, we do this before running dcm2niix to account for that
482519
image_folder = helper_functions.sanitize_bad_path(self.image_folder)
483-
cmd = f"{self.dcm2niix_path} -b y -w 1 -z y {file_format_args} -o {tempdir_pathlike} {image_folder}"
520+
cmd = f"{self.dcm2niix_path} {self.dcm2niix_options} {file_format_args} -o {tempdir_pathlike} {image_folder}"
484521
convert = subprocess.run(cmd, shell=True, capture_output=True)
485522
self.telemetry_data["dcm2niix"] = {
486523
"returncode": convert.returncode,
@@ -674,10 +711,19 @@ def run_dcm2niix(self):
674711
if re.search(
675712
r"\d+.\d+", sidecar_json.get("ConvolutionKernel")
676713
):
677-
recon_filter_size = re.search(
678-
r"\d+.\d*", sidecar_json.get("ConvolutionKernel")
679-
)[0]
680-
recon_filter_size = float(recon_filter_size)
714+
try:
715+
recon_filter_size = re.search(
716+
r"\d+.\d*",
717+
sidecar_json.get("ConvolutionKernel"),
718+
)[0]
719+
recon_filter_size = float(recon_filter_size)
720+
except ValueError:
721+
# If float conversion fails, try splitting and take first part
722+
match_str = re.search(
723+
r"\d+.\d*",
724+
sidecar_json.get("ConvolutionKernel"),
725+
)[0]
726+
recon_filter_size = float(match_str.split()[0])
681727
sidecar_json.update(
682728
{"ReconFilterSize": float(recon_filter_size)}
683729
)
@@ -1037,9 +1083,13 @@ def load_spread_sheet_data(self):
10371083
10381084
example usage:
10391085
1040-
dcm2niix4pet folder_with_pet_dicoms/ --destinationp-path sub-ValidBidSSubject/pet # the simplest conversion
1086+
dcm2niix4pet folder_with_pet_dicoms/ --destination-path sub-ValidBidSSubject/pet # the simplest conversion
10411087
dcm2niix4pet folder_with_pet_dicoms/ --destination-path sub-ValidBidsSubject/pet --metadata-path metadata.xlsx \
10421088
# use with an input spreadsheet
1089+
dcm2niix4pet folder_with_pet_dicoms/ --destination-path sub-ValidBidsSubject/pet --dcm2niix-options -v y -w 1 -z y \
1090+
# use with custom dcm2niix options
1091+
dcm2niix4pet --set-dcm2niix-options '-v y -w 1 -z y' \
1092+
# set default dcm2niix options in config file
10431093
10441094
"""
10451095
)
@@ -1135,6 +1185,13 @@ def cli():
11351185
f"DCM2NIIX_PATH",
11361186
type=pathlib.Path,
11371187
)
1188+
parser.add_argument(
1189+
"--set-dcm2niix-options",
1190+
help="Provide dcm2niix options to be used as defaults, writes to config "
1191+
f"file {Path.home()}/.pet2bidsconfig under the variable "
1192+
f"PET2BIDS_DCM2NIIX_OPTIONS. Example: --set-dcm2niix-options '-v y -w 1 -z y'",
1193+
type=str,
1194+
)
11381195
parser.add_argument(
11391196
"--set-default-metadata-json",
11401197
help="Provide a path to a default metadata file json file."
@@ -1190,6 +1247,15 @@ def cli():
11901247
help="Accept any NifTi produced by dcm2niix even if it contains errors. This flag should only be used for "
11911248
"batch processing and only if you're performing robust QC after the fact.",
11921249
)
1250+
parser.add_argument(
1251+
"--dcm2niix-options",
1252+
nargs="*",
1253+
default=[],
1254+
help="Additional dcm2niix options to pass through. Use the same format as dcm2niix command line. "
1255+
"Note: -f flag and its value will be filtered out as file format is handled separately. "
1256+
"You can also set default options using --set-dcm2niix-options or the PET2BIDS_DCM2NIIX_OPTIONS environment variable. "
1257+
"Example: --dcm2niix-options -v y -w 1 -z y",
1258+
)
11931259
return parser
11941260

11951261

@@ -1336,6 +1402,12 @@ def main():
13361402
helper_functions.modify_config_file("DCM2NIIX_PATH", cli_args.set_dcm2niix_path)
13371403
sys.exit(0)
13381404

1405+
if cli_args.set_dcm2niix_options:
1406+
helper_functions.modify_config_file(
1407+
"PET2BIDS_DCM2NIIX_OPTIONS", cli_args.set_dcm2niix_options
1408+
)
1409+
sys.exit(0)
1410+
13391411
if cli_args.set_default_metadata_json:
13401412
helper_functions.modify_config_file(
13411413
"DEFAULT_METADATA_JSON", cli_args.set_default_metadata_json
@@ -1354,6 +1426,9 @@ def main():
13541426
cli_args.translation_script_path
13551427
),
13561428
additional_arguments=cli_args.kwargs,
1429+
dcm2niix_options=(
1430+
" ".join(cli_args.dcm2niix_options) if cli_args.dcm2niix_options else ""
1431+
),
13571432
tempdir_location=cli_args.tempdir,
13581433
silent=cli_args.silent,
13591434
ezbids=cli_args.ezbids,

pypet2bids/pyproject.toml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "pypet2bids"
7-
version = "1.4.3"
7+
version = "1.4.4"
88
description = "A python library for converting PET imaging and blood data to BIDS."
99
authors = [
1010
{name = "anthony galassi", email = "[email protected]"}
@@ -52,6 +52,7 @@ dev = [
5252
"pyinstaller>=5.4.1",
5353
"build>=0.10.0",
5454
"briefcase>=0.3.23; python_version>='3.9'",
55+
"black>=23.0.0",
5556
]
5657

5758
[project.scripts]
@@ -78,3 +79,21 @@ include = [
7879
"/pypet2bids",
7980
"/README.md",
8081
]
82+
83+
[tool.black]
84+
line-length = 88
85+
target-version = ['py38']
86+
include = '\.pyi?$'
87+
extend-exclude = '''
88+
/(
89+
# directories
90+
\.eggs
91+
| \.git
92+
| \.hg
93+
| \.mypy_cache
94+
| \.tox
95+
| \.venv
96+
| build
97+
| dist
98+
)/
99+
'''

0 commit comments

Comments
 (0)