Browse Source

ref: check that patterns in mypy stronglist actually exist (#70847)

I also renamed the test module to match the module name -- split that
into a separate commit so github's per-commit diff reflects the changes
there

<!-- Describe your PR here. -->
anthony sottile 10 months ago
parent
commit
477548dd12

+ 1 - 2
pyproject.toml

@@ -616,7 +616,6 @@ module = [
     "sentry.services.hybrid_cloud.notifications.*",
     "sentry.services.hybrid_cloud.organization_actions.*",
     "sentry.services.hybrid_cloud.organization_mapping.*",
-    "sentry.services.hybrid_cloud.organization_provisioning.*",
     "sentry.services.hybrid_cloud.organizationmember_mapping.*",
     "sentry.services.hybrid_cloud.orgauthtoken.*",
     "sentry.services.hybrid_cloud.pagination",
@@ -635,7 +634,7 @@ module = [
     "sentry.tasks.commit_context",
     "sentry.tasks.on_demand_metrics",
     "sentry.tasks.reprocessing2",
-    "sentry.utils.actor",
+    "sentry.types.actor",
     "sentry.utils.arroyo",
     "sentry.utils.assets",
     "sentry.utils.audit",

+ 0 - 78
tests/tools/mypy_helpers/test_check_mypy_stronglist.py

@@ -1,78 +0,0 @@
-import re
-
-from tools.mypy_helpers.check_stronglist import _glob_to_re, main
-
-
-def test_glob_to_re_exact_matches():
-    pat = re.compile(_glob_to_re("a.b.c"))
-    assert pat.fullmatch("a.b.c")
-    assert not pat.fullmatch("a.b.c.d")
-    assert not pat.fullmatch("a_b_c")
-
-
-def test_glob_to_re_wildcards():
-    pat = re.compile(_glob_to_re("a.b.c.*"))
-    assert pat.fullmatch("a.b.c")
-    assert pat.fullmatch("a.b.c.d")
-    assert not pat.fullmatch("a_b_c")
-
-
-def test_ok(tmp_path):
-    src = """\
-[[tool.mypy.overrides]]
-module = ["a.b.c", "d.e.f", "g.h.i"]
-disable_error_code = ["misc"]
-
-[[tool.mypy.overrides]]
-module = ["j.k.*"]
-disallow_untyped_defs = true
-"""
-    f = tmp_path.joinpath("f")
-    f.write_text(src)
-
-    assert main((str(f),)) == 0
-
-
-def test_errors_on_exact_module(tmp_path, capsys):
-    src = """\
-[[tool.mypy.overrides]]
-module = ["a.b.c", "d.e.f", "g.h.i"]
-disable_error_code = ["misc"]
-
-[[tool.mypy.overrides]]
-module = ["a.b.c", "d.e.f"]
-disallow_untyped_defs = true
-"""
-    f = tmp_path.joinpath("f")
-    f.write_text(src)
-
-    assert main((str(f),)) == 1
-
-    expected = f"""\
-{f}: a.b.c is in the typing errors allowlist *and* stronglist
-{f}: d.e.f is in the typing errors allowlist *and* stronglist
-"""
-    assert capsys.readouterr().out == expected
-
-
-def test_errors_on_globbed_module(tmp_path, capsys):
-    src = """\
-[[tool.mypy.overrides]]
-module = ["a.b.c", "a.b.c.d", "a.b.c.e"]
-disable_error_code = ["misc"]
-
-[[tool.mypy.overrides]]
-module = ["a.b.c.*"]
-disallow_untyped_defs = true
-"""
-    f = tmp_path.joinpath("f")
-    f.write_text(src)
-
-    assert main((str(f),)) == 1
-
-    expected = f"""\
-{f}: a.b.c is in the typing errors allowlist *and* stronglist
-{f}: a.b.c.d is in the typing errors allowlist *and* stronglist
-{f}: a.b.c.e is in the typing errors allowlist *and* stronglist
-"""
-    assert capsys.readouterr().out == expected

+ 188 - 0
tests/tools/mypy_helpers/test_check_stronglist.py

@@ -0,0 +1,188 @@
+import re
+
+from tools.mypy_helpers.check_stronglist import _glob_to_re, main
+
+
+def test_glob_to_re_exact_matches():
+    pat = re.compile(_glob_to_re("a.b.c"))
+    assert pat.fullmatch("a.b.c")
+    assert not pat.fullmatch("a.b.c.d")
+    assert not pat.fullmatch("a_b_c")
+
+
+def test_glob_to_re_wildcards():
+    pat = re.compile(_glob_to_re("a.b.c.*"))
+    assert pat.fullmatch("a.b.c")
+    assert pat.fullmatch("a.b.c.d")
+    assert not pat.fullmatch("a_b_c")
+
+
+def test_ok(tmp_path):
+    src = """\
+[[tool.mypy.overrides]]
+module = ["a.b.c", "d.e.f", "g.h.i"]
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["j.k.*"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    tmp_path.joinpath("j/k").mkdir(parents=True)
+    tmp_path.joinpath("j/k/l.py").touch()
+
+    assert main((str(f),)) == 0
+
+
+def test_errors_on_exact_module(tmp_path, capsys):
+    src = """\
+[[tool.mypy.overrides]]
+module = ["a.b.c", "d.e.f", "g.h.i"]
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.b.c", "d.e.f"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    tmp_path.joinpath("a/b").mkdir(parents=True)
+    tmp_path.joinpath("a/b/c.py").touch()
+    tmp_path.joinpath("d/e").mkdir(parents=True)
+    tmp_path.joinpath("d/e/f.py").touch()
+
+    assert main((str(f),)) == 1
+
+    expected = f"""\
+{f}: a.b.c is in the typing errors allowlist *and* stronglist
+{f}: d.e.f is in the typing errors allowlist *and* stronglist
+"""
+    assert capsys.readouterr().out == expected
+
+
+def test_errors_on_globbed_module(tmp_path, capsys):
+    src = """\
+[[tool.mypy.overrides]]
+module = ["a.b.c", "a.b.c.d", "a.b.c.e"]
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.b.c.*"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    tmp_path.joinpath("a/b/c").mkdir(parents=True)
+    tmp_path.joinpath("a/b/c/d.py").touch()
+
+    assert main((str(f),)) == 1
+
+    expected = f"""\
+{f}: a.b.c is in the typing errors allowlist *and* stronglist
+{f}: a.b.c.d is in the typing errors allowlist *and* stronglist
+{f}: a.b.c.e is in the typing errors allowlist *and* stronglist
+"""
+    assert capsys.readouterr().out == expected
+
+
+def test_stronglist_existence_file_missing(tmp_path, capsys):
+    src = """\
+[[tool.mypy.overrides]]
+module = []
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.b"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    assert main((str(f),)) == 1
+
+    expected = f"""\
+{f}: a.b in stronglist does not match any files!
+"""
+    assert capsys.readouterr().out == expected
+
+
+def test_stronglist_existence_glob_missing(tmp_path, capsys):
+    src = """\
+[[tool.mypy.overrides]]
+module = []
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.*"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    assert main((str(f),)) == 1
+
+    expected = f"""\
+{f}: a.* in stronglist does not match any files!
+"""
+    assert capsys.readouterr().out == expected
+
+
+def test_stronglist_existence_ok_src_layout(tmp_path):
+    src = """\
+[[tool.mypy.overrides]]
+module = []
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.b"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    tmp_path.joinpath("src/a").mkdir(parents=True)
+    tmp_path.joinpath("src/a/b.py").touch()
+
+    assert main((str(f),)) == 0
+
+
+def test_stronglist_existence_ok_glob(tmp_path):
+    src = """\
+[[tool.mypy.overrides]]
+module = []
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.*"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    tmp_path.joinpath("a").mkdir(parents=True)
+    tmp_path.joinpath("a/c.py").touch()
+
+    assert main((str(f),)) == 0
+
+
+def test_stronglist_existince_ok_init_py(tmp_path):
+    src = """\
+[[tool.mypy.overrides]]
+module = []
+disable_error_code = ["misc"]
+
+[[tool.mypy.overrides]]
+module = ["a.b"]
+disallow_untyped_defs = true
+"""
+    f = tmp_path.joinpath("f")
+    f.write_text(src)
+
+    tmp_path.joinpath("a/b").mkdir(parents=True)
+    tmp_path.joinpath("a/b/__init__.py").touch()
+
+    assert main((str(f),)) == 0

+ 20 - 0
tools/mypy_helpers/check_stronglist.py

@@ -1,4 +1,6 @@
 import argparse
+import glob
+import os.path
 import re
 from collections.abc import Sequence
 
@@ -20,6 +22,8 @@ def main(argv: Sequence[str] | None = None) -> int:
 
     retv = 0
     for filename in args.filenames:
+        reldir = os.path.dirname(os.path.abspath(filename))
+
         with open(filename, "rb") as f:
             overrides = tomllib.load(f)["tool"]["mypy"]["overrides"]
 
@@ -33,6 +37,22 @@ def main(argv: Sequence[str] | None = None) -> int:
                 print(f"{filename}: {mod} is in the typing errors allowlist *and* stronglist")
                 retv = 1
 
+        for pat in stronglist["module"]:
+            orig_pat = pat
+            firstmod = pat.split(".")[0]
+            if os.path.exists(os.path.join(reldir, "src", firstmod)):
+                pat = f"src.{pat}"
+            pat = pat.replace(".", "/")
+            if pat.endswith("*"):
+                if glob.glob(os.path.join(reldir, pat)):
+                    continue
+            elif os.path.exists(os.path.join(reldir, f"{pat}.py")):
+                continue
+            elif os.path.exists(os.path.join(reldir, pat, "__init__.py")):
+                continue
+            print(f"{filename}: {orig_pat} in stronglist does not match any files!")
+            retv = 1
+
     return retv