@@ -300,6 +300,7 @@ if they evaluate to the same value (``str``), such as
300
300
Type Inference
301
301
==============
302
302
303
+ .. _inferring_literal_str :
303
304
304
305
Inferring ``Literal[str] ``
305
306
--------------------------
@@ -327,6 +328,10 @@ following cases:
327
328
has type ``Literal[str] `` if and only if ``s `` and the arguments have
328
329
types compatible with ``Literal[str] ``.
329
330
331
+ + Literal-preserving methods: In `Appendix C <appendix_C _>`_, we have
332
+ provided an exhaustive list of ``str `` methods that preserve the
333
+ ``Literal[str] `` type.
334
+
330
335
In all other cases, if one or more of the composed values has a
331
336
non-literal type ``str ``, the composition of types will have type
332
337
``str ``. For example, if ``s `` has type ``str ``, then ``"hello" + s ``
@@ -955,6 +960,246 @@ is documentation, which is easily ignored and often not seen. With
955
960
``Literal[str] ``, API misuse requires conscious thought and artifacts
956
961
in the code that reviewers and future developers can notice.
957
962
963
+ .. _appendix_C :
964
+
965
+ Appendix C: ``str `` methods that preserve ``Literal[str] ``
966
+ ==========================================================
967
+
968
+ The ``str `` class has several methods that would benefit from
969
+ ``Literal[str] ``. For example, users might expect
970
+ ``"hello".capitalize() `` to have the type ``Literal[str] `` similar to
971
+ the other examples we have seen in the `Inferring Literal[str] section
972
+ <inferring_literal_str> `_ section. Inferring the type ``Literal[str] ``
973
+ is correct because the string is not an arbitrary user-supplied
974
+ string. In other words, the ``capitalize `` method preserves the
975
+ ``Literal[str] `` type. There are several other methods that preserve
976
+ the ``Literal[str] ``.
977
+
978
+ We face a tradeoff in this PEP. We could require type checkers to
979
+ preserve ``Literal[str] `` either (a) only for the four cases mentioned
980
+ in the `Inferring Literal[str] section <inferring_literal_str _>`_
981
+ section or (b) for all the ``str `` methods for which it would be
982
+ valid. Option (a) might surprise users by losing the ``Literal[str] ``
983
+ type in innocuous uses, e.g., with ``my_literal.capitalize() ``. Option
984
+ (b) would be more user-friendly but would require some more work from
985
+ type checkers.
986
+
987
+ We decided to favor user-friendliness and go with option (b). However,
988
+ if the Steering Council feels the other way, we are willing to go with
989
+ option (a).
990
+
991
+ Further, we propose updating the stub for ``str `` in typeshed so that
992
+ the methods are overloads with the ``Literal[str] ``-preserving
993
+ versions. This means type checkers do not have hardcode
994
+ ``Literal[str] `` behavior for each method. This also lets us easily
995
+ support new methods in the future by updating the typeshed stub.
996
+
997
+ For example, to preserve literal types for the ``capitalize `` method,
998
+ we would change the stub as below:
999
+
1000
+ ::
1001
+
1002
+ # before
1003
+ def capitalize(self) -> str: ...
1004
+
1005
+ # after
1006
+ @overload
1007
+ def capitalize(self: Literal[str]) -> Literal[str]: ...
1008
+ @overload
1009
+ def capitalize(self) -> str: ...
1010
+
1011
+ The downside of changing ``str `` stub is that the stub becomes more
1012
+ complicated and can make error messages harder to understand. Type
1013
+ checkers may need to special-case ``str `` so that error messages are
1014
+ understandable for users.
1015
+
1016
+ If the Steering Council is opposed to this typeshed stub change, we
1017
+ will require type checkers to hardcode these methods.
1018
+
1019
+ Below is an exhaustive list of ``str `` methods which, when called as
1020
+ indicated with ``Literal[str]``(s) must be treated as returning a
1021
+ ``Literal[str] ``. If this PEP is accepted, we will update these method
1022
+ signatures in typeshed:
1023
+
1024
+ ::
1025
+
1026
+ @overload
1027
+ def __new__(cls, object: Literal[str] = ...) -> Literal[str]: ...
1028
+ @overload
1029
+
1030
+ @overload
1031
+ def capitalize(self: Literal[str]) -> Literal[str]: ...
1032
+ @overload
1033
+ def capitalize(self) -> str: ...
1034
+
1035
+ @overload
1036
+ def casefold(self: Literal[str]) -> Literal[str]: ...
1037
+ @overload
1038
+ def casefold(self) -> str: ...
1039
+
1040
+ @overload
1041
+ def center(self: Literal[str], __width: SupportsIndex, __fillchar: Literal[str] = ...) -> Literal[str]: ...
1042
+ @overload
1043
+ def center(self, __width: SupportsIndex, __fillchar: str = ...) -> str: ...
1044
+
1045
+ if sys.version_info >= (3, 8):
1046
+ @overload
1047
+ def expandtabs(self: Literal[str], tabsize: SupportsIndex = ...) -> Literal[str]: ...
1048
+ @overload
1049
+ def expandtabs(self, tabsize: SupportsIndex = ...) -> str: ...
1050
+
1051
+ else:
1052
+ @overload
1053
+ def expandtabs(self: Literal[str], tabsize: int = ...) -> Literal[str]: ...
1054
+ @overload
1055
+ def expandtabs(self, tabsize: int = ...) -> str: ...
1056
+
1057
+ @overload
1058
+ def format(self: Literal[str], *args: Literal[str], **kwargs: Literal[str]) -> Literal[str]: ...
1059
+ @overload
1060
+ def format(self, *args: str, **kwargs: str) -> str: ...
1061
+
1062
+ @overload
1063
+ def format_map(self: Literal[str], map: Mapping[str, Literal[str]]) -> Literal[str]: ...
1064
+ @overload
1065
+ def format_map(self, map: Mapping[str, str]) -> str: ...
1066
+
1067
+ @overload
1068
+ def join(self: Literal[str], __iterable: Iterable[Literal[str]]) -> Literal[str]: ...
1069
+ @overload
1070
+ def join(self, __iterable: Iterable[str]) -> str: ...
1071
+
1072
+ @overload
1073
+ def ljust(self: Literal[str], __width: SupportsIndex, __fillchar: Literal[str] = ...) -> Literal[str]: ...
1074
+ @overload
1075
+ def ljust(self, __width: SupportsIndex, __fillchar: str = ...) -> str: ...
1076
+
1077
+ @overload
1078
+ def lower(self: Literal[str]) -> Literal[str]: ...
1079
+ @overload
1080
+ def lower(self) -> Literal[str]: ...
1081
+
1082
+ @overload
1083
+ def lstrip(self: Literal[str], __chars: Literal[str] | None = ...) -> Literal[str]: ...
1084
+ @overload
1085
+ def lstrip(self, __chars: str | None = ...) -> str: ...
1086
+
1087
+ @overload
1088
+ def partition(self: Literal[str], __sep: Literal[str]) -> tuple[Literal[str], Literal[str], Literal[str]]: ...
1089
+ @overload
1090
+ def partition(self, __sep: str) -> tuple[str, str, str]: ...
1091
+
1092
+ @overload
1093
+ def replace(self: Literal[str], __old: Literal[str], __new: Literal[str], __count: SupportsIndex = ...) -> Literal[str]: ...
1094
+ @overload
1095
+ def replace(self, __old: str, __new: str, __count: SupportsIndex = ...) -> str: ...
1096
+
1097
+ if sys.version_info >= (3, 9):
1098
+ @overload
1099
+ def removeprefix(self: Literal[str], __prefix: Literal[str]) -> Literal[str]: ...
1100
+ @overload
1101
+ def removeprefix(self, __prefix: str) -> str: ...
1102
+
1103
+ @overload
1104
+ def removesuffix(self: Literal[str], __suffix: Literal[str]) -> Literal[str]: ...
1105
+ @overload
1106
+ def removesuffix(self, __suffix: str) -> str: ...
1107
+
1108
+ @overload
1109
+ def rjust(self: Literal[str], __width: SupportsIndex, __fillchar: Literal[str] = ...) -> Literal[str]: ...
1110
+ @overload
1111
+ def rjust(self, __width: SupportsIndex, __fillchar: str = ...) -> str: ...
1112
+
1113
+ @overload
1114
+ def rpartition(self: Literal[str], __sep: Literal[str]) -> tuple[Literal[str], Literal[str], Literal[str]]: ...
1115
+ @overload
1116
+ def rpartition(self, __sep: str) -> tuple[str, str, str]: ...
1117
+
1118
+ @overload
1119
+ def rsplit(self: Literal[str], sep: Literal[str] | None = ..., maxsplit: SupportsIndex = ...) -> list[Literal[str]]: ...
1120
+ @overload
1121
+ def rsplit(self, sep: str | None = ..., maxsplit: SupportsIndex = ...) -> list[str]: ...
1122
+
1123
+ @overload
1124
+ def rstrip(self: Literal[str], __chars: Literal[str] | None = ...) -> Literal[str]: ...
1125
+ @overload
1126
+ def rstrip(self, __chars: str | None = ...) -> str: ...
1127
+
1128
+ @overload
1129
+ def split(self: Literal[str], sep: Literal[str] | None = ..., maxsplit: SupportsIndex = ...) -> list[Literal[str]]: ...
1130
+ @overload
1131
+ def split(self, sep: str | None = ..., maxsplit: SupportsIndex = ...) -> list[str]: ...
1132
+
1133
+ @overload
1134
+ def splitlines(self: Literal[str], keepends: bool = ...) -> list[Literal[str]]: ...
1135
+ @overload
1136
+ def splitlines(self, keepends: bool = ...) -> list[str]: ...
1137
+
1138
+ @overload
1139
+ def strip(self: Literal[str], __chars: Literal[str] | None = ...) -> Literal[str]: ...
1140
+ @overload
1141
+ def strip(self, __chars: str | None = ...) -> str: ...
1142
+
1143
+ @overload
1144
+ def swapcase(self: Literal[str]) -> Literal[str]: ...
1145
+ @overload
1146
+ def swapcase(self) -> str: ...
1147
+
1148
+ @overload
1149
+ def title(self: Literal[str]) -> Literal[str]: ...
1150
+ @overload
1151
+ def title(self) -> str: ...
1152
+
1153
+ @overload
1154
+ def upper(self: Literal[str]) -> Literal[str]: ...
1155
+ @overload
1156
+ def upper(self) -> str: ...
1157
+
1158
+ @overload
1159
+ def zfill(self: Literal[str], __width: SupportsIndex) -> Literal[str]: ...
1160
+ @overload
1161
+ def zfill(self, __width: SupportsIndex) -> str: ...
1162
+
1163
+ @overload
1164
+ def __add__(self: Literal[str], __s: Literal[str]) -> Literal[str]: ...
1165
+ @overload
1166
+ def __add__(self, __s: str) -> str: ...
1167
+
1168
+ @overload
1169
+ def __iter__(self: Literal[str]) -> Iterator[str]: ...
1170
+ @overload
1171
+ def __iter__(self) -> Iterator[str]: ...
1172
+
1173
+ @overload
1174
+ def __mod__(self: Literal[str], __x: Union[Literal[str], Tuple[Literal[str], ...]]) -> str: ...
1175
+ @overload
1176
+ def __mod__(self, __x: Union[str, Tuple[str, ...]]) -> str: ...
1177
+
1178
+ @overload
1179
+ def __mul__(self: Literal[str], __n: SupportsIndex) -> Literal[str]: ...
1180
+ @overload
1181
+ def __mul__(self, __n: SupportsIndex) -> str: ...
1182
+
1183
+ @overload
1184
+ def __repr__(self: Literal[str]) -> Literal[str]: ...
1185
+ @overload
1186
+ def __repr__(self) -> str: ...
1187
+
1188
+ @overload
1189
+ def __rmul__(self: Literal[str], n: SupportsIndex) -> Literal[str]: ...
1190
+ @overload
1191
+ def __rmul__(self, n: SupportsIndex) -> str: ...
1192
+
1193
+ @overload
1194
+ def __str__(self: Literal[str]) -> Literal[str]: ...
1195
+ @overload
1196
+ def __str__(self) -> str: ...
1197
+
1198
+ @overload
1199
+ def __getnewargs__(self: Literal[str]) -> tuple[Literal[str]]: ...
1200
+ @overload
1201
+ def __getnewargs__(self) -> tuple[str]: ...
1202
+
958
1203
Resources
959
1204
=========
960
1205
0 commit comments