From 3c86dd6f5001c211fdfa6b7aba2c3f2e7aee253b Mon Sep 17 00:00:00 2001 From: erzoe Date: Tue, 18 Feb 2020 09:30:51 +0100 Subject: [PATCH 1/4] bugfix: _extract_traceback `index` was counting lines, not just of the traceback but of leading outputs as well (which are collected in `all_else`). Wether a line contained the location data or the corresponding source code was determined by checking if `index` was odd or even. This worked if there was an odd number of lines before the stacktrace but if there was no output before the stacktrace it skipped the first line of location info, interpreted the corresponding source code line as location info and the location info of the next entry as it's source code. Depending on the number of commas in the corresponding source code line this problem was more or less obvious. I have solved this by toggling a boolean variable called `location_info` instead of using `index`. The last entry of the stack trace is skipped because the 2nd for loop in _extract_traceback iterates over `entries[:-2]` where `entries[-1]` is the error message and `entries[-2]` is the last entry of the stack trace. --- backtrace.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/backtrace.py b/backtrace.py index a45fe5d..3701f50 100644 --- a/backtrace.py +++ b/backtrace.py @@ -218,21 +218,26 @@ def _extract_traceback(text): if text.count(TRACEBACK_IDENTIFIER) == 2: ignore_trace = True - for index, line in enumerate(text): + for line in text: if TRACEBACK_IDENTIFIER in line: if ignore_trace: ignore_trace = False continue capture = True + location_info = True # We're not capturing and making sure we only read lines # with spaces since, after the initial identifier, all traceback lines # contain a prefix spacing. elif capture and line.startswith(' '): - if index % 2 == 0: + if location_info: # Line containing a file, line and module. line = line.strip().strip('\n') - next_line = text[index + 1].strip('\n') - entries.append(line + ', ' + next_line) + entries.append(line) + else: + # The corresponding line of source code. + line = line.rstrip("\n") + entries[-1] += ', ' + line + location_info = not location_info elif capture: # Line containing the module call. entries.append(line) @@ -246,7 +251,7 @@ def _extract_traceback(text): # Build the traceback structure later passed for formatting. for index, line in enumerate(entries[:-2]): # TODO: This should be done in a _parse_entry function - element = line.split(',') + element = line.split(',', 3) element[0] = element[0].strip().lstrip('File').strip(' "') element[1] = element[1].strip().lstrip('line').strip() element[2] = element[2].strip().lstrip('in').strip() From a3d84af16765cdc029c6f49d3eeb9f937143f694 Mon Sep 17 00:00:00 2001 From: erzoe Date: Tue, 18 Feb 2020 10:47:31 +0100 Subject: [PATCH 2/4] changed comment This comment seems wrong to me. This block is executed if capture is False. capture is set to True when starting to parse the stack trace and never reset to False. Therefore it is executed for each line *before* the stack trace. Also, there should be nothing after the stack trace. --- backtrace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtrace.py b/backtrace.py index 3701f50..fc3b415 100644 --- a/backtrace.py +++ b/backtrace.py @@ -243,7 +243,7 @@ def _extract_traceback(text): entries.append(line) break else: - # Add everything else after the traceback. + # Add everything else before the traceback. all_else.append(line) traceback_entries = [] From 1b6e689a38f03a16c64f11c2875dbb0f654c4b42 Mon Sep 17 00:00:00 2001 From: erzoe Date: Tue, 18 Feb 2020 10:53:14 +0100 Subject: [PATCH 3/4] removed pointless strip strip() removes all white space, including linebreaks. Therefore there was nothing left to do for the strip('\n'). https://docs.python.org/3/library/stdtypes.html#str.strip --- backtrace.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtrace.py b/backtrace.py index fc3b415..a376bae 100644 --- a/backtrace.py +++ b/backtrace.py @@ -231,7 +231,7 @@ def _extract_traceback(text): elif capture and line.startswith(' '): if location_info: # Line containing a file, line and module. - line = line.strip().strip('\n') + line = line.strip() entries.append(line) else: # The corresponding line of source code. From 7e58cff1a8584ec783ba92956e329465c27243d8 Mon Sep 17 00:00:00 2001 From: erzoe Date: Tue, 18 Feb 2020 11:01:48 +0100 Subject: [PATCH 4/4] bugfix: don't crash on AssertionError AssertionErrors don't need to have an error message. --- backtrace.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backtrace.py b/backtrace.py index a376bae..316e959 100644 --- a/backtrace.py +++ b/backtrace.py @@ -269,7 +269,11 @@ def _stdin_hook(args): tb, all_else = _extract_traceback(output) sys.stdout.write(''.join(all_else)) - tpe, value = output[-1].strip('\n').split(': ', 1) + try: + tpe, value = output[-1].strip('\n').split(': ', 1) + except ValueError: + tpe = output[-1].strip('\n') + value = "" hook( reverse=args.reverse, align=args.align,