From 083b0df48e78b9d87f731747322a38d40d6cb64d Mon Sep 17 00:00:00 2001 From: GuGuMur <2221533105@qq.com> Date: Sun, 30 Mar 2025 13:47:46 +0800 Subject: [PATCH] feat: update template via encapsulated method --- .gitignore | 1 + src/mwparserfromhell/nodes/template.py | 41 ++++++++++++++++++++++++--- tests/test_template.py | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index b966a55..ffb8df4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ htmlcov/ compile_commands.json .idea/ .pytest_cache/ +.venv diff --git a/src/mwparserfromhell/nodes/template.py b/src/mwparserfromhell/nodes/template.py index ef0bcd1..05bd931 100644 --- a/src/mwparserfromhell/nodes/template.py +++ b/src/mwparserfromhell/nodes/template.py @@ -17,8 +17,11 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. - +import sys +from pathlib import Path +sys.path.append(str(Path(__file__).parent.parent)) from collections import defaultdict +from typing import TypedDict import re from ._base import Node @@ -32,7 +35,14 @@ __all__ = ["Template"] FLAGS = re.DOTALL | re.UNICODE # Used to allow None as a valid fallback value _UNSET = object() - +class TemplateParam(TypedDict): + """TypedDict for template.update() method.""" + name: any + value: any + showkey: bool | None = None + before: str | None = None + after: str | None = None + preserve_spacing: bool = True class Template(Node): """Represents a template in wikicode, like ``{{foo}}``.""" @@ -238,8 +248,14 @@ class Template(Node): return self.get(name) def add( - self, name, value, showkey=None, before=None, after=None, preserve_spacing=True - ): + self, + name: any, + value: any, + showkey: bool | None = None, + before: str | None = None, + after: str | None = None, + preserve_spacing: bool = True + ) -> Parameter: """Add a parameter to the template with a given *name* and *value*. *name* and *value* can be anything parsable by @@ -330,6 +346,23 @@ class Template(Node): self.params.append(param) return param + def update(self, params: list[TemplateParam]): + """Update the template with multiple parameters at once. + + This method accepts a list of parameter dictionaries, each containing + the same arguments as :meth:`add`. It will process each parameter + in order using the same logic as :meth:`add`. + """ + for param in params: + self.add( + name=param["name"], + value=param["value"], + showkey=param.get("showkey"), + before=param.get("before"), + after=param.get("after"), + preserve_spacing=param.get("preserve_spacing", True) + ) + def __setitem__(self, name, value): return self.add(name, value) diff --git a/tests/test_template.py b/tests/test_template.py index a67b9cd..aa3a664 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -394,6 +394,58 @@ def test_add(): assert "{{a|b=c|d=e|f=g|new_param=value}}" == node44 +def test_update(): + """test template.update()""" + node1 = Template(wraptext("a")) + node1.update([{"name": "b", "value": "c"}]) + assert "{{a|b=c}}" == node1 + + node2 = Template(wraptext("a")) + node2.update([{"name": "1", "value": "b", "showkey": False}]) + assert "{{a|b}}" == node2 + + node3 = Template(wraptext("a"), [pgens("b", "c"), pgens("d", "e")]) + node3.update([ + {"name": "f", "value": "g", "before": "d"}, + {"name": "h", "value": "i", "after": "b"} + ]) + assert "{{a|b=c|h=i|f=g|d=e}}" == node3 + + node4 = Template(wraptext("a\n"), [ + pgens("b ", "c\n"), + pgens("d ", " e") + ]) + node4.update([{ + "name": "e", + "value": "f", + "preserve_spacing": True + }]) + assert "{{a\n|b =c\n|d = e|e =f}}" == node4 + + node5 = Template(wraptext("a"), [pgens("b", "c")]) + node5.update([ + { + "name": "1", + "value": "e", + "showkey": False, + "before": "b" + }, + { + "name": "f", + "value": "g", + "preserve_spacing": False + } + ]) + assert "{{a|e|b=c|f=g}}" == node5 + + node6 = Template(wraptext("a"), [pgens("b", "c")]) + node6.update([{"name": "b", "value": "d"}]) + assert "{{a|b=d}}" == node6 + + node7 = Template(wraptext("a"), [pgenh("1", "b")]) + node7.update([{"name": "1", "value": "c"}]) + assert "{{a|c}}" == node7 + def test_remove(): """test Template.remove()""" node1 = Template(wraptext("foobar"))