def _pygmented_scope_lines(self) -> Optional[Tuple[int, List[str]]]: # noinspection PyUnresolvedReferences from pygments.formatters import HtmlFormatter formatter = self.options.pygments_formatter scope = self.scope assert_(formatter, ValueError("Must set a pygments formatter in Options")) assert_(scope) if isinstance(formatter, HtmlFormatter): formatter.nowrap = True atok = self.source.asttokens() node = self.executing.node if node and getattr(formatter.style, "for_executing_node", False): scope_start = atok.get_text_range(scope)[0] start, end = atok.get_text_range(node) start -= scope_start end -= scope_start ranges = [(start, end)] else: ranges = [] code = atok.get_text(scope) lines = _pygmented_with_ranges(formatter, code, ranges) start_line = line_range(scope)[0] return start_line, lines
def __init__( self, *, options=Options(), pygmented=False, show_executing_node=True, pygments_formatter_cls=None, pygments_formatter_kwargs=None, pygments_style="monokai", executing_node_modifier="bg:#005080", executing_node_underline="^", current_line_indicator="-->", line_gap_string="(...)", show_variables=False, use_code_qualname=True, show_linenos=True, strip_leading_indent=True, html=False, chain=True, collapse_repeated_frames=True ): if pygmented and not options.pygments_formatter: if show_executing_node: pygments_style = style_with_executing_node( pygments_style, executing_node_modifier ) if pygments_formatter_cls is None: from pygments.formatters.terminal256 import Terminal256Formatter \ as pygments_formatter_cls options.pygments_formatter = pygments_formatter_cls( style=pygments_style, **pygments_formatter_kwargs or {}, ) self.pygmented = pygmented self.show_executing_node = show_executing_node assert_( len(executing_node_underline) == 1, ValueError("executing_node_underline must be a single character"), ) self.executing_node_underline = executing_node_underline self.current_line_indicator = current_line_indicator or "" self.line_gap_string = line_gap_string self.show_variables = show_variables self.show_linenos = show_linenos self.use_code_qualname = use_code_qualname self.strip_leading_indent = strip_leading_indent self.html = html self.chain = chain self.options = options self.collapse_repeated_frames = collapse_repeated_frames
def render(self, markers: Iterable[MarkerInLine] = (), *, strip_leading_indent: bool = True, pygmented: bool = False, escape_html: bool = False) -> str: """ Produces a string for display consisting of .text with the .strings of each marker inserted at the correct positions. If strip_leading_indent is true (the default) then leading spaces common to all lines in this frame will be excluded. """ if pygmented: assert_(not markers, ValueError("Cannot use pygmented with markers")) start_line, lines = self.frame_info._pygmented_scope_lines result = lines[self.lineno - start_line] if strip_leading_indent: result = result.replace(self.text[:self.leading_indent], "", 1) return result text = self.text # This just makes the loop below simpler markers = list(markers) + [ MarkerInLine(position=len(text), is_start=False, string='') ] markers.sort(key=lambda t: t[:2]) parts = [] if strip_leading_indent: start = self.leading_indent else: start = 0 original_start = start for marker in markers: text_part = text[start:marker.position] if escape_html: text_part = html.escape(text_part) parts.append(text_part) parts.append(marker.string) # Ensure that start >= leading_indent start = max(marker.position, original_start) return ''.join(parts)
def format_frame( self, frame: Union[FrameInfo, FrameType, TracebackType]) -> Iterable[str]: if not isinstance(frame, FrameInfo): frame = FrameInfo(frame, self.options) yield self.format_frame_header(frame) for line in frame.lines: if isinstance(line, Line): yield self.format_line(line) else: assert_(line is LINE_GAP) yield self.line_gap_string + "\n" if self.show_variables: yield from self.format_variables(frame)