k3cacheable 0.1.2__tar.gz → 0.1.4__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.
@@ -1,22 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: k3cacheable
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Cache data which access frequently
5
5
  Author-email: Zhang Yanpo <drdr.xp@gmail.com>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/pykit3/k3cacheable
8
8
  Project-URL: Documentation, https://k3cacheable.readthedocs.io
9
9
  Keywords: cache,cacheable,memoize,pykit3
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: Software Development :: Libraries
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.9
16
14
  Classifier: Programming Language :: Python :: 3.10
17
15
  Classifier: Programming Language :: Python :: 3.11
18
16
  Classifier: Programming Language :: Python :: 3.12
19
- Requires-Python: >=3.9
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  Requires-Dist: msgpack
@@ -59,57 +59,57 @@ pip install k3cacheable
59
59
  # Synopsis
60
60
 
61
61
  ```python
62
+ import time
62
63
 
63
64
  import k3cacheable
64
- import time
65
65
 
66
66
  # create a `LRU`, capacity:10 timeout:60
67
67
  c = k3cacheable.LRU(10, 60)
68
68
 
69
69
  # set value like the `dict`
70
- c['key'] = 'val'
70
+ c["key"] = "val"
71
71
 
72
72
  # get value like the `dict`
73
73
  # if item timeout, delete it and raise `KeyError`
74
74
  # if item not exist, raise `KeyError`
75
75
  try:
76
- val = c['key']
76
+ val = c["key"]
77
77
  except KeyError:
78
- print('key error')
78
+ print("key error")
79
79
 
80
80
  cache_data = {
81
- 'key1': 'val_1',
82
- 'key2': 'val_2',
81
+ "key1": "val_1",
82
+ "key2": "val_2",
83
83
  }
84
84
 
85
+
85
86
  # define the function with a decorator
86
- @k3cacheable.cache('cache_name', capacity=100, timeout=60,
87
- is_deepcopy=False, mutex_update=False)
87
+ @k3cacheable.cache("cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
88
88
  def get_data(param):
89
- return cache_data.get(param, '')
89
+ return cache_data.get(param, "")
90
+
90
91
 
91
92
  # call `get_data`, if item has not been cached, cache the return value
92
- data = get_data('key1')
93
+ data = get_data("key1")
93
94
 
94
95
  # call `get_data` use the same param, data will be got from cache
95
96
  time.sleep(1)
96
- data = get_data('key1')
97
+ data = get_data("key1")
97
98
 
98
99
  # if item timeout, when call `get_data`, cache again
99
100
  time.sleep(1)
100
- data = get_data('key1')
101
+ data = get_data("key1")
101
102
 
102
- # define a method with a decorator
103
- class MethodCache(object):
104
103
 
105
- @k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
106
- is_deepcopy=False, mutex_update=False)
104
+ # define a method with a decorator
105
+ class MethodCache:
106
+ @k3cacheable.cache("method_cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
107
107
  def get_data(self, param):
108
- return cache_data.get(param, '')
108
+ return cache_data.get(param, "")
109
109
 
110
- mm = MethodCache()
111
- data = mm.get_data('key2')
112
110
 
111
+ mm = MethodCache()
112
+ data = mm.get_data("key2")
113
113
  ```
114
114
 
115
115
  # Author
@@ -23,57 +23,57 @@ pip install k3cacheable
23
23
  # Synopsis
24
24
 
