def test_doctrings_are_corrrectly_rendered(): from cleo.formatters.formatter import Formatter from cleo.ui.exception_trace import Highlighter source = ''' def test(): """ Doctring """ ... ''' formatter = Formatter() highlighter = Highlighter() lines = highlighter.highlighted_lines(source) assert [formatter.format(l) for l in lines] == [ "", "def test():", ' """', " Doctring", ' """', " ...", "", ]
def _render_exception(self, io: Union[IO, Output], exception: Exception) -> None: from crashtest.inspector import Inspector inspector = Inspector(exception) if not inspector.frames: return if inspector.has_previous_exception(): self._render_exception(io, inspector.previous_exception) io.write_line("") io.write_line( "The following error occurred when trying to handle this error:" ) io.write_line("") self._render_trace(io, inspector.frames) self._render_line(io, "<error>{}</error>".format(inspector.exception_name), True) io.write_line("") exception_message = (Formatter().format( inspector.exception_message).replace("\n", "\n ")) self._render_line(io, "<b>{}</b>".format(exception_message)) current_frame = inspector.frames[-1] self._render_snippet(io, current_frame) self._render_solution(io, inspector)
def _describe_command(self, command: Command, **options: Any) -> None: command.merge_application_definition(False) description = command.description if description: self._write("<b>Description:</b>") self._write("\n") self._write(" " + description) self._write("\n\n") self._write("<b>Usage:</b>") for usage in [command.synopsis(True) ] + command.aliases + command.usages: self._write("\n") self._write(" " + Formatter.escape(usage)) self._write("\n") definition = command.definition if definition.options or definition.arguments: self._write("\n") self._describe_definition(definition, **options) self._write("\n") help_text = command.processed_help if help_text and help_text != description: self._write("\n") self._write("<b>Help:</b>") self._write("\n") self._write(" " + help_text.replace("\n", "\n ")) self._write("\n")
def _format_default_value(self, default: Any) -> str: if isinstance(default, str): default = Formatter.escape(default) elif isinstance(default, list): new_default = [] for value in default: if isinstance(value, str): new_default.append(Formatter.escape(value)) default = new_default elif isinstance(default, dict): new_default = {} for key, value in default.items(): if isinstance(value, str): new_default[key] = Formatter.escape(value) default = new_default return json.dumps(default).replace("\\\\", "\\")
def __init__( self, verbosity: Verbosity = Verbosity.NORMAL, decorated: bool = False, formatter: Optional[Formatter] = None, ) -> None: self._verbosity: Verbosity = verbosity if formatter is None: formatter = Formatter() self._formatter = formatter self._formatter.decorated(decorated) self._section_outputs = []
def _build_table_rows(self, rows: _Rows) -> Generator: unmerged_rows = {} row_key = 0 while row_key < len(rows): rows = self._fill_next_rows(rows, row_key) # Remove any new line breaks and replace it with a new line for column, cell in enumerate(rows[row_key]): colspan = cell.colspan if isinstance(cell, TableCell) else 1 if column in self._column_max_widths and self._column_max_widths[ column] < len(self._io.remove_format(cell)): cell = self._io.formatter.format_and_wrap( cell, self._column_max_widths[column] * colspan) if "\n" not in cell: continue escaped = "\n".join( Formatter.escape_trailing_backslash(c) for c in cell.split("\n")) cell = (TableCell(escaped, colspan=cell.colspan) if isinstance( cell, TableCell) else escaped) lines = cell.replace( "\n", "<fg=default;bg=default>\n</>").split("\n") for line_key, line in enumerate(lines): if colspan > 1: line = TableCell(line, colspan=colspan) if line_key == 0: rows[row_key][column] = line else: if row_key not in unmerged_rows: unmerged_rows[row_key] = {} if line_key not in unmerged_rows[row_key]: unmerged_rows[row_key][line_key] = self._copy_row( rows, row_key) unmerged_rows[row_key][line_key][column] = line row_key += 1 for row_key, row in enumerate(rows): yield self._fill_cells(row) if row_key in unmerged_rows: for unmerged_row in unmerged_rows[row_key].values(): yield self._fill_cells(unmerged_row)
def test_format_and_wrap_undecorated(text, width, expected): formatter = Formatter(False) assert formatter.format_and_wrap(text, width) == expected
def test_format_and_wrap(text, width, expected): formatter = Formatter(True) assert formatter.format_and_wrap(text, width) == expected
def split_to_lines(self, source): lines = [] current_line = 1 current_col = 0 buffer = "" current_type = None source_io = io.BytesIO(source.encode()) formatter = Formatter() def readline(): return formatter.format( formatter.escape(source_io.readline().decode())).encode() tokens = tokenize.tokenize(readline) line = "" for token_info in tokens: token_type, token_string, start, end, _ = token_info lineno = start[0] if lineno == 0: # Encoding line continue if token_type == tokenize.ENDMARKER: # End of source if current_type is None: current_type = self.TOKEN_DEFAULT line += "<{}>{}</>".format(self._theme[current_type], buffer) lines.append(line) break if lineno > current_line: if current_type is None: current_type = self.TOKEN_DEFAULT diff = lineno - current_line if diff > 1: lines += [""] * (diff - 1) line += "<{}>{}</>".format(self._theme[current_type], buffer.rstrip("\n")) # New line lines.append(line) line = "" current_line = lineno current_col = 0 buffer = "" if token_string in self.KEYWORDS: new_type = self.TOKEN_KEYWORD elif token_string in self.BUILTINS or token_string == "self": new_type = self.TOKEN_BUILTIN elif token_type == tokenize.STRING: new_type = self.TOKEN_STRING elif token_type == tokenize.NUMBER: new_type = self.TOKEN_NUMBER elif token_type == tokenize.COMMENT: new_type = self.TOKEN_COMMENT elif token_type == tokenize.OP: new_type = self.TOKEN_OP elif token_type == tokenize.NEWLINE: continue else: new_type = self.TOKEN_DEFAULT if current_type is None: current_type = new_type if start[1] > current_col: buffer += token_info.line[current_col:start[1]] if current_type != new_type: line += "<{}>{}</>".format(self._theme[current_type], buffer) buffer = "" current_type = new_type if lineno < end[0]: # The token spans multiple lines token_lines = token_string.split("\n") line += "<{}>{}</>".format(self._theme[current_type], token_lines[0]) lines.append(line) for token_line in token_lines[1:-1]: lines.append("<{}>{}</>".format(self._theme[current_type], token_line)) current_line = end[0] buffer = token_lines[-1][:end[1]] line = "" continue buffer += token_string current_col = end[1] current_line = lineno return lines
def _render_trace(self, io: Union[IO, Output], frames: FrameCollection) -> None: stack_frames = FrameCollection() for frame in frames: if (self._ignore and re.match(self._ignore, frame.filename) and not io.is_debug()): continue stack_frames.append(frame) remaining_frames_length = len(stack_frames) - 1 if io.is_verbose() and remaining_frames_length: self._render_line(io, "<fg=yellow>Stack trace</>:", True) max_frame_length = len(str(remaining_frames_length)) frame_collections = stack_frames.compact() i = remaining_frames_length for collection in frame_collections: if collection.is_repeated(): if len(collection) > 1: frames_message = "<fg=yellow>{}</> frames".format( len(collection)) else: frames_message = "frame" self._render_line( io, "<fg=blue>{:>{}}</> Previous {} repeated <fg=blue>{}</> times" .format( "...", max_frame_length, frames_message, collection.repetitions + 1, ), True, ) i -= len(collection) * (collection.repetitions + 1) for frame in collection: relative_file_path = self._get_relative_file_path( frame.filename) relative_file_path_parts = relative_file_path.split( os.path.sep) relative_file_path = "{}".format( "<fg=default;options=dark>{}</>".format( Formatter.escape( os.sep)).join(relative_file_path_parts[:-1] + [ "<fg=default;options=bold>{}</>".format( relative_file_path_parts[-1]) ]), ) self._render_line( io, "<fg=yellow>{:>{}}</> {}<fg=default;options=dark>:</><b>{}</b> in <fg=cyan>{}</>" .format( i, max_frame_length, relative_file_path, frame.lineno, frame.function, ), True, ) if io.is_debug(): if (frame, 2, 2) not in self._FRAME_SNIPPET_CACHE: code_lines = Highlighter( supports_utf8=io.supports_utf8()).code_snippet( frame.file_content, frame.lineno, ) self._FRAME_SNIPPET_CACHE[(frame, 2, 2)] = code_lines code_lines = self._FRAME_SNIPPET_CACHE[(frame, 2, 2)] for code_line in code_lines: self._render_line( io, "{:>{}}{}".format(" ", max_frame_length, code_line), indent=3, ) else: highlighter = Highlighter( supports_utf8=io.supports_utf8()) try: code_line = highlighter.highlighted_lines( frame.line.strip())[0] except tokenize.TokenError: code_line = frame.line.strip() self._render_line( io, "{:>{}} {}".format( " ", max_frame_length, code_line, ), ) i -= 1