Skip to content

Commit

Permalink
ref: check that patterns in mypy stronglist actually exist (#70847)
Browse files Browse the repository at this point in the history
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. -->
  • Loading branch information
asottile-sentry committed May 14, 2024
1 parent ff87f5e commit 477548d
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 80 deletions.
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
78 changes: 0 additions & 78 deletions tests/tools/mypy_helpers/test_check_mypy_stronglist.py

This file was deleted.

188 changes: 188 additions & 0 deletions tests/tools/mypy_helpers/test_check_stronglist.py
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions tools/mypy_helpers/check_stronglist.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import argparse
import glob
import os.path
import re
from collections.abc import Sequence

Expand All @@ -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"]

Expand All @@ -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


Expand Down

0 comments on commit 477548d

Please sign in to comment.