25
25
  ```python
26
+ import time
26
27
 
27
28
  import k3cacheable
28
- import time
29
29
 
30
30
  # create a `LRU`, capacity:10 timeout:60
31
31
  c = k3cacheable.LRU(10, 60)
32
32
 
33
33
  # set value like the `dict`
34
- c['key'] = 'val'
34
+ c["key"] = "val"
35
35
 
36
36
  # get value like the `dict`
37
37
  # if item timeout, delete it and raise `KeyError`
38
38
  # if item not exist, raise `KeyError`
39
39
  try:
40
- val = c['key']
40
+ val = c["key"]
41
41
  except KeyError:
42
- print('key error')
42
+ print("key error")
43
43
 
44
44
  cache_data = {
45
- 'key1': 'val_1',
46
- 'key2': 'val_2',
45
+ "key1": "val_1",
46
+ "key2": "val_2",
47
47
  }
48
48
 
49
+
49
50
  # define the function with a decorator
50
- @k3cacheable.cache('cache_name', capacity=100, timeout=60,
51
- is_deepcopy=False, mutex_update=False)
51
+ @k3cacheable.cache("cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
52
52
  def get_data(param):
53
- return cache_data.get(param, '')
53
+ return cache_data.get(param, "")
54
+
54
55
 
55
56
  # call `get_data`, if item has not been cached, cache the return value
56
- data = get_data('key1')
57
+ data = get_data("key1")
57
58
 
58
59
  # call `get_data` use the same param, data will be got from cache
59
60
  time.sleep(1)
60
- data = get_data('key1')
61
+ data = get_data("key1")
61
62
 
62
63
  # if item timeout, when call `get_data`, cache again
63
64
  time.sleep(1)
64
- data = get_data('key1')
65
+ data = get_data("key1")
65
66
 
66
- # define a method with a decorator
67
- class MethodCache(object):
68
67
 
69
- @k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
70
- is_deepcopy=False, mutex_update=False)
68
+ # define a method with a decorator
69
+ class MethodCache:
70
+ @k3cacheable.cache("method_cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
71
71
  def get_data(self, param):
72
- return cache_data.get(param, '')
72
+ return cache_data.get(param, "")
73
73
 
74
- mm = MethodCache()
75
- data = mm.get_data('key2')
76
74
 
75
+ mm = MethodCache()
76
+ data = mm.get_data("key2")
77
77
  ```
78
78
 
79
79
  # Author
@@ -1,17 +1,15 @@
1
- #!/usr/bin/env python
2
- # coding: utf-8
3
-
4
1
  import copy
5
2
  import logging
6
3
  import threading
7
4
  import time
5
+
8
6
  import msgpack
9
7
 
10
8
  logger = logging.getLogger(__name__)
11
9
  _lock_mutex_update = threading.RLock()
12
10
 
13
11
 
14
- class LRU(object):
12
+ class LRU:
15
13
  """
16
14
  `LRU` contain `__getitem__` and `__setitem__`,
17
15
  so can get value and set value like `dict`
@@ -75,7 +73,7 @@ class LRU(object):
75
73
 
76
74
  if now > item["tm"] + self.timeout:
77
75
  self._del_item(item)
78
- raise KeyError("{k} is timeout".format(k=key))
76
+ raise KeyError(f"{key} is timeout")
79
77
 
80
78
  self._move_to_tail(item)
81
79
 
@@ -127,7 +125,7 @@ class LRU(object):
127
125
  self._del_item(item)
128
126
 
129
127
 
130
- class Cacheable(object):
128
+ class Cacheable:
131
129
  def __init__(self, capacity=1024 * 4, timeout=60, is_deepcopy=True, is_pack=False, mutex_update=False):
132
130
  """
133
131
  Create a `LRU` object, all items will be cached in it.
@@ -163,7 +161,8 @@ class Cacheable(object):
163
161
  def _cache_wrapper(self, fun):
164
162
  def func_wrapper(*args, **argkv):
165
163
  val = None
166
- generate_key = self._arg_str(args, argkv)
164
+ # Functions that use the same cache name share one LRU, so the key includes the function.
165
+ generate_key = (fun, self._arg_str(args, argkv))
167
166
 
168
167
  try:
169
168
  val = self.lru[generate_key]
