Skip to content

Commit cf9dfbb

Browse files
+ Decorator base class
1 parent de98eb9 commit cf9dfbb

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

src/thread/decorators.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"""
2+
## Decorators
3+
4+
Documentation: https://thread.ngjx.org
5+
"""
6+
7+
from functools import wraps
8+
from abc import ABC, abstractmethod
9+
10+
from ._types import TargetFunction, Overflow_In, Data_Out, Data_In
11+
from typing import Any, Callable, Mapping, Tuple
12+
13+
from .thread import Thread
14+
from .exceptions import AbstractInvokationError, ArgumentValidationError
15+
16+
17+
class DecoratorBase(ABC):
18+
"""
19+
Decorator Base Class
20+
21+
This should only be used from inheriting classes
22+
23+
Use Case
24+
--------
25+
```py
26+
class MyDecorator(DecoratorBase):
27+
# DocString here for decorator without arguments
28+
29+
# Arguments to the decorator are here
30+
args: Tuple[Any, ...]
31+
kwargs: Mapping[str, Any]
32+
33+
def __init__(self, *args, **kwargs):
34+
# DocString here for decorator with arguments
35+
# If you want to have type hinting
36+
# If you want to validate arguments to decorator
37+
super().__init__(*args, **kwargs)
38+
39+
def __validate__(self, args, kwargs):
40+
# If you want to validate arguments to the wrapped function
41+
return bool
42+
43+
def __execute__(self, func, args, kwargs):
44+
return func(*args, **kwargs)
45+
```
46+
"""
47+
48+
args: Tuple[Any, ...]
49+
kwargs: Mapping[str, Any]
50+
51+
def __init__(self, *args: Any, **kwargs: Any) -> None:
52+
"""init"""
53+
self.args = args
54+
self.kwargs = kwargs
55+
56+
def __call__(self, *args: Any, **kwargs: Any) -> Data_Out:
57+
"""
58+
The main logic to allow decorators to be invoked:
59+
60+
```py
61+
@MyDecorator
62+
def a(): ...
63+
64+
@MyDecorator()
65+
def b(): ...
66+
67+
@MyDecorator(1, 2, 3)
68+
def c(): ...
69+
```
70+
"""
71+
if callable(self.args[0]) and self.__validate__(args, kwargs):
72+
func = self.args[0]
73+
return self.__execute__(func, args, kwargs)
74+
75+
elif not callable(self.args[0]):
76+
func = args[0]
77+
78+
@wraps(self.__execute__)
79+
def wrapper(*args, **kwargs):
80+
if self.__validate__(args, kwargs):
81+
return self.__execute__(func, args, kwargs)
82+
return wrapper
83+
84+
else:
85+
raise ArgumentValidationError()
86+
87+
88+
@abstractmethod
89+
def __execute__(self, func: Callable[..., Data_Out], args: Tuple[Any, ...], kwargs: Mapping[str, Any]) -> Data_Out:
90+
"""
91+
The main code returning the result of the wrapped method
92+
93+
Parameters
94+
----------
95+
:param func: The wrapped function
96+
:param args: The tuple of parsed arguments
97+
:param kwargs: The tuple of parsed keyword arguments
98+
99+
Returns
100+
-------
101+
:returns Data_Out: The result of the wrapped function
102+
103+
Raises
104+
------
105+
AbstractInvocationsError: When the base class abstract method is invoked
106+
107+
Use Case
108+
--------
109+
```py
110+
class MyDecorator(DecoratorBase):
111+
...
112+
def __execute__(self, func, args, kwargs):
113+
return func(*args, **kwargs)
114+
```
115+
"""
116+
raise AbstractInvokationError('__execute__')
117+
118+
@abstractmethod
119+
def __validate__(self, args: Tuple[Any, ...], kwargs: Mapping[str, Any]) -> bool:
120+
"""
121+
Validate arguments parsed to the wrapped method
122+
123+
Parameters
124+
----------
125+
:param args: Tuple of parsed positional arguments
126+
:param kwargs: Dictionary of parsed keyword arguments
127+
128+
Returns
129+
-------
130+
:returns bool: True if the arguments are valid
131+
132+
Raises
133+
------
134+
AbstractInvokationError: When the base class abstract method is invoked
135+
136+
Use Case
137+
--------
138+
```py
139+
@MyDecorator
140+
def myfunction(*args, **kwargs): ...
141+
142+
myfunction(1, 2, 3) # Arguments parsed here is validated here
143+
```
144+
"""
145+
raise AbstractInvokationError('__validate__')
146+

0 commit comments

Comments
 (0)