Skip to content

Commit 724f05c

Browse files
committed
#36 improve the type signature of find_ancestor_of_type
1 parent e7eeae6 commit 724f05c

3 files changed

Lines changed: 12 additions & 69 deletions

File tree

pylasu/model/traversing.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import TypeVar, Type
2+
13
from . import Position
24
from .model import Node
35
from ..support import extension_method
@@ -56,8 +58,10 @@ def walk_descendants(self: Node, walker=walk, restrict_to=Node):
5658
yield node
5759

5860

61+
T = TypeVar("T")
62+
5963
@extension_method(Node)
60-
def find_ancestor_of_type(self: Node, target: type):
64+
def find_ancestor_of_type(self: Node, target: Type[T]) -> T:
6165
"""Returns the nearest ancestor of this node that is an instance of the target type.
6266
6367
Note that type is not strictly forced to be a subtype of Node. This is intended to support trait types like

pylasu/testing/testing.py

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +0,0 @@
1-
import unittest
2-
3-
from pylasu.model import Node
4-
5-
6-
def assert_asts_are_equal(
7-
case: unittest.TestCase,
8-
expected: Node, actual: Node,
9-
context: str = "<root>", consider_position: bool = False
10-
):
11-
if expected.node_type != actual.node_type:
12-
case.fail(f"{context}: expected node of type {expected.node_type}, "
13-
f"but found {actual.node_type}")
14-
if consider_position:
15-
case.assertEqual(expected.position, actual.position, f"{context}.position")
16-
for expected_property in expected.properties:
17-
try:
18-
actual_property = next(filter(lambda p: p.name == expected_property.name, actual.properties))
19-
except StopIteration:
20-
case.fail(f"No property {expected_property.name} found at {context}")
21-
actual_prop_value = actual_property.value
22-
expected_prop_value = expected_property.value
23-
if expected_property.provides_nodes:
24-
if expected_property.multiple:
25-
assert_multi_properties_are_equal(
26-
case, expected_property, expected_prop_value, actual_prop_value, context, consider_position)
27-
else:
28-
assert_single_properties_are_equal(case, expected_property, expected_prop_value, actual_prop_value,
29-
context, consider_position)
30-
# TODO not yet supported elif expected_property.property_type == PropertyType.REFERENCE:
31-
else:
32-
case.assertEqual(
33-
expected_prop_value, actual_prop_value,
34-
f"{context}, comparing property {expected_property.name} of {expected.node_type}")
35-
36-
37-
def assert_single_properties_are_equal(case, expected_property, expected_prop_value, actual_prop_value, context,
38-
consider_position):
39-
if expected_prop_value is None and actual_prop_value is not None:
40-
case.assertEqual(expected_prop_value, actual_prop_value,
41-
f"{context}.{expected_property.name}")
42-
elif expected_prop_value is not None and actual_prop_value is None:
43-
case.assertEqual(expected_prop_value, actual_prop_value,
44-
f"{context}.{expected_property.name}")
45-
elif expected_prop_value is None and actual_prop_value is None:
46-
# that is ok
47-
pass
48-
else:
49-
case.assertIsInstance(actual_prop_value, Node)
50-
assert_asts_are_equal(
51-
case, expected_prop_value, actual_prop_value,
52-
context=f"{context}.{expected_property.name}",
53-
consider_position=consider_position)
54-
55-
56-
def assert_multi_properties_are_equal(case, expected_property, expected_prop_value, actual_prop_value, context,
57-
consider_position):
58-
# TODO IgnoreChildren
59-
case.assertEqual(actual_prop_value is None, expected_prop_value is None,
60-
f"{context}.{expected_property.name} nullness")
61-
if actual_prop_value is not None and expected_prop_value is not None:
62-
case.assertEqual(len(actual_prop_value), len(expected_prop_value),
63-
f"{context}.{expected_property.name} length")
64-
for expected_it, actual_it, i in \
65-
zip(expected_prop_value, actual_prop_value, range(len(expected_prop_value))):
66-
assert_asts_are_equal(case, expected_it, actual_it, f"{context}[{i}]",
67-
consider_position=consider_position)

tests/test_traversing.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import unittest
22

33
from pylasu.model import pos
4-
from tests.fixtures import box
4+
from pylasu.model.traversing import find_ancestor_of_type
5+
from tests.fixtures import box, Box
56

67

78
class TraversingTest(unittest.TestCase):
@@ -42,3 +43,8 @@ def test_walk_ancestors(self):
4243
box.assign_parents()
4344
item4 = box.contents[2].contents[0].contents[1]
4445
self.assertEqual(["small", "big", "root"], [n.name for n in item4.walk_ancestors()])
46+
47+
def test_find_ancestor_of_type(self):
48+
box.assign_parents()
49+
item = box.contents[1]
50+
self.assertEqual(box, find_ancestor_of_type(item, Box))

0 commit comments

Comments
 (0)