• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pyta-uoft / pyta / 36646375051

29 Sep 2026 11:39PM UTC coverage: 90.867% (-0.06%) from 90.925%
36646375051

push

github

web-flow
Added type annotations and fixed mypy errors in python-ta package (#1397)

256 of 269 new or added lines in 33 files covered. (95.17%)

2 existing lines in 2 files now uncovered.

3761 of 4139 relevant lines covered (90.87%)

17.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/python-ta/src/python_ta/contracts/__main__.py
1
from __future__ import annotations
×
2

3
import os.path
×
4
import sys
×
5
import traceback
×
6
import types
×
7
from typing import TextIO
×
8

9
import click
×
10

11
from . import check_all_contracts
×
12

13

14
@click.command()
×
15
@click.argument("file", type=click.File(mode="r"))
×
16
@click.option("--extra-mod-name", "-e", multiple=True, help="Name of imported module to also check")
×
17
@click.option("--no-decorate-main", is_flag=True, default=True, help="Disable decorating FILE")
×
NEW
18
def check_contracts(file: TextIO, extra_mod_name: tuple, no_decorate_main: bool) -> None:
×
19
    """Run FILE as Python script with PythonTA's contract checking enabled.
20

21
    FILE the Python script as if you were to just run `python FILE`
22
    """
23
    contents = file.read()
×
24
    lines = contents.splitlines()
×
25

26
    main_lineno = _find_main_lineno(lines)
×
27

28
    if main_lineno:
×
29
        duck_main = ContractsRunnerModule(
×
30
            "__main__", main_lineno, lines, extra_mod_name, no_decorate_main
31
        )
32

33
        true_main = sys.modules["__main__"]
×
34
        sys.modules["__main__"] = duck_main
×
35
        try:
×
36
            duck_main.run()
×
37
        except SystemExit as se:
×
38
            sys.stderr.write(_formatted_traceback(file.name))
×
39
            sys.exit(se.args[0])
×
40
        except Exception:
×
41
            sys.stderr.write(_formatted_traceback(file.name))
×
42
            sys.exit(1)
×
43

44
        sys.modules["__main__"] = true_main
×
45

46

47
class ContractsRunnerModule(types.ModuleType):
×
48
    """A pseudo module used for splitting up execution contexts to insert contract checking
49
    before the if __name__ == "__main__" entry point
50
    """
51

52
    def __init__(
×
53
        self,
54
        name: str,
55
        main_lineno: int,
56
        lines: list[str],
57
        extra_mod_names: tuple,
58
        no_main: bool,
59
    ) -> None:
60
        super().__init__(name)
×
61

62
        split_point = main_lineno - 1
×
63
        self.before_main = "\n".join(lines[:split_point])
×
64
        self.after_main = "\n" * split_point + "\n".join(lines[split_point:])
×
65
        self.extra_mod_names = extra_mod_names
×
66
        self.no_main = no_main
×
67

68
        # not required but prevents __dict__ from being auto populated with all default builtins
69
        self.__builtins__ = globals()["__builtins__"]
×
70

71
    def run(self) -> None:
×
72
        exec(self.before_main, self.__dict__)
×
73
        check_all_contracts(*self.extra_mod_names, decorate_main=self.no_main)
×
74
        exec(self.after_main, self.__dict__)
×
75

76

77
def _formatted_traceback(file_name) -> str:
×
78
    """Gets current traceback as string while removing run and exec frames and replacing
79
    the default exec context name "<string>" with the ran file name."""
80
    exception_traceback = sys.exc_info()[2]
×
81

82
    stack_size = len(traceback.extract_tb(exception_traceback))
×
83
    # ignores first two frames of traceback (module runner and exec frames)
84
    exception_message = traceback.format_exc(limit=-(stack_size - 2))
×
85

86
    main_path = os.path.abspath(file_name)
×
87
    formatted_exception = exception_message.replace("<string>", main_path)
×
88
    return formatted_exception
×
89

90

91
def _find_main_lineno(lines: list[str]) -> int:
×
92
    for lineno, line in enumerate(lines, start=1):
×
93
        if _has_main_check(line):
×
94
            return lineno
×
95
    return 0
×
96

97

98
def _has_main_check(line: str) -> bool:
×
99
    if line.strip() == "":
×
100
        return False
×
101
    keyword, *condition = line.split()
×
102
    spaceless_condition = "".join(condition)
×
103
    return (
×
104
        keyword == "if"
105
        and line.startswith(keyword)
106
        and (
107
            spaceless_condition == "__name__=='__main__':"
108
            or spaceless_condition == '__name__=="__main__":'
109
        )
110
    )
111

112

113
if __name__ == "__main__":
×
114
    check_contracts()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc