walker: fix index path string cast
[mdis.git] / src / mdis / walker.py
1 __all__ = [
2 "Walker",
3 "WalkerMeta",
4 ]
5
6 import enum
7 import dataclasses
8
9 from . import dispatcher
10
11
12 class WalkerMeta(dispatcher.DispatcherMeta):
13 pass
14
15
16 class GenericPath:
17 def __init__(self, path):
18 self.__path = path
19 return super().__init__()
20
21 def __str__(self):
22 return self.__path.__str__()
23
24 def __repr__(self):
25 return f"{self.__class__.__name__}({str(self)})"
26
27 @property
28 def path(self):
29 return self.__path
30
31
32 class IndexPath(GenericPath):
33 def __str__(self):
34 return f"[{self.path!r}]"
35
36
37 class AttributePath(GenericPath):
38 def __str__(self):
39 return f".{self.path}]"
40
41
42 class HashPath(GenericPath):
43 def __str__(self):
44 return f"{{{self.path}}}"
45
46
47 class Walker(dispatcher.Dispatcher, metaclass=WalkerMeta):
48 @dispatcher.Hook(tuple, list)
49 def dispatch_ordered_sequence(self, node, *_, **__):
50 for (index, item) in enumerate(node):
51 yield (item, node, index, IndexPath)
52
53 @dispatcher.Hook(set, frozenset)
54 def dispatch_unordered_sequence(self, node, *_, **__):
55 for item in node:
56 yield (item, node, item, HashPath)
57
58 @dispatcher.Hook(dataclasses.is_dataclass)
59 def dispatch_dataclass(self, node, *_, **__):
60 for field in dataclasses.fields(node):
61 key = field.name
62 value = getattr(node, key)
63 yield (value, node, key, AttributePath)
64
65 @dispatcher.Hook(dict)
66 def dispatch_mapping(self, node, *_, **__):
67 for (key, value) in node.items():
68 yield (key, node, key, HashPath)
69 yield (value, node, key, IndexPath)
70
71 @dispatcher.Hook(object)
72 def dispatch_object(self, node, *_, **__):
73 yield from ()