diff --git a/.copier-answers.yml b/.copier-answers.yml
index c30101c87e27c5e06a154a98d8d1993d67dd844d..22a774e57e214cfdd89c69c4a7696f24a49a0539 100644
--- a/.copier-answers.yml
+++ b/.copier-answers.yml
@@ -1,5 +1,5 @@
 # Changes here will be overwritten by Copier
-_commit: v0.2.3
+_commit: v0.3.3
 _src_path: https://gitlab.softwareheritage.org/swh/devel/swh-py-template.git
 description: Software Heritage core utilities
 distribution_name: swh-core
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9f008d1f16c6454506809d2bc9540626a8d09904..813eeab43cdab98072e890c913b4bfb1e46cf9f0 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,18 +1,18 @@
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.6.0
+    rev: v5.0.0
     hooks:
       - id: trailing-whitespace
       - id: check-json
       - id: check-yaml
 
   - repo: https://github.com/python/black
-    rev: 24.8.0
+    rev: 25.1.0
     hooks:
       - id: black
 
   - repo: https://github.com/PyCQA/isort
-    rev: 5.13.2
+    rev: 6.0.0
     hooks:
       - id: isort
 
@@ -20,15 +20,15 @@ repos:
     rev: 7.1.1
     hooks:
       - id: flake8
-        additional_dependencies: [flake8-bugbear==24.4.26]
+        additional_dependencies: [flake8-bugbear==24.12.12, flake8-pyproject]
 
   - repo: https://github.com/codespell-project/codespell
-    rev: v2.3.0
+    rev: v2.4.1
     hooks:
       - id: codespell
         name: Check source code spelling
         args: [-L crate]
-        stages: [commit]
+        stages: [pre-commit]
       - id: codespell
         name: Check commit message spelling
         stages: [commit-msg]
diff --git a/mypy.ini b/mypy.ini
deleted file mode 100644
index 7b2d088e989d6e188fb7746294c4dd5c70a07164..0000000000000000000000000000000000000000
--- a/mypy.ini
+++ /dev/null
@@ -1,50 +0,0 @@
-[mypy]
-namespace_packages = True
-warn_unused_ignores = True
-explicit_package_bases = True
-# ^ Needed for mypy to detect py.typed from swh packages installed
-# in editable mode
-
-# 3rd party libraries without stubs (yet)
-
-[mypy-aiohttp_utils.*]
-ignore_missing_imports = True
-
-[mypy-arrow.*]
-ignore_missing_imports = True
-
-[mypy-backports.entry_points_selectable.*]
-ignore_missing_imports = True
-
-[mypy-celery.*]
-ignore_missing_imports = True
-
-[mypy-decorator.*]
-ignore_missing_imports = True
-
-[mypy-deprecated.*]
-ignore_missing_imports = True
-
-[mypy-django.*]  # false positive, only used by hypotesis' extras
-ignore_missing_imports = True
-
-[mypy-iso8601.*]
-ignore_missing_imports = True
-
-[mypy-magic.*]
-ignore_missing_imports = True
-
-[mypy-msgpack.*]
-ignore_missing_imports = True
-
-[mypy-pytest_postgresql.*]
-ignore_missing_imports = True
-
-[mypy-requests_mock.*]
-ignore_missing_imports = True
-
-[mypy-systemd.*]
-ignore_missing_imports = True
-
-# [mypy-add_your_lib_here.*]
-# ignore_missing_imports = True
diff --git a/pyproject.toml b/pyproject.toml
index f81566cc8af50ff77370495243b4b5fd4deb0668..952392d9cc6402d1ba7f8a0eda1a298b68096ccf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -71,3 +71,38 @@ ensure_newline_before_comments = true
 line_length = 88
 force_sort_within_sections = true
 known_first_party = ['swh']
