cachetools 5.4.0__tar.gz → 5.5.0__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.
- {cachetools-5.4.0 → cachetools-5.5.0}/CHANGELOG.rst +14 -0
- {cachetools-5.4.0/src/cachetools.egg-info → cachetools-5.5.0}/PKG-INFO +1 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/docs/index.rst +49 -7
- {cachetools-5.4.0 → cachetools-5.5.0}/src/cachetools/__init__.py +17 -6
- {cachetools-5.4.0 → cachetools-5.5.0/src/cachetools.egg-info}/PKG-INFO +1 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/__init__.py +0 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_cache.py +0 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_fifo.py +0 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_keys.py +35 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_lfu.py +0 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_lru.py +0 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_mru.py +0 -2
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_rr.py +0 -1
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_tlru.py +8 -5
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_ttl.py +12 -7
- {cachetools-5.4.0 → cachetools-5.5.0}/LICENSE +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/MANIFEST.in +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/README.rst +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/docs/conf.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/pyproject.toml +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/setup.cfg +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/setup.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/src/cachetools/func.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/src/cachetools/keys.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/src/cachetools.egg-info/SOURCES.txt +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/src/cachetools.egg-info/dependency_links.txt +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/src/cachetools.egg-info/top_level.txt +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_cached.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_cachedmethod.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/tests/test_func.py +0 -0
- {cachetools-5.4.0 → cachetools-5.5.0}/tox.ini +0 -0
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
v5.5.0 (2024-08-18)
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
- ``TTLCache.expire()`` returns iterable of expired ``(key, value)``
|
|
5
|
+
pairs.
|
|
6
|
+
|
|
7
|
+
- ``TLRUCache.expire()`` returns iterable of expired ``(key, value)``
|
|
8
|
+
pairs.
|
|
9
|
+
|
|
10
|
+
- Documentation improvements.
|
|
11
|
+
|
|
12
|
+
- Update CI environment.
|
|
13
|
+
|
|
14
|
+
|
|
1
15
|
v5.4.0 (2024-07-15)
|
|
2
16
|
===================
|
|
3
17
|
|
|
@@ -26,6 +26,8 @@ method calls.
|
|
|
26
26
|
from unittest import mock
|
|
27
27
|
urllib = mock.MagicMock()
|
|
28
28
|
|
|
29
|
+
import time
|
|
30
|
+
|
|
29
31
|
|
|
30
32
|
Cache implementations
|
|
31
33
|
=====================
|
|
@@ -153,6 +155,8 @@ computed when the item is inserted into the cache.
|
|
|
153
155
|
items that have expired by the current value returned by
|
|
154
156
|
:attr:`timer`.
|
|
155
157
|
|
|
158
|
+
:returns: An iterable of expired `(key, value)` pairs.
|
|
159
|
+
|
|
156
160
|
.. autoclass:: TLRUCache(maxsize, ttu, timer=time.monotonic, getsizeof=None)
|
|
157
161
|
:members: popitem, timer, ttu
|
|
158
162
|
|
|
@@ -164,18 +168,29 @@ computed when the item is inserted into the cache.
|
|
|
164
168
|
value of `timer()`.
|
|
165
169
|
|
|
166
170
|
.. testcode::
|
|
167
|
-
|
|
168
|
-
from datetime import datetime, timedelta
|
|
169
|
-
|
|
171
|
+
|
|
170
172
|
def my_ttu(_key, value, now):
|
|
171
|
-
# assume value.
|
|
172
|
-
|
|
173
|
+
# assume value.ttu contains the item's time-to-use in seconds
|
|
174
|
+
# note that the _key argument is ignored in this example
|
|
175
|
+
return now + value.ttu
|
|
173
176
|
|
|
174
|
-
cache = TLRUCache(maxsize=10, ttu=my_ttu
|
|
177
|
+
cache = TLRUCache(maxsize=10, ttu=my_ttu)
|
|
175
178
|
|
|
176
179
|
The expression `ttu(key, value, timer())` defines the expiration
|
|
177
180
|
time of a cache item, and must be comparable against later results
|
|
178
|
-
of `timer()`.
|
|
181
|
+
of `timer()`. As with :class:`TTLCache`, a custom `timer` function
|
|
182
|
+
can be supplied, which does not have to return a numeric value.
|
|
183
|
+
|
|
184
|
+
.. testcode::
|
|
185
|
+
|
|
186
|
+
from datetime import datetime, timedelta
|
|
187
|
+
|
|
188
|
+
def datetime_ttu(_key, value, now):
|
|
189
|
+
# assume now to be of type datetime.datetime, and
|
|
190
|
+
# value.hours to contain the item's time-to-use in hours
|
|
191
|
+
return now + timedelta(hours=value.hours)
|
|
192
|
+
|
|
193
|
+
cache = TLRUCache(maxsize=10, ttu=datetime_ttu, timer=datetime.now)
|
|
179
194
|
|
|
180
195
|
Items that expire because they have exceeded their time-to-use will
|
|
181
196
|
be no longer accessible, and will be removed eventually. If no
|
|
@@ -193,6 +208,8 @@ computed when the item is inserted into the cache.
|
|
|
193
208
|
items that have expired by the current value returned by
|
|
194
209
|
:attr:`timer`.
|
|
195
210
|
|
|
211
|
+
:returns: An iterable of expired `(key, value)` pairs.
|
|
212
|
+
|
|
196
213
|
|
|
197
214
|
Extending cache classes
|
|
198
215
|
=======================
|
|
@@ -217,6 +234,31 @@ cache, this can be achieved by overriding this method in a subclass:
|
|
|
217
234
|
>>> c['c'] = 3
|
|
218
235
|
Key "a" evicted with value "1"
|
|
219
236
|
|
|
237
|
+
With :class:`TTLCache` and :class:`TLRUCache`, items may also be
|
|
238
|
+
removed after they expire. In this case, :meth:`popitem` will *not*
|
|
239
|
+
be called, but :meth:`expire` will be called from the next mutating
|
|
240
|
+
operation and will return an iterable of the expired `(key, value)`
|
|
241
|
+
pairs. By overrding :meth:`expire`, a subclass will be able to track
|
|
242
|
+
expired items:
|
|
243
|
+
|
|
244
|
+
.. doctest::
|
|
245
|
+
:pyversion: >= 3
|
|
246
|
+
|
|
247
|
+
>>> class ExpCache(TTLCache):
|
|
248
|
+
... def expire(self, time=None):
|
|
249
|
+
... items = super().expire(time)
|
|
250
|
+
... print(f"Expired items: {items}")
|
|
251
|
+
... return items
|
|
252
|
+
|
|
253
|
+
>>> c = ExpCache(maxsize=10, ttl=1.0)
|
|
254
|
+
>>> c['a'] = 1
|
|
255
|
+
Expired items: []
|
|
256
|
+
>>> c['b'] = 2
|
|
257
|
+
Expired items: []
|
|
258
|
+
>>> time.sleep(1.5)
|
|
259
|
+
>>> c['c'] = 3
|
|
260
|
+
Expired items: [('a', 1), ('b', 2)]
|
|
261
|
+
|
|
220
262
|
Similar to the standard library's :class:`collections.defaultdict`,
|
|
221
263
|
subclasses of :class:`Cache` may implement a :meth:`__missing__`
|
|
222
264
|
method which is called by :meth:`Cache.__getitem__` if the requested
|
|
@@ -13,7 +13,7 @@ __all__ = (
|
|
|
13
13
|
"cachedmethod",
|
|
14
14
|
)
|
|
15
15
|
|
|
16
|
-
__version__ = "5.
|
|
16
|
+
__version__ = "5.5.0"
|
|
17
17
|
|
|
18
18
|
import collections
|
|
19
19
|
import collections.abc
|
|
@@ -26,7 +26,6 @@ from . import keys
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class _DefaultSize:
|
|
29
|
-
|
|
30
29
|
__slots__ = ()
|
|
31
30
|
|
|
32
31
|
def __getitem__(self, _):
|
|
@@ -378,7 +377,6 @@ class TTLCache(_TimedCache):
|
|
|
378
377
|
"""LRU Cache implementation with per-item time-to-live (TTL) value."""
|
|
379
378
|
|
|
380
379
|
class _Link:
|
|
381
|
-
|
|
382
380
|
__slots__ = ("key", "expires", "next", "prev")
|
|
383
381
|
|
|
384
382
|
def __init__(self, key=None, expires=None):
|
|
@@ -469,19 +467,26 @@ class TTLCache(_TimedCache):
|
|
|
469
467
|
return self.__ttl
|
|
470
468
|
|
|
471
469
|
def expire(self, time=None):
|
|
472
|
-
"""Remove expired items from the cache
|
|
470
|
+
"""Remove expired items from the cache and return an iterable of the
|
|
471
|
+
expired `(key, value)` pairs.
|
|
472
|
+
|
|
473
|
+
"""
|
|
473
474
|
if time is None:
|
|
474
475
|
time = self.timer()
|
|
475
476
|
root = self.__root
|
|
476
477
|
curr = root.next
|
|
477
478
|
links = self.__links
|
|
479
|
+
expired = []
|
|
478
480
|
cache_delitem = Cache.__delitem__
|
|
481
|
+
cache_getitem = Cache.__getitem__
|
|
479
482
|
while curr is not root and not (time < curr.expires):
|
|
483
|
+
expired.append((curr.key, cache_getitem(self, curr.key)))
|
|
480
484
|
cache_delitem(self, curr.key)
|
|
481
485
|
del links[curr.key]
|
|
482
486
|
next = curr.next
|
|
483
487
|
curr.unlink()
|
|
484
488
|
curr = next
|
|
489
|
+
return expired
|
|
485
490
|
|
|
486
491
|
def popitem(self):
|
|
487
492
|
"""Remove and return the `(key, value)` pair least recently used that
|
|
@@ -508,7 +513,6 @@ class TLRUCache(_TimedCache):
|
|
|
508
513
|
|
|
509
514
|
@functools.total_ordering
|
|
510
515
|
class _Item:
|
|
511
|
-
|
|
512
516
|
__slots__ = ("key", "expires", "removed")
|
|
513
517
|
|
|
514
518
|
def __init__(self, key=None, expires=None):
|
|
@@ -583,7 +587,10 @@ class TLRUCache(_TimedCache):
|
|
|
583
587
|
return self.__ttu
|
|
584
588
|
|
|
585
589
|
def expire(self, time=None):
|
|
586
|
-
"""Remove expired items from the cache
|
|
590
|
+
"""Remove expired items from the cache and return an iterable of the
|
|
591
|
+
expired `(key, value)` pairs.
|
|
592
|
+
|
|
593
|
+
"""
|
|
587
594
|
if time is None:
|
|
588
595
|
time = self.timer()
|
|
589
596
|
items = self.__items
|
|
@@ -592,12 +599,16 @@ class TLRUCache(_TimedCache):
|
|
|
592
599
|
if len(order) > len(items) * 2:
|
|
593
600
|
self.__order = order = [item for item in order if not item.removed]
|
|
594
601
|
heapq.heapify(order)
|
|
602
|
+
expired = []
|
|
595
603
|
cache_delitem = Cache.__delitem__
|
|
604
|
+
cache_getitem = Cache.__getitem__
|
|
596
605
|
while order and (order[0].removed or not (time < order[0].expires)):
|
|
597
606
|
item = heapq.heappop(order)
|
|
598
607
|
if not item.removed:
|
|
608
|
+
expired.append((item.key, cache_getitem(self, item.key)))
|
|
599
609
|
cache_delitem(self, item.key)
|
|
600
610
|
del items[item.key]
|
|
611
|
+
return expired
|
|
601
612
|
|
|
602
613
|
def popitem(self):
|
|
603
614
|
"""Remove and return the `(key, value)` pair least recently used that
|
|
@@ -21,6 +21,24 @@ class CacheKeysTest(unittest.TestCase):
|
|
|
21
21
|
self.assertEqual(key(1, 2, 3), key(1.0, 2.0, 3.0))
|
|
22
22
|
self.assertEqual(hash(key(1, 2, 3)), hash(key(1.0, 2.0, 3.0)))
|
|
23
23
|
|
|
24
|
+
def methodkey(self, key=cachetools.keys.methodkey):
|
|
25
|
+
# similar to hashkey(), but ignores its first positional argument
|
|
26
|
+
self.assertEqual(key("x"), key("y"))
|
|
27
|
+
self.assertEqual(hash(key("x")), hash(key("y")))
|
|
28
|
+
self.assertEqual(key("x", 1, 2, 3), key("y", 1, 2, 3))
|
|
29
|
+
self.assertEqual(hash(key("x", 1, 2, 3)), hash(key("y", 1, 2, 3)))
|
|
30
|
+
self.assertEqual(key("x", 1, 2, 3, x=0), key("y", 1, 2, 3, x=0))
|
|
31
|
+
self.assertEqual(hash(key("x", 1, 2, 3, x=0)), hash(key("y", 1, 2, 3, x=0)))
|
|
32
|
+
self.assertNotEqual(key("x", 1, 2, 3), key("x", 3, 2, 1))
|
|
33
|
+
self.assertNotEqual(key("x", 1, 2, 3), key("x", 1, 2, 3, x=None))
|
|
34
|
+
self.assertNotEqual(key("x", 1, 2, 3, x=0), key("x", 1, 2, 3, x=None))
|
|
35
|
+
self.assertNotEqual(key("x", 1, 2, 3, x=0), key("x", 1, 2, 3, y=0))
|
|
36
|
+
with self.assertRaises(TypeError):
|
|
37
|
+
hash("x", key({}))
|
|
38
|
+
# untyped keys compare equal
|
|
39
|
+
self.assertEqual(key("x", 1, 2, 3), key("y", 1.0, 2.0, 3.0))
|
|
40
|
+
self.assertEqual(hash(key("x", 1, 2, 3)), hash(key("y", 1.0, 2.0, 3.0)))
|
|
41
|
+
|
|
24
42
|
def test_typedkey(self, key=cachetools.keys.typedkey):
|
|
25
43
|
self.assertEqual(key(), key())
|
|
26
44
|
self.assertEqual(hash(key()), hash(key()))
|
|
@@ -37,6 +55,23 @@ class CacheKeysTest(unittest.TestCase):
|
|
|
37
55
|
# typed keys compare unequal
|
|
38
56
|
self.assertNotEqual(key(1, 2, 3), key(1.0, 2.0, 3.0))
|
|
39
57
|
|
|
58
|
+
def test_typedmethodkey(self, key=cachetools.keys.typedmethodkey):
|
|
59
|
+
# similar to typedkey(), but ignores its first positional argument
|
|
60
|
+
self.assertEqual(key("x"), key("y"))
|
|
61
|
+
self.assertEqual(hash(key("x")), hash(key("y")))
|
|
62
|
+
self.assertEqual(key("x", 1, 2, 3), key("y", 1, 2, 3))
|
|
63
|
+
self.assertEqual(hash(key("x", 1, 2, 3)), hash(key("y", 1, 2, 3)))
|
|
64
|
+
self.assertEqual(key("x", 1, 2, 3, x=0), key("y", 1, 2, 3, x=0))
|
|
65
|
+
self.assertEqual(hash(key("x", 1, 2, 3, x=0)), hash(key("y", 1, 2, 3, x=0)))
|
|
66
|
+
self.assertNotEqual(key("x", 1, 2, 3), key("x", 3, 2, 1))
|
|
67
|
+
self.assertNotEqual(key("x", 1, 2, 3), key("x", 1, 2, 3, x=None))
|
|
68
|
+
self.assertNotEqual(key("x", 1, 2, 3, x=0), key("x", 1, 2, 3, x=None))
|
|
69
|
+
self.assertNotEqual(key("x", 1, 2, 3, x=0), key("x", 1, 2, 3, y=0))
|
|
70
|
+
with self.assertRaises(TypeError):
|
|
71
|
+
hash(key("x", {}))
|
|
72
|
+
# typed keys compare unequal
|
|
73
|
+
self.assertNotEqual(key("x", 1, 2, 3), key("x", 1.0, 2.0, 3.0))
|
|
74
|
+
|
|
40
75
|
def test_addkeys(self, key=cachetools.keys.hashkey):
|
|
41
76
|
self.assertIsInstance(key(), tuple)
|
|
42
77
|
self.assertIsInstance(key(1, 2, 3) + key(4, 5, 6), type(key()))
|
|
@@ -7,12 +7,10 @@ from . import CacheTestMixin
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class MRUCacheTest(unittest.TestCase, CacheTestMixin):
|
|
10
|
-
|
|
11
10
|
# TODO: method to create cache that can be overridden
|
|
12
11
|
Cache = MRUCache
|
|
13
12
|
|
|
14
13
|
def test_evict__writes_only(self):
|
|
15
|
-
|
|
16
14
|
with warnings.catch_warnings(record=True) as w:
|
|
17
15
|
warnings.simplefilter("always")
|
|
18
16
|
cache = MRUCache(maxsize=2)
|
|
@@ -29,7 +29,6 @@ class TLRUTestCache(TLRUCache):
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class TLRUCacheTest(unittest.TestCase, CacheTestMixin):
|
|
32
|
-
|
|
33
32
|
Cache = TLRUTestCache
|
|
34
33
|
|
|
35
34
|
def test_ttu(self):
|
|
@@ -157,28 +156,32 @@ class TLRUCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
157
156
|
self.assertEqual(2, cache[2])
|
|
158
157
|
self.assertEqual(3, cache[3])
|
|
159
158
|
|
|
160
|
-
cache.expire()
|
|
159
|
+
items = cache.expire()
|
|
160
|
+
self.assertEqual(set(), set(items))
|
|
161
161
|
self.assertEqual({1, 2, 3}, set(cache))
|
|
162
162
|
self.assertEqual(3, len(cache))
|
|
163
163
|
self.assertEqual(1, cache[1])
|
|
164
164
|
self.assertEqual(2, cache[2])
|
|
165
165
|
self.assertEqual(3, cache[3])
|
|
166
166
|
|
|
167
|
-
cache.expire(3)
|
|
167
|
+
items = cache.expire(3)
|
|
168
|
+
self.assertEqual({(1, 1)}, set(items))
|
|
168
169
|
self.assertEqual({2, 3}, set(cache))
|
|
169
170
|
self.assertEqual(2, len(cache))
|
|
170
171
|
self.assertNotIn(1, cache)
|
|
171
172
|
self.assertEqual(2, cache[2])
|
|
172
173
|
self.assertEqual(3, cache[3])
|
|
173
174
|
|
|
174
|
-
cache.expire(4)
|
|
175
|
+
items = cache.expire(4)
|
|
176
|
+
self.assertEqual({(2, 2)}, set(items))
|
|
175
177
|
self.assertEqual({3}, set(cache))
|
|
176
178
|
self.assertEqual(1, len(cache))
|
|
177
179
|
self.assertNotIn(1, cache)
|
|
178
180
|
self.assertNotIn(2, cache)
|
|
179
181
|
self.assertEqual(3, cache[3])
|
|
180
182
|
|
|
181
|
-
cache.expire(5)
|
|
183
|
+
items = cache.expire(5)
|
|
184
|
+
self.assertEqual({(3, 3)}, set(items))
|
|
182
185
|
self.assertEqual(set(), set(cache))
|
|
183
186
|
self.assertEqual(0, len(cache))
|
|
184
187
|
self.assertNotIn(1, cache)
|
|
@@ -26,7 +26,6 @@ class TTLTestCache(TTLCache):
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class TTLCacheTest(unittest.TestCase, CacheTestMixin):
|
|
29
|
-
|
|
30
29
|
Cache = TTLTestCache
|
|
31
30
|
|
|
32
31
|
def test_ttl(self):
|
|
@@ -132,28 +131,32 @@ class TTLCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
132
131
|
self.assertEqual(2, cache[2])
|
|
133
132
|
self.assertEqual(3, cache[3])
|
|
134
133
|
|
|
135
|
-
cache.expire()
|
|
134
|
+
items = cache.expire()
|
|
135
|
+
self.assertEqual(set(), set(items))
|
|
136
136
|
self.assertEqual({1, 2, 3}, set(cache))
|
|
137
137
|
self.assertEqual(3, len(cache))
|
|
138
138
|
self.assertEqual(1, cache[1])
|
|
139
139
|
self.assertEqual(2, cache[2])
|
|
140
140
|
self.assertEqual(3, cache[3])
|
|
141
141
|
|
|
142
|
-
cache.expire(3)
|
|
142
|
+
items = cache.expire(3)
|
|
143
|
+
self.assertEqual({(1, 1)}, set(items))
|
|
143
144
|
self.assertEqual({2, 3}, set(cache))
|
|
144
145
|
self.assertEqual(2, len(cache))
|
|
145
146
|
self.assertNotIn(1, cache)
|
|
146
147
|
self.assertEqual(2, cache[2])
|
|
147
148
|
self.assertEqual(3, cache[3])
|
|
148
149
|
|
|
149
|
-
cache.expire(4)
|
|
150
|
+
items = cache.expire(4)
|
|
151
|
+
self.assertEqual({(2, 2)}, set(items))
|
|
150
152
|
self.assertEqual({3}, set(cache))
|
|
151
153
|
self.assertEqual(1, len(cache))
|
|
152
154
|
self.assertNotIn(1, cache)
|
|
153
155
|
self.assertNotIn(2, cache)
|
|
154
156
|
self.assertEqual(3, cache[3])
|
|
155
157
|
|
|
156
|
-
cache.expire(5)
|
|
158
|
+
items = cache.expire(5)
|
|
159
|
+
self.assertEqual({(3, 3)}, set(items))
|
|
157
160
|
self.assertEqual(set(), set(cache))
|
|
158
161
|
self.assertEqual(0, len(cache))
|
|
159
162
|
self.assertNotIn(1, cache)
|
|
@@ -192,7 +195,9 @@ class TTLCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
192
195
|
|
|
193
196
|
cache[1] = 1
|
|
194
197
|
self.assertEqual(1, len(cache))
|
|
195
|
-
cache.expire(datetime.now())
|
|
198
|
+
items = cache.expire(datetime.now())
|
|
199
|
+
self.assertEqual([], list(items))
|
|
196
200
|
self.assertEqual(1, len(cache))
|
|
197
|
-
cache.expire(datetime.now() + timedelta(days=1))
|
|
201
|
+
items = cache.expire(datetime.now() + timedelta(days=1))
|
|
202
|
+
self.assertEqual([(1, 1)], list(items))
|
|
198
203
|
self.assertEqual(0, len(cache))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|