Module pedantic.tests.tests_small_method_decorators

Expand source code
import asyncio
import unittest
import warnings
from abc import abstractmethod
from unittest import IsolatedAsyncioTestCase

from pedantic import overrides, timer, count_calls, trace, trace_if_returns, does_same_as_function, deprecated, \
    unimplemented, mock, require_kwargs
from pedantic.exceptions import NotImplementedException, PedanticOverrideException, PedanticCallWithArgsException


class TestSmallDecoratorMethods(unittest.TestCase):
    def test_overrides_parent_has_no_such_method(self):
        class MyClassA:
            pass

        with self.assertRaises(expected_exception=PedanticOverrideException):
            class MyClassB(MyClassA):
                @overrides(MyClassA)
                def operation(self): pass

    def test_overrides_all_good(self):
        class MyClassA:
            def operation(self): pass

        class MyClassB(MyClassA):
            @overrides(MyClassA)
            def operation(self):
                return 42

        b = MyClassB()
        b.operation()

    def test_overrides_static_method(self):
        class MyClassA:
            @staticmethod
            def operation(): pass

        class MyClassB(MyClassA):
            @staticmethod
            @overrides(MyClassA)
            def operation():
                return 42

        b = MyClassB()
        self.assertEqual(b.operation(), 42)
        self.assertEqual(MyClassB.operation(), 42)

    def test_overrides_below_property(self):
        class MyClassA:
            @property
            @abstractmethod
            def operation(self): pass

        class MyClassB(MyClassA):
            @property
            @overrides(MyClassA)   # Note: it does not work the other way around
            def operation(self):
                return 43

        b = MyClassB()
        self.assertEqual(b.operation, 43)

    def test_overrides_function(self):
        class MyClassA:
            pass

        with self.assertRaises(expected_exception=PedanticOverrideException):
            @overrides(MyClassA)
            def operation(): return 42

    def test_deprecated_1(self):
        @deprecated
        def old_method(i: int) -> str: return str(i)

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            old_method(42)
            assert len(w) == 1
            assert issubclass(w[-1].category, DeprecationWarning)
            assert "deprecated" in str(w[-1].message)

    def test_deprecated_2(self):
        def old_method(i: int) -> str:
            return str(i)

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            old_method(42)
            assert not len(w) == 1

    def test_unimplemented(self):
        @unimplemented
        def dirt(i: int) -> str:
            return str(i)

        with self.assertRaises(expected_exception=NotImplementedException):
            dirt(42)

    def test_timer(self):
        @timer
        def operation(i: int) -> str:
            return str(i)

        operation(42)

    def test_count_calls(self):
        @count_calls
        def operation(i: int) -> str:
            return str(i)

        operation(42)

    def test_trace(self):
        def some_method(x, y):
            return x + y

        traced_method = trace(some_method)
        self.assertEqual(some_method(42, 99), traced_method(42, 99))

    def test_trace_if_returns(self):
        def some_method(x, y):
            return x + y
        traced_method = trace_if_returns(100)(some_method)
        self.assertEqual(some_method(42, 99), traced_method(42, 99))
        self.assertEqual(some_method(42, 58), traced_method(42, 58))

    def test_does_same_as_function(self):
        def some_method(x, y, z):
            return x * (y + z)

        @does_same_as_function(some_method)
        def other_method(x, y, z):
            return x * y + x * z

        other_method(1, 2, 3)
        other_method(4, 5, 6)

    def test_does_same_as_function_wrong(self):
        def some_method(x, y, z):
            return x * (y + z)

        @does_same_as_function(some_method)
        def other_method(x, y, z):
            return x * y + z

        other_method(0, 2, 0)
        with self.assertRaises(expected_exception=AssertionError):
            other_method(4, 5, 6)


