Skip to content

Commit 2da1479

Browse files
committed
gh-113317, AC: Add libclinic.parameter
* Move Parameter class to a new libclinic.parameter module. * Move VersionTuple and Sentinels to libclinic.utils.
1 parent 2a54c4b commit 2da1479

File tree

4 files changed

+100
-80
lines changed

4 files changed

+100
-80
lines changed

Tools/clinic/clinic.py

Lines changed: 4 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import builtins as bltns
1313
import collections
1414
import contextlib
15-
import copy
1615
import dataclasses as dc
1716
import enum
1817
import functools
@@ -50,7 +49,10 @@
5049
# Local imports.
5150
import libclinic
5251
import libclinic.cpp
53-
from libclinic import ClinicError, fail, warn
52+
from libclinic import (
53+
ClinicError, Sentinels, VersionTuple,
54+
fail, warn, unspecified, unknown)
55+
from libclinic.parameter import Parameter
5456

5557

5658
# TODO:
@@ -70,18 +72,6 @@
7072
LIMITED_CAPI_REGEX = re.compile(r'# *define +Py_LIMITED_API')
7173

7274

73-
class Sentinels(enum.Enum):
74-
unspecified = "unspecified"
75-
unknown = "unknown"
76-
77-
def __repr__(self) -> str:
78-
return f"<{self.value.capitalize()}>"
79-
80-
81-
unspecified: Final = Sentinels.unspecified
82-
unknown: Final = Sentinels.unknown
83-
84-
8575
# This one needs to be a distinct class, unlike the other two
8676
class Null:
8777
def __repr__(self) -> str:
@@ -2652,71 +2642,6 @@ def copy(self, **overrides: Any) -> Function:
26522642
return f
26532643

26542644

2655-
VersionTuple = tuple[int, int]
2656-
2657-
2658-
@dc.dataclass(repr=False, slots=True)
2659-
class Parameter:
2660-
"""
2661-
Mutable duck type of inspect.Parameter.
2662-
"""
2663-
name: str
2664-
kind: inspect._ParameterKind
2665-
_: dc.KW_ONLY
2666-
default: object = inspect.Parameter.empty
2667-
function: Function
2668-
converter: CConverter
2669-
annotation: object = inspect.Parameter.empty
2670-
docstring: str = ''
2671-
group: int = 0
2672-
# (`None` signifies that there is no deprecation)
2673-
deprecated_positional: VersionTuple | None = None
2674-
deprecated_keyword: VersionTuple | None = None
2675-
right_bracket_count: int = dc.field(init=False, default=0)
2676-
2677-
def __repr__(self) -> str:
2678-
return f'<clinic.Parameter {self.name!r}>'
2679-
2680-
def is_keyword_only(self) -> bool:
2681-
return self.kind == inspect.Parameter.KEYWORD_ONLY
2682-
2683-
def is_positional_only(self) -> bool:
2684-
return self.kind == inspect.Parameter.POSITIONAL_ONLY
2685-
2686-
def is_vararg(self) -> bool:
2687-
return self.kind == inspect.Parameter.VAR_POSITIONAL
2688-
2689-
def is_optional(self) -> bool:
2690-
return not self.is_vararg() and (self.default is not unspecified)
2691-
2692-
def copy(
2693-
self,
2694-
/,
2695-
*,
2696-
converter: CConverter | None = None,
2697-
function: Function | None = None,
2698-
**overrides: Any
2699-
) -> Parameter:
2700-
function = function or self.function
2701-
if not converter:
2702-
converter = copy.copy(self.converter)
2703-
converter.function = function
2704-
return dc.replace(self, **overrides, function=function, converter=converter)
2705-
2706-
def get_displayname(self, i: int) -> str:
2707-
if i == 0:
2708-
return 'argument'
2709-
if not self.is_positional_only():
2710-
return f'argument {self.name!r}'
2711-
else:
2712-
return f'argument {i}'
2713-
2714-
def render_docstring(self) -> str:
2715-
lines = [f" {self.name}"]
2716-
lines.extend(f" {line}" for line in self.docstring.split("\n"))
2717-
return "\n".join(lines).rstrip()
2718-
2719-
27202645
CConverterClassT = TypeVar("CConverterClassT", bound=type["CConverter"])
27212646

