Reported by Σ.tags/v0.3.3
@@ -5,6 +5,7 @@ v0.4 (unreleased): | |||||
is a breaking change if you rely on the default behavior. | is a breaking change if you rely on the default behavior. | ||||
- The 'matches' argument of Wikicode's filter methods now accepts a function | - 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. | (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 | - Wikicode.matches() now accepts a tuple or list of strings/Wikicode objects | ||||
instead of just a single string or Wikicode. | instead of just a single string or Wikicode. | ||||
- C code cleanup and speed improvements. | - C code cleanup and speed improvements. | ||||
@@ -14,6 +14,7 @@ Unreleased | |||||
- The *matches* argument of :py:class:`Wikicode's <.Wikicode>` | - The *matches* argument of :py:class:`Wikicode's <.Wikicode>` | ||||
:py:meth:`.filter` methods now accepts a function (taking one argument, a | :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: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 | - :py:meth:`.Wikicode.matches` now accepts a tuple or list of | ||||
strings/:py:class:`.Wikicode` objects instead of just a single string or | strings/:py:class:`.Wikicode` objects instead of just a single string or | ||||
:py:class:`.Wikicode`. | :py:class:`.Wikicode`. | ||||
@@ -434,34 +434,31 @@ class Wikicode(StringMixIn): | |||||
""" | """ | ||||
if matches: | if matches: | ||||
matches = r"^(=+?)\s*" + matches + r"\s*\1$" | 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: | 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 = [] | 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 | return sections | ||||
def strip_code(self, normalize=True, collapse=True): | def strip_code(self, normalize=True, collapse=True): | ||||
@@ -351,12 +351,12 @@ class TestWikicode(TreeEqualityTestCase): | |||||
p4_III = "== Section III ==\n" + p4_IIIA | p4_III = "== Section III ==\n" + p4_IIIA | ||||
page4 = parse(p4_lead + p4_I + p4_II + p4_III) | 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=="], page2.get_sections()) | ||||
self.assertEqual(["", "===Heading===\nFoo bar baz\n====Gnidaeh====\n", | self.assertEqual(["", "===Heading===\nFoo bar baz\n====Gnidaeh====\n", | ||||
"====Gnidaeh====\n"], page3.get_sections()) | "====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()) | page4.get_sections()) | ||||
self.assertEqual(["====Gnidaeh====\n"], page3.get_sections(levels=[4])) | self.assertEqual(["====Gnidaeh====\n"], page3.get_sections(levels=[4])) | ||||
@@ -370,16 +370,16 @@ class TestWikicode(TreeEqualityTestCase): | |||||
page3.get_sections(include_lead=False)) | page3.get_sections(include_lead=False)) | ||||
self.assertEqual([p4_IB1, p4_IIIA2], page4.get_sections(levels=[4])) | 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", | self.assertEqual(["\nSection I.B.1 body.\n\n•Some content.\n\n", | ||||
"\nEven more text.\n" + p4_IIIA2ai1], | "\nEven more text.\n" + p4_IIIA2ai1], | ||||
page4.get_sections(levels=[4], | page4.get_sections(levels=[4], | ||||
include_headings=False)) | include_headings=False)) | ||||
self.assertEqual([], page4.get_sections(matches=r"body")) | 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].*?")) | 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.*?")) | page4.get_sections(matches=r".*?a.*?")) | ||||
self.assertEqual([p4_IIIA1a, p4_IIIA2ai1], | self.assertEqual([p4_IIIA1a, p4_IIIA2ai1], | ||||
page4.get_sections(matches=r".*?a.*?", flags=re.U)) | 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, | page4.get_sections(matches=r".*?a.*?", flags=re.U, | ||||
include_headings=False)) | 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") | page5 = parse("X\n== Foo ==\nBar\n== Baz ==\nBuzz") | ||||
section = page5.get_sections(matches="Foo")[0] | section = page5.get_sections(matches="Foo")[0] | ||||
section.replace("\nBar\n", "\nBarf ") | section.replace("\nBar\n", "\nBarf ") | ||||