summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2023-05-16 20:18:28 +0300
committerGitHub <noreply@github.com>2023-05-16 17:18:28 +0000
commita454a6651ba26ed623377dd01ed62a0a22afa8c7 (patch)
tree6d5b189b679cb9994f1cec99bf1bd93cd0dfa475
parent1163782868454287ca9ac170aaebca4beeb83192 (diff)
downloadcpython-git-a454a6651ba26ed623377dd01ed62a0a22afa8c7.tar.gz
gh-104050: Add more annotations to `Tools/clinic.py` (#104544)
-rwxr-xr-xTools/clinic/clinic.py82
-rw-r--r--Tools/clinic/cpp.py7
-rw-r--r--Tools/clinic/mypy.ini1
3 files changed, 60 insertions, 30 deletions
diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 0ef5deb586..dfe43c80ef 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -28,7 +28,7 @@ import traceback
from collections.abc import Callable
from types import FunctionType, NoneType
-from typing import Any, NamedTuple
+from typing import Any, NamedTuple, NoReturn, Literal, overload
# TODO:
#
@@ -59,21 +59,21 @@ CLINIC_PREFIXED_ARGS = {
}
class Unspecified:
- def __repr__(self):
+ def __repr__(self) -> str:
return '<Unspecified>'
unspecified = Unspecified()
class Null:
- def __repr__(self):
+ def __repr__(self) -> str:
return '<Null>'
NULL = Null()
class Unknown:
- def __repr__(self):
+ def __repr__(self) -> str:
return '<Unknown>'
unknown = Unknown()
@@ -81,15 +81,15 @@ unknown = Unknown()
sig_end_marker = '--'
Appender = Callable[[str], None]
-Outputter = Callable[[None], str]
+Outputter = Callable[[], str]
class _TextAccumulator(NamedTuple):
text: list[str]
append: Appender
output: Outputter
-def _text_accumulator():
- text = []
+def _text_accumulator() -> _TextAccumulator:
+ text: list[str] = []
def output():
s = ''.join(text)
text.clear()
@@ -98,10 +98,10 @@ def _text_accumulator():
class TextAccumulator(NamedTuple):
- text: list[str]
append: Appender
+ output: Outputter
-def text_accumulator():
+def text_accumulator() -> TextAccumulator:
"""
Creates a simple text accumulator / joiner.
@@ -115,8 +115,28 @@ def text_accumulator():
text, append, output = _text_accumulator()
return TextAccumulator(append, output)
-
-def warn_or_fail(fail=False, *args, filename=None, line_number=None):
+@overload
+def warn_or_fail(
+ *args: object,
+ fail: Literal[True],
+ filename: str | None = None,
+ line_number: int | None = None,
+) -> NoReturn: ...
+
+@overload
+def warn_or_fail(
+ *args: object,
+ fail: Literal[False] = False,
+ filename: str | None = None,
+ line_number: int | None = None,
+) -> None: ...
+
+def warn_or_fail(
+ *args: object,
+ fail: bool = False,
+ filename: str | None = None,
+ line_number: int | None = None,
+) -> None:
joined = " ".join([str(a) for a in args])
add, output = text_accumulator()
if fail:
@@ -139,14 +159,22 @@ def warn_or_fail(fail=False, *args, filename=None, line_number=None):
sys.exit(-1)
-def warn(*args, filename=None, line_number=None):
- return warn_or_fail(False, *args, filename=filename, line_number=line_number)
+def warn(
+ *args: object,
+ filename: str | None = None,
+ line_number: int | None = None,
+) -> None:
+ return warn_or_fail(*args, filename=filename, line_number=line_number, fail=False)
-def fail(*args, filename=None, line_number=None):
- return warn_or_fail(True, *args, filename=filename, line_number=line_number)
+def fail(
+ *args: object,
+ filename: str | None = None,
+ line_number: int | None = None,
+) -> NoReturn:
+ warn_or_fail(*args, filename=filename, line_number=line_number, fail=True)
-def quoted_for_c_string(s):
+def quoted_for_c_string(s: str) -> str:
for old, new in (
('\\', '\\\\'), # must be first!
('"', '\\"'),
@@ -155,13 +183,13 @@ def quoted_for_c_string(s):
s = s.replace(old, new)
return s
-def c_repr(s):
+def c_repr(s: str) -> str:
return '"' + s + '"'
is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match
-def is_legal_py_identifier(s):
+def is_legal_py_identifier(s: str) -> bool:
return all(is_legal_c_identifier(field) for field in s.split('.'))
# identifiers that are okay in Python but aren't a good idea in C.
@@ -174,7 +202,7 @@ register return short signed sizeof static struct switch
typedef typeof union unsigned void volatile while
""".strip().split())
-def ensure_legal_c_identifier(s):
+def ensure_legal_c_identifier(s: str) -> str:
# for now, just complain if what we're given isn't legal
if not is_legal_c_identifier(s):
fail("Illegal C identifier: {}".format(s))
@@ -183,7 +211,7 @@ def ensure_legal_c_identifier(s):
return s + "_value"
return s
-def rstrip_lines(s):
+def rstrip_lines(s: str) -> str:
text, add, output = _text_accumulator()
for line in s.split('\n'):
add(line.rstrip())
@@ -191,14 +219,14 @@ def rstrip_lines(s):
text.pop()
return output()
-def format_escape(s):
+def format_escape(s: str) -> str:
# double up curly-braces, this string will be used
# as part of a format_map() template later
s = s.replace('{', '{{')
s = s.replace('}', '}}')
return s
-def linear_format(s, **kwargs):
+def linear_format(s: str, **kwargs: str) -> str:
"""
Perform str.format-like substitution, except:
* The strings substituted must be on lines by
@@ -242,7 +270,7 @@ def linear_format(s, **kwargs):
return output()[:-1]
-def indent_all_lines(s, prefix):
+def indent_all_lines(s: str, prefix: str) -> str:
"""
Returns 's', with 'prefix' prepended to all lines.
@@ -263,7 +291,7 @@ def indent_all_lines(s, prefix):
final.append(last)
return ''.join(final)
-def suffix_all_lines(s, suffix):
+def suffix_all_lines(s: str, suffix: str) -> str:
"""
Returns 's', with 'suffix' appended to all lines.
@@ -283,7 +311,7 @@ def suffix_all_lines(s, suffix):
return ''.join(final)
-def version_splitter(s):
+def version_splitter(s: str) -> tuple[int, ...]:
"""Splits a version string into a tuple of integers.
The following ASCII characters are allowed, and employ
@@ -294,7 +322,7 @@ def version_splitter(s):
(This permits Python-style version strings such as "1.4b3".)
"""
version = []
- accumulator = []
+ accumulator: list[str] = []
def flush():
if not accumulator:
raise ValueError('Unsupported version string: ' + repr(s))
@@ -314,7 +342,7 @@ def version_splitter(s):
flush()
return tuple(version)
-def version_comparitor(version1, version2):
+def version_comparitor(version1: str, version2: str) -> Literal[-1, 0, 1]:
iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0)
for i, (a, b) in enumerate(iterator):
if a < b:
diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py
index bc2cc713aa..a3546f570c 100644
--- a/Tools/clinic/cpp.py
+++ b/Tools/clinic/cpp.py
@@ -1,6 +1,7 @@
import re
import sys
from collections.abc import Callable
+from typing import NoReturn
TokenAndCondition = tuple[str, str]
@@ -30,7 +31,7 @@ class Monitor:
is_a_simple_defined: Callable[[str], re.Match[str] | None]
is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match
- def __init__(self, filename=None, *, verbose: bool = False):
+ def __init__(self, filename: str | None = None, *, verbose: bool = False) -> None:
self.stack: TokenStack = []
self.in_comment = False
self.continuation: str | None = None
@@ -55,7 +56,7 @@ class Monitor:
"""
return " && ".join(condition for token, condition in self.stack)
- def fail(self, *a):
+ def fail(self, *a: object) -> NoReturn:
if self.filename:
filename = " " + self.filename
else:
@@ -64,7 +65,7 @@ class Monitor:
print(" ", ' '.join(str(x) for x in a))
sys.exit(-1)
- def close(self):
+ def close(self) -> None:
if self.stack:
self.fail("Ended file while still in a preprocessor conditional block!")
diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini
index 3c5643e789..672911dc19 100644
--- a/Tools/clinic/mypy.ini
+++ b/Tools/clinic/mypy.ini
@@ -8,4 +8,5 @@ strict_concatenate = True
warn_redundant_casts = True
warn_unused_ignores = True
warn_unused_configs = True
+warn_unreachable = True
files = Tools/clinic/