From 4f8436a5414131f4e04f742eee83f4ad35c76a24 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:44:36 +0200 Subject: [PATCH 01/14] maint: run `ruff check` --- .github/workflows/pythonpackage.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 1ec634f7..f2fc1d7d 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -79,7 +79,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: pipx run ruff format --diff + - run: | + pipx run ruff check --output-format=github + pipx run ruff format --diff codespell: runs-on: ubuntu-latest From b011355c0db956f4297285b9a0f68d45d1403ca8 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:49:34 +0200 Subject: [PATCH 02/14] maint: update ruff rule selection - No need to specify `F` and `E` rules with `extend-select`. - Update rules to ignore. --- pyproject.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cf5917f5..b929f1cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -193,8 +193,6 @@ line-length = 99 [tool.ruff.lint] extend-select = [ - "F", - "E", "W", "I", "UP", @@ -202,10 +200,9 @@ extend-select = [ "S", "BLE", "B", - "A", # "CPY", "C4", "DTZ", - "T10", # "EM", + "T10", "EXE", "FA", "ISC", @@ -216,6 +213,7 @@ extend-select = [ ignore = [ "F841", "S311", # We are not using random for cryptographic purposes + "S310", "S603", ] @@ -224,6 +222,7 @@ inline-quotes = "single" [tool.ruff.lint.extend-per-file-ignores] "*/test_*.py" = ["S101"] +"docs/notebooks/*.ipynb" = ["B018", "F401", "F821"] "docs/source/conf.py" = ["A001"] "mriqc/bin/nib_hash.py" = ["S324"] "mriqc/config.py" = ["S105"] From 8547540354b9b94694521e71fe7cb2aa3da3851f Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:50:03 +0200 Subject: [PATCH 03/14] Apply ruff/pycodestyle rule E741 E741 Ambiguous variable name: `l` --- docs/notebooks/MRIQC Web API.ipynb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/notebooks/MRIQC Web API.ipynb b/docs/notebooks/MRIQC Web API.ipynb index b0e6cfcd..bfd59e5c 100644 --- a/docs/notebooks/MRIQC Web API.ipynb +++ b/docs/notebooks/MRIQC Web API.ipynb @@ -224,11 +224,11 @@ "print(\n", " ','.join(\n", " [\n", - " l\n", - " for l in df_t1w.columns\n", - " if not l.startswith('_')\n", - " and not l.startswith('bids_meta')\n", - " and not l.startswith('provenance')\n", + " line\n", + " for line in df_t1w.columns\n", + " if not line.startswith('_')\n", + " and not line.startswith('bids_meta')\n", + " and not line.startswith('provenance')\n", " ]\n", " )\n", ")" @@ -291,11 +291,11 @@ "print(\n", " ','.join(\n", " [\n", - " l\n", - " for l in df_bold.columns\n", - " if not l.startswith('_')\n", - " and not l.startswith('bids_meta')\n", - " and not l.startswith('provenance')\n", + " line\n", + " for line in df_bold.columns\n", + " if not line.startswith('_')\n", + " and not line.startswith('bids_meta')\n", + " and not line.startswith('provenance')\n", " ]\n", " )\n", ")" From a91d78a2f58b7e596736e44ef6a8657c4aef0ab5 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:52:05 +0200 Subject: [PATCH 04/14] Apply ruff/pycodestyle rule E401 E401 Multiple imports on one line --- docs/notebooks/MRIQC Web API.ipynb | 3 ++- docs/notebooks/finding_spikes.ipynb | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/notebooks/MRIQC Web API.ipynb b/docs/notebooks/MRIQC Web API.ipynb index bfd59e5c..d56a8adb 100644 --- a/docs/notebooks/MRIQC Web API.ipynb +++ b/docs/notebooks/MRIQC Web API.ipynb @@ -21,7 +21,8 @@ "source": [ "import pandas as pd\n", "from json import load\n", - "import urllib.request, json\n", + "import urllib.request\n", + "import json\n", "from pandas.io.json import json_normalize\n", "import seaborn as sns\n", "import pylab as plt\n", diff --git a/docs/notebooks/finding_spikes.ipynb b/docs/notebooks/finding_spikes.ipynb index a2e68867..41643412 100644 --- a/docs/notebooks/finding_spikes.ipynb +++ b/docs/notebooks/finding_spikes.ipynb @@ -8,7 +8,9 @@ }, "outputs": [], "source": [ - "import nibabel, nipy, nilearn\n", + "import nibabel\n", + "import nipy\n", + "import nilearn\n", "from nipy.labs.mask import compute_mask\n", "from nilearn.masking import compute_epi_mask\n", "from nilearn.image import mean_img, new_img_like\n", From 1ee311a4f0cf1cdca8ae6bc3082ccb6fcf354e9d Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:53:04 +0200 Subject: [PATCH 05/14] Apply ruff/pycodestyle rule W605 W605 Invalid escape sequence --- docs/notebooks/Paper-v1.0.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 5fbda5fe..3ed6feb6 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -213,7 +213,7 @@ " draw_line(mean + std, ax=ax, color=color, extend=True)\n", "\n", " ax.annotate(\n", - " '$\\mu$=%0.3f' % mean,\n", + " r'$\\mu$=%0.3f' % mean,\n", " xy=(mean_coord[0], 0.75 * ymax),\n", " xytext=(-35, 30),\n", " textcoords='offset points',\n", @@ -239,7 +239,7 @@ " arrowprops=dict(arrowstyle='<->'),\n", " )\n", " ax.annotate(\n", - " '$2\\sigma$=%0.3f' % (2 * std),\n", + " r'$2\\sigma$=%0.3f' % (2 * std),\n", " xy=(mean_coord[0], 0.70 * ymax),\n", " xytext=(-25, -12),\n", " textcoords='offset points',\n", From 719e939dfeb18b05bb6c8e99479cc4f3a8be0ac4 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:53:42 +0200 Subject: [PATCH 06/14] Apply ruff/pycodestyle rule I001 I001 Import block is un-sorted or un-formatted --- docs/notebooks/MRIQC Web API.ipynb | 16 +++++++++------- docs/notebooks/Paper-v1.0.ipynb | 5 +++-- docs/notebooks/Paper-v2.0.ipynb | 8 ++++---- docs/notebooks/Supplemental Materials.ipynb | 1 + docs/notebooks/finding_spikes.ipynb | 12 ++++++------ mriqc/cli/run.py | 2 +- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/docs/notebooks/MRIQC Web API.ipynb b/docs/notebooks/MRIQC Web API.ipynb index d56a8adb..b73760f4 100644 --- a/docs/notebooks/MRIQC Web API.ipynb +++ b/docs/notebooks/MRIQC Web API.ipynb @@ -19,15 +19,16 @@ }, "outputs": [], "source": [ - "import pandas as pd\n", - "from json import load\n", - "import urllib.request\n", "import json\n", - "from pandas.io.json import json_normalize\n", - "import seaborn as sns\n", - "import pylab as plt\n", "import multiprocessing as mp\n", + "import urllib.request\n", + "from json import load\n", + "\n", "import numpy as np\n", + "import pandas as pd\n", + "import pylab as plt\n", + "import seaborn as sns\n", + "from pandas.io.json import json_normalize\n", "\n", "%matplotlib inline" ] @@ -151,8 +152,9 @@ ], "source": [ "import datetime\n", - "from dateutil import parser\n", + "\n", "import matplotlib.dates as mdates\n", + "from dateutil import parser\n", "\n", "dates_t1w = [parser.parse(d) for d in df_t1w['_created'].values]\n", "dates_t1w.sort()\n", diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 3ed6feb6..52aee2f9 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -11,10 +11,11 @@ "%matplotlib inline\n", "%load_ext autoreload\n", "%autoreload 2\n", - "import matplotlib.pyplot as plt\n", "import os.path as op\n", - "import pandas as pd\n", + "\n", + "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "import pandas as pd\n", "import seaborn as sn\n", "\n", "sn.set(style='whitegrid')" diff --git a/docs/notebooks/Paper-v2.0.ipynb b/docs/notebooks/Paper-v2.0.ipynb index 02f2c03e..8cc52a21 100644 --- a/docs/notebooks/Paper-v2.0.ipynb +++ b/docs/notebooks/Paper-v2.0.ipynb @@ -24,12 +24,12 @@ "%load_ext autoreload\n", "%autoreload 2\n", "import os.path as op\n", + "\n", "import numpy as np\n", "import pandas as pd\n", - "from pkg_resources import resource_filename as pkgrf\n", - "\n", + "from mriqc.classifier.data import combine_datasets, read_dataset\n", "from mriqc.viz import misc as mviz\n", - "from mriqc.classifier.data import read_dataset, combine_datasets\n", + "from pkg_resources import resource_filename as pkgrf\n", "\n", "# Where the outputs should be saved\n", "outputs_path = '../../mriqc-data/'\n", @@ -776,8 +776,8 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", - "from mriqc.viz.utils import plot_slice\n", "import nibabel as nb\n", + "from mriqc.viz.utils import plot_slice\n", "\n", "for im, z in fn_clear:\n", " image_path = op.join(ds030_path, 'sub-%s' % im, 'anat', 'sub-%s_T1w.nii.gz' % im)\n", diff --git a/docs/notebooks/Supplemental Materials.ipynb b/docs/notebooks/Supplemental Materials.ipynb index 0758f348..965a30a4 100644 --- a/docs/notebooks/Supplemental Materials.ipynb +++ b/docs/notebooks/Supplemental Materials.ipynb @@ -23,6 +23,7 @@ "%load_ext autoreload\n", "%autoreload 2\n", "import os.path as op\n", + "\n", "import numpy as np\n", "import pandas as pd\n", "from mriqc.viz import misc as mviz\n", diff --git a/docs/notebooks/finding_spikes.ipynb b/docs/notebooks/finding_spikes.ipynb index 41643412..b7d42d90 100644 --- a/docs/notebooks/finding_spikes.ipynb +++ b/docs/notebooks/finding_spikes.ipynb @@ -9,15 +9,15 @@ "outputs": [], "source": [ "import nibabel\n", - "import nipy\n", "import nilearn\n", - "from nipy.labs.mask import compute_mask\n", - "from nilearn.masking import compute_epi_mask\n", - "from nilearn.image import mean_img, new_img_like\n", + "import nipy\n", + "import numpy as np\n", "import pylab as plt\n", "import seaborn as sns\n", - "from nilearn.plotting import plot_epi, plot_anat, plot_roi\n", - "import numpy as np\n", + "from nilearn.image import mean_img, new_img_like\n", + "from nilearn.masking import compute_epi_mask\n", + "from nilearn.plotting import plot_anat, plot_epi, plot_roi\n", + "from nipy.labs.mask import compute_mask\n", "\n", "%matplotlib inline" ] diff --git a/mriqc/cli/run.py b/mriqc/cli/run.py index efbe345d..bd872f28 100644 --- a/mriqc/cli/run.py +++ b/mriqc/cli/run.py @@ -35,11 +35,11 @@ def format_elapsed_time(elapsed_timedelta): def main(argv=None): """Entry point for MRIQC's CLI.""" import atexit + import datetime import gc import os import sys import time - import datetime from tempfile import mkstemp from mriqc import config, messages From 39378170120d0e318ee215a6afcd989064d19479 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:54:27 +0200 Subject: [PATCH 07/14] Apply ruff/flake8-comprehensions rule C408 C408 Unnecessary `dict()` call (rewrite as a literal) --- docs/notebooks/Paper-v1.0.ipynb | 51 +++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 52aee2f9..165b769b 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -221,23 +221,23 @@ " va='center',\n", " color='w',\n", " size=14,\n", - " bbox=dict(boxstyle='round', fc=color, ec='none', color='none', lw=0),\n", - " arrowprops=dict(\n", - " arrowstyle='wedge,tail_width=0.8',\n", - " lw=0,\n", - " patchA=None,\n", - " patchB=None,\n", - " fc=color,\n", - " ec='none',\n", - " relpos=(0.5, 0.5),\n", - " ),\n", + " bbox={'boxstyle': 'round', 'fc': color, 'ec': 'none', 'color': 'none', 'lw': 0},\n", + " arrowprops={\n", + " 'arrowstyle': 'wedge,tail_width=0.8',\n", + " 'lw': 0,\n", + " 'patchA': None,\n", + " 'patchB': None,\n", + " 'fc': color,\n", + " 'ec': 'none',\n", + " 'relpos': (0.5, 0.5),\n", + " },\n", " )\n", " sigmay = 0.70 * ymax\n", " ax.annotate(\n", " s='',\n", " xy=(mean - std, sigmay),\n", " xytext=(mean + std, sigmay),\n", - " arrowprops=dict(arrowstyle='<->'),\n", + " arrowprops={'arrowstyle': '<->'},\n", " )\n", " ax.annotate(\n", " r'$2\\sigma$=%0.3f' % (2 * std),\n", @@ -247,7 +247,14 @@ " va='center',\n", " color='k',\n", " size=12,\n", - " bbox=dict(boxstyle='round', fc='w', ec='none', color='none', alpha=0.7, lw=0),\n", + " bbox={\n", + " 'boxstyle': 'round',\n", + " 'fc': 'w',\n", + " 'ec': 'none',\n", + " 'color': 'none',\n", + " 'alpha': 0.7,\n", + " 'lw': 0,\n", + " },\n", " )\n", "\n", " if ds030_score is not None:\n", @@ -260,16 +267,16 @@ " va='center',\n", " color='w',\n", " size=16,\n", - " bbox=dict(boxstyle='round', fc=color, ec='none', color='none', lw=0),\n", - " arrowprops=dict(\n", - " arrowstyle='wedge,tail_width=0.8',\n", - " lw=0,\n", - " patchA=None,\n", - " patchB=None,\n", - " fc=color,\n", - " ec='none',\n", - " relpos=(0.5, 0.5),\n", - " ),\n", + " bbox={'boxstyle': 'round', 'fc': color, 'ec': 'none', 'color': 'none', 'lw': 0},\n", + " arrowprops={\n", + " 'arrowstyle': 'wedge,tail_width=0.8',\n", + " 'lw': 0,\n", + " 'patchA': None,\n", + " 'patchB': None,\n", + " 'fc': color,\n", + " 'ec': 'none',\n", + " 'relpos': (0.5, 0.5),\n", + " },\n", " )\n", "\n", "\n", From 5cc3b829f841d8e0b8d4b7e40c5a6044e2448e49 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:55:12 +0200 Subject: [PATCH 08/14] Apply ruff/flake8-comprehensions rule C413 C413 Unnecessary `list()` call around `sorted()` --- docs/notebooks/Paper-v1.0.ipynb | 2 +- docs/notebooks/Paper-v2.0.ipynb | 2 +- docs/notebooks/Supplemental Materials.ipynb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 165b769b..5d102774 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -32,7 +32,7 @@ "from mriqc.classifier import data as mcd\n", "\n", "abide, _ = mcd.read_dataset(x_path, y_path, rate_label='rater_1')\n", - "sites = list(sorted(set(abide.site.values.ravel())))\n", + "sites = sorted(set(abide.site.values.ravel()))\n", "\n", "fmt = r'{site} & \\pixmat{{{size[0]:d}$\\pm${sr[0]:d}}}{{{size[1]:d}$\\pm${sr[1]:d}}}{{{size[2]:d}$\\pm${sr[1]:d}}}'\n", "fmt += r'& \\pixmat[mm]{{{sp[0]:.2f}$\\pm${spr[0]:.2f}}}{{{sp[1]:.2f}$\\pm${spr[1]:.2f}}}{{{sp[2]:.2f}$\\pm${spr[1]:.2f}}}'\n", diff --git a/docs/notebooks/Paper-v2.0.ipynb b/docs/notebooks/Paper-v2.0.ipynb index 8cc52a21..cc522033 100644 --- a/docs/notebooks/Paper-v2.0.ipynb +++ b/docs/notebooks/Paper-v2.0.ipynb @@ -63,7 +63,7 @@ "rater_types = {'rater_1': float, 'rater_2': float, 'rater_3': float}\n", "mdata = pd.read_csv(y_path, index_col=False, dtype=rater_types)\n", "\n", - "sites = list(sorted(list(set(mdata.site.values.ravel().tolist()))))" + "sites = sorted(list(set(mdata.site.values.ravel().tolist())))" ] }, { diff --git a/docs/notebooks/Supplemental Materials.ipynb b/docs/notebooks/Supplemental Materials.ipynb index 965a30a4..c599b0a1 100644 --- a/docs/notebooks/Supplemental Materials.ipynb +++ b/docs/notebooks/Supplemental Materials.ipynb @@ -48,7 +48,7 @@ "rater_types = {'rater_1': float, 'rater_2': float, 'rater_3': float}\n", "mdata = pd.read_csv(y_path, index_col=False, dtype=rater_types)\n", "\n", - "sites = list(sorted(list(set(mdata.site.values.ravel().tolist()))))" + "sites = sorted(list(set(mdata.site.values.ravel().tolist())))" ] }, { From b47c5ebfe87b2c06e58b6f7a5a4040b1c527f52d Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:56:03 +0200 Subject: [PATCH 09/14] Apply ruff/flake8-comprehensions rule C414 C414 Unnecessary `list()` call within `sorted()` --- docs/notebooks/Paper-v1.0.ipynb | 2 +- docs/notebooks/Paper-v2.0.ipynb | 2 +- docs/notebooks/Supplemental Materials.ipynb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 5d102774..18cd62e3 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -404,7 +404,7 @@ }, "outputs": [], "source": [ - "sites = sorted(list(set(loso_outer.site.ravel().tolist())))\n", + "sites = sorted(set(loso_outer.site.ravel().tolist()))\n", "palette = sn.color_palette('husl', len(sites))\n", "fig = plt.figure()\n", "for i, site in enumerate(sites):\n", diff --git a/docs/notebooks/Paper-v2.0.ipynb b/docs/notebooks/Paper-v2.0.ipynb index cc522033..2e444171 100644 --- a/docs/notebooks/Paper-v2.0.ipynb +++ b/docs/notebooks/Paper-v2.0.ipynb @@ -63,7 +63,7 @@ "rater_types = {'rater_1': float, 'rater_2': float, 'rater_3': float}\n", "mdata = pd.read_csv(y_path, index_col=False, dtype=rater_types)\n", "\n", - "sites = sorted(list(set(mdata.site.values.ravel().tolist())))" + "sites = sorted(set(mdata.site.values.ravel().tolist()))" ] }, { diff --git a/docs/notebooks/Supplemental Materials.ipynb b/docs/notebooks/Supplemental Materials.ipynb index c599b0a1..dc680d8d 100644 --- a/docs/notebooks/Supplemental Materials.ipynb +++ b/docs/notebooks/Supplemental Materials.ipynb @@ -48,7 +48,7 @@ "rater_types = {'rater_1': float, 'rater_2': float, 'rater_3': float}\n", "mdata = pd.read_csv(y_path, index_col=False, dtype=rater_types)\n", "\n", - "sites = sorted(list(set(mdata.site.values.ravel().tolist())))" + "sites = sorted(set(mdata.site.values.ravel().tolist()))" ] }, { From dd212a08a111d5f73f24ae22220b68e5d6e1c8a9 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:56:38 +0200 Subject: [PATCH 10/14] Apply ruff/flake8-comprehensions rule C420 C420 Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead --- mriqc/bin/dfcheck.py | 2 +- mriqc/reports/group.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mriqc/bin/dfcheck.py b/mriqc/bin/dfcheck.py index 832b3fd5..346b6a68 100644 --- a/mriqc/bin/dfcheck.py +++ b/mriqc/bin/dfcheck.py @@ -40,7 +40,7 @@ def read_iqms(feat_file): feat_file = Path(feat_file) if feat_file.suffix == '.csv': - x_df = pd.read_csv(feat_file, index_col=False, dtype={col: str for col in BIDS_COMP}) + x_df = pd.read_csv(feat_file, index_col=False, dtype=dict.fromkeys(BIDS_COMP, str)) # Find present bids bits and sort by them bids_comps_present = list(set(x_df.columns) & set(BIDS_COMP)) bids_comps_present = [bit for bit in BIDS_COMP if bit in bids_comps_present] diff --git a/mriqc/reports/group.py b/mriqc/reports/group.py index 4fa17772..4ef5e7fe 100644 --- a/mriqc/reports/group.py +++ b/mriqc/reports/group.py @@ -45,9 +45,7 @@ def gen_html(csv_file, mod, csv_failed=None, out_file=None): load_data = Loader('mriqc') if csv_file.suffix == '.csv': - dataframe = pd.read_csv( - csv_file, index_col=False, dtype={comp: object for comp in BIDS_COMP} - ) + dataframe = pd.read_csv(csv_file, index_col=False, dtype=dict.fromkeys(BIDS_COMP, object)) id_labels = list(set(BIDS_COMP) & set(dataframe.columns)) dataframe['label'] = dataframe[id_labels].apply(_format_labels, args=(id_labels,), axis=1) From 924ff8bea9c16d5bc32cf10be6e30663e2ba4c78 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:57:17 +0200 Subject: [PATCH 11/14] Apply ruff/flake8-pytest-style PT001 PT001 Use `@pytest.fixture` over `@pytest.fixture()` --- mriqc/conftest.py | 6 +++--- mriqc/qc/tests/test_anatomical.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mriqc/conftest.py b/mriqc/conftest.py index 7d0d55a7..da06ce4b 100644 --- a/mriqc/conftest.py +++ b/mriqc/conftest.py @@ -70,16 +70,16 @@ def expand_namespace(doctest_namespace): tmpdir.cleanup() -@pytest.fixture() +@pytest.fixture def testdata_path(): return _datadir -@pytest.fixture() +@pytest.fixture def workdir(): return None if test_workdir is None else Path(test_workdir) -@pytest.fixture() +@pytest.fixture def outdir(): return None if test_output_dir is None else Path(test_output_dir) diff --git a/mriqc/qc/tests/test_anatomical.py b/mriqc/qc/tests/test_anatomical.py index b89fa1aa..5fa4799b 100644 --- a/mriqc/qc/tests/test_anatomical.py +++ b/mriqc/qc/tests/test_anatomical.py @@ -60,7 +60,7 @@ def get_data(self, sigma, noise='normal'): return test_data, wmdata, bgdata -@pytest.fixture() +@pytest.fixture def gtruth(): return GroundTruth() From 2f0a013ca05c5280c1acc773889ae336312eea64 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:22:14 +0200 Subject: [PATCH 12/14] Apply ruff/pyupgrade rule UP031 UP031 Use format specifiers instead of percent format --- docs/notebooks/MRIQC Web API.ipynb | 9 ++++----- docs/notebooks/Paper-v1.0.ipynb | 2 +- docs/notebooks/Paper-v2.0.ipynb | 14 +++++++------- docs/notebooks/Supplemental Materials.ipynb | 4 ++-- mriqc/bin/fs2gif.py | 13 +++++-------- mriqc/synthstrip/model.py | 4 ++-- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/docs/notebooks/MRIQC Web API.ipynb b/docs/notebooks/MRIQC Web API.ipynb index b73760f4..f0e10716 100644 --- a/docs/notebooks/MRIQC Web API.ipynb +++ b/docs/notebooks/MRIQC Web API.ipynb @@ -64,14 +64,13 @@ " query = []\n", "\n", " if software is not None:\n", - " query.append('\"provenance.software\":\"%s\"' % software)\n", + " query.append(f'\"provenance.software\":\"{software}\"')\n", "\n", " if version != '*':\n", - " query.append('\"provenance.version\":\"%s\"' % version)\n", + " query.append(f'\"provenance.version\":\"{version}\"')\n", "\n", - " page_url = url_root.format(\n", - " modality=modality, query='where={%s}&page=%d' % (','.join(query), page)\n", - " )\n", + " where = ','.join(query)\n", + " page_url = url_root.format(modality=modality, query=f'where={where}&page={page}')\n", " with urllib.request.urlopen(page_url) as url:\n", " data = json.loads(url.read().decode())\n", " dfs.append(json_normalize(data['_items']))\n", diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 18cd62e3..955f09a8 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -214,7 +214,7 @@ " draw_line(mean + std, ax=ax, color=color, extend=True)\n", "\n", " ax.annotate(\n", - " r'$\\mu$=%0.3f' % mean,\n", + " rf'$\\mu$={mean:0.3f}',\n", " xy=(mean_coord[0], 0.75 * ymax),\n", " xytext=(-35, 30),\n", " textcoords='offset points',\n", diff --git a/docs/notebooks/Paper-v2.0.ipynb b/docs/notebooks/Paper-v2.0.ipynb index 2e444171..8547cf67 100644 --- a/docs/notebooks/Paper-v2.0.ipynb +++ b/docs/notebooks/Paper-v2.0.ipynb @@ -283,14 +283,14 @@ " y1, y2, out_file=op.join(outputs_path, 'figures', 'fig02-irv.pdf')\n", ")\n", "\n", - "print(\"Cohen's Kappa %f\" % cohen_kappa_score(y1, y2))\n", + "print(f\"Cohen's Kappa {cohen_kappa_score(y1, y2):f}\")\n", "\n", "y1 = overlap.rater_1.values.ravel()\n", "y1[y1 == 0] = 1\n", "\n", "y2 = overlap.rater_2.values.ravel()\n", "y2[y2 == 0] = 1\n", - "print(\"Cohen's Kappa (binarized): %f\" % cohen_kappa_score(y1, y2))" + "print(f\"Cohen's Kappa (binarized): {cohen_kappa_score(y1, y2):f}\")" ] }, { @@ -667,7 +667,7 @@ "fig = plt.figure(figsize=(20, 6))\n", "# plt.title(\"Feature importance plot\")\n", "sn.boxplot(x='Feature', y='Importance', data=pd.DataFrame(df), linewidth=1, notch=True)\n", - "plt.xlabel('Features selected (%d)' % len(features))\n", + "plt.xlabel(f'Features selected ({len(features)})')\n", "# plt.bar(range(nft), importances[indices],\n", "# color=\"r\", yerr=std[indices], align=\"center\")\n", "plt.xticks(range(nft))\n", @@ -780,13 +780,13 @@ "from mriqc.viz.utils import plot_slice\n", "\n", "for im, z in fn_clear:\n", - " image_path = op.join(ds030_path, 'sub-%s' % im, 'anat', 'sub-%s_T1w.nii.gz' % im)\n", + " image_path = op.join(ds030_path, f'sub-{im}', 'anat', f'sub-{im}_T1w.nii.gz')\n", " imdata = nb.load(image_path).get_data()\n", "\n", " fig, ax = plt.subplots()\n", " plot_slice(imdata[..., z], annotate=True)\n", " fig.savefig(\n", - " op.join(outputs_path, 'figures', 'fig-06_sub-%s_slice-%03d.svg' % (im, z)),\n", + " op.join(outputs_path, 'figures', f'fig-06_sub-{im}_slice-{z:03}.svg'),\n", " dpi=300,\n", " bbox_inches='tight',\n", " )\n", @@ -807,13 +807,13 @@ " ('50073', 162),\n", "]\n", "for im, z in fp_clear:\n", - " image_path = op.join(ds030_path, 'sub-%s' % im, 'anat', 'sub-%s_T1w.nii.gz' % im)\n", + " image_path = op.join(ds030_path, f'sub-{im}', 'anat', f'sub-{im}_T1w.nii.gz')\n", " imdata = nb.load(image_path).get_data()\n", "\n", " fig, ax = plt.subplots()\n", " plot_slice(imdata[..., z], annotate=True)\n", " fig.savefig(\n", - " op.join(outputs_path, 'figures', 'fig-06_sub-%s_slice-%03d.svg' % (im, z)),\n", + " op.join(outputs_path, 'figures', f'fig-06_sub-{im}_slice-{z:03}.svg'),\n", " dpi=300,\n", " bbox_inches='tight',\n", " )\n", diff --git a/docs/notebooks/Supplemental Materials.ipynb b/docs/notebooks/Supplemental Materials.ipynb index dc680d8d..5068aaa0 100644 --- a/docs/notebooks/Supplemental Materials.ipynb +++ b/docs/notebooks/Supplemental Materials.ipynb @@ -87,14 +87,14 @@ " out_file=op.join(outputs_path, 'figures', 'suppl-intrarv.pdf'),\n", ")\n", "\n", - "print(\"Cohen's Kappa %f\" % cohen_kappa_score(y1, y2))\n", + "print(f\"Cohen's Kappa {cohen_kappa_score(y1, y2):f}\")\n", "\n", "y1 = overlap.rater_2.values.ravel()\n", "y1[y1 == 0] = 1\n", "\n", "y2 = overlap.rater_3.values.ravel()\n", "y2[y2 == 0] = 1\n", - "print(\"Cohen's Kappa (binarized): %f\" % cohen_kappa_score(y1, y2))" + "print(f\"Cohen's Kappa (binarized): {cohen_kappa_score(y1, y2):f}\")" ] }, { diff --git a/mriqc/bin/fs2gif.py b/mriqc/bin/fs2gif.py index 762a13d8..18d5a712 100644 --- a/mriqc/bin/fs2gif.py +++ b/mriqc/bin/fs2gif.py @@ -125,8 +125,7 @@ def main(): with open(tcl_file, 'w') as tclfp: tclfp.write(tcl_contents) tclfp.write( - 'for { set slice %d } { $slice < %d } { incr slice } {' - % (bbox_min[2], bbox_max[2]) + f'for {{ set slice {bbox_min[2]} }} {{ $slice < {bbox_max[2]} }} {{ incr slice }} {{' ) tclfp.write(' SetSlice $slice\n') tclfp.write(' RedrawScreen\n') @@ -170,10 +169,9 @@ def main(): tclfp.write(tcl_contents) tclfp.write('SetZoomLevel 2') tclfp.write( - 'for { set slice %d } { $slice < %d } { incr slice } {' - % (bbox_min[2], bbox_max[2]) + 'for {{ set slice {bbox_min[2]} }} {{ $slice < {bbox_max[2]} }} {{ incr slice }} {{' ) - tclfp.write(' SetZoomCenter %d %d $slice\n' % (center[0] + 30, center[1] - 10)) + tclfp.write(f' SetZoomCenter {center[0] + 30} {center[1] - 10} $slice\n') tclfp.write(' SetSlice $slice\n') tclfp.write(' RedrawScreen\n') tclfp.write(f' SaveTIFF [format "{tmp_sub}/{subid}-lh-%03d.tif" $i]\n') @@ -195,10 +193,9 @@ def main(): tclfp.write(tcl_contents) tclfp.write('SetZoomLevel 2') tclfp.write( - 'for { set slice %d } { $slice < %d } { incr slice } {' - % (bbox_min[2], bbox_max[2]) + 'for {{ set slice {bbox_min[2]} }} {{ $slice < {bbox_max[2]} }} {{ incr slice }} {{' ) - tclfp.write(' SetZoomCenter %d %d $slice\n' % (center[0] - 30, center[1] - 10)) + tclfp.write(f' SetZoomCenter {center[0] - 30} {center[1] - 10} $slice\n') tclfp.write(' SetSlice $slice\n') tclfp.write(' RedrawScreen\n') tclfp.write(f' SaveTIFF [format "{tmp_sub}/{subid}-rh-%03d.tif" $slice]\n') diff --git a/mriqc/synthstrip/model.py b/mriqc/synthstrip/model.py index 3081d2d7..74eba9cf 100644 --- a/mriqc/synthstrip/model.py +++ b/mriqc/synthstrip/model.py @@ -89,7 +89,7 @@ def __init__( max_pool = [max_pool] * self.nb_levels # cache downsampling / upsampling operations - MaxPooling = getattr(nn, 'MaxPool%dd' % ndims) + MaxPooling = getattr(nn, f'MaxPool{ndims}d') self.pooling = [MaxPooling(s) for s in max_pool] self.upsampling = [nn.Upsample(scale_factor=s, mode='nearest') for s in max_pool] @@ -164,7 +164,7 @@ class ConvBlock(nn.Module): def __init__(self, ndims, in_channels, out_channels, stride=1, activation='leaky'): super().__init__() - Conv = getattr(nn, 'Conv%dd' % ndims) + Conv = getattr(nn, f'Conv{ndims}d') self.conv = Conv(in_channels, out_channels, 3, stride, 1) if activation == 'leaky': self.activation = nn.LeakyReLU(0.2) From 675996966762f6551bbbb3377fefcc8d604ecaaa Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:26:12 +0200 Subject: [PATCH 13/14] Apply ruff/pyupgrade rule UP035 UP035 Import from `collections.abc` instead --- mriqc/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mriqc/config.py b/mriqc/config.py index 898cf94a..c1aca569 100644 --- a/mriqc/config.py +++ b/mriqc/config.py @@ -93,10 +93,11 @@ import os import pickle import sys +from collections.abc import Iterable from contextlib import suppress from pathlib import Path from time import strftime -from typing import TYPE_CHECKING, Any, Iterable +from typing import TYPE_CHECKING, Any from uuid import uuid4 try: From 595401ed34164b4671d7426c10134839f8139adc Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:28:08 +0200 Subject: [PATCH 14/14] Apply ruff/flake8-import-conventions rule ICN001 ICN001 `seaborn` should be imported as `sns` --- docs/notebooks/Paper-v1.0.ipynb | 18 +++++++++--------- docs/notebooks/Paper-v2.0.ipynb | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/notebooks/Paper-v1.0.ipynb b/docs/notebooks/Paper-v1.0.ipynb index 955f09a8..ba0655d8 100644 --- a/docs/notebooks/Paper-v1.0.ipynb +++ b/docs/notebooks/Paper-v1.0.ipynb @@ -16,9 +16,9 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", - "import seaborn as sn\n", + "import seaborn as sns\n", "\n", - "sn.set(style='whitegrid')" + "sns.set(style='whitegrid')" ] }, { @@ -192,7 +192,7 @@ " ax = plt.gca()\n", "\n", " outer_score = data.loc[data[score].notnull(), [score, 'zscored']]\n", - " sn.distplot(\n", + " sns.distplot(\n", " outer_score.loc[outer_score.zscored == zscored, score],\n", " hist=True,\n", " norm_hist=True,\n", @@ -318,12 +318,12 @@ }, "outputs": [], "source": [ - "sn.set(style='whitegrid')\n", + "sns.set(style='whitegrid')\n", "\n", "fig = plt.figure(figsize=(20, 8))\n", "ax1 = plt.subplot2grid((2, 4), (0, 0), colspan=2, rowspan=2)\n", "\n", - "sn.violinplot(\n", + "sns.violinplot(\n", " x='Classifier',\n", " y='AUC',\n", " hue='Split scheme',\n", @@ -390,8 +390,8 @@ "outputs": [], "source": [ "zscoreddf = loso_outer.loc[loso_outer.zscored == 0, ['auc', 'acc', 'site']]\n", - "palette = sn.color_palette('cubehelix', len(set(zscoreddf.site)))\n", - "sn.pairplot(\n", + "palette = sns.color_palette('cubehelix', len(set(zscoreddf.site)))\n", + "sns.pairplot(\n", " zscoreddf.loc[zscoreddf.auc.notnull(), ['auc', 'acc', 'site']], hue='site', palette=palette\n", ")" ] @@ -405,12 +405,12 @@ "outputs": [], "source": [ "sites = sorted(set(loso_outer.site.ravel().tolist()))\n", - "palette = sn.color_palette('husl', len(sites))\n", + "palette = sns.color_palette('husl', len(sites))\n", "fig = plt.figure()\n", "for i, site in enumerate(sites):\n", " sitedf = loso_outer.loc[loso_outer.site == site]\n", " accdf = sitedf.loc[sitedf.zscored == 0]\n", - " sn.distplot(accdf.acc.values.ravel(), bins=20, kde=0, label=site, color=palette[i])\n", + " sns.distplot(accdf.acc.values.ravel(), bins=20, kde=0, label=site, color=palette[i])\n", "\n", "fig.gca().legend()\n", "fig.gca().set_xlim([0.5, 1.0])" diff --git a/docs/notebooks/Paper-v2.0.ipynb b/docs/notebooks/Paper-v2.0.ipynb index 8547cf67..0fb4f959 100644 --- a/docs/notebooks/Paper-v2.0.ipynb +++ b/docs/notebooks/Paper-v2.0.ipynb @@ -309,7 +309,7 @@ "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", - "import seaborn as sn\n", + "import seaborn as sns\n", "\n", "rfc_acc = [\n", " 0.842,\n", @@ -391,13 +391,13 @@ "\n", "fig = plt.figure(figsize=(10, 3))\n", "ax2 = plt.subplot2grid((1, 4), (0, 3))\n", - "plot = sn.violinplot(\n", + "plot = sns.violinplot(\n", " data=df, x='Model', y='accuracy', ax=ax2, palette=colors, bw=0.1, linewidth=0.7\n", ")\n", "for i in range(dim):\n", " ax2.axhline(np.average(allvals[i]), ls='--', color=colors[i], lw=0.8)\n", "# ax2.axhline(np.percentile(allvals[i], 50), ls='--', color=colors[i], lw=.8)\n", - "# sn.swarmplot(x=\"model\", y=\"accuracy\", data=df, color=\"w\", alpha=.5, ax=ax2);\n", + "# sns.swarmplot(x=\"model\", y=\"accuracy\", data=df, color=\"w\", alpha=.5, ax=ax2);\n", "ax2.yaxis.tick_right()\n", "ax2.set_ylabel('')\n", "ax2.set_xticklabels(ax2.get_xticklabels(), rotation=40)\n", @@ -506,7 +506,7 @@ "\n", "fig = plt.figure(figsize=(10, 3))\n", "ax2 = plt.subplot2grid((1, 4), (0, 3))\n", - "plot = sn.violinplot(data=df, x='Model', y='auc', ax=ax2, palette=colors, bw=0.1, linewidth=0.7)\n", + "plot = sns.violinplot(data=df, x='Model', y='auc', ax=ax2, palette=colors, bw=0.1, linewidth=0.7)\n", "for i in range(dim):\n", " ax2.axhline(np.average(allvals[i]), ls='--', color=colors[i], lw=0.8)\n", "\n", @@ -584,10 +584,10 @@ }, "outputs": [], "source": [ - "import seaborn as sn\n", + "import seaborn as sns\n", "from sklearn.externals.joblib import load as loadpkl\n", "\n", - "sn.set_style('white')\n", + "sns.set_style('white')\n", "\n", "# Get the RFC\n", "estimator = loadpkl(\n", @@ -666,7 +666,7 @@ " df['Importance'] += [tree.feature_importances_[i]]\n", "fig = plt.figure(figsize=(20, 6))\n", "# plt.title(\"Feature importance plot\")\n", - "sn.boxplot(x='Feature', y='Importance', data=pd.DataFrame(df), linewidth=1, notch=True)\n", + "sns.boxplot(x='Feature', y='Importance', data=pd.DataFrame(df), linewidth=1, notch=True)\n", "plt.xlabel(f'Features selected ({len(features)})')\n", "# plt.bar(range(nft), importances[indices],\n", "# color=\"r\", yerr=std[indices], align=\"center\")\n",