From 310f3e471131210b95a0073762b798d921a7be45 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 89e1f8e4e..93fcdff97 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", + "G", + "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", + "PLW2901", + "RUF005", + "RUF012", ] [tool.ruff.lint.flake8-quotes] From 5ae7cf0da99576abd05fe291b984867709cfbefe Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Thu, 29 Feb 2024 22:26:10 +0100 Subject: [PATCH 02/14] STY: Apply ruff/flake8-logging-format rule G004 G004 Logging statement uses f-string --- fmriprep/_warnings.py | 2 +- fmriprep/interfaces/reports.py | 5 +++-- fmriprep/workflows/bold/stc.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fmriprep/_warnings.py b/fmriprep/_warnings.py index 151b6ca0c..a744a8e9e 100644 --- a/fmriprep/_warnings.py +++ b/fmriprep/_warnings.py @@ -35,7 +35,7 @@ def _warn(message, category=None, stacklevel=1, source=None): category = type(category).__name__ category = category.replace('type', 'WARNING') - logging.getLogger('py.warnings').warning(f'{category or "WARNING"}: {message}') + logging.getLogger('py.warnings').warning('%s: %s', category or 'WARNING', message) def _showwarning(message, category, filename, lineno, file=None, line=None): diff --git a/fmriprep/interfaces/reports.py b/fmriprep/interfaces/reports.py index 6d199ccee..3e1fdc324 100644 --- a/fmriprep/interfaces/reports.py +++ b/fmriprep/interfaces/reports.py @@ -365,7 +365,8 @@ def get_world_pedir(ornt, pe_direction): if flip[not inv].startswith(axcode): return '-'.join(flip) LOGGER.warning( - 'Cannot determine world direction of phase encoding. ' - f'Orientation: {ornt}; PE dir: {pe_direction}' + 'Cannot determine world direction of phase encoding. Orientation: %s; PE dir: %s', + ornt, + pe_direction, ) return 'Could not be determined - assuming Anterior-Posterior' diff --git a/fmriprep/workflows/bold/stc.py b/fmriprep/workflows/bold/stc.py index 65e9e6fe9..bae48f704 100644 --- a/fmriprep/workflows/bold/stc.py +++ b/fmriprep/workflows/bold/stc.py @@ -115,7 +115,7 @@ def init_bold_stc_wf( inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file', 'skip_vols']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['stc_file']), name='outputnode') - LOGGER.log(25, f'BOLD series will be slice-timing corrected to an offset of {tzero:.3g}s.') + LOGGER.log(25, 'BOLD series will be slice-timing corrected to an offset of %.3gs.', tzero) # It would be good to fingerprint memory use of afni.TShift slice_timing_correction = pe.Node( From 1b038b91f967812d48bf655c39ed056c3e50f95e 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 03/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 3ecd4de67..e289792b4 100644 --- a/fmriprep/config.py +++ b/fmriprep/config.py @@ -775,9 +775,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 3e1fdc324..363c301c9 100644 --- a/fmriprep/interfaces/reports.py +++ b/fmriprep/interfaces/reports.py @@ -254,20 +254,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 98c225ab03939992c34b66344ffb4129909916c9 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 04/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 e289792b4..d299e044a 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 ff683dc0837b6bcfb671bc7ab8956fefbd469c53 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 05/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 a8511d04b..46ea82b54 100644 --- a/fmriprep/interfaces/conftest.py +++ b/fmriprep/interfaces/conftest.py @@ -9,7 +9,7 @@ import os from contextlib import contextmanager - @contextmanager # type: ignore + @contextmanager def _chdir(path): cwd = os.getcwd() os.chdir(path) From 5a3779cef92f7f0c626c507535e953cec725eaa4 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 06/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 e666830c1..925dc0caa 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 97c94d482423dfd33bf87ec67713667ceed2a4e6 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 07/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 d68ea2bbd..c4044d74a 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 ad76bb3218011de678a9117f652444db1b7f3c76 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 08/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 | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fmriprep/workflows/bold/base.py b/fmriprep/workflows/bold/base.py index 0130ebf65..1af997ef2 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, ) -> pe.Workflow: """ diff --git a/fmriprep/workflows/bold/fit.py b/fmriprep/workflows/bold/fit.py index a585d5646..51958606c 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, omp_nthreads: int = 1, name: str = 'bold_fit_wf', diff --git a/fmriprep/workflows/tests/test_base.py b/fmriprep/workflows/tests/test_base.py index 1af32eb18..2e58fc3e5 100644 --- a/fmriprep/workflows/tests/test_base.py +++ b/fmriprep/workflows/tests/test_base.py @@ -117,8 +117,8 @@ def _make_params( use_syn_sdc: str | bool = False, force_syn: bool = False, freesurfer: bool = True, - ignore: list[str] = None, - bids_filters: dict = None, + ignore: list[str] | None = None, + bids_filters: dict | None = None, ): if ignore is None: ignore = [] From be39078a91f680c0657ba0fdfc09c4d08d1c3fcf 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 09/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 c8a2fb8a7..f8b007b2d 100644 --- a/fmriprep/workflows/base.py +++ b/fmriprep/workflows/base.py @@ -792,8 +792,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 4a6f4a1a9b5f72ac116527fcb8e9db3a6acad143 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 10/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 754c88545..b5d1c036b 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 5ff955253160278e9af955692e119c1e539f6211 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 11/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 51958606c..c32d6cce5 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 @@ -746,7 +746,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 56d4663274f2c421060561474aeaba888de4b878 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 12/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 0b6ae837c..1717cb808 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 7b8dec29e4e58af5793ad2a6b353f9ff97bf67ca 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 13/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 c32d6cce5..27783ec6f 100644 --- a/fmriprep/workflows/bold/fit.py +++ b/fmriprep/workflows/bold/fit.py @@ -794,7 +794,7 @@ def init_bold_native_wf( # Multiecho outputs 'bold_echos', # Individual corrected echos 't2star_map', # T2* map - ], # fmt:skip + ], ), name='outputnode', ) From 4ebdbe8dba2003571d5d81fc199c5fce45ee086e 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 14/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 7be150bd9..106ce8082 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 363c301c9..0c56f5845 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 33116f760..7226025b7 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):