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

feihoo87 / waveforms / 6902226398

17 Nov 2023 09:31AM UTC coverage: 43.344% (+0.2%) from 43.147%
6902226398

push

github

feihoo87
upgrade make_clifford_generators

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

110 existing lines in 4 files now uncovered.

7472 of 17239 relevant lines covered (43.34%)

3.89 hits per line

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

66.4
/waveforms/cache.py
1
import functools
9✔
2
import hashlib
9✔
3
import pathlib
9✔
4
import pickle
9✔
5
import time
9✔
6
from typing import Any, Callable, Hashable, KeysView, Optional, Union
9✔
7

8
try:
9✔
9
    from portalocker import Lock
9✔
10
except:
×
11
    import warnings
×
12

13
    warnings.warn('portalocker not installed, cache will not be thread safe!')
×
14

15
    class Lock():
×
16

17
        def __init__(self, file, mode):
×
18
            self.file = file
×
19
            self.mode = mode
×
20
            self.fh = None
×
21

22
        def __enter__(self):
×
23
            self.fh = open(self.file, self.mode)
×
24
            return self.fh
×
25

26
        def __exit__(self, exc_type, exc_value, traceback):
×
27
            self.fh.close()
×
28

29

30
cache_dir = pathlib.Path.home() / '.waveforms' / 'cache'
9✔
31
cache_dir.mkdir(parents=True, exist_ok=True)
9✔
32

33
MAXVALUESIZE = 1024
9✔
34
Decorator = Callable[[Callable], Callable]
9✔
35

36

37
class Cache(dict):
9✔
38

39
    def __init__(self, name: str, path: pathlib.Path = cache_dir):
9✔
40
        name = name.split('.')
9✔
41
        self.path: pathlib.Path = path.joinpath(*name[:-1]) / (name[-1] +
9✔
42
                                                               '.cache.d')
43
        self._buffer = {}
9✔
44
        self._index = {}
9✔
45
        self._mtime = 0
9✔
46
        (self.path / 'values').mkdir(parents=True, exist_ok=True)
9✔
47

48
    @property
9✔
49
    def index(self) -> pathlib.Path:
9✔
50
        return self.path / 'index'
9✔
51

52
    @staticmethod
9✔
53
    def _hash(key: Hashable) -> str:
9✔
54
        return hashlib.md5(pickle.dumps(key)).hexdigest()
9✔
55

56
    def _syncIndex(self) -> None:
9✔
57
        if not self.index.exists() or self._mtime > self.index.stat().st_mtime:
9✔
58
            with Lock(self.index, 'wb') as fh:
9✔
59
                pickle.dump(self._index, fh)
9✔
60
        elif self._mtime < self.index.stat().st_mtime:
9✔
61
            with Lock(self.index, 'rb') as fh:
×
62
                self._index = pickle.load(fh)
×
63
        self._mtime = self.index.stat().st_mtime
9✔
64

65
    def _valuePath(self, key: Hashable) -> pathlib.Path:
9✔
66
        hashedKey = self._hash(key)
9✔
67
        return self.path / 'values' / hashedKey
9✔
68

69
    def _storeValue(self, k: Hashable, buf: bytes) -> None:
9✔
70
        with Lock(self._valuePath(k), 'wb') as fh:
9✔
71
            fh.write(buf)
9✔
72

73
    def _loadValue(self, k: Hashable) -> None:
9✔
74
        with Lock(self._valuePath(k), 'rb') as fh:
×
75
            buf = fh.read()
×
76
        hashstr = self._hash(buf)
×
77
        self._index[k] = self._valuePath(k).stat().st_mtime, None, hashstr
×
78
        self._buffer[k] = pickle.loads(buf)
×
79

80
    def __setitem__(self, k: Hashable, v: Any) -> None:
9✔
81
        buf = pickle.dumps(v)
9✔
82
        if len(buf) <= MAXVALUESIZE:
9✔
UNCOV
83
            mtime = time.time()
×
UNCOV
84
            self._index[k] = mtime, buf, ''
×
UNCOV
85
            self._mtime = mtime
×
UNCOV
86
            self._valuePath(k).unlink(missing_ok=True)
×
87
        else:
88
            hashstr = self._hash(buf)
9✔
89
            if k not in self._index or hashstr != self._index[k][2]:
9✔
90
                self._storeValue(k, buf)
9✔
91
                mtime = self._valuePath(k).stat().st_mtime
9✔
92
                self._index[k] = mtime, None, hashstr
9✔
93
                self._mtime = mtime
9✔
94
        self._syncIndex()
9✔
95
        self._buffer[k] = v
9✔
96

97
    def __getitem__(self, k: Hashable) -> Any:
9✔
98
        self._syncIndex()
9✔
99
        mtime, buf, hashstr = self._index[k]
9✔
100
        if k not in self._buffer and buf is not None:
9✔
101
            self._buffer[k] = pickle.loads(buf)
×
102
        elif k not in self._buffer:
9✔
103
            self._loadValue(k)
×
104
        return self._buffer[k]
9✔
105

106
    def __contains__(self, x: Hashable) -> bool:
9✔
107
        self._syncIndex()
×
108
        return x in self._index
×
109

110
    def keys(self) -> KeysView[Hashable]:
9✔
111
        self._syncIndex()
×
112
        return self._index.keys()
×
113

114
    def clear(self) -> None:
9✔
115
        self._buffer.clear()
×
116
        self._index.clear()
×
117
        self.index.unlink()
×
118
        for f in (self.path / 'values').iterdir():
×
119
            f.unlink()
×
120
        self._mtime = 0
×
121

122

123
__caches = {}
9✔
124

125

126
def _getCache(name: str) -> Cache:
9✔
127
    try:
9✔
128
        return __caches[name]
9✔
129
    except:
9✔
130
        __caches[name] = Cache(name)
9✔
131
        return __caches[name]
9✔
132

133

134
def cache(storage: Optional[Union[str, Cache]] = None) -> Decorator:
9✔
135

136
    def decorator(func: Callable,
9✔
137
                  storage: Optional[Union[str, Cache]] = storage) -> Callable:
138
        if storage is None:
9✔
139
            storage = _getCache('.'.join([func.__module__, func.__name__]))
9✔
140
        elif isinstance(storage, str):
×
141
            storage = _getCache(storage)
×
142
        elif not isinstance(storage, Cache):
×
143
            raise Exception(f'storage type {type(storage)} not understand!')
×
144

145
        @functools.wraps(func)
9✔
146
        def wrapper(*args, **kwds):
9✔
147
            kwds = {k: kwds[k] for k in sorted(kwds)}
9✔
148
            try:
9✔
149
                ret = storage[pickle.dumps((args, kwds))]
9✔
150
            except:
9✔
151
                ret = func(*args, **kwds)
9✔
152
                storage[pickle.dumps((args, kwds))] = ret
9✔
153
            return ret
9✔
154

155
        wrapper.cache = storage
9✔
156
        return wrapper
9✔
157

158
    return decorator
9✔
159

160

161
def clear(name: str) -> None:
9✔
162
    cache = _getCache(name)
×
163
    cache.clear()
×
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

© 2025 Coveralls, Inc