Skip to content

Commit 37a90d5

Browse files
Extract _guess_type from convert_type and add overloads
This is a refactor that was original part of `typing/paramtype` branch but split out of #3371 to keep the latter focused on typing only. Co-authored-by: Kevin Deldycke <kevin@deldycke.com>
1 parent d777956 commit 37a90d5

1 file changed

Lines changed: 65 additions & 34 deletions

File tree

src/click/types.py

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,64 +1109,95 @@ def convert(
11091109
)
11101110

11111111

1112-
def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType:
1112+
def _guess_type(
1113+
ty: type[t.Any] | ParamType | None,
1114+
default: t.Any | None,
1115+
) -> type[t.Any] | tuple[type[t.Any], ...] | ParamType | None:
1116+
"""Infer a type from *ty* or *default*.
1117+
1118+
Returns *ty* unchanged when it is not ``None``. Otherwise inspects
1119+
*default* to produce a ``type``, a ``tuple`` of types (for tuple
1120+
defaults), or ``None``.
1121+
"""
1122+
if ty is not None:
1123+
return ty
1124+
1125+
if default is None:
1126+
return None
1127+
1128+
if not isinstance(default, (tuple, list)):
1129+
return type(default)
1130+
1131+
# If the default is empty, return None so convert_type falls
1132+
# through to STRING.
1133+
if not default:
1134+
return None
1135+
1136+
item = default[0]
1137+
1138+
# A sequence of iterables needs to detect the inner types.
1139+
# Can't call convert_type recursively because that would
1140+
# incorrectly unwind the tuple to a single type.
1141+
if isinstance(item, (tuple, list)):
1142+
return tuple(map(type, item))
1143+
1144+
return type(item)
1145+
1146+
1147+
@t.overload
1148+
def convert_type(ty: None, default: None = None) -> StringParamType: ...
1149+
1150+
1151+
@t.overload
1152+
def convert_type(
1153+
ty: type[t.Any] | ParamType, default: t.Any | None = None
1154+
) -> ParamType: ...
1155+
1156+
1157+
@t.overload
1158+
def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: ...
1159+
1160+
1161+
def convert_type(ty: t.Any | None = None, default: t.Any | None = None) -> ParamType:
11131162
"""Find the most appropriate :class:`ParamType` for the given Python
11141163
type. If the type isn't provided, it can be inferred from a default
11151164
value.
11161165
"""
1117-
guessed_type = False
1118-
1119-
if ty is None and default is not None:
1120-
if isinstance(default, (tuple, list)):
1121-
# If the default is empty, ty will remain None and will
1122-
# return STRING.
1123-
if default:
1124-
item = default[0]
1125-
1126-
# A tuple of tuples needs to detect the inner types.
1127-
# Can't call convert recursively because that would
1128-
# incorrectly unwind the tuple to a single type.
1129-
if isinstance(item, (tuple, list)):
1130-
ty = tuple(map(type, item))
1131-
else:
1132-
ty = type(item)
1133-
else:
1134-
ty = type(default)
1166+
guessed = _guess_type(ty, default)
1167+
is_guessed = guessed is not ty
11351168

1136-
guessed_type = True
1169+
if isinstance(guessed, tuple):
1170+
return Tuple(guessed)
11371171

1138-
if isinstance(ty, tuple):
1139-
return Tuple(ty)
1140-
1141-
if isinstance(ty, ParamType):
1142-
return ty
1172+
if isinstance(guessed, ParamType):
1173+
return guessed
11431174

1144-
if ty is str or ty is None:
1175+
if guessed is str or guessed is None:
11451176
return STRING
11461177

1147-
if ty is int:
1178+
if guessed is int:
11481179
return INT
11491180

1150-
if ty is float:
1181+
if guessed is float:
11511182
return FLOAT
11521183

1153-
if ty is bool:
1184+
if guessed is bool:
11541185
return BOOL
11551186

1156-
if guessed_type:
1187+
if is_guessed:
11571188
return STRING
11581189

11591190
if __debug__:
11601191
try:
1161-
if issubclass(ty, ParamType):
1192+
if issubclass(guessed, ParamType):
11621193
raise AssertionError(
1163-
f"Attempted to use an uninstantiated parameter type ({ty})."
1194+
f"Attempted to use an uninstantiated parameter type ({guessed})."
11641195
)
11651196
except TypeError:
1166-
# ty is an instance (correct), so issubclass fails.
1197+
# guessed is an instance (correct), so issubclass fails.
11671198
pass
11681199

1169-
return FuncParamType(ty)
1200+
return FuncParamType(guessed)
11701201

11711202

11721203
#: A dummy parameter type that just does nothing. From a user's

0 commit comments

Comments
 (0)