class AsyncSmallDecoratorTests(IsolatedAsyncioTestCase):
    async def test_overrides_async_instance_method(self) -> None:
        class MyClassA:
            async def operation(self): pass

        class MyClassB(MyClassA):
            @overrides(MyClassA)
            async def operation(self):
                await asyncio.sleep(0)
                return 42

        b = MyClassB()
        await b.operation()

    async def test_overrides_parent_has_no_such_method_async(self):
        class MyClassA:
            pass

        with self.assertRaises(expected_exception=PedanticOverrideException):
            class MyClassB(MyClassA):
                @overrides(MyClassA)
                async def operation(self): return 42

    async def test_count_calls_async(self):
        @count_calls
        async def operation(i: int) -> str:
            await asyncio.sleep(0)
            return str(i)

        res = await operation(42)
        self.assertEqual('42', res)

    async def test_trace_async(self):
        async def some_method(x, y):
            await asyncio.sleep(0)
            return x + y

        traced_method = trace(some_method)
        self.assertEqual(await some_method(42, 99), await traced_method(42, 99))

    async def test_trace_if_returns_async(self):
        async def some_method(x, y):
            await asyncio.sleep(0)
            return x + y

        traced_method = trace_if_returns(100)(some_method)
        self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
        self.assertEqual(await some_method(42, 58), await traced_method(42, 58))

    async def test_timer_async(self):
        @timer
        async def operation(i: int) -> str:
            await asyncio.sleep(0.05)
            return str(i)

        await operation(42)

    async def test_deprecated_async(self):
        @deprecated
        async def old_method(i: int) -> str:
            return str(i)

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            await old_method(42)
            assert len(w) == 1
            assert issubclass(w[-1].category, DeprecationWarning)
            assert "deprecated" in str(w[-1].message)

    async def test_does_same_as_function_async(self):
        async def some_method(x, y, z):
            await asyncio.sleep(0)
            return x * (y + z)

        @does_same_as_function(some_method)
        async def other_method(x, y, z):
            await asyncio.sleep(0)
            return x * y + x * z

        await other_method(1, 2, 3)
        await other_method(4, 5, 6)

    async def test_does_same_as_function_async_and_sync(self):
        def some_method(x, y, z):
            return x * (y + z)

        @does_same_as_function(some_method)
        async def other_method(x, y, z):
            await asyncio.sleep(0)
            return x * y + x * z

        await other_method(1, 2, 3)
        await other_method(4, 5, 6)

    async def test_does_same_as_function_wrong(self):
        async def some_method(x, y, z):
            await asyncio.sleep(0)
            return x * (y + z)

        @does_same_as_function(some_method)
        async def other_method(x, y, z):
            await asyncio.sleep(0)
            return x * y + z

        await other_method(0, 2, 0)

        with self.assertRaises(expected_exception=AssertionError):
            await other_method(4, 5, 6)

    async def test_mock_async(self) -> None:
        @mock(return_value=42)
        async def my_function(a, b, c): return a + b + c

        assert await my_function(1, 2, 3) == 42
        assert await my_function(100, 200, 300) == 42

    async def test_require_kwargs(self):
        @require_kwargs
        async def calc(n: int, m: int, i: int) -> int:
            return n + m + i

        await calc(n=1, m=2, i=3)

        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
            await calc(1, m=2, i=3)

Classes

class AsyncSmallDecoratorTests (methodName='runTest')

A class whose instances are single test cases.

By default, the test code itself should be placed in a method named 'runTest'.

If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute.

Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively.

If it is necessary to override the init method, the base class init method must always be called. It is important that subclasses should not change the signature of their init method, since instances of the classes are instantiated automatically by parts of the framework in order to be run.

When subclassing TestCase, you can set these attributes: * failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. * longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. * maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required.

Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name.

