Skip to content

Commit d86f399

Browse files
committed
procedure: Provide workaround for argument types representing GIMP-related objects
For arguments such as `Gegl.Color`, one must pass arguments as a function returning a list (a new feature) or call `Gegl.init()` at the module level before registering plug-in procedures.
1 parent 3154770 commit d86f399

File tree

2 files changed

+66
-20
lines changed

2 files changed

+66
-20
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ Within the main file of your plug-in (a Python script with same name as its pare
127127

128128
At the end of your main Python file (`some-plug-in.py` in the example above), call `procedure.main()`.
129129

130+
For some argument/return value types, e.g. `Gegl.Color`, the default value can be a valid `Gegl.Color` object. In that case, you must call `Gegl.init()` first before instantiating the default objects as otherwise plug-in registration will fail (the plug-in will crash). Alternatively, you can pass a function returning a list to the `arguments` parameter rather than the list itself to delay the creation of the default values until it's necessary, at which point `Gegl.init()` will have been automatically called already.
131+
130132

131133
## Regenerating the `pypdb.pyi` stub file
132134

wrappers/procedure.py

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@
2727
def register_procedure(
2828
procedure: Callable,
2929
procedure_type: Type[Gimp.Procedure] = Gimp.ImageProcedure,
30-
arguments: Optional[Iterable[List]] = None,
31-
return_values: Optional[Iterable[List]] = None,
30+
arguments: Optional[Union[Iterable[List], Callable[[], Iterable[List]]]] = None,
31+
return_values: Optional[Union[Iterable[List], Callable[[], Iterable[List]]]] = None,
3232
menu_label: Optional[str] = None,
3333
menu_path: Optional[Union[str, Iterable[str]]] = None,
3434
image_types: Optional[str] = None,
3535
sensitivity_mask: Optional[Gimp.ProcedureSensitivityMask] = None,
3636
documentation: Optional[Union[Tuple[str, str], Tuple[str, str, str]]] = None,
3737
attribution: Optional[Tuple[str, str, str]] = None,
38-
auxiliary_arguments: Optional[Iterable[List]] = None,
38+
auxiliary_arguments: Optional[Union[Iterable[List], Callable[[], Iterable[List]]]] = None,
3939
run_data: Optional[Iterable] = None,
4040
init_ui: bool = True,
4141
pdb_procedure_type: Gimp.PDBProcType = Gimp.PDBProcType.PLUGIN,
@@ -69,7 +69,8 @@ def register_procedure(
6969
registered. If ``procedure_type`` is `Gimp.ImageProcedure`, several PDB
7070
arguments will be pre-filled (see the documentation for
7171
`Gimp.ImageProcedure` for more information).
72-
arguments: List of arguments (procedure parameters).
72+
arguments: List of arguments (procedure parameters), or a function returning
73+
a list of arguments.
7374
Each argument must be a list containing the following elements in this
7475
order:
7576
* argument type. The type corresponds to one of the
@@ -82,9 +83,40 @@ def register_procedure(
8283
Underscores in argument names (``_``) are automatically replaced with
8384
hyphens (``-``).
8485
86+
If your argument list contains arguments of type e.g. `Gegl.Color`, you
87+
will have to pass a function taking no parameters, for example:
88+
>>> def get_arguments():
89+
>>> _default_foreground_color = Gegl.Color.new('black')
90+
>>> _default_foreground_color.set_rgba(0.65, 0.6, 0.3, 1.0)
91+
>>>
92+
>>> _default_background_color = Gegl.Color.new('black')
93+
>>> _default_background_color.set_rgba(0.1, 0.4, 0.15, 1.0)
94+
>>>
95+
>>> return [
96+
>>> [
97+
>>> 'color',
98+
>>> 'foreground-color',
99+
>>> 'Foreground color',
100+
>>> 'Foreground color',
101+
>>> True,
102+
>>> _default_foreground_color,
103+
>>> GObject.ParamFlags.READWRITE,
104+
>>> ],
105+
>>> [
106+
>>> 'color',
107+
>>> 'background-color',
108+
>>> 'Background color',
109+
>>> 'Background color',
110+
>>> True,
111+
>>> _default_background_color,
112+
>>> GObject.ParamFlags.READWRITE,
113+
>>> ],
114+
>>> ]
115+
85116
For documentation on the ``Gimp.Procedure.add_*_argument`` functions, see:
86117
https://lazka.github.io/pgi-docs/#Gimp-3.0/classes/Procedure.html
87-
return_values: List of return values.
118+
return_values: List of return values, or a function returning a list of
119+
return values.
88120
See ``arguments`` for more information about the contents and format of
89121
the list.
90122
@@ -111,7 +143,8 @@ def register_procedure(
111143
specify it explicitly.
112144
attribution: Plug-in authors, copyright notice and date.
113145
This is a tuple of (authors, copyright notice, date) strings.
114-
auxiliary_arguments: List of auxiliary arguments.
146+
auxiliary_arguments: List of auxiliary arguments, or a function returning
147+
a list of auxiliary arguments.
115148
See ``arguments`` for more information about the contentsn and format of
116149
the list.
117150
@@ -204,15 +237,15 @@ def register_procedure(
204237
proc_dict = _PROCEDURE_NAMES_AND_DATA[proc_name]
205238
proc_dict['procedure'] = procedure
206239
proc_dict['procedure_type'] = procedure_type
207-
proc_dict['arguments'] = _parse_and_check_parameters(arguments)
208-
proc_dict['return_values'] = _parse_and_check_parameters(return_values)
240+
proc_dict['arguments'] = arguments
241+
proc_dict['return_values'] = return_values
209242
proc_dict['menu_label'] = menu_label
210243
proc_dict['menu_path'] = menu_path
211244
proc_dict['image_types'] = image_types
212245
proc_dict['sensitivity_mask'] = sensitivity_mask
213246
proc_dict['documentation'] = documentation
214247
proc_dict['attribution'] = attribution
215-
proc_dict['auxiliary_arguments'] = _parse_and_check_parameters(auxiliary_arguments)
248+
proc_dict['auxiliary_arguments'] = auxiliary_arguments
216249
proc_dict['run_data'] = run_data
217250
proc_dict['init_ui'] = init_ui
218251
proc_dict['pdb_procedure_type'] = pdb_procedure_type
@@ -227,12 +260,17 @@ def _parse_and_check_parameters(parameters):
227260
if parameters is None:
228261
return None
229262

230-
if not isinstance(parameters, Iterable):
263+
if callable(parameters):
264+
processed_parameters = parameters()
265+
else:
266+
processed_parameters = parameters
267+
268+
if not isinstance(processed_parameters, Iterable):
231269
raise TypeError('Arguments and return values must be specified as a list-like iterable')
232270

233-
processed_parameters = {}
271+
parsed_parameters = {}
234272

235-
for param in parameters:
273+
for param in processed_parameters:
236274
processed_param = list(param)
237275

238276
if isinstance(processed_param, list):
@@ -249,14 +287,14 @@ def _parse_and_check_parameters(parameters):
249287

250288
name = processed_param.pop(1).replace('_', '-')
251289

252-
if name in processed_parameters:
290+
if name in parsed_parameters:
253291
raise ValueError(f'Argument or return value named "{name}" was already specified')
254292

255-
processed_parameters[name] = processed_param
293+
parsed_parameters[name] = processed_param
256294
else:
257295
raise TypeError('Only lists are allowed when specifying an argument or return value')
258296

259-
return processed_parameters
297+
return parsed_parameters
260298

261299

262300
def set_use_locale(enabled):
@@ -337,6 +375,8 @@ def _do_query_procedures(_plugin_instance):
337375

338376

339377
def _do_create_procedure(plugin_instance, proc_name):
378+
Gegl.init(None)
379+
340380
if proc_name in _PROCEDURE_NAMES_AND_DATA:
341381
proc_dict = _PROCEDURE_NAMES_AND_DATA[proc_name]
342382
else:
@@ -386,17 +426,23 @@ def _do_create_procedure(plugin_instance, proc_name):
386426
)
387427

388428
if proc_dict['arguments'] is not None:
389-
for name, params in proc_dict['arguments'].items():
429+
parsed_arguments = _parse_and_check_parameters(proc_dict['arguments'])
430+
431+
for name, params in parsed_arguments.items():
390432
param_type = params.pop(0)
391433
_get_add_param_func(procedure, param_type, 'argument')(name, *params)
392434

393435
if proc_dict['return_values'] is not None:
394-
for name, params in proc_dict['return_values'].items():
436+
parsed_return_values = _parse_and_check_parameters(proc_dict['return_values'])
437+
438+
for name, params in parsed_return_values.items():
395439
param_type = params.pop(0)
396440
_get_add_param_func(procedure, param_type, 'return_value')(name, *params)
397441

398442
if proc_dict['auxiliary_arguments'] is not None:
399-
for name, params in proc_dict['auxiliary_arguments'].items():
443+
parsed_auxiliary_arguments = _parse_and_check_parameters(proc_dict['auxiliary_arguments'])
444+
445+
for name, params in parsed_auxiliary_arguments.items():
400446
param_type = params.pop(0)
401447
_get_add_param_func(procedure, param_type, 'aux_argument')(name, *params)
402448

@@ -464,8 +510,6 @@ def func_wrapper(*procedure_and_args):
464510
if init_ui and run_mode == Gimp.RunMode.INTERACTIVE:
465511
GimpUi.init(procedure.get_name())
466512

467-
Gegl.init()
468-
469513
return_values = func(*procedure_and_args)
470514

471515
if return_values is None:

0 commit comments

Comments
 (0)