Skip to content

Commit 687d50d

Browse files
macevhiczMHendricks
authored andcommitted
Prevent duplicate offending-line-output for console syntax errors
1 parent b7a0a50 commit 687d50d

File tree

1 file changed

+57
-28
lines changed

1 file changed

+57
-28
lines changed

preditor/gui/console_base.py

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,6 @@
3030
class ConsoleBase(QTextEdit):
3131
"""Base class for a text widget used to show stdout/stderr writes."""
3232

33-
workbox_pattern = re.compile(
34-
r'File "<Workbox(?:Selection)?>:(?P<workboxName>.*)", '
35-
r'line (?P<lineNum>\d{1,6})'
36-
r'(?P<inStr>, in)?'
37-
)
38-
"""For Traceback workbox lines, use this regex pattern, so we can extract
39-
workboxName and lineNum. Note that Syntax errors present slightly
40-
differently than other Exceptions.
41-
SyntaxErrors:
42-
- Do NOT include the text ", in" followed by a module
43-
- DO include the offending line of code
44-
Other Exceptions
45-
- DO include the text ", in" followed by a module
46-
- Do NOT include the offending line of code if from stdIn (ie
47-
a workbox)
48-
So we will use the presence of the text ", in" to tell use whether to
49-
fake the offending code line or not.
50-
"""
51-
52-
traceback_pattern = re.compile(
53-
r'File "(?P<filename>.*)", line (?P<lineNum>\d{1,10})(, in|\r\n|\n|$)'
54-
)
55-
"""A pattern to capture info from tracebacks. The newline/$ section
56-
handle SyntaxError output that does not include the `, in ...` portion."""
57-
5833
def __init__(self, parent: QWidget, controller: Optional[LoggerWindow] = None):
5934
super().__init__(parent)
6035
self.controller = controller
@@ -80,6 +55,48 @@ def __repr__(self):
8055

8156
return f"<{module}.{class_}{name} object at 0x{id(self):016X}>"
8257

58+
@classmethod
59+
def __defineRegexPatterns(cls):
60+
"""Define various regex patterns to use to determine if the msg to write
61+
is part of a traceback, and also to determine if it is from a workbox, or
62+
from the console.
63+
64+
We construct various parts of the patterns, and combine them into the
65+
final patterns. The workbox pattern and console pattern share the line
66+
and in_str parts.
67+
"""
68+
69+
# For Traceback workbox lines, use this regex pattern, so we can extract
70+
# workboxName and lineNum. Note that Syntax errors present slightly
71+
# differently than other Exceptions.
72+
# SyntaxErrors:
73+
# - Do NOT include the text ", in" followed by a module
74+
# - DO include the offending line of code
75+
# Other Exceptions
76+
# - DO include the text ", in" followed by a module
77+
# - Do NOT include the offending line of code if from stdIn (ie
78+
# a workbox)
79+
# So we will use the presence of the text ", in" to tell use whether to
80+
# fake the offending code line or not.
81+
82+
# Define pattern pieces
83+
console_pattern = r'File "<ConsolePrEdit>", '
84+
workbox_pattern = r'File "<Workbox(?:Selection)?>:(?P<workboxName>.*)", '
85+
line_pattern = r'line (?P<lineNum>\d{1,6})'
86+
in_str_pattern = r'(?P<inStr>, in)?'
87+
88+
# Put the pattern pieces to together to make patterns
89+
workbox_pattern = workbox_pattern + line_pattern + in_str_pattern
90+
cls.workbox_pattern = re.compile(workbox_pattern)
91+
92+
console_pattern = console_pattern + line_pattern + in_str_pattern
93+
cls.console_pattern = re.compile(console_pattern)
94+
95+
# Define a pattern to capture info from tracebacks. The newline/$ section
96+
# handle SyntaxError output that does not include the `, in ...` portion.
97+
pattern = r'File "(?P<filename>.*)", line (?P<lineNum>\d{1,10})(, in|\r\n|\n|$)'
98+
cls.traceback_pattern = re.compile(pattern)
99+
83100
def add_separator(self):
84101
"""Add a marker line for visual separation of console output."""
85102
# Ensure the input is written to the end of the document on a new line
@@ -624,9 +641,17 @@ def _write(self, msg, stream_type=StreamType.STDOUT):
624641
msg = "{}{}{}".format(msg, indent, workboxLine)
625642

626643
elif isConsolePrEdit:
627-
consoleLine = self.consoleLine
628-
indent = self.getIndentForCodeTracebackLine(msg)
629-
msg = "{}{}{}\n".format(msg, indent, consoleLine)
644+
# Syntax error tracebacks are different than other Exception.
645+
# They don't include ", in ..." and are issued differently than
646+
# other Exceptions, in that they will issue the final piece of
647+
# offending code, whereas other Exceptions do not, for some
648+
# reason. They do not need, and shouldn't, be handled here.
649+
match = self.console_pattern.search(msg)
650+
inStr = match.groupdict().get("inStr", "")
651+
if inStr:
652+
consoleLine = self.consoleLine
653+
indent = self.getIndentForCodeTracebackLine(msg)
654+
msg = "{}{}{}\n".format(msg, indent, consoleLine)
630655

631656
# To make it easier to see relevant lines of a traceback, optionally insert
632657
# a newline separating internal PrEditor code from the code run by user.
@@ -720,3 +745,7 @@ def _write(self, msg, stream_type=StreamType.STDOUT):
720745
"""Should this console print captured exceptions? Only use this if
721746
stream_echo_stderr is disabled or you likely will get duplicate output.
722747
"""
748+
749+
750+
# Build and add the class properties for regex patterns so subclasses can use them.
751+
ConsoleBase._ConsoleBase__defineRegexPatterns()

0 commit comments

Comments
 (0)