Skip to content

Commit d6517a9

Browse files
refactor @OVERRIDES decorator
1 parent 3bc3440 commit d6517a9

File tree

13 files changed

+622
-92
lines changed

13 files changed

+622
-92
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Changelog
2+
## Pedantic 2.1.6
3+
- Remove `inspect.getsource()` call from `@overrides`
4+
25
## Pedantic 2.1.5
36
- Close `multiprocess.connection.Connection` correctly in `@in_subprocess` decorator
47
- Updated dependencies

docs/pedantic/decorators/fn_deco_overrides.html

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ <h1 class="title">Module <code>pedantic.decorators.fn_deco_overrides</code></h1>
3030

3131
from pedantic.constants import F
3232
from pedantic.exceptions import PedanticOverrideException
33-
from pedantic.models.decorated_function import DecoratedFunction
3433

3534

3635
def overrides(base_class: Type) -&gt; F:
@@ -50,16 +49,12 @@ <h1 class="title">Module <code>pedantic.decorators.fn_deco_overrides</code></h1>
5049
&#34;&#34;&#34;
5150

5251
def decorator(func: F) -&gt; F:
53-
deco_func = DecoratedFunction(func=func)
54-
uses_multiple_decorators = deco_func.num_of_decorators &gt; 1
52+
name = func.__name__
5553

