File: ast.py

package info (click to toggle)
python-tatsu 5.13.1%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 892 kB
  • sloc: python: 10,202; makefile: 54
file content (134 lines) | stat: -rw-r--r-- 3,402 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from __future__ import annotations

import copy
import operator
from functools import reduce

from .util import asjson, is_list


class AST(dict):
    _frozen = False

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.update(*args, **kwargs)
        self._frozen = True

    @property
    def frozen(self):
        return self._frozen

    @property
    def parseinfo(self):
        try:
            return super().__getitem__('parseinfo')
        except KeyError:
            pass

    def set_parseinfo(self, value):
        super().__setitem__('parseinfo', value)

    def copy(self):
        return copy.copy(self)

    def asjson(self):
        return asjson(self)

    def _set(self, key, value, force_list=False):
        key = self._safekey(key)
        previous = self.get(key)

        if previous is None and force_list:
            value = [value]
        elif previous is None:
            pass
        elif is_list(previous):
            value = [*previous, value]
        else:
            value = [previous, value]

        super().__setitem__(key, value)

    def _setlist(self, key, value):
        return self._set(key, value, force_list=True)

    def __copy__(self):
        return AST(self)

    def __getitem__(self, key):
        if key in self:
            return super().__getitem__(key)
        key = self._safekey(key)
        if key in self:
            return super().__getitem__(key)
        return None

    def __setitem__(self, key, value):
        self._set(key, value)

    def __delitem__(self, key):
        key = self._safekey(key)
        super().__delitem__(key)

    def __setattr__(self, name, value):
        if self._frozen and name not in vars(self):
            raise AttributeError(
                f'{type(self).__name__} attributes are fixed. '
                f' Cannot set attribute "{name}".',
            )
        super().__setattr__(name, value)

    def __getattr__(self, name):
        key = self._safekey(name)
        if key in self:
            return self[key]
        elif name in self:
            return self[name]

        try:
            return super().__getattribute__(name)
        except AttributeError:
            return None

    def __hasattribute__(self, name):
        try:
            super().__getattribute__(name)
        except (TypeError, AttributeError):
            return False
        else:
            return True

    def __reduce__(self):
        return (AST, (list(self.items()),))

    def _safekey(self, key):
        while self.__hasattribute__(key):
            key += '_'
        return key

    def _define(self, keys, list_keys=None):
        for key in (self._safekey(k) for k in keys):
            if key not in self:
                super().__setitem__(key, None)

        for key in (self._safekey(k) for k in list_keys or []):
            if key not in self:
                super().__setitem__(key, [])

    def __json__(self, seen=None):
        return {name: asjson(value, seen=seen) for name, value in self.items()}

    def __repr__(self):
        return repr(self.asjson())

    def __str__(self):
        return str(self.asjson())

    def __hash__(self):
        # NOTE: objects are actually mutable during creation
        return reduce(
            operator.xor,
            (hash((name, id(value))) for name, value in self.items()),
            0,
        )