diff --git a/org_rw/dom.py b/org_rw/dom.py index cb3d8fd..6b3e455 100644 --- a/org_rw/dom.py +++ b/org_rw/dom.py @@ -27,7 +27,7 @@ class PropertyNode: self.value = value def __repr__(self): - return "{{{}: {}}}".format(self.key, self.value) + return "{{{}: {}}".format(self.key, self.value) class ListGroupNode: @@ -89,12 +89,11 @@ class BlockNode: class CodeBlock(BlockNode): - def __init__(self, header, subtype, arguments): + def __init__(self, header, subtype): super().__init__() self.header = header self.lines = None self.subtype = subtype - self.arguments = arguments def set_lines(self, lines): self.lines = lines diff --git a/org_rw/org_rw.py b/org_rw/org_rw.py index 9a60199..6cbd04b 100644 --- a/org_rw/org_rw.py +++ b/org_rw/org_rw.py @@ -92,10 +92,10 @@ LIST_ITEM_RE = re.compile( ) # Org-Babel -BEGIN_BLOCK_RE = re.compile(r"^\s*#\+BEGIN_(?P[^ ]+)(?P.*)$", re.I) +BEGIN_BLOCK_RE = re.compile(r"^\s*#\+BEGIN_(?P[^ ]+)(?P.*)$", re.I) END_BLOCK_RE = re.compile(r"^\s*#\+END_(?P[^ ]+)\s*$", re.I) RESULTS_DRAWER_RE = re.compile(r"^\s*:results:\s*$", re.I) -CodeSnippet = collections.namedtuple("CodeSnippet", ("name", "content", "result", "arguments")) +CodeSnippet = collections.namedtuple("CodeSnippet", ("name", "content", "result")) # Groupings NON_FINISHED_GROUPS = (type(None), dom.ListGroupNode, dom.ResultsDrawerNode, dom.PropertyDrawerNode) @@ -154,26 +154,6 @@ class RangeInRaw: contents.insert(start_idx + i + 1, element) -def unescape_block_lines(lines: str) -> str: - """ - Remove leading ',' from block_lines if they escape `*` characters. - """ - i = 0 - lines = lines.split('\n') - while i < len(lines): - line = lines[i] - if (line.lstrip(' ').startswith(',') - and line.lstrip(' ,').startswith('*') - ): - # Remove leading ',' - lead_pos = line.index(',') - line = line[:lead_pos] + line[lead_pos + 1:] - lines[i] = line - - i += 1 - - return '\n'.join(lines) - def get_links_from_content(content): in_link = False in_description = False @@ -376,7 +356,7 @@ class Headline: end = line.linenum lines = self.get_lines_between(start + 1, end) - contents = unescape_block_lines("\n".join(lines)) + contents = "\n".join(lines) if contents.endswith("\n"): # This is not ideal, but to avoid having to do this maybe # the content parsing must be re-thinked @@ -396,32 +376,18 @@ class Headline: current_node.append(dom.PropertyNode(line.key, line.value)) elif isinstance(line, Text): - tree_up = list(indentation_tree) - while len(tree_up) > 0: - node = tree_up[-1] - if (isinstance(node, dom.BlockNode) - or isinstance(node, dom.DrawerNode) - ): - node.append(dom.Text(line)) - current_node = node - contents = [] - break - elif ((not isinstance(node, dom.TableNode)) and - (type(node) not in NON_FINISHED_GROUPS) - ): - raise NotImplementedError('Not implemented node type: {} (headline_id={}, line={}, doc={})'.format( - node, - self.id, - line.linenum, - self.doc.path, - )) - else: - tree_up.pop(-1) + if isinstance(current_node, dom.BlockNode): + current_node.append(dom.Text(line)) + elif isinstance(current_node, dom.DrawerNode): + current_node.append(dom.Text(line)) else: + if isinstance(current_node, dom.TableNode): + pass # No problem here + elif type(current_node) not in NON_FINISHED_GROUPS: + raise NotImplementedError('Not implemented node type: {}'.format(current_node)) current_node = None contents = [] tree.append(dom.Text(text_to_dom(line.contents, line))) - indentation_tree = tree_up elif isinstance(line, ListItem): if (current_node is None @@ -429,12 +395,9 @@ class Headline: or isinstance(current_node, dom.BlockNode) or isinstance(current_node, dom.DrawerNode) ): - was_node = current_node current_node = dom.ListGroupNode() - if was_node is None: + if current_node is None: tree.append(current_node) - else: - was_node.append(current_node) indentation_tree.append(current_node) if not isinstance(current_node, dom.ListGroupNode): if not isinstance(current_node, dom.ListGroupNode): @@ -457,22 +420,18 @@ class Headline: current_node = sublist indentation_tree.append(current_node) - while len(indentation_tree) > 0: - list_children = [ - c - for c in indentation_tree[-1].children - if isinstance(c, dom.ListItem) - ] - - if (len(list_children) == 0): - break - if ((len(list_children[-1].orig.indentation) - <= len(line.indentation))): - # No more breaking out of lists, it's indentation - # is less than ours - break - - rem = indentation_tree.pop(-1) + while len(indentation_tree) > 0 and ( + (len(indentation_tree[-1].children) > 0) + and len( + [ + c + for c in indentation_tree[-1].children + if isinstance(c, dom.ListItem) + ][-1].orig.indentation + ) + > len(line.indentation) + ): + rem = indentation_tree.pop() if len(indentation_tree) == 0: indentation_tree.append(rem) current_node = rem @@ -489,15 +448,9 @@ class Headline: tree.append(current_node) # TODO: Allow indentation of this element inside others indentation_tree = [current_node] - elif not isinstance(current_node, dom.TableNode): - if isinstance(current_node, dom.ListGroupNode): - # As an item inside a list - list_node = current_node - current_node = dom.TableNode() - list_node.append(current_node) - indentation_tree.append(current_node) - else: - logging.debug("Expected a {}, found: {} on line {}".format(dom.TableNode, current_node, line.linenum)) + if not isinstance(current_node, dom.TableNode): + if not isinstance(current_node, dom.TableNode): + logging.warning("Expected a {}, found: {} on line {}".format(dom.TableNode, current_node, line.linenum)) # This can happen. Frequently inside a LogDrawer if len(line.cells) > 0 and len(line.cells[0]) > 0 and line.cells[0][0] == '-': @@ -511,7 +464,7 @@ class Headline: and line.delimiter_type == DelimiterLineType.BEGIN_BLOCK ): assert type(current_node) in NON_FINISHED_GROUPS - current_node = dom.CodeBlock(line, line.type_data.subtype, line.arguments) + current_node = dom.CodeBlock(line, line.type_data.subtype) elif isinstance(line, Keyword): logging.warning("Keywords not implemented on `as_dom()`") @@ -559,6 +512,8 @@ class Headline: tree_up.pop(-1) else: raise Exception('Unexpected node ({}) on headline (id={}), line {}'.format(current_node, self.id, linenum)) + if self.id == 'd07fcf27-d6fc-41e3-a9d0-b2e2902aec23': + print("Found node:", current_node) current_node = None elif content.strip().upper() == ":RESULTS:": assert current_node is None @@ -579,26 +534,14 @@ class Headline: last_line = None for li in self.list_items: - if last_line is None: - lists.append([li]) + if last_line == li.linenum - 1: + lists[-1].append(li) else: - num_lines = li.linenum - (last_line + 1) - lines_between = ''.join(['\n' + l - for l in self.get_lines_between(last_line + 1, li.linenum)] - ) + lists.append([li]) - # Only empty lines - if ((num_lines == lines_between.count('\n')) - and (len(lines_between.strip()) == 0) - ): - lists[-1].append(li) - else: - lists.append([li]) - - last_line = li.linenum + sum(c.count('\n') for c in li.content) + last_line = li.linenum return lists - # @DEPRECATED: use `get_lists` def getLists(self): return self.get_lists() @@ -680,9 +623,6 @@ class Headline: else: return list(self.shallow_tags) + self.parent.tags - def add_tag(self, tag: str): - self.shallow_tags.append(tag) - def get_property(self, name: str, default=None): for prop in self.properties: if prop.key == name: @@ -736,14 +676,18 @@ class Headline: for lst in self.get_lists(): for item in lst: - if item.tag: - yield from get_links_from_content(item.tag) yield from get_links_from_content(item.content) def get_lines_between(self, start, end): for line in self.contents: if start <= line.linenum < end: - yield "".join(line.get_raw()) + text = [] + for item in line.contents: + if isinstance(item, str): + text.append(item) + elif isinstance(item, MarkerType): + text.append(ModeToMarker[item]) + yield "".join(text) def get_contents(self, format): if format == "raw": @@ -793,19 +737,17 @@ class Headline: inside_code = False sections = [] - arguments = None for delimiter in self.delimiters: if delimiter.delimiter_type == DelimiterLineType.BEGIN_BLOCK and delimiter.type_data.subtype.lower() == "src": line_start = delimiter.linenum inside_code = True - arguments = delimiter.arguments elif delimiter.delimiter_type == DelimiterLineType.END_BLOCK and delimiter.type_data.subtype.lower() == "src": inside_code = False start, end = line_start, delimiter.linenum lines = self.get_lines_between(start + 1, end) - contents = unescape_block_lines("\n".join(lines)) + contents = "\n".join(lines) if contents.endswith("\n"): # This is not ideal, but to avoid having to do this maybe # the content parsing must be re-thinked @@ -816,10 +758,8 @@ class Headline: "line_first": start + 1, "line_last": end - 1, "content": contents, - "arguments": arguments, } ) - arguments = None line_start = None for kword in self.keywords: @@ -870,40 +810,10 @@ class Headline: name = None content = section["content"] code_result = section.get("result", None) - arguments = section.get("arguments", None) - results.append(CodeSnippet(name=name, content=content, result=code_result, arguments=arguments)) + results.append(CodeSnippet(name=name, content=content, result=code_result)) return results - def create_headline_at_end(self) -> Headline: - headline = Headline( - start_line=1, - depth=self.depth + 1, - orig=None, - properties=[], - keywords=[], - priority_start=None, - priority=None, - title_start=None, - title="", - state="", - tags_start=None, - tags=[], - contents=[], - children=[], - structural=[], - delimiters=[], - list_items=[], - table_rows=[], - parent=self, - is_todo=False, - is_done=False, - spacing=" ", - ) - - self.children.append(headline) - return headline - RawLine = collections.namedtuple("RawLine", ("linenum", "line")) Keyword = collections.namedtuple( @@ -913,34 +823,22 @@ Property = collections.namedtuple( "Property", ("linenum", "match", "key", "value", "options") ) -class ListItem: - def __init__(self, - linenum, match, - indentation, - bullet, counter, counter_sep, - checkbox_indentation, checkbox_value, - tag_indentation, tag, - content, - ): - self.linenum = linenum - self.match = match - self.indentation = indentation - self.bullet = bullet - self.counter = counter - self.counter_sep = counter_sep - self.checkbox_indentation = checkbox_indentation - self.checkbox_value = checkbox_value - self.tag_indentation = tag_indentation - self.tag = tag - self.content = content - - @property - def text_start_pos(self): - return len(self.indentation) + 1 # Indentation + bullet - - def append_line(self, line): - self.content += parse_content_block('\n' + line).contents - +ListItem = collections.namedtuple( + "ListItem", + ( + "linenum", + "match", + "indentation", + "bullet", + "counter", + "counter_sep", + "checkbox_indentation", + "checkbox_value", + "tag_indentation", + "tag", + "content", + ), +) TableRow = collections.namedtuple( "TableRow", ( @@ -1054,7 +952,7 @@ BlockDelimiterTypeData = collections.namedtuple( ) DelimiterLine = collections.namedtuple( - "DelimiterLine", ("linenum", "line", "delimiter_type", "type_data", "arguments") + "DelimiterLine", ("linenum", "line", "delimiter_type", "type_data") ) @@ -1102,8 +1000,6 @@ def token_from_type(tok_type): class TimeRange: def __init__(self, start_time: OrgTime, end_time: OrgTime): - assert start_time is not None - assert end_time is not None self.start_time = start_time self.end_time = end_time @@ -1644,20 +1540,14 @@ def parse_contents(raw_contents: List[RawLine]): return [parse_content_block(block) for block in blocks] -def parse_content_block(raw_contents: Union[List[RawLine],str]): +def parse_content_block(raw_contents: List[RawLine]): contents_buff = [] - if isinstance(raw_contents, str): - contents_buff.append(raw_contents) - else: - for line in raw_contents: - contents_buff.append(line.line) + for line in raw_contents: + contents_buff.append(line.line) contents = "\n".join(contents_buff) tokens = tokenize_contents(contents) - if isinstance(raw_contents, str): - current_line = None - else: - current_line = raw_contents[0].linenum + current_line = raw_contents[0].linenum contents = [] # Use tokens to tag chunks of text with it's container type @@ -1684,9 +1574,7 @@ def dump_contents(raw): elif isinstance(raw, ListItem): bullet = raw.bullet if raw.bullet else raw.counter + raw.counter_sep - content_full = token_list_to_raw(raw.content) - content_lines = content_full.split('\n') - content = '\n'.join(content_lines) + content = token_list_to_raw(raw.content) checkbox = f"[{raw.checkbox_value}]" if raw.checkbox_value else "" tag = f"{raw.tag_indentation}{token_list_to_raw(raw.tag or '')}::" if raw.tag or raw.tag_indentation else "" return ( @@ -1916,12 +1804,7 @@ class OrgDoc: if headline.state: state = headline.state + " " - raw_title = token_list_to_raw(headline.title.contents) - tags_padding = "" - if not raw_title.endswith(" ") and tags: - tags_padding = " " - - yield "*" * headline.depth + headline.spacing + state + raw_title + tags_padding + tags + yield "*" * headline.depth + headline.spacing + state + token_list_to_raw(headline.title.contents) + tags planning = headline.get_planning_line() if planning is not None: @@ -2080,19 +1963,19 @@ class OrgDocReader: def add_list_item_line(self, linenum: int, match: re.Match) -> int: li = ListItem( - linenum=linenum, - match=match, - indentation=match.group("indentation"), - bullet=match.group("bullet"), - counter=match.group("counter"), - counter_sep=match.group("counter_sep"), - checkbox_indentation=match.group("checkbox_indentation"), - checkbox_value=match.group("checkbox_value"), - tag_indentation=match.group("tag_indentation"), - tag=parse_content_block( + linenum, + match, + match.group("indentation"), + match.group("bullet"), + match.group("counter"), + match.group("counter_sep"), + match.group("checkbox_indentation"), + match.group("checkbox_value"), + match.group("tag_indentation"), + parse_content_block( [RawLine(linenum=linenum, line=match.group("tag"))] ).contents if match.group("tag") else None, - content=parse_content_block( + parse_content_block( [RawLine(linenum=linenum, line=match.group("content"))] ).contents, ) @@ -2101,7 +1984,6 @@ class OrgDocReader: self.list_items.append(li) else: self.headline_hierarchy[-1]["list_items"].append(li) - return li def add_table_line(self, linenum: int, line: str) -> int: chunks = line.split('|') @@ -2151,7 +2033,7 @@ class OrgDocReader: def add_begin_block_line(self, linenum: int, match: re.Match): line = DelimiterLine(linenum, match.group(0), DelimiterLineType.BEGIN_BLOCK, - BlockDelimiterTypeData(match.group("subtype")), match.group('arguments')) + BlockDelimiterTypeData(match.group("subtype"))) if len(self.headline_hierarchy) == 0: self.delimiters.append(line) else: @@ -2159,7 +2041,7 @@ class OrgDocReader: def add_end_block_line(self, linenum: int, match: re.Match): line = DelimiterLine(linenum, match.group(0), DelimiterLineType.END_BLOCK, - BlockDelimiterTypeData(match.group("subtype")), None) + BlockDelimiterTypeData(match.group("subtype"))) if len(self.headline_hierarchy) == 0: self.delimiters.append(line) else: @@ -2211,25 +2093,6 @@ class OrgDocReader: reader = enumerate(lines) in_drawer = False in_block = False - list_item_indentation = None - list_item = None - - def add_raw_line_with_possible_indentation(linenum, line): - added = False - nonlocal list_item - nonlocal list_item_indentation - if list_item: - if ((line[:list_item.text_start_pos].strip() == '') - or (len(line.strip()) == 0) - ): - list_item.append_line(line) - added = True - else: - list_item = None - list_item_indentation = None - - if not added: - self.add_raw_line(linenum, line) for lnum, line in reader: linenum = lnum + 1 @@ -2238,58 +2101,41 @@ class OrgDocReader: if m := END_BLOCK_RE.match(line): self.add_end_block_line(linenum, m) in_block = False - list_item_indentation = None - list_item = None else: - add_raw_line_with_possible_indentation(linenum, line) + self.add_raw_line(linenum, line) elif m := HEADLINE_RE.match(line): - list_item_indentation = None - list_item = None self.add_headline(linenum, m) elif m := LIST_ITEM_RE.match(line): - list_item = self.add_list_item_line(linenum, m) - list_item_indentation = m.group("indentation") + self.add_list_item_line(linenum, m) elif m := RAW_LINE_RE.match(line): - add_raw_line_with_possible_indentation(linenum, line) + self.add_raw_line(linenum, line) # Org-babel elif m := BEGIN_BLOCK_RE.match(line): self.add_begin_block_line(linenum, m) in_block = True - list_item_indentation = None - list_item = None elif m := END_BLOCK_RE.match(line): self.add_end_block_line(linenum, m) in_block = False - list_item_indentation = None - list_item = None # Generic properties elif m := KEYWORDS_RE.match(line): self.add_keyword_line(linenum, m) elif m := DRAWER_END_RE.match(line): self.add_drawer_end_line(linenum, line, m) in_drawer = False - list_item_indentation = None - list_item = None elif (not in_drawer) and (m := DRAWER_START_RE.match(line)): self.add_property_drawer_line(linenum, line, m) in_drawer = True - list_item_indentation = None - list_item = None elif (not in_drawer) and (m := RESULTS_DRAWER_RE.match(line)): self.add_results_drawer_line(linenum, line, m) in_drawer = True - list_item_indentation = None - list_item = None elif m := NODE_PROPERTIES_RE.match(line): self.add_node_properties_line(linenum, m) elif line.strip().startswith('|'): self.add_table_line(linenum, line) - list_item_indentation = None - list_item = None # Not captured else: - add_raw_line_with_possible_indentation(linenum, line) + self.add_raw_line(linenum, line) except: logging.error("Error line {}: {}".format(linenum + 1, line)) raise diff --git a/tests/04-code.org b/tests/04-code.org index 956d961..161dc2f 100644 --- a/tests/04-code.org +++ b/tests/04-code.org @@ -36,16 +36,3 @@ exit 0 # Comment This is another test with two lines too :end: - -* Escaped code - :PROPERTIES: - :ID: 04-code-escaped-code-id - :CREATED: [2020-01-01 Wed 01:01] - :END: - - #+BEGIN_SRC c :results drawer -/* This code has to be escaped to - ,* avoid confusion with new headlines. - ,*/ -main(){} - #+END_SRC diff --git a/tests/06-lists.org b/tests/06-lists.org index 1ee04e7..b80e358 100644 --- a/tests/06-lists.org +++ b/tests/06-lists.org @@ -1,5 +1,5 @@ -#+TITLE: 06-Lists -#+DESCRIPTION: Simple org file to test lists +#+TITLE: 06-Links +#+DESCRIPTION: Simple org file to test links #+TODO: TODO(t) PAUSED(p) | DONE(d) @@ -51,25 +51,3 @@ Also with markup - _Key_ :: _Value_ - /Key/ 2 :: /Value/ 2 - -* List with multiline elements - :PROPERTIES: - :ID: 07-list-with-multiline-elements - :CREATED: [2020-01-01 Wed 01:01] - :END: - - - This is a list item... - that spans multiple lines - - - This is another list item... - that has content on multiple lines - - Text after a multiline element - - - This is another - multiline list - - #+begin_quote - With a block element inside - #+end_quote - diff --git a/tests/10-tables.org b/tests/10-tables.org index a473bed..d9d404b 100644 --- a/tests/10-tables.org +++ b/tests/10-tables.org @@ -16,18 +16,3 @@ | Content2-1 | Content2-2 | Content2-3 | Content after the table. -** Indented table -:PROPERTIES: -:ID: 10-table-test-id-02-indented -:CREATED: [2020-01-01 Wed 01:01] -:END: - -- This table is indented inside a list item. - - Item before in list - - | Header1 | Header2 | Header3 | - |------------+------------+------------| - | Content1-1 | Content1-2 | Content1-3 (last cell unclosed) - | Content2-1 | Content2-2 | Content2-3 | - - Item after in list -- This item happens after the indented table. diff --git a/tests/11-nested-lists.org b/tests/11-nested-lists.org deleted file mode 100644 index a4a8632..0000000 --- a/tests/11-nested-lists.org +++ /dev/null @@ -1,16 +0,0 @@ -#+TITLE: 11-Nested lists -#+DESCRIPTION: Simple org file to test nested lists -#+TODO: TODO(t) PAUSED(p) | DONE(d) - -* Nested lists - :PROPERTIES: - :ID: 11-nested-lists - :CREATED: [2020-01-01 Wed 01:01] - :END: - - 1 - - 1.1 - - 1.2 - - 2 - - 2.1 - - 2.2 - - 3 diff --git a/tests/test_org.py b/tests/test_org.py index 2f4200d..3509ffc 100644 --- a/tests/test_org.py +++ b/tests/test_org.py @@ -4,8 +4,7 @@ import unittest from datetime import date from datetime import datetime as DT -from org_rw import MarkerToken, MarkerType, Timestamp, dumps, load, loads, dom -import org_rw +from org_rw import MarkerToken, MarkerType, Timestamp, dumps, load, loads from utils.assertions import (BOLD, CODE, HL, ITALIC, SPAN, STRIKE, UNDERLINED, VERBATIM, WEB_LINK, Doc, Tokens) @@ -434,14 +433,13 @@ class TestSerde(unittest.TestCase): doc = load(f) snippets = list(doc.get_code_snippets()) - self.assertEqual(len(snippets), 3) + self.assertEqual(len(snippets), 2) self.assertEqual( snippets[0].content, 'echo "This is a test"\n' + 'echo "with two lines"\n' + "exit 0 # Exit successfully", ) - self.assertEqual(snippets[0].arguments.split(), ['shell', ':results', 'verbatim']) self.assertEqual( snippets[0].result, "This is a test\n" + "with two lines", @@ -457,14 +455,6 @@ class TestSerde(unittest.TestCase): snippets[1].result, "This is another test\n" + "with two lines too" ) - self.assertEqual( - snippets[2].content, - '/* This code has to be escaped to\n' - + ' * avoid confusion with new headlines.\n' - + ' */\n' - + 'main(){}', - ) - def test_mimic_write_file_05(self): with open(os.path.join(DIR, "05-dates.org")) as f: orig = f.read() @@ -561,7 +551,7 @@ class TestSerde(unittest.TestCase): MarkerToken(closing=False, tok_type=MarkerType.UNDERLINED_MODE), "markup", MarkerToken(closing=True, tok_type=MarkerType.UNDERLINED_MODE), - ".", "\n" + ".", ], ) @@ -577,7 +567,7 @@ class TestSerde(unittest.TestCase): self.assertEqual(lists2[0][0].counter, "1") self.assertEqual(lists2[0][0].counter_sep, ".") - self.assertEqual(lists2[0][1].content, ["Second element", "\n"]) + self.assertEqual(lists2[0][1].content, ["Second element"]) self.assertEqual(lists2[0][1].counter, "2") self.assertEqual(lists2[0][1].counter_sep, ".") @@ -585,24 +575,10 @@ class TestSerde(unittest.TestCase): self.assertEqual(lists2[1][0].counter, "1") self.assertEqual(lists2[1][0].counter_sep, ")") - self.assertEqual(lists2[1][1].content, ["Second element", "\n"]) + self.assertEqual(lists2[1][1].content, ["Second element"]) self.assertEqual(lists2[1][1].counter, "2") self.assertEqual(lists2[1][1].counter_sep, ")") - hl4 = doc.getTopHeadlines()[3] - # ... - lists4 = hl4.getLists() - print(lists4) - self.assertEqual(len(lists4), 2) - - self.assertEqual(lists4[0][0].content, ["This is a list item...", "\n that spans multiple lines", "\n"]) - self.assertEqual(lists4[0][0].bullet, "-") - self.assertEqual(lists4[0][1].content, ["This is another list item...", "\n that has content on multiple lines", "\n"]) - self.assertEqual(lists4[0][1].bullet, "-") - - self.assertEqual(lists4[1][0].content, ["This is another", "\n multiline list", "\n"]) - self.assertEqual(lists4[1][0].bullet, "-") - def test_org_roam_07(self): with open(os.path.join(DIR, "07-org-roam-v2.org")) as f: orig = f.read() @@ -682,99 +658,3 @@ class TestSerde(unittest.TestCase): self.assertEqual(first_table[0].cells[1].strip(), 'Header2') self.assertEqual(first_table[0].cells[2].strip(), 'Header3') - hl = hl.children[0] - - tables = hl.get_tables() - first_table = tables[0] - self.assertEqual(len(first_table), 4) - - print(first_table[0]) - self.assertEqual(len(first_table[0].cells), 3) - self.assertEqual(first_table[0].cells[0].strip(), 'Header1') - self.assertEqual(first_table[0].cells[1].strip(), 'Header2') - self.assertEqual(first_table[0].cells[2].strip(), 'Header3') - - def test_tables_html_file_10(self): - with open(os.path.join(DIR, "10-tables.org")) as f: - doc = load(f) - - hl = doc.getTopHeadlines()[0] - - tree = hl.as_dom() - non_props = [ - item - for item in tree - if not isinstance(item, dom.PropertyDrawerNode) - ] - self.assertTrue(isinstance(non_props[0], dom.Text) - and isinstance(non_props[1], dom.TableNode) - and isinstance(non_props[2], dom.Text), - 'Expected ') - - - hl = hl.children[0] - tree = hl.as_dom() - non_props = [ - item - for item in tree - if not (isinstance(item, dom.PropertyDrawerNode) - or isinstance(item, dom.Text)) - ] - print_tree(non_props) - self.assertTrue(len(non_props) == 1, - 'Expected , with only (1) element') - - def test_nested_lists_html_file_11(self): - with open(os.path.join(DIR, "11-nested-lists.org")) as f: - doc = load(f) - - hl = doc.getTopHeadlines()[0] - - tree = hl.as_dom() - non_props = [ - item - for item in tree - if not isinstance(item, dom.PropertyDrawerNode) - ] - print_tree(non_props) - self.assertTrue((len(non_props) == 1) and (isinstance(non_props[0], dom.ListGroupNode)), - 'Expected only as top level') - - dom_list = non_props[0] - children = dom_list.children - self.assertTrue(len(children) == 5, 'Expected 5 items inside , 3 texts and 2 sublists') - - # Assert texts - self.assertEqual(children[0].content, ['1']) - self.assertEqual(children[2].content, ['2']) - self.assertEqual(children[4].content[0], '3') # Might be ['3', '\n'] but shouldn't be a breaking change - - # Assert lists - self.assertTrue(isinstance(children[1], dom.ListGroupNode), 'Expected sublist inside "1"') - self.assertEqual(children[1].children[0].content, ['1.1']) - self.assertEqual(children[1].children[1].content, ['1.2']) - self.assertTrue(isinstance(children[3], dom.ListGroupNode), 'Expected sublist inside "2"') - self.assertEqual(children[3].children[0].content, ['2.1']) - self.assertEqual(children[3].children[1].content, ['2.2']) - - -def print_tree(tree, indentation=0, headline=None): - for element in tree: - print(" " * indentation * 2, "EL:", element) - if "children" in dir(element): - if len(element.children) > 0: - print_element(element.children, indentation + 1, headline) - print() - - elif "content" in dir(element): - for content in element.content: - print_element(content, indentation + 1, headline) - - -def print_element(element, indentation, headline): - if isinstance(element, org_rw.Link): - print(" " * indentation * 2, "Link:", element.get_raw()) - elif isinstance(element, str): - print(" " * indentation * 2, "Str[" + element.replace('\n', '') + "]", type(element)) - else: - print_tree(element, indentation, headline)