pluginify 1.0.0.post16.dev0__py3-none-any.whl → 1.0.0.post41.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pluginify/__init__.py +15 -2
- pluginify/_version.py +2 -2
- pluginify/commandline_typer.py +21 -19
- pluginify/config.py +18 -11
- pluginify/create_plugin_registries.py +162 -104
- pluginify/errors.py +11 -3
- pluginify/interfaces/__init__.py +10 -1
- pluginify/interfaces/base.py +168 -100
- pluginify/interfaces/class_based/data_modifiers.py +4 -1
- pluginify/interfaces/class_based_plugin.py +167 -63
- pluginify/interfaces/yaml_based/configs.py +2 -0
- pluginify/plugin_registry.py +213 -172
- pluginify/plugins/classes/data_modifiers/cuboid.py +10 -8
- pluginify/pydantic_models/v1/configs.py +8 -2
- pluginify/utils/__init__.py +37 -17
- pluginify/utils/context_managers.py +18 -6
- pluginify/utils/validators.py +87 -14
- {pluginify-1.0.0.post16.dev0.dist-info → pluginify-1.0.0.post41.dev0.dist-info}/METADATA +3 -1
- pluginify-1.0.0.post41.dev0.dist-info/RECORD +23 -0
- pluginify-1.0.0.post16.dev0.dist-info/RECORD +0 -23
- {pluginify-1.0.0.post16.dev0.dist-info → pluginify-1.0.0.post41.dev0.dist-info}/WHEEL +0 -0
- {pluginify-1.0.0.post16.dev0.dist-info → pluginify-1.0.0.post41.dev0.dist-info}/entry_points.txt +0 -0
- {pluginify-1.0.0.post16.dev0.dist-info → pluginify-1.0.0.post41.dev0.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,31 +4,84 @@
|
|
|
4
4
|
"""Implements a base class for class-based plugins.
|
|
5
5
|
|
|
6
6
|
The base class implemented here would expose the call signature of the child plugin
|
|
7
|
-
class as
|
|
7
|
+
class as ``__call__()`` while also providing hooks for pre- and post-processing.
|
|
8
8
|
|
|
9
|
-
The hooks are available as
|
|
9
|
+
The hooks are available as ``_pre_call()`` and ``_post_call()``. They should be used to
|
|
10
10
|
implement common functionality that all plugins of this type should posess but which we
|
|
11
11
|
don't want developers to need to implement. They are intended to be overridden by the
|
|
12
|
-
child plugin-type class (e.g. BaseReaderPlugin). They should define what kwargs they
|
|
12
|
+
child plugin-type class (e.g. ``BaseReaderPlugin``). They should define what kwargs they
|
|
13
13
|
accept when defined on the plugin-type class but should accept their arguments from
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The
|
|
17
|
-
the data processing for the plugin.
|
|
18
|
-
of
|
|
19
|
-
by the hooks.
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
``**kwargs`` from ``__call__()``.
|
|
15
|
+
|
|
16
|
+
The ``call()`` method should be overridden on the actual plugin class. It should provide
|
|
17
|
+
the data processing for the plugin. ``__call__()``'s signature will be identical to that
|
|
18
|
+
of ``call()`` except that ``call()`` should not accept ``**kwargs``. That should be
|
|
19
|
+
consumed by the hooks.
|
|
20
|
+
|
|
21
|
+
``__call__()`` should not be overridden anywhere.
|
|
22
|
+
|
|
23
|
+
Required attributes
|
|
24
|
+
-------------------
|
|
25
|
+
interface : str
|
|
26
|
+
The interface type the plugin belongs to
|
|
27
|
+
(e.g. ``'configs'``, ``'data_modifiers'``).
|
|
28
|
+
This is typically provided by the interface-level plugin class and not the
|
|
29
|
+
individual plugin class.
|
|
30
|
+
family : str
|
|
31
|
+
The family name of the plugin. This should be defined by the plugin class.
|
|
32
|
+
name : str
|
|
33
|
+
The specific name of the plugin. This should be defined by the plugin class.
|
|
34
|
+
|
|
35
|
+
Required methods
|
|
36
|
+
----------------
|
|
37
|
+
call()
|
|
38
|
+
The main method that performs the plugin's functionality. This method
|
|
39
|
+
should be implemented by the plugin class.
|
|
40
|
+
_pre_call()
|
|
41
|
+
A hook method that can be overridden to preprocess data before
|
|
42
|
+
calling the main ``call()`` method. This method should accept the same
|
|
43
|
+
arguments as ``call()`` via ``*args`` and ``**kwargs`` and should,
|
|
44
|
+
typically, be implemented by the interface-level plugin class.
|
|
45
|
+
_post_call()
|
|
46
|
+
A hook method that can be overridden to post-process data after
|
|
47
|
+
calling the main ``call()`` method. This method should accept the same
|
|
48
|
+
arguments as ``call()`` via ``*args`` and ``**kwargs`` and should,
|
|
49
|
+
typically, be implemented by the interface-level plugin class.
|
|
50
|
+
|
|
51
|
+
Notes
|
|
52
|
+
-----
|
|
53
|
+
The purpose of ``_pre_call()`` and ``_post_call()`` is to allow for common
|
|
54
|
+
functionality that all plugins of a certain type should possess, without requiring
|
|
55
|
+
developers to implement this functionality in every plugin class. Initially, this
|
|
56
|
+
will be used to convert inputs from DataTree to other formats and back to DataTree
|
|
57
|
+
after processing, but it could be used for other common tasks as well.
|
|
22
58
|
"""
|
|
23
59
|
|
|
24
60
|
from __future__ import annotations
|
|
61
|
+
|
|
25
62
|
from abc import ABC, abstractmethod
|
|
26
63
|
import functools
|
|
27
64
|
import inspect
|
|
65
|
+
from typing import Any
|
|
28
66
|
|
|
29
67
|
|
|
30
|
-
def valid_str_attr(cls, attr_name: str):
|
|
31
|
-
"""Check that the given attribute is a non-empty string.
|
|
68
|
+
def valid_str_attr(cls: type, attr_name: str) -> None:
|
|
69
|
+
"""Check that the given attribute is a non-empty string.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
cls : type
|
|
74
|
+
The class whose attribute should be checked.
|
|
75
|
+
attr_name : str
|
|
76
|
+
The name of the attribute to check.
|
|
77
|
+
|
|
78
|
+
Raises
|
|
79
|
+
------
|
|
80
|
+
TypeError
|
|
81
|
+
If the attribute is not a string.
|
|
82
|
+
ValueError
|
|
83
|
+
If the attribute is an empty string.
|
|
84
|
+
"""
|
|
32
85
|
attr_value = getattr(cls, attr_name, None)
|
|
33
86
|
if not isinstance(attr_value, str):
|
|
34
87
|
raise TypeError(f"{cls.__name__}.{attr_name} must be a string")
|
|
@@ -41,27 +94,35 @@ class BaseClassPlugin(ABC):
|
|
|
41
94
|
|
|
42
95
|
All plugins are required to carry the following class attributes:
|
|
43
96
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
97
|
+
interface : str
|
|
98
|
+
The interface type the plugin belongs to
|
|
99
|
+
(e.g. ``'configs'``, ``'data_modifiers'``).
|
|
100
|
+
This is typically provided by the interface-level plugin class and not the
|
|
101
|
+
individual plugin class.
|
|
102
|
+
family : str
|
|
103
|
+
The family name of the plugin. This should be defined by the plugin class.
|
|
104
|
+
name : str
|
|
105
|
+
The specific name of the plugin. This should be defined by the plugin class.
|
|
50
106
|
|
|
51
107
|
Subclasses of this base class must also implement the following methods:
|
|
52
108
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
109
|
+
call()
|
|
110
|
+
The main method that performs the plugin's functionality. This method
|
|
111
|
+
should be implemented by the plugin class.
|
|
112
|
+
_pre_call()
|
|
113
|
+
A hook method that can be overridden to preprocess data before
|
|
114
|
+
calling the main ``call()`` method. This method should accept the same
|
|
115
|
+
arguments as ``call()`` via ``*args`` and ``**kwargs`` and should,
|
|
116
|
+
typically, be implemented by the interface-level plugin class.
|
|
117
|
+
_post_call()
|
|
118
|
+
A hook method that can be overridden to post-process data after
|
|
119
|
+
calling the main ``call()`` method. This method should accept the same
|
|
120
|
+
arguments as ``call()`` via ``*args`` and ``**kwargs`` and should,
|
|
121
|
+
typically, be implemented by the interface-level plugin class.
|
|
122
|
+
|
|
123
|
+
Notes
|
|
124
|
+
-----
|
|
125
|
+
The purpose of ``_pre_call()`` and ``_post_call()`` is to allow for common
|
|
65
126
|
functionality that all plugins of a certain type should possess, without requiring
|
|
66
127
|
developers to implement this functionality in every plugin class. Initially, this
|
|
67
128
|
will be used to convert inputs from DataTree to other formats and back to DataTree
|
|
@@ -78,55 +139,100 @@ class BaseClassPlugin(ABC):
|
|
|
78
139
|
__plugin_abstract__: bool = False
|
|
79
140
|
|
|
80
141
|
def _check_interface_attribute(cls):
|
|
81
|
-
"""Check
|
|
142
|
+
"""Check that the 'interface' attribute is valid.
|
|
82
143
|
|
|
83
|
-
|
|
84
|
-
|
|
144
|
+
Ensures the attribute is a non-empty string and a known plugin interface.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
cls : type
|
|
149
|
+
The class whose interface attribute should be checked.
|
|
85
150
|
"""
|
|
86
151
|
valid_str_attr(cls, "interface")
|
|
87
152
|
|
|
88
153
|
def _check_family_attribute(cls):
|
|
89
|
-
"""Check
|
|
154
|
+
"""Check that the 'family' attribute is valid.
|
|
155
|
+
|
|
156
|
+
Ensures the attribute is a non-empty string.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
cls : type
|
|
161
|
+
The class whose family attribute should be checked.
|
|
162
|
+
"""
|
|
90
163
|
valid_str_attr(cls, "family")
|
|
91
164
|
|
|
92
165
|
def _check_name_attribute(cls):
|
|
93
|
-
"""Check
|
|
166
|
+
"""Check that the 'name' attribute is valid.
|
|
167
|
+
|
|
168
|
+
Ensures the attribute is a non-empty string.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
cls : type
|
|
173
|
+
The class whose name attribute should be checked.
|
|
174
|
+
"""
|
|
94
175
|
valid_str_attr(cls, "name")
|
|
95
176
|
|
|
96
177
|
@abstractmethod
|
|
97
|
-
def call(self, *args, **kwargs):
|
|
98
|
-
"""Callable method to be implemented by the plugin class.
|
|
178
|
+
def call(self, *args: Any, **kwargs: Any) -> Any:
|
|
179
|
+
"""Callable method to be implemented by the plugin class.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
Any
|
|
184
|
+
The result of the plugin's processing.
|
|
185
|
+
"""
|
|
99
186
|
pass
|
|
100
187
|
|
|
101
188
|
# hooks are intentionally loose; document their accepted kwargs
|
|
102
|
-
def _pre_call(self, data=None, *args, **kwargs):
|
|
189
|
+
def _pre_call(self, data: Any = None, *args: Any, **kwargs: Any) -> Any:
|
|
103
190
|
"""Preprocess the data before calling the main plugin method.
|
|
104
191
|
|
|
105
192
|
Parameters
|
|
106
193
|
----------
|
|
107
|
-
data :
|
|
194
|
+
data : Any
|
|
195
|
+
The input data for the plugin.
|
|
108
196
|
|
|
109
197
|
Returns
|
|
110
198
|
-------
|
|
111
|
-
|
|
199
|
+
Any
|
|
200
|
+
The processed data.
|
|
112
201
|
"""
|
|
113
202
|
return data
|
|
114
203
|
|
|
115
|
-
def _post_call(self, data=None, *args, **kwargs):
|
|
204
|
+
def _post_call(self, data: Any = None, *args: Any, **kwargs: Any) -> Any:
|
|
116
205
|
"""Post-process the data after calling the main plugin method.
|
|
117
206
|
|
|
118
207
|
Parameters
|
|
119
208
|
----------
|
|
120
|
-
data :
|
|
209
|
+
data : Any
|
|
121
210
|
The output data from the plugin.
|
|
122
211
|
|
|
123
212
|
Returns
|
|
124
213
|
-------
|
|
214
|
+
Any
|
|
125
215
|
The processed data.
|
|
126
216
|
"""
|
|
127
217
|
return data
|
|
128
218
|
|
|
129
|
-
def _invoke(self, data=None, *args, **kwargs):
|
|
219
|
+
def _invoke(self, data: Any = None, *args: Any, **kwargs: Any) -> Any:
|
|
220
|
+
"""Invoke the plugin's processing pipeline.
|
|
221
|
+
|
|
222
|
+
If data is provided, runs the full ``_pre_call()`` → ``call()`` →
|
|
223
|
+
``_post_call()`` pipeline. Otherwise, delegates directly to ``call()``.
|
|
224
|
+
|
|
225
|
+
Parameters
|
|
226
|
+
----------
|
|
227
|
+
data : Any, optional
|
|
228
|
+
The input data for the plugin. If ``None``, ``call()`` is invoked
|
|
229
|
+
directly with ``*args`` and ``**kwargs``.
|
|
230
|
+
|
|
231
|
+
Returns
|
|
232
|
+
-------
|
|
233
|
+
Any
|
|
234
|
+
The result of the plugin's processing pipeline.
|
|
235
|
+
"""
|
|
130
236
|
if data is None:
|
|
131
237
|
data = self.call(*args, **kwargs)
|
|
132
238
|
else:
|
|
@@ -135,18 +241,16 @@ class BaseClassPlugin(ABC):
|
|
|
135
241
|
data = self._post_call(data, *args, **kwargs)
|
|
136
242
|
return data
|
|
137
243
|
|
|
138
|
-
def __init__(self, module=None):
|
|
139
|
-
"""
|
|
140
|
-
Initialize the plugin object inheriting from BaseClasePlugin.
|
|
244
|
+
def __init__(self, module=None) -> None:
|
|
245
|
+
"""Initialize the plugin object.
|
|
141
246
|
|
|
142
247
|
Parameters
|
|
143
248
|
----------
|
|
144
|
-
module: ModuleType,
|
|
249
|
+
module : ModuleType, optional
|
|
145
250
|
The module from which the class-based plugin originated. This is used to
|
|
146
251
|
collect metadata from the module and attach it to the plugin object. The
|
|
147
252
|
metadata can then be used during validation to indicate where failing
|
|
148
|
-
plugins originated. If None
|
|
149
|
-
string value that can also be used in tests.
|
|
253
|
+
plugins originated. If ``None``, defaults are set.
|
|
150
254
|
"""
|
|
151
255
|
if module:
|
|
152
256
|
self.module_name = module.__name__
|
|
@@ -155,28 +259,28 @@ class BaseClassPlugin(ABC):
|
|
|
155
259
|
self.module_name = "Unknown."
|
|
156
260
|
self.module_path = "Unknown."
|
|
157
261
|
|
|
158
|
-
def __init_subclass__(cls, *, abstract=False, **kwargs) -> None:
|
|
159
|
-
"""
|
|
160
|
-
Initialize a subclass of the plugin.
|
|
262
|
+
def __init_subclass__(cls, *, abstract: bool = False, **kwargs: Any) -> None:
|
|
263
|
+
"""Initialize a subclass of the plugin.
|
|
161
264
|
|
|
162
265
|
Parameters
|
|
163
266
|
----------
|
|
164
267
|
abstract : bool, optional
|
|
165
|
-
If True
|
|
166
|
-
validation is disabled in __init_subclass__
|
|
268
|
+
If ``True``, the subclass is treated as abstract. When treated as
|
|
269
|
+
abstract, validation is disabled in ``__init_subclass__``. Defaults to
|
|
270
|
+
``False``.
|
|
271
|
+
|
|
272
|
+
Returns
|
|
273
|
+
-------
|
|
274
|
+
None
|
|
167
275
|
|
|
168
276
|
Raises
|
|
169
277
|
------
|
|
170
278
|
TypeError
|
|
171
279
|
If the subclass does not define the required attributes.
|
|
172
280
|
TypeError
|
|
173
|
-
If the subclass does not implement the call() method.
|
|
281
|
+
If the subclass does not implement the ``call()`` method.
|
|
174
282
|
TypeError
|
|
175
|
-
If the subclass overrides the __call__() method.
|
|
176
|
-
|
|
177
|
-
Returns
|
|
178
|
-
-------
|
|
179
|
-
None
|
|
283
|
+
If the subclass overrides the ``__call__()`` method.
|
|
180
284
|
"""
|
|
181
285
|
super().__init_subclass__(**kwargs)
|
|
182
286
|
|
|
@@ -204,8 +308,8 @@ class BaseClassPlugin(ABC):
|
|
|
204
308
|
raise TypeError(f"{cls.__name__} must implement call()")
|
|
205
309
|
call_method = cls.__dict__["call"]
|
|
206
310
|
|
|
207
|
-
@functools.wraps(call_method)
|
|
208
|
-
def _call(self, data=None, *args, **kwargs):
|
|
311
|
+
@functools.wraps(call_method)
|
|
312
|
+
def _call(self, data: Any = None, *args: Any, **kwargs: Any) -> Any:
|
|
209
313
|
return cls._invoke(self, data, *args, **kwargs)
|
|
210
314
|
|
|
211
315
|
call_sig = inspect.signature(call_method)
|
|
@@ -17,6 +17,8 @@ class ConfigsInterface(BaseYamlInterface):
|
|
|
17
17
|
This is a 'dummy' interface which is strictly used for testing pluginify. All
|
|
18
18
|
plugins of this interface are also 'dummy' plugins strictly used for testing this
|
|
19
19
|
package.
|
|
20
|
+
|
|
21
|
+
Uses Pydantic model validation instead of JSON schema validation.
|
|
20
22
|
"""
|
|
21
23
|
|
|
22
24
|
name = "configs"
|