@@ -229,7 +228,9 @@ def cache(name, capacity=1024 * 4, timeout=60, is_deepcopy=True, is_pack=False,
229
228
  """
230
229
  c = caches.get(name)
231
230
  if c is None:
232
- c = Cacheable(capacity=capacity, timeout=timeout, is_deepcopy=is_deepcopy, mutex_update=mutex_update)
231
+ c = Cacheable(
232
+ capacity=capacity, timeout=timeout, is_deepcopy=is_deepcopy, is_pack=is_pack, mutex_update=mutex_update
233
+ )
233
234
  caches[name] = c
234
235
 
235
236
  return c._cache_wrapper
@@ -1,22 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: k3cacheable
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Cache data which access frequently
5
5
  Author-email: Zhang Yanpo <drdr.xp@gmail.com>
6
- License: MIT
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/pykit3/k3cacheable
8
8
  Project-URL: Documentation, https://k3cacheable.readthedocs.io
9
9
  Keywords: cache,cacheable,memoize,pykit3
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: Software Development :: Libraries
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.9
16
14
  Classifier: Programming Language :: Python :: 3.10
17
15
  Classifier: Programming Language :: Python :: 3.11
18
16
  Classifier: Programming Language :: Python :: 3.12
19
- Requires-Python: >=3.9
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  Requires-Dist: msgpack
@@ -59,57 +59,57 @@ pip install k3cacheable
59
59
  # Synopsis
60
60
 
61
61
  ```python
62
+ import time
62
63
 
63
64
  import k3cacheable
64
- import time
65
65
 
66
66
  # create a `LRU`, capacity:10 timeout:60
67
67
  c = k3cacheable.LRU(10, 60)
68
68
 
69
69
  # set value like the `dict`
70
- c['key'] = 'val'
70
+ c["key"] = "val"
71
71
 
72
72
  # get value like the `dict`
73
73
  # if item timeout, delete it and raise `KeyError`
74
74
  # if item not exist, raise `KeyError`
75
75
  try:
76
- val = c['key']
76
+ val = c["key"]
77
77
  except KeyError:
78
- print('key error')
78
+ print("key error")
79
79
 
80
80
  cache_data = {
81
- 'key1': 'val_1',
82
- 'key2': 'val_2',
81
+ "key1": "val_1",
82
+ "key2": "val_2",
83
83
  }
84
84
 
85
+
85
86
  # define the function with a decorator
86
- @k3cacheable.cache('cache_name', capacity=100, timeout=60,
87
- is_deepcopy=False, mutex_update=False)
87
+ @k3cacheable.cache("cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
88
88
  def get_data(param):
89
- return cache_data.get(param, '')
89
+ return cache_data.get(param, "")
90
+
90
91
 
91
92
  # call `get_data`, if item has not been cached, cache the return value
92
- data = get_data('key1')
93
+ data = get_data("key1")
93
94
 
94
95
  # call `get_data` use the same param, data will be got from cache
95
96
  time.sleep(1)
96
- data = get_data('key1')
97
+ data = get_data("key1")
97
98
 
98
99
  # if item timeout, when call `get_data`, cache again
99
100
  time.sleep(1)
100
- data = get_data('key1')
101
+ data = get_data("key1")
101
102
 
102
- # define a method with a decorator
103
- class MethodCache(object):
104
103
 
105
- @k3cacheable.cache('method_cache_name', capacity=100, timeout=60,
106
- is_deepcopy=False, mutex_update=False)
104
+ # define a method with a decorator
105
+ class MethodCache:
106
+ @k3cacheable.cache("method_cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
107
107
  def get_data(self, param):
108
- return cache_data.get(param, '')
108
+ return cache_data.get(param, "")
109
109
 
110
- mm = MethodCache()
111
- data = mm.get_data('key2')
112
110
 
111
+ mm = MethodCache()
112
+ data = mm.get_data("key2")
113
113
  ```
114
114
 
115
115
  # Author
@@ -1,14 +1,14 @@
1
1
  [build-system]
2
- requires = ["setuptools>=61.0"]
2
+ requires = ["setuptools>=77.0"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "k3cacheable"
7
- version = "0.1.2"
7
+ version = "0.1.4"
8
8
  description = "Cache data which access frequently"
9
9
  readme = "README.md"
10
- license = {text = "MIT"}
11
- requires-python = ">=3.9"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
12
  authors = [
13
13
  { name = "Zhang Yanpo", email = "drdr.xp@gmail.com" }
14
14
  ]
@@ -17,12 +17,12 @@ classifiers = [
17
17
  "Development Status :: 4 - Beta",
18
18
  "Intended Audience :: Developers",
19
19
  "Topic :: Software Development :: Libraries",
20
- "License :: OSI Approved :: MIT License",
21
20
  "Programming Language :: Python :: 3",
22
- "Programming Language :: Python :: 3.9",
23
21
  "Programming Language :: Python :: 3.10",
24
22
  "Programming Language :: Python :: 3.11",
25
23
  "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
26
  ]
27
27
  dependencies = [
28
28
  "msgpack",
@@ -1,6 +1,7 @@
1
- import k3cacheable
2
1
  import time
3
2
 
3
+ import k3cacheable
4
+
4
5
  # create a `LRU`, capacity:10 timeout:60
5
6
  c = k3cacheable.LRU(10, 60)
6
7
 
@@ -40,7 +41,7 @@ data = get_data("key1")
40
41
 
41
42
 
42
43
  # define a method with a decorator
43
- class MethodCache(object):
44
+ class MethodCache:
44
45
  @k3cacheable.cache("method_cache_name", capacity=100, timeout=60, is_deepcopy=False, mutex_update=False)
45
46
  def get_data(self, param):
46
47
  return cache_data.get(param, "")
@@ -1,6 +1,3 @@
1
- #!/usr/bin/env python
2
- # coding: utf-8
3
-
4
1
  import _thread
5
2
  import time
6
3
  import unittest
@@ -61,12 +58,12 @@ class TestLRU(unittest.TestCase):
61
58
  for insert_count, exist_items, cleanup_items in cases:
62
59
  lru = k3cacheable.LRU(capacity, 10)
63
60
  for i in range(insert_count):
64
- lru[i] = "val%d" % (i)
61
+ lru[i] = f"val{i}"
65
62
 
66
63
  for i in range(insert_count):
67
64
  try:
68
65
  val = lru[i]
69
- self.assertEqual(val, "val%d" % (i))
66
+ self.assertEqual(val, f"val{i}")
70
67
  self.assertEqual(lru.tail["key"], i)
71
68
  self.assertIn(i, exist_items)
72
69
 
@@ -118,20 +115,20 @@ class TestCacheable(unittest.TestCase):
118
115
 
119
116
  def test_get_items_from_cache(self):
120
117
  cache_items = {}
121
- for key in need_cache_data.keys():
118
+ for key in need_cache_data:
122
119
  cache_items[key] = get_cache_data(key)
123
120
 
124
121
  time.sleep(0.1)
125
- for key in need_cache_data.keys():
122
+ for key in need_cache_data:
126
123
  self.assertEqual(get_cache_data(key), cache_items[key])
127
124
 
128
125
  def test_get_items_from_cache_use_method(self):
129
126
  cache_items = {}
130
- for key in need_cache_data.keys():
127
+ for key in need_cache_data:
131
128
  cache_items[key] = self._method_cache_data(key)
132
129
 
133
130
  time.sleep(0.1)
134
- for key in need_cache_data.keys():
131
+ for key in need_cache_data:
135
132
  self.assertEqual(self._method_cache_data(key), cache_items[key])
136
133
 
137
134
  def test_cache_item_timeout_and_cache_again(self):
@@ -151,6 +148,13 @@ class TestCacheable(unittest.TestCase):
151
148
  def test_get_deepcopy_item_from_cache(self):
152
149
  self.assertIsNot(get_deepcopy_of_cache_data("key1"), get_deepcopy_of_cache_data("key1"))
153
150
 
151
+ def test_get_pack_item_from_cache(self):
152
+ # With `is_deepcopy=False`, only unpacking the cached msgpack bytes gives a new object on each call.
153
+ first = get_pack_of_cache_data("key1")
154
+ second = get_pack_of_cache_data("key1")
155
+ self.assertEqual({"key": "key1"}, first)
156
+ self.assertIsNot(first, second)
157
+
154
158
  def test_get_concurrent_update_cache_data(self):
155
159
  result = {}
156
160
 
@@ -198,12 +202,29 @@ class TestCacheable(unittest.TestCase):
198
202
  for args, argkv, expect_str in cases:
199
203
  self.assertEqual(k3cacheable.Cacheable()._arg_str(args, argkv), expect_str)
200
204
 
205
+ def test_functions_sharing_cache_name(self):
206
+ @k3cacheable.cache("shared_by_two_functions", capacity=10, timeout=60, is_deepcopy=False)
207
+ def get_aa(key):
208
+ return "aa-" + key
209
+
210
+ @k3cacheable.cache("shared_by_two_functions", capacity=10, timeout=60, is_deepcopy=False)
211
+ def get_bb(key):
212
+ return "bb-" + key
213
+
214
+ self.assertEqual("aa-k", get_aa("k"))
215
+ self.assertEqual("bb-k", get_bb("k"))
216
+
201
217
 
202
218
  @k3cacheable.cache("deepcopy_of_cache_data", capacity=100, timeout=60, is_deepcopy=True)
203
219
  def get_deepcopy_of_cache_data(key):
204
220
  return need_cache_data.get(key, {})
205
221
 
206
222
 
223
+ @k3cacheable.cache("pack_of_cache_data", capacity=100, timeout=60, is_deepcopy=False, is_pack=True)
224
+ def get_pack_of_cache_data(key):
225
+ return {"key": key}
226
+
227
+
207
228
  @k3cacheable.cache("cache_data", capacity=100, timeout=4, is_deepcopy=False)
208
229
  def get_cache_data(key):
209
230
  cache_data = need_cache_data.get(key, {})
File without changes
File without changes
File without changes