Skip to content

Commit b509227

Browse files
committed
Fix all mypy type checking errors
- Add return type annotation to PatchtestParser.get_parser() - Add type annotations to patchtest_result decorator and wrapper - Add type annotations to MboxReader methods (__exit__, __iter__, __next__) - Add type annotation for 'lines' list in MboxReader.__next__() - Fix Patch.__init__ to handle Message.get_payload() union type - Add None checks for email header fields - Fix TargetRepo.can_be_merged to return bool consistently - Fix git.execute() call to use proper keyword argument - Add None checks for module spec and loader in dynamic import - Add type annotations to all test functions in core.py and oe.py - Add type: ignore comments for untyped unidiff imports - Add types-unidiff to dev dependencies - Import Tuple from typing for test function signatures Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
1 parent fa007cc commit b509227

7 files changed

Lines changed: 51 additions & 38 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dev = [
4040
"pytest>=7.4.0",
4141
"pytest-cov>=4.1.0",
4242
"types-setuptools",
43+
"types-unidiff",
4344
]
4445
test = [
4546
"pytest>=7.4.0",

src/patchtest2/mbox.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import re
1616
from dataclasses import dataclass
1717
from email.message import Message
18-
from typing import List, Optional
18+
from typing import List, Optional, Iterator, Any
1919

2020
import git
2121

@@ -29,14 +29,14 @@ def __init__(self, filepath: str) -> None:
2929
def __enter__(self) -> "MboxReader":
3030
return self
3131

32-
def __exit__(self, exc_type, exc_value, exc_traceback) -> None:
32+
def __exit__(self, exc_type: Any, exc_value: Any, exc_traceback: Any) -> None:
3333
self.handle.close()
3434

35-
def __iter__(self):
35+
def __iter__(self) -> Iterator[Message]:
3636
return iter(self.__next__())
3737

38-
def __next__(self):
39-
lines = []
38+
def __next__(self) -> Iterator[Message]:
39+
lines: List[bytes] = []
4040
while True:
4141
line = self.handle.readline()
4242
if line == b"" or line.startswith(b"From "):
@@ -51,13 +51,19 @@ def __next__(self):
5151
class Patch:
5252
def __init__(self, data: Message) -> None:
5353
self.data = data
54-
self.author: str = data["From"]
55-
self.to: str = data["To"]
56-
self.cc: str = data["Cc"]
57-
self.subject: str = data["Subject"]
58-
self.split_body: List[str] = re.split("---", data.get_payload(), maxsplit=1)
54+
self.author: str = data["From"] or ""
55+
self.to: str = data["To"] or ""
56+
self.cc: str = data["Cc"] or ""
57+
self.subject: str = data["Subject"] or ""
58+
payload = data.get_payload()
59+
# Handle payload that might be a list or string
60+
if isinstance(payload, list):
61+
payload_str = str(payload[0]) if payload else ""
62+
else:
63+
payload_str = str(payload)
64+
self.split_body: List[str] = re.split("---", payload_str, maxsplit=1)
5965
self.commit_message: str = self.split_body[0]
60-
self.diff: str = self.split_body[1]
66+
self.diff: str = self.split_body[1] if len(self.split_body) > 1 else ""
6167
# get the shortlog, but make sure to exclude bracketed prefixes
6268
# before the colon, and remove extra whitespace/newlines
6369
self.shortlog: str = (
@@ -138,20 +144,16 @@ def checkout_working_branch(self, target_branch: str) -> None:
138144
["git", "checkout", "-B", self.working_branch, target_branch]
139145
)
140146

141-
def can_be_merged(self, patchfile: str):
147+
def can_be_merged(self, patchfile: str) -> bool:
142148
# We don't actually want to propagate the error if the patch
143149
# can't merge, so put a try-except around it. However, if the
144-
# check fails, return the error message so that it can be parsed
145-
# to identify the failing message in the series
150+
# check fails, return False
146151
try:
147152
self.merge_patch(patchfile)
148-
result = True
149-
150-
except git.exc.GitCommandError as ce:
151-
result = ce
153+
return True
154+
except git.exc.GitCommandError:
152155
self.abort_merge()
153-
154-
return result
156+
return False
155157

156158
def merge_patch(self, patchfile: str) -> None:
157159
self.repo.git.execute(

src/patchtest2/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class PatchtestParser(object):
2323
"""Abstract the patchtest argument parser"""
2424

2525
@classmethod
26-
def get_parser(cls):
26+
def get_parser(cls) -> argparse.ArgumentParser:
2727
parser = argparse.ArgumentParser()
2828

2929
target_patch_group = parser.add_mutually_exclusive_group(required=True)

src/patchtest2/patchtest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ def _load_test_modules(self) -> None:
6464
spec = importlib.util.spec_from_file_location(
6565
f"patchtest2.suites.{suite_name}", module_file
6666
)
67+
if spec is None or spec.loader is None:
68+
logger.warning(
69+
f"Could not load spec for suite '{suite_name}' from {module_file}"
70+
)
71+
continue
72+
6773
module = importlib.util.module_from_spec(spec)
6874

6975
# Add to sys.modules to handle imports within the module

src/patchtest2/results.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import functools
22
import inspect
3-
from typing import Any, Tuple
3+
from typing import Any, Tuple, Callable
44

55

6-
def patchtest_result(func):
6+
def patchtest_result(func: Callable[..., Tuple[str, str, str]]) -> Callable[..., str]:
77
"""Decorator that formats test results consistently.
88
99
Test functions must return a tuple of (subject, result, reason) where:
@@ -13,7 +13,7 @@ def patchtest_result(func):
1313
"""
1414

1515
@functools.wraps(func)
16-
def wrapper(*args, **kwargs):
16+
def wrapper(*args: Any, **kwargs: Any) -> str:
1717
result = func(*args, **kwargs)
1818

1919
# Validate return value

src/patchtest2/suites/core.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
import pyparsing
44
import unidiff
55

6-
import patchtest2.patterns as patterns
6+
import patchtest2.patterns as patterns # type: ignore[import-untyped]
77
from patchtest2.results import patchtest_result
8+
from patchtest2.mbox import Patch
9+
from typing import Tuple
810

911

1012
@patchtest_result
11-
def test_mbox_has_signed_off_by(target):
13+
def test_mbox_has_signed_off_by(target: Patch) -> Tuple[str, str, str]:
1214
result = "FAIL"
1315
if patterns.signed_off_by.search_string(target.commit_message):
1416
result = "PASS"
@@ -17,7 +19,7 @@ def test_mbox_has_signed_off_by(target):
1719

1820

1921
@patchtest_result
20-
def test_mbox_shortlog_format(target):
22+
def test_mbox_shortlog_format(target: Patch) -> Tuple[str, str, str]:
2123
result = "PASS"
2224
reason = None
2325
if not target.shortlog.strip():
@@ -38,7 +40,7 @@ def test_mbox_shortlog_format(target):
3840

3941

4042
@patchtest_result
41-
def test_mbox_shortlog_length(target):
43+
def test_mbox_shortlog_length(target: Patch) -> Tuple[str, str, str]:
4244
shortlog = re.sub("^(\[.*?\])+ ", "", target.shortlog)
4345
shortlog_len = len(shortlog)
4446
result = "PASS"
@@ -55,7 +57,7 @@ def test_mbox_shortlog_length(target):
5557

5658

5759
@patchtest_result
58-
def test_mbox_has_commit_message(target):
60+
def test_mbox_has_commit_message(target: Patch) -> Tuple[str, str, str]:
5961
result = "PASS"
6062
reason = "Please include a commit message on your patch explaining the change"
6163

@@ -74,7 +76,7 @@ def test_mbox_has_commit_message(target):
7476

7577

7678
@patchtest_result
77-
def test_mbox_unidiff_parse_error(target):
79+
def test_mbox_unidiff_parse_error(target: Patch) -> Tuple[str, str, str]:
7880
result = "PASS"
7981
reason = f'Patch "{target.shortlog}" contains malformed diff lines.'
8082

@@ -87,7 +89,7 @@ def test_mbox_unidiff_parse_error(target):
8789

8890

8991
@patchtest_result
90-
def test_mbox_revert_signed_off_by_exception(target):
92+
def test_mbox_revert_signed_off_by_exception(target: Patch) -> Tuple[str, str, str]:
9193
"""Skip signed-off-by test for revert commits"""
9294
result = "PASS"
9395
reason = None
@@ -106,7 +108,7 @@ def test_mbox_revert_signed_off_by_exception(target):
106108

107109
# Additional helper test that might be useful
108110
@patchtest_result
109-
def test_mbox_shortlog_revert_format(target):
111+
def test_mbox_shortlog_revert_format(target: Patch) -> Tuple[str, str, str]:
110112
"""Test revert commit shortlog format"""
111113
result = "PASS"
112114
reason = None

src/patchtest2/suites/oe.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
import pyparsing
44
import unidiff
55

6-
import patchtest2.patterns as patterns
6+
import patchtest2.patterns as patterns # type: ignore[import-untyped]
77
from patchtest2.results import patchtest_result
8+
from patchtest2.mbox import Patch
9+
from typing import Tuple
810

911

1012
@patchtest_result
11-
def test_mbox_commit_message_user_tags(target):
13+
def test_mbox_commit_message_user_tags(target: Patch) -> Tuple[str, str, str]:
1214
"""Test for GitHub-style username tags (@username) in commit messages"""
1315
result = "PASS"
1416
reason = "Mbox includes one or more GitHub-style username tags. Ensure that any '@' symbols are stripped out of usernames"
@@ -20,7 +22,7 @@ def test_mbox_commit_message_user_tags(target):
2022

2123

2224
@patchtest_result
23-
def test_mbox_non_auh_upgrade(target):
25+
def test_mbox_non_auh_upgrade(target: Patch) -> Tuple[str, str, str]:
2426
"""Test that patch is not from AUH (Auto Upgrade Helper)"""
2527
result = "PASS"
2628
reason = f"Invalid author {patterns.auh_email}. Resend the series with a valid patch author"
@@ -32,7 +34,7 @@ def test_mbox_non_auh_upgrade(target):
3234

3335

3436
@patchtest_result
35-
def test_mbox_target_mailing_list_meta_project(target):
37+
def test_mbox_target_mailing_list_meta_project(target: Patch) -> Tuple[str, str, str]:
3638
"""Check for meta-* project tags in subject line"""
3739
result = "PASS"
3840
reason = "Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists"
@@ -46,7 +48,7 @@ def test_mbox_target_mailing_list_meta_project(target):
4648

4749

4850
@patchtest_result
49-
def test_mbox_bugzilla_entry_format(target):
51+
def test_mbox_bugzilla_entry_format(target: Patch) -> Tuple[str, str, str]:
5052
"""Test for proper Bugzilla entry format in commit messages"""
5153
result = "PASS"
5254
reason = None
@@ -63,7 +65,7 @@ def test_mbox_bugzilla_entry_format(target):
6365

6466

6567
@patchtest_result
66-
def test_mbox_author_valid(target):
68+
def test_mbox_author_valid(target: Patch) -> Tuple[str, str, str]:
6769
"""Test for valid patch author"""
6870
result = "PASS"
6971
reason = (

0 commit comments

Comments
 (0)