+
+[tool.mypy]
+namespace_packages = true
+warn_unused_ignores = true
+explicit_package_bases = true
+# ^ Needed for mypy to detect py.typed from swh packages installed
+# in editable mode
+
+plugins = []
+
+# 3rd party libraries without stubs (yet)
+[[tool.mypy.overrides]]
+module = [
+    "aiohttp_utils.*",
+    "backports.entry_points_selectable.*",
+    "systemd.*",
+]
+ignore_missing_imports = true
+
+[tool.flake8]
+select = ["C", "E", "F", "W", "B950"]
+ignore = [
+    "E203", # whitespaces before ':' <https://github.com/psf/black/issues/315>
+    "E231", # missing whitespace after ','
+    "E501", # line too long, use B950 warning from flake8-bugbear instead
+    "W503" # line break before binary operator <https://github.com/psf/black/issues/52>
+]
+max-line-length = 88
+extend-exclude = ".git,.tox,.mypy_cache,build,dist"
+
+
+[tool.pytest.ini_options]
+norecursedirs = "build docs .*"
+asyncio_mode = "strict"
+consider_namespace_packages = true
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index 28882a78220a28f8ba8e48ad673f7f67d88b1aec..0000000000000000000000000000000000000000
--- a/pytest.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[pytest]
-norecursedirs = build docs .*
-asyncio_mode = strict
-consider_namespace_packages = true
-filterwarnings =
-  ignore:.*uses the 'db_with_data' fixture
diff --git a/requirements-test.txt b/requirements-test.txt
index c1eea4bda4d2c2e4925a7f524f4aebcce7c9fd74..48581180954fb6a0878b445443dcbeb07a9e6e03 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,4 +1,6 @@
+celery-types
 hypothesis >= 3.11.0
+msgpack-types
 pytest >= 8.1
 pytest-mock
 pytest-postgresql > 5
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 018b9b185e37643f79b0a0c0cefb1e4cfb7adecf..0000000000000000000000000000000000000000
--- a/setup.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-[flake8]
-# E203: whitespaces before ':' <https://github.com/psf/black/issues/315>
-# E231: missing whitespace after ','
-# E501: line too long, use B950 warning from flake8-bugbear instead
-# W503: line break before binary operator <https://github.com/psf/black/issues/52>
-select = C,E,F,W,B950
-ignore = E203,E231,E501,E704,W503
-max-line-length = 88
-extend-exclude = .git,.tox,.mypy_cache,build,dist
diff --git a/swh/core/logger.py b/swh/core/logger.py
index 524366859270c8fde73130b38fda87846a6b48c1..763e8e44e3e3dbd88b34aa73b021f386a41773a1 100644
--- a/swh/core/logger.py
+++ b/swh/core/logger.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2015  The Software Heritage developers
+# Copyright (C) 2015-2025  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU General Public License version 3, or any later version
 # See top-level LICENSE file for more information
@@ -12,8 +12,10 @@ from systemd.journal import send
 
 try:
     from celery import current_task
+
+    celery_available = True
 except ImportError:
-    current_task = None
+    celery_available = False
 
 
 EXTRA_LOGDATA_PREFIX = "swh_"
@@ -53,7 +55,7 @@ def get_extra_data(record: logging.LogRecord) -> Dict[str, Any]:
         extra_data["logging_args"] = args
 
     # Retrieve Celery task info
-    if current_task and current_task.request:
+    if celery_available and current_task.request.kwargs:
         extra_data["task"] = {
             "id": current_task.request.id,
             "name": current_task.name,
diff --git a/tox.ini b/tox.ini
index 73356fe97c7d1eb28f002cf28c2160b0040ae646..69738a6189c782abfd7b0afd22a5219d1508205f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -34,7 +34,7 @@ commands = tox run -e {env_name}-core-db-server-github-slow-cover -- {posargs}
 [testenv:black]
 skip_install = true
 deps =
-  black==24.8.0
+  black==25.1.0
 commands =
   {envpython} -m black --check swh
 
@@ -42,8 +42,10 @@ commands =
 skip_install = true
 deps =
   flake8==7.1.1
-  flake8-bugbear==24.4.26
+  flake8-bugbear==24.12.12
+  flake8-pyproject==1.2.3
   pycodestyle==2.12.1
+
 commands =
   {envpython} -m flake8
 
@@ -55,7 +57,7 @@ extras =
   http
   github
 deps =
-  mypy==1.11.1
+  mypy==1.15.0
 commands =
   mypy swh