@@ -214,28 +214,38 @@ def get_python_framesummary(self) -> traceback.FrameSummary:
214214 stack_summary = traceback .extract_tb (self ._rawentry , limit = 1 )
215215 return stack_summary [0 ]
216216
217- @property
218- def end_lineno_relative (self ) -> int | None :
219- if sys .version_info < (3 , 11 ):
220- return None
221- frame_summary = self .get_python_framesummary ()
222- if frame_summary .end_lineno is None :
217+ # Column and end line numbers introduced in python 3.11
218+ if sys .version_info < (3 , 11 ):
219+
220+ @property
221+ def end_lineno_relative (self ) -> int | None :
223222 return None
224- return frame_summary .end_lineno - 1 - self .frame .code .firstlineno
225223
226- @property
227- def colno (self ) -> int | None :
228- """Starting byte offset of the expression in the traceback entry."""
229- if sys .version_info < (3 , 11 ):
224+ @property
225+ def colno (self ) -> int | None :
230226 return None
231- return self .get_python_framesummary ().colno
232227
233- @property
234- def end_colno (self ) -> int | None :
235- """Ending byte offset of the expression in the traceback entry."""
236- if sys .version_info < (3 , 11 ):
228+ @property
229+ def end_colno (self ) -> int | None :
237230 return None
238- return self .get_python_framesummary ().end_colno
231+ else :
232+
233+ @property
234+ def end_lineno_relative (self ) -> int | None :
235+ frame_summary = self .get_python_framesummary ()
236+ if frame_summary .end_lineno is None :
237+ return None
238+ return frame_summary .end_lineno - 1 - self .frame .code .firstlineno
239+
240+ @property
241+ def colno (self ) -> int | None :
242+ """Starting byte offset of the expression in the traceback entry."""
243+ return self .get_python_framesummary ().colno
244+
245+ @property
246+ def end_colno (self ) -> int | None :
247+ """Ending byte offset of the expression in the traceback entry."""
248+ return self .get_python_framesummary ().end_colno
239249
240250 @property
241251 def frame (self ) -> Frame :
@@ -956,10 +966,8 @@ def get_highlight_arrows_for_line(
956966
957967 num_stripped_chars = len (raw_line ) - len (line )
958968
959- start_char_offset = traceback ._byte_offset_to_character_offset (raw_line , colno )
960- end_char_offset = traceback ._byte_offset_to_character_offset (
961- raw_line , end_colno
962- )
969+ start_char_offset = _byte_offset_to_character_offset (raw_line , colno )
970+ end_char_offset = _byte_offset_to_character_offset (raw_line , end_colno )
963971 num_carets = end_char_offset - start_char_offset
964972 # If the highlight would span the whole line, it is redundant, don't
965973 # show it.
@@ -1477,6 +1485,12 @@ def getfslineno(obj: object) -> tuple[str | Path, int]:
14771485 return code .path , code .firstlineno
14781486
14791487
1488+ def _byte_offset_to_character_offset (str , offset ):
1489+ """Converts a byte based offset in a string to a code-point."""
1490+ as_utf8 = str .encode ("utf-8" )
1491+ return len (as_utf8 [:offset ].decode ("utf-8" , errors = "replace" ))
1492+
1493+
14801494# Relative paths that we use to filter traceback entries from appearing to the user;
14811495# see filter_traceback.
14821496# note: if we need to add more paths than what we have now we should probably use a list
0 commit comments