578284e4c9b9667ceb44f759e200fd9f92a25834
[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 PartId(enum.Enum):
17 Index = enum.auto()
18 Attribute = enum.auto()
19 Hash = enum.auto()
20
21 def __call__(self, part):
22 return {
23 PartId.Index: "[{part}]",
24 PartId.Attribute: ".{part}",
25 PartId.Hash: "{{{part}}}",
26 }[self].format(part=part)
27
28
29 class Walker(dispatcher.Dispatcher, metaclass=WalkerMeta):
30 @dispatcher.Hook(tuple, list)
31 def dispatch_ordered_sequence(self, instance, path=()):
32 for (index, item) in enumerate(instance):
33 part = (PartId.Index, index)
34 parts = (path + (part,))
35 yield (item, parts)
36 yield from self(item, path=parts)
37
38 @dispatcher.Hook(set, frozenset)
39 def dispatch_unordered_sequence(self, instance, path=[]):
40 for item in instance:
41 part = (PartId.Hash, item)
42 parts = (path + (part,))
43 yield (item, parts)
44 yield from self(item, path=parts)
45
46 @dispatcher.Hook(dataclasses.is_dataclass)
47 def dispatch_dataclass(self, instance, path=[]):
48 for field in dataclasses.fields(instance):
49 key = field.name
50 value = getattr(instance, key)
51 part = (PartId.Attribute, key)
52 parts = (path + (part,))
53 yield (value, parts)
54 yield from self(value, path=parts)
55
56 @dispatcher.Hook(dict)
57 def dispatch_mapping(self, instance, path=[]):
58 for (key, value) in instance.items():
59 part = (PartId.Index, key)
60 parts = (path + (part,))
61 yield (value, parts)
62 yield from self(value, path=parts)
63
64 @dispatcher.Hook(object)
65 def dispatch_object(self, instance, path=()):
66 yield from ()