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

pyta-uoft / pyta / 22512390765

28 Feb 2026 03:28AM UTC coverage: 89.956% (-0.02%) from 89.979%
22512390765

push

github

web-flow
Extracted watchdog into separate dependency group (#1309)

3 of 4 new or added lines in 2 files covered. (75.0%)

1 existing line in 1 file now uncovered.

3448 of 3833 relevant lines covered (89.96%)

17.44 hits per line

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

95.83
/packages/python-ta/src/python_ta/__init__.py
1
"""Python Teaching Assistant
2

3
The goal of this module is to provide automated feedback to students in our
4
introductory Python courses, using static analysis of their code.
5

6
To run the checker, call the check function on the name of the module to check.
7

8
> import python_ta
9
> python_ta.check_all('mymodule.py')
10

11
Or, put the following code in your Python module:
12

13
if __name__ == '__main__':
14
    import python_ta
15
    python_ta.check_all()
16
"""
17

18
from __future__ import annotations
20✔
19

20
from importlib.metadata import version
20✔
21

22
__version__ = version("python-ta")
20✔
23

24
# First, remove underscore from builtins if it has been bound in the REPL.
25
# Must appear before other imports from pylint/python_ta.
26
import builtins
20✔
27

28
try:
20✔
29
    del builtins._
20✔
30
except AttributeError:
20✔
31
    pass
20✔
32

33

34
import logging
20✔
35
import webbrowser
20✔
36
from typing import IO, TYPE_CHECKING, Any, Literal, Optional, Union
20✔
37

38
from .check.helpers import (
20✔
39
    check_file,
40
    get_file_paths,
41
    get_valid_files_to_check,
42
    setup_linter,
43
    upload_linter_results,
44
    verify_pre_check,
45
)
46

47
if TYPE_CHECKING:
48
    from .reporters.core import PythonTaReporter
49

50
HELP_URL = "http://www.cs.toronto.edu/~david/pyta/checkers/index.html"
20✔
51

52

53
def check_errors(
20✔
54
    module_name: Union[list[str], str] = "",
55
    config: Union[dict[str, Any], str] = "",
56
    output: Optional[Union[str, IO]] = None,
57
    load_default_config: bool = True,
58
    autoformat: Optional[bool] = False,
59
    on_verify_fail: Literal["log", "raise"] = "log",
60
) -> PythonTaReporter:
61
    """Check a module for errors, printing a report."""
62
    return _check(
20✔
63
        module_name=module_name,
64
        level="error",
65
        local_config=config,
66
        output=output,
67
        load_default_config=load_default_config,
68
        autoformat=autoformat,
69
        on_verify_fail=on_verify_fail,
70
    )
71

72

73
def check_all(
20✔
74
    module_name: Union[list[str], str] = "",
75
    config: Union[dict[str, Any], str] = "",
76
    output: Optional[Union[str, IO]] = None,
77
    load_default_config: bool = True,
78
    autoformat: Optional[bool] = False,
79
    on_verify_fail: Literal["log", "raise"] = "log",
80
) -> PythonTaReporter:
81
    """Analyse one or more Python modules for code issues and display the results.
82

83
    Args:
84
        module_name:
85
            If an empty string (default), the module where this function is called is checked.
86
            If a non-empty string, it is interpreted as a path to a single Python module or a
87
            directory containing Python modules. If the latter, all Python modules in the directory
88
            are checked.
89
            If a list of strings, each string is interpreted as a path to a module or directory,
90
            and all modules across all paths are checked.
91
        config:
92
            If a string, a path to a configuration file to use.
93
            If a dictionary, a map of configuration options (each key is the name of an option).
94
        output:
95
            If a string, a path to a file to which the PythonTA report is written.
96
            If a typing.IO object, the report is written to this stream.
97
            If None, the report is written to standard out or automatically displayed in a
98
            web browser, depending on which reporter is used.
99
        load_default_config:
100
            If True (default), additional configuration passed with the ``config`` option is
101
            merged with the default PythonTA configuration file.
102
            If False, the default PythonTA configuration is not used.
103
        autoformat:
104
            If True, autoformat all modules using the black formatting tool before analyzing code.
105
        on_verify_fail:
106
            Determines how to handle files that cannot be checked. If set to "log" (default), an error
107
            message is logged and execution continues. If set to "raise", an error is raised immediately to stop
108
            execution.
109

110
    Returns:
111
        The ``PythonTaReporter`` object that generated the report.
112
    """
113
    return _check(
20✔
114
        module_name=module_name,
115
        level="all",
116
        local_config=config,
117
        output=output,
118
        load_default_config=load_default_config,
119
        autoformat=autoformat,
120
        on_verify_fail=on_verify_fail,
121
    )
122

123

124
def _check(
20✔
125
    module_name: Union[list[str], str] = "",
126
    level: str = "all",
127
    local_config: Union[dict[str, Any], str] = "",
128
    output: Optional[Union[str, IO]] = None,
129
    load_default_config: bool = True,
130
    autoformat: Optional[bool] = False,
131
    on_verify_fail: Literal["log", "raise"] = "log",
132
) -> PythonTaReporter:
133
    """Check a module for problems, printing a report.
134

135
    The `module_name` can take several inputs:
136
      - string of a directory, or file to check (`.py` extension optional).
137
      - list of strings of directories or files -- can have multiple.
138
      - no argument -- checks the python file containing the function call.
139
    `level` is used to specify which checks should be made.
140
    `local_config` is a dict of config options or string (config file name).
141
    `output` is an absolute or relative path to a file, or a typing.IO object to capture pyta data
142
    output. If None, stdout is used.
143
    `load_default_config` is used to specify whether to load the default .pylintrc file that comes
144
    with PythonTA. It will load it by default.
145
    `autoformat` is used to specify whether the black formatting tool is run. It is not run by default.
146
    `on_verify_fail` determines how to handle files that cannot be checked. If set to "log" (default), an error
147
     message is logged and execution continues. If set to "raise", an error is raised immediately to stop execution.
148
    """
149
    # Configuring logger
150
    logging.basicConfig(format="[%(levelname)s] %(message)s", level=logging.INFO)
20✔
151
    linter, current_reporter = setup_linter(local_config, load_default_config, output)
20✔
152
    try:
20✔
153
        # Flag indicating whether at least one file has been checked
154
        is_any_file_checked = False
20✔
155
        linted_files = set()
20✔
156
        f_paths = []  # Paths to files for data submission
20✔
157
        for locations in get_valid_files_to_check(module_name):
20✔
158
            f_paths = []
20✔
159
            for file_py in get_file_paths(locations):
20✔
160
                linted_files.add(file_py)
20✔
161
                if not verify_pre_check(
20✔
162
                    file_py,
163
                    linter.config.allow_pylint_comments,
164
                    on_verify_fail=on_verify_fail,
165
                ):
166
                    # The only way to reach this is if verify_pre_check returns False, and `on_verify_fail="log"`.
167
                    continue
20✔
168
                is_any_file_checked, linter = check_file(
20✔
169
                    file_py=file_py,
170
                    local_config=local_config,
171
                    load_default_config=load_default_config,
172
                    autoformat=autoformat,
173
                    is_any_file_checked=is_any_file_checked,
174
                    current_reporter=current_reporter,
175
                    f_paths=f_paths,
176
                )
177
                current_reporter = linter.reporter
20✔
178
                current_reporter.print_messages(level)
20✔
179
            upload_linter_results(linter, current_reporter, f_paths, local_config)
20✔
180
        # Only generate reports (display the webpage) if there were valid files to check
181
        if is_any_file_checked:
20✔
182
            linter.generate_reports()
20✔
183
            if linter.config.watch:
20✔
184
                # import only when needed to avoid dragging in watchdog
NEW
185
                from .check.watch import watch_files
×
186

UNCOV
187
                watch_files(
×
188
                    file_paths=linted_files,
189
                    level=level,
190
                    local_config=local_config,
191
                    load_default_config=load_default_config,
192
                    autoformat=autoformat,
193
                    linter=linter,
194
                    f_paths=f_paths,
195
                )
196

197
        return current_reporter
20✔
198
    except Exception as e:
20✔
199
        logging.error(
20✔
200
            "Unexpected error encountered! Please report this to your instructor (and attach the code that caused the error)."
201
        )
202
        logging.error('Error message: "{}"'.format(e))
20✔
203
        raise e
20✔
204

205

206
def doc(msg_id: str) -> None:
20✔
207
    """Open the PythonTA documentation page for the given error message id.
208

209
    Args:
210
        msg_id: The five-character error code, e.g. ``"E0401"``.
211
    """
212
    msg_url = HELP_URL + "#" + msg_id.lower()
20✔
213
    print("Opening {} in a browser.".format(msg_url))
20✔
214
    webbrowser.open(msg_url)
20✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc