summaryrefslogtreecommitdiff
path: root/tests/test_templite.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2023-01-07 22:54:05 -0500
committerNed Batchelder <ned@nedbatchelder.com>2023-01-07 22:54:05 -0500
commit08564c09144b2223be808f49b001c8856966bd46 (patch)
tree3bfe15a660292e1463448988c95de683a4a553cd /tests/test_templite.py
parent65aad086ccccea33f0ff9535c9612e1b4b6712ce (diff)
downloadpython-coveragepy-git-08564c09144b2223be808f49b001c8856966bd46.tar.gz
mypy: templite.py test_templite.py
Diffstat (limited to 'tests/test_templite.py')
-rw-r--r--tests/test_templite.py96
1 files changed, 48 insertions, 48 deletions
diff --git a/tests/test_templite.py b/tests/test_templite.py
index d2e98479..e34f7169 100644
--- a/tests/test_templite.py
+++ b/tests/test_templite.py
@@ -3,8 +3,13 @@
"""Tests for coverage.templite."""
+from __future__ import annotations
+
import re
+from types import SimpleNamespace
+from typing import Any, ContextManager, Dict, List, Optional
+
import pytest
from coverage.templite import Templite, TempliteSyntaxError, TempliteValueError
@@ -13,23 +18,18 @@ from tests.coveragetest import CoverageTest
# pylint: disable=possibly-unused-variable
-class AnyOldObject:
- """Simple testing object.
-
- Use keyword arguments in the constructor to set attributes on the object.
-
- """
- def __init__(self, **attrs):
- for n, v in attrs.items():
- setattr(self, n, v)
-
class TempliteTest(CoverageTest):
"""Tests for Templite."""
run_in_temp_dir = False
- def try_render(self, text, ctx=None, result=None):
+ def try_render(
+ self,
+ text: str,
+ ctx: Optional[Dict[str, Any]] = None,
+ result: Optional[str] = None,
+ ) -> None:
"""Render `text` through `ctx`, and it had better be `result`.
Result defaults to None so we can shorten the calls where we expect
@@ -42,30 +42,30 @@ class TempliteTest(CoverageTest):
assert result is not None
assert actual == result
- def assertSynErr(self, msg):
+ def assertSynErr(self, msg: str) -> ContextManager[None]:
"""Assert that a `TempliteSyntaxError` will happen.
A context manager, and the message should be `msg`.
"""
pat = "^" + re.escape(msg) + "$"
- return pytest.raises(TempliteSyntaxError, match=pat)
+ return pytest.raises(TempliteSyntaxError, match=pat) # type: ignore
- def test_passthrough(self):
+ def test_passthrough(self) -> None:
# Strings without variables are passed through unchanged.
assert Templite("Hello").render() == "Hello"
assert Templite("Hello, 20% fun time!").render() == "Hello, 20% fun time!"
- def test_variables(self):
+ def test_variables(self) -> None:
# Variables use {{var}} syntax.
self.try_render("Hello, {{name}}!", {'name':'Ned'}, "Hello, Ned!")
- def test_undefined_variables(self):
+ def test_undefined_variables(self) -> None:
# Using undefined names is an error.
with pytest.raises(Exception, match="'name'"):
self.try_render("Hi, {{name}}!")
- def test_pipes(self):
+ def test_pipes(self) -> None:
# Variables can be filtered with pipes.
data = {
'name': 'Ned',
@@ -77,7 +77,7 @@ class TempliteTest(CoverageTest):
# Pipes can be concatenated.
self.try_render("Hello, {{name|upper|second}}!", data, "Hello, E!")
- def test_reusability(self):
+ def test_reusability(self) -> None:
# A single Templite can be used more than once with different data.
globs = {
'upper': lambda x: x.upper(),
@@ -88,30 +88,30 @@ class TempliteTest(CoverageTest):
assert template.render({'name':'Ned'}) == "This is NED!"
assert template.render({'name':'Ben'}) == "This is BEN!"
- def test_attribute(self):
+ def test_attribute(self) -> None:
# Variables' attributes can be accessed with dots.
- obj = AnyOldObject(a="Ay")
+ obj = SimpleNamespace(a="Ay")
self.try_render("{{obj.a}}", locals(), "Ay")
- obj2 = AnyOldObject(obj=obj, b="Bee")
+ obj2 = SimpleNamespace(obj=obj, b="Bee")
self.try_render("{{obj2.obj.a}} {{obj2.b}}", locals(), "Ay Bee")
- def test_member_function(self):
+ def test_member_function(self) -> None:
# Variables' member functions can be used, as long as they are nullary.
- class WithMemberFns(AnyOldObject):
+ class WithMemberFns(SimpleNamespace):
"""A class to try out member function access."""
- def ditto(self):
+ def ditto(self) -> str:
"""Return twice the .txt attribute."""
- return self.txt + self.txt
+ return self.txt + self.txt # type: ignore
obj = WithMemberFns(txt="Once")
self.try_render("{{obj.ditto}}", locals(), "OnceOnce")
- def test_item_access(self):
+ def test_item_access(self) -> None:
# Variables' items can be used.
d = {'a':17, 'b':23}
self.try_render("{{d.a}} < {{d.b}}", locals(), "17 < 23")
- def test_loops(self):
+ def test_loops(self) -> None:
# Loops work like in Django.
nums = [1,2,3,4]
self.try_render(
@@ -120,7 +120,7 @@ class TempliteTest(CoverageTest):
"Look: 1, 2, 3, 4, done."
)
# Loop iterables can be filtered.
- def rev(l):
+ def rev(l: List[int]) -> List[int]:
"""Return the reverse of `l`."""
l = l[:]
l.reverse()
@@ -132,21 +132,21 @@ class TempliteTest(CoverageTest):
"Look: 4, 3, 2, 1, done."
)
- def test_empty_loops(self):
+ def test_empty_loops(self) -> None:
self.try_render(
"Empty: {% for n in nums %}{{n}}, {% endfor %}done.",
{'nums':[]},
"Empty: done."
)
- def test_multiline_loops(self):
+ def test_multiline_loops(self) -> None:
self.try_render(
"Look: \n{% for n in nums %}\n{{n}}, \n{% endfor %}done.",
{'nums':[1,2,3]},
"Look: \n\n1, \n\n2, \n\n3, \ndone."
)
- def test_multiple_loops(self):
+ def test_multiple_loops(self) -> None:
self.try_render(
"{% for n in nums %}{{n}}{% endfor %} and " +
"{% for n in nums %}{{n}}{% endfor %}",
@@ -154,7 +154,7 @@ class TempliteTest(CoverageTest):
"123 and 123"
)
- def test_comments(self):
+ def test_comments(self) -> None:
# Single-line comments work:
self.try_render(
"Hello, {# Name goes here: #}{{name}}!",
@@ -166,7 +166,7 @@ class TempliteTest(CoverageTest):
{'name':'Ned'}, "Hello, Ned!"
)
- def test_if(self):
+ def test_if(self) -> None:
self.try_render(
"Hi, {% if ned %}NED{% endif %}{% if ben %}BEN{% endif %}!",
{'ned': 1, 'ben': 0},
@@ -193,10 +193,10 @@ class TempliteTest(CoverageTest):
"Hi, NEDBEN!"
)
- def test_complex_if(self):
- class Complex(AnyOldObject):
+ def test_complex_if(self) -> None:
+ class Complex(SimpleNamespace):
"""A class to try out complex data access."""
- def getit(self):
+ def getit(self): # type: ignore
"""Return it."""
return self.it
obj = Complex(it={'x':"Hello", 'y': 0})
@@ -210,7 +210,7 @@ class TempliteTest(CoverageTest):
"@XS!"
)
- def test_loop_if(self):
+ def test_loop_if(self) -> None:
self.try_render(
"@{% for n in nums %}{% if n %}Z{% endif %}{{n}}{% endfor %}!",
{'nums': [0,1,2]},
@@ -227,7 +227,7 @@ class TempliteTest(CoverageTest):
"X!"
)
- def test_nested_loops(self):
+ def test_nested_loops(self) -> None:
self.try_render(
"@" +
"{% for n in nums %}" +
@@ -238,7 +238,7 @@ class TempliteTest(CoverageTest):
"@a0b0c0a1b1c1a2b2c2!"
)
- def test_whitespace_handling(self):
+ def test_whitespace_handling(self) -> None:
self.try_render(
"@{% for n in nums %}\n" +
" {% for a in abc %}{{a}}{{n}}{% endfor %}\n" +
@@ -268,7 +268,7 @@ class TempliteTest(CoverageTest):
)
self.try_render(" hello ", {}, " hello ")
- def test_eat_whitespace(self):
+ def test_eat_whitespace(self) -> None:
self.try_render(
"Hey!\n" +
"{% joined %}\n" +
@@ -286,14 +286,14 @@ class TempliteTest(CoverageTest):
"Hey!\n@XYa0XYb0XYc0XYa1XYb1XYc1XYa2XYb2XYc2!\n"
)
- def test_non_ascii(self):
+ def test_non_ascii(self) -> None:
self.try_render(
"{{where}} ollǝɥ",
{ 'where': 'ǝɹǝɥʇ' },
"ǝɹǝɥʇ ollǝɥ"
)
- def test_exception_during_evaluation(self):
+ def test_exception_during_evaluation(self) -> None:
# TypeError: Couldn't evaluate {{ foo.bar.baz }}:
regex = "^Couldn't evaluate None.bar$"
with pytest.raises(TempliteValueError, match=regex):
@@ -301,7 +301,7 @@ class TempliteTest(CoverageTest):
"Hey {{foo.bar.baz}} there", {'foo': None}, "Hey ??? there"
)
- def test_bad_names(self):
+ def test_bad_names(self) -> None:
with self.assertSynErr("Not a valid name: 'var%&!@'"):
self.try_render("Wat: {{ var%&!@ }}")
with self.assertSynErr("Not a valid name: 'filter%&!@'"):
@@ -309,17 +309,17 @@ class TempliteTest(CoverageTest):
with self.assertSynErr("Not a valid name: '@'"):
self.try_render("Wat: {% for @ in x %}{% endfor %}")
- def test_bogus_tag_syntax(self):
+ def test_bogus_tag_syntax(self) -> None:
with self.assertSynErr("Don't understand tag: 'bogus'"):
self.try_render("Huh: {% bogus %}!!{% endbogus %}??")
- def test_malformed_if(self):
+ def test_malformed_if(self) -> None:
with self.assertSynErr("Don't understand if: '{% if %}'"):
self.try_render("Buh? {% if %}hi!{% endif %}")
with self.assertSynErr("Don't understand if: '{% if this or that %}'"):
self.try_render("Buh? {% if this or that %}hi!{% endif %}")
- def test_malformed_for(self):
+ def test_malformed_for(self) -> None:
with self.assertSynErr("Don't understand for: '{% for %}'"):
self.try_render("Weird: {% for %}loop{% endfor %}")
with self.assertSynErr("Don't understand for: '{% for x from y %}'"):
@@ -327,7 +327,7 @@ class TempliteTest(CoverageTest):
with self.assertSynErr("Don't understand for: '{% for x, y in z %}'"):
self.try_render("Weird: {% for x, y in z %}loop{% endfor %}")
- def test_bad_nesting(self):
+ def test_bad_nesting(self) -> None:
with self.assertSynErr("Unmatched action tag: 'if'"):
self.try_render("{% if x %}X")
with self.assertSynErr("Mismatched end tag: 'for'"):
@@ -335,7 +335,7 @@ class TempliteTest(CoverageTest):
with self.assertSynErr("Too many ends: '{% endif %}'"):
self.try_render("{% if x %}{% endif %}{% endif %}")
- def test_malformed_end(self):
+ def test_malformed_end(self) -> None:
with self.assertSynErr("Don't understand end: '{% end if %}'"):
self.try_render("{% if x %}X{% end if %}")
with self.assertSynErr("Don't understand end: '{% endif now %}'"):