• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

feihoo87 / waveforms / 7111190278

06 Dec 2023 06:51AM UTC coverage: 33.465% (-9.2%) from 42.666%
7111190278

push

github

feihoo87
v1.9.0

1 of 1 new or added line in 1 file covered. (100.0%)

225 existing lines in 3 files now uncovered.

2795 of 8352 relevant lines covered (33.47%)

2.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/waveforms/baseconfig.py
UNCOV
1
from __future__ import annotations
×
2

UNCOV
3
import copy
×
UNCOV
4
import json
×
UNCOV
5
import random
×
UNCOV
6
from pathlib import Path
×
UNCOV
7
from typing import Any, Optional, Union
×
8

UNCOV
9
from .dicttree import flattenDict as _flattenDict
×
UNCOV
10
from .dicttree import flattenDictIter as _flattenDictIter
×
UNCOV
11
from .dicttree import foldDict as _foldDict
×
UNCOV
12
from .dicttree import update_tree as _update
×
13

14

UNCOV
15
def _query(q, dct):
×
16
    return {
×
17
        k.removeprefix(q + '.'): v
18
        for k, v in dct.items() if k.startswith(q + '.')
19
    }
20

21

UNCOV
22
def randomStr(n):
×
UNCOV
23
    s = ('abcdefghijklmnopqrstuvwxyz'
×
24
         'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
25
         '0123456789')
UNCOV
26
    return ''.join(random.choices(s, k=n))
×
27

28

UNCOV
29
def mixin(o: object, *traits: type) -> object:
×
UNCOV
30
    bases = (o.__class__, *traits)
×
UNCOV
31
    name = '_'.join([cls.__name__ for cls in bases])
×
UNCOV
32
    name = '_'.join([name, randomStr(6)])
×
UNCOV
33
    cls = type(name, bases, {})
×
UNCOV
34
    o.__class__ = cls
×
UNCOV
35
    return o
×
36

37

UNCOV
38
class TraitMeta(type):
×
UNCOV
39
    _traits = {}
×
40

UNCOV
41
    def __new__(cls, name, bases, namespace):
×
UNCOV
42
        cls = super().__new__(cls, name, bases, namespace)
×
UNCOV
43
        if name != 'Trait':
×
UNCOV
44
            TraitMeta._traits[name] = cls
×
UNCOV
45
        return cls
×
46

47

UNCOV
48
class Trait(metaclass=TraitMeta):
×
UNCOV
49
    pass
×
50

51

UNCOV
52
def queryKey(q, dct, prefix=None):
×
UNCOV
53
    if prefix is None:
×
54
        prefix = []
×
55

UNCOV
56
    keys = q.split('.', maxsplit=1)
×
57

UNCOV
58
    if not isinstance(dct, dict):
×
59
        k = '.'.join(prefix)
×
60
        raise KeyError(
×
61
            f"Query {k}.{q} error, type '{k}' is {type(dct)}, not dict.")
UNCOV
62
    try:
×
UNCOV
63
        sub = dct[keys[0]]
×
64
    except KeyError:
×
65
        k = '.'.join([*prefix, keys[0]])
×
66
        raise KeyError(
×
67
            f"Query {'.'.join([*prefix, q])} error, key '{k}' not found.")
68

UNCOV
69
    if len(keys) == 1:
×
UNCOV
70
        return sub
×
71

72
    else:
UNCOV
73
        return queryKey(keys[1], sub, [*prefix, keys[0]])
×
74

75

UNCOV
76
def query(q, dct, prefix=None):
×
UNCOV
77
    if isinstance(q, str):
×
UNCOV
78
        return queryKey(q, dct, prefix)
×
79
    elif isinstance(q, list):
×
80
        return [query(sub_q, dct, prefix) for sub_q in q]
×
81
    elif isinstance(q, tuple):
×
82
        return tuple([query(sub_q, dct, prefix) for sub_q in q])
×
83
    elif isinstance(q, set):
×
84
        return {sub_q: query(sub_q, dct, prefix) for sub_q in q}
