diff --git a/.flake8 b/.flake8
deleted file mode 100644
index db1a275..0000000
--- a/.flake8
+++ /dev/null
@@ -1,15 +0,0 @@
-[flake8]
-count = True
-show-source = True
-statistics = True
-exclude =
- *build
- .git
- __pycache__
- _version.py
-ignore = D100, D103, W503
-max-line-length = 90
-max_complexity = 15
-max_function_length = 150
-max_parameters_amount = 15
-max_returns_amount = 5
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 6891c9d..2336b9a 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,14 +3,25 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- - id: end-of-file-fixer
- - id: check-added-large-files
+ - id: check-ast
- id: check-case-conflict
- id: check-json
- id: check-merge-conflict
+ - id: check-toml
- id: check-yaml
- - id: debug-statements
+ - id: end-of-file-fixer
+ - id: mixed-line-ending
+ args: [--fix=lf]
- id: trailing-whitespace
+
+ # Checks for .rst files
+- repo: https://github.com/pre-commit/pygrep-hooks
+ rev: v1.10.0
+ hooks:
+ - id: rst-backticks
+ - id: rst-directive-colons
+ - id: rst-inline-touching-normal
+
- repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt
rev: 0.2.3
hooks:
@@ -22,6 +33,7 @@ repos:
- '4'
- --offset
- '0'
+
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.16.0
hooks:
@@ -30,35 +42,38 @@ repos:
- --autofix
- --indent
- '4'
+
- repo: https://github.com/asottile/pyupgrade
rev: v3.21.2
hooks:
- id: pyupgrade
args:
- --py38-plus
+
- repo: https://github.com/seddonym/import-linter
rev: v2.11
hooks:
- id: import-linter
-- repo: https://github.com/pycqa/isort
- rev: 8.0.1
- hooks:
- - id: isort
- args:
- - --settings-path
- - pyproject.toml
+ args: [--verbose]
+ language: python
+
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.20.0
hooks:
- id: blacken-docs
additional_dependencies:
- black==24.2.0
-- repo: https://github.com/psf/black-pre-commit-mirror
- rev: 26.3.0
+
+ # Lint and format Python code
+- repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.15.1
hooks:
- - id: black
- args:
- - --config=pyproject.toml
+ - id: ruff-check
+ # args: [--statistics]
+ args: [--fix, --show-fixes, --unsafe-fixes]
+ - id: ruff-format
+ # args: [--diff]
+
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1
hooks:
@@ -71,28 +86,14 @@ repos:
args:
- --config-file
- pyproject.toml
+
- repo: https://github.com/codespell-project/codespell
rev: v2.4.2
hooks:
- id: codespell
- args:
- - --toml=pyproject.toml
- additional_dependencies:
- - tomli
-- repo: https://github.com/pycqa/flake8
- rev: 7.3.0
- hooks:
- - id: flake8
- exclude: tests_.*.py|version.*.py|setup.py
- args:
- - --config
- - .flake8
- - --verbose
- additional_dependencies:
- - flake8-docstrings
- - flake8-use-fstring
- - flake8-functions
- - flake8-bugbear
+ args: [--toml=pyproject.toml]
+ additional_dependencies: [tomli]
+
ci:
autoupdate_commit_msg: 'chore: update pre-commit hooks'
autoupdate_schedule: monthly
diff --git a/bidsmreye/_parsers.py b/bidsmreye/_parsers.py
index d807161..a56793c 100644
--- a/bidsmreye/_parsers.py
+++ b/bidsmreye/_parsers.py
@@ -10,7 +10,7 @@
def _base_parser(formatter_class: type[HelpFormatter] = HelpFormatter) -> ArgumentParser:
parser = ArgumentParser(
description=(
- "BIDS app using deepMReye to decode " "eye motion for fMRI time series data."
+ "BIDS app using deepMReye to decode eye motion for fMRI time series data."
),
epilog="""
For a more readable version of this help section,
diff --git a/bidsmreye/bids_utils.py b/bidsmreye/bids_utils.py
index 782a71c..70cd13d 100644
--- a/bidsmreye/bids_utils.py
+++ b/bidsmreye/bids_utils.py
@@ -36,11 +36,8 @@ def check_layout(cfg: Config, layout: BIDSLayout, for_file: str = "bold") -> Non
:raises RuntimeError: _description_
"""
desc = layout.get_dataset_description()
- if (
- "DatasetType" not in desc
- and "PipelineDescription" not in desc
- or "DatasetType" in desc
- and desc["DatasetType"] != "derivative"
+ if ("DatasetType" not in desc and "PipelineDescription" not in desc) or (
+ "DatasetType" in desc and desc["DatasetType"] != "derivative"
):
raise RuntimeError(
"DatasetType must be 'derivative' in dataset_description.json\n."
diff --git a/bidsmreye/configuration.py b/bidsmreye/configuration.py
index 3f44ce7..cbf35c8 100644
--- a/bidsmreye/configuration.py
+++ b/bidsmreye/configuration.py
@@ -74,7 +74,7 @@ def __attrs_post_init__(self) -> None:
self.bids_filter = get_bids_filter_config()
self.output_dir = self.output_dir / "bidsmreye"
- if not self.output_dir:
+ if not self.output_dir.exists():
self.output_dir.mkdir(parents=True, exist_ok=True)
database_path = self.input_dir / "pybids_db"
@@ -136,7 +136,7 @@ def check_argument(self, attribute: str, layout_in: BIDSLayout) -> Config:
self.listify(attribute)
# convert all run values to integers
- if attribute in {"run"}:
+ if attribute == "run":
for i, j in enumerate(value):
value[i] = int(j)
tmp = [int(j) for j in getattr(self, attribute)]
@@ -155,7 +155,7 @@ def check_argument(self, attribute: str, layout_in: BIDSLayout) -> Config:
# run and space can be empty if their entity are not used
# we will figure out the values for run
# in subject / task wise manner later on
- if attribute not in ["run"]:
+ if attribute != "run":
setattr(self, attribute, value)
if attribute not in ["run", "space"] and not getattr(self, attribute):
@@ -236,7 +236,7 @@ def get_config(config_file: Path | None = None, default: str = "") -> dict[str,
my_path = Path(__file__).absolute().parent / "config"
config_file = my_path / default
- if config_file is None or not Path(config_file).exists():
+ if not Path(config_file).exists():
raise FileNotFoundError(f"Config file {config_file} not found")
with open(config_file) as ff:
diff --git a/bidsmreye/methods.py b/bidsmreye/methods.py
index fe9c7cb..61e6f14 100644
--- a/bidsmreye/methods.py
+++ b/bidsmreye/methods.py
@@ -29,7 +29,7 @@ def methods(
:rtype: Path
"""
if output_dir is None:
- output_dir = Path(".")
+ output_dir = Path()
if isinstance(output_dir, str):
output_dir = Path(output_dir)
output_dir = output_dir / "logs"
diff --git a/bidsmreye/quality_control.py b/bidsmreye/quality_control.py
index 18bb072..ac2d349 100644
--- a/bidsmreye/quality_control.py
+++ b/bidsmreye/quality_control.py
@@ -325,7 +325,7 @@ def compute_robust_outliers(
indices.pop(i)
tmp = time_series[indices]
- tmp.dropna(inplace=True)
+ tmp = tmp.dropna()
# median of all pair-wise distances
distance.append(np.median(abs(this_timepoint - tmp)))
diff --git a/bidsmreye/report.py b/bidsmreye/report.py
index 30576cf..7cd88b2 100644
--- a/bidsmreye/report.py
+++ b/bidsmreye/report.py
@@ -66,7 +66,6 @@ def generate_report(output_dir: Path, subject_label: str, action: str) -> None:
if __name__ == "__main__":
-
cwd = Path("/home/remi/github/cpp-lln-lab/bidsMReye")
output_dir = cwd / "outputs" / "moae_fmriprep" / "derivatives" / "bidsmreye"
diff --git a/bidsmreye/visualize.py b/bidsmreye/visualize.py
index 23797ca..6c1e63e 100644
--- a/bidsmreye/visualize.py
+++ b/bidsmreye/visualize.py
@@ -17,14 +17,14 @@
from bidsmreye.utils import check_if_file_found, set_this_filter
LINE_WIDTH = 3
-FONT_SIZE = dict(size=14)
+FONT_SIZE = {"size": 14}
GRID_COLOR = "grey"
LINE_COLOR = "rgb(0, 150, 175)"
BG_COLOR = "rgb(255,255,255)"
HEAT_MAP_COLOR = "gnbu"
MARKER_SIZE = 10
-TICK_FONT = dict(family="arial", color="black", size=14)
+TICK_FONT = {"family": "arial", "color": "black", "size": 14}
X_POSITION_1 = 1
X_POSITION_2 = 1.5
@@ -113,7 +113,7 @@ def plot_group_boxplot(
go.Box(
x=np.ones(nb_data_points) * X_POSITION[i],
y=qc_data[this_column],
- marker=dict(size=MARKER_SIZE, color=COLORS[i]),
+ marker={"size": MARKER_SIZE, "color": COLORS[i]},
name=trace_names[i],
),
row=row,
@@ -128,7 +128,7 @@ def plot_group_boxplot(
fig.update_yaxes(
row=row,
col=col,
- title=dict(text=yaxes_title, font=FONT_SIZE),
+ title={"text": yaxes_title, "font": FONT_SIZE},
)
@@ -186,7 +186,7 @@ def group_report(cfg: Config) -> None:
)
fig.update_yaxes(
- title=dict(standoff=0, font=FONT_SIZE),
+ title={"standoff": 0, "font": FONT_SIZE},
showline=True,
linewidth=LINE_WIDTH - 1,
linecolor="black",
@@ -215,9 +215,9 @@ def group_report(cfg: Config) -> None:
boxmean=True,
width=0.2,
hovertext=qc_data["filename"],
- marker=dict(size=MARKER_SIZE),
+ marker={"size": MARKER_SIZE},
fillcolor="rgb(200, 200, 200)",
- line=dict(color="black"),
+ line={"color": "black"},
)
fig.update_layout(
@@ -226,17 +226,17 @@ def group_report(cfg: Config) -> None:
paper_bgcolor=BG_COLOR,
height=800,
width=800,
- title=dict(
- text=f"""bidsmreye: group report
+ title={
+ "text": f"""bidsmreye: group report
Summary
- Date and time: {datetime.now():%Y-%m-%d, %H:%M}
- bidsmreye version: {__version__}
""",
- x=0.05,
- y=0.95,
- font=dict(size=19, color="black"),
- ),
- margin=dict(t=150, b=10, l=100, r=10, pad=0),
+ "x": 0.05,
+ "y": 0.95,
+ "font": {"size": 19, "color": "black"},
+ },
+ margin={"t": 150, "b": 10, "l": 100, "r": 10, "pad": 0},
)
fig.show()
@@ -288,7 +288,7 @@ def visualize_eye_gaze_data(
fig.update_xaxes(
row=3,
col=1,
- title=dict(text="Time (s)", standoff=16, font=FONT_SIZE),
+ title={"text": "Time (s)", "standoff": 16, "font": FONT_SIZE},
tickfont=TICK_FONT,
)
@@ -376,7 +376,7 @@ def plot_time_series(
griddash="dot",
gridwidth=0.5,
ticksuffix="°",
- title=dict(text=title_text, standoff=0, font=FONT_SIZE),
+ title={"text": title_text, "standoff": 0, "font": FONT_SIZE},
tickfont=FONT_SIZE,
)
@@ -428,7 +428,7 @@ def plot_heat_map(fig: Any, eye_gaze_data: pd.DataFrame) -> None:
x=X,
y=Y,
opacity=0.4,
- line=dict(color="black", width=1, dash="dash"),
+ line={"color": "black", "width": 1, "dash": "dash"},
),
row=1,
col=3,
@@ -448,7 +448,7 @@ def plot_heat_map(fig: Any, eye_gaze_data: pd.DataFrame) -> None:
col=3,
range=value_range(X),
ticksuffix="°",
- title=dict(text="X", standoff=16, font=FONT_SIZE),
+ title={"text": "X", "standoff": 16, "font": FONT_SIZE},
tickfont=TICK_FONT,
)
fig.update_yaxes(
@@ -456,7 +456,7 @@ def plot_heat_map(fig: Any, eye_gaze_data: pd.DataFrame) -> None:
col=3,
range=value_range(Y),
ticksuffix="°",
- title=dict(text="Y", standoff=16, font=FONT_SIZE),
+ title={"text": "Y", "standoff": 16, "font": FONT_SIZE},
tickfont=TICK_FONT,
)
diff --git a/pyproject.toml b/pyproject.toml
index 809296c..b06e3bb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -113,22 +113,18 @@ layers = [
name = "Layered architecture"
type = "layers"
-[tool.isort]
-combine_as_imports = true
-line_length = 90
-profile = "black"
-skip_gitignore = true
-
[tool.mypy]
check_untyped_defs = true
disallow_any_generics = true
disallow_incomplete_defs = false
disallow_untyped_defs = false
-# enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
+enable_error_code = ["redundant-expr", "truthy-bool"]
+# enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] # TODO
exclude = ['tests/']
no_implicit_optional = true
plugins = ["numpy.typing.mypy_plugin", "pydantic.mypy"]
warn_redundant_casts = true
+# warn_unreachable = true # TODO
warn_unused_ignores = true
[[tool.mypy.overrides]]
@@ -163,6 +159,109 @@ addopts = "-ra --cov bidsmreye --strict-config --strict-markers --doctest-module
doctest_optionflags = "NORMALIZE_WHITESPACE ELLIPSIS"
junit_family = "xunit2"
log_cli_level = "INFO"
+log_level = "INFO"
minversion = "6.0"
testpaths = ["tests"]
xfail_strict = true
+
+[tool.ruff]
+extend-exclude = ["bidsmreye/_version.py"]
+include = [
+ "pyproject.toml",
+ "bidsmreye/**/*.py",
+ "tools/**/*.py",
+ "doc/**/*.py"
+]
+indent-width = 4
+line-length = 90
+
+[tool.ruff.format]
+docstring-code-format = true
+docstring-code-line-length = "dynamic"
+indent-style = "space"
+line-ending = "auto"
+quote-style = "double"
+skip-magic-trailing-comma = false
+
+[tool.ruff.lint]
+dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+fixable = ["ALL"]
+ignore = [
+ "ARG001",
+ "ARG002",
+ "ERA001",
+ "D100",
+ "D103",
+ "D203",
+ "D213",
+ "N802",
+ "N803",
+ "N806",
+ "N816",
+ "N815",
+ "PLR2004",
+ "PD003",
+ "PGH003",
+ "PTH100",
+ "PTH107",
+ "PTH103",
+ "PTH123",
+ "SIM115",
+ "NPY002",
+ # Avoid linter rules conflicting with the formatter
+ # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
+ "COM812",
+ "COM819",
+ "E111",
+ "E114",
+ "E117",
+ "Q000",
+ "Q001",
+ "Q002",
+ "Q003",
+ "W191"
+]
+# List of all the ruff rules (includes why the rule matters)
+# https://docs.astral.sh/ruff/rules/
+select = [
+ "ARG",
+ "B",
+ "C4",
+ "C90",
+ "D",
+ "E",
+ "ERA",
+ "F",
+ "FLY",
+ "FURB",
+ "I",
+ "N",
+ "NPY",
+ "PERF",
+ "PIE",
+ "PTH",
+ "PD",
+ "PGH",
+ "PLR",
+ "RUF",
+ "SIM",
+ "UP",
+ "W"
+]
+unfixable = []
+
+[tool.ruff.lint.mccabe]
+max-complexity = 15
+
+[tool.ruff.lint.per-file-ignores]
+"__init__.py" = ["D104"]
+
+[tool.ruff.lint.pylint]
+# https://docs.astral.sh/ruff/settings/#lint_pylint_max-args
+max-args = 15
+# https://docs.astral.sh/ruff/settings/#lint_pylint_max-branches
+max-branches = 10
+# https://docs.astral.sh/ruff/settings/#lint_pylint_max-returns
+max-returns = 6
+# https://docs.astral.sh/ruff/settings/#lint_pylint_max-statements
+max-statements = 80