• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LostInDarkMath / pedantic-python-decorators / 22019841150

14 Feb 2026 03:28PM UTC coverage: 99.793% (+0.7%) from 99.14%
22019841150

Pull #115

github

LostInDarkMath
CI: added a check that CHANGELOG.md is modified on feature branches
Pull Request #115: V3: remove unused decorators

268 of 268 branches covered (100.0%)

Branch coverage included in aggregate %.

102 of 102 new or added lines in 15 files covered. (100.0%)

2 existing lines in 2 files now uncovered.

1663 of 1667 relevant lines covered (99.76%)

3.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.07
/pedantic/models/decorated_function.py
1
import inspect
4✔
2
import re
4✔
3
from typing import Any, Callable, Dict, Optional
4✔
4

5
try:
4✔
6
    from docstring_parser import parse, Docstring
4✔
7
    IS_DOCSTRING_PARSER_INSTALLED = True
4✔
8
except ImportError:
9
    IS_DOCSTRING_PARSER_INSTALLED = False
10
    Docstring = None
11
    parse = None
12

13
from pedantic.exceptions import PedanticTypeCheckException
4✔
14

15
FUNCTIONS_THAT_REQUIRE_KWARGS = [
4✔
16
    '__new__', '__init__', '__str__', '__del__', '__int__', '__float__', '__complex__', '__oct__', '__hex__',
17
    '__index__', '__trunc__', '__repr__', '__unicode__', '__hash__', '__nonzero__', '__dir__', '__sizeof__'
18
]
19

20

21
class DecoratedFunction:
4✔
22
    def __init__(self, func: Callable[..., Any]) -> None:
4✔
23
        self._func = func
4✔
24

25
        if not callable(func):
4✔
UNCOV
26
            raise PedanticTypeCheckException(f'{self.full_name} should be a method or function.')
×
27

28
        self._full_arg_spec = inspect.getfullargspec(func)
4✔
29
        self._signature = inspect.signature(func)
4✔
30
        self._err = f'In function {self.full_name}:\n'
4✔
31

32
        try:
4✔
33
            source = inspect.getsource(object=func)
4✔
34
        except TypeError:
4✔
35
            source = None
4✔
36

37
        self._source: str | None = source
4✔
38

39
        if IS_DOCSTRING_PARSER_INSTALLED:
4✔
40
            self._docstring = parse(func.__doc__)
4✔
41
        else:  # pragma: no cover
42
            self._docstring = None
43

44
    @property
4✔
45
    def func(self) -> Callable[..., Any]:
4✔
46
        return self._func
4✔
47

48
    @property
4✔
49
    def annotations(self) -> Dict[str, Any]:
4✔
50
        return self._full_arg_spec.annotations
4✔
51

52
    @property
4✔
53
    def docstring(self) -> Optional[Docstring]:
4✔
54
        """
55
            Returns the docstring if the docstring-parser package is installed else None.
56
            See also https://pypi.org/project/docstring-parser/
57
        """
58

59
        return self._docstring
4✔
60

61
    @property
4✔
62
    def raw_doc(self) -> Optional[str]:
4✔
63
        return self._func.__doc__
4✔
64

65
    @property
4✔
66
    def signature(self) -> inspect.Signature:
4✔
67
        return self._signature
4✔
68

69
    @property
4✔
70
    def err(self) -> str:
4✔
71
        return self._err
4✔
72

73
    @property
4✔
74
    def source(self) -> str:
4✔
75
        return self._source
4✔
76

77
    @property
4✔
78
    def name(self) -> str:
4✔
79
        if hasattr(self._func, '__name__'):
4✔
80
            return self._func.__name__
4✔
81

82
        return self._func.func.__name__
4✔
83

84
    @property
4✔
85
    def full_name(self) -> str:
4✔
86
        if hasattr(self._func, '__qualname__'):
4✔
87
            return self._func.__qualname__
4✔
88

89
        return self._func.func.__qualname__
4✔
90

91
    @property
4✔
92
    def is_static_method(self) -> bool:
4✔
93
        """ I honestly have no idea how to do this better :( """
94

95
        if self.source is None:
4✔
96
            return False
4✔
97

98
        return '@staticmethod' in self.source
4✔
99

100
    @property
4✔
101
    def wants_args(self) -> bool:
4✔
102
        if self.source is None:
4✔
103
            return False
4✔
104

105
        return '*args' in self.source
4✔
106

107
    @property
4✔
108
    def is_property_setter(self) -> bool:
4✔
109
        if self.source is None:
4✔
110
            return False
4✔
111

112
        return f'@{self.name}.setter' in self.source
4✔
113

114
    @property
4✔
115
    def should_have_kwargs(self) -> bool:
4✔
116
        if self.is_property_setter or self.wants_args:
4✔
117
            return False
4✔
118
        elif not self.name.startswith('__') or not self.name.endswith('__'):
4✔
119
            return True
4✔
120
        return self.name in FUNCTIONS_THAT_REQUIRE_KWARGS
4✔
121

122
    @property
4✔
123
    def is_instance_method(self) -> bool:
4✔
124
        return self._full_arg_spec.args != [] and self._full_arg_spec.args[0] == 'self'
4✔
125

126
    @property
4✔
127
    def is_class_method(self) -> bool:
4✔
128
        """
129
            Returns true if the function is decoratorated with the @classmethod decorator.
130
            See also: https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod
131
        """
132

133
        return inspect.ismethod(self._func)
4✔
134

135
    @property
4✔
136
    def num_of_decorators(self) -> int:
4✔
137
        if self.source is None:
4✔
138
            return 0
4✔
139

140
        return len(re.findall('@', self.source.split('def')[0]))
4✔
141

142
    @property
4✔
143
    def is_pedantic(self) -> bool:
4✔
144
        if self.source is None:
4✔
145
            return False
4✔
146

147
        return '@pedantic' in self.source or '@require_kwargs' in self.source
4✔
148

149
    @property
4✔
150
    def is_coroutine(self) -> bool:
4✔
151
        return inspect.iscoroutinefunction(self._func)
4✔
152

153
    @property
4✔
154
    def is_generator(self) -> bool:
4✔
155
        return inspect.isgeneratorfunction(self._func)
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc