Skip to content

Commit 2f369ca

Browse files
gh-104050: Add type hints to Argument Clinic converter keywords (#104588)
Introduce TypeSet, and use it to annotate the 'accept' keyword of various C converters. Also add some missing return annotations for converter init functions.
1 parent aed643b commit 2f369ca

File tree

1 file changed

+36
-12
lines changed

1 file changed

+36
-12
lines changed

Tools/clinic/clinic.py

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,7 +2600,7 @@ class CConverter(metaclass=CConverterAutoRegister):
26002600
# Or the magic value "unknown" if this value is a cannot be evaluated
26012601
# at Argument-Clinic-preprocessing time (but is presumed to be valid
26022602
# at runtime).
2603-
default = unspecified
2603+
default: bool | Unspecified = unspecified
26042604

26052605
# If not None, default must be isinstance() of this type.
26062606
# (You can also specify a tuple of types.)
@@ -2655,7 +2655,7 @@ class CConverter(metaclass=CConverterAutoRegister):
26552655

26562656
# What encoding do we want for this variable? Only used
26572657
# by format units starting with 'e'.
2658-
encoding = None
2658+
encoding: str | None = None
26592659

26602660
# Should this object be required to be a subclass of a specific type?
26612661
# If not None, should be a string representing a pointer to a
@@ -2982,14 +2982,16 @@ def parser_name(self):
29822982
# note however that they will never be called with keyword-only parameters.
29832983
legacy_converters: ConverterDict = {}
29842984

2985+
TypeSet = set[bltns.type[Any]]
2986+
29852987

29862988
class bool_converter(CConverter):
29872989
type = 'int'
29882990
default_type = bool
29892991
format_unit = 'p'
29902992
c_ignored_default = '0'
29912993

2992-
def converter_init(self, *, accept={object}):
2994+
def converter_init(self, *, accept: TypeSet = {object}) -> None:
29932995
if accept == {int}:
29942996
self.format_unit = 'i'
29952997
elif accept != {object}:
@@ -3176,7 +3178,7 @@ class int_converter(CConverter):
31763178
format_unit = 'i'
31773179
c_ignored_default = "0"
31783180

3179-
def converter_init(self, *, accept={int}, type=None) -> None:
3181+
def converter_init(self, *, accept: TypeSet = {int}, type=None) -> None:
31803182
if accept == {str}:
31813183
self.format_unit = 'C'
31823184
elif accept != {int}:
@@ -3313,7 +3315,7 @@ class Py_ssize_t_converter(CConverter):
33133315
type = 'Py_ssize_t'
33143316
c_ignored_default = "0"
33153317

3316-
def converter_init(self, *, accept={int}) -> None:
3318+
def converter_init(self, *, accept: TypeSet = {int}) -> None:
33173319
if accept == {int}:
33183320
self.format_unit = 'n'
33193321
self.default_type = int
@@ -3344,7 +3346,7 @@ def parse_arg(self, argname: str, displayname: str) -> str:
33443346
class slice_index_converter(CConverter):
33453347
type = 'Py_ssize_t'
33463348

3347-
def converter_init(self, *, accept={int, NoneType}) -> None:
3349+
def converter_init(self, *, accept: TypeSet = {int, NoneType}) -> None:
33483350
if accept == {int}:
33493351
self.converter = '_PyEval_SliceIndexNotNone'
33503352
elif accept == {int, NoneType}:
@@ -3447,7 +3449,12 @@ class object_converter(CConverter):
34473449
type = 'PyObject *'
34483450
format_unit = 'O'
34493451

3450-
def converter_init(self, *, converter=None, type=None, subclass_of=None):
3452+
def converter_init(
3453+
self, *,
3454+
converter=None,
3455+
type=None,
3456+
subclass_of=None
3457+
) -> None:
34513458
if converter:
34523459
if subclass_of:
34533460
fail("object: Cannot pass in both 'converter' and 'subclass_of'")
@@ -3483,7 +3490,13 @@ class str_converter(CConverter):
34833490
default_type = (str, Null, NoneType)
34843491
format_unit = 's'
34853492

3486-
def converter_init(self, *, accept={str}, encoding=None, zeroes=False):
3493+
def converter_init(
3494+
self,
3495+
*,
3496+
accept: TypeSet = {str},
3497+
encoding: str | None = None,
3498+
zeroes: bool = False
3499+
) -> None:
34873500

34883501
key = str_converter_key(accept, encoding, zeroes)
34893502
format_unit = str_converter_argument_map.get(key)
@@ -3561,7 +3574,14 @@ def parse_arg(self, argname: str, displayname: str) -> str:
35613574
# mapping from arguments to format unit *and* registers the
35623575
# legacy C converter for that format unit.
35633576
#
3564-
def r(format_unit, *, accept, encoding=False, zeroes=False):
3577+
ConverterKeywordDict = dict[str, TypeSet | bool]
3578+
3579+
def r(format_unit: str,
3580+
*,
3581+
accept: TypeSet,
3582+
encoding: bool = False,
3583+
zeroes: bool = False
3584+
) -> None:
35653585
if not encoding and format_unit != 's':
35663586
# add the legacy c converters here too.
35673587
#
@@ -3571,7 +3591,7 @@ def r(format_unit, *, accept, encoding=False, zeroes=False):
35713591
#
35723592
# also don't add the converter for 's' because
35733593
# the metaclass for CConverter adds it for us.
3574-
kwargs = {}
3594+
kwargs: ConverterKeywordDict = {}
35753595
if accept != {str}:
35763596
kwargs['accept'] = accept
35773597
if zeroes:
@@ -3660,7 +3680,11 @@ class Py_UNICODE_converter(CConverter):
36603680
type = 'const Py_UNICODE *'
36613681
default_type = (str, Null, NoneType)
36623682

3663-
def converter_init(self, *, accept={str}, zeroes: bool = False) -> None:
3683+
def converter_init(
3684+
self, *,
3685+
accept: TypeSet = {str},
3686+
zeroes: bool = False
3687+
) -> None:
36643688
format_unit = 'Z' if accept=={str, NoneType} else 'u'
36653689
if zeroes:
36663690
format_unit += '#'
@@ -3722,7 +3746,7 @@ class Py_buffer_converter(CConverter):
37223746
impl_by_reference = True
37233747
c_ignored_default = "{NULL, NULL}"
37243748

3725-
def converter_init(self, *, accept={buffer}) -> None:
3749+
def converter_init(self, *, accept: TypeSet = {buffer}) -> None:
37263750
if self.default not in (unspecified, None):
37273751
fail("The only legal default value for Py_buffer is None.")
37283752

0 commit comments

Comments
 (0)