56-
if not deco_func.is_instance_method and not uses_multiple_decorators:
54+
if name not in dir(base_class):
5755
raise PedanticOverrideException(
58-
f&#39;{deco_func.err} Function &#34;{deco_func.name}&#34; should be an instance method of a class!&#39;)
59-
60-
if deco_func.name not in dir(base_class):
61-
raise PedanticOverrideException(
62-
f&#39;{deco_func.err} Base class &#34;{base_class.__name__}&#34; does not have such a method &#34;{deco_func.name}&#34;.&#39;)
56+
f&#39;In function {func.__qualname__}:\n &#39;
57+
f&#39;Base class &#34;{base_class.__name__}&#34; does not have such a method &#34;{name}&#34;.&#39;)
6358
return func
6459
return decorator
6560

@@ -112,16 +107,12 @@ <h2 class="section-title" id="header-functions">Functions</h2>
112107
&#34;&#34;&#34;
113108

114109
def decorator(func: F) -&gt; F:
115-
deco_func = DecoratedFunction(func=func)
116-
uses_multiple_decorators = deco_func.num_of_decorators &gt; 1
117-
118-
if not deco_func.is_instance_method and not uses_multiple_decorators:
119-
raise PedanticOverrideException(
120-
f&#39;{deco_func.err} Function &#34;{deco_func.name}&#34; should be an instance method of a class!&#39;)
110+
name = func.__name__
121111

122-
if deco_func.name not in dir(base_class):
112+
if name not in dir(base_class):
123113
raise PedanticOverrideException(
124-
f&#39;{deco_func.err} Base class &#34;{base_class.__name__}&#34; does not have such a method &#34;{deco_func.name}&#34;.&#39;)
114+
f&#39;In function {func.__qualname__}:\n &#39;
115+
f&#39;Base class &#34;{base_class.__name__}&#34; does not have such a method &#34;{name}&#34;.&#39;)
125116
return func
126117
return decorator</code></pre>
127118
</details>

docs/pedantic/decorators/fn_deco_retry.html

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,17 @@ <h1 class="title">Module <code>pedantic.decorators.fn_deco_retry</code></h1>
3131
from datetime import timedelta
3232
from functools import wraps
3333
from logging import Logger
34-
from typing import Callable, TypeVar, TypeVarTuple, Any
34+
from typing import Callable, TypeVar, Any, ParamSpec
3535

3636
C = TypeVar(&#39;C&#39;, bound=Callable)
37-
Ts = TypeVarTuple(&#39;Ts&#39;)
37+
P = ParamSpec(&#39;P&#39;)
38+
R = TypeVar(&#39;R&#39;)
3839

3940

4041
def retry(
4142
*,
4243
attempts: int,
43-
exceptions: type[Exception] | tuple[type[Exception], ...] = None,
44+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
4445
sleep_time: timedelta = timedelta(seconds=0),
4546
logger: Logger = None,
4647
) -&gt; Callable[[C], C]:
@@ -61,28 +62,46 @@ <h1 class="title">Module <code>pedantic.decorators.fn_deco_retry</code></h1>
6162
&gt;&gt;&gt; foo()
6263
&#34;&#34;&#34;
6364

64-
if exceptions is None:
65-
exceptions = Exception
65+
def decorator(func: C) -&gt; C:
66+
@wraps(func)
67+
def wrapper(*args, **kwargs) -&gt; Any:
68+
return retry_func(
69+
func,
70+
*args,
71+
attempts=attempts,
72+
exceptions=exceptions,
73+
sleep_time=sleep_time,
74+
logger=logger,
75+
**kwargs,
76+
)
77+
return wrapper
78+
return decorator
79+
80+
81+
def retry_func(
82+
func: Callable[P, R],
83+
*args: P.args,
84+
attempts: int,
85+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
86+
sleep_time: timedelta = timedelta(seconds=0),
87+
logger: Logger = None,
88+
**kwargs: P.kwargs,
89+
) -&gt; R:
90+
attempt = 1
6691

6792
if logger is None:
6893
logger = logging.getLogger()
6994

70-
def decorator(func: C) -&gt; C:
71-
@wraps(func)
72-
def wrapper(*args, **kwargs) -&gt; Any:
73-
attempt = 1
74-
75-
while attempt &lt; attempts:
76-
try:
77-
return func(*args, **kwargs)
78-
except exceptions:
79-
logger.warning(f&#39;Exception thrown when attempting to run {func.__name__}, &#39;
80-
f&#39;attempt {attempt} of {attempts}&#39;)
81-
attempt += 1
82-
time.sleep(sleep_time.total_seconds())
95+
while attempt &lt; attempts:
96+
try:
8397
return func(*args, **kwargs)
84-
return wrapper
85-
return decorator</code></pre>
98+
except exceptions:
99+
logger.warning(f&#39;Exception thrown when attempting to run {func.__name__}, &#39;
100+
f&#39;attempt {attempt} of {attempts}&#39;)
101+
attempt += 1
102+
time.sleep(sleep_time.total_seconds())
103+
104+
return func(*args, **kwargs)</code></pre>
86105
</details>
87106
</section>
88107
<section>
@@ -93,7 +112,7 @@ <h1 class="title">Module <code>pedantic.decorators.fn_deco_retry</code></h1>
93112
<h2 class="section-title" id="header-functions">Functions</h2>
94113
<dl>
95114
<dt id="pedantic.decorators.fn_deco_retry.retry"><code class="name flex">
96-
<span>def <span class="ident">retry</span></span>(<span>*, attempts: int, exceptions: type[Exception] | tuple[type[Exception], ...] = None, sleep_time: datetime.timedelta = datetime.timedelta(0), logger: logging.Logger = None) ‑> Callable[[~C], ~C]</span>
115+
<span>def <span class="ident">retry</span></span>(<span>*, attempts: int, exceptions: type[Exception] | tuple[type[Exception], ...] = builtins.Exception, sleep_time: datetime.timedelta = datetime.timedelta(0), logger: logging.Logger = None) ‑> Callable[[~C], ~C]</span>
97116
</code></dt>
98117
<dd>
99118
<div class="desc"><p>Retries the wrapped function/method <code>attempts</code> times if the exceptions listed
@@ -116,7 +135,7 @@ <h2 id="example">Example</h2>
116135
<pre><code class="python">def retry(
117136
*,
118137
attempts: int,
119-
exceptions: type[Exception] | tuple[type[Exception], ...] = None,
138+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
120139
sleep_time: timedelta = timedelta(seconds=0),
121140
logger: Logger = None,
122141
) -&gt; Callable[[C], C]:
@@ -137,30 +156,57 @@ <h2 id="example">Example</h2>
137156
&gt;&gt;&gt; foo()
138157
&#34;&#34;&#34;
139158

140-
if exceptions is None:
141-
exceptions = Exception
142-
143-
if logger is None:
144-
logger = logging.getLogger()
145-
146159
def decorator(func: C) -&gt; C:
147160
@wraps(func)
148161
def wrapper(*args, **kwargs) -&gt; Any:
149-
attempt = 1
150-
151-
while attempt &lt; attempts:
152-
try:
153-
return func(*args, **kwargs)
154-
except exceptions:
155-
logger.warning(f&#39;Exception thrown when attempting to run {func.__name__}, &#39;
156-
f&#39;attempt {attempt} of {attempts}&#39;)
157-
attempt += 1
158-
time.sleep(sleep_time.total_seconds())
159-
return func(*args, **kwargs)
162+
return retry_func(
163+
func,
164+
*args,
165+
attempts=attempts,
166+
exceptions=exceptions,
167+
sleep_time=sleep_time,
168+
logger=logger,
169+
**kwargs,
170+
)
160171
return wrapper
161172
return decorator</code></pre>
162173
</details>
163174
</dd>
175+
<dt id="pedantic.decorators.fn_deco_retry.retry_func"><code class="name flex">
176+
<span>def <span class="ident">retry_func</span></span>(<span>func: Callable[~P, ~R], *args: P.args, attempts: int, exceptions: type[Exception] | tuple[type[Exception], ...] = builtins.Exception, sleep_time: datetime.timedelta = datetime.timedelta(0), logger: logging.Logger = None, **kwargs: P.kwargs) ‑> ~R</span>
177+
</code></dt>
178+
<dd>
179+
<div class="desc"></div>
180+
<details class="source">
181+
<summary>
182+
<span>Expand source code</span>
183+
</summary>
184+
<pre><code class="python">def retry_func(
185+
func: Callable[P, R],
186+
*args: P.args,
187+
attempts: int,
188+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
189+
sleep_time: timedelta = timedelta(seconds=0),
190+
logger: Logger = None,
191+
**kwargs: P.kwargs,
192+
) -&gt; R:
193+
attempt = 1
194+
195+
if logger is None:
196+
logger = logging.getLogger()
197+
198+
while attempt &lt; attempts:
199+
try:
200+
return func(*args, **kwargs)
201+
except exceptions:
202+
logger.warning(f&#39;Exception thrown when attempting to run {func.__name__}, &#39;
203+
f&#39;attempt {attempt} of {attempts}&#39;)
204+
attempt += 1
205+
time.sleep(sleep_time.total_seconds())
206+
207+
return func(*args, **kwargs)</code></pre>
208+
</details>
209+
</dd>
164210
</dl>
165211
</section>
166212
<section>
@@ -180,6 +226,7 @@ <h1>Index</h1>
180226
<li><h3><a href="#header-functions">Functions</a></h3>
181227
<ul class="">
182228
<li><code><a title="pedantic.decorators.fn_deco_retry.retry" href="#pedantic.decorators.fn_deco_retry.retry">retry</a></code></li>
229+
<li><code><a title="pedantic.decorators.fn_deco_retry.retry_func" href="#pedantic.decorators.fn_deco_retry.retry_func">retry_func</a></code></li>
183230
</ul>
184231
</li>
185232
</ul>

docs/pedantic/decorators/fn_deco_validate/fn_deco_validate.html

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -398,23 +398,38 @@ <h2 class="section-title" id="header-classes">Classes</h2>
398398
</code></pre>
399399
<p>Access them by:</p>
400400
<ul>
401-
<li>attribute access::</li>
401+
<li>attribute access:</li>
402402
</ul>
403-
<pre><code class="language-python-repl">&gt;&gt;&gt; Color.RED
404-
&lt;Color.RED: 1&gt;
405-
</code></pre>
403+
<blockquote>
404+
<blockquote>
405+
<blockquote>
406+
<p>Color.RED
407+
<Color.RED: 1></p>
408+
</blockquote>
409+
</blockquote>
410+
</blockquote>
406411
<ul>
407412
<li>value lookup:</li>
408413
</ul>
409-
<pre><code class="language-python-repl">&gt;&gt;&gt; Color(1)
410-
&lt;Color.RED: 1&gt;
411-
</code></pre>
414+
<blockquote>
415+
<blockquote>
416+
<blockquote>
417+
<p>Color(1)
418+
<Color.RED: 1></p>
419+
</blockquote>
420+
</blockquote>
421+
</blockquote>
412422
<ul>
413423
<li>name lookup:</li>
414424
</ul>
415-
<pre><code class="language-python-repl">&gt;&gt;&gt; Color['RED']
416-
&lt;Color.RED: 1&gt;
417-
</code></pre>
425+
<blockquote>
426+
<blockquote>
427+
<blockquote>
428+
<p>Color['RED']
429+
<Color.RED: 1></p>
430+
</blockquote>
431+
</blockquote>
432+
</blockquote>
418433
<p>Enumerations can be iterated over, and know how many members they have:</p>
419434
<pre><code class="language-python-repl">&gt;&gt;&gt; len(Color)
420435
3

docs/pedantic/decorators/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ <h1 class="title">Module <code>pedantic.decorators</code></h1>
3636
from .fn_deco_pedantic import pedantic, pedantic_require_docstring
3737
from .fn_deco_rename_kwargs import rename_kwargs, Rename
3838
from .fn_deco_require_kwargs import require_kwargs
39-
from .fn_deco_retry import retry
39+
from .fn_deco_retry import retry, retry_func
4040
from .fn_deco_timer import timer
4141
from .fn_deco_trace import trace
4242
from .fn_deco_trace_if_returns import trace_if_returns

docs/pedantic/models/decorated_function.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ <h1 class="title">Module <code>pedantic.models.decorated_function</code></h1>
5656

5757
self._full_arg_spec = inspect.getfullargspec(func)
5858
self._signature = inspect.signature(func)
59-
self._err = f&#39;In function {func.__qualname__}:&#39; + &#39;\n&#39;
59+
self._err = f&#39;In function {func.__qualname__}:\n&#39;
6060
self._source: str = inspect.getsource(object=func)
6161

6262
if IS_DOCSTRING_PARSER_INSTALLED:
@@ -185,7 +185,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
185185

186186
self._full_arg_spec = inspect.getfullargspec(func)
187187
self._signature = inspect.signature(func)
188-
self._err = f&#39;In function {func.__qualname__}:&#39; + &#39;\n&#39;
188+
self._err = f&#39;In function {func.__qualname__}:\n&#39;
189189
self._source: str = inspect.getsource(object=func)
190190

191191
if IS_DOCSTRING_PARSER_INSTALLED:

0 commit comments

Comments
 (0)