27222647
def add_c_converter(

Tools/clinic/libclinic/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
compute_checksum,
2929
create_regex,
3030
write_file,
31+
VersionTuple,
32+
Sentinels,
33+
unspecified,
34+
unknown,
3135
)
3236

3337

@@ -60,6 +64,10 @@
6064
"compute_checksum",
6165
"create_regex",
6266
"write_file",
67+
"VersionTuple",
68+
"Sentinels",
69+
"unspecified",
70+
"unknown",
6371
]
6472

6573

Tools/clinic/libclinic/parameter.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from __future__ import annotations
2+
import copy
3+
import dataclasses as dc
4+
import inspect
5+
from typing import Any, TYPE_CHECKING
6+
7+
from libclinic import VersionTuple, unspecified
8+
if TYPE_CHECKING:
9+
from clinic import Function, CConverter
10+
11+
12+
@dc.dataclass(repr=False, slots=True)
13+
class Parameter:
14+
"""
15+
Mutable duck type of inspect.Parameter.
16+
"""
17+
name: str
18+
kind: inspect._ParameterKind
19+
_: dc.KW_ONLY
20+
default: object = inspect.Parameter.empty
21+
function: Function
22+
converter: CConverter
23+
annotation: object = inspect.Parameter.empty
24+
docstring: str = ''
25+
group: int = 0
26+
# (`None` signifies that there is no deprecation)
27+
deprecated_positional: VersionTuple | None = None
28+
deprecated_keyword: VersionTuple | None = None
29+
right_bracket_count: int = dc.field(init=False, default=0)
30+
31+
def __repr__(self) -> str:
32+
return f'<clinic.Parameter {self.name!r}>'
33+
34+
def is_keyword_only(self) -> bool:
35+
return self.kind == inspect.Parameter.KEYWORD_ONLY
36+
37+
def is_positional_only(self) -> bool:
38+
return self.kind == inspect.Parameter.POSITIONAL_ONLY
39+
40+
def is_vararg(self) -> bool:
41+
return self.kind == inspect.Parameter.VAR_POSITIONAL
42+
43+
def is_optional(self) -> bool:
44+
return not self.is_vararg() and (self.default is not unspecified)
45+
46+
def copy(
47+
self,
48+
/,
49+
*,
50+
converter: CConverter | None = None,
51+
function: Function | None = None,
52+
**overrides: Any
53+
) -> Parameter:
54+
function = function or self.function
55+
if not converter:
56+
converter = copy.copy(self.converter)
57+
converter.function = function
58+
return dc.replace(self, **overrides, function=function, converter=converter)
59+
60+
def get_displayname(self, i: int) -> str:
61+
if i == 0:
62+
return 'argument'
63+
if not self.is_positional_only():
64+
return f'argument {self.name!r}'
65+
else:
66+
return f'argument {i}'
67+
68+
def render_docstring(self) -> str:
69+
lines = [f" {self.name}"]
70+
lines.extend(f" {line}" for line in self.docstring.split("\n"))
71+
return "\n".join(lines).rstrip()

Tools/clinic/libclinic/utils.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import collections
2+
import enum
23
import hashlib
34
import os
45
import re
56
import string
6-
from typing import Literal
7+
from typing import Literal, Final
78

89

910
def write_file(filename: str, new_contents: str) -> None:
@@ -66,3 +67,18 @@ def get_value(
6667
) -> Literal[""]:
6768
self.counts[key] += 1
6869
return ""
70+
71+
72+
VersionTuple = tuple[int, int]
73+
74+
75+
class Sentinels(enum.Enum):
76+
unspecified = "unspecified"
77+
unknown = "unknown"
78+
79+
def __repr__(self) -> str:
80+
return f"<{self.value.capitalize()}>"
81+
82+
83+
unspecified: Final = Sentinels.unspecified
84+
unknown: Final = Sentinels.unknown

0 commit comments

Comments
 (0)