Bump version to 0.4.dev.tags/v0.3.3
| @@ -1,3 +1,8 @@ | |||||
| v0.4 (unreleased): | |||||
| - 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. | |||||
| v0.3.2 (released September 1, 2013): | v0.3.2 (released September 1, 2013): | ||||
| - Added support for Python 3.2 (along with current support for 3.3 and 2.7). | - Added support for Python 3.2 (along with current support for 3.3 and 2.7). | ||||
| @@ -1,6 +1,16 @@ | |||||
| Changelog | Changelog | ||||
| ========= | ========= | ||||
| v0.4 | |||||
| ---- | |||||
| Unreleased | |||||
| (`changes <https://github.com/earwig/mwparserfromhell/compare/v0.3.2...develop>`__): | |||||
| - 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. | |||||
| v0.3.2 | v0.3.2 | ||||
| ------ | ------ | ||||
| @@ -31,7 +31,7 @@ from __future__ import unicode_literals | |||||
| __author__ = "Ben Kurtovic" | __author__ = "Ben Kurtovic" | ||||
| __copyright__ = "Copyright (C) 2012, 2013 Ben Kurtovic" | __copyright__ = "Copyright (C) 2012, 2013 Ben Kurtovic" | ||||
| __license__ = "MIT License" | __license__ = "MIT License" | ||||
| __version__ = "0.3.2" | |||||
| __version__ = "0.4.dev" | |||||
| __email__ = "ben.kurtovic@verizon.net" | __email__ = "ben.kurtovic@verizon.net" | ||||
| from . import (compat, definitions, nodes, parser, smart_list, string_mixin, | from . import (compat, definitions, nodes, parser, smart_list, string_mixin, | ||||
| @@ -378,17 +378,21 @@ class Wikicode(StringMixIn): | |||||
| """Iterate over nodes in our list matching certain conditions. | """Iterate over nodes in our list matching certain conditions. | ||||
| If *recursive* is ``True``, we will iterate over our children and all | If *recursive* is ``True``, we will iterate over our children and all | ||||
| descendants of our children, otherwise just our immediate children. If | |||||
| *matches* is given, we will only yield the nodes that match the given | |||||
| regular expression (with :py:func:`re.search`). The default flags used | |||||
| are :py:const:`re.IGNORECASE`, :py:const:`re.DOTALL`, and | |||||
| :py:const:`re.UNICODE`, but custom flags can be specified by passing | |||||
| *flags*. If *forcetype* is given, only nodes that are instances of this | |||||
| type are yielded. | |||||
| of their descendants, otherwise just our immediate children. If | |||||
| *forcetype* is given, only nodes that are instances of this type are | |||||
| yielded. *matches* can be used to further restrict the nodes, either as | |||||
| a function (taking a single :py:class:`.Node` and returning a boolean) | |||||
| or a regular expression (matched against the node's string | |||||
| representation with :py:func:`re.search`). If *matches* is a regex, the | |||||
| flags passed to :py:func:`re.search` are :py:const:`re.IGNORECASE`, | |||||
| :py:const:`re.DOTALL`, and :py:const:`re.UNICODE`, but custom flags can | |||||
| be specified by passing *flags*. | |||||
| """ | """ | ||||
| if matches and not callable(matches): | |||||
| pat, matches = matches, lambda obj: re.search(pat, str(obj), flags) | |||||
| for node in (self._get_all_nodes(self) if recursive else self.nodes): | for node in (self._get_all_nodes(self) if recursive else self.nodes): | ||||
| if not forcetype or isinstance(node, forcetype): | if not forcetype or isinstance(node, forcetype): | ||||
| if not matches or re.search(matches, str(node), flags): | |||||
| if not matches or matches(node): | |||||
| yield node | yield node | ||||
| def filter(self, recursive=True, matches=None, flags=FLAGS, | def filter(self, recursive=True, matches=None, flags=FLAGS, | ||||
| @@ -256,7 +256,7 @@ class TestWikicode(TreeEqualityTestCase): | |||||
| def genlist(gen): | def genlist(gen): | ||||
| self.assertIsInstance(gen, GeneratorType) | self.assertIsInstance(gen, GeneratorType) | ||||
| return list(gen) | return list(gen) | ||||
| ifilter = lambda code: (lambda **kw: genlist(code.ifilter(**kw))) | |||||
| ifilter = lambda code: (lambda *a, **k: genlist(code.ifilter(*a, **k))) | |||||
| code = parse("a{{b}}c[[d]]{{{e}}}{{f}}[[g]]") | code = parse("a{{b}}c[[d]]{{{e}}}{{f}}[[g]]") | ||||
| for func in (code.filter, ifilter(code)): | for func in (code.filter, ifilter(code)): | ||||
| @@ -292,21 +292,27 @@ class TestWikicode(TreeEqualityTestCase): | |||||
| "{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"], | "{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"], | ||||
| func(recursive=True, forcetype=Template)) | func(recursive=True, forcetype=Template)) | ||||
| code3 = parse("{{foobar}}{{FOO}}{{baz}}{{bz}}") | |||||
| code3 = parse("{{foobar}}{{FOO}}{{baz}}{{bz}}{{barfoo}}") | |||||
| for func in (code3.filter, ifilter(code3)): | for func in (code3.filter, ifilter(code3)): | ||||
| self.assertEqual(["{{foobar}}", "{{FOO}}"], func(recursive=False, matches=r"foo")) | |||||
| self.assertEqual(["{{foobar}}", "{{barfoo}}"], | |||||
| func(False, matches=lambda node: "foo" in node)) | |||||
| self.assertEqual(["{{foobar}}", "{{FOO}}", "{{barfoo}}"], | |||||
| func(False, matches=r"foo")) | |||||
| self.assertEqual(["{{foobar}}", "{{FOO}}"], | self.assertEqual(["{{foobar}}", "{{FOO}}"], | ||||
| func(recursive=False, matches=r"^{{foo.*?}}")) | |||||
| func(matches=r"^{{foo.*?}}")) | |||||
| self.assertEqual(["{{foobar}}"], | self.assertEqual(["{{foobar}}"], | ||||
| func(recursive=False, matches=r"^{{foo.*?}}", flags=re.UNICODE)) | |||||
| self.assertEqual(["{{baz}}", "{{bz}}"], func(recursive=False, matches=r"^{{b.*?z")) | |||||
| self.assertEqual(["{{baz}}"], func(recursive=False, matches=r"^{{b.+?z}}")) | |||||
| func(matches=r"^{{foo.*?}}", flags=re.UNICODE)) | |||||
| self.assertEqual(["{{baz}}", "{{bz}}"], func(matches=r"^{{b.*?z")) | |||||
| self.assertEqual(["{{baz}}"], func(matches=r"^{{b.+?z}}")) | |||||
| self.assertEqual(["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}"], | self.assertEqual(["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}"], | ||||
| code2.filter_templates(recursive=False)) | code2.filter_templates(recursive=False)) | ||||
| self.assertEqual(["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}", "{{b}}", | self.assertEqual(["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}", "{{b}}", | ||||
| "{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"], | "{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"], | ||||
| code2.filter_templates(recursive=True)) | code2.filter_templates(recursive=True)) | ||||
| self.assertEqual(["{{foobar}}"], code3.filter_templates( | |||||
| matches=lambda node: node.name.matches("Foobar"))) | |||||
| self.assertEqual(["{{baz}}", "{{bz}}"], | self.assertEqual(["{{baz}}", "{{bz}}"], | ||||
| code3.filter_templates(matches=r"^{{b.*?z")) | code3.filter_templates(matches=r"^{{b.*?z")) | ||||
| self.assertEqual([], code3.filter_tags(matches=r"^{{b.*?z")) | self.assertEqual([], code3.filter_tags(matches=r"^{{b.*?z")) | ||||