def read_table_body(self, reader: LineReader, aligns: List[str]) -> List[nodes.row]: try: rows = [] while True: if self.parser.is_interrupted(reader): break else: row = self.parse_row(reader.readline()) if len(row) == 1 and row[0] == '': reader.step(-1) break entries = [] for i, align in enumerate(aligns): try: text = row[i].strip() except IndexError: text = '' entry = nodes.entry() if text: entry += nodes.paragraph(text, text) entry.source, entry.line = reader.get_source_and_line() if align: entry['align'] = align entries.append(entry) rows.append(nodes.row('', *entries)) except IOError: pass return rows
def run(self, reader: LineReader, document: Element) -> bool: location = reader.get_source_and_line(incr=1) lines = [] underline = None try: for line in reader: lines.append(line.lstrip()) if self.pattern.match(reader.next_line): underline = reader.readline() break elif self.parser.is_interrupted(reader): break except IOError: pass if underline is None: # underline of heading not found. backtracking. reader.step(-len(lines)) return False else: text = ''.join(lines).strip() depth = self.section_level[underline.strip()[0]] section = nodes.section(depth=depth) section += nodes.title(text, text) location.set_source_info(section[0]) get_root_document(document).note_implicit_target(section) document += section return True
def test_WalledBlockReader(): text = ("===wall\n" "Lorem ipsum dolor sit amet, \n" "consectetur adipiscing elit, \n" "\n" "=====nested_wall\n" " sed do eiusmod tempor incididunt \n" " ut labore et dolore magna aliqua.\n" "===\n" "\n" "===\n" "Ut enim ad minim veniam, quis nostrud") reader = LineReader(text.splitlines(True), source='dummy.md') assert reader.readline() == "===wall\n" walled_block_reader = WalledBlockReader(reader) assert walled_block_reader.eof() is False assert walled_block_reader.get_source_and_line() == ('dummy.md', 1) # read first line assert walled_block_reader.readline() == "Lorem ipsum dolor sit amet, \n" assert walled_block_reader.current_line == "Lorem ipsum dolor sit amet, \n" assert walled_block_reader.fetch() == "Lorem ipsum dolor sit amet, \n" assert walled_block_reader.get_source_and_line() == ('dummy.md', 2) # read consequence lines assert walled_block_reader.readline() == "consectetur adipiscing elit, \n" assert walled_block_reader.readline() == "\n" assert walled_block_reader.readline() == "=====nested_wall\n" # nested WalledBlockReader nested_wbreader = WalledBlockReader(walled_block_reader) assert nested_wbreader.readline( ) == " sed do eiusmod tempor incididunt \n" assert nested_wbreader.readline( ) == " ut labore et dolore magna aliqua.\n" # reach the end of the nested block assert nested_wbreader.eof() is True try: nested_wbreader.readline() assert False except IOError: pass # read consequence lines by parent reader nested_wbreader.consume_endmarker() assert walled_block_reader.readline() == "\n" # reach the end of the parent block assert walled_block_reader.eof() is True try: walled_block_reader.readline() assert False except IOError: pass walled_block_reader.consume_endmarker() assert reader.readline() == "Ut enim ad minim veniam, quis nostrud"
def test_FencedCodeBlockReader(): text = ("Lorem ipsum dolor sit amet, \n" " consectetur adipiscing elit, \n" " sed do eiusmod tempor incididunt \n" " ```\n" " ut labore et dolore magna aliqua.\n" " ```\n" "Ut enim ad minim veniam, quis nostrud") reader = LineReader(text.splitlines(True), source='dummy.md') codeblock_reader = FencedCodeBlockReader(reader, 0, '```') assert codeblock_reader.readline() == "Lorem ipsum dolor sit amet, \n" assert codeblock_reader.readline() == " consectetur adipiscing elit, \n" assert codeblock_reader.readline( ) == " sed do eiusmod tempor incididunt \n" assert codeblock_reader.readline() == " ```\n" assert codeblock_reader.readline( ) == " ut labore et dolore magna aliqua.\n" assert codeblock_reader.eof() reader = LineReader(text.splitlines(True), source='dummy.md') codeblock_reader = FencedCodeBlockReader(reader, 3, '```') assert codeblock_reader.readline() == "Lorem ipsum dolor sit amet, \n" assert codeblock_reader.readline() == "consectetur adipiscing elit, \n" assert codeblock_reader.readline( ) == " sed do eiusmod tempor incididunt \n" assert codeblock_reader.readline() == " ```\n" assert codeblock_reader.readline( ) == " ut labore et dolore magna aliqua.\n" assert codeblock_reader.eof()
def test_LazyLineReader(): reader = LineReader(quoted_text.splitlines(True), source='dummy.md') lazy_reader = LazyLineReader(BlockQuoteReader(reader)) assert lazy_reader.eof() is False assert lazy_reader.get_source_and_line() == ('dummy.md', 0) # read first line assert lazy_reader.readline() == "Lorem ipsum dolor sit amet, \n" assert lazy_reader.current_line == "Lorem ipsum dolor sit amet, \n" assert lazy_reader.fetch() == "Lorem ipsum dolor sit amet, \n" assert lazy_reader.get_source_and_line() == ('dummy.md', 1) # read second line assert lazy_reader.readline() == " consectetur adipiscing elit, \n" # empty line causes IOError try: lazy_reader.readline() assert False except IOError: pass assert reader.readline() == '\n' assert reader.readline() == "sed do eiusmod tempor incididunt \n" assert reader.readline() == "ut labore et dolore magna aliqua."
def consume_blanklines(self, reader: LineReader, list_item: nodes.list_item) -> None: """Skip over blank lines at beginning of the list item.""" try: while reader.next_line.strip() == '': reader.step() list_item += addnodes.blankline() except IOError: pass
def run(self, reader: LineReader, document: Element) -> bool: marker, title = self.pattern.match(reader.readline()).groups() title = self.trailing_hashes.sub('', title).strip() title_node = nodes.title(title, title) title_node.source, title_node.line = reader.get_source_and_line() section = nodes.section('', title_node, depth=len(marker)) get_root_document(document).note_implicit_target(section) document += section return True
def run(self, reader: LineReader, document: Element) -> bool: line = reader.readline() klass = line.strip().strip('=').strip() container = nodes.container(classes=[klass]) container.source, container.line = reader.get_source_and_line() document += container walled_block_reader = WalledBlockReader(reader) self.parser.parse(walled_block_reader, container) walled_block_reader.consume_endmarker() return True
def run(self, reader: LineReader, document: Element) -> bool: lineno = reader.lineno try: multiline_reader = MultiLineReader(reader) target = self.parse_linkref_definition(multiline_reader, document) if target: document += target return True else: reader.step(lineno - reader.lineno) # rollback return False except IOError: reader.step(lineno - reader.lineno) # rollback return False
def test_nested_line_readers(): text = ("> 1. > Blockquote\n" "continued here.\n") reader = LineReader(text.splitlines(True)) reader = BlockQuoteReader(reader) reader = ListItemReader(reader, r'1\.', BlockProcessor(None)) reader = BlockQuoteReader(reader) reader = LazyLineReader(reader) assert reader.readline() == 'Blockquote\n' assert reader.eof() is False assert reader.next_line == 'continued here.\n' assert reader.readline() == 'continued here.\n'
def run(self, reader: LineReader, document: Element) -> bool: location = reader.get_source_and_line(incr=1) indent, marker, info = self.pattern.match(reader.readline()).groups() code = ''.join(FencedCodeBlockReader(reader, len(indent), marker)) literal_block = nodes.literal_block(code, code, classes=['code']) location.set_source_info(literal_block) if info.strip(): language = unescape(entitytrans._unescape(info.split()[0].strip())) literal_block['language'] = language literal_block['classes'].append('language-%s' % language.split()[0]) document += literal_block return True
def test_ListItemReader(): text = ("- Lorem ipsum dolor sit amet, \n" "- consectetur adipiscing elit, \n" "\n" " sed do eiusmod tempor incididunt \n" "ut labore et dolore magna aliqua.") reader = LineReader(text.splitlines(True)) list_reader = ListItemReader(reader, '-', BlockProcessor(None)) assert list_reader.readline() == "Lorem ipsum dolor sit amet, \n" # reached next item try: list_reader.readline() assert False except IOError: pass list_reader = ListItemReader(reader, '-', BlockProcessor(None)) assert list_reader.readline() == "consectetur adipiscing elit, \n" assert list_reader.readline() == "\n" assert list_reader.readline() == "sed do eiusmod tempor incididunt \n" # reached the end of list try: list_reader.readline() assert False except IOError: pass # can read the next line with laziness assert list_reader.readline( lazy=True) == "ut labore et dolore magna aliqua."
def parse(self, reader: LineReader, document: Element) -> None: """Parses a text and build document.""" while not reader.eof(): for _, processor in self.processors: if processor.match(reader): if processor.run(reader, document): break else: raise RuntimeError('Failed to parse')
def run(self, reader: LineReader, document: Element) -> bool: location = reader.get_source_and_line(incr=1) code = ''.join(IndentedCodeBlockReader(reader)) code = re.sub('^\n+', '', code) # strip blank lines code = re.sub('\n+$', '\n', code) # strip blank lines document += nodes.literal_block(code, code, classes=['code']) location.set_source_info(document[-1]) return True
def test_IndentedCodeBlockReader(): text = (" Lorem ipsum dolor sit amet, \n" " consectetur adipiscing elit, \n" "\n" " sed do eiusmod tempor incididunt \n") reader = LineReader(text.splitlines(True), source='dummy.md') codeblock_reader = IndentedCodeBlockReader(reader) assert codeblock_reader.readline() == "Lorem ipsum dolor sit amet, \n" assert codeblock_reader.readline() == " consectetur adipiscing elit, \n" assert codeblock_reader.readline() == "\n" assert codeblock_reader.eof()
def run(self, reader: LineReader, document: Element) -> bool: location = reader.get_source_and_line(incr=1) content = '' for line in reader: content += line if self.closing_pattern.search(line): break content = re.sub('\n+$', '\n', content) # strip multiple CRs on tail document += nodes.raw(content, content, format='html') location.set_source_info(document[-1]) return True
def test_BlockQuoteReader(): reader = LineReader(quoted_text.splitlines(True), source='dummy.md') quoted_reader = BlockQuoteReader(reader) assert quoted_reader.eof() is False assert quoted_reader.get_source_and_line() == ('dummy.md', 0) # read first line assert quoted_reader.readline() == "Lorem ipsum dolor sit amet, \n" assert quoted_reader.current_line == "Lorem ipsum dolor sit amet, \n" assert quoted_reader.fetch() == "Lorem ipsum dolor sit amet, \n" assert quoted_reader.get_source_and_line() == ('dummy.md', 1) # laziness: off try: quoted_reader.readline() assert False except IOError: pass # lazyness allows texts hanging on quoted block assert quoted_reader.readline( lazy=True) == " consectetur adipiscing elit, \n" # empty line causes IOError try: quoted_reader.readline() assert False except IOError: pass # empty line causes IOError even if lazy try: quoted_reader.readline(lazy=True) assert False except IOError: pass assert reader.readline() == '\n' assert reader.readline() == "sed do eiusmod tempor incididunt \n" assert reader.readline() == "ut labore et dolore magna aliqua."
def read_table_header(self, reader: LineReader) -> Tuple[nodes.row, List[str]]: try: location = reader.get_source_and_line(incr=1) header = self.parse_row(reader.readline()) if self.parser.is_interrupted(reader): raise IOError elif not self.delimiter_pattern.match(reader.next_line): raise IOError delimiters = self.parse_row(reader.next_line) aligns = [align(d) for d in delimiters] if len(header) != len(delimiters): raise IOError except IOError: reader.step(-1) return None, None reader.step() row = nodes.row() for i, cell in enumerate(header): text = cell.strip() entry = nodes.entry() location.set_source_info(entry) if text: entry += nodes.paragraph(text, text) if aligns[i]: entry['align'] = aligns[i] row += entry return row, aligns
def run(self, reader: LineReader, document: Element) -> bool: if reader.lineno != 0: return False reader.readline() field_list = nodes.field_list() field_list.source, field_list.line = reader.get_source_and_line() for line in reader: if self.pattern.match(line): break elif ':' in line: key, value = line.split(':') field_name = nodes.field_name('', key.strip()) field_body = nodes.field_body('', nodes.paragraph('', value.strip())) field_list += nodes.field('', field_name, field_body) else: # Not a frontmatter, rollback lines = len(field_list) + 2 reader.step(-lines) return False document += field_list return True
def run(self, reader: LineReader, document: Element) -> bool: location = reader.get_source_and_line(incr=1) reader = LazyLineReader(reader) text = '' for line in reader: text += line.lstrip() if self.parser.is_interrupted(reader): break node = nodes.paragraph(text.strip(), text.strip()) location.set_source_info(node) document += node return True
def run(self, reader: LineReader, document: Element) -> bool: location = reader.get_source_and_line(incr=1) header_row, aligns = self.read_table_header(reader) if header_row is None: return False body_rows = self.read_table_body(reader, aligns) colspecs = [ nodes.colspec('', colwidth=int(100 / len(aligns))) for _ in aligns ] thead = nodes.thead('', header_row) tgroup = nodes.tgroup('', *colspecs, thead, cols=len(aligns)) if body_rows: tgroup += nodes.tbody('', *body_rows) table = nodes.table('', tgroup) location.set_source_info(table) document += table return True
def test_LineReader(): reader = LineReader(text.splitlines(), source='dummy.md') assert reader.eof() is False assert reader.get_source_and_line() == ('dummy.md', 0) # read first line assert reader.readline() == "Lorem ipsum dolor sit amet, " assert reader.current_line == "Lorem ipsum dolor sit amet, " assert reader.fetch() == "Lorem ipsum dolor sit amet, " assert reader.fetch(1) == "consectetur adipiscing elit, " assert reader.next_line == "consectetur adipiscing elit, " assert reader.fetch(2) == "" assert reader.get_source_and_line() == ('dummy.md', 1) # read second line assert reader.readline() == "consectetur adipiscing elit, " assert reader.current_line == "consectetur adipiscing elit, " assert reader.fetch() == "consectetur adipiscing elit, " assert reader.fetch(1) == "" assert reader.get_source_and_line() == ('dummy.md', 2) # rollback a line reader.step(-1) assert reader.current_line == "Lorem ipsum dolor sit amet, " assert reader.get_source_and_line() == ('dummy.md', 1) # step a line again reader.step() assert reader.current_line == "consectetur adipiscing elit, " # read until the end assert reader.readline() == "" assert reader.readline() == " sed do eiusmod tempor incididunt " assert reader.readline() == " ut labore et dolore magna aliqua." assert reader.readline() == "" assert reader.readline() == "Ut enim ad minim veniam, quis nostrud" assert reader.eof() is True try: assert reader.readline() assert False, "reader does not raise IOError on EOF" except IOError: pass
def run(self, reader: LineReader, document: Element) -> bool: reader.readline() # skip the line document += addnodes.blankline() return True
def run(self, reader: LineReader, document: Element) -> bool: reader.readline() document += nodes.transition() return True
def parse(self, inputtext: str, document: nodes.document) -> None: """Parses a text and build document.""" document.settings.inline_processors = self.get_inline_processors() reader = LineReader(inputtext.splitlines(True), source=document['source']) block_parser = self.create_block_parser() block_parser.parse(reader, document)
def run(self, reader: LineReader, document: Element) -> bool: quote = nodes.block_quote() quote.source, quote.line = reader.get_source_and_line(incr=1) document += quote self.parser.parse(BlockQuoteReader(reader), quote) return True