Metadata-Version: 2.1
Name: strongtyping
Version: 1.5.5
Summary: Decorator which checks whether the function is called with the correct type of parameters
Home-page: https://github.com/FelixTheC/strongtyping
Author: FelixTheC
Author-email: fberndt87@gmail.com
License: MIT
Description: [![PyPI version](https://badge.fury.io/py/strongtyping.svg)](https://badge.fury.io/py/strongtyping)
        ![Python application](https://github.com/FelixTheC/strongtyping/workflows/Python%20application/badge.svg)
        ![image](https://codecov.io/gh/FelixTheC/strongtyping/graph/badge.svg)
        
        
        # Strong Typing
        <p>Decorator which <b>checks at Runtime</b> whether the function is called with the correct type of parameters.<br> 
        And <b><em>raises</em> TypeMisMatch</b> if the used parameters in a function call where invalid.</p>
         
        ## Included decorators
        
        | from strongtyping.strong_typing import            | description                           |
        | :-------------                                    | ----------:                           |
        | [match_typing](#getting-started)                  | decorator for a function              |
        | [match_class_typing](#match_class_typing)         | decorator for a class                 |
        | [setter](#setter)                                 | property decorator for a setter function      |
        | [getter_setter](#getter_setter)                   | property decorator for get and setter function|
        
        | from strongtyping.docstring_typing import         | description                           |
        | :-------------                                    | ----------:                           |
        | [match_docstring](#reST-docstrings)               | decorator for a function              |
        | [match_class_docstring](#match_class_docstring)   | decorator for a class                 |
        | [setter](#docstring_typing_setter)                | property decorator for a setter function       |
        | [getter_setter](#docstring_typing_getter_setter)  | property decorator for get and setter function |
        
        ## Configuration
        |                                                   | description                           |
        | :-------------                                    | ----------:                           |
        | [severity_level](#severity_level)                 | set global severity level             |
        
        ## Configuration
        |                                                   | description                           |
        | :-------------                                    | ----------:                           |
        | [severity_level](#severity_level)             | set global severity level             |
        
        ## Additional features
        | from strongtyping.type_namedtuple import          | description                           |
        | :-------------                                    | ----------:                           |
        | [typed_namedtuple](#typed_namedtuple)             | an extension of the original namedtuple|
        
        
        ### The problem:
        - Highlighting
            - __Some__ IDE's will/can highlight that one of the parameters in a function call doesn't match but you can execute the function.
        - Exception??
            - When the call raise an Exception then we know what to do but sometimes we don't get an Exception only a weird result.
        
        ```python
        def multipler(a: int, b: int):
            return a * b
        
        
        product = multipler(3, 4)
        # >>> 12
        
        product_2 = multipler('Hello', 'World') # Will be highlighted in some IDE's
        # >>> TypeError
        
        product_3 = multipler('Hello', 4)
        # >>> 'HelloHelloHelloHello'
        # No Exception but the result isn’t really what we expect
        ```
        ___
        Now we can say that we will check the types in the function body to prevent this.
        ___
        
        ```python
        def multipler(a: int, b: int):
            if isinstance(a, int) and isinstance(b, int):
                return a * b
            ...
        ```
        But when your function needs a lot of different parameters with different types you have to create a lot of noising code.<br>
        And why should we then use typing in our parameters??
        
        ### My solution:
        I created a decorator called <b>@match_typing</b> which will check at runtime if the parameters which will be used when <br>
        calling this function is from the same type as you have defined.<br><br>
        Here are some examples from my tests
        ```python
        # more imports
        from strongtyping.strong_typing import match_typing
        
        @match_typing
        def func_a(a: str, b: int, c: list):
            ...
        
        func_a('1', 2, [i for i in range(5)])
        # >>> True
        
        func_a(1, 2, [i for i in range(5)])
        # >>> will raise a TypeMismatch Exception
        
        @match_typing
        def func_e(a: List[Union[str, int]], b: List[Union[str, int, tuple]]):
            return f'{len(a)}-{len(b)}'
        
        func_e([1, '2', 3, '4'], [5, ('a', 'b'), '10'])
        # >>> '4-3'
        
        func_e([5, ('a', 'b'), '10'], [1, '2', 3, datetime.date])
        # >>> will raise a TypeMismatch Exception
        ```
        > I love python and his freedom but with the new option of adding type hints I wanted to get rid of writing `if isinstance(value, whatever)` in my programs. 
        > 
        >> In a bigger project, it happened that some developers used a tiny IDE and others a more advanced one which highlighted 
         typing issues. And there the trouble began, we had a bug and after a long debugging session we found out that the issue 
         was a wrong type of an argument, it doesn't crash the program but the output was not what anyone of us had expected.  
        > 
        > And that only encouraged me even more to tackle this problem.
        
        
        ## Getting Started
        
        - normal decorator
        ```python
        from strongtyping.strong_typing import match_typing
        
        @match_typing
        def foo_bar(a: str, b: int, c: list):
            ...
        ```
        
        - class method decorator
        ```python
        from strongtyping.strong_typing import match_typing
        
        class Foo:
            ...
            @match_typing
            def foo_bar(self, a: int):
                ...
        ```
        
        - use a mix of typed and untyped parameters but then only the typed parameters are checked on runtime
        ```python
        from strongtyping.strong_typing import match_typing
        
        @match_typing
        def foo_bar(with_type_a: str, without_type_a, with_type_b: list, without_type_b):
            ...
        
        # no exception
        foo_bar('hello', 'world', [1, 2, 3], ('a', 'b'))
        
        # will raise an exception
        foo_bar(123, 'world', [1, 2, 3], ('a', 'b'))
        ```
        
        - add your own exception
        ```python
        from strongtyping.strong_typing import match_typing
        
        class SomeException(Exception):
            pass
        
        @match_typing(excep_raise=SomeException)
        def foo_bar(with_type_a: str, without_type_a, with_type_b: list, without_type_b):
            ...
        ```
        
        - enable internal cache with cache_size = 1
        ```python
        from strongtyping.strong_typing import match_typing
        
        class MyClass:
            pass
        
        @match_typing(cache_size=1)
        def foo_bar(a: tuple, b: MyClass):
            ...
        ```
        
        - disable Exception
            - You can also __disable__ the raise of an __Exception__ and get a __warning instead__ this means your function will <br>
            execute even when the parameters are wrong <b>use only when you know what you're doing</b>
        ```python
        from strongtyping.strong_typing import match_typing
        
        @match_typing(excep_raise=None)
        def multipler(a: int, b: int):
            return a * b
        
        print(multipler('Hello', 4))
        """
        /StrongTyping/strongtyping/strong_typing.py:208: RuntimeWarning: Incorrect parameters: a: <class 'int'>
          warnings.warn(msg, RuntimeWarning)
        HelloHelloHelloHello
        """
        ```
        
        #### At the current state, it will work with
        
        - builtin types like: str, int, tuple etc
        - from typing: 
            - List
            - Tuple
            - Union also nested ( Tuple[Union[str, int], Union[list, tuple]] )
            - Any
            - Dict
            - Set
            - Type
            - Iterator
            - Callable
            - Generator
            - Literal
        - from types:
            - FunctionType
            - MethodType
        - with string types representation like
        
        ```python
        from strongtyping.strong_typing import match_typing
        
        class A:
            @match_typing
            def func_a(self, a: 'A'):
                ...
        ```
        - [Back to top](#strong-typing)
        
        ## match_class_typing
        - this decorator will cover each class function automatically with the __match_typing__ decorator
         
        ```python
        from strongtyping.strong_typing import match_class_typing
        
        @match_class_typing
        class Dummy:
            attr = 100
        
            def a(self, val: int):
                return val * .25
        
            def b(self):
                return 'b'
        
            def c(self):
                return 'c'
        
            def _my_secure_func(self, val: Union[int, float], other: 'Dummy'):
                return val * other.attr
        ```
        - this decorator supports also disabling of raising Exception and internal caching
        ```python
        from strongtyping.strong_typing import match_class_typing
        
        @match_class_typing(excep_raise=None)
        class Dummy:
            attr = 100
        
            def a(self, val: int):
                return val * 3
        
            def b(self):
                return 'b'
        
            def c(self):
                return 'c'
        
            def _my_secure_func(self, val: Union[int, float], other: 'Dummy'):
                return val * other.attr
        
        ```
        - single class methods inside of a allready decorated class can be overwritten with the match_typing decorator
        ```python
        from strongtyping.strong_typing import match_class_typing
        from strongtyping.strong_typing import match_typing
        
        @match_class_typing
        class Dummy:
            attr = 100
        
            @match_typing(excep_raise=None)  # this decorator will be used
            def a(self, val: int):
                return val * 3
        
            def b(self):
                return 'b'
        
            def c(self):
                return 'c'
        
            def _my_secure_func(self, val: Union[int, float], other: 'Dummy'):
                return val * other.attr
        ```
        - [Back to top](#strong-typing)
        
        ## setter
        this decorator can replace your *@foo.setter* from property and check your typing
        - this is an extension of [easy_property](https://github.com/salabim/easy_property)
        ```python
        from strongtyping.strong_typing import getter
        from strongtyping.strong_typing import setter
        
        class Dummy:
            attr = 100
            val = 'foo'
        
            @getter
            def b(self):
                return self.val
        
            @setter
            def b(self, val: str):
                self.val = val
        
        d = Dummy()
        d.b == 'foo'  # will raise AttributeError 
        
        d.b = 'bar'  # works like a charm
        
        d.b = 1  # will raise TypeMisMatch
        ```
        - [Back to top](#strong-typing)
        
        ## getter_setter
        this decorator can replace *@propery* from property and check your typing
        - this is an extension of [easy_property](https://github.com/salabim/easy_property)
        ```python
        from strongtyping.strong_typing import getter_setter
        
        class Dummy:
            attr = 100
        
            @getter_setter  # here you will have all in one place (DRY) 
            def c(self, val: int = None):
                if val is not None:
                    self.attr = val
                return self.attr
        
        d = Dummy()
        d.c == 100  # works like a charm
        
        d.c = 1  # works like a charm
        
        d.c = 'foobar'  # will raise TypeMisMatch
        ```
        - [Back to top](#strong-typing)
        
        ## reST docstrings
        When working with docstrings in reST style format use the decorator __match_docstring__
        ```python
        from strongtyping.docstring_typing import match_docstring
        
        @match_docstring
        def func_a(a):
            """
            :param a:
            :type a: list
            ...
            """
        
        @match_docstring
        def func_a(a, b):
            """
            :param int a: foo
            :vartype b: str
            ...
            """
        
        @match_docstring
        def func_a(a, b):
            """
            :parameter int a: foo
            :argument str b: bar
            ...
            """
        ```
        At the current state, it will work with basically everything which is written here
        https://gist.github.com/jesuGMZ/d83b5e9de7ccc16f71c02adf7d2f3f44
        
        - extended with support for 
            - Iterator
            - Callable
            - Generator
            - FunctionType
            - MethodType
        
        please check __tests/test_typing__ to see what is supported and if something is missing feel free to create an issue.
        - [Back to top](#strong-typing)
        
        ## match_class_docstring
        - this decorator will cover each class function automatically with the __match_docstring__ decorator
        ```python
        from strongtyping.docstring_typing import match_class_docstring
        
        @match_class_docstring
        class Dummy:
            attr = 100
        
            def a(self, val: int):
                """
                :param int val: foo
                """
                return val * .25
        
            def b(self):
                return 'b'
        
            def c(self):
                return 'c'
        
            def _my_secure_func(self, val, other):
                """
                :param val: foo
                :type val: int or float
                :param other: Dummy
                :return:
                """
                return val * other.attr
        ```
        - this decorator supports also disabling of raising Exception and internal caching
        
        ```python
        from strongtyping.docstring_typing import match_class_docstring
        
        @match_class_docstring(excep_raise=None)
        class Dummy:
            attr = 100
        
            def a(self, val: int):
                """
                :param int val: foo
                """
                return val * 5
        
            def b(self):
                return 'b'
        
            def c(self):
                return 'c'
        
            def _my_secure_func(self, val, other):
                """
                :param val: foo
                :type val: int or float
                :param other: this class
                :type other: Dummy
                :return:
                """
                return val * other.attr
        ```
        - single class methods inside of a allready decorated class can be overwritten with the match_docstring decorator
        ```python
        from strongtyping.docstring_typing import match_class_docstring
        from strongtyping.docstring_typing import match_docstring
        
        @match_class_docstring
        class Other:
            attr = 100
        
            def a(self, val: int):
                """
                :param int val: foo
                """
                return val * 2
        
            def b(self):
                return 'b'
        
            def c(self):
                return 'c'
        
            @match_docstring(excep_raise=None)  # this decorator will be used
            def _my_secure_func(self, other):
                """
                :param other: instance of same class
                :type other: Other
                :return:
                """
                return 2 * other.attr
        ```
        - [Back to top](#strong-typing)
        
        ## docstring_typing_setter
        this decorator can replace your *@foo.setter* from property and check your typing
        - this is an extension of [easy_property](https://github.com/salabim/easy_property)
        ```python
        from strongtyping.docstring_typing import getter
        from strongtyping.docstring_typing import setter
        
        class Dummy:
            attr = 100
            val = 'foo'
        
            @getter
            def b(self):
                return self.val
        
            @setter
            def b(self, val): 
                """
                :parameter int val: foo
                """
                self.val = val
        
        d = Dummy()
        d.b == 'foo'  # will raise AttributeError 
        
        d.b = 'bar'  # works like a charm
        
        d.b = 1  # will raise TypeMisMatch
        ```
        - [Back to top](#strong-typing)
        
        ## docstring_typing_getter_setter
        this decorator can replace *@propery* from property and check your typing
        - this is an extension of [easy_property](https://github.com/salabim/easy_property)
        ```python
        from strongtyping.docstring_typing import getter_setter
        
        class Dummy:
            attr = 100
        
            @getter_setter  # here you will have all in one place (DRY) 
            def c(self, val=None):
                """
                :parameter int val: foo
                """
                if val is not None:
                    self.attr = val
                return self.attr
        
        d = Dummy()
        d.c == 100  # works like a charm
        
        d.c = 1  # works like a charm
        
        d.c = 'foobar'  # will raise TypeMisMatch
        ```
        - [Back to top](#strong-typing)
        
        
        ## typed_namedtuple
        
        - from my side it was only logical to create an own version of namedtuple with typing support
        - for typing use the reST-style
        ```python
        from strongtyping.type_namedtuple import typed_namedtuple
        
        Dummy = typed_namedtuple('Dummy', 'spell:str, mana:int or str,effect:list')
        
        Dummy(mana='Lumos', spell=5, effect='Makes light')  # will raise a TypeError
        Dummy(spell='Lumos', mana=5, effect=['Makes light', ])  # works like a charm
        
        ```
        - the same happens also with wrong default values (the typed_namedtuple needs the exact same length)
        ```python
        from strongtyping.type_namedtuple import typed_namedtuple
        
        # will raise a TypeError
        Dummy = typed_namedtuple('Dummy', ['spell:str', 'mana:int', 'effect:list'],  defaults=[0, '', ''])
        
        ```
        - and also when you try to replace an attribute with a wrong type
        ```python
        from strongtyping.type_namedtuple import typed_namedtuple
        Dummy = typed_namedtuple('Dummy', ['spell:str', 'mana:int', 'effect:list'])
        d = Dummy('Lumos', mana=5, effect=['Makes light', ])
        
        d._replace(effect=b'Makes light')  # will raise a TypeError
        
        ```
        
        - it is also possible to use the typing.NamedTuple way for instantiating
        ```python
        from strongtyping.type_namedtuple import typed_namedtuple
        Dummy = typed_namedtuple('Dummy', [('spell', str), ('mana', int), ('effect', Union[list, tuple])])
        
        Dummy('Papyrus Reparo', 10, {1, 2, 3})  # will raise a TypeError
        
        # when using this way you will also have the __annototaions__
        
        print(Dummy.__annotations__)
        # {'spell': <class 'str'>, 'mana': <class 'int'>, 'effect': typing.Union[list, tuple]}
        
        ```
        
        - the docstring will also display the types of the parameter in the reST-style
        ```python
        from strongtyping.type_namedtuple import typed_namedtuple
        Dummy = typed_namedtuple('Dummy', 'spell:str, mana:int or str,effect:list')
        
        print(help(Dummy))
        
        """
        class Dummy(builtins.tuple)
             |  Dummy(*args, **kwargs)
             |  
             |  Dummy(spell, mana, effect)
             |  :type spell: str
             |  :type mana: int or str
             |  :type effect: list
            ...
        """
        ```
        
        - [Back to top](#strong-typing)
        
        ## severity_level
        
        - to set the project wide settings add in your .env file
            - the options are: __'enabled', 'warning', 'disable'__
        ```bash
        ST_SEVERITY='disable'
        ```
        - or place this somewhere in your project
        ```python
        from strongtyping.config import set_severity_level
        from strongtyping.config import SEVERITY_LEVEL
        
        set_severity_level(SEVERITY_LEVEL.WARNING)
        ```
        
        - you can also override the project wide setting for particular classes or functions
        ```python
        from strongtyping.config import SEVERITY_LEVEL
        from strongtyping.strong_typing import match_class_typing
        from strongtyping.strong_typing import match_typing
        
        
        @match_class_typing(severity=SEVERITY_LEVEL.WARNING)
        class OtherDummy:
            ...
        
        
        @match_typing(severity=SEVERITY_LEVEL.ENABLED)
        def a(value: int):
            ...
        ```
        
        - [Back to top](#strong-typing)
        <br>
        
        ## Package
        
        ### Tested for Versions
        - 3.6, 3.7, 3.8, 3.9.0b4
        
        ### Installing
        - pip install strongtyping
        
        #### Versioning
        - For the versions available, see the tags on this repository.
        
        ### Authors
        - Felix Eisenmenger
        
        ### License
        - This project is licensed under the MIT License - see the LICENSE.md file for details
        
        ### Special thanks
        - Thanks to Ruud van der Ham for helping me to improve my code and for his [easy_property](https://github.com/salabim/easy_property) package
        - Thanks to Dan Bader who puts this package into [PyCoder’s Weekly Issue #428 (July 7, 2020)](https://pycoders.com/issues/428)
        - And all how gave me Feedback in the Pythonista Cafe
Platform: UNKNOWN
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.6
Description-Content-Type: text/markdown
