From 68ca1b8fd32aa13f9954d41fe82ac19622159e11 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 21:47:18 +0100 Subject: [PATCH 01/14] STY: Enforce more ruff rules --- pyproject.toml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7a05d2f3..d1403d6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -154,9 +154,6 @@ line-length = 99 [tool.ruff.lint] extend-select = [ - "F", - "E", - "W", "I", "UP", "YTT", @@ -164,8 +161,8 @@ extend-select = [ "BLE", "B", "A", - # "CPY", "C4", + # "CPY", "DTZ", "T10", # "EM", @@ -173,12 +170,33 @@ extend-select = [ "FA", "ISC", "ICN", + "LOG", + "PIE", + "PYI", "PT", "Q", + # "SIM", + # "TID", + "FLY", + # "PD", + "PERF", + "W", + "PGH", + "PLC", + "PLE", + "PLW", + "FURB", + "RUF", ] ignore = [ "S311", # We are not using random for cryptographic purposes "S603", + "PIE790", + "PERF203", + "PLC0415", + "PLW2901", + "RUF005", + "RUF012", ] [tool.ruff.lint.flake8-quotes] From 4ac93ca81b69744664dae0f9ec0a0ba4609eec96 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 21:57:30 +0100 Subject: [PATCH 02/14] STY: Apply ruff/flynt rules FLY002 FLY002 Consider f-string instead of string join --- fmriprep/config.py | 4 +--- fmriprep/interfaces/reports.py | 11 +++-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/fmriprep/config.py b/fmriprep/config.py index c9f6efd4..7d15b04f 100644 --- a/fmriprep/config.py +++ b/fmriprep/config.py @@ -780,9 +780,7 @@ def get(flat=False): return settings return { - '.'.join((section, k)): v - for section, configs in settings.items() - for k, v in configs.items() + f'{section}.{k}': v for section, configs in settings.items() for k, v in configs.items() } diff --git a/fmriprep/interfaces/reports.py b/fmriprep/interfaces/reports.py index 49ac5905..6df1d343 100644 --- a/fmriprep/interfaces/reports.py +++ b/fmriprep/interfaces/reports.py @@ -261,20 +261,15 @@ def _generate_segment(self): pedir = get_world_pedir(self.inputs.orientation, self.inputs.pe_direction) - dummy_scan_tmp = '{n_dum}' if self.inputs.dummy_scans == self.inputs.algo_dummy_scans: - dummy_scan_msg = ' '.join( - [dummy_scan_tmp, '(Confirmed: {n_alg} automatically detected)'] - ).format(n_dum=self.inputs.dummy_scans, n_alg=self.inputs.algo_dummy_scans) + dummy_scan_msg = f'{self.inputs.dummy_scans} (Confirmed: {self.inputs.algo_dummy_scans} automatically detected)' # the number of dummy scans was specified by the user and # it is not equal to the number detected by the algorithm elif self.inputs.dummy_scans is not None: - dummy_scan_msg = ' '.join( - [dummy_scan_tmp, '(Warning: {n_alg} automatically detected)'] - ).format(n_dum=self.inputs.dummy_scans, n_alg=self.inputs.algo_dummy_scans) + dummy_scan_msg = f'{self.inputs.dummy_scans} (Warning: {self.inputs.algo_dummy_scans} automatically detected)' # the number of dummy scans was not specified by the user else: - dummy_scan_msg = dummy_scan_tmp.format(n_dum=self.inputs.algo_dummy_scans) + dummy_scan_msg = f'{self.inputs.algo_dummy_scans}' multiecho = 'Single-echo EPI sequence.' n_echos = len(self.inputs.echo_idx) From 3b91ee44dd267f649e580ed4e8625aefb9079842 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:07:53 +0100 Subject: [PATCH 03/14] STY: Apply ruff/Perflint rule PERF403 PERF403 Use a dictionary comprehension instead of a for-loop --- fmriprep/config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fmriprep/config.py b/fmriprep/config.py index 7d15b04f..3beb1b75 100644 --- a/fmriprep/config.py +++ b/fmriprep/config.py @@ -530,8 +530,7 @@ def _process_value(value): 'raw': cls.bids_dir, 'templateflow': Path(TF_LAYOUT.root), } - for deriv_name, deriv_path in cls.derivatives.items(): - dataset_links[deriv_name] = deriv_path + dataset_links.update(cls.derivatives) cls.dataset_links = dataset_links if 'all' in cls.debug: From 5f19852ac5eb741860d2ec7289666e4cd52575f1 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:14:31 +0100 Subject: [PATCH 04/14] STY: Apply ruff/pygrep-hooks rule PGH003 PGH003 Use specific rule codes when ignoring type issues --- fmriprep/interfaces/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmriprep/interfaces/conftest.py b/fmriprep/interfaces/conftest.py index 6f7e850c..a3dbf198 100644 --- a/fmriprep/interfaces/conftest.py +++ b/fmriprep/interfaces/conftest.py @@ -10,7 +10,7 @@ import os from contextlib import contextmanager - @contextmanager # type: ignore + @contextmanager def _chdir(path): cwd = os.getcwd() os.chdir(path) From bc2af9e069ee4260d0f48446621240ea882e953c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:15:49 +0100 Subject: [PATCH 05/14] STY: Apply ruff/Pylint rule PLE1205 PLE1205 Too many arguments for `logging` format string --- fmriprep/interfaces/workbench.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmriprep/interfaces/workbench.py b/fmriprep/interfaces/workbench.py index e666830c..925dc0ca 100644 --- a/fmriprep/interfaces/workbench.py +++ b/fmriprep/interfaces/workbench.py @@ -292,7 +292,7 @@ def _format_arg(self, opt, spec, val): if opt == 'valid_roi_out' and val: # generate a filename and add it to argstr roi_out = self._gen_filename(self.inputs.in_file, suffix='_roi') - iflogger.info('Setting roi output file as', roi_out) + iflogger.info('Setting roi output file as %s', roi_out) spec.argstr += ' ' + roi_out return super()._format_arg(opt, spec, val) From ddc48142901193f9ae870155e9cb39de88c716fd Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:18:19 +0100 Subject: [PATCH 06/14] STY: Apply ruff rule RUF010 RUF010 Use explicit conversion flag --- fmriprep/cli/tests/test_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmriprep/cli/tests/test_parser.py b/fmriprep/cli/tests/test_parser.py index c44221d1..e6cf4d49 100644 --- a/fmriprep/cli/tests/test_parser.py +++ b/fmriprep/cli/tests/test_parser.py @@ -254,7 +254,7 @@ def test_derivatives(tmp_path): # Providing --derivatives with names should use them temp_args = args + [ '--derivatives', - f'anat={str(bids_path / "derivatives/smriprep")}', + f'anat={bids_path / "derivatives/smriprep"}', ] opts = parser.parse_args(temp_args) assert opts.derivatives == {'anat': bids_path / 'derivatives/smriprep'} From 21a0cd55f19b98bd418f99664cd9ee8f2547cb0f Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:18:59 +0100 Subject: [PATCH 07/14] STY: Apply ruff rule RUF013 RUF013 PEP 484 prohibits implicit `Optional` --- fmriprep/workflows/bold/base.py | 2 +- fmriprep/workflows/bold/fit.py | 2 +- fmriprep/workflows/tests/test_base.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fmriprep/workflows/bold/base.py b/fmriprep/workflows/bold/base.py index bcd282d5..89aa4974 100644 --- a/fmriprep/workflows/bold/base.py +++ b/fmriprep/workflows/bold/base.py @@ -55,7 +55,7 @@ def init_bold_wf( *, bold_series: list[str], - precomputed: dict = None, + precomputed: dict | None = None, fieldmap_id: str | None = None, jacobian: bool = False, ) -> pe.Workflow: diff --git a/fmriprep/workflows/bold/fit.py b/fmriprep/workflows/bold/fit.py index 0a653625..e9301c35 100644 --- a/fmriprep/workflows/bold/fit.py +++ b/fmriprep/workflows/bold/fit.py @@ -95,7 +95,7 @@ def get_sbrefs( def init_bold_fit_wf( *, bold_series: list[str], - precomputed: dict = None, + precomputed: dict | None = None, fieldmap_id: str | None = None, jacobian: bool = False, omp_nthreads: int = 1, diff --git a/fmriprep/workflows/tests/test_base.py b/fmriprep/workflows/tests/test_base.py index df96afdd..c7a73528 100644 --- a/fmriprep/workflows/tests/test_base.py +++ b/fmriprep/workflows/tests/test_base.py @@ -115,9 +115,9 @@ def _make_params( skull_strip_t1w: str = 'auto', use_syn_sdc: str | bool = False, freesurfer: bool = True, - ignore: list[str] = None, - force: list[str] = None, - bids_filters: dict = None, + ignore: list[str] | None = None, + force: list[str] | None = None, + bids_filters: dict | None = None, ): if ignore is None: ignore = [] From 0f68d9a871f27f9ddb3e8adeb46c007815a53c4d Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:19:40 +0100 Subject: [PATCH 08/14] STY: Apply ruff rule RUF021 RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear --- fmriprep/workflows/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fmriprep/workflows/base.py b/fmriprep/workflows/base.py index 57b75772..3b7fb007 100644 --- a/fmriprep/workflows/base.py +++ b/fmriprep/workflows/base.py @@ -876,8 +876,8 @@ def map_fieldmap_estimation( fmap_estimators = find_estimators( layout=layout, subject=subject_id, - fmapless=bool(use_syn) or ignore_fieldmaps and force_syn, - force_fmapless=force_syn or ignore_fieldmaps and use_syn, + fmapless=bool(use_syn) or (ignore_fieldmaps and force_syn), + force_fmapless=force_syn or (ignore_fieldmaps and use_syn), bids_filters=filters, ) From 63c47fd34ec7b56343f46c309c7dd902ea9b4c4b Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:20:39 +0100 Subject: [PATCH 09/14] STY: Apply ruff rule RUF100 RUF100 Unused `noqa` directive --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 754c8854..b5d1c036 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ sys.path.append(os.path.abspath('sphinxext')) sys.path.insert(0, os.path.abspath('../wrapper')) -from github_link import make_linkcode_resolve # noqa: E402 +from github_link import make_linkcode_resolve # -- General configuration ------------------------------------------------ From f07affd7e13716e3ac64931cea823c6b645cdcb9 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:24:00 +0100 Subject: [PATCH 10/14] STY: Apply ruff/Pyflakes preview rule F841 F841 Local variable is assigned to but never used --- fmriprep/workflows/bold/fit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fmriprep/workflows/bold/fit.py b/fmriprep/workflows/bold/fit.py index e9301c35..21a01367 100644 --- a/fmriprep/workflows/bold/fit.py +++ b/fmriprep/workflows/bold/fit.py @@ -231,7 +231,7 @@ def init_bold_fit_wf( metadata = layout.get_metadata(bold_file) orientation = ''.join(nb.aff2axcodes(nb.load(bold_file).affine)) - bold_tlen, mem_gb = estimate_bold_mem_usage(bold_file) + _bold_tlen, mem_gb = estimate_bold_mem_usage(bold_file) # Boolean used to update workflow self-descriptions multiecho = len(bold_series) > 1 @@ -793,7 +793,7 @@ def init_bold_native_wf( bold_file = bold_series[0] metadata = all_metadata[0] - bold_tlen, mem_gb = estimate_bold_mem_usage(bold_file) + _bold_tlen, mem_gb = estimate_bold_mem_usage(bold_file) if multiecho: shapes = [nb.load(echo).shape for echo in bold_series] From 71266072619f1c335a9e993f86a6fd4dea70fae1 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:25:18 +0100 Subject: [PATCH 11/14] STY: Apply ruff/refurb preview rule FURB192 FURB192 Prefer `max` over `sorted()` to compute the maximum value in a sequence --- fmriprep/cli/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmriprep/cli/version.py b/fmriprep/cli/version.py index 0b6ae837..1717cb80 100644 --- a/fmriprep/cli/version.py +++ b/fmriprep/cli/version.py @@ -72,7 +72,7 @@ def check_latest(): versions = [Version(rel) for rel in response.json()['releases'].keys()] versions = [rel for rel in versions if not rel.is_prerelease] if versions: - latest = sorted(versions)[-1] + latest = max(versions) else: latest = None From d1e4a09a6e33eb81bad6e3fb4ca0a8688edd75f1 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:26:07 +0100 Subject: [PATCH 12/14] STY: Apply ruff preview rule RUF028 RUF028 This suppression comment is invalid because it cannot be in an expression, pattern, argument list, or other non-statement --- fmriprep/workflows/bold/fit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmriprep/workflows/bold/fit.py b/fmriprep/workflows/bold/fit.py index 21a01367..5013dfe1 100644 --- a/fmriprep/workflows/bold/fit.py +++ b/fmriprep/workflows/bold/fit.py @@ -841,7 +841,7 @@ def init_bold_native_wf( # Multiecho outputs 'bold_echos', # Individual corrected echos 't2star_map', # T2* map - ], # fmt:skip + ], ), name='outputnode', ) From 9acf3d40b9dd0cd083621594cf21b4fc77429985 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:27:05 +0100 Subject: [PATCH 13/14] STY: Apply ruff preview rule RUF039 RUF039 First argument is not raw string --- fmriprep/interfaces/confounds.py | 4 ++-- fmriprep/interfaces/reports.py | 12 ++++++------ fmriprep/utils/telemetry.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fmriprep/interfaces/confounds.py b/fmriprep/interfaces/confounds.py index 7be150bd..106ce808 100644 --- a/fmriprep/interfaces/confounds.py +++ b/fmriprep/interfaces/confounds.py @@ -429,8 +429,8 @@ def less_breakable(a_string): # Taken from https://stackoverflow.com/questions/1175208/ # If we end up using it more than just here, probably worth pulling in a well-tested package def camel_to_snake(name): - s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + s1 = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', s1).lower() def _adjust_indices(left_df, right_df): # This forces missing values to appear at the beginning of the DataFrame diff --git a/fmriprep/interfaces/reports.py b/fmriprep/interfaces/reports.py index 6df1d343..f46843ef 100644 --- a/fmriprep/interfaces/reports.py +++ b/fmriprep/interfaces/reports.py @@ -131,12 +131,12 @@ def _run_interface(self, runtime): def _generate_segment(self): BIDS_NAME = re.compile( r'^(.*\/)?' - '(?Psub-[a-zA-Z0-9]+)' - '(_(?Pses-[a-zA-Z0-9]+))?' - '(_(?Ptask-[a-zA-Z0-9]+))?' - '(_(?Pacq-[a-zA-Z0-9]+))?' - '(_(?Prec-[a-zA-Z0-9]+))?' - '(_(?Prun-[a-zA-Z0-9]+))?' + r'(?Psub-[a-zA-Z0-9]+)' + r'(_(?Pses-[a-zA-Z0-9]+))?' + r'(_(?Ptask-[a-zA-Z0-9]+))?' + r'(_(?Pacq-[a-zA-Z0-9]+))?' + r'(_(?Prec-[a-zA-Z0-9]+))?' + r'(_(?Prun-[a-zA-Z0-9]+))?' ) if not isdefined(self.inputs.subjects_dir): diff --git a/fmriprep/utils/telemetry.py b/fmriprep/utils/telemetry.py index 33116f76..7226025b 100644 --- a/fmriprep/utils/telemetry.py +++ b/fmriprep/utils/telemetry.py @@ -156,7 +156,7 @@ def before_send(event, hints): return None if msg.startswith('Saving crash info to '): return None - if re.match('Node .+ failed to run on host .+', msg): + if re.match(r'Node .+ failed to run on host .+', msg): return None if 'breadcrumbs' in event and isinstance(event['breadcrumbs'], list): From b8cc14e7ec983d53dbde5459f6a28b4d1f753fff Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 6 Aug 2025 08:00:55 +0200 Subject: [PATCH 14/14] chore: ISC rules do not conflict with the formatter any more https://astral.sh/blog/ruff-v0.9.0#fewer-single-line-implicitly-concatenated-strings --- .pre-commit-config.yaml | 2 +- tox.ini | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 837429d2..18254a7a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: check-toml - id: check-added-large-files - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.2 + rev: v0.12.7 hooks: - id: ruff-check args: [ --fix ] diff --git a/tox.ini b/tox.ini index ced8d6cd..2c97cad4 100644 --- a/tox.ini +++ b/tox.ini @@ -73,7 +73,6 @@ skip_install = true commands = ruff check --fix ruff format - ruff check --select ISC001 [testenv:spellcheck] description = Check spelling