Skip to content

Commit 6be03d6

Browse files
add transformation parameter to create_decorator to make adding custom behavior easier
1 parent 1b15782 commit 6be03d6

File tree

10 files changed

+296
-252
lines changed

10 files changed

+296
-252
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.7
3+
- add `transformation` parameter to `create_decorator` to make adding custom behavior easier
4+
25
## Pedantic 2.1.6
36
- Remove `inspect.getsource()` call from `@overrides`
47

docs/pedantic/mixins/with_decorated_methods.html

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,23 @@ <h1 class="title">Module <code>pedantic.mixins.with_decorated_methods</code></h1
5050
C = TypeVar(&#39;C&#39;, bound=Callable)
5151

5252

53-
def create_decorator(decorator_type: DecoratorType) -&gt; Callable[[T], Callable[[C], C]]:
54-
&#34;&#34;&#34; Creates a new decorator that is parametrized with one argument of an arbitrary type. &#34;&#34;&#34;
53+
def create_decorator(
54+
decorator_type: DecoratorType,
55+
transformation: Callable[[C], C] = None,
56+
) -&gt; Callable[[T], Callable[[C], C]]:
57+
&#34;&#34;&#34;
58+
Creates a new decorator that is parametrized with one argument of an arbitrary type.
59+
You can also pass an arbitrary [transformation] to add custom behavior to the decorator.
60+
&#34;&#34;&#34;
5561

5662
def decorator(value: T) -&gt; Callable[[C], C]:
5763
def fun(f: C) -&gt; C:
5864
setattr(f, decorator_type, value)
59-
return f
65+
66+
if transformation is None:
67+
return f
68+
69+
return transformation(f)
6070

6171
return fun # we do not need functools.wraps, because we return the original function here
6272

@@ -122,21 +132,32 @@ <h1 class="title">Module <code>pedantic.mixins.with_decorated_methods</code></h1
122132
<h2 class="section-title" id="header-functions">Functions</h2>
123133
<dl>
124134
<dt id="pedantic.mixins.with_decorated_methods.create_decorator"><code class="name flex">
125-
<span>def <span class="ident">create_decorator</span></span>(<span>decorator_type: <a title="pedantic.mixins.with_decorated_methods.DecoratorType" href="#pedantic.mixins.with_decorated_methods.DecoratorType">DecoratorType</a>) ‑> Callable[[~T], Callable[[~C], ~C]]</span>
135+
<span>def <span class="ident">create_decorator</span></span>(<span>decorator_type: <a title="pedantic.mixins.with_decorated_methods.DecoratorType" href="#pedantic.mixins.with_decorated_methods.DecoratorType">DecoratorType</a>, transformation: Callable[[~C], ~C] = None) ‑> Callable[[~T], Callable[[~C], ~C]]</span>
126136
</code></dt>
127137
<dd>
128-
<div class="desc"><p>Creates a new decorator that is parametrized with one argument of an arbitrary type.</p></div>
138+
<div class="desc"><p>Creates a new decorator that is parametrized with one argument of an arbitrary type.
139+
You can also pass an arbitrary [transformation] to add custom behavior to the decorator.</p></div>
129140
<details class="source">
130141
<summary>
131142
<span>Expand source code</span>
132143
</summary>
133-
<pre><code class="python">def create_decorator(decorator_type: DecoratorType) -&gt; Callable[[T], Callable[[C], C]]:
134-
&#34;&#34;&#34; Creates a new decorator that is parametrized with one argument of an arbitrary type. &#34;&#34;&#34;
144+
<pre><code class="python">def create_decorator(
145+
decorator_type: DecoratorType,
146+
transformation: Callable[[C], C] = None,
147+
) -&gt; Callable[[T], Callable[[C], C]]:
148+
&#34;&#34;&#34;
149+
Creates a new decorator that is parametrized with one argument of an arbitrary type.
150+
You can also pass an arbitrary [transformation] to add custom behavior to the decorator.
151+
&#34;&#34;&#34;
135152

136153
def decorator(value: T) -&gt; Callable[[C], C]:
137154
def fun(f: C) -&gt; C:
138155
setattr(f, decorator_type, value)
139-
return f
156+
157+
if transformation is None:
158+
return f
159+
160+
return transformation(f)
140161

141162
return fun # we do not need functools.wraps, because we return the original function here
142163

docs/pedantic/tests/test_with_decorated_methods.html

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ <h1 class="title">Module <code>pedantic.tests.test_with_decorated_methods</code>
2727
<span>Expand source code</span>
2828
</summary>
2929
<pre><code class="python">import unittest
30+
from functools import wraps
3031

3132
from pedantic import DecoratorType, create_decorator, WithDecoratedMethods
3233

@@ -91,7 +92,35 @@ <h1 class="title">Module <code>pedantic.tests.test_with_decorated_methods</code>
9192
instance.m3: 44,
9293
}
9394
}
94-
assert instance.get_decorated_functions() == expected</code></pre>
95+
assert instance.get_decorated_functions() == expected
96+
97+
98+
def test_with_custom_transformation(self):
99+
def my_transformation(f):
100+
@wraps(f)
101+
def wrapper(*args, **kwargs):
102+
f(*args, **kwargs)
103+
return 4422 # we add a return value
104+
105+
return wrapper
106+
107+
my_decorator = create_decorator(decorator_type=Decorators.BAR, transformation=my_transformation)
108+
109+
class MyClass(WithDecoratedMethods[Decorators]):
110+
@my_decorator(42)
111+
def m1(self) -&gt; int:
112+
return 1
113+
114+
instance = MyClass()
115+
expected = {
116+
Decorators.BAR: {
117+
instance.m1: 42,
118+
},
119+
Decorators.FOO: {},
120+
}
121+
assert instance.get_decorated_functions() == expected
122+
123+
assert instance.m1() == 4422 # check that transformation was applied</code></pre>
95124
</details>
96125
</section>
97126
<section>
@@ -231,14 +260,79 @@ <h3>Class variables</h3>
231260
instance.m3: 44,
232261
}
233262
}
234-
assert instance.get_decorated_functions() == expected</code></pre>
263+
assert instance.get_decorated_functions() == expected
264+
265+
266+
def test_with_custom_transformation(self):
267+
def my_transformation(f):
268+
@wraps(f)
269+
def wrapper(*args, **kwargs):
270+
f(*args, **kwargs)
271+
return 4422 # we add a return value
272+
273+
return wrapper
274+
275+
my_decorator = create_decorator(decorator_type=Decorators.BAR, transformation=my_transformation)
276+
277+
class MyClass(WithDecoratedMethods[Decorators]):
278+
@my_decorator(42)
279+
def m1(self) -&gt; int:
280+
return 1
281+
282+
instance = MyClass()
283+
expected = {
284+
Decorators.BAR: {
285+
instance.m1: 42,
286+
},
287+
Decorators.FOO: {},
288+
}
289+
assert instance.get_decorated_functions() == expected
290+
291+
assert instance.m1() == 4422 # check that transformation was applied</code></pre>
235292
</details>
236293
<h3>Ancestors</h3>
237294
<ul class="hlist">
238295
<li>unittest.case.TestCase</li>
239296
</ul>
240297
<h3>Methods</h3>
241298
<dl>
299+
<dt id="pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_custom_transformation"><code class="name flex">
300+
<span>def <span class="ident">test_with_custom_transformation</span></span>(<span>self)</span>
301+
</code></dt>
302+
<dd>
303+
<div class="desc"></div>
304+
<details class="source">
305+
<summary>
306+
<span>Expand source code</span>
307+
</summary>
308+
<pre><code class="python">def test_with_custom_transformation(self):
309+
def my_transformation(f):
310+
@wraps(f)
311+
def wrapper(*args, **kwargs):
312+
f(*args, **kwargs)
313+
return 4422 # we add a return value
314+
315+
return wrapper
316+
317+
my_decorator = create_decorator(decorator_type=Decorators.BAR, transformation=my_transformation)
318+
319+
class MyClass(WithDecoratedMethods[Decorators]):
320+
@my_decorator(42)
321+
def m1(self) -&gt; int:
322+
return 1
323+
324+
instance = MyClass()
325+
expected = {
326+
Decorators.BAR: {
327+
instance.m1: 42,
328+
},
329+
Decorators.FOO: {},
330+
}
331+
assert instance.get_decorated_functions() == expected
332+
333+
assert instance.m1() == 4422 # check that transformation was applied</code></pre>
334+
</details>
335+
</dd>
242336
<dt id="pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_decorated_methods_async"><code class="name flex">
243337
<span>def <span class="ident">test_with_decorated_methods_async</span></span>(<span>self)</span>
244338
</code></dt>
@@ -339,6 +433,7 @@ <h4><code><a title="pedantic.tests.test_with_decorated_methods.Decorators" href=
339433
<li>
340434
<h4><code><a title="pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods" href="#pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods">TestWithDecoratedMethods</a></code></h4>
341435
<ul class="">
436+
<li><code><a title="pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_custom_transformation" href="#pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_custom_transformation">test_with_custom_transformation</a></code></li>
342437
<li><code><a title="pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_decorated_methods_async" href="#pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_decorated_methods_async">test_with_decorated_methods_async</a></code></li>
343438
<li><code><a title="pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_decorated_methods_sync" href="#pedantic.tests.test_with_decorated_methods.TestWithDecoratedMethods.test_with_decorated_methods_sync">test_with_decorated_methods_sync</a></code></li>
344439
</ul>

0 commit comments

Comments
 (0)