mirror of
https://github.com/servo/servo.git
synced 2025-07-18 21:03:45 +01:00
Mach: introduce Pyrefly for Python type checking, starting with the wpt folder (#37953)
This is the first stage of adopting Pyrefly. It introduces the Python folder and focuses on fixing issues around it. Testing: *Describe how this pull request is tested or why it doesn't require tests* Fixes: *Link to an issue this pull requests fixes or remove this line if there is no issue* --------- Signed-off-by: Jerens Lensun <jerensslensun@gmail.com>
This commit is contained in:
parent
2366a8bf9e
commit
55fd7b862f
14 changed files with 303 additions and 154 deletions
|
@ -39,7 +39,7 @@ import flask
|
|||
import flask.cli
|
||||
import requests
|
||||
|
||||
from .exporter import SyncRun, WPTSync
|
||||
from .exporter import SyncRun, WPTSync, LocalGitRepo
|
||||
from .exporter.step import CreateOrUpdateBranchForPRStep
|
||||
|
||||
TESTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tests")
|
||||
|
@ -56,14 +56,14 @@ class MockPullRequest:
|
|||
|
||||
|
||||
class MockGitHubAPIServer:
|
||||
def __init__(self, port: int):
|
||||
def __init__(self, port: int) -> None:
|
||||
self.port = port
|
||||
self.disable_logging()
|
||||
self.app = flask.Flask(__name__)
|
||||
self.pulls: list[MockPullRequest] = []
|
||||
|
||||
class NoLoggingHandler(WSGIRequestHandler):
|
||||
def log_message(self, *args):
|
||||
def log_message(self, *args) -> None:
|
||||
pass
|
||||
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
|
@ -74,12 +74,12 @@ class MockGitHubAPIServer:
|
|||
self.server = make_server("localhost", self.port, self.app, handler_class=handler)
|
||||
self.start_server_thread()
|
||||
|
||||
def disable_logging(self):
|
||||
def disable_logging(self) -> None:
|
||||
flask.cli.show_server_banner = lambda *args: None
|
||||
logging.getLogger("werkzeug").disabled = True
|
||||
logging.getLogger("werkzeug").setLevel(logging.CRITICAL)
|
||||
|
||||
def start(self):
|
||||
def start(self) -> None:
|
||||
self.thread.start()
|
||||
|
||||
# Wait for the server to be started.
|
||||
|
@ -92,7 +92,7 @@ class MockGitHubAPIServer:
|
|||
except Exception:
|
||||
time.sleep(0.1)
|
||||
|
||||
def reset_server_state_with_pull_requests(self, pulls: list[MockPullRequest]):
|
||||
def reset_server_state_with_pull_requests(self, pulls: list[MockPullRequest]) -> None:
|
||||
response = requests.get(
|
||||
f"http://localhost:{self.port}/reset-mock-github",
|
||||
json=[dataclasses.asdict(pull_request) for pull_request in pulls],
|
||||
|
@ -101,21 +101,21 @@ class MockGitHubAPIServer:
|
|||
assert response.status_code == 200
|
||||
assert response.text == "👍"
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
self.server.shutdown()
|
||||
self.thread.join()
|
||||
|
||||
def start_server_thread(self):
|
||||
def start_server_thread(self) -> None:
|
||||
# pylint: disable=unused-argument
|
||||
self.thread = threading.Thread(target=self.server.serve_forever, daemon=True)
|
||||
self.thread.start()
|
||||
|
||||
@self.app.route("/ping")
|
||||
def ping():
|
||||
def ping() -> tuple[str, int]:
|
||||
return ("pong", 200)
|
||||
|
||||
@self.app.route("/reset-mock-github")
|
||||
def reset_server():
|
||||
def reset_server() -> tuple[str, int]:
|
||||
self.pulls = [
|
||||
MockPullRequest(pull_request["head"], pull_request["number"], pull_request["state"])
|
||||
for pull_request in flask.request.json
|
||||
|
@ -123,7 +123,7 @@ class MockGitHubAPIServer:
|
|||
return ("👍", 200)
|
||||
|
||||
@self.app.route("/repos/<org>/<repo>/pulls/<int:number>/merge", methods=["PUT"])
|
||||
def merge_pull_request(org, repo, number):
|
||||
def merge_pull_request(org, repo, number) -> tuple[str, int]:
|
||||
for pull_request in self.pulls:
|
||||
if pull_request.number == number:
|
||||
pull_request.state = "closed"
|
||||
|
@ -131,7 +131,7 @@ class MockGitHubAPIServer:
|
|||
return ("", 404)
|
||||
|
||||
@self.app.route("/search/issues", methods=["GET"])
|
||||
def search():
|
||||
def search() -> str:
|
||||
params = {}
|
||||
param_strings = flask.request.args.get("q", "").split(" ")
|
||||
for string in param_strings:
|
||||
|
@ -149,13 +149,13 @@ class MockGitHubAPIServer:
|
|||
return json.dumps({"total_count": 0, "items": []})
|
||||
|
||||
@self.app.route("/repos/<org>/<repo>/pulls", methods=["POST"])
|
||||
def create_pull_request(org, repo):
|
||||
def create_pull_request(org, repo) -> dict[str, int]:
|
||||
new_pr_number = len(self.pulls) + 1
|
||||
self.pulls.append(MockPullRequest(flask.request.json["head"], new_pr_number, "open"))
|
||||
return {"number": new_pr_number}
|
||||
|
||||
@self.app.route("/repos/<org>/<repo>/pulls/<int:number>", methods=["PATCH"])
|
||||
def update_pull_request(org, repo, number):
|
||||
def update_pull_request(org, repo, number) -> tuple[str, int]:
|
||||
for pull_request in self.pulls:
|
||||
if pull_request.number == number:
|
||||
if "state" in flask.request.json:
|
||||
|
@ -166,7 +166,7 @@ class MockGitHubAPIServer:
|
|||
@self.app.route("/repos/<org>/<repo>/issues/<number>/labels", methods=["GET", "POST"])
|
||||
@self.app.route("/repos/<org>/<repo>/issues/<number>/labels/<label>", methods=["DELETE"])
|
||||
@self.app.route("/repos/<org>/<repo>/issues/<issue>/comments", methods=["GET", "POST"])
|
||||
def other_requests(*args, **kwargs):
|
||||
def other_requests(*args, **kwargs) -> tuple[str, int]:
|
||||
return ("", 204)
|
||||
|
||||
|
||||
|
@ -174,7 +174,7 @@ class TestCleanUpBodyText(unittest.TestCase):
|
|||
"""Tests that SyncRun.clean_up_body_text properly prepares the
|
||||
body text for an upstream pull request."""
|
||||
|
||||
def test_prepare_body(self):
|
||||
def test_prepare_body(self) -> None:
|
||||
text = "Simple body text"
|
||||
self.assertEqual(text, SyncRun.clean_up_body_text(text))
|
||||
self.assertEqual(
|
||||
|
@ -210,7 +210,7 @@ class TestApplyCommitsToWPT(unittest.TestCase):
|
|||
"""Tests that commits are properly applied to WPT by
|
||||
CreateOrUpdateBranchForPRStep._create_or_update_branch_for_pr."""
|
||||
|
||||
def run_test(self, pr_number: int, commit_data: dict):
|
||||
def run_test(self, pr_number: int, commit_data: dict) -> None:
|
||||
def make_commit(data):
|
||||
with open(os.path.join(TESTS_DIR, data[2]), "rb") as file:
|
||||
return {"author": data[0], "message": data[1], "diff": file.read()}
|
||||
|
@ -221,7 +221,7 @@ class TestApplyCommitsToWPT(unittest.TestCase):
|
|||
pull_request = SYNC.servo.get_pull_request(pr_number)
|
||||
step = CreateOrUpdateBranchForPRStep({"number": pr_number}, pull_request)
|
||||
|
||||
def get_applied_commits(num_commits: int, applied_commits: list[Tuple[str, str]]):
|
||||
def get_applied_commits(num_commits: int, applied_commits: list[Tuple[str, str]]) -> None:
|
||||
assert SYNC is not None
|
||||
repo = SYNC.local_wpt_repo
|
||||
log = ["log", "--oneline", f"-{num_commits}"]
|
||||
|
@ -240,10 +240,10 @@ class TestApplyCommitsToWPT(unittest.TestCase):
|
|||
expected_commits = [(commit["author"], commit["message"]) for commit in commits]
|
||||
self.assertListEqual(applied_commits, expected_commits)
|
||||
|
||||
def test_simple_commit(self):
|
||||
def test_simple_commit(self) -> None:
|
||||
self.run_test(45, [["test author <test@author>", "test commit message", "18746.diff"]])
|
||||
|
||||
def test_two_commits(self):
|
||||
def test_two_commits(self) -> None:
|
||||
self.run_test(
|
||||
100,
|
||||
[
|
||||
|
@ -253,7 +253,7 @@ class TestApplyCommitsToWPT(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_non_utf8_commit(self):
|
||||
def test_non_utf8_commit(self) -> None:
|
||||
self.run_test(
|
||||
100,
|
||||
[
|
||||
|
@ -266,15 +266,15 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
server: Optional[MockGitHubAPIServer] = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
def setUpClass(cls) -> None:
|
||||
cls.server = MockGitHubAPIServer(PORT)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
def tearDownClass(cls) -> None:
|
||||
assert cls.server is not None
|
||||
cls.server.shutdown()
|
||||
|
||||
def tearDown(self):
|
||||
def tearDown(self) -> None:
|
||||
assert SYNC is not None
|
||||
|
||||
# Clean up any old files.
|
||||
|
@ -282,7 +282,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
SYNC.local_servo_repo.run("reset", "--hard", first_commit_hash)
|
||||
SYNC.local_servo_repo.run("clean", "-fxd")
|
||||
|
||||
def mock_servo_repository_state(self, diffs: list):
|
||||
def mock_servo_repository_state(self, diffs: list) -> str:
|
||||
assert SYNC is not None
|
||||
|
||||
def make_commit_data(diff):
|
||||
|
@ -333,7 +333,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
SYNC.run(payload, step_callback=lambda step: actual_steps.append(step.name))
|
||||
return actual_steps
|
||||
|
||||
def test_opened_upstreamable_pr(self):
|
||||
def test_opened_upstreamable_pr(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("opened.json", ["18746.diff"]),
|
||||
[
|
||||
|
@ -344,7 +344,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_opened_upstreamable_pr_with_move_into_wpt(self):
|
||||
def test_opened_upstreamable_pr_with_move_into_wpt(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("opened.json", ["move-into-wpt.diff"]),
|
||||
[
|
||||
|
@ -355,7 +355,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_opened_upstreamble_pr_with_move_into_wpt_and_non_ascii_author(self):
|
||||
def test_opened_upstreamble_pr_with_move_into_wpt_and_non_ascii_author(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"opened.json",
|
||||
|
@ -376,7 +376,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_opened_upstreamable_pr_with_move_out_of_wpt(self):
|
||||
def test_opened_upstreamable_pr_with_move_out_of_wpt(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("opened.json", ["move-out-of-wpt.diff"]),
|
||||
[
|
||||
|
@ -387,11 +387,11 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_opened_new_mr_with_no_sync_signal(self):
|
||||
def test_opened_new_mr_with_no_sync_signal(self) -> None:
|
||||
self.assertListEqual(self.run_test("opened-with-no-sync-signal.json", ["18746.diff"]), [])
|
||||
self.assertListEqual(self.run_test("opened-with-no-sync-signal.json", ["non-wpt.diff"]), [])
|
||||
|
||||
def test_opened_upstreamable_pr_not_applying_cleanly_to_upstream(self):
|
||||
def test_opened_upstreamable_pr_not_applying_cleanly_to_upstream(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("opened.json", ["does-not-apply-cleanly.diff"]),
|
||||
[
|
||||
|
@ -401,7 +401,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_open_new_upstreamable_pr_with_preexisting_upstream_pr(self):
|
||||
def test_open_new_upstreamable_pr_with_preexisting_upstream_pr(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"opened.json",
|
||||
|
@ -416,7 +416,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_open_new_non_upstreamable_pr_with_preexisting_upstream_pr(self):
|
||||
def test_open_new_non_upstreamable_pr_with_preexisting_upstream_pr(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"opened.json",
|
||||
|
@ -433,7 +433,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_opened_upstreamable_pr_with_non_utf8_file_contents(self):
|
||||
def test_opened_upstreamable_pr_with_non_utf8_file_contents(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("opened.json", ["add-non-utf8-file.diff"]),
|
||||
[
|
||||
|
@ -446,7 +446,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
|
||||
def test_open_new_upstreamable_pr_with_preexisting_upstream_pr_not_apply_cleanly_to_upstream(
|
||||
self,
|
||||
):
|
||||
) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"opened.json",
|
||||
|
@ -463,10 +463,10 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_closed_pr_no_upstream_pr(self):
|
||||
def test_closed_pr_no_upstream_pr(self) -> None:
|
||||
self.assertListEqual(self.run_test("closed.json", ["18746.diff"]), [])
|
||||
|
||||
def test_closed_pr_with_preexisting_upstream_pr(self):
|
||||
def test_closed_pr_with_preexisting_upstream_pr(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"closed.json",
|
||||
|
@ -476,7 +476,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
["ChangePRStep:wpt/wpt#10:closed", "RemoveBranchForPRStep:servo/wpt/servo_export_18746"],
|
||||
)
|
||||
|
||||
def test_synchronize_move_new_changes_to_preexisting_upstream_pr(self):
|
||||
def test_synchronize_move_new_changes_to_preexisting_upstream_pr(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"synchronize.json",
|
||||
|
@ -491,7 +491,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_synchronize_close_upstream_pr_after_new_changes_do_not_include_wpt(self):
|
||||
def test_synchronize_close_upstream_pr_after_new_changes_do_not_include_wpt(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"synchronize.json",
|
||||
|
@ -508,7 +508,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_synchronize_open_upstream_pr_after_new_changes_include_wpt(self):
|
||||
def test_synchronize_open_upstream_pr_after_new_changes_include_wpt(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("synchronize.json", ["18746.diff"]),
|
||||
[
|
||||
|
@ -521,7 +521,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
|
||||
def test_synchronize_fail_to_update_preexisting_pr_after_new_changes_do_not_apply(
|
||||
self,
|
||||
):
|
||||
) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test(
|
||||
"synchronize.json",
|
||||
|
@ -538,7 +538,7 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_edited_with_upstream_pr(self):
|
||||
def test_edited_with_upstream_pr(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("edited.json", ["wpt.diff"], [MockPullRequest("servo:servo_export_19620", 10)]),
|
||||
[
|
||||
|
@ -548,12 +548,12 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_edited_with_no_upstream_pr(self):
|
||||
def test_edited_with_no_upstream_pr(self) -> None:
|
||||
self.assertListEqual(self.run_test("edited.json", ["wpt.diff"], []), [])
|
||||
|
||||
def test_synchronize_move_new_changes_to_preexisting_upstream_pr_with_multiple_commits(
|
||||
self,
|
||||
):
|
||||
) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("synchronize-multiple.json", ["18746.diff", "non-wpt.diff", "wpt.diff"]),
|
||||
[
|
||||
|
@ -564,23 +564,23 @@ class TestFullSyncRun(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_synchronize_with_non_upstreamable_changes(self):
|
||||
def test_synchronize_with_non_upstreamable_changes(self) -> None:
|
||||
self.assertListEqual(self.run_test("synchronize.json", ["non-wpt.diff"]), [])
|
||||
|
||||
def test_merge_upstream_pr_after_merge(self):
|
||||
def test_merge_upstream_pr_after_merge(self) -> None:
|
||||
self.assertListEqual(
|
||||
self.run_test("merged.json", ["18746.diff"], [MockPullRequest("servo:servo_export_19620", 100)]),
|
||||
["MergePRStep:wpt/wpt#100", "RemoveBranchForPRStep:servo/wpt/servo_export_19620"],
|
||||
)
|
||||
|
||||
def test_pr_merged_no_upstream_pr(self):
|
||||
def test_pr_merged_no_upstream_pr(self) -> None:
|
||||
self.assertListEqual(self.run_test("merged.json", ["18746.diff"]), [])
|
||||
|
||||
def test_merge_of_non_upstreamble_pr(self):
|
||||
def test_merge_of_non_upstreamble_pr(self) -> None:
|
||||
self.assertListEqual(self.run_test("merged.json", ["non-wpt.diff"]), [])
|
||||
|
||||
|
||||
def setUpModule():
|
||||
def setUpModule() -> None:
|
||||
# pylint: disable=invalid-name
|
||||
global TMP_DIR, SYNC
|
||||
|
||||
|
@ -599,7 +599,7 @@ def setUpModule():
|
|||
suppress_force_push=True,
|
||||
)
|
||||
|
||||
def setup_mock_repo(repo_name, local_repo, default_branch: str):
|
||||
def setup_mock_repo(repo_name: str, local_repo: LocalGitRepo, default_branch: str) -> None:
|
||||
subprocess.check_output(["cp", "-R", "-p", os.path.join(TESTS_DIR, repo_name), local_repo.path])
|
||||
local_repo.run("init", "-b", default_branch)
|
||||
local_repo.run("add", ".")
|
||||
|
@ -612,15 +612,15 @@ def setUpModule():
|
|||
logging.info("=" * 80)
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
def tearDownModule() -> None:
|
||||
# pylint: disable=invalid-name
|
||||
shutil.rmtree(TMP_DIR)
|
||||
|
||||
|
||||
def run_tests():
|
||||
def run_tests() -> bool:
|
||||
verbosity = 1 if logging.getLogger().level >= logging.WARN else 2
|
||||
|
||||
def run_suite(test_case: Type[unittest.TestCase]):
|
||||
def run_suite(test_case: Type[unittest.TestCase]) -> bool:
|
||||
return (
|
||||
unittest.TextTestRunner(verbosity=verbosity)
|
||||
.run(unittest.TestLoader().loadTestsFromTestCase(test_case))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue