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

pyta-uoft / pyta / 19300648625

12 Nov 2025 02:22PM UTC coverage: 93.909% (-0.4%) from 94.325%
19300648625

push

github

web-flow
Optimized performance for 'test_examples.py' (#1251)

8 of 8 new or added lines in 2 files covered. (100.0%)

16 existing lines in 7 files now uncovered.

3515 of 3743 relevant lines covered (93.91%)

17.81 hits per line

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

99.59
/python_ta/reporters/node_printers.py
1
"""Specify how errors should be rendered."""
2

3
import re
20✔
4
from enum import Enum
20✔
5

6
from astroid import nodes
20✔
7

8
NEW_BLANK_LINE_MESSAGE = "# INSERT NEW BLANK LINE HERE"
20✔
9
MAX_SNIPPET_LINES = 10
20✔
10

11

12
def render_message(msg, node, source_lines, config=None):
20✔
13
    """Render a message based on type."""
14
    renderer = CUSTOM_MESSAGES.get(msg.symbol, render_generic)
20✔
15
    yield from renderer(msg, node, source_lines, config)
20✔
16

17

18
def render_generic(msg, node=None, source_lines=None, config=None):
20✔
19
    """Default rendering for a message."""
20
    if node is not None:
20✔
21
        start_line, start_col = node.fromlineno, node.col_offset
20✔
22

23
        if isinstance(node, (nodes.FunctionDef, nodes.ClassDef)):
20✔
24
            end_line, end_col = start_line, None
20✔
25
        else:
26
            end_line, end_col = node.end_lineno, node.end_col_offset
20✔
27

28
        # Display up to 2 lines before node for context:
29
        yield from render_context(start_line - 2, start_line, source_lines)
20✔
30

31
        if start_line == end_line:
20✔
32
            yield (
20✔
33
                start_line,
34
                slice(start_col, end_col),
35
                LineType.ERROR,
36
                source_lines[start_line - 1],
37
            )
38
        else:
39
            yield (start_line, slice(start_col, None), LineType.ERROR, source_lines[start_line - 1])
20✔
40
            yield from (
20✔
41
                (line, slice(None, None), LineType.ERROR, source_lines[line - 1])
42
                for line in range(start_line + 1, end_line)
43
            )
44
            yield (end_line, slice(None, end_col), LineType.ERROR, source_lines[end_line - 1])
20✔
45

46
        # Display up to 2 lines after node for context:
47
        yield from render_context(end_line + 1, end_line + 3, source_lines)
20✔
48

49
    else:
50
        line = msg.line
20✔
51
        yield from render_context(line - 2, line, source_lines)
20✔
52
        yield (line, slice(None, None), LineType.ERROR, source_lines[line - 1])
20✔
53
        yield from render_context(line + 1, line + 3, source_lines)
20✔
54

55

56
def render_missing_docstring(_msg, node, source_lines=None, config=None):
20✔
57
    """Render a missing docstring message."""
58
    if isinstance(node, nodes.Module):
20✔
59
        yield (None, slice(None, None), LineType.DOCSTRING, '"""YOUR DOCSTRING HERE"""')
20✔
60
        yield from render_context(1, 3, source_lines)
20✔
61
    elif isinstance(node, nodes.ClassDef) or isinstance(node, nodes.FunctionDef):
20✔
62
        start = node.fromlineno
20✔
63
        end = node.body[0].fromlineno
20✔
64
        yield from render_context(start, end, source_lines)
20✔
65
        # Calculate indentation
66
        body = source_lines[end - 1]
20✔
67
        indentation = len(body) - len(body.lstrip())
20✔
68
        yield (
20✔
69
            None,
70
            slice(None, None),
71
            LineType.DOCSTRING,
72
            body[:indentation] + '"""YOUR DOCSTRING HERE"""',
73
        )
74
        yield from render_context(end, end + 2, source_lines)
20✔
75

76

77
def render_line_too_long(msg, node, source_lines=None, config=None):
20✔
78
    """Render a line too long message."""
79
    line = msg.line
20✔
80

81
    # Set start_index to configured max-line-length and end_index to length of line
82
    start_index, end_index = config.max_line_length, len(source_lines[line - 1])
20✔
83

84
    yield from render_context(line - 2, line, source_lines)
20✔
85
    yield (line, slice(start_index, end_index), LineType.ERROR, source_lines[line - 1])
20✔
86
    yield from render_context(line + 1, line + 2, source_lines)
20✔
87

88

89
def render_trailing_newlines(msg, _node, source_lines=None, config=None):
20✔
90
    """Render a trailing newlines message."""
91
    # Get start of trailing newlines
92
    half_threshold = MAX_SNIPPET_LINES // 2
20✔
93
    total_lines = len(source_lines) + 1  # Accommodating for last blank line
20✔
94

95
    start_line = len(source_lines)
20✔
96
    while start_line > 0 and source_lines[start_line - 2].strip() == "":
20✔
97
        start_line -= 1
20✔
98

99
    num_trailing_newlines = total_lines - start_line
20✔
100

101
    yield from render_context(start_line - 2, start_line + 1, source_lines)
20✔
102

103
    for line in range(start_line, start_line + min(half_threshold, num_trailing_newlines - 1)):
20✔
104
        yield (
20✔
105
            line + 1,
106
            slice(None, None),
107
            LineType.ERROR,
108
            source_lines[line] + "# DELETE THIS LINE",
109
        )
110

111
    if num_trailing_newlines > MAX_SNIPPET_LINES:
20✔
112
        yield ("", slice(None, None), LineType.OTHER, "...")
20✔
113

114
    for line in range(
20✔
115
        total_lines - min(half_threshold, num_trailing_newlines - half_threshold),
116
        len(source_lines),
117
    ):
118
        yield (
20✔
119
            line + 1,
120
            slice(None, None),
121
            LineType.ERROR,
122
            source_lines[line] + "# DELETE THIS LINE",
123
        )
124

125
    # Accommodate for last blank line
126
    yield (total_lines, slice(None, None), LineType.ERROR, "# DELETE THIS LINE")
20✔
127

128

129
def render_trailing_whitespace(msg, _node, source_lines=None, config=None):
20✔
130
    """Render a trailing whitespace message."""
131
    line = msg.line
20✔
132
    start_index, end_index = len(source_lines[line - 1].rstrip()), len(source_lines[line - 1])
20✔
133
    yield from render_context(line - 1, line, source_lines)
20✔
134
    yield (line, slice(start_index, end_index), LineType.ERROR, source_lines[line - 1])
20✔
135
    yield from render_context(line + 1, line + 2, source_lines)
20✔
136

137

138
def render_context(start, stop, source_lines):
20✔
139
    """Helper for rendering context lines."""
140
    start, stop = max(start, 1), min(stop, len(source_lines))
20✔
141
    yield from (
20✔
142
        (line, slice(None, None), LineType.CONTEXT, source_lines[line - 1])
143
        for line in range(start, stop)
144
    )
145

146

147
def render_missing_return_type(_msg, node, source_lines=None, config=None):
20✔
148
    """Render a type annotation return message."""
149
    start_line, start_col = node.fromlineno, node.parent.col_offset
20✔
150
    end_line, end_col = node.end_lineno, node.end_col_offset
20✔
151

152
    # Display up to 2 lines before node for context:
153
    yield from render_context(start_line - 2, start_line, source_lines)
20✔
154
    yield from (
20✔
155
        (line, slice(None, end_col + 1), LineType.ERROR, source_lines[line - 1])
156
        for line in range(start_line, end_line + 1)
157
    )
158
    # Display up to 2 lines after node for context:
159
    yield from render_context(end_line + 1, end_line + 3, source_lines)
20✔
160

161

162
def render_too_many_arguments(msg, node, source_lines=None, config=None):
20✔
163
    """Render a too many arguments message."""
164
    # node is a FunctionDef node so replace it with its Arguments child
165
    yield from render_generic(msg, node.args, source_lines, config)
20✔
166

167

168
def render_missing_space_in_doctest(msg, _node, source_lines=None, config=None):
20✔
169
    """Render a missing space in doctest message"""
170
    line = msg.line
20✔
171

172
    # Display 2 lines before and after the erroneous line
173
    yield from render_context(line - 2, line, source_lines)
20✔
174
    yield (line, slice(None, None), LineType.ERROR, source_lines[line - 1])
20✔
175
    yield from render_context(line + 1, line + 3, source_lines)
20✔
176

177

178
def render_pep8_errors(msg, _node, source_lines=None, config=None):
20✔
179
    """Render a PEP8 error message."""
180
    # Extract the raw error message
181
    raw_msg = getattr(msg, "msg", "")
20✔
182

183
    # Search for the first appearance of the error code in the extracted error text
184
    matched_error = re.search(r"(E\d{3})", raw_msg)
20✔
185
    if matched_error:
20✔
186
        error_code = matched_error.group(1)
20✔
187
        # Render the appropriate error through the RENDERERS dict
188
        if error_code in RENDERERS:
20✔
189
            line = msg.line
20✔
190
            require_source_lines_renderers = {"E302", "E303", "E304", "E305"}
20✔
191
            if error_code in require_source_lines_renderers:
20✔
192
                yield from RENDERERS[error_code](msg, line, source_lines)
20✔
193
            else:
194
                col = msg.column
20✔
195
                yield from render_context(line - 3, line, source_lines)
20✔
196
                yield from RENDERERS[error_code](line, col, source_lines[line - 1])
20✔
197
                yield from render_context(line + 1, line + 3, source_lines)
20✔
198
            return
20✔
199

200
    # If none of the error codes were present, render the error using the generic error renderer
201
    yield from render_generic(msg, _node, source_lines)
20✔
202

203

204
def render_blank_line(line):
20✔
205
    """Render a blank line for a PEP8 error message."""
206
    yield (line + 1, slice(None, None), LineType.ERROR, " " * 28)
20✔
207

208

209
def render_pep8_errors_e101_and_e123_and_e116(line, col, source_line=None):
20✔
210
    """Render a PEP8 indentation contains mixed spaces and tabs message
211
    AND a PEP8 closing bracket does not match indentation of opening bracket's line message."""
212
    curr_idx = len(source_line) - len(source_line.lstrip())
20✔
213
    yield (line, slice(0, curr_idx), LineType.ERROR, source_line)
20✔
214

215

216
def render_pep8_errors_e115(line, col, source_line=None):
20✔
217
    """Render a PEP8 expected an indented block (comment) message."""
218
    yield (
20✔
219
        line,
220
        slice(0, len(source_line)),
221
        LineType.ERROR,
222
        source_line + "  # INDENT THIS LINE",
223
    )
224

225

226
def render_pep8_errors_e122_and_e127_and_e131(line, col, source_line=None):
20✔
227
    """
228
    Render a PEP8 continuation line missing indentation or outdented message, a line over-indented for visual indent
229
    message, and a continuation line unaligned for hanging indent message.
230
    """
231
    curr_line_start_index = len(source_line) - len(source_line.lstrip())
20✔
232
    end_index = curr_line_start_index if curr_line_start_index > 0 else len(source_line)
20✔
233
    yield (
20✔
234
        line,
235
        slice(0, end_index),
236
        LineType.ERROR,
237
        source_line,
238
    )
239

240

241
def render_pep8_errors_e124(line, col, source_line=None):
20✔
242
    """Render a PEP8 closing bracket does not match visual indentation message."""
243
    yield (line, slice(col, col + 1), LineType.ERROR, source_line)
20✔
244

245

246
def render_pep8_errors_e125_and_e129(line, col, source_line=None):
20✔
247
    """Render a PEP8 continuation line with same indent as next logical line message
248
    AND a PEP8 visually indented line with same indent as next logical line messsage"""
249
    curr_idx = len(source_line) - len(source_line.lstrip())
20✔
250
    yield (
20✔
251
        line,
252
        slice(curr_idx, len(source_line)),
253
        LineType.ERROR,
254
        source_line + " " * 2 + "# INDENT THIS LINE",
255
    )
256

257

258
def render_pep8_errors_e128(line, col, source_line):
20✔
259
    """Render a PEP8 continuation line under-indented for visual indent message."""
260
    yield (line, slice(0, col if col != 0 else None), LineType.ERROR, source_line)
20✔
261

262

263
def render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272(line, col, source_line=None):
20✔
264
    """Render a PEP8 whitespace after '(' message,
265
    a PEP8 whitespace before ')' message,
266
    a PEP8 whitespace before ‘,’, ‘;’, or ‘:’ message,
267
    a PEP8 whitespace before '(' message,
268
    a PEP8 multiple spaces before operator message,
269
    a PEP8 multiple spaces after keyword message,
270
    a PEP8 multiple spaces before keyword message
271
    and a PEP8 multiple spaces after operator message."""
272
    curr_idx = col + len(source_line[col:]) - len(source_line[col:].lstrip())
20✔
273

274
    yield (line, slice(col, curr_idx), LineType.ERROR, source_line)
20✔
275

276

277
def render_pep8_errors_e204(line, col, source_line=None):
20✔
278
    """Render a PEP8 whitespace after decorator '@' message"""
279
    # calculates the length of the leading whitespaces by subtracting the length of everything after the first character after stripping all leading whitespaces from the total line length
280
    curr_idx = col + len(source_line[col:]) - len(source_line[col + 1 :].lstrip())
20✔
281

282
    yield (line, slice(col, curr_idx), LineType.ERROR, source_line)
20✔
283

284

285
def render_pep8_errors_e223_and_e274(line, col, source_line=None):
20✔
286
    """Render a PEP8 tab before operator message and a PEP8 tab before keyword message."""
287
    curr_idx = col + len(source_line[col:]) - len(source_line[col:].lstrip("\t"))
20✔
288

289
    yield (line, slice(col, curr_idx), LineType.ERROR, source_line)
20✔
290

291

292
def render_pep8_errors_e224_and_e273(line, col, source_line):
20✔
293
    """Render a PEP8 tab after operator message and a PEP8 tab after keyword message."""
294
    curr_idx = col + len(source_line[col:]) - len(source_line[col:].lstrip("\t"))
20✔
295

296
    yield (line, slice(col, curr_idx), LineType.ERROR, source_line)
20✔
297

298

299
def render_pep8_errors_e225(line, col, source_line):
20✔
300
    """Render a PEP8 missing whitespace around operator message"""
301
    curr_idx = col + 1
20✔
302

303
    two_char_operators = {
20✔
304
        "==",
305
        ">=",
306
        "<=",
307
        "!=",
308
        ":=",
309
        "&=",
310
        "->",
311
        "%=",
312
        "/=",
313
        "+=",
314
        "-=",
315
        "*=",
316
        "|=",
317
        "^=",
318
        "@=",
319
    }
320
    three_char_operators = {"//=", ">>=", "<<=", "**="}
20✔
321
    # highlight multiple characters for operators that are longer than one character
322
    if source_line[col : col + 2] in two_char_operators:
20✔
323
        curr_idx += 1
20✔
324
    elif source_line[col : col + 3] in three_char_operators:
20✔
325
        curr_idx += 2
20✔
326

327
    yield (line, slice(col, curr_idx), LineType.ERROR, source_line)
20✔
328

329

330
def render_pep8_errors_e226(line, col, source_line):
20✔
331
    """Render a PEP8 missing whitespace around arithmetic operator message"""
332
    end_idx = col + 1
20✔
333

334
    multi_char_operators = {"//"}
20✔
335
    # highlight multiple characters for arithmetic operators that are longer than one character
336
    if source_line[col : col + 2] in multi_char_operators:
20✔
337
        end_idx += 1
20✔
338

339
    yield (line, slice(col, end_idx), LineType.ERROR, source_line)
20✔
340

341

342
def render_pep8_errors_e227(line, col, source_line=None):
20✔
343
    """Render a PEP8 missing whitespace around bitwise or shift operator message."""
344
    # Check which operator to get the correct range of the line to highlight.
345
    # Default highlight is one character, but may be updated to two.
346
    # Note that only binary bitwise operators that are more than one character are included.
347
    operators = {">>", "<<"}
20✔
348
    end_idx = col + 1
20✔
349
    end_idx = end_idx + 1 if source_line[col : col + 2] in operators else end_idx
20✔
350

351
    yield (line, slice(col, end_idx), LineType.ERROR, source_line)
20✔
352

353

354
def render_pep8_errors_e228(line, col, source_line=None):
20✔
355
    """Render a PEP8 missing whitespace around modulo operator message."""
356
    yield (
20✔
357
        line,
358
        slice(col, col + 1),
359
        LineType.ERROR,
360
        source_line + "  # INSERT A SPACE BEFORE AND AFTER THE % OPERATOR",
361
    )
362

363

364
def render_pep8_errors_e231(line, col, source_line=None):
20✔
365
    curr_idx = col + 1
20✔
366

367
    yield (line, slice(col, curr_idx), LineType.ERROR, source_line)
20✔
368

369

370
def render_pep8_errors_e251(line, col, source_line=None):
20✔
371
    """Render a PEP8 unexpected spaces around keyword / parameter equals message."""
372
    equals_sign_idx = source_line[col:].find("=")
20✔
373
    code = source_line[col : col + equals_sign_idx if equals_sign_idx != -1 else None]
20✔
374
    end_idx = col + len(code) - len(code.lstrip())
20✔
375

376
    yield (line, slice(col, end_idx), LineType.ERROR, source_line)
20✔
377

378

379
def render_pep8_errors_e261(line, col, source_line=None):
20✔
380
    """Render a PEP8 at least two spaces before inline comment message."""
381
    yield (
20✔
382
        line,
383
        slice(col, len(source_line)),
384
        LineType.ERROR,
385
        source_line + "  # INSERT TWO SPACES BEFORE THE '#'",
386
    )
387

388

389
def render_pep8_errors_e262(line, col, source_line=None):
20✔
390
    """Render a PEP8 inline comment should start with '# ' message"""
391
    keyword_idx = len(source_line) - len(source_line[col:].lstrip("# \t"))
20✔
392

393
    yield (line, slice(col, keyword_idx), LineType.ERROR, source_line)
20✔
394

395

396
def render_pep8_errors_e265(line, col, source_line=None):
20✔
397
    """Render a PEP8 block comment should start with '# ' message."""
398
    yield (
20✔
399
        line,
400
        slice(0, len(source_line)),
401
        LineType.ERROR,
402
        source_line + "  # INSERT SPACE AFTER THE '#'",
403
    )
404

405

406
def render_pep8_errors_e266(line, col, source_line=None):
20✔
407
    """Render a PEP8 too many leading ‘#’ for block comment message."""
408
    curr_idx = col + len(source_line[col:]) - len(source_line[col:].lstrip("#"))
20✔
409

410
    yield (
20✔
411
        line,
412
        slice(col, curr_idx),
413
        LineType.ERROR,
414
        source_line + "  # THERE SHOULD ONLY BE ONE '#'",
415
    )
416

417

418
def render_pep8_errors_e275(line, col, source_line=None):
20✔
419
    """Render a PEP8 missing whitespace after keyword message."""
420
    # Get the range for highlighting the corresponding keyword.
421
    keyword = source_line[:col].split()[-1]
20✔
422
    keyword_idx = source_line.index(keyword)
20✔
423

424
    yield (
20✔
425
        line,
426
        slice(keyword_idx, col),
427
        LineType.ERROR,
428
        source_line + "  # INSERT SPACE AFTER KEYWORD",
429
    )
430

431

432
def render_pep8_errors_e301(line, col, source_line=None):
20✔
433
    """Render a PEP8 expected 1 blank line message."""
434
    indentation = len(source_line) - len(source_line.lstrip())
20✔
435
    yield (
20✔
436
        None,
437
        slice(None, None),
438
        LineType.ERROR,
439
        source_line[:indentation] + NEW_BLANK_LINE_MESSAGE,
440
    )
441

442

443
def render_pep8_errors_e302(msg, line, source_lines=None):
20✔
444
    """Render a PEP8 expected 2 blank lines message."""
445
    if "found 0" in msg.msg:
20✔
446
        yield from render_context(line - 3, line, source_lines)
20✔
447
        yield from (
20✔
448
            (
449
                None,
450
                slice(None, None),
451
                LineType.ERROR,
452
                NEW_BLANK_LINE_MESSAGE,
453
            )
454
            for _ in range(0, 2)
455
        )
456
    else:
457
        yield from render_context(line - 3, line - 1, source_lines)
20✔
458
        yield from render_blank_line(line)
20✔
459
        yield (None, slice(None, None), LineType.ERROR, NEW_BLANK_LINE_MESSAGE)
20✔
460
    yield from render_context(line, line + 3, source_lines)
20✔
461

462

463
def render_pep8_errors_e303_and_e304(msg, line, source_lines=None):
20✔
464
    """Render a PEP8 too many blank lines message
465
    and a PEP8 blank lines found after function decorator message
466
    """
467
    half_threshold = MAX_SNIPPET_LINES // 2
20✔
468

469
    dline = line
20✔
470
    while source_lines[dline - 2].strip() == "":
20✔
471
        dline -= 1
20✔
472

473
    end_line = line - 1
20✔
474
    # Determine which PEP8 error we are rendering; adjust first offending blank line and last context line indices accordingly
475
    if "@" in source_lines[dline - 2]:
20✔
476
        # E304 Case: First blank line should be included in ERROR lines, and excluded from Context lines
477
        num_blank_lines = end_line - dline + 1
20✔
478
        end_context = dline
20✔
479
    else:
480
        # E304 Case: First blank line should be excluded from ERROR lines, and included as a Context line
481
        num_blank_lines = end_line - dline
20✔
482
        end_context = dline + 1
20✔
483

484
    yield from render_context(dline - 3, end_context, source_lines)
20✔
485

486
    for curr_line in range(dline, dline + min(half_threshold, num_blank_lines)):
20✔
487
        yield (curr_line + 1, slice(None, None), LineType.ERROR, "# DELETE THIS LINE")
20✔
488

489
    if num_blank_lines > MAX_SNIPPET_LINES:
20✔
490
        yield ("", slice(None, None), LineType.OTHER, "...")
20✔
491

492
    for curr_line in range(
20✔
493
        end_line - min(half_threshold, num_blank_lines - half_threshold),
494
        end_line,
495
    ):
496
        yield (curr_line + 1, slice(None, None), LineType.ERROR, "# DELETE THIS LINE")
20✔
497

498
    yield from render_context(line, line + 3, source_lines)
20✔
499

500

501
def render_pep8_errors_e305(msg, line, source_lines=None):
20✔
502
    """Render a PEP8 expected 2 blank lines after class or function definition message."""
503
    if "found 0" in msg.msg:
20✔
504
        yield from render_context(line - 3, line, source_lines)
20✔
505
        yield from (
20✔
506
            (
507
                None,
508
                slice(None, None),
509
                LineType.ERROR,
510
                NEW_BLANK_LINE_MESSAGE,
511
            )
512
            for _ in range(0, 2)
513
        )
514
    else:
515
        yield from render_context(line - 3, line - 1, source_lines)
20✔
516
        yield from render_blank_line(line)
20✔
517
        yield (None, slice(None, None), LineType.ERROR, NEW_BLANK_LINE_MESSAGE)
20✔
518
    yield from render_context(line, line + 3, source_lines)
20✔
519

520

521
def render_pep8_errors_e306(line, col, source_line=None):
20✔
522
    """Render a PEP8 expected 1 blank line before a nested definition message."""
523
    indentation = len(source_line) - len(source_line.lstrip())
20✔
524
    yield (
20✔
525
        None,
526
        slice(None, None),
527
        LineType.ERROR,
528
        source_line[:indentation] + NEW_BLANK_LINE_MESSAGE,
529
    )
530

531

532
def render_pep8_errors_e502(line, col, source_line=None):
20✔
533
    """Render a PEP8 the backslash is redundant between brackets."""
534
    yield (line, slice(col, col + 1), LineType.ERROR, source_line)
20✔
535

536

537
def render_missing_return_statement(msg, node, source_lines=None, config=None):
20✔
538
    """
539
    Render a missing return statements message
540
    """
541
    yield from render_context(msg.line, msg.end_line + 1, source_lines)
20✔
542

543
    # calculate indentation for the insertion point
544
    body = source_lines[msg.end_line - 1]
20✔
545
    indentation = len(source_lines[msg.line - 1]) - len(source_lines[msg.line - 1].lstrip())
20✔
546

547
    # determine whether reaching the end of function
548
    first_statement_line = node.end_lineno if len(node.body) == 0 else node.body[0].lineno
20✔
549
    function_indentation = len(source_lines[first_statement_line - 1]) - len(
20✔
550
        source_lines[first_statement_line - 1].lstrip()
551
    )
552

553
    if msg.end_line == node.end_lineno and indentation == function_indentation:
20✔
554
        insertion_text = body[:indentation] + "# INSERT RETURN STATEMENT HERE"
20✔
555
    else:
UNCOV
556
        insertion_text = body[:indentation] + "# INSERT RETURN STATEMENT HERE (OR BELOW)"
×
557

558
    # insert the message
559
    yield (
20✔
560
        None,
561
        slice(indentation, None),
562
        LineType.ERROR,
563
        insertion_text,
564
    )
565

566
    yield from render_context(msg.end_line + 1, msg.end_line + 3, source_lines)
20✔
567

568

569
def render_static_type_checker_errors(msg, _node=None, source_lines=None, config=None):
20✔
570
    """Render a message for incompatible argument types."""
571
    start_line = msg.line
20✔
572
    start_col = msg.column
20✔
573
    end_line = msg.end_line
20✔
574
    end_col = msg.end_column
20✔
575
    yield from render_context(start_line - 2, start_line, source_lines)
20✔
576

577
    if start_line == end_line:
20✔
578
        yield (
20✔
579
            start_line,
580
            slice(start_col - 1, end_col),
581
            LineType.ERROR,
582
            source_lines[start_line - 1],
583
        )
584
    else:
585
        yield (start_line, slice(start_col - 1, None), LineType.ERROR, source_lines[start_line - 1])
20✔
586
        yield from (
20✔
587
            (line, slice(None, None), LineType.ERROR, source_lines)
588
            for line in range(start_line + 1, end_line)
589
        )
590
        yield (end_line, slice(None, end_col), LineType.ERROR, source_lines[end_line - 1])
20✔
591
    yield from render_context(end_line + 1, end_line + 3, source_lines)
20✔
592

593

594
CUSTOM_MESSAGES = {
20✔
595
    "missing-module-docstring": render_missing_docstring,
596
    "missing-class-docstring": render_missing_docstring,
597
    "missing-function-docstring": render_missing_docstring,
598
    "line-too-long": render_line_too_long,
599
    "trailing-newlines": render_trailing_newlines,
600
    "trailing-whitespace": render_trailing_whitespace,
601
    "missing-return-type": render_missing_return_type,
602
    "too-many-arguments": render_too_many_arguments,
603
    "missing-space-in-doctest": render_missing_space_in_doctest,
604
    "pep8-errors": render_pep8_errors,
605
    "missing-return-statement": render_missing_return_statement,
606
    "incompatible-argument-type": render_static_type_checker_errors,
607
    "incompatible-assignment": render_static_type_checker_errors,
608
    "list-item-type-mismatch": render_static_type_checker_errors,
609
    "unsupported-operand-types": render_static_type_checker_errors,
610
    "union-attr-error": render_static_type_checker_errors,
611
    "dict-item-type-mismatch": render_static_type_checker_errors,
612
}
613

614
RENDERERS = {
20✔
615
    "E101": render_pep8_errors_e101_and_e123_and_e116,
616
    "E123": render_pep8_errors_e101_and_e123_and_e116,
617
    "E115": render_pep8_errors_e115,
618
    "E116": render_pep8_errors_e101_and_e123_and_e116,
619
    "E122": render_pep8_errors_e122_and_e127_and_e131,
620
    "E127": render_pep8_errors_e122_and_e127_and_e131,
621
    "E131": render_pep8_errors_e122_and_e127_and_e131,
622
    "E124": render_pep8_errors_e124,
623
    "E125": render_pep8_errors_e125_and_e129,
624
    "E129": render_pep8_errors_e125_and_e129,
625
    "E128": render_pep8_errors_e128,
626
    "E201": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
627
    "E202": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
628
    "E203": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
629
    "E204": render_pep8_errors_e204,
630
    "E211": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
631
    "E221": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
632
    "E222": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
633
    "E223": render_pep8_errors_e223_and_e274,
634
    "E224": render_pep8_errors_e224_and_e273,
635
    "E225": render_pep8_errors_e225,
636
    "E231": render_pep8_errors_e231,
637
    "E273": render_pep8_errors_e224_and_e273,
638
    "E274": render_pep8_errors_e223_and_e274,
639
    "E226": render_pep8_errors_e226,
640
    "E227": render_pep8_errors_e227,
641
    "E228": render_pep8_errors_e228,
642
    "E251": render_pep8_errors_e251,
643
    "E261": render_pep8_errors_e261,
644
    "E262": render_pep8_errors_e262,
645
    "E265": render_pep8_errors_e265,
646
    "E266": render_pep8_errors_e266,
647
    "E271": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
648
    "E272": render_pep8_errors_e201_e202_e203_e211_e221_e222_e271_e272,
649
    "E275": render_pep8_errors_e275,
650
    "E301": render_pep8_errors_e301,
651
    "E302": render_pep8_errors_e302,
652
    "E303": render_pep8_errors_e303_and_e304,
653
    "E304": render_pep8_errors_e303_and_e304,
654
    "E305": render_pep8_errors_e305,
655
    "E306": render_pep8_errors_e306,
656
    "E502": render_pep8_errors_e502,
657
}
658

659

660
class LineType(Enum):
20✔
661
    """An enumeration for _add_line method line types."""
662

663
    ERROR = 1  # line with error
20✔
664
    CONTEXT = 2  # non-error/other line added for context
20✔
665
    OTHER = 3  # line included in source but not error
20✔
666
    ELLIPSIS = 5  # code replaced with ellipsis
20✔
667
    DOCSTRING = 6  # docstring needed warning
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