Module pedantic.models.decorated_function
Expand source code
import inspect
import re
import types
from typing import Any, Callable, Dict, Optional
try:
from docstring_parser import parse, Docstring
IS_DOCSTRING_PARSER_INSTALLED = True
except ImportError:
IS_DOCSTRING_PARSER_INSTALLED = False
Docstring = None
parse = None
from pedantic.exceptions import PedanticTypeCheckException
FUNCTIONS_THAT_REQUIRE_KWARGS = [
'__new__', '__init__', '__str__', '__del__', '__int__', '__float__', '__complex__', '__oct__', '__hex__',
'__index__', '__trunc__', '__repr__', '__unicode__', '__hash__', '__nonzero__', '__dir__', '__sizeof__'
]
class DecoratedFunction:
def __init__(self, func: Callable[..., Any]) -> None:
self._func = func
if not isinstance(func, (types.FunctionType, types.MethodType)):
raise PedanticTypeCheckException(f'{self.full_name} should be a method or function.')
self._full_arg_spec = inspect.getfullargspec(func)
self._signature = inspect.signature(func)
self._err = f'In function {func.__qualname__}:\n'
self._source: str = inspect.getsource(object=func)
if IS_DOCSTRING_PARSER_INSTALLED:
self._docstring = parse(func.__doc__)
else: # pragma: no cover
self._docstring = None
@property
def func(self) -> Callable[..., Any]:
return self._func
@property
def annotations(self) -> Dict[str, Any]:
return self._full_arg_spec.annotations
@property
def docstring(self) -> Optional[Docstring]:
"""
Returns the docstring if the docstring-parser package is installed else None.
See also https://pypi.org/project/docstring-parser/
"""
return self._docstring
@property
def raw_doc(self) -> Optional[str]:
return self._func.__doc__
@property
def signature(self) -> inspect.Signature:
return self._signature
@property
def err(self) -> str:
return self._err
@property
def source(self) -> str:
return self._source
@property
def name(self) -> str:
return self._func.__name__
@property
def full_name(self) -> str:
return self._func.__qualname__
@property
def is_static_method(self) -> bool:
""" I honestly have no idea how to do this better :( """
return '@staticmethod' in self.source
@property
def wants_args(self) -> bool:
return '*args' in self.source
@property
def is_property_setter(self) -> bool:
return f'@{self.name}.setter' in self.source
@property
def should_have_kwargs(self) -> bool:
if self.is_property_setter or self.wants_args:
return False
elif not self.name.startswith('__') or not self.name.endswith('__'):
return True
return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS
@property
def is_instance_method(self) -> bool:
return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self'
@property
def is_class_method(self) -> bool:
"""
Returns true if the function is decoratorated with the @classmethod decorator.
See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod
"""
return inspect.ismethod(self._func)
@property
def num_of_decorators(self) -> int:
return len(re.findall('@', self.source.split('def')[0]))
@property
def is_pedantic(self) -> bool:
return '@pedantic' in self.source or '@require_kwargs' in self.source
@property
def is_coroutine(self) -> bool:
return inspect.iscoroutinefunction(self._func)
@property
def is_generator(self) -> bool:
return inspect.isgeneratorfunction(self._func)
Classes
class DecoratedFunction (func: Callable[..., Any])
-
Expand source code
class DecoratedFunction: def __init__(self, func: Callable[..., Any]) -> None: self._func = func if not isinstance(func, (types.FunctionType, types.MethodType)): raise PedanticTypeCheckException(f'{self.full_name} should be a method or function.') self._full_arg_spec = inspect.getfullargspec(func) self._signature = inspect.signature(func) self._err = f'In function {func.__qualname__}:\n' self._source: str = inspect.getsource(object=func) if IS_DOCSTRING_PARSER_INSTALLED: self._docstring = parse(func.__doc__) else: # pragma: no cover self._docstring = None @property def func(self) -> Callable[..., Any]: return self._func @property def annotations(self) -> Dict[str, Any]: return self._full_arg_spec.annotations @property def docstring(self) -> Optional[Docstring]: """ Returns the docstring if the docstring-parser package is installed else None. See also https://pypi.org/project/docstring-parser/ """ return self._docstring @property def raw_doc(self) -> Optional[str]: return self._func.__doc__ @property def signature(self) -> inspect.Signature: return self._signature @property def err(self) -> str: return self._err @property def source(self) -> str: return self._source @property def name(self) -> str: return self._func.__name__ @property def full_name(self) -> str: return self._func.__qualname__ @property def is_static_method(self) -> bool: """ I honestly have no idea how to do this better :( """ return '@staticmethod' in self.source @property def wants_args(self) -> bool: return '*args' in self.source @property def is_property_setter(self) -> bool: return f'@{self.name}.setter' in self.source @property def should_have_kwargs(self) -> bool: if self.is_property_setter or self.wants_args: return False elif not self.name.startswith('__') or not self.name.endswith('__'): return True return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS @property def is_instance_method(self) -> bool: return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self' @property def is_class_method(self) -> bool: """ Returns true if the function is decoratorated with the @classmethod decorator. See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod """ return inspect.ismethod(self._func) @property def num_of_decorators(self) -> int: return len(re.findall('@', self.source.split('def')[0])) @property def is_pedantic(self) -> bool: return '@pedantic' in self.source or '@require_kwargs' in self.source @property def is_coroutine(self) -> bool: return inspect.iscoroutinefunction(self._func) @property def is_generator(self) -> bool: return inspect.isgeneratorfunction(self._func)
Instance variables
var annotations : Dict[str, Any]
-
Expand source code
@property def annotations(self) -> Dict[str, Any]: return self._full_arg_spec.annotations
var docstring : Optional[docstring_parser.common.Docstring]
-
Returns the docstring if the docstring-parser package is installed else None. See also https://pypi.org/project/docstring-parser/
Expand source code
@property def docstring(self) -> Optional[Docstring]: """ Returns the docstring if the docstring-parser package is installed else None. See also https://pypi.org/project/docstring-parser/ """ return self._docstring
var err : str
-
Expand source code
@property def err(self) -> str: return self._err
var full_name : str
-
Expand source code
@property def full_name(self) -> str: return self._func.__qualname__
var func : Callable[..., Any]
-
Expand source code
@property def func(self) -> Callable[..., Any]: return self._func
var is_class_method : bool
-
Returns true if the function is decoratorated with the @classmethod decorator. See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod
Expand source code
@property def is_class_method(self) -> bool: """ Returns true if the function is decoratorated with the @classmethod decorator. See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod """ return inspect.ismethod(self._func)
var is_coroutine : bool
-
Expand source code
@property def is_coroutine(self) -> bool: return inspect.iscoroutinefunction(self._func)
var is_generator : bool
-
Expand source code
@property def is_generator(self) -> bool: return inspect.isgeneratorfunction(self._func)
var is_instance_method : bool
-
Expand source code
@property def is_instance_method(self) -> bool: return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self'
var is_pedantic : bool
-
Expand source code
@property def is_pedantic(self) -> bool: return '@pedantic' in self.source or '@require_kwargs' in self.source
var is_property_setter : bool
-
Expand source code
@property def is_property_setter(self) -> bool: return f'@{self.name}.setter' in self.source
var is_static_method : bool
-
I honestly have no idea how to do this better :(
Expand source code
@property def is_static_method(self) -> bool: """ I honestly have no idea how to do this better :( """ return '@staticmethod' in self.source
var name : str
-
Expand source code
@property def name(self) -> str: return self._func.__name__
var num_of_decorators : int
-
Expand source code
@property def num_of_decorators(self) -> int: return len(re.findall('@', self.source.split('def')[0]))
var raw_doc : Optional[str]
-
Expand source code
@property def raw_doc(self) -> Optional[str]: return self._func.__doc__
var should_have_kwargs : bool
-
Expand source code
@property def should_have_kwargs(self) -> bool: if self.is_property_setter or self.wants_args: return False elif not self.name.startswith('__') or not self.name.endswith('__'): return True return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS
var signature : inspect.Signature
-
Expand source code
@property def signature(self) -> inspect.Signature: return self._signature
var source : str
-
Expand source code
@property def source(self) -> str: return self._source
var wants_args : bool
-
Expand source code
@property def wants_args(self) -> bool: return '*args' in self.source