@@ -622,10 +622,14 @@ class TracebackException:
622622 occurred.
623623 - :attr:`lineno` For syntax errors - the linenumber where the error
624624 occurred.
625+ - :attr:`end_lineno` For syntax errors - the end linenumber where the error
626+ occurred. Can be `None` if not present.
625627 - :attr:`text` For syntax errors - the text where the error
626628 occurred.
627629 - :attr:`offset` For syntax errors - the offset into the text where the
628630 error occurred.
631+ - :attr:`end_offset` For syntax errors - the offset into the text where the
632+ error occurred. Can be `None` if not present.
629633 - :attr:`msg` For syntax errors - the compiler error message.
630634 """
631635
@@ -655,8 +659,11 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None,
655659 self .filename = exc_value .filename
656660 lno = exc_value .lineno
657661 self .lineno = str (lno ) if lno is not None else None
662+ end_lno = exc_value .end_lineno
663+ self .end_lineno = str (end_lno ) if end_lno is not None else None
658664 self .text = exc_value .text
659665 self .offset = exc_value .offset
666+ self .end_offset = exc_value .end_offset
660667 self .msg = exc_value .msg
661668 if lookup_lines :
662669 self ._load_lines ()
@@ -771,12 +778,20 @@ def _format_syntax_error(self, stype):
771778 ltext = rtext .lstrip (' \n \f ' )
772779 spaces = len (rtext ) - len (ltext )
773780 yield ' {}\n ' .format (ltext )
774- # Convert 1-based column offset to 0-based index into stripped text
775- caret = (self .offset or 0 ) - 1 - spaces
776- if caret >= 0 :
777- # non-space whitespace (likes tabs) must be kept for alignment
778- caretspace = ((c if c .isspace () else ' ' ) for c in ltext [:caret ])
779- yield ' {}^\n ' .format ('' .join (caretspace ))
781+
782+ if self .offset is not None :
783+ offset = self .offset
784+ end_offset = self .end_offset if self .end_offset is not None else offset
785+ if offset == end_offset or end_offset == - 1 :
786+ end_offset = offset + 1
787+
788+ # Convert 1-based column offset to 0-based index into stripped text
789+ colno = offset - 1 - spaces
790+ end_colno = end_offset - 1 - spaces
791+ if colno >= 0 :
792+ # non-space whitespace (likes tabs) must be kept for alignment
793+ caretspace = ((c if c .isspace () else ' ' ) for c in ltext [:colno ])
794+ yield ' {}{}' .format ("" .join (caretspace ), ('^' * (end_colno - colno ) + "\n " ))
780795 msg = self .msg or "<no detail available>"
781796 yield "{}: {}{}\n " .format (stype , msg , filename_suffix )
782797
0 commit comments