k3cacheable 0.1.0__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- k3cacheable-0.1.2/LICENSE +21 -0
- k3cacheable-0.1.2/PKG-INFO +126 -0
- k3cacheable-0.1.0/k3cacheable/synopsis.py → k3cacheable-0.1.2/README.md +90 -49
- {k3cacheable-0.1.0/k3cacheable → k3cacheable-0.1.2}/__init__.py +6 -5
- {k3cacheable-0.1.0/k3cacheable → k3cacheable-0.1.2}/cacheable.py +22 -38
- k3cacheable-0.1.2/k3cacheable.egg-info/PKG-INFO +126 -0
- k3cacheable-0.1.2/k3cacheable.egg-info/SOURCES.txt +16 -0
- k3cacheable-0.1.2/k3cacheable.egg-info/requires.txt +16 -0
- k3cacheable-0.1.2/pyproject.toml +59 -0
- k3cacheable-0.1.2/synopsis.py +50 -0
- k3cacheable-0.1.2/test/test_doctest.py +8 -0
- k3cacheable-0.1.2/test/test_k3cacheable.py +231 -0
- k3cacheable-0.1.0/PKG-INFO +0 -107
- k3cacheable-0.1.0/k3cacheable/setup.py +0 -23
- k3cacheable-0.1.0/k3cacheable.egg-info/PKG-INFO +0 -107
- k3cacheable-0.1.0/k3cacheable.egg-info/SOURCES.txt +0 -10
- k3cacheable-0.1.0/k3cacheable.egg-info/requires.txt +0 -1
- k3cacheable-0.1.0/setup.py +0 -23
- {k3cacheable-0.1.0 → k3cacheable-0.1.2}/k3cacheable.egg-info/dependency_links.txt +0 -0
- {k3cacheable-0.1.0 → k3cacheable-0.1.2}/k3cacheable.egg-info/top_level.txt +0 -0
- {k3cacheable-0.1.0 → k3cacheable-0.1.2}/setup.cfg +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 张炎泼
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: k3cacheable
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Cache data which access frequently
|
|
5
|
+
Author-email: Zhang Yanpo <drdr.xp@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/pykit3/k3cacheable
|
|
8
|
+
Project-URL: Documentation, https://k3cacheable.readthedocs.io
|
|
9
|
+
Keywords: cache,cacheable,memoize,pykit3
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: msgpack
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
25
|
+
Requires-Dist: ruff; extra == "dev"
|
|
26
|
+
Requires-Dist: coverage; extra == "dev"
|
|
27
|
+
Provides-Extra: publish
|
|
28
|
+
Requires-Dist: build; extra == "publish"
|
|
29
|
+
Requires-Dist: twine; extra == "publish"
|
|
30
|
+
Requires-Dist: pk3; extra == "publish"
|
|
31
|
+
Provides-Extra: docs
|
|
32
|
+
Requires-Dist: mkdocs>=1.5; extra == "docs"
|
|
33
|
+
Requires-Dist: mkdocs-material>=9.0; extra == "docs"
|
|
34
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# k3cacheable
|
|
38
|
+
|
|
39
|
+
[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)
|
|
40
|
+
[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)
|
|
41
|
+
[](https://pypi.org/project/k3cacheable)
|
|
42
|
+
|
|
43
|
+
Cache data which access frequently.
|
|
44
|
+
|
|
45
|
+
k3cacheable is a component of [pykit3] project: a python3 toolkit set.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Cache data which access frequently.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Install
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
pip install k3cacheable
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
# Synopsis
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
|
|
63
|
+
import k3cacheable
|
|
64
|
+
import time
|
|
65
|
+
|
|
66
|
+
# create a `LRU`, capacity:10 timeout:60
|
|
67
|
+
c = k3cacheable.LRU(10, 60)
|
|
68
|
+
|
|
69
|
+
# set value like the `dict`
|
|
70
|
+
c['key'] = 'val'
|
|
71
|
+
|
|
72
|
+
# get value like the `dict`
|
|
73
|
+
# if item timeout, delete it and raise `KeyError`
|
|
74
|
+
# if item not exist, raise `KeyError`
|
|
75
|
+
try:
|
|
76
|
+
val = c['key']
|
|
77
|
+
except KeyError:
|
|
78
|
+
print('key error')
|
|
79
|
+
|
|
80
|
+
cache_data = {
|
|
81
|
+
'key1': 'val_1',
|
|
82
|
+
'key2': 'val_2',
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# define the function with a decorator
|
|
86
|
+
@k3cacheable.cache('cache_name', capacity=100, timeout=60,
|
|
87
|
+
is_deepcopy=False, mutex_update=False)
|
|
88
|
+
def get_data(param):
|
|
89
|
+
return cache_data.get(param, '')
|
|
90
|
+
|
|
91
|
+
# call `get_data`, if item has not been cached, cache the return value
|
|
92
|
+
data = get_data('key1')
|
|
93
|
+
|
|
94
|
+
# call `get_data` use the same param, data will be got from cache
|
|
95
|
+
time.sleep(1)
|
|
96
|
+
data = get_data('key1')
|
|
97
|
+
|
|
98
|
+
# if item timeout, when call `get_data`, cache again
|
|
99
|
+
time.sleep(1)
|
|
100
|
+
data = get_data('key1')
|
|
101
|
+
|
|
102
|
+
# define a method with a decorator
|
|
103
|
+
class MethodCache(object):
|
|
104
|
+
|
|
105
|
+
@k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
|
|
106
|
+
is_deepcopy=False, mutex_update=False)
|
|
107
|
+
def get_data(self, param):
|
|
108
|
+
return cache_data.get(param, '')
|
|
109
|
+
|
|
110
|
+
mm = MethodCache()
|
|
111
|
+
data = mm.get_data('key2')
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
# Author
|
|
116
|
+
|
|
117
|
+
Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
118
|
+
|
|
119
|
+
# Copyright and License
|
|
120
|
+
|
|
121
|
+
The MIT License (MIT)
|
|
122
|
+
|
|
123
|
+
Copyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
[pykit3]: https://github.com/pykit3
|
|
@@ -1,49 +1,90 @@
|
|
|
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
|
-
|
|
1
|
+
# k3cacheable
|
|
2
|
+
|
|
3
|
+
[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)
|
|
4
|
+
[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)
|
|
5
|
+
[](https://pypi.org/project/k3cacheable)
|
|
6
|
+
|
|
7
|
+
Cache data which access frequently.
|
|
8
|
+
|
|
9
|
+
k3cacheable is a component of [pykit3] project: a python3 toolkit set.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Cache data which access frequently.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Install
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
pip install k3cacheable
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
# Synopsis
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
|
|
27
|
+
import k3cacheable
|
|
28
|
+
import time
|
|
29
|
+
|
|
30
|
+
# create a `LRU`, capacity:10 timeout:60
|
|
31
|
+
c = k3cacheable.LRU(10, 60)
|
|
32
|
+
|
|
33
|
+
# set value like the `dict`
|
|
34
|
+
c['key'] = 'val'
|
|
35
|
+
|
|
36
|
+
# get value like the `dict`
|
|
37
|
+
# if item timeout, delete it and raise `KeyError`
|
|
38
|
+
# if item not exist, raise `KeyError`
|
|
39
|
+
try:
|
|
40
|
+
val = c['key']
|
|
41
|
+
except KeyError:
|
|
42
|
+
print('key error')
|
|
43
|
+
|
|
44
|
+
cache_data = {
|
|
45
|
+
'key1': 'val_1',
|
|
46
|
+
'key2': 'val_2',
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# define the function with a decorator
|
|
50
|
+
@k3cacheable.cache('cache_name', capacity=100, timeout=60,
|
|
51
|
+
is_deepcopy=False, mutex_update=False)
|
|
52
|
+
def get_data(param):
|
|
53
|
+
return cache_data.get(param, '')
|
|
54
|
+
|
|
55
|
+
# call `get_data`, if item has not been cached, cache the return value
|
|
56
|
+
data = get_data('key1')
|
|
57
|
+
|
|
58
|
+
# call `get_data` use the same param, data will be got from cache
|
|
59
|
+
time.sleep(1)
|
|
60
|
+
data = get_data('key1')
|
|
61
|
+
|
|
62
|
+
# if item timeout, when call `get_data`, cache again
|
|
63
|
+
time.sleep(1)
|
|
64
|
+
data = get_data('key1')
|
|
65
|
+
|
|
66
|
+
# define a method with a decorator
|
|
67
|
+
class MethodCache(object):
|
|
68
|
+
|
|
69
|
+
@k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
|
|
70
|
+
is_deepcopy=False, mutex_update=False)
|
|
71
|
+
def get_data(self, param):
|
|
72
|
+
return cache_data.get(param, '')
|
|
73
|
+
|
|
74
|
+
mm = MethodCache()
|
|
75
|
+
data = mm.get_data('key2')
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
# Author
|
|
80
|
+
|
|
81
|
+
Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
82
|
+
|
|
83
|
+
# Copyright and License
|
|
84
|
+
|
|
85
|
+
The MIT License (MIT)
|
|
86
|
+
|
|
87
|
+
Copyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
[pykit3]: https://github.com/pykit3
|
|
@@ -6,8 +6,9 @@ Cache data which access frequently.
|
|
|
6
6
|
# from .proc import CalledProcessError
|
|
7
7
|
# from .proc import ProcError
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
from importlib.metadata import version
|
|
10
|
+
|
|
11
|
+
__version__ = version("k3cacheable")
|
|
11
12
|
|
|
12
13
|
from .cacheable import (
|
|
13
14
|
LRU,
|
|
@@ -16,7 +17,7 @@ from .cacheable import (
|
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
__all__ = [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
"LRU",
|
|
21
|
+
"Cacheable",
|
|
22
|
+
"cache",
|
|
22
23
|
]
|
|
@@ -23,7 +23,7 @@ class LRU(object):
|
|
|
23
23
|
|
|
24
24
|
If size of `LRU` is greater than `capacity` * 1.5,
|
|
25
25
|
clean items from head until size is equal to `capacity`.
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
.. highlight:: python
|
|
28
28
|
.. code-block:: python
|
|
29
29
|
|
|
@@ -51,6 +51,7 @@ class LRU(object):
|
|
|
51
51
|
print('key not in lru')
|
|
52
52
|
...
|
|
53
53
|
"""
|
|
54
|
+
|
|
54
55
|
def __init__(self, capacity, timeout=60):
|
|
55
56
|
"""
|
|
56
57
|
Least Recently Used Cache.
|
|
@@ -64,39 +65,33 @@ class LRU(object):
|
|
|
64
65
|
self.timeout = timeout
|
|
65
66
|
self.size = 0
|
|
66
67
|
self.items = {}
|
|
67
|
-
self.head = {
|
|
68
|
+
self.head = {"next": None, "pre": None}
|
|
68
69
|
self.tail = self.head
|
|
69
70
|
|
|
70
71
|
def __getitem__(self, key):
|
|
71
|
-
|
|
72
72
|
with self.lock:
|
|
73
73
|
now = int(time.time())
|
|
74
74
|
item = self.items[key]
|
|
75
75
|
|
|
76
|
-
if now > item[
|
|
76
|
+
if now > item["tm"] + self.timeout:
|
|
77
77
|
self._del_item(item)
|
|
78
|
-
raise KeyError(
|
|
78
|
+
raise KeyError("{k} is timeout".format(k=key))
|
|
79
79
|
|
|
80
80
|
self._move_to_tail(item)
|
|
81
81
|
|
|
82
|
-
return item[
|
|
82
|
+
return item["val"]
|
|
83
83
|
|
|
84
84
|
def __setitem__(self, key, val):
|
|
85
|
-
|
|
86
85
|
with self.lock:
|
|
87
86
|
if key in self.items:
|
|
88
87
|
item = self.items[key]
|
|
89
|
-
item[
|
|
90
|
-
item[
|
|
88
|
+
item["val"] = val
|
|
89
|
+
item["tm"] = int(time.time())
|
|
91
90
|
|
|
92
91
|
self._move_to_tail(item)
|
|
93
92
|
|
|
94
93
|
else:
|
|
95
|
-
self.items[key] = {
|
|
96
|
-
'val': val,
|
|
97
|
-
'pre': None,
|
|
98
|
-
'next': None,
|
|
99
|
-
'tm': int(time.time())}
|
|
94
|
+
self.items[key] = {"key": key, "val": val, "pre": None, "next": None, "tm": int(time.time())}
|
|
100
95
|
|
|
101
96
|
self._move_to_tail(self.items[key])
|
|
102
97
|
|
|
@@ -106,40 +101,34 @@ class LRU(object):
|
|
|
106
101
|
self._cleanup()
|
|
107
102
|
|
|
108
103
|
def _remove_item(self, item):
|
|
109
|
-
|
|
110
|
-
item[
|
|
111
|
-
|
|
112
|
-
item['next']['pre'] = item['pre']
|
|
104
|
+
item["pre"]["next"] = item["next"]
|
|
105
|
+
if item["next"] is not None:
|
|
106
|
+
item["next"]["pre"] = item["pre"]
|
|
113
107
|
else:
|
|
114
|
-
self.tail = item[
|
|
108
|
+
self.tail = item["pre"]
|
|
115
109
|
|
|
116
110
|
def _move_to_tail(self, item):
|
|
117
|
-
|
|
118
|
-
if item['pre'] is not None:
|
|
111
|
+
if item["pre"] is not None:
|
|
119
112
|
self._remove_item(item)
|
|
120
113
|
|
|
121
|
-
self.tail[
|
|
122
|
-
item[
|
|
123
|
-
item[
|
|
114
|
+
self.tail["next"] = item
|
|
115
|
+
item["pre"] = self.tail
|
|
116
|
+
item["next"] = None
|
|
124
117
|
self.tail = item
|
|
125
118
|
|
|
126
119
|
def _del_item(self, item):
|
|
127
|
-
|
|
128
|
-
del self.items[item['key']]
|
|
120
|
+
del self.items[item["key"]]
|
|
129
121
|
self._remove_item(item)
|
|
130
122
|
self.size -= 1
|
|
131
123
|
|
|
132
124
|
def _cleanup(self):
|
|
133
|
-
|
|
134
125
|
while self.size > self.capacity:
|
|
135
|
-
item = self.head[
|
|
126
|
+
item = self.head["next"]
|
|
136
127
|
self._del_item(item)
|
|
137
128
|
|
|
138
129
|
|
|
139
130
|
class Cacheable(object):
|
|
140
|
-
|
|
141
|
-
def __init__(self, capacity=1024 * 4, timeout=60,
|
|
142
|
-
is_deepcopy=True, is_pack=False, mutex_update=False):
|
|
131
|
+
def __init__(self, capacity=1024 * 4, timeout=60, is_deepcopy=True, is_pack=False, mutex_update=False):
|
|
143
132
|
"""
|
|
144
133
|
Create a `LRU` object, all items will be cached in it.
|
|
145
134
|
:param capacity: for create `LRU` object, default is 1024 * 4
|
|
@@ -166,16 +155,13 @@ class Cacheable(object):
|
|
|
166
155
|
self.mutex_update = mutex_update
|
|
167
156
|
|
|
168
157
|
def _arg_str(self, args, argkv):
|
|
169
|
-
|
|
170
158
|
argkv = [(k, v) for k, v in list(argkv.items())]
|
|
171
159
|
argkv.sort()
|
|
172
160
|
|
|
173
161
|
return str([args, argkv])
|
|
174
162
|
|
|
175
163
|
def _cache_wrapper(self, fun):
|
|
176
|
-
|
|
177
164
|
def func_wrapper(*args, **argkv):
|
|
178
|
-
|
|
179
165
|
val = None
|
|
180
166
|
generate_key = self._arg_str(args, argkv)
|
|
181
167
|
|
|
@@ -211,8 +197,7 @@ class Cacheable(object):
|
|
|
211
197
|
caches = {}
|
|
212
198
|
|
|
213
199
|
|
|
214
|
-
def cache(name, capacity=1024 * 4, timeout=60,
|
|
215
|
-
is_deepcopy=True, is_pack=False, mutex_update=False):
|
|
200
|
+
def cache(name, capacity=1024 * 4, timeout=60, is_deepcopy=True, is_pack=False, mutex_update=False):
|
|
216
201
|
"""
|
|
217
202
|
If not exist, create a `cacheable.Cacheable` and save it, else use exist one.
|
|
218
203
|
:param name: for distinguishing different `cacheable.Cacheable`
|
|
@@ -244,8 +229,7 @@ def cache(name, capacity=1024 * 4, timeout=60,
|
|
|
244
229
|
"""
|
|
245
230
|
c = caches.get(name)
|
|
246
231
|
if c is None:
|
|
247
|
-
c = Cacheable(capacity=capacity, timeout=timeout,
|
|
248
|
-
is_deepcopy=is_deepcopy, mutex_update=mutex_update)
|
|
232
|
+
c = Cacheable(capacity=capacity, timeout=timeout, is_deepcopy=is_deepcopy, mutex_update=mutex_update)
|
|
249
233
|
caches[name] = c
|
|
250
234
|
|
|
251
235
|
return c._cache_wrapper
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: k3cacheable
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Cache data which access frequently
|
|
5
|
+
Author-email: Zhang Yanpo <drdr.xp@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/pykit3/k3cacheable
|
|
8
|
+
Project-URL: Documentation, https://k3cacheable.readthedocs.io
|
|
9
|
+
Keywords: cache,cacheable,memoize,pykit3
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: msgpack
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
25
|
+
Requires-Dist: ruff; extra == "dev"
|
|
26
|
+
Requires-Dist: coverage; extra == "dev"
|
|
27
|
+
Provides-Extra: publish
|
|
28
|
+
Requires-Dist: build; extra == "publish"
|
|
29
|
+
Requires-Dist: twine; extra == "publish"
|
|
30
|
+
Requires-Dist: pk3; extra == "publish"
|
|
31
|
+
Provides-Extra: docs
|
|
32
|
+
Requires-Dist: mkdocs>=1.5; extra == "docs"
|
|
33
|
+
Requires-Dist: mkdocs-material>=9.0; extra == "docs"
|
|
34
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == "docs"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# k3cacheable
|
|
38
|
+
|
|
39
|
+
[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)
|
|
40
|
+
[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)
|
|
41
|
+
[](https://pypi.org/project/k3cacheable)
|
|
42
|
+
|
|
43
|
+
Cache data which access frequently.
|
|
44
|
+
|
|
45
|
+
k3cacheable is a component of [pykit3] project: a python3 toolkit set.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Cache data which access frequently.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Install
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
pip install k3cacheable
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
# Synopsis
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
|
|
63
|
+
import k3cacheable
|
|
64
|
+
import time
|
|
65
|
+
|
|
66
|
+
# create a `LRU`, capacity:10 timeout:60
|
|
67
|
+
c = k3cacheable.LRU(10, 60)
|
|
68
|
+
|
|
69
|
+
# set value like the `dict`
|
|
70
|
+
c['key'] = 'val'
|
|
71
|
+
|
|
72
|
+
# get value like the `dict`
|
|
73
|
+
# if item timeout, delete it and raise `KeyError`
|
|
74
|
+
# if item not exist, raise `KeyError`
|
|
75
|
+
try:
|
|
76
|
+
val = c['key']
|
|
77
|
+
except KeyError:
|
|
78
|
+
print('key error')
|
|
79
|
+
|
|
80
|
+
cache_data = {
|
|
81
|
+
'key1': 'val_1',
|
|
82
|
+
'key2': 'val_2',
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# define the function with a decorator
|
|
86
|
+
@k3cacheable.cache('cache_name', capacity=100, timeout=60,
|
|
87
|
+
is_deepcopy=False, mutex_update=False)
|
|
88
|
+
def get_data(param):
|
|
89
|
+
return cache_data.get(param, '')
|
|
90
|
+
|
|
91
|
+
# call `get_data`, if item has not been cached, cache the return value
|
|
92
|
+
data = get_data('key1')
|
|
93
|
+
|
|
94
|
+
# call `get_data` use the same param, data will be got from cache
|
|
95
|
+
time.sleep(1)
|
|
96
|
+
data = get_data('key1')
|
|
97
|
+
|
|
98
|
+
# if item timeout, when call `get_data`, cache again
|
|
99
|
+
time.sleep(1)
|
|
100
|
+
data = get_data('key1')
|
|
101
|
+
|
|
102
|
+
# define a method with a decorator
|
|
103
|
+
class MethodCache(object):
|
|
104
|
+
|
|
105
|
+
@k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
|
|
106
|
+
is_deepcopy=False, mutex_update=False)
|
|
107
|
+
def get_data(self, param):
|
|
108
|
+
return cache_data.get(param, '')
|
|
109
|
+
|
|
110
|
+
mm = MethodCache()
|
|
111
|
+
data = mm.get_data('key2')
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
# Author
|
|
116
|
+
|
|
117
|
+
Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
118
|
+
|
|
119
|
+
# Copyright and License
|
|
120
|
+
|
|
121
|
+
The MIT License (MIT)
|
|
122
|
+
|
|
123
|
+
Copyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
[pykit3]: https://github.com/pykit3
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
__init__.py
|
|
4
|
+
cacheable.py
|
|
5
|
+
pyproject.toml
|
|
6
|
+
synopsis.py
|
|
7
|
+
./__init__.py
|
|
8
|
+
./cacheable.py
|
|
9
|
+
./synopsis.py
|
|
10
|
+
k3cacheable.egg-info/PKG-INFO
|
|
11
|
+
k3cacheable.egg-info/SOURCES.txt
|
|
12
|
+
k3cacheable.egg-info/dependency_links.txt
|
|
13
|
+
k3cacheable.egg-info/requires.txt
|
|
14
|
+
k3cacheable.egg-info/top_level.txt
|
|
15
|
+
test/test_doctest.py
|
|
16
|
+
test/test_k3cacheable.py
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "k3cacheable"
|
|
7
|
+
version = "0.1.2"
|
|
8
|
+
description = "Cache data which access frequently"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Zhang Yanpo", email = "drdr.xp@gmail.com" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["cache", "cacheable", "memoize", "pykit3"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Software Development :: Libraries",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"msgpack",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/pykit3/k3cacheable"
|
|
33
|
+
Documentation = "https://k3cacheable.readthedocs.io"
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"pytest>=7.0",
|
|
38
|
+
"ruff",
|
|
39
|
+
"coverage",
|
|
40
|
+
]
|
|
41
|
+
publish = [
|
|
42
|
+
"build",
|
|
43
|
+
"twine",
|
|
44
|
+
"pk3",
|
|
45
|
+
]
|
|
46
|
+
docs = [
|
|
47
|
+
"mkdocs>=1.5",
|
|
48
|
+
"mkdocs-material>=9.0",
|
|
49
|
+
"mkdocstrings[python]>=0.24",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[tool.setuptools]
|
|
53
|
+
packages = ["k3cacheable"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.package-dir]
|
|
56
|
+
k3cacheable = "."
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 120
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import k3cacheable
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
# create a `LRU`, capacity:10 timeout:60
|
|
5
|
+
c = k3cacheable.LRU(10, 60)
|
|
6
|
+
|
|
7
|
+
# set value like the `dict`
|
|
8
|
+
c["key"] = "val"
|
|
9
|
+
|
|
10
|
+
# get value like the `dict`
|
|
11
|
+
# if item timeout, delete it and raise `KeyError`
|
|
12
|
+
# if item not exist, raise `KeyError`
|
|
13
|
+
try:
|
|
14
|
+
val = c["key"]
|
|
15
|
+
except KeyError:
|
|
16
|
+
print("key error")
|
|
17
|
+
|
|
18
|
+
cache_data = {
|
|
19
|
+
"key1": "val_1",
|
|
20
|
+
"key2": "val_2",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# define the function with a decorator
|
|
25
|
+
@k3cacheable.cache("cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
|
|
26
|
+
def get_data(param):
|
|
27
|
+
return cache_data.get(param, "")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# call `get_data`, if item has not been cached, cache the return value
|
|
31
|
+
data = get_data("key1")
|
|
32
|
+
|
|
33
|
+
# call `get_data` use the same param, data will be got from cache
|
|
34
|
+
time.sleep(1)
|
|
35
|
+
data = get_data("key1")
|
|
36
|
+
|
|
37
|
+
# if item timeout, when call `get_data`, cache again
|
|
38
|
+
time.sleep(1)
|
|
39
|
+
data = get_data("key1")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# define a method with a decorator
|
|
43
|
+
class MethodCache(object):
|
|
44
|
+
@k3cacheable.cache("method_cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
|
|
45
|
+
def get_data(self, param):
|
|
46
|
+
return cache_data.get(param, "")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
mm = MethodCache()
|
|
50
|
+
data = mm.get_data("key2")
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
|
|
4
|
+
import _thread
|
|
5
|
+
import time
|
|
6
|
+
import unittest
|
|
7
|
+
|
|
8
|
+
import k3cacheable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestLRU(unittest.TestCase):
|
|
12
|
+
def _assert_lru_list(self, lru):
|
|
13
|
+
size = lru.size
|
|
14
|
+
item_head = lru.head
|
|
15
|
+
item_tail = lru.tail
|
|
16
|
+
for i in range(size):
|
|
17
|
+
item_head = item_head["next"]
|
|
18
|
+
item_tail = item_tail["pre"]
|
|
19
|
+
|
|
20
|
+
self.assertIs(item_head, lru.tail)
|
|
21
|
+
self.assertIs(item_tail, lru.head)
|
|
22
|
+
|
|
23
|
+
def _assert_lru_items_order(self, lru, order_keys):
|
|
24
|
+
item = lru.head["next"]
|
|
25
|
+
lru_keys = []
|
|
26
|
+
while item is not None:
|
|
27
|
+
lru_keys.append(item["key"])
|
|
28
|
+
item = item["next"]
|
|
29
|
+
|
|
30
|
+
self.assertEqual(order_keys, lru_keys)
|
|
31
|
+
|
|
32
|
+
def test_lru_timeout(self):
|
|
33
|
+
cases = (
|
|
34
|
+
("k1", "v1", 3, True),
|
|
35
|
+
("k2", "v2", 1, False),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
lru = k3cacheable.LRU(10, 2)
|
|
39
|
+
for key, val, sleep_time, is_timeout in cases:
|
|
40
|
+
lru[key] = val
|
|
41
|
+
time.sleep(sleep_time)
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
lru[key]
|
|
45
|
+
self.assertFalse(is_timeout)
|
|
46
|
+
|
|
47
|
+
except KeyError:
|
|
48
|
+
self._assert_lru_list(lru)
|
|
49
|
+
self.assertTrue(is_timeout)
|
|
50
|
+
|
|
51
|
+
def test_lru_getitem(self):
|
|
52
|
+
capacity = 4
|
|
53
|
+
cases = (
|
|
54
|
+
(3, [0, 1, 2], []),
|
|
55
|
+
(4, [0, 1, 2, 3], []),
|
|
56
|
+
(5, [0, 1, 2, 3, 4], []),
|
|
57
|
+
(6, [0, 1, 2, 3, 4, 5], []),
|
|
58
|
+
(7, [3, 4, 5, 6], [0, 1, 2]),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
for insert_count, exist_items, cleanup_items in cases:
|
|
62
|
+
lru = k3cacheable.LRU(capacity, 10)
|
|
63
|
+
for i in range(insert_count):
|
|
64
|
+
lru[i] = "val%d" % (i)
|
|
65
|
+
|
|
66
|
+
for i in range(insert_count):
|
|
67
|
+
try:
|
|
68
|
+
val = lru[i]
|
|
69
|
+
self.assertEqual(val, "val%d" % (i))
|
|
70
|
+
self.assertEqual(lru.tail["key"], i)
|
|
71
|
+
self.assertIn(i, exist_items)
|
|
72
|
+
|
|
73
|
+
except KeyError:
|
|
74
|
+
self.assertIn(i, cleanup_items)
|
|
75
|
+
|
|
76
|
+
def test_lru_setitem(self):
|
|
77
|
+
capacity = 4
|
|
78
|
+
cases = (
|
|
79
|
+
(3, [0, 1, 2]),
|
|
80
|
+
(4, [0, 1, 2, 3]),
|
|
81
|
+
(5, [0, 1, 2, 3, 4]),
|
|
82
|
+
(6, [0, 1, 2, 3, 4, 5]),
|
|
83
|
+
# size of lru > capacity*1.5
|
|
84
|
+
# clean items from head, until size=capacity
|
|
85
|
+
(7, [3, 4, 5, 6]),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
for insert_count, expect_order_keys in cases:
|
|
89
|
+
lru = k3cacheable.LRU(capacity, 10)
|
|
90
|
+
for i in range(insert_count):
|
|
91
|
+
lru[i] = "val"
|
|
92
|
+
self._assert_lru_list(lru)
|
|
93
|
+
|
|
94
|
+
self._assert_lru_items_order(lru, expect_order_keys)
|
|
95
|
+
|
|
96
|
+
def test_lru_capacity(self):
|
|
97
|
+
cases = (
|
|
98
|
+
(0, ((0, 0), (1, 0))),
|
|
99
|
+
(1, ((1, 1), (2, 1))),
|
|
100
|
+
(10, ((9, 9), (10, 10), (13, 13), (15, 15), (16, 10))),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
for capacity, case in cases:
|
|
104
|
+
for insert_count, expect_size in case:
|
|
105
|
+
lru = k3cacheable.LRU(capacity, 60)
|
|
106
|
+
for i in range(insert_count):
|
|
107
|
+
lru[i] = "val"
|
|
108
|
+
|
|
109
|
+
self.assertEqual(lru.size, expect_size)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class TestCacheable(unittest.TestCase):
|
|
113
|
+
@k3cacheable.cache("method_cache_data", capacity=10, timeout=4, is_deepcopy=False)
|
|
114
|
+
def _method_cache_data(self, key):
|
|
115
|
+
data = need_cache_data.get(key, {})
|
|
116
|
+
data["tm"] = time.time()
|
|
117
|
+
return data
|
|
118
|
+
|
|
119
|
+
def test_get_items_from_cache(self):
|
|
120
|
+
cache_items = {}
|
|
121
|
+
for key in need_cache_data.keys():
|
|
122
|
+
cache_items[key] = get_cache_data(key)
|
|
123
|
+
|
|
124
|
+
time.sleep(0.1)
|
|
125
|
+
for key in need_cache_data.keys():
|
|
126
|
+
self.assertEqual(get_cache_data(key), cache_items[key])
|
|
127
|
+
|
|
128
|
+
def test_get_items_from_cache_use_method(self):
|
|
129
|
+
cache_items = {}
|
|
130
|
+
for key in need_cache_data.keys():
|
|
131
|
+
cache_items[key] = self._method_cache_data(key)
|
|
132
|
+
|
|
133
|
+
time.sleep(0.1)
|
|
134
|
+
for key in need_cache_data.keys():
|
|
135
|
+
self.assertEqual(self._method_cache_data(key), cache_items[key])
|
|
136
|
+
|
|
137
|
+
def test_cache_item_timeout_and_cache_again(self):
|
|
138
|
+
cases = (
|
|
139
|
+
(2, False),
|
|
140
|
+
(4, True),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
tm = get_cache_data("key")["tm"]
|
|
144
|
+
for sleep_time, is_timeout in cases:
|
|
145
|
+
time.sleep(sleep_time)
|
|
146
|
+
if is_timeout:
|
|
147
|
+
self.assertNotEqual(tm, get_cache_data("key")["tm"])
|
|
148
|
+
else:
|
|
149
|
+
self.assertEqual(tm, get_cache_data("key")["tm"])
|
|
150
|
+
|
|
151
|
+
def test_get_deepcopy_item_from_cache(self):
|
|
152
|
+
self.assertIsNot(get_deepcopy_of_cache_data("key1"), get_deepcopy_of_cache_data("key1"))
|
|
153
|
+
|
|
154
|
+
def test_get_concurrent_update_cache_data(self):
|
|
155
|
+
result = {}
|
|
156
|
+
|
|
157
|
+
def _store_result(key):
|
|
158
|
+
result[key] = get_concurrent_update_cache_data()
|
|
159
|
+
|
|
160
|
+
_thread.start_new_thread(_store_result, ("key1",))
|
|
161
|
+
time.sleep(1)
|
|
162
|
+
_thread.start_new_thread(_store_result, ("key2",))
|
|
163
|
+
|
|
164
|
+
while True:
|
|
165
|
+
if "key2" in result:
|
|
166
|
+
break
|
|
167
|
+
time.sleep(0.1)
|
|
168
|
+
|
|
169
|
+
self.assertIsNot(result["key1"], result["key2"])
|
|
170
|
+
|
|
171
|
+
def test_get_mutext_update_cache_data(self):
|
|
172
|
+
result = {}
|
|
173
|
+
|
|
174
|
+
def _store_result(key):
|
|
175
|
+
result[key] = get_mutex_update_cache_data()
|
|
176
|
+
|
|
177
|
+
_thread.start_new_thread(_store_result, ("key1",))
|
|
178
|
+
time.sleep(1)
|
|
179
|
+
_thread.start_new_thread(_store_result, ("key2",))
|
|
180
|
+
|
|
181
|
+
while True:
|
|
182
|
+
if "key2" in result:
|
|
183
|
+
break
|
|
184
|
+
time.sleep(0.1)
|
|
185
|
+
|
|
186
|
+
self.assertIs(result["key1"], result["key2"])
|
|
187
|
+
|
|
188
|
+
def test_generate_lru_key(self):
|
|
189
|
+
cases = (
|
|
190
|
+
((), {}, "[(), []]"),
|
|
191
|
+
((1), {1: "val_1"}, "[1, [(1, 'val_1')]]"),
|
|
192
|
+
((1), {"a": "val_a"}, "[1, [('a', 'val_a')]]"),
|
|
193
|
+
(("c"), {"b": "val_b"}, "['c', [('b', 'val_b')]]"),
|
|
194
|
+
((1, "c"), {"a": "val_a", "b": "val_b"}, "[(1, 'c'), [('a', 'val_a'), ('b', 'val_b')]]"),
|
|
195
|
+
(("c", 1), {"b": "val_b", "a": "val_a"}, "[('c', 1), [('a', 'val_a'), ('b', 'val_b')]]"),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
for args, argkv, expect_str in cases:
|
|
199
|
+
self.assertEqual(k3cacheable.Cacheable()._arg_str(args, argkv), expect_str)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@k3cacheable.cache("deepcopy_of_cache_data", capacity=100, timeout=60, is_deepcopy=True)
|
|
203
|
+
def get_deepcopy_of_cache_data(key):
|
|
204
|
+
return need_cache_data.get(key, {})
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@k3cacheable.cache("cache_data", capacity=100, timeout=4, is_deepcopy=False)
|
|
208
|
+
def get_cache_data(key):
|
|
209
|
+
cache_data = need_cache_data.get(key, {})
|
|
210
|
+
cache_data["tm"] = time.time()
|
|
211
|
+
return cache_data
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@k3cacheable.cache("concurrent_update_cache_data", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
|
|
215
|
+
def get_concurrent_update_cache_data():
|
|
216
|
+
time.sleep(3)
|
|
217
|
+
return {}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@k3cacheable.cache("mutex_update_cache_data", capacity=100, timeout=60, is_deepcopy=False, mutex_update=True)
|
|
221
|
+
def get_mutex_update_cache_data():
|
|
222
|
+
time.sleep(3)
|
|
223
|
+
return {}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
need_cache_data = {
|
|
227
|
+
"key1": {"tm": 0},
|
|
228
|
+
"key2": {"tm": 0},
|
|
229
|
+
"key3": {"tm": 0},
|
|
230
|
+
"key4": {"tm": 0},
|
|
231
|
+
}
|
k3cacheable-0.1.0/PKG-INFO
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: k3cacheable
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Cache data which access frequently.
|
|
5
|
-
Home-page: https://github.com/pykit3/k3cacheable
|
|
6
|
-
Author: Zhang Yanpo
|
|
7
|
-
Author-email: drdr.xp@gmail.com
|
|
8
|
-
License: MIT
|
|
9
|
-
Description: # k3cacheable
|
|
10
|
-
|
|
11
|
-
[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)
|
|
12
|
-
[](https://travis-ci.com/pykit3/k3cacheable)
|
|
13
|
-
[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)
|
|
14
|
-
[](https://pypi.org/project/k3cacheable)
|
|
15
|
-
|
|
16
|
-
Cache data which access frequently.
|
|
17
|
-
|
|
18
|
-
k3cacheable is a component of [pykit3] project: a python3 toolkit set.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Cache data which access frequently.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# Install
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
pip install k3cacheable
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
# Synopsis
|
|
33
|
-
|
|
34
|
-
```python
|
|
35
|
-
|
|
36
|
-
import k3cacheable
|
|
37
|
-
import time
|
|
38
|
-
|
|
39
|
-
# create a `LRU`, capacity:10 timeout:60
|
|
40
|
-
c = k3cacheable.LRU(10, 60)
|
|
41
|
-
|
|
42
|
-
# set value like the `dict`
|
|
43
|
-
c['key'] = 'val'
|
|
44
|
-
|
|
45
|
-
# get value like the `dict`
|
|
46
|
-
# if item timeout, delete it and raise `KeyError`
|
|
47
|
-
# if item not exist, raise `KeyError`
|
|
48
|
-
try:
|
|
49
|
-
val = c['key']
|
|
50
|
-
except KeyError:
|
|
51
|
-
print('key error')
|
|
52
|
-
|
|
53
|
-
cache_data = {
|
|
54
|
-
'key1': 'val_1',
|
|
55
|
-
'key2': 'val_2',
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
# define the function with a decorator
|
|
59
|
-
@k3cacheable.cache('cache_name', capacity=100, timeout=60,
|
|
60
|
-
is_deepcopy=False, mutex_update=False)
|
|
61
|
-
def get_data(param):
|
|
62
|
-
return cache_data.get(param, '')
|
|
63
|
-
|
|
64
|
-
# call `get_data`, if item has not been cached, cache the return value
|
|
65
|
-
data = get_data('key1')
|
|
66
|
-
|
|
67
|
-
# call `get_data` use the same param, data will be got from cache
|
|
68
|
-
time.sleep(1)
|
|
69
|
-
data = get_data('key1')
|
|
70
|
-
|
|
71
|
-
# if item timeout, when call `get_data`, cache again
|
|
72
|
-
time.sleep(1)
|
|
73
|
-
data = get_data('key1')
|
|
74
|
-
|
|
75
|
-
# define a method with a decorator
|
|
76
|
-
class MethodCache(object):
|
|
77
|
-
|
|
78
|
-
@k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
|
|
79
|
-
is_deepcopy=False, mutex_update=False)
|
|
80
|
-
def get_data(self, param):
|
|
81
|
-
return cache_data.get(param, '')
|
|
82
|
-
|
|
83
|
-
mm = MethodCache()
|
|
84
|
-
data = mm.get_data('key2')
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
# Author
|
|
89
|
-
|
|
90
|
-
Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
91
|
-
|
|
92
|
-
# Copyright and License
|
|
93
|
-
|
|
94
|
-
The MIT License (MIT)
|
|
95
|
-
|
|
96
|
-
Copyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
[pykit3]: https://github.com/pykit3
|
|
100
|
-
Keywords: python,cache
|
|
101
|
-
Platform: UNKNOWN
|
|
102
|
-
Classifier: Development Status :: 4 - Beta
|
|
103
|
-
Classifier: Intended Audience :: Developers
|
|
104
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
105
|
-
Classifier: Programming Language :: Python :: 3
|
|
106
|
-
Requires-Python: >=3.0
|
|
107
|
-
Description-Content-Type: text/markdown
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# DO NOT EDIT!!! built with `python _building/build_setup.py`
|
|
2
|
-
import setuptools
|
|
3
|
-
setuptools.setup(
|
|
4
|
-
name="k3cacheable",
|
|
5
|
-
packages=["k3cacheable"],
|
|
6
|
-
version="0.1.0",
|
|
7
|
-
license='MIT',
|
|
8
|
-
description='Cache data which access frequently.',
|
|
9
|
-
long_description="# k3cacheable\n\n[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)\n[](https://travis-ci.com/pykit3/k3cacheable)\n[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)\n[](https://pypi.org/project/k3cacheable)\n\nCache data which access frequently.\n\nk3cacheable is a component of [pykit3] project: a python3 toolkit set.\n\n\nCache data which access frequently.\n\n\n\n\n# Install\n\n```\npip install k3cacheable\n```\n\n# Synopsis\n\n```python\n\nimport k3cacheable\nimport time\n\n# create a `LRU`, capacity:10 timeout:60\nc = k3cacheable.LRU(10, 60)\n\n# set value like the `dict`\nc['key'] = 'val'\n\n# get value like the `dict`\n# if item timeout, delete it and raise `KeyError`\n# if item not exist, raise `KeyError`\ntry:\n val = c['key']\nexcept KeyError:\n print('key error')\n\ncache_data = {\n 'key1': 'val_1',\n 'key2': 'val_2',\n}\n\n# define the function with a decorator\n@k3cacheable.cache('cache_name', capacity=100, timeout=60,\n is_deepcopy=False, mutex_update=False)\ndef get_data(param):\n return cache_data.get(param, '')\n\n# call `get_data`, if item has not been cached, cache the return value\ndata = get_data('key1')\n\n# call `get_data` use the same param, data will be got from cache\ntime.sleep(1)\ndata = get_data('key1')\n\n# if item timeout, when call `get_data`, cache again\ntime.sleep(1)\ndata = get_data('key1')\n\n# define a method with a decorator\nclass MethodCache(object):\n\n @k3cacheable.cache('method_cache_name', capacity=100, timeout=60,\n is_deepcopy=False, mutex_update=False)\n def get_data(self, param):\n return cache_data.get(param, '')\n\nmm = MethodCache()\ndata = mm.get_data('key2')\n\n```\n\n# Author\n\nZhang Yanpo (张炎泼) <drdr.xp@gmail.com>\n\n# Copyright and License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>\n\n\n[pykit3]: https://github.com/pykit3",
|
|
10
|
-
long_description_content_type="text/markdown",
|
|
11
|
-
author='Zhang Yanpo',
|
|
12
|
-
author_email='drdr.xp@gmail.com',
|
|
13
|
-
url='https://github.com/pykit3/k3cacheable',
|
|
14
|
-
keywords=['python', 'cache'],
|
|
15
|
-
python_requires='>=3.0',
|
|
16
|
-
|
|
17
|
-
install_requires=['msgpack>=1.0.0'],
|
|
18
|
-
classifiers=[
|
|
19
|
-
'Development Status :: 4 - Beta',
|
|
20
|
-
'Intended Audience :: Developers',
|
|
21
|
-
'Topic :: Software Development :: Libraries',
|
|
22
|
-
] + ['Programming Language :: Python :: 3'],
|
|
23
|
-
)
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: k3cacheable
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Cache data which access frequently.
|
|
5
|
-
Home-page: https://github.com/pykit3/k3cacheable
|
|
6
|
-
Author: Zhang Yanpo
|
|
7
|
-
Author-email: drdr.xp@gmail.com
|
|
8
|
-
License: MIT
|
|
9
|
-
Description: # k3cacheable
|
|
10
|
-
|
|
11
|
-
[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)
|
|
12
|
-
[](https://travis-ci.com/pykit3/k3cacheable)
|
|
13
|
-
[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)
|
|
14
|
-
[](https://pypi.org/project/k3cacheable)
|
|
15
|
-
|
|
16
|
-
Cache data which access frequently.
|
|
17
|
-
|
|
18
|
-
k3cacheable is a component of [pykit3] project: a python3 toolkit set.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Cache data which access frequently.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# Install
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
pip install k3cacheable
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
# Synopsis
|
|
33
|
-
|
|
34
|
-
```python
|
|
35
|
-
|
|
36
|
-
import k3cacheable
|
|
37
|
-
import time
|
|
38
|
-
|
|
39
|
-
# create a `LRU`, capacity:10 timeout:60
|
|
40
|
-
c = k3cacheable.LRU(10, 60)
|
|
41
|
-
|
|
42
|
-
# set value like the `dict`
|
|
43
|
-
c['key'] = 'val'
|
|
44
|
-
|
|
45
|
-
# get value like the `dict`
|
|
46
|
-
# if item timeout, delete it and raise `KeyError`
|
|
47
|
-
# if item not exist, raise `KeyError`
|
|
48
|
-
try:
|
|
49
|
-
val = c['key']
|
|
50
|
-
except KeyError:
|
|
51
|
-
print('key error')
|
|
52
|
-
|
|
53
|
-
cache_data = {
|
|
54
|
-
'key1': 'val_1',
|
|
55
|
-
'key2': 'val_2',
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
# define the function with a decorator
|
|
59
|
-
@k3cacheable.cache('cache_name', capacity=100, timeout=60,
|
|
60
|
-
is_deepcopy=False, mutex_update=False)
|
|
61
|
-
def get_data(param):
|
|
62
|
-
return cache_data.get(param, '')
|
|
63
|
-
|
|
64
|
-
# call `get_data`, if item has not been cached, cache the return value
|
|
65
|
-
data = get_data('key1')
|
|
66
|
-
|
|
67
|
-
# call `get_data` use the same param, data will be got from cache
|
|
68
|
-
time.sleep(1)
|
|
69
|
-
data = get_data('key1')
|
|
70
|
-
|
|
71
|
-
# if item timeout, when call `get_data`, cache again
|
|
72
|
-
time.sleep(1)
|
|
73
|
-
data = get_data('key1')
|
|
74
|
-
|
|
75
|
-
# define a method with a decorator
|
|
76
|
-
class MethodCache(object):
|
|
77
|
-
|
|
78
|
-
@k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
|
|
79
|
-
is_deepcopy=False, mutex_update=False)
|
|
80
|
-
def get_data(self, param):
|
|
81
|
-
return cache_data.get(param, '')
|
|
82
|
-
|
|
83
|
-
mm = MethodCache()
|
|
84
|
-
data = mm.get_data('key2')
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
# Author
|
|
89
|
-
|
|
90
|
-
Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
91
|
-
|
|
92
|
-
# Copyright and License
|
|
93
|
-
|
|
94
|
-
The MIT License (MIT)
|
|
95
|
-
|
|
96
|
-
Copyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
[pykit3]: https://github.com/pykit3
|
|
100
|
-
Keywords: python,cache
|
|
101
|
-
Platform: UNKNOWN
|
|
102
|
-
Classifier: Development Status :: 4 - Beta
|
|
103
|
-
Classifier: Intended Audience :: Developers
|
|
104
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
105
|
-
Classifier: Programming Language :: Python :: 3
|
|
106
|
-
Requires-Python: >=3.0
|
|
107
|
-
Description-Content-Type: text/markdown
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
setup.py
|
|
2
|
-
k3cacheable/__init__.py
|
|
3
|
-
k3cacheable/cacheable.py
|
|
4
|
-
k3cacheable/setup.py
|
|
5
|
-
k3cacheable/synopsis.py
|
|
6
|
-
k3cacheable.egg-info/PKG-INFO
|
|
7
|
-
k3cacheable.egg-info/SOURCES.txt
|
|
8
|
-
k3cacheable.egg-info/dependency_links.txt
|
|
9
|
-
k3cacheable.egg-info/requires.txt
|
|
10
|
-
k3cacheable.egg-info/top_level.txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
msgpack>=1.0.0
|
k3cacheable-0.1.0/setup.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# DO NOT EDIT!!! built with `python _building/build_setup.py`
|
|
2
|
-
import setuptools
|
|
3
|
-
setuptools.setup(
|
|
4
|
-
name="k3cacheable",
|
|
5
|
-
packages=["k3cacheable"],
|
|
6
|
-
version="0.1.0",
|
|
7
|
-
license='MIT',
|
|
8
|
-
description='Cache data which access frequently.',
|
|
9
|
-
long_description="# k3cacheable\n\n[](https://github.com/pykit3/k3cacheable/actions/workflows/python-package.yml)\n[](https://travis-ci.com/pykit3/k3cacheable)\n[](https://k3cacheable.readthedocs.io/en/stable/?badge=stable)\n[](https://pypi.org/project/k3cacheable)\n\nCache data which access frequently.\n\nk3cacheable is a component of [pykit3] project: a python3 toolkit set.\n\n\nCache data which access frequently.\n\n\n\n\n# Install\n\n```\npip install k3cacheable\n```\n\n# Synopsis\n\n```python\n\nimport k3cacheable\nimport time\n\n# create a `LRU`, capacity:10 timeout:60\nc = k3cacheable.LRU(10, 60)\n\n# set value like the `dict`\nc['key'] = 'val'\n\n# get value like the `dict`\n# if item timeout, delete it and raise `KeyError`\n# if item not exist, raise `KeyError`\ntry:\n val = c['key']\nexcept KeyError:\n print('key error')\n\ncache_data = {\n 'key1': 'val_1',\n 'key2': 'val_2',\n}\n\n# define the function with a decorator\n@k3cacheable.cache('cache_name', capacity=100, timeout=60,\n is_deepcopy=False, mutex_update=False)\ndef get_data(param):\n return cache_data.get(param, '')\n\n# call `get_data`, if item has not been cached, cache the return value\ndata = get_data('key1')\n\n# call `get_data` use the same param, data will be got from cache\ntime.sleep(1)\ndata = get_data('key1')\n\n# if item timeout, when call `get_data`, cache again\ntime.sleep(1)\ndata = get_data('key1')\n\n# define a method with a decorator\nclass MethodCache(object):\n\n @k3cacheable.cache('method_cache_name', capacity=100, timeout=60,\n is_deepcopy=False, mutex_update=False)\n def get_data(self, param):\n return cache_data.get(param, '')\n\nmm = MethodCache()\ndata = mm.get_data('key2')\n\n```\n\n# Author\n\nZhang Yanpo (张炎泼) <drdr.xp@gmail.com>\n\n# Copyright and License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Zhang Yanpo (张炎泼) <drdr.xp@gmail.com>\n\n\n[pykit3]: https://github.com/pykit3",
|
|
10
|
-
long_description_content_type="text/markdown",
|
|
11
|
-
author='Zhang Yanpo',
|
|
12
|
-
author_email='drdr.xp@gmail.com',
|
|
13
|
-
url='https://github.com/pykit3/k3cacheable',
|
|
14
|
-
keywords=['python', 'cache'],
|
|
15
|
-
python_requires='>=3.0',
|
|
16
|
-
|
|
17
|
-
install_requires=['msgpack>=1.0.0'],
|
|
18
|
-
classifiers=[
|
|
19
|
-
'Development Status :: 4 - Beta',
|
|
20
|
-
'Intended Audience :: Developers',
|
|
21
|
-
'Topic :: Software Development :: Libraries',
|
|
22
|
-
] + ['Programming Language :: Python :: 3'],
|
|
23
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|