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

pyta-uoft / pyta / 27479146033

13 Jun 2026 09:07PM UTC coverage: 90.918% (-0.01%) from 90.929%
27479146033

Pull #1356

github

web-flow
Merge 691b90661 into 722e8c7db
Pull Request #1356: Modify PyTA report messages

17 of 18 new or added lines in 2 files covered. (94.44%)

6 existing lines in 3 files now uncovered.

3694 of 4063 relevant lines covered (90.92%)

17.67 hits per line

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

98.55
/packages/python-ta/src/python_ta/reporters/plain_reporter.py
1
from __future__ import annotations
20✔
2

3
import random
20✔
4
from typing import TYPE_CHECKING
20✔
5

6
from .core import NewMessage, PythonTaReporter
20✔
7
from .node_printers import LineType
20✔
8

9
if TYPE_CHECKING:
10
    from pylint.lint import PyLinter
11

12

13
class PlainReporter(PythonTaReporter):
20✔
14
    """Plain text reporter."""
15

16
    name = "pyta-plain"
20✔
17

18
    OUTPUT_FILENAME = "pyta_report.txt"
20✔
19

20
    NO_ERR_EMOJIS = ["🎉", "🥳", "🌟", "👍", "👏", "😊", "🎊", "🙌", "🕺"]
20✔
21

22
    # Rendering constants
23
    _SPACE = " "
20✔
24
    _BREAK = "\n"
20✔
25
    _COLOURING = {}
20✔
26
    code_err_title = "=== Code errors/forbidden usage (fix: high priority) ==="
20✔
27
    style_err_title = "=== Style/convention errors (fix: before submission) ==="
20✔
28
    no_snippet = "No code to display for this message." + _BREAK * 2
20✔
29

30
    def no_err_message(self) -> str:
20✔
31
        """Return the no errors message with a random emoji."""
32
        return "No problems detected, good job! " + random.choice(self.NO_ERR_EMOJIS)
20✔
33

34
    def print_messages(self, level: str = "all") -> None:
20✔
35
        """Print messages for the current file.
36

37
        If level == 'all', both errors and style errors are displayed. Otherwise,
38
        only errors are displayed.
39
        """
40
        error_msgs, style_msgs = self.group_messages(self.messages[self.current_file])
20✔
41

42
        result = "PyTA Report for: " + self._colourify("bold", self.current_file) + self._BREAK
20✔
43
        result += self._generate_report_date_time() + self._BREAK
20✔
44
        code_msgs_result = self._colour_messages_by_type(error_msgs)
20✔
45
        if code_msgs_result:
20✔
46
            result += self._colourify("code-heading", self.code_err_title + self._BREAK)
20✔
47
            result += code_msgs_result
20✔
48

49
        if level == "all":
20✔
50
            style_msgs_result = self._colour_messages_by_type(style_msgs)
20✔
51
            if style_msgs_result:
20✔
52
                result += self._colourify("style-heading", self.style_err_title + self._BREAK)
20✔
53
                result += style_msgs_result
20✔
54

55
        if not (code_msgs_result or style_msgs_result):
20✔
56
            result += self.no_err_message()
20✔
57

58
        self.writeln(result)
20✔
59
        self.out.flush()
20✔
60

61
    def _colour_messages_by_type(self, messages: dict[str, list[NewMessage]]) -> str:
20✔
62
        """
63
        Return string of properly formatted members of the messages dict
64
        (error or style) indicated by style.
65
        """
66
        max_messages = self.linter.config.pyta_number_of_messages
20✔
67

68
        result = ""
20✔
69
        for msg_id in messages:
20✔
70
            result += self._colourify("bold", msg_id)
20✔
71
            result += self._colourify("bold", " ({})  ".format(messages[msg_id][0].symbol))
20✔
72
            result += "Number of occurrences: {}.".format(len(messages[msg_id]))
20✔
73
            if (
20✔
74
                max_messages != 0
75
                and max_messages != float("inf")
76
                and max_messages < len(messages[msg_id])
77
            ):
78
                result += " (First {} shown).".format(max_messages)
20✔
79
            result += self._BREAK
20✔
80

81
            for i, msg in enumerate(messages[msg_id]):
20✔
82
                if max_messages != 0 and i == max_messages:
20✔
83
                    break
20✔
84

85
                # Use only explanation, without redundant accessory information
86
                msg_truncated = msg.msg.split("\n")[0]
20✔
87
                result += 2 * self._SPACE
20✔
88
                result += (
20✔
89
                    self._colourify("bold", "[Line {}] {}".format(msg.line, msg_truncated))
90
                    + self._BREAK
91
                )
92

93
                result += msg.snippet
20✔
94
                result += self._BREAK
20✔
95

96
        return result
20✔
97

98
    def _add_line(self, lineno: int, linetype: LineType, slice_: slice, text: str = "") -> str:
20✔
99
        """Format given source code line as specified and return as str.
100

101
        Called by _build_snippet, relies on _colourify.
102
        """
103
        lineno_spaces = self._PRE_LINE_NUM_SPACES + self._NUM_LENGTH_SPACES + self._AFTER_NUM_SPACES
20✔
104
        snippet_so_far = super()._add_line(lineno, linetype, slice_, text)
20✔
105
        if linetype == LineType.ERROR:
20✔
106
            start = slice_.start or 0
20✔
107
            prespace = (
20✔
108
                lineno_spaces + start
109
            ) * self._SPACE  # number 7 for prespaces included for adding line number
110
            snippet_so_far += self._overline_helper(text[slice_], prespace)
20✔
111

112
        elif linetype == LineType.DOCSTRING:
20✔
113
            prespace = (lineno_spaces + len(text) - len(text.lstrip(" "))) * self._SPACE
20✔
114
            snippet_so_far += self._overline_helper(text.lstrip(" "), prespace)
20✔
115

116
        return snippet_so_far
20✔
117

118
    def _overline_helper(self, text: str, prespace: str) -> str:
20✔
119
        """
120
        Helper method _add_line. Adds the Unicode U+203E (the overline character "‾") under any
121
        part that is highlighted as ERROR. Returns the corresponding snippet as a result.
122
        """
123
        overline = "‾" * len(text)
20✔
124
        return prespace + overline + self._BREAK
20✔
125

126

127
def register(linter: PyLinter):
20✔
UNCOV
128
    linter.register_reporter(PlainReporter)
×
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