| @@ -5,6 +5,7 @@ v0.4 (unreleased): | |||
| is a breaking change if you rely on the default behavior. | |||
| - The 'matches' argument of Wikicode's filter methods now accepts a function | |||
| (taking one argument, a Node, and returning a bool) in addition to a regex. | |||
| - Wikicode.get_sections() now returns sections in the correct order. | |||
| - Wikicode.matches() now accepts a tuple or list of strings/Wikicode objects | |||
| instead of just a single string or Wikicode. | |||
| - C code cleanup and speed improvements. | |||
| @@ -14,6 +14,7 @@ Unreleased | |||
| - The *matches* argument of :py:class:`Wikicode's <.Wikicode>` | |||
| :py:meth:`.filter` methods now accepts a function (taking one argument, a | |||
| :py:class:`.Node`, and returning a bool) in addition to a regex. | |||
| - :py:meth:`.Wikicode.get_sections` now returns sections in the correct order. | |||
| - :py:meth:`.Wikicode.matches` now accepts a tuple or list of | |||
| strings/:py:class:`.Wikicode` objects instead of just a single string or | |||
| :py:class:`.Wikicode`. | |||
| @@ -434,34 +434,31 @@ class Wikicode(StringMixIn): | |||
| """ | |||
| if matches: | |||
| matches = r"^(=+?)\s*" + matches + r"\s*\1$" | |||
| headings = self.filter_headings() | |||
| filtered = self.filter_headings(matches=matches, flags=flags) | |||
| headings = self.filter_headings(recursive=False, matches=matches, | |||
| flags=flags) | |||
| if levels: | |||
| filtered = [head for head in filtered if head.level in levels] | |||
| headings = [head for head in headings if head.level in levels] | |||
| if matches or include_lead is False or (not include_lead and levels): | |||
| buffers = [] | |||
| else: | |||
| buffers = [(maxsize, 0)] | |||
| sections = [] | |||
| i = 0 | |||
| while i < len(self.nodes): | |||
| if self.nodes[i] in headings: | |||
| this = self.nodes[i].level | |||
| for (level, start) in buffers: | |||
| if this <= level: | |||
| sections.append(Wikicode(self.nodes[start:i])) | |||
| buffers = [buf for buf in buffers if buf[0] < this] | |||
| if self.nodes[i] in filtered: | |||
| if not include_headings: | |||
| i += 1 | |||
| if i >= len(self.nodes): | |||
| break | |||
| buffers.append((this, i)) | |||
| i += 1 | |||
| for (level, start) in buffers: | |||
| if start != i: | |||
| sections.append(Wikicode(self.nodes[start:i])) | |||
| if include_lead or not (include_lead is not None or matches or levels): | |||
| iterator = self.ifilter_headings(recursive=False) | |||
| try: | |||
| first = self.index(next(iterator)) | |||
| sections.append(Wikicode(self.nodes[:first])) | |||
| except StopIteration: # No headings in page | |||
| sections.append(Wikicode(self.nodes[:])) | |||
| for heading in headings: | |||
| start = self.index(heading) | |||
| i = start + 1 | |||
| if not include_headings: | |||
| start += 1 | |||
| while i < len(self.nodes): | |||
| node = self.nodes[i] | |||
| if isinstance(node, Heading) and node.level <= heading.level: | |||
| break | |||
| i += 1 | |||
| sections.append(Wikicode(self.nodes[start:i])) | |||
| return sections | |||
| def strip_code(self, normalize=True, collapse=True): | |||
| @@ -351,12 +351,12 @@ class TestWikicode(TreeEqualityTestCase): | |||
| p4_III = "== Section III ==\n" + p4_IIIA | |||
| page4 = parse(p4_lead + p4_I + p4_II + p4_III) | |||
| self.assertEqual([], page1.get_sections()) | |||
| self.assertEqual([""], page1.get_sections()) | |||
| self.assertEqual(["", "==Heading=="], page2.get_sections()) | |||
| self.assertEqual(["", "===Heading===\nFoo bar baz\n====Gnidaeh====\n", | |||
| "====Gnidaeh====\n"], page3.get_sections()) | |||
| self.assertEqual([p4_lead, p4_IA, p4_I, p4_IB, p4_IB1, p4_II, | |||
| p4_IIIA1a, p4_III, p4_IIIA, p4_IIIA2, p4_IIIA2ai1], | |||
| self.assertEqual([p4_lead, p4_I, p4_IA, p4_IB, p4_IB1, p4_II, | |||
| p4_III, p4_IIIA, p4_IIIA1a, p4_IIIA2, p4_IIIA2ai1], | |||
| page4.get_sections()) | |||
| self.assertEqual(["====Gnidaeh====\n"], page3.get_sections(levels=[4])) | |||
| @@ -370,16 +370,16 @@ class TestWikicode(TreeEqualityTestCase): | |||
| page3.get_sections(include_lead=False)) | |||
| self.assertEqual([p4_IB1, p4_IIIA2], page4.get_sections(levels=[4])) | |||
| self.assertEqual([""], page2.get_sections(include_headings=False)) | |||
| self.assertEqual(["", ""], page2.get_sections(include_headings=False)) | |||
| self.assertEqual(["\nSection I.B.1 body.\n\n•Some content.\n\n", | |||
| "\nEven more text.\n" + p4_IIIA2ai1], | |||
| page4.get_sections(levels=[4], | |||
| include_headings=False)) | |||
| self.assertEqual([], page4.get_sections(matches=r"body")) | |||
| self.assertEqual([p4_IA, p4_I, p4_IB, p4_IB1], | |||
| self.assertEqual([p4_I, p4_IA, p4_IB, p4_IB1], | |||
| page4.get_sections(matches=r"Section\sI[.\s].*?")) | |||
| self.assertEqual([p4_IA, p4_IIIA1a, p4_IIIA, p4_IIIA2, p4_IIIA2ai1], | |||
| self.assertEqual([p4_IA, p4_IIIA, p4_IIIA1a, p4_IIIA2, p4_IIIA2ai1], | |||
| page4.get_sections(matches=r".*?a.*?")) | |||
| self.assertEqual([p4_IIIA1a, p4_IIIA2ai1], | |||
| page4.get_sections(matches=r".*?a.*?", flags=re.U)) | |||
| @@ -387,6 +387,11 @@ class TestWikicode(TreeEqualityTestCase): | |||
| page4.get_sections(matches=r".*?a.*?", flags=re.U, | |||
| include_headings=False)) | |||
| sections = page2.get_sections(include_headings=False) | |||
| sections[0].append("Lead!\n") | |||
| sections[1].append("\nFirst section!") | |||
| self.assertEqual("Lead!\n==Heading==\nFirst section!", page2) | |||
| page5 = parse("X\n== Foo ==\nBar\n== Baz ==\nBuzz") | |||
| section = page5.get_sections(matches="Foo")[0] | |||
| section.replace("\nBar\n", "\nBarf ") | |||