Expand source code
class AsyncSmallDecoratorTests(IsolatedAsyncioTestCase):
    async def test_overrides_async_instance_method(self) -> None:
        class MyClassA:
            async def operation(self): pass

        class MyClassB(MyClassA):
            @overrides(MyClassA)
            async def operation(self):
                await asyncio.sleep(0)
                return 42

        b = MyClassB()
        await b.operation()

    async def test_overrides_parent_has_no_such_method_async(self):
        class MyClassA:
            pass

        with self.assertRaises(expected_exception=PedanticOverrideException):
            class MyClassB(MyClassA):
                @overrides(MyClassA)
                async def operation(self): return 42

    async def test_count_calls_async(self):
        @count_calls
        async def operation(i: int) -> str:
            await asyncio.sleep(0)
            return str(i)

        res = await operation(42)
        self.assertEqual('42', res)

    async def test_trace_async(self):
        async def some_method(x, y):
            await asyncio.sleep(0)
            return x + y

        traced_method = trace(some_method)
        self.assertEqual(await some_method(42, 99), await traced_method(42, 99))

    async def test_trace_if_returns_async(self):
        async def some_method(x, y):
            await asyncio.sleep(0)
            return x + y

        traced_method = trace_if_returns(100)(some_method)
        self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
        self.assertEqual(await some_method(42, 58), await traced_method(42, 58))

    async def test_timer_async(self):
        @timer
        async def operation(i: int) -> str:
            await asyncio.sleep(0.05)
            return str(i)

        await operation(42)

    async def test_deprecated_async(self):
        @deprecated
        async def old_method(i: int) -> str:
            return str(i)

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            await old_method(42)
            assert len(w) == 1
            assert issubclass(w[-1].category, DeprecationWarning)
            assert "deprecated" in str(w[-1].message)

    async def test_does_same_as_function_async(self):
        async def some_method(x, y, z):
            await asyncio.sleep(0)
            return x * (y + z)

        @does_same_as_function(some_method)
        async def other_method(x, y, z):
            await asyncio.sleep(0)
            return x * y + x * z

        await other_method(1, 2, 3)
        await other_method(4, 5, 6)

    async def test_does_same_as_function_async_and_sync(self):
        def some_method(x, y, z):
            return x * (y + z)

        @does_same_as_function(some_method)
        async def other_method(x, y, z):
            await asyncio.sleep(0)
            return x * y + x * z

        await other_method(1, 2, 3)
        await other_method(4, 5, 6)

    async def test_does_same_as_function_wrong(self):
        async def some_method(x, y, z):
            await asyncio.sleep(0)
            return x * (y + z)

        @does_same_as_function(some_method)
        async def other_method(x, y, z):
            await asyncio.sleep(0)
            return x * y + z

        await other_method(0, 2, 0)

        with self.assertRaises(expected_exception=AssertionError):
            await other_method(4, 5, 6)

    async def test_mock_async(self) -> None:
        @mock(return_value=42)
        async def my_function(a, b, c): return a + b + c

        assert await my_function(1, 2, 3) == 42
        assert await my_function(100, 200, 300) == 42

    async def test_require_kwargs(self):
        @require_kwargs
        async def calc(n: int, m: int, i: int) -> int:
            return n + m + i

        await calc(n=1, m=2, i=3)

        with self.assertRaises(expected_exception=PedanticCallWithArgsException):
            await calc(1, m=2, i=3)

Ancestors

  • unittest.async_case.IsolatedAsyncioTestCase
  • unittest.case.TestCase

Methods

async def test_count_calls_async(self)
Expand source code
async def test_count_calls_async(self):
    @count_calls
    async def operation(i: int) -> str:
        await asyncio.sleep(0)
        return str(i)

    res = await operation(42)
    self.assertEqual('42', res)
async def test_deprecated_async(self)
Expand source code
async def test_deprecated_async(self):
    @deprecated
    async def old_method(i: int) -> str:
        return str(i)

    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        await old_method(42)
        assert len(w) == 1
        assert issubclass(w[-1].category, DeprecationWarning)
        assert "deprecated" in str(w[-1].message)
