Skip to content

Commit f16131e

Browse files
committed
Work around passing arguments matching Python keywords
1 parent 4e5af79 commit f16131e

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Updated type annotations for parameters that can be `None` (e.g. `Gimp.Image` or `Gimp.Layer`) in the stub file.
88
* Slightly optimized access to PDB procedures and GEGL operations via the `pdb` object.
99
* Improved GUI for the output directory for the stub generator.
10+
* Arguments whose names match a Python keyword can now be passed with a trailing `_`, e.g. `lambda_` (passing `lambda=<value>` would result in a syntax error).
1011

1112

1213
4.2

generate-pdb-stubs/stubgen.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import ast
44
import inspect
5+
import keyword
56
import os
67
import re
78
import sys
@@ -161,7 +162,7 @@ def _insert_gimp_pdb_procedure_node(pypdb_class_node, procedure_name):
161162

162163

163164
def _create_pdb_procedure_node(procedure_name):
164-
func_name = pypdb.pdb.canonical_name_to_python_name(procedure_name)
165+
func_name = _canonical_name_to_python_name(procedure_name)
165166

166167
# Constructing a `FunctionDef` node this way is more readable and less error-prone.
167168
func_base_arguments_str = 'self'
@@ -179,7 +180,7 @@ def _insert_gimp_pdb_procedure_arguments(procedure_node, procedure):
179180

180181
for proc_arg in reversed(proc_args):
181182
arg_node = ast.arg(
182-
arg=pypdb.pdb.canonical_name_to_python_name(proc_arg.name),
183+
arg=_canonical_name_to_python_name(proc_arg.name),
183184
annotation=_get_proc_argument_type_hint(proc_arg),
184185
col_offset=None,
185186
end_col_offset=None,
@@ -382,7 +383,7 @@ def _add_proc_params_or_retvals_to_docstring(
382383
param_prefix = '* '
383384

384385
for param in params:
385-
name = pypdb.pdb.canonical_name_to_python_name(param.name)
386+
name = _canonical_name_to_python_name(param.name)
386387

387388
description = param.blurb
388389
if description:
@@ -685,7 +686,7 @@ def _insert_gegl_procedure_arguments(procedure, procedure_node):
685686

686687
for proc_arg in reversed(proc_args):
687688
arg_node = ast.arg(
688-
arg=pypdb.pdb.canonical_name_to_python_name(proc_arg.name),
689+
arg=_canonical_name_to_python_name(proc_arg.name),
689690
annotation=_get_proc_argument_type_hint(proc_arg),
690691
col_offset=None,
691692
end_col_offset=None,
@@ -795,6 +796,17 @@ def _get_type_hint_name_from_gtype(value_type, default_type):
795796
return default_type
796797

797798

799+
def _canonical_name_to_python_name(name):
800+
processed_name = pypdb.pdb.canonical_name_to_python_name(name)
801+
802+
# This allows passing arguments with a trailing '_' to avoid name clashes
803+
# with Python keywords.
804+
if keyword.iskeyword(processed_name):
805+
processed_name = f'{processed_name}_'
806+
807+
return processed_name
808+
809+
798810
def write_stub_file(dirpath, root_node):
799811
os.makedirs(dirpath, exist_ok=True)
800812

wrappers/pypdb.py

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Wrapper of ``Gimp.get_pdb()`` to simplify invoking GIMP PDB procedures."""
22

33
import abc
4+
import keyword
45
from typing import Optional
56

67
import gi
@@ -137,9 +138,32 @@ def __call__(self, **kwargs):
137138
138139
All underscore characters (``_``) in argument names are automatically
139140
replaced by ``-``.
141+
142+
Arguments whose names match a Python keyword (``if``, ``lambda``,
143+
etc.) can be specified by appending a ``_``, e.g. ``lambda_=<value>``.
140144
"""
141145
pass
142146

147+
@staticmethod
148+
def _process_arg_name(arg_name):
149+
"""Transforms the given Python argument name to the name of a property
150+
defined for this procedure.
151+
152+
For example, ``'run_mode'`` is transformed to ``'run-mode'``.
153+
154+
Argument names matching a Python keyword can be specified with a trailing
155+
``_``, e.g. ``lambda_``. This is transformed such that the trailing `_``
156+
is removed, e.g. ``lambda``.
157+
"""
158+
processed_arg_name = arg_name.replace('_', '-')
159+
160+
# This allows passing arguments with a trailing '_' to avoid name clashes
161+
# with Python keywords.
162+
if processed_arg_name.endswith('-') and keyword.iskeyword(processed_arg_name[:-1]):
163+
processed_arg_name = processed_arg_name[:-1]
164+
165+
return processed_arg_name
166+
143167
@property
144168
@abc.abstractmethod
145169
def arguments(self):
@@ -310,7 +334,7 @@ def _create_config_for_call(self, **proc_kwargs):
310334
args_and_names = {arg.name: arg for arg in args}
311335

312336
for arg_name, arg_value in proc_kwargs.items():
313-
processed_arg_name = arg_name.replace('_', '-')
337+
processed_arg_name = self._process_arg_name(arg_name)
314338

315339
try:
316340
arg = args_and_names[processed_arg_name]
@@ -379,7 +403,7 @@ def __call__(self, *args, **kwargs):
379403
``drawable_`` argument, which may be specified as the first and the only
380404
positional argument.
381405
"""
382-
processed_kwargs = {name.replace('_', '-'): value for name, value in kwargs.items()}
406+
processed_kwargs = {self._process_arg_name(name): value for name, value in kwargs.items()}
383407

384408
if 'drawable-' in processed_kwargs:
385409
drawable = processed_kwargs.pop('drawable-')

0 commit comments

Comments
 (0)