From a96a626fcd68cd5cf860378416b9c3d5f68c1944 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 7 Apr 2025 18:11:16 +0000
Subject: [PATCH 01/16] :technologist: pre-commit autoupdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.9.9 → v0.11.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.9.9...v0.11.4)
---
.pre-commit-config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7691af305..a71419e89 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -60,7 +60,7 @@ repos:
- id: rst-inline-touching-normal # Detect mistake of inline code touching normal text in rst.
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
- rev: v0.9.9
+ rev: v0.11.4
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
From 410bf4e38bfd3bb655b4e76a95bdcfdc226d1a50 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 7 Apr 2025 18:11:46 +0000
Subject: [PATCH 02/16] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
benchmarks/annotation_store.ipynb | 2 +-
tiatoolbox/annotation/storage.py | 35 ++++++++++---------
tiatoolbox/models/architecture/utils.py | 2 +-
tiatoolbox/models/engine/patch_predictor.py | 2 +-
.../models/engine/semantic_segmentor.py | 2 +-
tiatoolbox/tools/graph.py | 2 +-
tiatoolbox/tools/stainaugment.py | 2 +-
tiatoolbox/utils/visualization.py | 2 +-
8 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/benchmarks/annotation_store.ipynb b/benchmarks/annotation_store.ipynb
index b3ba543f8..6cf6cf8e6 100644
--- a/benchmarks/annotation_store.ipynb
+++ b/benchmarks/annotation_store.ipynb
@@ -2417,7 +2417,7 @@
" return_counts=True,\n",
" )\n",
" total = np.sum(counts)\n",
- " frequencies = {v: 0 for v in range(256)}\n",
+ " frequencies = dict.fromkeys(range(256), 0)\n",
" for v, x in zip(values, counts):\n",
" frequencies[v] = x / total\n",
" frequency_array = np.array(list(frequencies.values()))\n",
diff --git a/tiatoolbox/annotation/storage.py b/tiatoolbox/annotation/storage.py
index c129842e1..f7dbb5da3 100644
--- a/tiatoolbox/annotation/storage.py
+++ b/tiatoolbox/annotation/storage.py
@@ -72,6 +72,7 @@
from shapely.geometry import LineString, Point, Polygon
from shapely.geometry import mapping as geometry2feature
from shapely.geometry import shape as feature2geometry
+from typing_extensions import Self
import tiatoolbox
from tiatoolbox import DuplicateFilter, logger
@@ -441,10 +442,10 @@ class AnnotationStore(ABC, MutableMapping[str, Annotation]):
"""Annotation store abstract base class."""
def __new__(
- cls: type[StoreInstanceType],
+ cls,
*args: str, # noqa: ARG004
**kwargs: int, # noqa: ARG004
- ) -> StoreInstanceType:
+ ) -> Self:
"""Return an instance of a subclass of AnnotationStore."""
if cls is AnnotationStore:
msg = (
@@ -814,7 +815,7 @@ def patch_many(
geometries = geometries or (None for _ in keys) # pragma: no branch
# Update the store
for key, geometry, properties in zip(keys, geometries, properties_iter):
- properties_ = cast(dict[str, Any], copy.deepcopy(properties))
+ properties_ = cast("dict[str, Any]", copy.deepcopy(properties))
self.patch(key, geometry, properties_)
def remove(self: AnnotationStore, key: str) -> None:
@@ -949,7 +950,7 @@ def _eval_where(
predicate = pickle.loads(predicate) # skipcq: BAN-B301 # noqa: S301
# predicate is Callable
- predicate = cast(Callable, predicate)
+ predicate = cast("Callable", predicate)
return bool(predicate(properties))
@staticmethod
@@ -1719,7 +1720,7 @@ def nquery(
geometry_predicate = "centers_within_k"
elif from_mode == "poly": # pragma: no branch
geometry = ann.geometry
- geometry = cast(Geometry, geometry)
+ geometry = cast("Geometry", geometry)
geometry = geometry.buffer(distance)
subquery_result = self.query(
geometry=geometry,
@@ -1842,7 +1843,7 @@ def _dump_cases(
if fp is not None:
# It is a file-like object, write to it
if hasattr(fp, "write"):
- file_handle = cast(IO, fp)
+ file_handle = cast("IO", fp)
return file_fn(file_handle) # type: ignore[func-returns-value]
# Turn a path into a file handle, then write to it
with Path(fp).open("w", encoding="utf-8") as file_handle:
@@ -1864,7 +1865,7 @@ def _load_cases(
if isinstance(fp, (str, bytes)):
return string_fn(fp)
if hasattr(fp, "read"):
- file_io = cast(IO, fp)
+ file_io = cast("IO", fp)
return file_fn(file_io)
msg = "Invalid file handle or path."
raise OSError(msg)
@@ -1979,7 +1980,7 @@ def transform_geometry(geom: Geometry) -> Geometry:
string_fn=json.loads,
file_fn=json.load,
)
- geojson = cast(dict, geojson)
+ geojson = cast("dict", geojson)
annotations = [
transform(
@@ -2044,7 +2045,7 @@ def write_geojson_to_file_handle(file_handle: IO) -> None:
none_fn=lambda: json.dumps(self.to_geodict()),
)
if result is not None:
- return cast(str, result)
+ return cast("str", result)
return result
@overload
@@ -2108,7 +2109,7 @@ def to_ndjson(
none_fn=lambda: "".join(string_lines_generator),
)
if result is not None:
- return cast(str, result)
+ return cast("str", result)
return result
@classmethod
@@ -2148,7 +2149,7 @@ def from_ndjson(cls: type[AnnotationStore], fp: Path | IO | str) -> AnnotationSt
string_fn=lambda fp: fp.splitlines(),
file_fn=lambda fp: fp.readlines(),
)
- cases = cast(list, cases)
+ cases = cast("list", cases)
for line in cases:
dictionary = json.loads(line)
key = dictionary.get("key", uuid.uuid4().hex)
@@ -3442,7 +3443,7 @@ def pquery(
if not unique:
return_columns.append("[key]")
if is_str_query and not is_star_query:
- select = cast(str, select)
+ select = cast("str", select)
select_names = eval( # skipcq: PYL-W0123, # noqa: S307
select,
SQL_GLOBALS,
@@ -3466,8 +3467,8 @@ def pquery(
if is_pickle_query or is_callable_query:
# Where to apply after database query
# only done for Callable where.
- post_where = cast(CallablePredicate, where) if is_callable_query else None
- select = cast(CallableSelect, select)
+ post_where = cast("CallablePredicate", where) if is_callable_query else None
+ select = cast("CallableSelect", select)
result = self._handle_pickle_callable_pquery(
select,
post_where,
@@ -3482,7 +3483,7 @@ def pquery(
)
if unique and squeeze and len(result) == 1:
- result = cast(list[set], result)
+ result = cast("list[set]", result)
return result[0]
return result
@@ -3814,7 +3815,7 @@ def dump(self: SQLiteStore, fp: Path | str | IO) -> None:
"""
if hasattr(fp, "write"):
- fp = cast(IO, fp)
+ fp = cast("IO", fp)
fp = fp.name
target = sqlite3.connect(fp)
self.con.backup(target)
@@ -3940,7 +3941,7 @@ def __init__(
string_fn=lambda fp: fp.splitlines(),
file_fn=lambda fp: fp.readlines(),
)
- cases = cast(list, cases)
+ cases = cast("list", cases)
for line in cases:
dictionary = json.loads(line)
key = dictionary.get("key", uuid.uuid4().hex)
diff --git a/tiatoolbox/models/architecture/utils.py b/tiatoolbox/models/architecture/utils.py
index 59378383d..bfd759b3a 100644
--- a/tiatoolbox/models/architecture/utils.py
+++ b/tiatoolbox/models/architecture/utils.py
@@ -98,7 +98,7 @@ def compile_model(
)
return model
- return cast(nn.Module, torch.compile(model, mode=mode)) # pragma: no cover
+ return cast("nn.Module", torch.compile(model, mode=mode)) # pragma: no cover
def centre_crop(
diff --git a/tiatoolbox/models/engine/patch_predictor.py b/tiatoolbox/models/engine/patch_predictor.py
index 088f78687..76d3d3bd6 100644
--- a/tiatoolbox/models/engine/patch_predictor.py
+++ b/tiatoolbox/models/engine/patch_predictor.py
@@ -426,7 +426,7 @@ def _predict_engine(
if self.verbose:
pbar = tqdm.tqdm(
- total=int(len(dataloader)),
+ total=len(dataloader),
leave=True,
ncols=80,
ascii=True,
diff --git a/tiatoolbox/models/engine/semantic_segmentor.py b/tiatoolbox/models/engine/semantic_segmentor.py
index 791f369f7..fe0c3e02b 100644
--- a/tiatoolbox/models/engine/semantic_segmentor.py
+++ b/tiatoolbox/models/engine/semantic_segmentor.py
@@ -799,7 +799,7 @@ def _predict_one_wsi(
pbar = tqdm.tqdm(
desc=pbar_desc,
leave=True,
- total=int(len(self._loader)),
+ total=len(self._loader),
ncols=80,
ascii=True,
position=0,
diff --git a/tiatoolbox/tools/graph.py b/tiatoolbox/tools/graph.py
index 25a97784b..1f812333d 100644
--- a/tiatoolbox/tools/graph.py
+++ b/tiatoolbox/tools/graph.py
@@ -408,7 +408,7 @@ def build(
dthresh=connectivity_distance,
)
edge_index = affinity_to_edge_index(adjacency_matrix)
- edge_index = cast(np.ndarray, edge_index)
+ edge_index = cast("np.ndarray", edge_index)
return {
"x": feature_centroids_arr,
"edge_index": edge_index,
diff --git a/tiatoolbox/tools/stainaugment.py b/tiatoolbox/tools/stainaugment.py
index 68df53295..2248a82ac 100644
--- a/tiatoolbox/tools/stainaugment.py
+++ b/tiatoolbox/tools/stainaugment.py
@@ -197,7 +197,7 @@ def augment(self: StainAugmentor) -> np.ndarray:
else:
augmented_concentrations[self.tissue_mask, i] *= self.alpha
augmented_concentrations[self.tissue_mask, i] += self.beta
- self.stain_matrix = cast(np.ndarray, self.stain_matrix)
+ self.stain_matrix = cast("np.ndarray", self.stain_matrix)
img_augmented = 255 * np.exp(
-1 * np.dot(augmented_concentrations, self.stain_matrix),
)
diff --git a/tiatoolbox/utils/visualization.py b/tiatoolbox/utils/visualization.py
index 4aa0746b8..74a89242c 100644
--- a/tiatoolbox/utils/visualization.py
+++ b/tiatoolbox/utils/visualization.py
@@ -732,7 +732,7 @@ def get_color(
# use colors directly specified in annotation properties
rgb = []
for c in annotation.properties["color"]: # type: ignore[union-attr]
- c = cast(int, c)
+ c = cast("int", c)
rgb.append(int(255 * c))
# rgb = [int(255 * c) for cast(int,c) in annotation.properties["color"]]
return (*rgb, 255)
From 5d6d991f5efb0e9361eb89b355101741ceec5959 Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 10:10:03 +0100
Subject: [PATCH 03/16] :pushpin: Update `ruff` version to `0.11.4`
---
.github/workflows/python-package.yml | 2 +-
requirements/requirements_dev.txt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml
index a6bf3b6c1..5fcbe3905 100644
--- a/.github/workflows/python-package.yml
+++ b/.github/workflows/python-package.yml
@@ -30,7 +30,7 @@ jobs:
sudo apt update
sudo apt-get install -y libopenslide-dev openslide-tools libopenjp2-7 libopenjp2-tools
python -m pip install --upgrade pip
- python -m pip install ruff==0.9.9 pytest pytest-cov pytest-runner
+ python -m pip install ruff==0.11.4 pytest pytest-cov pytest-runner
pip install -r requirements/requirements.txt
- name: Cache tiatoolbox static assets
uses: actions/cache@v3
diff --git a/requirements/requirements_dev.txt b/requirements/requirements_dev.txt
index 2e89d1c26..3022eed12 100644
--- a/requirements/requirements_dev.txt
+++ b/requirements/requirements_dev.txt
@@ -10,7 +10,7 @@ pytest>=7.2.0
pytest-cov>=4.0.0
pytest-runner>=6.0
pytest-xdist[psutil]
-ruff==0.9.9 # This will be updated by pre-commit bot to latest version
+ruff==0.11.4 # This will be updated by pre-commit bot to latest version
toml>=0.10.2
twine>=4.0.1
wheel>=0.37.1
From e95c53bdfbd5f408716902fb47dd9ee2166e1306 Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 10:19:04 +0100
Subject: [PATCH 04/16] :bug: Fix `ruff` errors
---
tiatoolbox/wsicore/wsireader.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tiatoolbox/wsicore/wsireader.py b/tiatoolbox/wsicore/wsireader.py
index 4557b7226..0e9224045 100644
--- a/tiatoolbox/wsicore/wsireader.py
+++ b/tiatoolbox/wsicore/wsireader.py
@@ -1627,8 +1627,8 @@ def save_tiles(
output_dir.mkdir(parents=True)
data = []
- vertical_tiles = int(math.ceil((slide_h - tile_h) / tile_h + 1))
- horizontal_tiles = int(math.ceil((slide_w - tile_w) / tile_w + 1))
+ vertical_tiles = int(math.ceil((slide_h - tile_h) / tile_h + 1)) # noqa: RUF046
+ horizontal_tiles = int(math.ceil((slide_w - tile_w) / tile_w + 1)) # noqa: RUF046
for iter_tot, (h, w) in enumerate(np.ndindex(vertical_tiles, horizontal_tiles)):
start_h = h * tile_h
end_h = (h * tile_h) + tile_h
From f9ac227bcfa7dec9b8cf5ce391cc9bdcdfd85306 Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 10:23:27 +0100
Subject: [PATCH 05/16] :bug: Fix `ruff` errors
---
tiatoolbox/utils/env_detection.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tiatoolbox/utils/env_detection.py b/tiatoolbox/utils/env_detection.py
index cdda60fcc..8605af745 100644
--- a/tiatoolbox/utils/env_detection.py
+++ b/tiatoolbox/utils/env_detection.py
@@ -210,7 +210,7 @@ def colab_has_gpu() -> bool:
False otherwise.
"""
- return bool(int(os.environ.get("COLAB_GPU", 0)))
+ return bool(int(os.environ.get("COLAB_GPU", 0))) # noqa: PLW1508
def has_network(
From e139a5632794d2774b686e2e928f4b3b96fc7b04 Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 10:24:53 +0100
Subject: [PATCH 06/16] :bug: Fix `ruff` errors
---
tiatoolbox/annotation/storage.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tiatoolbox/annotation/storage.py b/tiatoolbox/annotation/storage.py
index f7dbb5da3..eed3ee05a 100644
--- a/tiatoolbox/annotation/storage.py
+++ b/tiatoolbox/annotation/storage.py
@@ -84,10 +84,12 @@
py_regexp,
)
from tiatoolbox.enums import GeometryType
-from tiatoolbox.type_hints import CallablePredicate, CallableSelect, Geometry
if TYPE_CHECKING: # pragma: no cover
from tiatoolbox.type_hints import (
+ CallablePredicate,
+ CallableSelect,
+ Geometry,
Predicate,
Properties,
QueryGeometry,
From 5ec971d249260ce39d90c18ea795e77919c35a81 Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 10:26:27 +0100
Subject: [PATCH 07/16] :bug: Fix `ruff` errors
---
tests/test_utils.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index d84aba0b0..718111f7a 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -3,7 +3,6 @@
from __future__ import annotations
import hashlib
-import os
import shutil
from pathlib import Path
from typing import TYPE_CHECKING, NoReturn
@@ -1056,7 +1055,7 @@ def test_download_unzip_data(tmp_path: Path) -> None:
extracted_path = save_dir_path / "test_directory"
# to avoid hidden files in case of MAC-OS or Windows (?)
- extracted_dirs = [f for f in os.listdir(extracted_path) if not f.startswith(".")]
+ extracted_dirs = [f for f in Path.iterdir(extracted_path) if not f.startswith(".")]
extracted_dirs.sort() # ensure same ordering
assert extracted_dirs == ["dir1", "dir2", "dir3"]
From 17e1b2fb4f25da911e2755d04edc2ac010eed72c Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 10:26:42 +0100
Subject: [PATCH 08/16] :bug: Fix `ruff` errors
---
docs/conf.py | 42 +++++++++++++++++-------------------------
1 file changed, 17 insertions(+), 25 deletions(-)
diff --git a/docs/conf.py b/docs/conf.py
index a16b690a8..6ccda24ec 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# flake8: noqa
#
# tiatoolbox documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 9 13:47:02 2017.
@@ -19,9 +18,9 @@
# absolute, like shown here.
#
import os
-from pathlib import Path
import shutil
import sys
+from pathlib import Path
sys.path.insert(0, os.path.abspath(".."))
@@ -84,7 +83,7 @@
# General information about the project.
project = "TIA Toolbox"
-copyright = "2025, TIA Lab"
+copyright = "2025, TIA Lab" # noqa: A001
author = "TIA Lab"
# The version info for the project you're documenting, acts as replacement
@@ -140,9 +139,11 @@
"name": "TIA",
"url": "https://warwick.ac.uk/fac/cross_fac/tia/",
"html": """
-
""",
"class": "only-light",
@@ -1901,8 +1908,7 @@
html_static_path = []
# These paths are either relative to html_static_path
-# or fully qualified paths (eg. https://...)
-# html_css_files = []
+# or fully qualified paths (e.g., https://...)
# -- Options for HTMLHelp output ---------------------------------------
@@ -1963,15 +1969,6 @@
"Sphinx": ("https://www.sphinx-doc.org/en/stable/", None),
}
-# create latex preamble so that we can build arbitrary nested depth
-fh = open("latex_preamble.tex", "r+")
-PREAMBLE = fh.read()
-fh.close()
-latex_elements = {
- # Additional stuff for the LaTeX preamble.
- "preamble": PREAMBLE,
-}
-
# -- Options for autodoc -----------------------------------------------
autodoc_typehints = "description"
@@ -1980,9 +1977,9 @@
"ArrayLike": "ArrayLike",
}
-print("=" * 43)
+print("=" * 43) # noqa: T201
print("Copy example notebooks into docs/_notebooks")
-print("=" * 43)
+print("=" * 43) # noqa: T201
def all_but_ipynb(dir_path, contents):
@@ -2004,13 +2001,8 @@ def all_but_ipynb(dir_path, contents):
ignore=all_but_ipynb,
)
-# shutil.copy(
-# os.path.join(PROJ_ROOT, "docs/usage_examples.rst"),
-# os.path.join(PROJ_ROOT, "docs/_notebooks/usage_examples.rst"),
-# )
-
# Read in the file
-with open("../examples/README.md", "r") as file:
+with open("../examples/README.md") as file:
file_data = file.read()
# Replace the target string
From 4d9f7933e29564432ff21145bef57fd0a7d442ab Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 11:41:28 +0100
Subject: [PATCH 09/16] :bug: Fix `ruff` errors
---
docs/conf.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/conf.py b/docs/conf.py
index 6ccda24ec..2eaf8f94a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+"""Defines configuration for sphinx and readthedocs."""
#
# tiatoolbox documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 9 13:47:02 2017.
@@ -22,7 +23,7 @@
import sys
from pathlib import Path
-sys.path.insert(0, os.path.abspath(".."))
+sys.path.insert(0, str(Path("..").resolve()))
import tiatoolbox
From 57398be5b2622e747e8f0ac4055f6521a9577539 Mon Sep 17 00:00:00 2001
From: Shan E Ahmed Raza <13048456+shaneahmed@users.noreply.github.com>
Date: Wed, 9 Apr 2025 14:29:10 +0100
Subject: [PATCH 10/16] :bug: Fix `ruff` errors
---
docs/conf.py | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/docs/conf.py b/docs/conf.py
index 2eaf8f94a..f79a12f5d 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,5 +1,8 @@
#!/usr/bin/env python
"""Defines configuration for sphinx and readthedocs."""
+
+from __future__ import annotations
+
#
# tiatoolbox documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 9 13:47:02 2017.
@@ -12,7 +15,6 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
-
# If extensions (or modules to document with autodoc) are in another
# directory, add these directories to sys.path here. If the directory is
# relative to the documentation root, use os.path.abspath to make it
@@ -142,7 +144,7 @@
"html": """