Metadata-Version: 2.1
Name: decoratorutilities
Version: 1.0.2
Summary: Python library to user type guard utilities to check parameters and return type, allow function overloading and function mocking at runtime
Home-page: https://github.com/Symone95/decoratorutilities
Author: Scalamandrè Simone, Giovanni Cardamone
Author-email: simone.scalamandre@sourcesense.com, giovanni.cardamone@sourcesense.com
License: UNKNOWN
Download-URL: https://pypi.org/project/decoratorutilities/#files
Description: # DecoratorUtilities
        
        ### Readthedocs Reference
        
        Please read our documentation here: [Readthedocs Reference](https://decoratorutilities.readthedocs.io/en/dev/)
        
        ### Package Reference
        
        Our package reference link is: https://pypi.org/project/decoratorutilities
        
        ## Menu
        
        - [Intro](#intro)
        - [Installation](#installation)
        - [Decorators](#decorators)
            - [Check Type Decorator](#check_type_decorator)
            - [Overloading Decorator](#overloading_decorator)
            - [Mocking Decorator](#mocking-decorator)
            - [Memoized Decorator](#memoized-decorator)
            - [Timeit Decorator](#timeit-decorator)
            - [Singleton Decorator](#singleton-decorator)
        
        ## Intro
        DecoratorUtilities is a python library that provides different utilities for functions and class methods such as
        to check parameters and return type, allow overloading, to cache results to speed up them, instantiate a Singleton object
        and mocking at runtime
        
        ## Installation
        
        ```bash
        pip install decoratorutilities
        ```
        
        ## Decorators
        
        ### Check Type Decorator
        
        Decorate your own functions with **@checktype** decorator to check parameters type and return type too
        **Example:**
        
        ```python
        from decoratorutilities import checktype
        import pytest
        
        @checktype
        def my_functon(a: int, b: int) -> int:
            return 1
        
        # Valid usage: Integer parameters and return type
        my_functon(5, 6)  # return 1
        assert my_functon(5, 6) == 1  # True
        
        # Invalid usage: String parameters and return type
        with pytest.raises(TypeError):
            my_functon("5", "6")  # Raises TypeError Exception
        with pytest.raises(TypeError):
            my_functon("invalid", b="Invalid")  # Raises TypeError Exception
        with pytest.raises(TypeError):
            my_functon(a="invalid", b="Invalid")  # Raises TypeError Exception
        with pytest.raises(TypeError):
            assert my_functon(5, 6) == "1"  # Raises TypeError Exception
        ```
        
        Decorate your own class methods with **@checktype** decorator to check parameters type and return type too
        **Example:**
        
        ```python
        from decoratorutilities import checktype
        import pytest
        
        class X(object):
        
            @checktype  # checktype decorator for classes methods
            def my_function(self, value: int):
                return value
        
        # Valid usage: Integer parameters and return type
        assert X().my_function(1) == 1  # True
        
        # Invalid usage: String parameters and return type
        with pytest.raises(TypeError):
            X().my_function('1')  # Raises TypeError Exception
        with pytest.raises(TypeError):
            X().my_function(1) == "1"  # Raises TypeError Exception
        ```
        
        ### Overloading Decorator
        
        Decorate your own function with **@overload** decorator to define multiple functions with same name but with different parameters  
        **Example:**
        
        ```python
        from decoratorutilities import overload
        
        @overload
        def my_functon(a:int):
            return 1
        
        @overload
        def my_functon(a:str):
            return 2
        
        # Invoke first my_functon and return 1
        my_functon(1)
        # Invoke second my_functon and return 2
        my_functon('1')
        ```
        
        Decorate your own class method with **@overload** decorator to define multiple class methods with same name but with different parameters  
        **Example:**
        
        ```python
        from decoratorutilities import overload
        
        class X(object):
            @overload
            def x(self, x: int):
                return int
        
            @overload
            def x(self, x: str):
                return str
        
        assert X().x(1) == int  # True
        assert X().x('1') == str  # True
        ```
        
        
        ### Mocking Decorator
        
        Decorate your own function with **@mocking** decorator to mock that function adding args in a tuple, kwargs in a dict and return value  
        **Example:**
        
        ```python
        from decoratorutilities import mocking
        
        # Define args tuple, kwargs dict and return value
        @mocking([
           ((1, 2, 3), {"a": 1}, 1),
           ((4, 5, 6), {"b": 2}, 2)
        ])
        def a():
           pass
        
        # Valid usage
        assert a(1, 2, 3, a=1) == 1  # return 1
        assert a(4, 5, 6, b=2) == 2  # return 2
        
        # Invalid usage
        assert a(7, 8, 9, c=1) == 1  # Raises KeyError Exception
        ```
        
        ### Memoized Decorator
        
        Decorate your own function or class method with **@memoized** decorator to speed up it by storing the results and returning the cached result when the same inputs occur again  
        **Example:**
        
        ```python
        from decoratorutilities import memoized
        import datetime
        
        def util_run_function_with_time(fn, args, kwargs):
            start_time = datetime.datetime.now()
            tmp = fn(*args, **kwargs)
            end_time = datetime.datetime.now()
            return (end_time - start_time), tmp
        
        @memoized
        def memoized_fibonacci(x):
            if x == 0:
                return 0
        
            if x == 1:
                return 1
        
            return memoized_fibonacci(x - 1) + memoized_fibonacci(x - 2)
        
        def fibonacci(x):
            if x == 0:
                return 0
        
            if x == 1:
                return 1
        
            return fibonacci(x - 1) + fibonacci(x - 2)
        
        fib_value = 20
        memoized_execution_time, memoized_value = util_run_function_with_time(memoized_fibonacci, (fib_value, ), {})  # Return execution time and value for memoized function
        unmemoized_execution_time, unmemoized_value = util_run_function_with_time(fibonacci, (fib_value, ), {})  # Return execution time and value for unmemoized function
        
        print(f"memoized_execution_time: {memoized_execution_time} - unmemoized_execution_time: {unmemoized_execution_time}")
        
        assert memoized_execution_time < unmemoized_execution_time  # OK
        assert memoized_value == unmemoized_value  # OK
        ```   
        
        ### Timeit Decorator
        
        Decorate your own function with **@timeit** decorator to monitoring execution time  
        **Example:**
        
        ```python
        from decoratorutilities import timeit
        import time
        
        
        @timeit
        def hello():
            time.sleep(0.1)
        
        
        if __name__ == "__main__":
            hello()  # print "Execution time: 100.75 ms"
        ```
        
        
        ### Debug Decorator
        
        Decorate your own function with **@debug** decorator to print in console more Exception details  
        **Example:**
        
        ```python
        from decoratorutilities import debug
        import pytest
        
        @debug
        def a():
            message = "Hello " + 5
            return message
        
        with pytest.raises(TypeError):
            a() # Print in console: Found "<class 'TypeError'>" Exception in file "('../tests', 'test_debug.py')" on line "9"
                # Error message: "can only concatenate str (not "int") to str"
        ```
        
        Decorate your own class methods with **@debug** decorator to print in console more Exception details  
        **Example:**
        
        ```python
        from decoratorutilities import debug
        import pytest
        
        class A(object):
        
            @debug
            def __init__(self):
                self.message = "Hello " + 5
        
        with pytest.raises(TypeError):
            A()  # Raises TypeError Exception
        ```
        
        ### Singleton Decorator
        
        Decorate your own classes with **@singleton()** decorator to ensure that only one instance of the singleton class ever exists.
        Never invoke **@singleton()** decorator without brackets otherwise it will cause problems
        Define your class method `__init__()` without parameters, pass them to the **@singleton()** decorator
        
        **Example with args and kwargs**
        
        ```python
        import pytest
        from decoratorutilities import singleton
        
        @singleton(10, message="Message to send", email=["simone.scalamandre95@gmail.com"])
        class A(object):
            def __init__(self):
                self.x = 50  # Define constant class attribute
        
            def print_hello(self):  # Custom method
                return "Hello World"
        
        # Valid usage
        assert A[0] == 10  # True -> Get first arg
        assert A.x == 50  # True -> Get decorated class attribute
        assert A.print_hello() == "Hello World"  # True -> Get decorated class method "print_hello()"
        assert A.message == "Message to send"  # True -> Get kwarg "message" passed to Singleton decorator
        assert A.email == ["simone.scalamandre95@gmail.com"]  # True
        
        with pytest.raises(TypeError):
            # Invalid usage, brackets are missing
            @singleton
            class B(object):
                def __init__(self):
                    self.x = 10
        
            B()  # Raises TypeError Exception
        ```
        
        We can define our singleton class with or without args and kwargs parameters but we can only instantiate one
        **Example**
        
        ```python
        import pytest
        from decoratorutilities import singleton
        
        @singleton()
        class A(object):
            def __init__(self):
                pass
        
        @singleton(x=10)
        class B(object):
            def __init__(self):
                pass
        
        with pytest.raises(TypeError) as e:
            A()  # Raises TypeError Exception
        
        with pytest.raises(TypeError):
            B()  # Raises TypeError Exception
        ```
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.7
Description-Content-Type: text/markdown