async def test_does_same_as_function_async(self)
Expand source code
async def test_does_same_as_function_async(self):
    async def some_method(x, y, z):
        await asyncio.sleep(0)
        return x * (y + z)

    @does_same_as_function(some_method)
    async def other_method(x, y, z):
        await asyncio.sleep(0)
        return x * y + x * z

    await other_method(1, 2, 3)
    await other_method(4, 5, 6)
async def test_does_same_as_function_async_and_sync(self)
Expand source code
async def test_does_same_as_function_async_and_sync(self):
    def some_method(x, y, z):
        return x * (y + z)

    @does_same_as_function(some_method)
    async def other_method(x, y, z):
        await asyncio.sleep(0)
        return x * y + x * z

    await other_method(1, 2, 3)
    await other_method(4, 5, 6)
async def test_does_same_as_function_wrong(self)
Expand source code
async def test_does_same_as_function_wrong(self):
    async def some_method(x, y, z):
        await asyncio.sleep(0)
        return x * (y + z)

    @does_same_as_function(some_method)
    async def other_method(x, y, z):
        await asyncio.sleep(0)
        return x * y + z

    await other_method(0, 2, 0)

    with self.assertRaises(expected_exception=AssertionError):
        await other_method(4, 5, 6)
async def test_mock_async(self) ‑> None
Expand source code
async def test_mock_async(self) -> None:
    @mock(return_value=42)
    async def my_function(a, b, c): return a + b + c

    assert await my_function(1, 2, 3) == 42
    assert await my_function(100, 200, 300) == 42
async def test_overrides_async_instance_method(self) ‑> None
Expand source code
async def test_overrides_async_instance_method(self) -> None:
    class MyClassA:
        async def operation(self): pass

    class MyClassB(MyClassA):
        @overrides(MyClassA)
        async def operation(self):
            await asyncio.sleep(0)
            return 42

    b = MyClassB()
    await b.operation()
async def test_overrides_parent_has_no_such_method_async(self)
Expand source code
async def test_overrides_parent_has_no_such_method_async(self):
    class MyClassA:
        pass

    with self.assertRaises(expected_exception=PedanticOverrideException):
        class MyClassB(MyClassA):
            @overrides(MyClassA)
            async def operation(self): return 42
async def test_require_kwargs(self)
Expand source code
async def test_require_kwargs(self):
    @require_kwargs
    async def calc(n: int, m: int, i: int) -> int:
        return n + m + i

    await calc(n=1, m=2, i=3)

    with self.assertRaises(expected_exception=PedanticCallWithArgsException):
        await calc(1, m=2, i=3)
async def test_timer_async(self)
Expand source code
async def test_timer_async(self):
    @timer
    async def operation(i: int) -> str:
        await asyncio.sleep(0.05)
        return str(i)

    await operation(42)
async def test_trace_async(self)
Expand source code
async def test_trace_async(self):
    async def some_method(x, y):
        await asyncio.sleep(0)
        return x + y

    traced_method = trace(some_method)
    self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
async def test_trace_if_returns_async(self)
Expand source code
async def test_trace_if_returns_async(self):
    async def some_method(x, y):
        await asyncio.sleep(0)
        return x + y

    traced_method = trace_if_returns(100)(some_method)
    self.assertEqual(await some_method(42, 99), await traced_method(42, 99))
    self.assertEqual(await some_method(42, 58), await traced_method(42, 58))
class TestSmallDecoratorMethods (methodName='runTest')

A class whose instances are single test cases.

By default, the test code itself should be placed in a method named 'runTest'.

If the fixture may be used for many test cases, create as many test methods as are needed. When instantiating such a TestCase subclass, specify in the constructor arguments the name of the test method that the instance is to execute.

Test authors should subclass TestCase for their own tests. Construction and deconstruction of the test's environment ('fixture') can be implemented by overriding the 'setUp' and 'tearDown' methods respectively.

If it is necessary to override the init method, the base class init method must always be called. It is important that subclasses should not change the signature of their init method, since instances of the classes are instantiated automatically by parts of the framework in order to be run.

When subclassing TestCase, you can set these attributes: * failureException: determines which exception will be raised when the instance's assertion methods fail; test methods raising this exception will be deemed to have 'failed' rather than 'errored'. * longMessage: determines whether long messages (including repr of objects used in assert methods) will be printed on failure in addition to any explicit message passed. * maxDiff: sets the maximum length of a diff in failure messages by assert methods using difflib. It is looked up as an instance attribute so can be configured by individual tests if required.

Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name.

Expand source code
class TestSmallDecoratorMethods(unittest.TestCase):
    def test_overrides_parent_has_no_such_method(self):
        class MyClassA:
            pass

        with self.assertRaises(expected_exception=PedanticOverrideException):
            class MyClassB(MyClassA):
                @overrides(MyClassA)
                def operation(self): pass

    def test_overrides_all_good(self):
        class MyClassA:
            def operation(self): pass

        class MyClassB(MyClassA):
            @overrides(MyClassA)
            def operation(self):
                return 42

        b = MyClassB()
        b.operation()

    def test_overrides_static_method(self):
        class MyClassA:
            @staticmethod
            def operation(): pass

        class MyClassB(MyClassA):
            @staticmethod
            @overrides(MyClassA)
            def operation():
                return 42

        b = MyClassB()
        self.assertEqual(b.operation(), 42)
        self.assertEqual(MyClassB.operation(), 42)

    def test_overrides_below_property(self):
        class MyClassA:
            @property
            @abstractmethod
            def operation(self): pass

        class MyClassB(MyClassA):
            @property
            @overrides(MyClassA)   # Note: it does not work the other way around
            def operation(self):
                return 43

        b = MyClassB()
        self.assertEqual(b.operation, 43)

    def test_overrides_function(self):
        class MyClassA:
            pass

        with self.assertRaises(expected_exception=PedanticOverrideException):
            @overrides(MyClassA)
            def operation(): return 42

    def test_deprecated_1(self):
        @deprecated
        def old_method(i: int) -> str: return str(i)

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            old_method(42)
            assert len(w) == 1
            assert issubclass(w[-1].category, DeprecationWarning)
            assert "deprecated" in str(w[-1].message)

    def test_deprecated_2(self):
        def old_method(i: int) -> str:
            return str(i)

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            old_method(42)
            assert not len(w) == 1

    def test_unimplemented(self):
        @unimplemented
        def dirt(i: int) -> str:
            return str(i)

        with self.assertRaises(expected_exception=NotImplementedException):
            dirt(42)

    def test_timer(self):
        @timer
        def operation(i: int) -> str:
            return str(i)

        operation(42)

    def test_count_calls(self):
        @count_calls
        def operation(i: int) -> str:
            return str(i)

        operation(42)

    def test_trace(self):
        def some_method(x, y):
            return x + y

        traced_method = trace(some_method)
        self.assertEqual(some_method(42, 99), traced_method(42, 99))

    def test_trace_if_returns(self):
        def some_method(x, y):
            return x + y
        traced_method = trace_if_returns(100)(some_method)
        self.assertEqual(some_method(42, 99), traced_method(42, 99))
        self.assertEqual(some_method(42, 58), traced_method(42, 58))

    def test_does_same_as_function(self):
        def some_method(x, y, z):
            return x * (y + z)

        @does_same_as_function(some_method)
        def other_method(x, y, z):
            return x * y + x * z

        other_method(1, 2, 3)
        other_method(4, 5, 6)

    def test_does_same_as_function_wrong(self):
        def some_method(x, y, z):
            return x * (y + z)

        @does_same_as_function(some_method)
        def other_method(x, y, z):
            return x * y + z

        other_method(0, 2, 0)
        with self.assertRaises(expected_exception=AssertionError):
            other_method(4, 5, 6)

Ancestors

  • unittest.case.TestCase

