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

pyta-uoft / pyta / 13801531304

10 Mar 2025 03:51AM UTC coverage: 92.031% (-0.9%) from 92.957%
13801531304

Pull #1156

github

web-flow
Merge 589e90852 into 2b00cbabf
Pull Request #1156: Integrate Watchdog for Live Code Re-Checking

160 of 200 new or added lines in 3 files covered. (80.0%)

8 existing lines in 1 file now uncovered.

3303 of 3589 relevant lines covered (92.03%)

17.52 hits per line

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

98.11
/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
__version__ = "2.10.2.dev"  # Version number
20✔
21
# First, remove underscore from builtins if it has been bound in the REPL.
22
# Must appear before other imports from pylint/python_ta.
23
import builtins
20✔
24

25
try:
20✔
26
    del builtins._
20✔
27
except AttributeError:
20✔
28
    pass
20✔
29

30

31
import logging
20✔
32
import tokenize
20✔
33
import webbrowser
20✔
34
from typing import IO, Any, Optional, Union
20✔
35

36
from .check.helpers import (
20✔
37
    check_file,
38
    get_file_paths,
39
    get_valid_files_to_check,
40
    setup_linter,
41
    upload_linter_results,
42
    verify_pre_check,
43
)
44
from .check.watch import watch_files
20✔
45
from .config import (
20✔
46
    find_local_config,
47
    load_config,
48
    load_messages_config,
49
    override_config,
50
)
51
from .patches import patch_all
20✔
52
from .reporters import REPORTERS
20✔
53
from .reporters.core import PythonTaReporter
20✔
54
from .upload import upload_to_server
20✔
55
from .util.autoformat import run_autoformat
20✔
56

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

59

60
def check_errors(
20✔
61
    module_name: Union[list[str], str] = "",
62
    config: Union[dict[str, Any], str] = "",
63
    output: Optional[Union[str, IO]] = None,
64
    load_default_config: bool = True,
65
    autoformat: Optional[bool] = False,
66
) -> PythonTaReporter:
67
    """Check a module for errors, printing a report."""
68
    return _check(
20✔
69
        module_name=module_name,
70
        level="error",
71
        local_config=config,
72
        output=output,
73
        load_default_config=load_default_config,
74
        autoformat=autoformat,
75
    )
76

77

78
def check_all(
20✔
79
    module_name: Union[list[str], str] = "",
80
    config: Union[dict[str, Any], str] = "",
81
    output: Optional[Union[str, IO]] = None,
82
    load_default_config: bool = True,
83
    autoformat: Optional[bool] = False,
84
) -> PythonTaReporter:
85
    """Analyse one or more Python modules for code issues and display the results.
86

87
    Args:
88
        module_name:
89
            If an empty string (default), the module where this function is called is checked.
90
            If a non-empty string, it is interpreted as a path to a single Python module or a
91
            directory containing Python modules. If the latter, all Python modules in the directory
92
            are checked.
93
            If a list of strings, each string is interpreted as a path to a module or directory,
94
            and all modules across all paths are checked.
95
        config:
96
            If a string, a path to a configuration file to use.
97
            If a dictionary, a map of configuration options (each key is the name of an option).
98
        output:
99
            If a string, a path to a file to which the PythonTA report is written.
100
            If a typing.IO object, the report is written to this stream.
101
            If None, the report is written to standard out or automatically displayed in a
102
            web browser, depending on which reporter is used.
103
        load_default_config:
104
            If True (default), additional configuration passed with the ``config`` option is
105
            merged with the default PythonTA configuration file.
106
            If False, the default PythonTA configuration is not used.
107
        autoformat:
108
            If True, autoformat all modules using the black formatting tool before analyzing code.
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
    )
121

122

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

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

185
        return current_reporter
20✔
186
    except Exception as e:
20✔
187
        logging.error(
20✔
188
            "Unexpected error encountered! Please report this to your instructor (and attach the code that caused the error)."
189
        )
190
        logging.error('Error message: "{}"'.format(e))
20✔
191
        raise e
20✔
192

193

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

197
    Args:
198
        msg_id: The five-character error code, e.g. ``"E0401"``.
199
    """
200
    msg_url = HELP_URL + "#" + msg_id.lower()
20✔
201
    print("Opening {} in a browser.".format(msg_url))
20✔
202
    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