×
85
    elif isinstance(q, dict):
×
86
        if prefix is None:
×
87
            prefix = []
×
88
        ret = {}
×
89
        for k, sub_q in q.items():
×
90
            if sub_q is None:
×
91
                ret[k] = queryKey(k, dct, prefix)
×
92
            else:
93
                ret[k] = query(sub_q, queryKey(k, dct, prefix), [*prefix, k])
×
94
        return ret
×
95
    else:
96
        raise TypeError
×
97

98

UNCOV
99
def setKey(q, value, dct, prefix=None):
×
100
    if prefix is None:
×
101
        prefix = []
×
102

103
    keys = q.split('.', maxsplit=1)
×
104

105
    if len(keys) == 1:
×
106
        if keys[0] in dct and isinstance(dct[keys[0]],
×
107
                                         dict) and not isinstance(value, dict):
108
            k = '.'.join([*prefix, keys[0]])
×
109
            raise ValueError(f'try to set a dict {k} to {type(value)}')
×
110
        else:
111
            dct[keys[0]] = value
×
112
    else:
113
        if keys[0] in dct and isinstance(dct[keys[0]], dict):
×
114
            sub = dct[keys[0]]
×
115
        elif keys[0] in dct and not isinstance(dct[keys[0]], dict):
×
116
            k = '.'.join([*prefix, keys[0]])
×
117
            raise ValueError(f'try to set a dict {k} to {type(value)}')
×
118
        else:
119
            sub = {}
×
120
            dct[keys[0]] = sub
×
121
        setKey(keys[1], sub, [*prefix, keys[0]])
×
122

123

UNCOV
124
class ConfigSection(dict):
×
UNCOV
125
    def __init__(self, cfg: BaseConfig, key: str):
×
UNCOV
126
        self._cfg_ = cfg
×
UNCOV
127
        self._key_ = key
×
128

UNCOV
129
    def __setitem__(self, key: str, value: Any) -> None:
×
UNCOV
130
        if self._cfg_ is None:
×
UNCOV
131
            self._modified_ = True
×
132
        else:
UNCOV
133
            self._cfg_._modified_ = True
×
UNCOV
134
        if isinstance(value, dict) and not isinstance(value, ConfigSection):
×
UNCOV
135
            key, *traits = key.split(':')
×
UNCOV
136
            if self._cfg_ is None:
×
UNCOV
137
                cfg = self
×
UNCOV
138
                k = key
×
139
            else:
UNCOV
140
                cfg = self._cfg_
×
UNCOV
141
                k = '.'.join([self._key_, key])
×
UNCOV
142
            d = ConfigSection(cfg, k)
×
UNCOV
143
            d.update(value)
×
UNCOV
144
            value = d
×
UNCOV
145
        elif isinstance(value, ConfigSection):
×
146
            value.__class__ = ConfigSection
×
UNCOV
147
        super().__setitem__(key, value)
×
148

UNCOV
149
    def __getitem__(self, key: str) -> ValueType:
×
UNCOV
150
        key, *traits = key.split(':')
×
UNCOV
151
        if self._cfg_ is not None:
×
UNCOV
152
            d = self._cfg_.query(self._key_)
×
UNCOV
153
            if self is not d:
×
154
                self.update(d)
×
UNCOV
155
        ret = super().__getitem__(key)
×
UNCOV
156
        if isinstance(ret, ConfigSection) and len(traits) > 0:
×
UNCOV
157
            traits = [
×
158
                TraitMeta._traits[n] for n in traits if n in TraitMeta._traits
159
            ]
UNCOV
160
            mixin(ret, *traits)
×
UNCOV
161
        return ret
×
162

UNCOV
163
    def __delitem__(self, key: str) -> None:
×
164
        if self._cfg_ is None:
×
165
            self._modified_ = True
×
166
        else:
167
            self._cfg_._modified_ = True
×
168
        return super().__delitem__(key)
×
169

UNCOV
170
    def __delattr__(self, name: str) -> None:
×
171
        if name in self:
×
172
            return self.__delitem__(name)
×
173
        else:
174
            return super().__delattr__(name)
×
175

UNCOV
176
    def __getattr__(self, name: str) -> Any:
×
UNCOV
177
        try:
×
UNCOV
178
            return self.__getattribute__(name)
×
UNCOV
179
        except:
×
UNCOV
180
            try:
×
UNCOV
181
                return self.__getitem__(name)
×
182
            except:
×
183
                raise AttributeError(f'Not Find Attr: {name}')
×
184

UNCOV
185
    def __setattr__(self, name: str, value: Any) -> None:
×
UNCOV
186
        if name in self:
×
187
            self.__setitem__(name, value)
×
188
        else:
UNCOV
189
            super().__setattr__(name, value)
×
190

UNCOV
191
    def __deepcopy__(self, memo):
×
UNCOV
192
        dct = {k: copy.deepcopy(v) for k, v in self.items()}
×
UNCOV
193
        return dct
×
194

UNCOV
195
    def query(self, q: Union[str, set, tuple, list,
×
196
                             dict]) -> Union[dict, ValueType]:
UNCOV
197
        if self._key_ is None:
×
UNCOV
198
            prefix = []
×
199
        else:
UNCOV
200
            prefix = self._key_.split('.')
×
UNCOV
201
        return query(q, self, prefix=prefix)
×
202

UNCOV
203
    def set(self, q, value):
×
204
        if self._key_ is None:
×
205
            prefix = []
×
206
        else:
207
            prefix = self._key_.split('.')
×
208
        setKey(q, value, self, prefix=prefix)
×
209

UNCOV
210
    def update(self, other):
×
UNCOV
211
        _update(self, other)
×
212

213

UNCOV
214
ValueType = Union[str, int, float, list, ConfigSection]
×
215

216

UNCOV
217
class BaseConfig(ConfigSection):
×
UNCOV
218
    def __init__(self,
×
219
                 path: Optional[Union[str, Path]] = None,
220
                 backup: bool = False):
UNCOV
221
        super().__init__(None, None)
×
UNCOV
222
        if isinstance(path, str):
×
223
            path = Path(path)
×
UNCOV
224
        self._path_ = path
×
UNCOV
225
        self._backup_ = backup
×
UNCOV
226
        self._modified_ = False
×
227

UNCOV
228
        if self._path_ is None:
×
UNCOV
229
            return
×
230
        if self._path_.exists():
×
231
            self.reload()
×
232
            if '__version__' not in self:
×
233
                self['__version__'] = 1
×
234
        else:
235
            self._path_.parent.mkdir(parents=True, exist_ok=True)
×
236
            self['__version__'] = 1
×
237
            self._modified_ = True
×
238
            self.commit()
×
239

UNCOV
240
    def commit(self):
×
241
        if not self._modified_ or self._path_ is None:
×
242
            return
×
243
        if self._backup_ and self._path_.exists():
×
244
            v = self['__version__']
×
245
            bk = self._path_.with_stem(self._path_.stem + f"_{v}")
×
246
            self._path_.rename(bk)
×
247
        with self._path_.open('w') as f:
×
248
            self['__version__'] = self['__version__'] + 1
×
249
            json.dump(self, f, indent=4)
×
250
            self._modified_ = False
×
251

UNCOV
252
    def rollback(self):
×
253
        if not self._modified_ or self._path_ is None:
×
254
            return
×
255
        self.reload()
×
256

UNCOV
257
    def reload(self):
×
258
        with self._path_.open('r') as f:
×
259
            dct = json.load(f)
×
260
            self.clear()
×
261
            self.update(dct)
×
262
            self._modified_ = False
×
263

UNCOV
264
    @classmethod
×
UNCOV
265
    def fromdict(cls, d: dict) -> BaseConfig:
×
UNCOV
266
        ret = cls()
×
UNCOV
267
        ret.update(d)
×
UNCOV
268
        return ret
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc