import argparse
import ast
import os
import re
import subprocess
from itertools import groupby
def get_test_lists(*args: str) -> list[str]:
cmd = [
"pytest",
"--collect-only",
"--disable-warnings",
"--no-header",
"--no-summary",
"-q",
"--color=no",
"--capture=no",
"-s",
*args,
]
output = subprocess.check_output(cmd, text=True, env=os.environ)
test_paths_with_params: list[str] = [line for line in output.splitlines(False) if ".py" in line]
filter_out = map(lambda x: re.sub(r"\[.*?\]", "", x), test_paths_with_params)
test_paths: list[str] = list(set(filter_out))
return sorted(test_paths)
def find_tests_without_mark(test_files: list[str]) -> list[str]:
grouped_tests: dict[str, tuple[str, ...]] = {
key: tuple(x.split("::", 1)[1] for x in group)
for key, group in groupby(test_files, lambda x: x.split(".py", 1)[0] + ".py")
}
tests_without_mark: list[str] = []
for file_path, test_functions in grouped_tests.items():
with open(file_path, "r") as file:
tree = ast.parse(file.read())
for node in ast.walk(tree):
# only for `test_*` function or `Test*` classes
if (isinstance(node, ast.FunctionDef) and node.name in test_functions) or (
isinstance(node, ast.ClassDef) and any(test.startswith(node.name) for test in test_functions)
):
has_mark_decorator = False
for decorator in node.decorator_list:
# does it have `pytest.mark.*`
has_mark_decorator = (
isinstance(decorator, ast.Attribute)
and isinstance(decorator.value, ast.Attribute)
and isinstance(decorator.value.value, ast.Name)
and decorator.value.value.id == "pytest"
and decorator.value.attr == "mark"
)
if has_mark_decorator:
break
if not has_mark_decorator:
tests_without_mark.append(f"{file_path}::{node.name}")
return tests_without_mark
test_files = get_test_lists("./")
tests_without_mark = find_tests_without_mark(test_files)
print(*tests_without_mark, sep="\n")
1条答案
按热度按时间j91ykkif1#
我终于解决了这个问题。
字符串