Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(188845)

Side by Side Diff: Lib/test/test_functools.py

Issue 14373: C implementation of functools.lru_cache
Patch Set: Created 6 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 import collections 1 import collections
2 import sys 2 import sys
3 import unittest 3 import unittest
4 from test import support 4 from test import support
5 from weakref import proxy 5 from weakref import proxy
6 import pickle 6 import pickle
7 from random import choice 7 from random import choice
8 8
9 import functools 9 import functools
10 10
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 return self.value == other.value 645 return self.value == other.value
646 return False 646 return False
647 def __lt__(self, other): 647 def __lt__(self, other):
648 if isinstance(other, TestTO): 648 if isinstance(other, TestTO):
649 return self.value < other.value 649 return self.value < other.value
650 raise TypeError 650 raise TypeError
651 with self.assertRaises(TypeError): 651 with self.assertRaises(TypeError):
652 TestTO(8) <= () 652 TestTO(8) <= ()
653 653
654 class TestLRU(unittest.TestCase): 654 class TestLRU(unittest.TestCase):
655
656 module = original_functools
storchaka 2012/12/20 11:02:21 This is not needed. TestLRU is an abstract class.
655 657
656 def test_lru(self): 658 def test_lru(self):
657 def orig(x, y): 659 def orig(x, y):
658 return 3 * x + y 660 return 3 * x + y
659 f = functools.lru_cache(maxsize=20)(orig) 661 f = self.module.lru_cache(maxsize=20)(orig)
660 hits, misses, maxsize, currsize = f.cache_info() 662 hits, misses, maxsize, currsize = f.cache_info()
661 self.assertEqual(maxsize, 20) 663 self.assertEqual(maxsize, 20)
662 self.assertEqual(currsize, 0) 664 self.assertEqual(currsize, 0)
663 self.assertEqual(hits, 0) 665 self.assertEqual(hits, 0)
664 self.assertEqual(misses, 0) 666 self.assertEqual(misses, 0)
665 667
666 domain = range(5) 668 domain = range(5)
667 for i in range(1000): 669 for i in range(1000):
668 x, y = choice(domain), choice(domain) 670 x, y = choice(domain), choice(domain)
669 actual = f(x, y) 671 actual = f(x, y)
(...skipping 17 matching lines...) Expand all
687 689
688 # Test bypassing the cache 690 # Test bypassing the cache
689 self.assertIs(f.__wrapped__, orig) 691 self.assertIs(f.__wrapped__, orig)
690 f.__wrapped__(x, y) 692 f.__wrapped__(x, y)
691 hits, misses, maxsize, currsize = f.cache_info() 693 hits, misses, maxsize, currsize = f.cache_info()
692 self.assertEqual(hits, 0) 694 self.assertEqual(hits, 0)
693 self.assertEqual(misses, 1) 695 self.assertEqual(misses, 1)
694 self.assertEqual(currsize, 1) 696 self.assertEqual(currsize, 1)
695 697
696 # test size zero (which means "never-cache") 698 # test size zero (which means "never-cache")
697 @functools.lru_cache(0) 699 @self.module.lru_cache(0)
698 def f(): 700 def f():
699 nonlocal f_cnt 701 nonlocal f_cnt
700 f_cnt += 1 702 f_cnt += 1
701 return 20 703 return 20
702 self.assertEqual(f.cache_info().maxsize, 0) 704 self.assertEqual(f.cache_info().maxsize, 0)
703 f_cnt = 0 705 f_cnt = 0
704 for i in range(5): 706 for i in range(5):
705 self.assertEqual(f(), 20) 707 self.assertEqual(f(), 20)
706 self.assertEqual(f_cnt, 5) 708 self.assertEqual(f_cnt, 5)
707 hits, misses, maxsize, currsize = f.cache_info() 709 hits, misses, maxsize, currsize = f.cache_info()
708 self.assertEqual(hits, 0) 710 self.assertEqual(hits, 0)
709 self.assertEqual(misses, 5) 711 self.assertEqual(misses, 5)
710 self.assertEqual(currsize, 0) 712 self.assertEqual(currsize, 0)
711 713
712 # test size one 714 # test size one
713 @functools.lru_cache(1) 715 @self.module.lru_cache(1)
714 def f(): 716 def f():
715 nonlocal f_cnt 717 nonlocal f_cnt
716 f_cnt += 1 718 f_cnt += 1
717 return 20 719 return 20
718 self.assertEqual(f.cache_info().maxsize, 1) 720 self.assertEqual(f.cache_info().maxsize, 1)
719 f_cnt = 0 721 f_cnt = 0
720 for i in range(5): 722 for i in range(5):
721 self.assertEqual(f(), 20) 723 self.assertEqual(f(), 20)
722 self.assertEqual(f_cnt, 1) 724 self.assertEqual(f_cnt, 1)
723 hits, misses, maxsize, currsize = f.cache_info() 725 hits, misses, maxsize, currsize = f.cache_info()
724 self.assertEqual(hits, 4) 726 self.assertEqual(hits, 4)
725 self.assertEqual(misses, 1) 727 self.assertEqual(misses, 1)
726 self.assertEqual(currsize, 1) 728 self.assertEqual(currsize, 1)
727 729
728 # test size two 730 # test size two
729 @functools.lru_cache(2) 731 @self.module.lru_cache(2)
730 def f(x): 732 def f(x):
731 nonlocal f_cnt 733 nonlocal f_cnt
732 f_cnt += 1 734 f_cnt += 1
733 return x*10 735 return x*10
734 self.assertEqual(f.cache_info().maxsize, 2) 736 self.assertEqual(f.cache_info().maxsize, 2)
735 f_cnt = 0 737 f_cnt = 0
736 for x in 7, 9, 7, 9, 7, 9, 8, 8, 8, 9, 9, 9, 8, 8, 8, 7: 738 for x in 7, 9, 7, 9, 7, 9, 8, 8, 8, 9, 9, 9, 8, 8, 8, 7:
737 # * * * * 739 # * * * *
738 self.assertEqual(f(x), x*10) 740 self.assertEqual(f(x), x*10)
739 self.assertEqual(f_cnt, 4) 741 self.assertEqual(f_cnt, 4)
740 hits, misses, maxsize, currsize = f.cache_info() 742 hits, misses, maxsize, currsize = f.cache_info()
741 self.assertEqual(hits, 12) 743 self.assertEqual(hits, 12)
742 self.assertEqual(misses, 4) 744 self.assertEqual(misses, 4)
743 self.assertEqual(currsize, 2) 745 self.assertEqual(currsize, 2)
744 746
745 def test_lru_with_maxsize_none(self): 747 def test_lru_with_maxsize_none(self):
746 @functools.lru_cache(maxsize=None) 748 @self.module.lru_cache(maxsize=None)
747 def fib(n): 749 def fib(n):
748 if n < 2: 750 if n < 2:
749 return n 751 return n
750 return fib(n-1) + fib(n-2) 752 return fib(n-1) + fib(n-2)
751 self.assertEqual([fib(n) for n in range(16)], 753 self.assertEqual([fib(n) for n in range(16)],
752 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]) 754 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610])
753 self.assertEqual(fib.cache_info(), 755 self.assertEqual(fib.cache_info(),
754 functools._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)) 756 self.module._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16 ))
755 fib.cache_clear() 757 fib.cache_clear()
756 self.assertEqual(fib.cache_info(), 758 self.assertEqual(fib.cache_info(),
757 functools._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)) 759 self.module._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0))
758 760
759 def test_lru_with_exceptions(self): 761 def test_lru_with_exceptions(self):
760 # Verify that user_function exceptions get passed through without 762 # Verify that user_function exceptions get passed through without
761 # creating a hard-to-read chained exception. 763 # creating a hard-to-read chained exception.
762 # http://bugs.python.org/issue13177 764 # http://bugs.python.org/issue13177
763 for maxsize in (None, 128): 765 for maxsize in (None, 128):
764 @functools.lru_cache(maxsize) 766 @self.module.lru_cache(maxsize)
765 def func(i): 767 def func(i):
766 return 'abc'[i] 768 return 'abc'[i]
767 self.assertEqual(func(0), 'a') 769 self.assertEqual(func(0), 'a')
768 with self.assertRaises(IndexError) as cm: 770 with self.assertRaises(IndexError) as cm:
769 func(15) 771 func(15)
770 self.assertIsNone(cm.exception.__context__) 772 self.assertIsNone(cm.exception.__context__)
771 # Verify that the previous exception did not result in a cached entr y 773 # Verify that the previous exception did not result in a cached entr y
772 with self.assertRaises(IndexError): 774 with self.assertRaises(IndexError):
773 func(15) 775 func(15)
774 776
775 def test_lru_with_types(self): 777 def test_lru_with_types(self):
776 for maxsize in (None, 128): 778 for maxsize in (None, 128):
777 @functools.lru_cache(maxsize=maxsize, typed=True) 779 @self.module.lru_cache(maxsize=maxsize, typed=True)
778 def square(x): 780 def square(x):
779 return x * x 781 return x * x
780 self.assertEqual(square(3), 9) 782 self.assertEqual(square(3), 9)
781 self.assertEqual(type(square(3)), type(9)) 783 self.assertEqual(type(square(3)), type(9))
782 self.assertEqual(square(3.0), 9.0) 784 self.assertEqual(square(3.0), 9.0)
783 self.assertEqual(type(square(3.0)), type(9.0)) 785 self.assertEqual(type(square(3.0)), type(9.0))
784 self.assertEqual(square(x=3), 9) 786 self.assertEqual(square(x=3), 9)
785 self.assertEqual(type(square(x=3)), type(9)) 787 self.assertEqual(type(square(x=3)), type(9))
786 self.assertEqual(square(x=3.0), 9.0) 788 self.assertEqual(square(x=3.0), 9.0)
787 self.assertEqual(type(square(x=3.0)), type(9.0)) 789 self.assertEqual(type(square(x=3.0)), type(9.0))
788 self.assertEqual(square.cache_info().hits, 4) 790 self.assertEqual(square.cache_info().hits, 4)
789 self.assertEqual(square.cache_info().misses, 4) 791 self.assertEqual(square.cache_info().misses, 4)
790 792
791 def test_lru_with_keyword_args(self): 793 def test_lru_with_keyword_args(self):
792 @functools.lru_cache() 794 @self.module.lru_cache()
793 def fib(n): 795 def fib(n):
794 if n < 2: 796 if n < 2:
795 return n 797 return n
796 return fib(n=n-1) + fib(n=n-2) 798 return fib(n=n-1) + fib(n=n-2)
797 self.assertEqual( 799 self.assertEqual(
798 [fib(n=number) for number in range(16)], 800 [fib(n=number) for number in range(16)],
799 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] 801 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
800 ) 802 )
801 self.assertEqual(fib.cache_info(), 803 self.assertEqual(fib.cache_info(),
802 functools._CacheInfo(hits=28, misses=16, maxsize=128, currsize=16)) 804 self.module._CacheInfo(hits=28, misses=16, maxsize=128, currsize=16) )
803 fib.cache_clear() 805 fib.cache_clear()
804 self.assertEqual(fib.cache_info(), 806 self.assertEqual(fib.cache_info(),
805 functools._CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)) 807 self.module._CacheInfo(hits=0, misses=0, maxsize=128, currsize=0))
806 808
807 def test_lru_with_keyword_args_maxsize_none(self): 809 def test_lru_with_keyword_args_maxsize_none(self):
808 @functools.lru_cache(maxsize=None) 810 @self.module.lru_cache(maxsize=None)
809 def fib(n): 811 def fib(n):
810 if n < 2: 812 if n < 2:
811 return n 813 return n
812 return fib(n=n-1) + fib(n=n-2) 814 return fib(n=n-1) + fib(n=n-2)
813 self.assertEqual([fib(n=number) for number in range(16)], 815 self.assertEqual([fib(n=number) for number in range(16)],
814 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]) 816 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610])
815 self.assertEqual(fib.cache_info(), 817 self.assertEqual(fib.cache_info(),
816 functools._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)) 818 self.module._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16 ))
817 fib.cache_clear() 819 fib.cache_clear()
818 self.assertEqual(fib.cache_info(), 820 self.assertEqual(fib.cache_info(),
819 functools._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)) 821 self.module._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0))
822
823 def test_lru_cache_decoration(self):
824 def f(zomg: 'zomg_annotation'):
825 """f doc string"""
826 return 42
827 g = self.module.lru_cache()(f)
828 for attr in self.module.WRAPPER_ASSIGNMENTS:
829 self.assertEqual(getattr(g, attr), getattr(f, attr))
830
831 class TestLRUC(BaseTestC, TestLRU):
832 pass
833
834 class TestLRUPy(BaseTestPy, TestLRU):
835 pass
820 836
821 def test_main(verbose=None): 837 def test_main(verbose=None):
822 test_classes = ( 838 test_classes = (
823 TestPartialC, 839 TestPartialC,
824 TestPartialPy, 840 TestPartialPy,
825 TestPartialCSubclass, 841 TestPartialCSubclass,
826 TestPartialPySubclass, 842 TestPartialPySubclass,
827 TestUpdateWrapper, 843 TestUpdateWrapper,
828 TestTotalOrdering, 844 TestTotalOrdering,
829 TestCmpToKeyC, 845 TestCmpToKeyC,
830 TestCmpToKeyPy, 846 TestCmpToKeyPy,
831 TestWraps, 847 TestWraps,
832 TestReduce, 848 TestReduce,
833 TestLRU, 849 TestLRU,
storchaka 2012/12/20 11:02:21 TestLRU should not be here. Both implementation ar
850 TestLRUC,
851 TestLRUPy
834 ) 852 )
835 support.run_unittest(*test_classes) 853 support.run_unittest(*test_classes)
836 854
837 # verify reference counting 855 # verify reference counting
838 if verbose and hasattr(sys, "gettotalrefcount"): 856 if verbose and hasattr(sys, "gettotalrefcount"):
839 import gc 857 import gc
840 counts = [None] * 5 858 counts = [None] * 5
841 for i in range(len(counts)): 859 for i in range(len(counts)):
842 support.run_unittest(*test_classes) 860 support.run_unittest(*test_classes)
843 gc.collect() 861 gc.collect()
844 counts[i] = sys.gettotalrefcount() 862 counts[i] = sys.gettotalrefcount()
845 print(counts) 863 print(counts)
846 864
847 if __name__ == '__main__': 865 if __name__ == '__main__':
848 test_main(verbose=True) 866 test_main(verbose=True)
OLDNEW

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+