Skip to content

Commit db8e1c6

Browse files
committed
Merge remote-tracking branch 'origin/master'
Conflicts: README.markdown
2 parents 77ef6f4 + 65e9f0f commit db8e1c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+931
-37
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ nosetests.xml
1515

1616
coverage.xml
1717
*.coverage
18-
.coverage_html_report
18+
.coverage_html_report
19+
20+
_build

README.markdown

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
[Documentation](http://docs.pythontoolbox.org)
2-
3-
[Installation](http://docs.pythontoolbox.org/installation.html)
1+
[Documentation](http://python_toolbox.readthedocs.org)
42

53

64
# What is the Python Toolbox? #
@@ -19,10 +17,15 @@ contains:
1917
- `python_toolbox.emitters`: A publisher-subscriber framework that doesn't
2018
abuse strings.
2119

22-
- And many, *many* more! The Python Toolbox contains **hundreds** of useful little
20+
- And many, *many* more! The Python Toolbox contains **100+** useful little
2321
tools.
2422

2523

24+
# Not backward-compatible yet #
25+
26+
Please keep in mind that Python Toolbox is still in alpha stage, and that backward compatibility would *not* be maintained in this phase.
27+
28+
2629
# Mailing lists #
2730

2831
All general discussion happens at **[the Python Toolbox Google Group](https://groups.google.com/forum/#!forum/python-toolbox)**. If you need help with the Python Toolbox, you're welcome to post your question and we'll try to help you.
@@ -34,10 +37,11 @@ If you want to be informed on new releases of the Python Toolbox, sign up for
3437

3538
# Python versions #
3639

37-
The Python Toolbox supports Python versions 2.5, 2.6, 2.7, 3.1 and 3.2.
40+
The Python Toolbox supports Python versions 2.5, 2.6 and 2.7.
3841

3942
It's tested on both CPython and PyPy.
4043

44+
It also supports PyPy 1.8. (Which runs Python 2.7.)
4145

4246
# Current state #
4347

docs/index.txt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,24 @@ Contents:
1515
.. toctree::
1616
:maxdepth: 2
1717

18-
intro/index
1918
topics/index
20-
ref/index
2119
misc/index
20+
21+
..
22+
ref/index
23+
24+
This documentation is still incomplete. If you have any questions or feedback,
25+
say hello on the `mailing list`_!
26+
27+
-------------------------------------------------------------------------------
28+
29+
The Python Toolbox repository is at: https://github.com/cool-RR/python_toolbox
30+
31+
Feel free to fork and send pull requests!
32+
2233

23-
This documentation is still incomplete. If you have any questions or feedback, say hello
24-
on the `mailing list`_!
2534

2635
.. _mailing list: https://groups.google.com/forum/#!forum/python-toolbox
2736

2837
.. * :ref:`genindex`
29-
.. * :ref:`modindex`
38+
.. * :ref:`modindex`

docs/topics/abc-tools.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-abc-tools:
8+
9+
:mod:`abc_tools` - documentation not written
10+
======================================

docs/topics/address-tools.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-address-tools:
8+
9+
:mod:`address_tools` - documentation not written
10+
======================================

docs/topics/arguments-profile.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-arguments-profile:
8+
9+
:mod:`arguments_profile` - documentation not written
10+
======================================

docs/topics/binary-search.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-binary-search:
8+
9+
:mod:`binary_search` - documentation not written
10+
======================================

docs/topics/caching/cache.txt

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-caching-cache:
8+
9+
:func:`caching.cache`
10+
====================
11+
12+
A caching decorator that understands arguments
13+
----------------------------------------------
14+
15+
The idea of a caching decorator is very cool. You decorate your function with a
16+
caching decorator:
17+
18+
>>> from python_toolbox import caching
19+
>>>
20+
>>> @caching.cache
21+
... def f(x):
22+
... print('Calculating...')
23+
... return x ** x # Some long expensive computation
24+
25+
And then, every time you call it, it'll cache the results for next time:
26+
27+
>>> f(4)
28+
Calculating...
29+
256
30+
>>> f(5)
31+
Calculating...
32+
3125
33+
>>> f(5)
34+
3125
35+
>>> f(5)
36+
3125
37+
38+
As you can see, after the first time we calculate ``f(5)`` the result gets
39+
saved to a cache and every time we'll call ``f(5)`` Python will return the
40+
result from the cache instead of calculating it again. This prevents making
41+
redundant performance-expensive calculations.
42+
43+
Now, depending on the function, there can be many different ways to make the same call. For example, if you have a function defined like this::
44+
45+
def g(a, b=2, **kwargs):
46+
return whatever
47+
48+
Then ``g(1)``, ``g(1, 2)``, ``g(b=2, a=1)`` and even ``g(1, 2, **{})`` are all equivalent. They give the exact same arguments, just in different ways. Most caching decorators out there don't understand that. If you call ``g(1)`` and then ``g(1, 2)``, they will calculate the function again, because they don't understand that it's exactly the same call and they could use the cached result.
49+
50+
Enter :func:`caching.cache`:
51+
52+
>>> @caching.cache()
53+
... def g(a, b=2, **kwargs):
54+
... print('Calculating')
55+
... return (a, b, kwargs)
56+
...
57+
>>> g(1)
58+
Calculating
59+
(1, 2, {})
60+
>>> g(1, 2) # Look ma, no calculating:
61+
(1, 2, {})
62+
>>> g(b=2, a=1) # No calculating again:
63+
(1, 2, {})
64+
>>> g(1, 2, **{}) # No calculating here either:
65+
(1, 2, {})
66+
>>> g('something_else') # Now calculating for different arguments:
67+
Calculating
68+
('something_else', 2, {})
69+
70+
As you can see above, :func:`caching.cache` analyzes the function and understands
71+
that calls like ``g(1)`` and ``g(1, 2)`` are identical and therefore should be
72+
cached together.
73+
74+
75+
Both limited and unlimited cache
76+
--------------------------------
77+
78+
By default, the cache size will be unlimited. If you want to limit the cache size, pass in the ``max_size`` argument:
79+
80+
>>> @caching.cache(max_size=7)
81+
... def f(): pass
82+
83+
84+
If and when the cache size reaches the limit (7 in this case), old values will
85+
get thrown away according to a `LRU order`_.
86+
87+
88+
Sleekrefs
89+
----------
90+
91+
:func:`caching.cache` arguments with sleekrefs. Sleekrefs are a more robust variation of `weakrefs`_. They are basically a gracefully-degrading version of weakrefs, so you can use them on un-weakreff-able objects like :class:`int`\, and they will just use regular references.
92+
93+
The usage of sleekrefs prevents memory leaks when using potentially-heavy arguments.
94+
95+
96+
.. _LRU order: http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
97+
.. _weakrefs: http://docs.python.org/library/weakref.html
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-caching-cached-property:
8+
9+
:class:`caching.CachedProperty`
10+
===============================
11+
12+
A cached property
13+
-----------------
14+
15+
Oftentimes you have a :class:`property` on a class that never gets changed and
16+
needs to be calculated only once. This is a good situation to use
17+
:class:`caching.CachedProperty` in order to have that property be calculated
18+
only one time per instance. Any future accesses to the property will use the
19+
cached value.
20+
21+
Example::
22+
23+
>>> import time
24+
>>> from python_toolbox import caching
25+
>>>
26+
>>> class MyObject(object):
27+
... # ... Regular definitions here
28+
... def _get_personality(self):
29+
... print('Calculating personality...')
30+
... time.sleep(5) # Time consuming process...
31+
... return 'Nice person'
32+
... personality = caching.CachedProperty(_get_personality)
33+
34+
35+
Now we create an object and calculate its "personality":
36+
37+
>>> my_object = MyObject()
38+
>>> my_object.personality
39+
'Nice person'
40+
>>> # We had to wait 5 seconds for the calculation!
41+
42+
Consecutive calls will be instantaneous:
43+
44+
>>> my_object.personality
45+
'Nice person'
46+
>>> # That one was cached and therefore instantaneous!
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
..
2+
Copyright 2009-2012 Ram Rachum. This work is licensed under a Creative
3+
Commons Attribution-ShareAlike 3.0 Unported License, with attribution to
4+
"Ram Rachum at ram.rachum.com" including link. The license may be obtained
5+
at http://creativecommons.org/licenses/by-sa/3.0/
6+
7+
.. _topics-caching-cached-type:
8+
9+
:class:`caching.CachedType`
10+
===========================
11+
12+
A class that automatically caches its instances
13+
-----------------------------------------------
14+
15+
Sometimes you define classes whose instances hold absolutely no state on them,
16+
and are completey determined by the arguments passed to them. In these cases
17+
using :class:`caching.CachedType` as a metaclass would cache class instances,
18+
preventing more than one of them from being created:
19+
20+
>>> from python_toolbox import caching
21+
>>>
22+
>>> class A(object):
23+
... __metaclass__ = caching.CachedType
24+
... def __init__(self, a=1, b=2):
25+
... self.a = a
26+
... self.b = b
27+
28+
Now every time you create an instance, it'll be cached:
29+
30+
>>> my_instance = A(b=3)
31+
32+
And the next time you'll create an instance with the same arguments:
33+
34+
>>> another_instance = A(b=3)
35+
36+
No instance will be actually created; the same instance from before will be used:
37+
38+
>>> assert another_instance is my_instance
39+

0 commit comments

Comments
 (0)