[PYTHON] Count / verify the number of method calls.

It relies on the snippet I mentioned earlier (http://qiita.com/items/1321). It counts / validates method calls in tests and so on.

from unittest import TestCase


class CallCounter(object):
    """Check a numbe of time a callable is called."""

    def __new__(cls, *args, **kargs):
        inst = super(CallCounter, cls).__new__(cls, *args, **kargs)
        inst._patch_mgr = PatchManager()
        inst._targets = {}
        return inst

    class FailedVerification(Exception):
        pass

    class CallCountManager(object):
        def __init__ (self, target, name, expected):
            self.__target = target
            self.__name = name
            self.__original = getattr(target, name)
            self.__count = 0
            self.__expected = expected

        def __call__(self, *args, **kargs):
            self.__count += 1
            return self.__original(*args, **kargs)

        def __verify(self):
            if self.__count == self.__expected:
                return

            msg = '%s.%s should be called %d times but %d' % \
                  (self.__target.__name__, self.__name, self.__expected,
                   self.__count,)
            raise CallCounter.FailedVerification(msg)

    def ensure(self, target, name, count):
        counter = self.CallCountManager(target, name, count)
        key = '%s.%s'%(target.__name__, name)
        self._targets[key] = counter
        self._patch_mgr.attach(target, name, counter)
        return

    def verify(self):
        for key, counter in self._targets.iteritems():
            counter._CallCountManager__verify()
        return

    def end(self):
        self._patch_mgr.detach_all()
        return

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end()
        if exc_type:
            return False
        return True


class TestCallCounter(TestCase):
    """Test for test.CallCounter."""

    def test_1(self):
        """Call it simply."""

        c = CallCounter()

        import datetime
        original = datetime.datetime
        c.ensure(datetime, 'datetime', 1)
        self.assert_(isinstance(datetime.datetime,
                                CallCounter.CallCountManager))
        self.assertNotEqual(datetime.datetime, original)

        # Call it first.
        datetime.datetime(year=2011, month=3, day=4)
        c.verify()

        # Call it second.
        datetime.datetime(year=2011, month=3, day=4)
        with self.assertRaises(CallCounter.FailedVerification):
            c.verify()

        # Verify a clearance.
        c.end()
        self.assertEqual(datetime.datetime, original)

        return

    def test_2(self):
        """Call it simply."""

        c = CallCounter()

        import datetime
        original = datetime.datetime
        c.ensure(datetime, 'datetime', 0)
        self.assertNotEqual(datetime.datetime, original)

        # Call it and verify.
        datetime.datetime(year=2011, month=3, day=4)
        with self.assertRaises(CallCounter.FailedVerification):
            c.verify()

        c.end()
        self.assertEqual(datetime.datetime, original)

        return

    def test_3(self):
        """Use it with `with statement`."""

        import datetime
        original = datetime.datetime
        with self.assertRaises(CallCounter.FailedVerification):
            with CallCounter() as c:
                c.ensure(datetime, 'datetime', 0)
                self.assertNotEqual(datetime.datetime, original)

                # Call it and verify.
                datetime.datetime(year=2011, month=3, day=4)
                c.verify()

        self.assertEqual(datetime.datetime, original)

        return

    def test_4(self):
        """Exception is happend in with statement."""

        import datetime
        original = datetime.datetime
        with self.assertRaises(AssertionError):
            with CallCounter() as c:
                c.ensure(datetime, 'datetime', 0)
                self.assertNotEqual(datetime.datetime, original)

                # Call it and verify.
                datetime.datetime(year=2011, month=3, day=4)
                raise AssertionError()

        self.assertEqual(datetime.datetime, original)

        return

Recommended Posts

Count / verify the number of method calls.
Count the number of characters with echo
10. Counting the number of lines
Count the number of parameters in the deep learning model
Get the number of digits
Calculate the number of changes
Count the number of characters in the text on the clipboard on mac
[Homology] Count the number of holes in data with Python
Get the number of views of Qiita
Calculation of the number of Klamer correlations
Get the number of Youtube subscribers
Count the number of Thai and Arabic characters well in Python
I investigated the X-means method that automatically estimates the number of clusters
[Linux] I tried to verify the secure confirmation method of FQDN (CentOS7)
4 methods to count the number of occurrences of integers in a certain interval (including imos method) [Python implementation]
Output the number of CPU cores in Python
About the accuracy of Archimedean circle calculation method
Clustering of clustering method
Calculate the total number of combinations with python
How to count the number of elements in Django and output to a template
Divide the string into the specified number of characters
Find the number of days in a month
Minimize the number of polishings by combinatorial optimization
Determine the number of classes using the Starges formula
How to count the number of occurrences of each element in the list in Python with weight
Check the processing time and the number of calls for each process in python (cProfile)
Calculation of the shortest path using the Monte Carlo method
python beginners tried to predict the number of criminals
[Python] A program that counts the number of valleys
Projecet Euler 12 Find the number of divisors without division.
How to get the number of digits in Python
relation of the Fibonacci number series and the Golden ratio
Calculation of the minimum required number of votes from turnout
Destroy the intermediate expression of the sweep method with Python
Try to estimate the number of likes on Twitter
Predict the number of people infected with COVID-19 with Prophet
What is the true identity of Python's sort method "sort"? ??
Get the size (number of elements) of UnionFind in Python
[Summary of 27 languages] My number check digit calculation method
Manage the package version number of requirements.txt with pip-tools
[Python] Get the number of views of all posted articles
I tried the simplest method of multi-label document classification
Visualize the number of complaints from life insurance companies
The copy method of pandas.DataFrame is deep copy by default
Clustering G-means that automatically determines the number of clusters
The beginning of cif2cell
The meaning of self
the zen of Python
The story of sys.path.append ()
Summary of test method
Revenge of the Types: Revenge of types
Increase the speed of the Monte Carlo method of Cython cut-out implementation.
How to find the optimal number of clusters in k-means
Maya | Find out the number of polygons in the selected object
A simple Python implementation of the k-nearest neighbor method (k-NN)
Reuse the behavior of the @property method by using a descriptor [16/100]
Examine the margin of error in the number of deaths from pneumonia
Analyzing data on the number of corona patients in Japan
Get the number of specific elements in a python list
Python --Find out number of groups in the regex expression
Decorator that displays "FIN method name" at the end of the method