From: Tamir Duberstein <tamird@kernel.org>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
Tamir Duberstein <tamird@kernel.org>
Subject: [PATCH b4 v2 07/11] Enable mypy unreachable warnings
Date: Sun, 19 Apr 2026 12:00:02 -0400 [thread overview]
Message-ID: <20260419-ruff-check-v2-7-089dfb264501@kernel.org> (raw)
In-Reply-To: <20260419-ruff-check-v2-0-089dfb264501@kernel.org>
Turn on warn_unreachable and remove dead branches that it exposes.
Some of those branches were stale null checks against non-optional APIs.
Others were test assertions that hit mypy's stale narrowing of mutable
attributes, so add targeted ignores with a reference to the upstream
issue.
Signed-off-by: Tamir Duberstein <tamird@kernel.org>
---
pyproject.toml | 2 +-
src/b4/__init__.py | 6 ++----
src/b4/mbox.py | 2 --
src/b4/pr.py | 2 +-
src/b4/review/tracking.py | 3 ++-
src/b4/review_tui/_common.py | 4 ----
src/b4/review_tui/_modals.py | 2 --
src/b4/review_tui/_review_app.py | 4 ++--
src/b4/ty.py | 3 ---
src/tests/test_tui_modals.py | 12 +++++++++---
src/tests/test_tui_tracking.py | 12 +++++++++---
11 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index c5b4593..b960994 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -125,7 +125,7 @@ quote-style = "single"
[tool.pyright]
typeCheckingMode = "off"
-# Configure mypy in strict mode
[tool.mypy]
exclude = ["^ezgb/", "^liblore/", "^patatt/"]
strict = true
+warn_unreachable = true
diff --git a/src/b4/__init__.py b/src/b4/__init__.py
index 3c1c127..6b1789f 100644
--- a/src/b4/__init__.py
+++ b/src/b4/__init__.py
@@ -1190,9 +1190,7 @@ class LoreSeries:
branches: Optional[List[str]] = None,
maxdays: int = 30,
) -> Tuple[str, int, int]:
- if self.indexes is None:
- self.populate_indexes()
- if self.indexes is None or not len(self.indexes):
+ if not self.indexes:
raise IndexError('No indexes to check against')
pdate = self.submission_date
@@ -1744,7 +1742,7 @@ class LoreMessage:
# walk until we find the first text/plain part
self.body, self.charset = LoreMessage.get_payload(self.msg)
- if self.body is None:
+ if not self.body:
# Woah, we didn't find any usable parts
logger.debug(' No plain or patch parts found in message')
logger.info(' Not plaintext: %s', self.full_subject)
diff --git a/src/b4/mbox.py b/src/b4/mbox.py
index 3198836..66b47ba 100644
--- a/src/b4/mbox.py
+++ b/src/b4/mbox.py
@@ -226,8 +226,6 @@ def make_am(msgs: List[EmailMessage], cmdargs: argparse.Namespace, msgid: str) -
if cmdargs.cherrypick == '_':
# We might want to pick a patch sent as a followup, so create a fake series
# and add followups with diffs
- if lser is None:
- lser = b4.LoreSeries(revision=1, expected=1)
for followup in lmbx.followups:
if followup.has_diff:
lser.add_patch(followup)
diff --git a/src/b4/pr.py b/src/b4/pr.py
index 7c0659a..b6a0c6b 100644
--- a/src/b4/pr.py
+++ b/src/b4/pr.py
@@ -92,7 +92,7 @@ def git_get_commit_id_from_repo_ref(repo: str, ref: str) -> Optional[str]:
def parse_pr_data(msg: email.message.EmailMessage) -> Optional[b4.LoreMessage]:
lmsg = b4.LoreMessage(msg)
- if lmsg.body is None:
+ if not lmsg.body:
logger.critical('Could not find a plain part in the message body')
return None
diff --git a/src/b4/review/tracking.py b/src/b4/review/tracking.py
index ee0d218..dd9a8e5 100644
--- a/src/b4/review/tracking.py
+++ b/src/b4/review/tracking.py
@@ -229,13 +229,14 @@ def record_take_branch(gitdir: str, branch: str) -> None:
metadata_dir = os.path.join(gitdir, REVIEW_METADATA_DIR)
pathlib.Path(metadata_dir).mkdir(parents=True, exist_ok=True)
metadata_path = get_repo_metadata_path(gitdir)
- data: Dict[str, Any] = {}
if os.path.exists(metadata_path):
try:
with open(metadata_path, 'r') as f:
data = json.load(f)
except (json.JSONDecodeError, OSError):
pass
+ else:
+ data = {}
if not isinstance(data, dict):
data = {}
branches = data.get('recent-take-branches', [])
diff --git a/src/b4/review_tui/_common.py b/src/b4/review_tui/_common.py
index c6d5df3..33349fb 100644
--- a/src/b4/review_tui/_common.py
+++ b/src/b4/review_tui/_common.py
@@ -792,10 +792,6 @@ def gather_attestation_info(lser: b4.LoreSeries) -> Dict[str, Any]:
apply_mismatches = 0
if topdir:
- # Ensure indexes are populated for applicability check
- if lser.indexes is None:
- lser.populate_indexes()
-
if base_commit:
base_exists = b4.git_commit_exists(topdir, base_commit)
diff --git a/src/b4/review_tui/_modals.py b/src/b4/review_tui/_modals.py
index c8521d6..dc72597 100644
--- a/src/b4/review_tui/_modals.py
+++ b/src/b4/review_tui/_modals.py
@@ -2256,8 +2256,6 @@ class TargetBranchScreen(ModalScreen[Optional[str]]):
ifh = io.BytesIO()
b4.save_git_am_mbox(am_msgs, ifh)
ambytes = ifh.getvalue()
- if lser.indexes is None:
- lser.populate_indexes()
return lser, ambytes
def _check_applicability(self, branch: str) -> None:
diff --git a/src/b4/review_tui/_review_app.py b/src/b4/review_tui/_review_app.py
index e476044..bf6f9ab 100644
--- a/src/b4/review_tui/_review_app.py
+++ b/src/b4/review_tui/_review_app.py
@@ -1265,7 +1265,7 @@ class ReviewApp(CheckRunnerMixin, App[None]):
editor_text.encode(), filehint='reply.b4-review.eml'
)
- if result is None:
+ if not result:
self.notify('Editor returned no content')
return
reply_text = result.decode(errors='replace')
@@ -1388,7 +1388,7 @@ class ReviewApp(CheckRunnerMixin, App[None]):
with self.suspend():
result = b4.edit_in_editor(editor_text.encode(), filehint='note.txt')
- if result is None:
+ if not result:
self.notify('Editor returned no content')
return
raw_text = result.decode(errors='replace')
diff --git a/src/b4/ty.py b/src/b4/ty.py
index 45c7773..5918193 100644
--- a/src/b4/ty.py
+++ b/src/b4/ty.py
@@ -521,9 +521,6 @@ def send_messages(
# This is a patch series
msg = generate_am_thanks(gitdir, jsondata, branch, cmdargs)
- if msg is None:
- continue
-
assert isinstance(jsondata['msgid'], str), 'msgid must be a string'
msgids.append(jsondata['msgid'])
assert isinstance(jsondata['patches'], list), 'patches must be a list'
diff --git a/src/tests/test_tui_modals.py b/src/tests/test_tui_modals.py
index 8f16781..4bb3069 100644
--- a/src/tests/test_tui_modals.py
+++ b/src/tests/test_tui_modals.py
@@ -88,7 +88,9 @@ class TestHelpScreen:
await pilot.pause()
# Should be back on the host screen
assert not isinstance(app.screen, HelpScreen)
- assert dismissed == [None]
+ # https://github.com/python/mypy/issues/9457:
+ # app.screen is stale-narrowed across await.
+ assert dismissed == [None] # type: ignore[unreachable]
@pytest.mark.asyncio
async def test_question_mark_dismisses(self) -> None:
@@ -182,7 +184,9 @@ class TestConfirmScreen:
await pilot.press('y')
await pilot.pause()
assert not isinstance(app.screen, ConfirmScreen)
- assert results == [True]
+ # https://github.com/python/mypy/issues/9457:
+ # app.screen is stale-narrowed across await.
+ assert results == [True] # type: ignore[unreachable]
@pytest.mark.asyncio
async def test_escape_cancels(self) -> None:
@@ -477,7 +481,9 @@ class TestPriorReviewScreen:
await pilot.press('escape')
await pilot.pause()
assert not isinstance(app.screen, PriorReviewScreen)
- assert results == [None]
+ # https://github.com/python/mypy/issues/9457:
+ # app.screen is stale-narrowed across await.
+ assert results == [None] # type: ignore[unreachable]
@pytest.mark.asyncio
async def test_content_rendered(self) -> None:
diff --git a/src/tests/test_tui_tracking.py b/src/tests/test_tui_tracking.py
index 76ff353..a9491ad 100644
--- a/src/tests/test_tui_tracking.py
+++ b/src/tests/test_tui_tracking.py
@@ -1044,7 +1044,9 @@ class TestTrackingSnooze:
assert not isinstance(app.screen, SnoozeScreen)
# Verify DB was updated
- conn = tracking.get_db(identifier)
+ # https://github.com/python/mypy/issues/9457:
+ # app.screen is stale-narrowed across await.
+ conn = tracking.get_db(identifier) # type: ignore[unreachable]
cursor = conn.execute(
'SELECT status, snoozed_until FROM series WHERE change_id = ?',
('snooze-test-1',),
@@ -2161,7 +2163,9 @@ class TestTargetBranch:
assert not isinstance(app.screen, TargetBranchScreen)
# Verify DB cleared
- conn = tracking.get_db(identifier)
+ # https://github.com/python/mypy/issues/9457:
+ # app.screen is stale-narrowed across await.
+ conn = tracking.get_db(identifier) # type: ignore[unreachable]
target = tracking.get_target_branch(conn, change_id)
conn.close()
assert target is None
@@ -2709,7 +2713,9 @@ class TestLoadSeriesCaching:
assert app._cached_branch_tips is not None
app._invalidate_caches()
assert app._cached_branch_tips is None
- assert app._cached_newest_revisions is None
+ # https://github.com/python/mypy/issues/9457:
+ # app._cached_branch_tips is stale-narrowed across a method call.
+ assert app._cached_newest_revisions is None # type: ignore[unreachable]
assert app._cached_revision_counts is None
assert app._cached_art_counts is None
--
2.53.0
next prev parent reply other threads:[~2026-04-19 16:00 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-19 15:59 [PATCH b4 v2 00/11] Enable stricter local checks Tamir Duberstein
2026-04-19 15:59 ` [PATCH b4 v2 01/11] Add CI script Tamir Duberstein
2026-04-19 15:59 ` [PATCH b4 v2 02/11] Add ruff checks to CI Tamir Duberstein
2026-04-19 15:59 ` [PATCH b4 v2 03/11] Import dependencies unconditionally Tamir Duberstein
2026-04-19 15:59 ` [PATCH b4 v2 04/11] Add ruff format check to CI Tamir Duberstein
2026-04-19 18:06 ` Tamir Duberstein
2026-04-19 16:00 ` [PATCH b4 v2 05/11] Fix tests under uv with complex git config Tamir Duberstein
2026-04-19 16:00 ` [PATCH b4 v2 06/11] Fix typings in misc/ Tamir Duberstein
2026-04-19 16:00 ` Tamir Duberstein [this message]
2026-04-19 16:00 ` [PATCH b4 v2 08/11] Enable and fix pyright diagnostics Tamir Duberstein
2026-04-19 16:00 ` [PATCH b4 v2 09/11] Avoid duplicate map lookups Tamir Duberstein
2026-04-19 16:00 ` [PATCH b4 v2 10/11] Add ty and configuration Tamir Duberstein
2026-04-19 16:00 ` [PATCH b4 v2 11/11] Enable pyright strict mode Tamir Duberstein
2026-04-23 2:48 ` [PATCH b4 v2 00/11] Enable stricter local checks Konstantin Ryabitsev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260419-ruff-check-v2-7-089dfb264501@kernel.org \
--to=tamird@kernel.org \
--cc=konstantin@linuxfoundation.org \
--cc=tools@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox