Skip to content

Commit b2c1b4d

Browse files
gh-104389: Add 'unused' keyword to Argument Clinic C converters (#104390)
Use the unused keyword param in the converter to explicitly mark an argument as unused: /*[clinic input] SomeBaseClass.stubmethod flag: bool(unused=True) [clinic start generated code]*/
1 parent 15795b5 commit b2c1b4d

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

Doc/howto/clinic.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,9 @@ All Argument Clinic converters accept the following arguments:
775775
because :pep:`8` mandates that the Python library may not use
776776
annotations.
777777

778+
``unused``
779+
Wrap the argument with :c:macro:`Py_UNUSED` in the impl function signature.
780+
778781
In addition, some converters accept additional arguments. Here is a list
779782
of these arguments, along with their meanings:
780783

Lib/test/test_clinic.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,44 @@ def test_legacy_converters(self):
774774
module, function = block.signatures
775775
self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
776776

777+
def test_unused_param(self):
778+
block = self.parse("""
779+
module foo
780+
foo.func
781+
fn: object
782+
k: float
783+
i: float(unused=True)
784+
/
785+
*
786+
flag: bool(unused=True) = False
787+
""")
788+
sig = block.signatures[1] # Function index == 1
789+
params = sig.parameters
790+
conv = lambda fn: params[fn].converter
791+
dataset = (
792+
{"name": "fn", "unused": False},
793+
{"name": "k", "unused": False},
794+
{"name": "i", "unused": True},
795+
{"name": "flag", "unused": True},
796+
)
797+
for param in dataset:
798+
name, unused = param.values()
799+
with self.subTest(name=name, unused=unused):
800+
p = conv(name)
801+
# Verify that the unused flag is parsed correctly.
802+
self.assertEqual(unused, p.unused)
803+
804+
# Now, check that we'll produce correct code.
805+
decl = p.simple_declaration(in_parser=False)
806+
if unused:
807+
self.assertIn("Py_UNUSED", decl)
808+
else:
809+
self.assertNotIn("Py_UNUSED", decl)
810+
811+
# Make sure the Py_UNUSED macro is not used in the parser body.
812+
parser_decl = p.simple_declaration(in_parser=True)
813+
self.assertNotIn("Py_UNUSED", parser_decl)
814+
777815
def parse(self, text):
778816
c = FakeClinic()
779817
parser = DSLParser(c)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Argument Clinic C converters now accept the ``unused`` keyword, for wrapping
2+
a parameter with :c:macro:`Py_UNUSED`. Patch by Erlend E. Aasland.

Tools/clinic/clinic.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2599,6 +2599,9 @@ class CConverter(metaclass=CConverterAutoRegister):
25992599
# Every non-abstract subclass should supply a valid value.
26002600
c_ignored_default = 'NULL'
26012601

2602+
# If true, wrap with Py_UNUSED.
2603+
unused = False
2604+
26022605
# The C converter *function* to be used, if any.
26032606
# (If this is not None, format_unit must be 'O&'.)
26042607
converter = None
@@ -2651,9 +2654,22 @@ class CConverter(metaclass=CConverterAutoRegister):
26512654
signature_name = None
26522655

26532656
# keep in sync with self_converter.__init__!
2654-
def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs):
2657+
def __init__(self,
2658+
# Positional args:
2659+
name,
2660+
py_name,
2661+
function,
2662+
default=unspecified,
2663+
*, # Keyword only args:
2664+
c_default=None,
2665+
py_default=None,
2666+
annotation=unspecified,
2667+
unused=False,
2668+
**kwargs
2669+
):
26552670
self.name = ensure_legal_c_identifier(name)
26562671
self.py_name = py_name
2672+
self.unused = unused
26572673

26582674
if default is not unspecified:
26592675
if self.default_type and not isinstance(default, (self.default_type, Unknown)):
@@ -2800,6 +2816,8 @@ def simple_declaration(self, by_reference=False, *, in_parser=False):
28002816
name = self.parser_name
28012817
else:
28022818
name = self.name
2819+
if self.unused:
2820+
name = f"Py_UNUSED({name})"
28032821
prototype.append(name)
28042822
return "".join(prototype)
28052823

0 commit comments

Comments
 (0)