Methods

def test_count_calls(self)
Expand source code
def test_count_calls(self):
    @count_calls
    def operation(i: int) -> str:
        return str(i)

    operation(42)
def test_deprecated_1(self)
Expand source code
def test_deprecated_1(self):
    @deprecated
    def old_method(i: int) -> str: return str(i)

    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        old_method(42)
        assert len(w) == 1
        assert issubclass(w[-1].category, DeprecationWarning)
        assert "deprecated" in str(w[-1].message)
def test_deprecated_2(self)
Expand source code
def test_deprecated_2(self):
    def old_method(i: int) -> str:
        return str(i)

    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        old_method(42)
        assert not len(w) == 1
def test_does_same_as_function(self)
Expand source code
def test_does_same_as_function(self):
    def some_method(x, y, z):
        return x * (y + z)

    @does_same_as_function(some_method)
    def other_method(x, y, z):
        return x * y + x * z

    other_method(1, 2, 3)
    other_method(4, 5, 6)
def test_does_same_as_function_wrong(self)
Expand source code
def test_does_same_as_function_wrong(self):
    def some_method(x, y, z):
        return x * (y + z)

    @does_same_as_function(some_method)
    def other_method(x, y, z):
        return x * y + z

    other_method(0, 2, 0)
    with self.assertRaises(expected_exception=AssertionError):
        other_method(4, 5, 6)
def test_overrides_all_good(self)
Expand source code
def test_overrides_all_good(self):
    class MyClassA:
        def operation(self): pass

    class MyClassB(MyClassA):
        @overrides(MyClassA)
        def operation(self):
            return 42

    b = MyClassB()
    b.operation()
def test_overrides_below_property(self)
Expand source code
def test_overrides_below_property(self):
    class MyClassA:
        @property
        @abstractmethod
        def operation(self): pass

    class MyClassB(MyClassA):
        @property
        @overrides(MyClassA)   # Note: it does not work the other way around
        def operation(self):
            return 43

    b = MyClassB()
    self.assertEqual(b.operation, 43)
def test_overrides_function(self)
Expand source code
def test_overrides_function(self):
    class MyClassA:
        pass

    with self.assertRaises(expected_exception=PedanticOverrideException):
        @overrides(MyClassA)
        def operation(): return 42
def test_overrides_parent_has_no_such_method(self)
Expand source code
def test_overrides_parent_has_no_such_method(self):
    class MyClassA:
        pass

    with self.assertRaises(expected_exception=PedanticOverrideException):
        class MyClassB(MyClassA):
            @overrides(MyClassA)
            def operation(self): pass
def test_overrides_static_method(self)
Expand source code
def test_overrides_static_method(self):
    class MyClassA:
        @staticmethod
        def operation(): pass

    class MyClassB(MyClassA):
        @staticmethod
        @overrides(MyClassA)
        def operation():
            return 42

    b = MyClassB()
    self.assertEqual(b.operation(), 42)
    self.assertEqual(MyClassB.operation(), 42)
def test_timer(self)
Expand source code
def test_timer(self):
    @timer
    def operation(i: int) -> str:
        return str(i)

    operation(42)
def test_trace(self)
Expand source code
def test_trace(self):
    def some_method(x, y):
        return x + y

    traced_method = trace(some_method)
    self.assertEqual(some_method(42, 99), traced_method(42, 99))
def test_trace_if_returns(self)
Expand source code
def test_trace_if_returns(self):
    def some_method(x, y):
        return x + y
    traced_method = trace_if_returns(100)(some_method)
    self.assertEqual(some_method(42, 99), traced_method(42, 99))
    self.assertEqual(some_method(42, 58), traced_method(42, 58))
def test_unimplemented(self)
Expand source code
def test_unimplemented(self):
    @unimplemented
    def dirt(i: int) -> str:
        return str(i)

    with self.assertRaises(expected_exception=NotImplementedException):
        dirt(42)