Merge lp:~logan/ubuntu/saucy/python-repoze.lru/0.6-1ubuntu1 into lp:ubuntu/saucy/python-repoze.lru
- Saucy (13.10)
- 0.6-1ubuntu1
- Merge into saucy
Proposed by
Logan Rosen
Status: | Merged |
---|---|
Merged at revision: | 12 |
Proposed branch: | lp:~logan/ubuntu/saucy/python-repoze.lru/0.6-1ubuntu1 |
Merge into: | lp:ubuntu/saucy/python-repoze.lru |
Diff against target: |
1945 lines (+1277/-183) 23 files modified
.gitignore (+1/-0) .pc/fix-lp-tests.patch/repoze/lru/tests.py (+144/-3) CHANGES.txt (+23/-2) CONTRIBUTORS.txt (+1/-0) PKG-INFO (+26/-41) README.txt (+1/-36) debian/changelog (+19/-1) debian/control (+2/-2) debian/patches/fix-lp-tests.patch (+8/-9) docs/Makefile (+153/-0) docs/api.rst (+23/-0) docs/conf.py (+242/-0) docs/index.rst (+19/-0) docs/make.bat (+190/-0) docs/narr.rst (+95/-0) repoze.lru.egg-info/PKG-INFO (+26/-41) repoze.lru.egg-info/SOURCES.txt (+9/-0) repoze.lru.egg-info/requires.txt (+8/-0) repoze/lru/__init__.py (+107/-6) repoze/lru/tests.py (+144/-3) setup.cfg (+4/-0) setup.py (+8/-3) tox.ini (+24/-36) |
To merge this branch: | bzr merge lp:~logan/ubuntu/saucy/python-repoze.lru/0.6-1ubuntu1 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Didier Roche-Tolomelli | Approve | ||
Ubuntu branches | Pending | ||
Review via email: mp+167882@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.gitignore' |
2 | --- .gitignore 2012-04-09 10:24:06 +0000 |
3 | +++ .gitignore 2013-06-07 00:36:27 +0000 |
4 | @@ -10,3 +10,4 @@ |
5 | nosetests.xml |
6 | coverage.xml |
7 | repoze/lru/coverage.xml |
8 | +docs/_build/* |
9 | |
10 | === modified file '.pc/fix-lp-tests.patch/repoze/lru/tests.py' |
11 | --- .pc/fix-lp-tests.patch/repoze/lru/tests.py 2012-05-24 11:54:28 +0000 |
12 | +++ .pc/fix-lp-tests.patch/repoze/lru/tests.py 2013-06-07 00:36:27 +0000 |
13 | @@ -1,14 +1,15 @@ |
14 | -#!/usr/bin/python -tt |
15 | import random |
16 | import time |
17 | import unittest |
18 | |
19 | try: |
20 | range = xrange |
21 | -except NameError: # pragma: no cover |
22 | +except NameError: # pragma: NO COVER (Python3) |
23 | pass |
24 | |
25 | + |
26 | class LRUCacheTests(unittest.TestCase): |
27 | + |
28 | def _getTargetClass(self): |
29 | from repoze.lru import LRUCache |
30 | return LRUCache |
31 | @@ -23,7 +24,7 @@ |
32 | |
33 | # lengths of data structures |
34 | self.assertEqual(len(cache.clock_keys), len(cache.clock_refs)) |
35 | - self.assertTrue(len(cache.data) <=len(cache.clock_refs)) |
36 | + self.assertTrue(len(cache.data) <= len(cache.clock_refs)) |
37 | |
38 | # For each item in cache.data |
39 | # 1. pos must be a valid index |
40 | @@ -181,6 +182,9 @@ |
41 | else: |
42 | cache.put(item, "item%s" % item) |
43 | |
44 | + self.assertEqual(cache.misses, 0) |
45 | + self.assertEqual(cache.evictions, 0) |
46 | + |
47 | self.check_cache_is_consistent(cache) |
48 | |
49 | def test_imperfect_hitrate(self): |
50 | @@ -214,8 +218,36 @@ |
51 | self.assertTrue(hit_ratio > 45) |
52 | self.assertTrue(hit_ratio < 55) |
53 | |
54 | + # The internal cache counters should have the same information |
55 | + internal_hit_ratio = 100 * cache.hits / cache.lookups |
56 | + self.assertTrue(internal_hit_ratio > 45) |
57 | + self.assertTrue(internal_hit_ratio < 55) |
58 | + |
59 | + # The internal miss counters should also be around 50% |
60 | + internal_miss_ratio = 100 * cache.misses / cache.lookups |
61 | + self.assertTrue(internal_miss_ratio > 45) |
62 | + self.assertTrue(internal_miss_ratio < 55) |
63 | + |
64 | self.check_cache_is_consistent(cache) |
65 | |
66 | + def test_eviction_counter(self): |
67 | + cache = self._makeOne(2) |
68 | + cache.put(1, 1) |
69 | + cache.put(2, 1) |
70 | + self.assertEqual(cache.evictions, 0) |
71 | + |
72 | + cache.put(3, 1) |
73 | + cache.put(4, 1) |
74 | + self.assertEqual(cache.evictions, 2) |
75 | + |
76 | + cache.put(3, 1) |
77 | + cache.put(4, 1) |
78 | + self.assertEqual(cache.evictions, 2) |
79 | + |
80 | + cache.clear() |
81 | + self.assertEqual(cache.evictions, 0) |
82 | + |
83 | + |
84 | def test_it(self): |
85 | cache = self._makeOne(3) |
86 | self.assertEqual(cache.get('a'), None) |
87 | @@ -271,6 +303,7 @@ |
88 | |
89 | |
90 | class ExpiringLRUCacheTests(LRUCacheTests): |
91 | + |
92 | def _getTargetClass(self): |
93 | from repoze.lru import ExpiringLRUCache |
94 | return ExpiringLRUCache |
95 | @@ -316,6 +349,7 @@ |
96 | # All clock_refs must be True or False, nothing else. |
97 | for clock_ref in cache.clock_refs: |
98 | self.assertTrue(clock_ref is True or clock_ref is False) |
99 | + |
100 | def test_it(self): |
101 | """Test a sequence of operations |
102 | |
103 | @@ -455,7 +489,9 @@ |
104 | self.assertEqual(cache.get("foo3"), "bar3") |
105 | self.check_cache_is_consistent(cache) |
106 | |
107 | + |
108 | class DecoratorTests(unittest.TestCase): |
109 | + |
110 | def _getTargetClass(self): |
111 | from repoze.lru import lru_cache |
112 | return lru_cache |
113 | @@ -526,6 +562,111 @@ |
114 | self.assertEqual(result3, 2 * "hello") |
115 | self.assertTrue(stop - start > 0.1) |
116 | |
117 | + |
118 | class DummyLRUCache(dict): |
119 | + |
120 | def put(self, k, v): |
121 | return self.__setitem__(k, v) |
122 | + |
123 | + |
124 | +class CacherMaker(unittest.TestCase): |
125 | + |
126 | + def _getTargetClass(self): |
127 | + from repoze.lru import CacheMaker |
128 | + return CacheMaker |
129 | + |
130 | + def _makeOne(self, *args, **kw): |
131 | + return self._getTargetClass()(*args, **kw) |
132 | + |
133 | + def test_named_cache(self): |
134 | + maker = self._makeOne() |
135 | + size = 10 |
136 | + name = "name" |
137 | + decorated = maker.lrucache(maxsize=size, name=name)(_adder) |
138 | + self.assertEqual(list(maker._cache.keys()), [name]) |
139 | + self.assertEqual(maker._cache[name].size, size) |
140 | + decorated(10) |
141 | + decorated(11) |
142 | + self.assertEqual(len(maker._cache[name].data),2) |
143 | + |
144 | + def test_exception(self): |
145 | + maker = self._makeOne() |
146 | + size = 10 |
147 | + name = "name" |
148 | + decorated = maker.lrucache(maxsize=size, name=name)(_adder) |
149 | + self.assertRaises(KeyError, maker.lrucache, maxsize=size, name=name) |
150 | + self.assertRaises(ValueError, maker.lrucache) |
151 | + |
152 | + def test_defaultvalue_and_clear(self): |
153 | + size = 10 |
154 | + maker = self._makeOne(maxsize=size) |
155 | + for i in range(100): |
156 | + decorated = maker.lrucache()(_adder) |
157 | + decorated(10) |
158 | + |
159 | + self.assertEqual(len(maker._cache) , 100) |
160 | + for _cache in maker._cache.values(): |
161 | + self.assertEqual( _cache.size,size) |
162 | + self.assertEqual(len(_cache.data),1) |
163 | + ## and test clear cache |
164 | + maker.clear() |
165 | + for _cache in maker._cache.values(): |
166 | + self.assertEqual( _cache.size,size) |
167 | + self.assertEqual(len(_cache.data),0) |
168 | + |
169 | + def test_clear_with_single_name(self): |
170 | + maker = self._makeOne(maxsize=10) |
171 | + one = maker.lrucache(name='one')(_adder) |
172 | + two = maker.lrucache(name='two')(_adder) |
173 | + for i in range(100): |
174 | + _ = one(i) |
175 | + _ = two(i) |
176 | + self.assertEqual(len(maker._cache['one'].data), 10) |
177 | + self.assertEqual(len(maker._cache['two'].data), 10) |
178 | + maker.clear('one') |
179 | + self.assertEqual(len(maker._cache['one'].data), 0) |
180 | + self.assertEqual(len(maker._cache['two'].data), 10) |
181 | + |
182 | + def test_clear_with_multiple_names(self): |
183 | + maker = self._makeOne(maxsize=10) |
184 | + one = maker.lrucache(name='one')(_adder) |
185 | + two = maker.lrucache(name='two')(_adder) |
186 | + three = maker.lrucache(name='three')(_adder) |
187 | + for i in range(100): |
188 | + _ = one(i) |
189 | + _ = two(i) |
190 | + _ = three(i) |
191 | + self.assertEqual(len(maker._cache['one'].data), 10) |
192 | + self.assertEqual(len(maker._cache['two'].data), 10) |
193 | + self.assertEqual(len(maker._cache['three'].data), 10) |
194 | + maker.clear('one', 'three') |
195 | + self.assertEqual(len(maker._cache['one'].data), 0) |
196 | + self.assertEqual(len(maker._cache['two'].data), 10) |
197 | + self.assertEqual(len(maker._cache['three'].data), 0) |
198 | + |
199 | + def test_expiring(self): |
200 | + size = 10 |
201 | + timeout = 10 |
202 | + name = "name" |
203 | + cache = self._makeOne(maxsize=size, timeout=timeout) |
204 | + for i in range(100): |
205 | + if not i: |
206 | + decorated = cache.expiring_lrucache(name=name)(_adder) |
207 | + self.assertEqual( cache._cache[name].size,size) |
208 | + else: |
209 | + decorated = cache.expiring_lrucache()(_adder) |
210 | + decorated(10) |
211 | + |
212 | + self.assertEqual( len(cache._cache) , 100) |
213 | + for _cache in cache._cache.values(): |
214 | + self.assertEqual( _cache.size,size) |
215 | + self.assertEqual( _cache.default_timeout,timeout) |
216 | + self.assertEqual(len(_cache.data),1) |
217 | + ## and test clear cache |
218 | + cache.clear() |
219 | + for _cache in cache._cache.values(): |
220 | + self.assertEqual( _cache.size,size) |
221 | + self.assertEqual(len(_cache.data),0) |
222 | + |
223 | +def _adder(x): |
224 | + return x + 10 |
225 | |
226 | === modified file 'CHANGES.txt' |
227 | --- CHANGES.txt 2012-04-09 10:24:06 +0000 |
228 | +++ CHANGES.txt 2013-06-07 00:36:27 +0000 |
229 | @@ -1,8 +1,29 @@ |
230 | Changelog |
231 | ========= |
232 | |
233 | -After 0.5 |
234 | ---------- |
235 | +0.6 (2012-07-12) |
236 | +---------------- |
237 | + |
238 | +- Added a 'CacheMaker' helper class: a maker keeps references (by name) |
239 | + to the caches it creates, to permit them to be cleared. |
240 | + |
241 | +- Added statistics to each cache, tracking lookups, hits, misses, and |
242 | + evictions. |
243 | + |
244 | +- Automated building Sphinx docs and testing example snippets under ``tox``. |
245 | + |
246 | +- Added Sphinx documentation. |
247 | + |
248 | +- Dropped support for Python 2.5. |
249 | + |
250 | +- Added support for PyPy. |
251 | + |
252 | +- Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies). |
253 | + |
254 | +- Added ``setup.py dev`` alias (runs ``develop`` plus installs ``nose`` |
255 | + and ``coverage``). |
256 | + |
257 | +- Added support for CI under supported Pythons using ``tox``. |
258 | |
259 | - Bug: Remove potential race condition on lock in face of interrupts |
260 | (Issue #10). |
261 | |
262 | === modified file 'CONTRIBUTORS.txt' |
263 | --- CONTRIBUTORS.txt 2011-09-20 11:37:18 +0000 |
264 | +++ CONTRIBUTORS.txt 2013-06-07 00:36:27 +0000 |
265 | @@ -105,3 +105,4 @@ |
266 | |
267 | - Tres Seaver, 2011/02/22 |
268 | - Joel Bohman, 2011/08/16 |
269 | +- Julien Tayon, 2012/07/04 |
270 | |
271 | === modified file 'PKG-INFO' |
272 | --- PKG-INFO 2012-04-09 10:24:06 +0000 |
273 | +++ PKG-INFO 2013-06-07 00:36:27 +0000 |
274 | @@ -1,6 +1,6 @@ |
275 | -Metadata-Version: 1.0 |
276 | +Metadata-Version: 1.1 |
277 | Name: repoze.lru |
278 | -Version: 0.5 |
279 | +Version: 0.6 |
280 | Summary: A tiny LRU cache implementation and decorator |
281 | Home-page: http://www.repoze.org |
282 | Author: Agendaless Consulting |
283 | @@ -14,49 +14,35 @@ |
284 | than keys and values that are used frequently. It works under Python 2.5, |
285 | Python 2.6, Python 2.7, and Python 3.2. |
286 | |
287 | - API |
288 | - --- |
289 | - |
290 | - Creating an LRUCache object:: |
291 | - |
292 | - from repoze.lru import LRUCache |
293 | - cache = LRUCache(100) # 100 max length |
294 | - |
295 | - Retrieving from an LRUCache object:: |
296 | - |
297 | - cache.get('nonexisting', 'foo') # will return 'foo' |
298 | - cache.get('nonexisting') # will return None |
299 | - cache.get('existing') # will return the value for existing |
300 | - |
301 | - Adding to an LRUCache object:: |
302 | - |
303 | - cache.put('key', 'value') # will add the key 'key' with the value 'value' |
304 | - |
305 | - Clearing an LRUCache:: |
306 | - |
307 | - cache.clear() |
308 | - |
309 | - Decorator |
310 | - --------- |
311 | - |
312 | - A ``lru_cache`` decorator exists. All values passed to the decorated |
313 | - function must be hashable. It does not support keyword arguments:: |
314 | - |
315 | - from repoze.lru import lru_cache |
316 | - |
317 | - @lru_cache(500) |
318 | - def expensive_function(*arg): |
319 | - pass |
320 | - |
321 | - Each function decorated with the lru_cache decorator uses its own |
322 | - cache related to that function. |
323 | + Please see ``docs/index.rst`` for detailed documentation. |
324 | |
325 | |
326 | Changelog |
327 | ========= |
328 | |
329 | - After 0.5 |
330 | - --------- |
331 | + 0.6 (2012-07-12) |
332 | + ---------------- |
333 | + |
334 | + - Added a 'CacheMaker' helper class: a maker keeps references (by name) |
335 | + to the caches it creates, to permit them to be cleared. |
336 | + |
337 | + - Added statistics to each cache, tracking lookups, hits, misses, and |
338 | + evictions. |
339 | + |
340 | + - Automated building Sphinx docs and testing example snippets under ``tox``. |
341 | + |
342 | + - Added Sphinx documentation. |
343 | + |
344 | + - Dropped support for Python 2.5. |
345 | + |
346 | + - Added support for PyPy. |
347 | + |
348 | + - Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies). |
349 | + |
350 | + - Added ``setup.py dev`` alias (runs ``develop`` plus installs ``nose`` |
351 | + and ``coverage``). |
352 | + |
353 | + - Added support for CI under supported Pythons using ``tox``. |
354 | |
355 | - Bug: Remove potential race condition on lock in face of interrupts |
356 | (Issue #10). |
357 | @@ -108,7 +94,6 @@ |
358 | Platform: UNKNOWN |
359 | Classifier: Intended Audience :: Developers |
360 | Classifier: Programming Language :: Python |
361 | -Classifier: Programming Language :: Python :: 2.5 |
362 | Classifier: Programming Language :: Python :: 2.6 |
363 | Classifier: Programming Language :: Python :: 2.7 |
364 | Classifier: Programming Language :: Python :: 3 |
365 | |
366 | === modified file 'README.txt' |
367 | --- README.txt 2011-09-20 11:37:18 +0000 |
368 | +++ README.txt 2013-06-07 00:36:27 +0000 |
369 | @@ -6,39 +6,4 @@ |
370 | than keys and values that are used frequently. It works under Python 2.5, |
371 | Python 2.6, Python 2.7, and Python 3.2. |
372 | |
373 | -API |
374 | ---- |
375 | - |
376 | -Creating an LRUCache object:: |
377 | - |
378 | - from repoze.lru import LRUCache |
379 | - cache = LRUCache(100) # 100 max length |
380 | - |
381 | -Retrieving from an LRUCache object:: |
382 | - |
383 | - cache.get('nonexisting', 'foo') # will return 'foo' |
384 | - cache.get('nonexisting') # will return None |
385 | - cache.get('existing') # will return the value for existing |
386 | - |
387 | -Adding to an LRUCache object:: |
388 | - |
389 | - cache.put('key', 'value') # will add the key 'key' with the value 'value' |
390 | - |
391 | -Clearing an LRUCache:: |
392 | - |
393 | - cache.clear() |
394 | - |
395 | -Decorator |
396 | ---------- |
397 | - |
398 | -A ``lru_cache`` decorator exists. All values passed to the decorated |
399 | -function must be hashable. It does not support keyword arguments:: |
400 | - |
401 | - from repoze.lru import lru_cache |
402 | - |
403 | - @lru_cache(500) |
404 | - def expensive_function(*arg): |
405 | - pass |
406 | - |
407 | -Each function decorated with the lru_cache decorator uses its own |
408 | -cache related to that function. |
409 | +Please see ``docs/index.rst`` for detailed documentation. |
410 | |
411 | === modified file 'debian/changelog' |
412 | --- debian/changelog 2013-03-09 13:55:57 +0000 |
413 | +++ debian/changelog 2013-06-07 00:36:27 +0000 |
414 | @@ -1,7 +1,25 @@ |
415 | +python-repoze.lru (0.6-1ubuntu1) saucy; urgency=low |
416 | + |
417 | + * Merge from Debian unstable. Remaining changes: |
418 | + - debian/rules: Run test during build. |
419 | + - debian/patches/fix-lp-tests.patch: Enable test during build. |
420 | + |
421 | + -- Logan Rosen <logan@ubuntu.com> Thu, 06 Jun 2013 20:24:23 -0400 |
422 | + |
423 | +python-repoze.lru (0.6-1) unstable; urgency=low |
424 | + |
425 | + [ Jakub Wilk ] |
426 | + * Use canonical URIs for Vcs-* fields. |
427 | + |
428 | + [ TANIGUCHI Takaki ] |
429 | + * New upstream release |
430 | + |
431 | + -- TANIGUCHI Takaki <takaki@debian.org> Wed, 08 May 2013 21:01:13 +0900 |
432 | + |
433 | python-repoze.lru (0.5-2ubuntu1) raring; urgency=low |
434 | |
435 | * Merge from Debian unstable. Remaining changes: |
436 | - - debian/rules: Run test duing build. |
437 | + - debian/rules: Run test during build. |
438 | - debian/patches/fix-lp-tests.patch: Enable test during build. |
439 | |
440 | -- Logan Rosen <logan@ubuntu.com> Sat, 09 Mar 2013 13:55:57 -0500 |
441 | |
442 | === modified file 'debian/control' |
443 | --- debian/control 2012-05-17 14:04:22 +0000 |
444 | +++ debian/control 2013-06-07 00:36:27 +0000 |
445 | @@ -7,8 +7,8 @@ |
446 | Build-Depends: debhelper (>= 7.0.50~), python-setuptools, python-all |
447 | Standards-Version: 3.9.3 |
448 | Homepage: http://www.repoze.org/ |
449 | -Vcs-Svn: svn://svn.debian.org/python-modules/packages/python-repoze.lru/trunk/ |
450 | -Vcs-Browser: http://svn.debian.org/viewsvn/python-modules/packages/python-repoze.lru/trunk/ |
451 | +Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/python-repoze.lru/trunk/ |
452 | +Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/python-repoze.lru/trunk/ |
453 | |
454 | Package: python-repoze.lru |
455 | Architecture: all |
456 | |
457 | === modified file 'debian/patches/fix-lp-tests.patch' |
458 | --- debian/patches/fix-lp-tests.patch 2012-05-24 12:29:59 +0000 |
459 | +++ debian/patches/fix-lp-tests.patch 2013-06-07 00:36:27 +0000 |
460 | @@ -1,7 +1,6 @@ |
461 | -diff -Naurp repoze.lru-0.5.orig/repoze/lru/tests.py repoze.lru-0.5/repoze/lru/tests.py |
462 | ---- repoze.lru-0.5.orig/repoze/lru/tests.py 2012-03-24 13:38:58.000000000 -0400 |
463 | -+++ repoze.lru-0.5/repoze/lru/tests.py 2012-05-24 12:28:34.287214437 -0400 |
464 | -@@ -391,7 +391,7 @@ class ExpiringLRUCacheTests(LRUCacheTest |
465 | +--- a/repoze/lru/tests.py |
466 | ++++ b/repoze/lru/tests.py |
467 | +@@ -425,7 +425,7 @@ |
468 | |
469 | time.sleep(0.1) |
470 | cache.put("FOO", "BAR") |
471 | @@ -10,7 +9,7 @@ |
472 | self.assertEqual(cache.get("FOO"), "BAR") |
473 | self.check_cache_is_consistent(cache) |
474 | |
475 | -@@ -410,21 +410,21 @@ class ExpiringLRUCacheTests(LRUCacheTest |
476 | +@@ -444,21 +444,21 @@ |
477 | |
478 | # Entry "one" must expire, "two"/"three" remain valid |
479 | time.sleep(0.1) |
480 | @@ -42,7 +41,7 @@ |
481 | |
482 | self.check_cache_is_consistent(cache) |
483 | |
484 | -@@ -450,10 +450,10 @@ class ExpiringLRUCacheTests(LRUCacheTest |
485 | +@@ -484,10 +484,10 @@ |
486 | |
487 | time.sleep(0.1) |
488 | # "foo2" must have expired |
489 | @@ -55,9 +54,9 @@ |
490 | + #self.assertEqual(cache.get("foo3"), "bar3") |
491 | + #self.check_cache_is_consistent(cache) |
492 | |
493 | + |
494 | class DecoratorTests(unittest.TestCase): |
495 | - def _getTargetClass(self): |
496 | -@@ -508,23 +508,23 @@ class DecoratorTests(unittest.TestCase): |
497 | +@@ -544,23 +544,23 @@ |
498 | start = time.time() |
499 | result1 = sleep_a_bit("hello") |
500 | stop = time.time() |
501 | @@ -85,5 +84,5 @@ |
502 | + #self.assertEqual(result3, 2 * "hello") |
503 | + #self.assertTrue(stop - start > 0.1) |
504 | |
505 | + |
506 | class DummyLRUCache(dict): |
507 | - def put(self, k, v): |
508 | |
509 | === added directory 'docs' |
510 | === added file 'docs/Makefile' |
511 | --- docs/Makefile 1970-01-01 00:00:00 +0000 |
512 | +++ docs/Makefile 2013-06-07 00:36:27 +0000 |
513 | @@ -0,0 +1,153 @@ |
514 | +# Makefile for Sphinx documentation |
515 | +# |
516 | + |
517 | +# You can set these variables from the command line. |
518 | +SPHINXOPTS = |
519 | +SPHINXBUILD = sphinx-build |
520 | +PAPER = |
521 | +BUILDDIR = _build |
522 | + |
523 | +# Internal variables. |
524 | +PAPEROPT_a4 = -D latex_paper_size=a4 |
525 | +PAPEROPT_letter = -D latex_paper_size=letter |
526 | +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . |
527 | +# the i18n builder cannot share the environment and doctrees with the others |
528 | +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . |
529 | + |
530 | +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext |
531 | + |
532 | +help: |
533 | + @echo "Please use \`make <target>' where <target> is one of" |
534 | + @echo " html to make standalone HTML files" |
535 | + @echo " dirhtml to make HTML files named index.html in directories" |
536 | + @echo " singlehtml to make a single large HTML file" |
537 | + @echo " pickle to make pickle files" |
538 | + @echo " json to make JSON files" |
539 | + @echo " htmlhelp to make HTML files and a HTML help project" |
540 | + @echo " qthelp to make HTML files and a qthelp project" |
541 | + @echo " devhelp to make HTML files and a Devhelp project" |
542 | + @echo " epub to make an epub" |
543 | + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" |
544 | + @echo " latexpdf to make LaTeX files and run them through pdflatex" |
545 | + @echo " text to make text files" |
546 | + @echo " man to make manual pages" |
547 | + @echo " texinfo to make Texinfo files" |
548 | + @echo " info to make Texinfo files and run them through makeinfo" |
549 | + @echo " gettext to make PO message catalogs" |
550 | + @echo " changes to make an overview of all changed/added/deprecated items" |
551 | + @echo " linkcheck to check all external links for integrity" |
552 | + @echo " doctest to run all doctests embedded in the documentation (if enabled)" |
553 | + |
554 | +clean: |
555 | + -rm -rf $(BUILDDIR)/* |
556 | + |
557 | +html: |
558 | + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html |
559 | + @echo |
560 | + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." |
561 | + |
562 | +dirhtml: |
563 | + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml |
564 | + @echo |
565 | + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." |
566 | + |
567 | +singlehtml: |
568 | + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml |
569 | + @echo |
570 | + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." |
571 | + |
572 | +pickle: |
573 | + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle |
574 | + @echo |
575 | + @echo "Build finished; now you can process the pickle files." |
576 | + |
577 | +json: |
578 | + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json |
579 | + @echo |
580 | + @echo "Build finished; now you can process the JSON files." |
581 | + |
582 | +htmlhelp: |
583 | + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp |
584 | + @echo |
585 | + @echo "Build finished; now you can run HTML Help Workshop with the" \ |
586 | + ".hhp project file in $(BUILDDIR)/htmlhelp." |
587 | + |
588 | +qthelp: |
589 | + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp |
590 | + @echo |
591 | + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ |
592 | + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" |
593 | + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/repozelru.qhcp" |
594 | + @echo "To view the help file:" |
595 | + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/repozelru.qhc" |
596 | + |
597 | +devhelp: |
598 | + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp |
599 | + @echo |
600 | + @echo "Build finished." |
601 | + @echo "To view the help file:" |
602 | + @echo "# mkdir -p $$HOME/.local/share/devhelp/repozelru" |
603 | + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/repozelru" |
604 | + @echo "# devhelp" |
605 | + |
606 | +epub: |
607 | + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub |
608 | + @echo |
609 | + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." |
610 | + |
611 | +latex: |
612 | + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex |
613 | + @echo |
614 | + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." |
615 | + @echo "Run \`make' in that directory to run these through (pdf)latex" \ |
616 | + "(use \`make latexpdf' here to do that automatically)." |
617 | + |
618 | +latexpdf: |
619 | + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex |
620 | + @echo "Running LaTeX files through pdflatex..." |
621 | + $(MAKE) -C $(BUILDDIR)/latex all-pdf |
622 | + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." |
623 | + |
624 | +text: |
625 | + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text |
626 | + @echo |
627 | + @echo "Build finished. The text files are in $(BUILDDIR)/text." |
628 | + |
629 | +man: |
630 | + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man |
631 | + @echo |
632 | + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." |
633 | + |
634 | +texinfo: |
635 | + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo |
636 | + @echo |
637 | + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." |
638 | + @echo "Run \`make' in that directory to run these through makeinfo" \ |
639 | + "(use \`make info' here to do that automatically)." |
640 | + |
641 | +info: |
642 | + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo |
643 | + @echo "Running Texinfo files through makeinfo..." |
644 | + make -C $(BUILDDIR)/texinfo info |
645 | + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." |
646 | + |
647 | +gettext: |
648 | + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale |
649 | + @echo |
650 | + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." |
651 | + |
652 | +changes: |
653 | + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes |
654 | + @echo |
655 | + @echo "The overview file is in $(BUILDDIR)/changes." |
656 | + |
657 | +linkcheck: |
658 | + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck |
659 | + @echo |
660 | + @echo "Link check complete; look for any errors in the above output " \ |
661 | + "or in $(BUILDDIR)/linkcheck/output.txt." |
662 | + |
663 | +doctest: |
664 | + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest |
665 | + @echo "Testing of doctests in the sources finished, look at the " \ |
666 | + "results in $(BUILDDIR)/doctest/output.txt." |
667 | |
668 | === added directory 'docs/_static' |
669 | === added file 'docs/_static/placeholder.txt' |
670 | === added directory 'docs/_templates' |
671 | === added file 'docs/_templates/placeholder.txt' |
672 | === added file 'docs/api.rst' |
673 | --- docs/api.rst 1970-01-01 00:00:00 +0000 |
674 | +++ docs/api.rst 2013-06-07 00:36:27 +0000 |
675 | @@ -0,0 +1,23 @@ |
676 | +:mod:`repoze.lru` API |
677 | +===================== |
678 | + |
679 | +Module: :mod:`repoze.lru` |
680 | +-------------------------- |
681 | + |
682 | +.. automodule:: repoze.lru |
683 | + |
684 | + .. autoclass:: LRUCache |
685 | + :members: |
686 | + :member-order: bysource |
687 | + |
688 | + .. autoclass:: ExpiringLRUCache |
689 | + :members: |
690 | + :member-order: bysource |
691 | + |
692 | + .. autoclass:: lru_cache |
693 | + :members: |
694 | + :member-order: bysource |
695 | + |
696 | + .. autoclass:: CacheMaker |
697 | + :members: |
698 | + :member-order: bysource |
699 | |
700 | === added file 'docs/conf.py' |
701 | --- docs/conf.py 1970-01-01 00:00:00 +0000 |
702 | +++ docs/conf.py 2013-06-07 00:36:27 +0000 |
703 | @@ -0,0 +1,242 @@ |
704 | +# -*- coding: utf-8 -*- |
705 | +# |
706 | +# repoze.lru documentation build configuration file, created by |
707 | +# sphinx-quickstart on Mon Jun 11 16:50:52 2012. |
708 | +# |
709 | +# This file is execfile()d with the current directory set to its containing dir. |
710 | +# |
711 | +# Note that not all possible configuration values are present in this |
712 | +# autogenerated file. |
713 | +# |
714 | +# All configuration values have a default; values that are commented out |
715 | +# serve to show the default. |
716 | + |
717 | +import sys, os |
718 | + |
719 | +# If extensions (or modules to document with autodoc) are in another directory, |
720 | +# add these directories to sys.path here. If the directory is relative to the |
721 | +# documentation root, use os.path.abspath to make it absolute, like shown here. |
722 | +#sys.path.insert(0, os.path.abspath('.')) |
723 | + |
724 | +# -- General configuration ----------------------------------------------------- |
725 | + |
726 | +# If your documentation needs a minimal Sphinx version, state it here. |
727 | +#needs_sphinx = '1.0' |
728 | + |
729 | +# Add any Sphinx extension module names here, as strings. They can be extensions |
730 | +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. |
731 | +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode'] |
732 | + |
733 | +# Add any paths that contain templates here, relative to this directory. |
734 | +templates_path = ['_templates'] |
735 | + |
736 | +# The suffix of source filenames. |
737 | +source_suffix = '.rst' |
738 | + |
739 | +# The encoding of source files. |
740 | +#source_encoding = 'utf-8-sig' |
741 | + |
742 | +# The master toctree document. |
743 | +master_doc = 'index' |
744 | + |
745 | +# General information about the project. |
746 | +project = u'repoze.lru' |
747 | +copyright = u'2012, Repoze contributors' |
748 | + |
749 | +# The version info for the project you're documenting, acts as replacement for |
750 | +# |version| and |release|, also used in various other places throughout the |
751 | +# built documents. |
752 | +# |
753 | +# The short X.Y version. |
754 | +version = '0.6' |
755 | +# The full version, including alpha/beta/rc tags. |
756 | +release = '0.6' |
757 | + |
758 | +# The language for content autogenerated by Sphinx. Refer to documentation |
759 | +# for a list of supported languages. |
760 | +#language = None |
761 | + |
762 | +# There are two options for replacing |today|: either, you set today to some |
763 | +# non-false value, then it is used: |
764 | +#today = '' |
765 | +# Else, today_fmt is used as the format for a strftime call. |
766 | +#today_fmt = '%B %d, %Y' |
767 | + |
768 | +# List of patterns, relative to source directory, that match files and |
769 | +# directories to ignore when looking for source files. |
770 | +exclude_patterns = ['_build'] |
771 | + |
772 | +# The reST default role (used for this markup: `text`) to use for all documents. |
773 | +#default_role = None |
774 | + |
775 | +# If true, '()' will be appended to :func: etc. cross-reference text. |
776 | +#add_function_parentheses = True |
777 | + |
778 | +# If true, the current module name will be prepended to all description |
779 | +# unit titles (such as .. function::). |
780 | +#add_module_names = True |
781 | + |
782 | +# If true, sectionauthor and moduleauthor directives will be shown in the |
783 | +# output. They are ignored by default. |
784 | +#show_authors = False |
785 | + |
786 | +# The name of the Pygments (syntax highlighting) style to use. |
787 | +pygments_style = 'sphinx' |
788 | + |
789 | +# A list of ignored prefixes for module index sorting. |
790 | +#modindex_common_prefix = [] |
791 | + |
792 | + |
793 | +# -- Options for HTML output --------------------------------------------------- |
794 | + |
795 | +# The theme to use for HTML and HTML Help pages. See the documentation for |
796 | +# a list of builtin themes. |
797 | +html_theme = 'default' |
798 | + |
799 | +# Theme options are theme-specific and customize the look and feel of a theme |
800 | +# further. For a list of options available for each theme, see the |
801 | +# documentation. |
802 | +#html_theme_options = {} |
803 | + |
804 | +# Add any paths that contain custom themes here, relative to this directory. |
805 | +#html_theme_path = [] |
806 | + |
807 | +# The name for this set of Sphinx documents. If None, it defaults to |
808 | +# "<project> v<release> documentation". |
809 | +#html_title = None |
810 | + |
811 | +# A shorter title for the navigation bar. Default is the same as html_title. |
812 | +#html_short_title = None |
813 | + |
814 | +# The name of an image file (relative to this directory) to place at the top |
815 | +# of the sidebar. |
816 | +#html_logo = None |
817 | + |
818 | +# The name of an image file (within the static path) to use as favicon of the |
819 | +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 |
820 | +# pixels large. |
821 | +#html_favicon = None |
822 | + |
823 | +# Add any paths that contain custom static files (such as style sheets) here, |
824 | +# relative to this directory. They are copied after the builtin static files, |
825 | +# so a file named "default.css" will overwrite the builtin "default.css". |
826 | +html_static_path = ['_static'] |
827 | + |
828 | +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, |
829 | +# using the given strftime format. |
830 | +#html_last_updated_fmt = '%b %d, %Y' |
831 | + |
832 | +# If true, SmartyPants will be used to convert quotes and dashes to |
833 | +# typographically correct entities. |
834 | +#html_use_smartypants = True |
835 | + |
836 | +# Custom sidebar templates, maps document names to template names. |
837 | +#html_sidebars = {} |
838 | + |
839 | +# Additional templates that should be rendered to pages, maps page names to |
840 | +# template names. |
841 | +#html_additional_pages = {} |
842 | + |
843 | +# If false, no module index is generated. |
844 | +#html_domain_indices = True |
845 | + |
846 | +# If false, no index is generated. |
847 | +#html_use_index = True |
848 | + |
849 | +# If true, the index is split into individual pages for each letter. |
850 | +#html_split_index = False |
851 | + |
852 | +# If true, links to the reST sources are added to the pages. |
853 | +#html_show_sourcelink = True |
854 | + |
855 | +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. |
856 | +#html_show_sphinx = True |
857 | + |
858 | +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. |
859 | +#html_show_copyright = True |
860 | + |
861 | +# If true, an OpenSearch description file will be output, and all pages will |
862 | +# contain a <link> tag referring to it. The value of this option must be the |
863 | +# base URL from which the finished HTML is served. |
864 | +#html_use_opensearch = '' |
865 | + |
866 | +# This is the file name suffix for HTML files (e.g. ".xhtml"). |
867 | +#html_file_suffix = None |
868 | + |
869 | +# Output file base name for HTML help builder. |
870 | +htmlhelp_basename = 'repozelrudoc' |
871 | + |
872 | + |
873 | +# -- Options for LaTeX output -------------------------------------------------- |
874 | + |
875 | +latex_elements = { |
876 | +# The paper size ('letterpaper' or 'a4paper'). |
877 | +#'papersize': 'letterpaper', |
878 | + |
879 | +# The font size ('10pt', '11pt' or '12pt'). |
880 | +#'pointsize': '10pt', |
881 | + |
882 | +# Additional stuff for the LaTeX preamble. |
883 | +#'preamble': '', |
884 | +} |
885 | + |
886 | +# Grouping the document tree into LaTeX files. List of tuples |
887 | +# (source start file, target name, title, author, documentclass [howto/manual]). |
888 | +latex_documents = [ |
889 | + ('index', 'repozelru.tex', u'repoze.lru Documentation', |
890 | + u'Repoze contributors', 'manual'), |
891 | +] |
892 | + |
893 | +# The name of an image file (relative to this directory) to place at the top of |
894 | +# the title page. |
895 | +#latex_logo = None |
896 | + |
897 | +# For "manual" documents, if this is true, then toplevel headings are parts, |
898 | +# not chapters. |
899 | +#latex_use_parts = False |
900 | + |
901 | +# If true, show page references after internal links. |
902 | +#latex_show_pagerefs = False |
903 | + |
904 | +# If true, show URL addresses after external links. |
905 | +#latex_show_urls = False |
906 | + |
907 | +# Documents to append as an appendix to all manuals. |
908 | +#latex_appendices = [] |
909 | + |
910 | +# If false, no module index is generated. |
911 | +#latex_domain_indices = True |
912 | + |
913 | + |
914 | +# -- Options for manual page output -------------------------------------------- |
915 | + |
916 | +# One entry per manual page. List of tuples |
917 | +# (source start file, name, description, authors, manual section). |
918 | +man_pages = [ |
919 | + ('index', 'repozelru', u'repoze.lru Documentation', |
920 | + [u'Repoze contributors'], 1) |
921 | +] |
922 | + |
923 | +# If true, show URL addresses after external links. |
924 | +#man_show_urls = False |
925 | + |
926 | + |
927 | +# -- Options for Texinfo output ------------------------------------------------ |
928 | + |
929 | +# Grouping the document tree into Texinfo files. List of tuples |
930 | +# (source start file, target name, title, author, |
931 | +# dir menu entry, description, category) |
932 | +texinfo_documents = [ |
933 | + ('index', 'repozelru', u'repoze.lru Documentation', |
934 | + u'Repoze contributors', 'repozelru', 'One line description of project.', |
935 | + 'Miscellaneous'), |
936 | +] |
937 | + |
938 | +# Documents to append as an appendix to all manuals. |
939 | +#texinfo_appendices = [] |
940 | + |
941 | +# If false, no module index is generated. |
942 | +#texinfo_domain_indices = True |
943 | + |
944 | +# How to display URL addresses: 'footnote', 'no', or 'inline'. |
945 | +#texinfo_show_urls = 'footnote' |
946 | |
947 | === added file 'docs/index.rst' |
948 | --- docs/index.rst 1970-01-01 00:00:00 +0000 |
949 | +++ docs/index.rst 2013-06-07 00:36:27 +0000 |
950 | @@ -0,0 +1,19 @@ |
951 | +:mod:`repoze.lru` |
952 | +================= |
953 | + |
954 | +Contents: |
955 | + |
956 | +.. toctree:: |
957 | + :maxdepth: 2 |
958 | + |
959 | + narr |
960 | + api |
961 | + |
962 | + |
963 | +Indices and tables |
964 | +================== |
965 | + |
966 | +* :ref:`genindex` |
967 | +* :ref:`modindex` |
968 | +* :ref:`search` |
969 | + |
970 | |
971 | === added file 'docs/make.bat' |
972 | --- docs/make.bat 1970-01-01 00:00:00 +0000 |
973 | +++ docs/make.bat 2013-06-07 00:36:27 +0000 |
974 | @@ -0,0 +1,190 @@ |
975 | +@ECHO OFF |
976 | + |
977 | +REM Command file for Sphinx documentation |
978 | + |
979 | +if "%SPHINXBUILD%" == "" ( |
980 | + set SPHINXBUILD=sphinx-build |
981 | +) |
982 | +set BUILDDIR=_build |
983 | +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . |
984 | +set I18NSPHINXOPTS=%SPHINXOPTS% . |
985 | +if NOT "%PAPER%" == "" ( |
986 | + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% |
987 | + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% |
988 | +) |
989 | + |
990 | +if "%1" == "" goto help |
991 | + |
992 | +if "%1" == "help" ( |
993 | + :help |
994 | + echo.Please use `make ^<target^>` where ^<target^> is one of |
995 | + echo. html to make standalone HTML files |
996 | + echo. dirhtml to make HTML files named index.html in directories |
997 | + echo. singlehtml to make a single large HTML file |
998 | + echo. pickle to make pickle files |
999 | + echo. json to make JSON files |
1000 | + echo. htmlhelp to make HTML files and a HTML help project |
1001 | + echo. qthelp to make HTML files and a qthelp project |
1002 | + echo. devhelp to make HTML files and a Devhelp project |
1003 | + echo. epub to make an epub |
1004 | + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter |
1005 | + echo. text to make text files |
1006 | + echo. man to make manual pages |
1007 | + echo. texinfo to make Texinfo files |
1008 | + echo. gettext to make PO message catalogs |
1009 | + echo. changes to make an overview over all changed/added/deprecated items |
1010 | + echo. linkcheck to check all external links for integrity |
1011 | + echo. doctest to run all doctests embedded in the documentation if enabled |
1012 | + goto end |
1013 | +) |
1014 | + |
1015 | +if "%1" == "clean" ( |
1016 | + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i |
1017 | + del /q /s %BUILDDIR%\* |
1018 | + goto end |
1019 | +) |
1020 | + |
1021 | +if "%1" == "html" ( |
1022 | + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html |
1023 | + if errorlevel 1 exit /b 1 |
1024 | + echo. |
1025 | + echo.Build finished. The HTML pages are in %BUILDDIR%/html. |
1026 | + goto end |
1027 | +) |
1028 | + |
1029 | +if "%1" == "dirhtml" ( |
1030 | + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml |
1031 | + if errorlevel 1 exit /b 1 |
1032 | + echo. |
1033 | + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. |
1034 | + goto end |
1035 | +) |
1036 | + |
1037 | +if "%1" == "singlehtml" ( |
1038 | + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml |
1039 | + if errorlevel 1 exit /b 1 |
1040 | + echo. |
1041 | + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. |
1042 | + goto end |
1043 | +) |
1044 | + |
1045 | +if "%1" == "pickle" ( |
1046 | + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle |
1047 | + if errorlevel 1 exit /b 1 |
1048 | + echo. |
1049 | + echo.Build finished; now you can process the pickle files. |
1050 | + goto end |
1051 | +) |
1052 | + |
1053 | +if "%1" == "json" ( |
1054 | + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json |
1055 | + if errorlevel 1 exit /b 1 |
1056 | + echo. |
1057 | + echo.Build finished; now you can process the JSON files. |
1058 | + goto end |
1059 | +) |
1060 | + |
1061 | +if "%1" == "htmlhelp" ( |
1062 | + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp |
1063 | + if errorlevel 1 exit /b 1 |
1064 | + echo. |
1065 | + echo.Build finished; now you can run HTML Help Workshop with the ^ |
1066 | +.hhp project file in %BUILDDIR%/htmlhelp. |
1067 | + goto end |
1068 | +) |
1069 | + |
1070 | +if "%1" == "qthelp" ( |
1071 | + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp |
1072 | + if errorlevel 1 exit /b 1 |
1073 | + echo. |
1074 | + echo.Build finished; now you can run "qcollectiongenerator" with the ^ |
1075 | +.qhcp project file in %BUILDDIR%/qthelp, like this: |
1076 | + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\repozelru.qhcp |
1077 | + echo.To view the help file: |
1078 | + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\repozelru.ghc |
1079 | + goto end |
1080 | +) |
1081 | + |
1082 | +if "%1" == "devhelp" ( |
1083 | + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp |
1084 | + if errorlevel 1 exit /b 1 |
1085 | + echo. |
1086 | + echo.Build finished. |
1087 | + goto end |
1088 | +) |
1089 | + |
1090 | +if "%1" == "epub" ( |
1091 | + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub |
1092 | + if errorlevel 1 exit /b 1 |
1093 | + echo. |
1094 | + echo.Build finished. The epub file is in %BUILDDIR%/epub. |
1095 | + goto end |
1096 | +) |
1097 | + |
1098 | +if "%1" == "latex" ( |
1099 | + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex |
1100 | + if errorlevel 1 exit /b 1 |
1101 | + echo. |
1102 | + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. |
1103 | + goto end |
1104 | +) |
1105 | + |
1106 | +if "%1" == "text" ( |
1107 | + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text |
1108 | + if errorlevel 1 exit /b 1 |
1109 | + echo. |
1110 | + echo.Build finished. The text files are in %BUILDDIR%/text. |
1111 | + goto end |
1112 | +) |
1113 | + |
1114 | +if "%1" == "man" ( |
1115 | + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man |
1116 | + if errorlevel 1 exit /b 1 |
1117 | + echo. |
1118 | + echo.Build finished. The manual pages are in %BUILDDIR%/man. |
1119 | + goto end |
1120 | +) |
1121 | + |
1122 | +if "%1" == "texinfo" ( |
1123 | + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo |
1124 | + if errorlevel 1 exit /b 1 |
1125 | + echo. |
1126 | + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. |
1127 | + goto end |
1128 | +) |
1129 | + |
1130 | +if "%1" == "gettext" ( |
1131 | + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale |
1132 | + if errorlevel 1 exit /b 1 |
1133 | + echo. |
1134 | + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. |
1135 | + goto end |
1136 | +) |
1137 | + |
1138 | +if "%1" == "changes" ( |
1139 | + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes |
1140 | + if errorlevel 1 exit /b 1 |
1141 | + echo. |
1142 | + echo.The overview file is in %BUILDDIR%/changes. |
1143 | + goto end |
1144 | +) |
1145 | + |
1146 | +if "%1" == "linkcheck" ( |
1147 | + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck |
1148 | + if errorlevel 1 exit /b 1 |
1149 | + echo. |
1150 | + echo.Link check complete; look for any errors in the above output ^ |
1151 | +or in %BUILDDIR%/linkcheck/output.txt. |
1152 | + goto end |
1153 | +) |
1154 | + |
1155 | +if "%1" == "doctest" ( |
1156 | + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest |
1157 | + if errorlevel 1 exit /b 1 |
1158 | + echo. |
1159 | + echo.Testing of doctests in the sources finished, look at the ^ |
1160 | +results in %BUILDDIR%/doctest/output.txt. |
1161 | + goto end |
1162 | +) |
1163 | + |
1164 | +:end |
1165 | |
1166 | === added file 'docs/narr.rst' |
1167 | --- docs/narr.rst 1970-01-01 00:00:00 +0000 |
1168 | +++ docs/narr.rst 2013-06-07 00:36:27 +0000 |
1169 | @@ -0,0 +1,95 @@ |
1170 | +Using :mod:`repoze.lru` |
1171 | +====================== |
1172 | + |
1173 | +``repoze.lru`` is a LRU (least recently used) cache implementation. Keys and |
1174 | +values that are not used frequently will be evicted from the cache faster |
1175 | +than keys and values that are used frequently. It works under Python 2.5, |
1176 | +Python 2.6, Python 2.7, and Python 3.2. |
1177 | + |
1178 | +Using the API programmatically |
1179 | +------------------------------ |
1180 | + |
1181 | +Creating an LRUCache object: |
1182 | + |
1183 | +.. doctest:: |
1184 | + |
1185 | + >>> from repoze.lru import LRUCache |
1186 | + >>> cache = LRUCache(100) # 100 max length |
1187 | + |
1188 | +Retrieving from an LRUCache object: |
1189 | + |
1190 | +.. doctest:: |
1191 | + |
1192 | + >>> cache.get('nonexisting', 'foo') # return 'foo' |
1193 | + 'foo' |
1194 | + >>> cache.get('nonexisting') is None |
1195 | + True |
1196 | + |
1197 | +Adding to an LRUCache object: |
1198 | + |
1199 | +.. doctest:: |
1200 | + |
1201 | + >>> cache.put('existing', 'value') # add the key 'key' with the value 'value' |
1202 | + >>> cache.get('existing') # return the value for existing |
1203 | + 'value' |
1204 | + |
1205 | +Clearing an LRUCache: |
1206 | + |
1207 | +.. doctest:: |
1208 | + |
1209 | + >>> cache.clear() |
1210 | + |
1211 | +Each LRU cache tracks some basic statistics via attributes: |
1212 | + |
1213 | + cache.lookups # number of calls to the get method |
1214 | + cache.hits # number of times a call to get found an object |
1215 | + cache.misses # number of times a call to get did not find an object |
1216 | + cahce.evictions # number of times a object was evicted from cache |
1217 | + |
1218 | + |
1219 | +Decorating an "expensive" function call |
1220 | +--------------------------------------- |
1221 | + |
1222 | +:mod:`repoze.lru` provides a class :class:`~repoze.lru.lru_cache`, which |
1223 | +wrapps another callable, caching the results. All values passed to the |
1224 | +decorated function must be hashable. It does not support keyword arguments: |
1225 | + |
1226 | +.. doctest:: |
1227 | + |
1228 | + >>> from repoze.lru import lru_cache |
1229 | + >>> @lru_cache(500) |
1230 | + ... def expensive_function(*arg): #* |
1231 | + ... pass |
1232 | + |
1233 | +Each function decorated with the lru_cache decorator uses its own |
1234 | +cache related to that function. |
1235 | + |
1236 | +Cleaning cache of decorated function |
1237 | +------------------------------------ |
1238 | + |
1239 | +:mod:`repoze.lru` provides a :class:`~repoze.lru.CacheMaker`, which generates |
1240 | +decorators. This way, you can later clear your cache if needed. |
1241 | + |
1242 | +.. doctest:: |
1243 | + |
1244 | + >>> from repoze.lru import CacheMaker |
1245 | + >>> cache_maker=CacheMaker() |
1246 | + >>> @cache_maker.lrucache(maxsize=300, name="adder") |
1247 | + ... def yet_another_exepensive_function(*arg):#* |
1248 | + ... pass |
1249 | + |
1250 | + >>> @cache_maker.expiring_lrucache(maxsize=300,timeout=30) |
1251 | + ... def another_exepensive_function(*arg):#* |
1252 | + ... pass |
1253 | + |
1254 | +This way, when you need it you can choose to either clear all cache: |
1255 | + |
1256 | +.. doctest:: |
1257 | + |
1258 | + >>> cache_maker.clear() |
1259 | + |
1260 | +or clear a specific cache |
1261 | + |
1262 | +.. doctest:: |
1263 | + |
1264 | + >>> cache_maker.clear("adder") |
1265 | |
1266 | === modified file 'repoze.lru.egg-info/PKG-INFO' |
1267 | --- repoze.lru.egg-info/PKG-INFO 2012-04-09 10:24:06 +0000 |
1268 | +++ repoze.lru.egg-info/PKG-INFO 2013-06-07 00:36:27 +0000 |
1269 | @@ -1,6 +1,6 @@ |
1270 | -Metadata-Version: 1.0 |
1271 | +Metadata-Version: 1.1 |
1272 | Name: repoze.lru |
1273 | -Version: 0.5 |
1274 | +Version: 0.6 |
1275 | Summary: A tiny LRU cache implementation and decorator |
1276 | Home-page: http://www.repoze.org |
1277 | Author: Agendaless Consulting |
1278 | @@ -14,49 +14,35 @@ |
1279 | than keys and values that are used frequently. It works under Python 2.5, |
1280 | Python 2.6, Python 2.7, and Python 3.2. |
1281 | |
1282 | - API |
1283 | - --- |
1284 | - |
1285 | - Creating an LRUCache object:: |
1286 | - |
1287 | - from repoze.lru import LRUCache |
1288 | - cache = LRUCache(100) # 100 max length |
1289 | - |
1290 | - Retrieving from an LRUCache object:: |
1291 | - |
1292 | - cache.get('nonexisting', 'foo') # will return 'foo' |
1293 | - cache.get('nonexisting') # will return None |
1294 | - cache.get('existing') # will return the value for existing |
1295 | - |
1296 | - Adding to an LRUCache object:: |
1297 | - |
1298 | - cache.put('key', 'value') # will add the key 'key' with the value 'value' |
1299 | - |
1300 | - Clearing an LRUCache:: |
1301 | - |
1302 | - cache.clear() |
1303 | - |
1304 | - Decorator |
1305 | - --------- |
1306 | - |
1307 | - A ``lru_cache`` decorator exists. All values passed to the decorated |
1308 | - function must be hashable. It does not support keyword arguments:: |
1309 | - |
1310 | - from repoze.lru import lru_cache |
1311 | - |
1312 | - @lru_cache(500) |
1313 | - def expensive_function(*arg): |
1314 | - pass |
1315 | - |
1316 | - Each function decorated with the lru_cache decorator uses its own |
1317 | - cache related to that function. |
1318 | + Please see ``docs/index.rst`` for detailed documentation. |
1319 | |
1320 | |
1321 | Changelog |
1322 | ========= |
1323 | |
1324 | - After 0.5 |
1325 | - --------- |
1326 | + 0.6 (2012-07-12) |
1327 | + ---------------- |
1328 | + |
1329 | + - Added a 'CacheMaker' helper class: a maker keeps references (by name) |
1330 | + to the caches it creates, to permit them to be cleared. |
1331 | + |
1332 | + - Added statistics to each cache, tracking lookups, hits, misses, and |
1333 | + evictions. |
1334 | + |
1335 | + - Automated building Sphinx docs and testing example snippets under ``tox``. |
1336 | + |
1337 | + - Added Sphinx documentation. |
1338 | + |
1339 | + - Dropped support for Python 2.5. |
1340 | + |
1341 | + - Added support for PyPy. |
1342 | + |
1343 | + - Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies). |
1344 | + |
1345 | + - Added ``setup.py dev`` alias (runs ``develop`` plus installs ``nose`` |
1346 | + and ``coverage``). |
1347 | + |
1348 | + - Added support for CI under supported Pythons using ``tox``. |
1349 | |
1350 | - Bug: Remove potential race condition on lock in face of interrupts |
1351 | (Issue #10). |
1352 | @@ -108,7 +94,6 @@ |
1353 | Platform: UNKNOWN |
1354 | Classifier: Intended Audience :: Developers |
1355 | Classifier: Programming Language :: Python |
1356 | -Classifier: Programming Language :: Python :: 2.5 |
1357 | Classifier: Programming Language :: Python :: 2.6 |
1358 | Classifier: Programming Language :: Python :: 2.7 |
1359 | Classifier: Programming Language :: Python :: 3 |
1360 | |
1361 | === modified file 'repoze.lru.egg-info/SOURCES.txt' |
1362 | --- repoze.lru.egg-info/SOURCES.txt 2011-09-20 11:37:18 +0000 |
1363 | +++ repoze.lru.egg-info/SOURCES.txt 2013-06-07 00:36:27 +0000 |
1364 | @@ -7,6 +7,14 @@ |
1365 | setup.cfg |
1366 | setup.py |
1367 | tox.ini |
1368 | +docs/Makefile |
1369 | +docs/api.rst |
1370 | +docs/conf.py |
1371 | +docs/index.rst |
1372 | +docs/make.bat |
1373 | +docs/narr.rst |
1374 | +docs/_static/placeholder.txt |
1375 | +docs/_templates/placeholder.txt |
1376 | repoze/__init__.py |
1377 | repoze.lru.egg-info/PKG-INFO |
1378 | repoze.lru.egg-info/SOURCES.txt |
1379 | @@ -14,6 +22,7 @@ |
1380 | repoze.lru.egg-info/entry_points.txt |
1381 | repoze.lru.egg-info/namespace_packages.txt |
1382 | repoze.lru.egg-info/not-zip-safe |
1383 | +repoze.lru.egg-info/requires.txt |
1384 | repoze.lru.egg-info/top_level.txt |
1385 | repoze/lru/__init__.py |
1386 | repoze/lru/tests.py |
1387 | \ No newline at end of file |
1388 | |
1389 | === added file 'repoze.lru.egg-info/requires.txt' |
1390 | --- repoze.lru.egg-info/requires.txt 1970-01-01 00:00:00 +0000 |
1391 | +++ repoze.lru.egg-info/requires.txt 2013-06-07 00:36:27 +0000 |
1392 | @@ -0,0 +1,8 @@ |
1393 | + |
1394 | + |
1395 | +[docs] |
1396 | +Sphinx |
1397 | + |
1398 | +[testing] |
1399 | +nose |
1400 | +coverage |
1401 | \ No newline at end of file |
1402 | |
1403 | === modified file 'repoze/lru/__init__.py' |
1404 | --- repoze/lru/__init__.py 2012-04-09 10:24:06 +0000 |
1405 | +++ repoze/lru/__init__.py 2013-06-07 00:36:27 +0000 |
1406 | @@ -3,17 +3,15 @@ |
1407 | |
1408 | import threading |
1409 | import time |
1410 | +import uuid |
1411 | |
1412 | -try: |
1413 | - range = xrange |
1414 | -except NameError: # pragma: no cover |
1415 | - pass |
1416 | |
1417 | _MARKER = object() |
1418 | # By default, expire items after 2**60 seconds. This fits into 64 bit |
1419 | # integers and is close enough to "never" for practical purposes. |
1420 | _DEFAULT_TIMEOUT = 2 ** 60 |
1421 | |
1422 | + |
1423 | class LRUCache(object): |
1424 | """ Implements a pseudo-LRU algorithm (CLOCK) |
1425 | |
1426 | @@ -31,6 +29,10 @@ |
1427 | self.clock_keys = None |
1428 | self.clock_refs = None |
1429 | self.data = None |
1430 | + self.evictions = 0 |
1431 | + self.hits = 0 |
1432 | + self.misses = 0 |
1433 | + self.lookups = 0 |
1434 | self.clear() |
1435 | |
1436 | def clear(self): |
1437 | @@ -47,12 +49,19 @@ |
1438 | self.clock_keys = [_MARKER] * size |
1439 | self.clock_refs = [False] * size |
1440 | self.hand = 0 |
1441 | + self.evictions = 0 |
1442 | + self.hits = 0 |
1443 | + self.misses = 0 |
1444 | + self.lookups = 0 |
1445 | |
1446 | def get(self, key, default=None): |
1447 | """Return value for key. If not in cache, return default""" |
1448 | + self.lookups += 1 |
1449 | try: |
1450 | pos, val = self.data[key] |
1451 | + self.hits += 1 |
1452 | except KeyError: |
1453 | + self.misses += 1 |
1454 | return default |
1455 | self.clock_refs[pos] = True |
1456 | return val |
1457 | @@ -98,7 +107,9 @@ |
1458 | # Maybe oldkey was not in self.data to begin with. If it |
1459 | # was, self.invalidate() in another thread might have |
1460 | # already removed it. del() would raise KeyError, so pop(). |
1461 | - data.pop(oldkey, None) |
1462 | + oldentry = data.pop(oldkey, _MARKER) |
1463 | + if oldentry is not _MARKER: |
1464 | + self.evictions += 1 |
1465 | clock_keys[hand] = key |
1466 | clock_refs[hand] = True |
1467 | data[key] = (hand, val) |
1468 | @@ -137,6 +148,10 @@ |
1469 | self.clock_keys = None |
1470 | self.clock_refs = None |
1471 | self.data = None |
1472 | + self.evictions = 0 |
1473 | + self.hits = 0 |
1474 | + self.misses = 0 |
1475 | + self.lookups = 0 |
1476 | self.clear() |
1477 | |
1478 | def clear(self): |
1479 | @@ -154,20 +169,28 @@ |
1480 | self.clock_keys = [_MARKER] * size |
1481 | self.clock_refs = [False] * size |
1482 | self.hand = 0 |
1483 | + self.evictions = 0 |
1484 | + self.hits = 0 |
1485 | + self.misses = 0 |
1486 | + self.lookups = 0 |
1487 | |
1488 | def get(self, key, default=None): |
1489 | """Return value for key. If not in cache or expired, return default""" |
1490 | + self.lookups += 1 |
1491 | try: |
1492 | pos, val, expires = self.data[key] |
1493 | except KeyError: |
1494 | + self.misses += 1 |
1495 | return default |
1496 | if expires > time.time(): |
1497 | # cache entry still valid |
1498 | + self.hits += 1 |
1499 | self.clock_refs[pos] = True |
1500 | return val |
1501 | else: |
1502 | # cache entry has expired. Make sure the space in the cache can |
1503 | # be recycled soon. |
1504 | + self.misses += 1 |
1505 | self.clock_refs[pos] = False |
1506 | return default |
1507 | |
1508 | @@ -218,7 +241,9 @@ |
1509 | # Maybe oldkey was not in self.data to begin with. If it |
1510 | # was, self.invalidate() in another thread might have |
1511 | # already removed it. del() would raise KeyError, so pop(). |
1512 | - data.pop(oldkey, None) |
1513 | + oldentry = data.pop(oldkey, _MARKER) |
1514 | + if oldentry is not _MARKER: |
1515 | + self.evictions += 1 |
1516 | clock_keys[hand] = key |
1517 | clock_refs[hand] = True |
1518 | data[key] = (hand, val, time.time() + timeout) |
1519 | @@ -238,6 +263,7 @@ |
1520 | self.clock_refs[entry[0]] = False |
1521 | # else: key was not in cache. Nothing to do. |
1522 | |
1523 | + |
1524 | class lru_cache(object): |
1525 | """ Decorator for LRU-cached function |
1526 | |
1527 | @@ -265,3 +291,78 @@ |
1528 | lru_cached.__name__ = f.__name__ |
1529 | lru_cached.__doc__ = f.__doc__ |
1530 | return lru_cached |
1531 | + |
1532 | + |
1533 | +class CacheMaker(object): |
1534 | + """Generates decorators that can be cleared later |
1535 | + """ |
1536 | + def __init__(self, maxsize=None, timeout=_DEFAULT_TIMEOUT): |
1537 | + """Create cache decorator factory. |
1538 | + |
1539 | + - maxsize : the default size for created caches. |
1540 | + |
1541 | + - timeout : the defaut expiraiton time for created caches. |
1542 | + """ |
1543 | + self._maxsize = maxsize |
1544 | + self._timeout = timeout |
1545 | + self._cache = {} |
1546 | + |
1547 | + def _resolve_setting(self, name=None, maxsize=None, timeout=None): |
1548 | + if name is None: |
1549 | + while True: |
1550 | + name = str(uuid.uuid4()) |
1551 | + ## the probability of collision is so low .... |
1552 | + if name not in self._cache: |
1553 | + break |
1554 | + |
1555 | + if name in self._cache: |
1556 | + raise KeyError("cache %s already in use" % name) |
1557 | + |
1558 | + if maxsize is None: |
1559 | + maxsize = self._maxsize |
1560 | + |
1561 | + if maxsize is None: |
1562 | + raise ValueError("Cache must have a maxsize set") |
1563 | + |
1564 | + if timeout is None: |
1565 | + timeout = self._timeout |
1566 | + |
1567 | + return name, maxsize, timeout |
1568 | + |
1569 | + def lrucache(self, name=None, maxsize=None): |
1570 | + """Named arguments: |
1571 | + |
1572 | + - name (optional) is a string, and should be unique amongst all caches |
1573 | + |
1574 | + - maxsize (optional) is an int, overriding any default value set by |
1575 | + the constructor |
1576 | + """ |
1577 | + name, maxsize, _ = self._resolve_setting(name, maxsize) |
1578 | + cache = self._cache[name] = LRUCache(maxsize) |
1579 | + return lru_cache(maxsize, cache) |
1580 | + |
1581 | + def expiring_lrucache(self, name=None, maxsize=None, timeout=None): |
1582 | + """Named arguments: |
1583 | + |
1584 | + - name (optional) is a string, and should be unique amongst all caches |
1585 | + |
1586 | + - maxsize (optional) is an int, overriding any default value set by |
1587 | + the constructor |
1588 | + |
1589 | + - timeout (optional) is an int, overriding any default value set by |
1590 | + the constructor or the default value (%d seconds) |
1591 | + """ % _DEFAULT_TIMEOUT |
1592 | + name, maxsize, timeout = self._resolve_setting(name, maxsize, timeout) |
1593 | + cache = self._cache[name] = ExpiringLRUCache(maxsize, timeout) |
1594 | + return lru_cache(maxsize, cache, timeout) |
1595 | + |
1596 | + def clear(self, *names): |
1597 | + """Clear the given cache(s). |
1598 | + |
1599 | + If no 'names' are passed, clear all caches. |
1600 | + """ |
1601 | + if len(names) == 0: |
1602 | + names = self._cache.keys() |
1603 | + |
1604 | + for name in names: |
1605 | + self._cache[name].clear() |
1606 | |
1607 | === modified file 'repoze/lru/tests.py' |
1608 | --- repoze/lru/tests.py 2012-05-24 12:29:59 +0000 |
1609 | +++ repoze/lru/tests.py 2013-06-07 00:36:27 +0000 |
1610 | @@ -1,14 +1,15 @@ |
1611 | -#!/usr/bin/python -tt |
1612 | import random |
1613 | import time |
1614 | import unittest |
1615 | |
1616 | try: |
1617 | range = xrange |
1618 | -except NameError: # pragma: no cover |
1619 | +except NameError: # pragma: NO COVER (Python3) |
1620 | pass |
1621 | |
1622 | + |
1623 | class LRUCacheTests(unittest.TestCase): |
1624 | + |
1625 | def _getTargetClass(self): |
1626 | from repoze.lru import LRUCache |
1627 | return LRUCache |
1628 | @@ -23,7 +24,7 @@ |
1629 | |
1630 | # lengths of data structures |
1631 | self.assertEqual(len(cache.clock_keys), len(cache.clock_refs)) |
1632 | - self.assertTrue(len(cache.data) <=len(cache.clock_refs)) |
1633 | + self.assertTrue(len(cache.data) <= len(cache.clock_refs)) |
1634 | |
1635 | # For each item in cache.data |
1636 | # 1. pos must be a valid index |
1637 | @@ -181,6 +182,9 @@ |
1638 | else: |
1639 | cache.put(item, "item%s" % item) |
1640 | |
1641 | + self.assertEqual(cache.misses, 0) |
1642 | + self.assertEqual(cache.evictions, 0) |
1643 | + |
1644 | self.check_cache_is_consistent(cache) |
1645 | |
1646 | def test_imperfect_hitrate(self): |
1647 | @@ -214,8 +218,36 @@ |
1648 | self.assertTrue(hit_ratio > 45) |
1649 | self.assertTrue(hit_ratio < 55) |
1650 | |
1651 | + # The internal cache counters should have the same information |
1652 | + internal_hit_ratio = 100 * cache.hits / cache.lookups |
1653 | + self.assertTrue(internal_hit_ratio > 45) |
1654 | + self.assertTrue(internal_hit_ratio < 55) |
1655 | + |
1656 | + # The internal miss counters should also be around 50% |
1657 | + internal_miss_ratio = 100 * cache.misses / cache.lookups |
1658 | + self.assertTrue(internal_miss_ratio > 45) |
1659 | + self.assertTrue(internal_miss_ratio < 55) |
1660 | + |
1661 | self.check_cache_is_consistent(cache) |
1662 | |
1663 | + def test_eviction_counter(self): |
1664 | + cache = self._makeOne(2) |
1665 | + cache.put(1, 1) |
1666 | + cache.put(2, 1) |
1667 | + self.assertEqual(cache.evictions, 0) |
1668 | + |
1669 | + cache.put(3, 1) |
1670 | + cache.put(4, 1) |
1671 | + self.assertEqual(cache.evictions, 2) |
1672 | + |
1673 | + cache.put(3, 1) |
1674 | + cache.put(4, 1) |
1675 | + self.assertEqual(cache.evictions, 2) |
1676 | + |
1677 | + cache.clear() |
1678 | + self.assertEqual(cache.evictions, 0) |
1679 | + |
1680 | + |
1681 | def test_it(self): |
1682 | cache = self._makeOne(3) |
1683 | self.assertEqual(cache.get('a'), None) |
1684 | @@ -271,6 +303,7 @@ |
1685 | |
1686 | |
1687 | class ExpiringLRUCacheTests(LRUCacheTests): |
1688 | + |
1689 | def _getTargetClass(self): |
1690 | from repoze.lru import ExpiringLRUCache |
1691 | return ExpiringLRUCache |
1692 | @@ -316,6 +349,7 @@ |
1693 | # All clock_refs must be True or False, nothing else. |
1694 | for clock_ref in cache.clock_refs: |
1695 | self.assertTrue(clock_ref is True or clock_ref is False) |
1696 | + |
1697 | def test_it(self): |
1698 | """Test a sequence of operations |
1699 | |
1700 | @@ -455,7 +489,9 @@ |
1701 | #self.assertEqual(cache.get("foo3"), "bar3") |
1702 | #self.check_cache_is_consistent(cache) |
1703 | |
1704 | + |
1705 | class DecoratorTests(unittest.TestCase): |
1706 | + |
1707 | def _getTargetClass(self): |
1708 | from repoze.lru import lru_cache |
1709 | return lru_cache |
1710 | @@ -526,6 +562,111 @@ |
1711 | #self.assertEqual(result3, 2 * "hello") |
1712 | #self.assertTrue(stop - start > 0.1) |
1713 | |
1714 | + |
1715 | class DummyLRUCache(dict): |
1716 | + |
1717 | def put(self, k, v): |
1718 | return self.__setitem__(k, v) |
1719 | + |
1720 | + |
1721 | +class CacherMaker(unittest.TestCase): |
1722 | + |
1723 | + def _getTargetClass(self): |
1724 | + from repoze.lru import CacheMaker |
1725 | + return CacheMaker |
1726 | + |
1727 | + def _makeOne(self, *args, **kw): |
1728 | + return self._getTargetClass()(*args, **kw) |
1729 | + |
1730 | + def test_named_cache(self): |
1731 | + maker = self._makeOne() |
1732 | + size = 10 |
1733 | + name = "name" |
1734 | + decorated = maker.lrucache(maxsize=size, name=name)(_adder) |
1735 | + self.assertEqual(list(maker._cache.keys()), [name]) |
1736 | + self.assertEqual(maker._cache[name].size, size) |
1737 | + decorated(10) |
1738 | + decorated(11) |
1739 | + self.assertEqual(len(maker._cache[name].data),2) |
1740 | + |
1741 | + def test_exception(self): |
1742 | + maker = self._makeOne() |
1743 | + size = 10 |
1744 | + name = "name" |
1745 | + decorated = maker.lrucache(maxsize=size, name=name)(_adder) |
1746 | + self.assertRaises(KeyError, maker.lrucache, maxsize=size, name=name) |
1747 | + self.assertRaises(ValueError, maker.lrucache) |
1748 | + |
1749 | + def test_defaultvalue_and_clear(self): |
1750 | + size = 10 |
1751 | + maker = self._makeOne(maxsize=size) |
1752 | + for i in range(100): |
1753 | + decorated = maker.lrucache()(_adder) |
1754 | + decorated(10) |
1755 | + |
1756 | + self.assertEqual(len(maker._cache) , 100) |
1757 | + for _cache in maker._cache.values(): |
1758 | + self.assertEqual( _cache.size,size) |
1759 | + self.assertEqual(len(_cache.data),1) |
1760 | + ## and test clear cache |
1761 | + maker.clear() |
1762 | + for _cache in maker._cache.values(): |
1763 | + self.assertEqual( _cache.size,size) |
1764 | + self.assertEqual(len(_cache.data),0) |
1765 | + |
1766 | + def test_clear_with_single_name(self): |
1767 | + maker = self._makeOne(maxsize=10) |
1768 | + one = maker.lrucache(name='one')(_adder) |
1769 | + two = maker.lrucache(name='two')(_adder) |
1770 | + for i in range(100): |
1771 | + _ = one(i) |
1772 | + _ = two(i) |
1773 | + self.assertEqual(len(maker._cache['one'].data), 10) |
1774 | + self.assertEqual(len(maker._cache['two'].data), 10) |
1775 | + maker.clear('one') |
1776 | + self.assertEqual(len(maker._cache['one'].data), 0) |
1777 | + self.assertEqual(len(maker._cache['two'].data), 10) |
1778 | + |
1779 | + def test_clear_with_multiple_names(self): |
1780 | + maker = self._makeOne(maxsize=10) |
1781 | + one = maker.lrucache(name='one')(_adder) |
1782 | + two = maker.lrucache(name='two')(_adder) |
1783 | + three = maker.lrucache(name='three')(_adder) |
1784 | + for i in range(100): |
1785 | + _ = one(i) |
1786 | + _ = two(i) |
1787 | + _ = three(i) |
1788 | + self.assertEqual(len(maker._cache['one'].data), 10) |
1789 | + self.assertEqual(len(maker._cache['two'].data), 10) |
1790 | + self.assertEqual(len(maker._cache['three'].data), 10) |
1791 | + maker.clear('one', 'three') |
1792 | + self.assertEqual(len(maker._cache['one'].data), 0) |
1793 | + self.assertEqual(len(maker._cache['two'].data), 10) |
1794 | + self.assertEqual(len(maker._cache['three'].data), 0) |
1795 | + |
1796 | + def test_expiring(self): |
1797 | + size = 10 |
1798 | + timeout = 10 |
1799 | + name = "name" |
1800 | + cache = self._makeOne(maxsize=size, timeout=timeout) |
1801 | + for i in range(100): |
1802 | + if not i: |
1803 | + decorated = cache.expiring_lrucache(name=name)(_adder) |
1804 | + self.assertEqual( cache._cache[name].size,size) |
1805 | + else: |
1806 | + decorated = cache.expiring_lrucache()(_adder) |
1807 | + decorated(10) |
1808 | + |
1809 | + self.assertEqual( len(cache._cache) , 100) |
1810 | + for _cache in cache._cache.values(): |
1811 | + self.assertEqual( _cache.size,size) |
1812 | + self.assertEqual( _cache.default_timeout,timeout) |
1813 | + self.assertEqual(len(_cache.data),1) |
1814 | + ## and test clear cache |
1815 | + cache.clear() |
1816 | + for _cache in cache._cache.values(): |
1817 | + self.assertEqual( _cache.size,size) |
1818 | + self.assertEqual(len(_cache.data),0) |
1819 | + |
1820 | +def _adder(x): |
1821 | + return x + 10 |
1822 | |
1823 | === modified file 'setup.cfg' |
1824 | --- setup.cfg 2012-04-09 10:24:06 +0000 |
1825 | +++ setup.cfg 2013-06-07 00:36:27 +0000 |
1826 | @@ -8,6 +8,10 @@ |
1827 | cover-package = repoze.lru |
1828 | cover-erase = 1 |
1829 | |
1830 | +[aliases] |
1831 | +dev = develop easy_install repoze.lru[testing] |
1832 | +docs = develop easy_install repoze.lru[docs] |
1833 | + |
1834 | [egg_info] |
1835 | tag_build = |
1836 | tag_date = 0 |
1837 | |
1838 | === modified file 'setup.py' |
1839 | --- setup.py 2012-04-09 10:24:06 +0000 |
1840 | +++ setup.py 2013-06-07 00:36:27 +0000 |
1841 | @@ -24,14 +24,15 @@ |
1842 | README = '' |
1843 | CHANGES = '' |
1844 | |
1845 | +testing_extras = ['nose', 'coverage'] |
1846 | + |
1847 | setup(name='repoze.lru', |
1848 | - version='0.5', |
1849 | + version='0.6', |
1850 | description='A tiny LRU cache implementation and decorator', |
1851 | long_description=README + '\n\n' + CHANGES, |
1852 | classifiers=[ |
1853 | "Intended Audience :: Developers", |
1854 | "Programming Language :: Python", |
1855 | - "Programming Language :: Python :: 2.5", |
1856 | "Programming Language :: Python :: 2.6", |
1857 | "Programming Language :: Python :: 2.7", |
1858 | "Programming Language :: Python :: 3", |
1859 | @@ -54,5 +55,9 @@ |
1860 | test_suite="repoze.lru", |
1861 | entry_points = """\ |
1862 | """, |
1863 | - ) |
1864 | + extras_require = { |
1865 | + 'testing': testing_extras, |
1866 | + 'docs': ['Sphinx',], |
1867 | + } |
1868 | +) |
1869 | |
1870 | |
1871 | === modified file 'tox.ini' |
1872 | --- tox.ini 2012-04-09 10:24:06 +0000 |
1873 | +++ tox.ini 2013-06-07 00:36:27 +0000 |
1874 | @@ -1,47 +1,35 @@ |
1875 | [tox] |
1876 | envlist = |
1877 | - py25,py26,py27,py32,pypy |
1878 | + py26,py27,py32,pypy,cover,docs |
1879 | |
1880 | [testenv] |
1881 | commands = |
1882 | python setup.py test -q |
1883 | - |
1884 | -# timing race conditions in tests cause a test under Jython 2.5 to fail: |
1885 | - |
1886 | -#.F....................... |
1887 | -#====================================================================== |
1888 | -#FAIL: When timeout is given, decorator must eventually forget entries |
1889 | -#---------------------------------------------------------------------- |
1890 | -#Traceback (most recent call last): |
1891 | -# File "/home/chrism/projects/repoze.lru/.tox/jython/Lib/site-packages/repoze/l#ru/tests.py", line 512, in test_expiry |
1892 | -# self.assertTrue(stop - start > 0.1) |
1893 | -#AssertionError |
1894 | - |
1895 | -#[testenv:jython] |
1896 | -#commands = |
1897 | -# jython setup.py test -q |
1898 | - |
1899 | -# coverage reporting broken with namespace packages and pip/nose apparently. |
1900 | -# It's not a tox thing or is it related to setuptools vs. distribute; once |
1901 | -# tox creates the virtualenv with either setuptools or distribute, this |
1902 | -# command finds no tests to run |
1903 | -# |
1904 | -# .tox/cover/bin/python setup.py nosetests |
1905 | -# |
1906 | -# which means it's something to do with nose probably |
1907 | - |
1908 | -# [testenv:cover] |
1909 | -# basepython = |
1910 | -# python2.7 |
1911 | -# commands = |
1912 | -# python setup.py nosetests --with-xunit --with-xcoverage |
1913 | -# deps = |
1914 | -# nose |
1915 | -# coverage==3.4 |
1916 | -# nosexcover |
1917 | -# distribute = False |
1918 | +deps = |
1919 | + setuptools-git |
1920 | + virtualenv |
1921 | + |
1922 | +[testenv:cover] |
1923 | +basepython = |
1924 | + python2.6 |
1925 | +commands = |
1926 | + nosetests --with-xunit --with-xcoverage |
1927 | +deps = |
1928 | + setuptools-git |
1929 | + virtualenv |
1930 | + nose |
1931 | + coverage |
1932 | + nosexcover |
1933 | |
1934 | # we separate coverage into its own testenv because a) "last run wins" wrt |
1935 | # cobertura jenkins reporting and b) pypy and jython can't handle any |
1936 | # combination of versions of coverage and nosexcover that i can find. |
1937 | |
1938 | +[testenv:docs] |
1939 | +basepython = |
1940 | + python2.6 |
1941 | +commands = |
1942 | + sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html |
1943 | + sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest |
1944 | +deps = |
1945 | + Sphinx |
Looking good, approved!