File: mypy_doctests_generator.py

package info (click to toggle)
python-pydash 8.0.5-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,280 kB
  • sloc: python: 14,027; makefile: 83
file content (76 lines) | stat: -rw-r--r-- 2,123 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from pathlib import Path
import re
import sys
import typing as t
from typing import reveal_type

class DocString(t.NamedTuple):
    content: str
    function_name: str

    def example_block(self) -> t.Union[t.Iterable[str], None]:
        expression_re = re.compile(r"Examples?:\n+((?:\s{8}.+?\n)+)")

        match = expression_re.search(self.content)
        if not match:
            return None

        example = match.group(1)

        return (line.strip() for line in example.strip().splitlines())


def docstrings(path: Path) -> t.Iterable[DocString]:
    docstring_re = re.compile(r"def (.+?)\((?:.|\n)+?:[\s\n]+?r?\"\"\"((?:.|\s|\n)+?)\"\"\"")

    with open(path) as f:
        text = f.read()
        docstrings = docstring_re.finditer(text)

    return map(
        lambda match: DocString(function_name=match.group(1), content=match.group(2)), docstrings
    )


def generate_test_function(docstring: DocString) -> str:
    if not (example_block := docstring.example_block()):
        return ""

    built_function = ""

    built_function += "@pytest.mark.mypy_testing\n"
    built_function += f"def test_mypy_{docstring.function_name}() -> None:\n"

    for line in map(lambda line_: line_.strip(), example_block):
        if not line:
            continue

        to_be_revealed = line.replace(">>> ", "")
        if line.startswith(">>> "):
            to_be_revealed = f"_.{to_be_revealed}"

        built_function += f"    reveal_type({to_be_revealed})  # R:\n"

    return built_function


def main(path: Path) -> str:
    imports = "import pytest\n\n"
    imports += "import pydash as _\n\n\n"

    return imports + "\n\n".join(map(generate_test_function, docstrings(path)))


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("filename", help="path to python file", type=Path)
    parser.add_argument("output", help="path to output file", type=Path)
    args = parser.parse_args()

    if not args.filename.exists():
        print(f"`{args.filename}` does not exist")
        sys.exit(1)

    args.output.write_text(main(args.filename))