Skip to content

Commit d2e4a42

Browse files
Extract _guess_type from convert_type and add overloads (#3372)
Co-authored-by: Andreas Backx <AndreasBackx@users.noreply.github.com>
1 parent 25edc1e commit d2e4a42

1 file changed

Lines changed: 69 additions & 34 deletions

File tree

src/click/types.py

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,64 +1157,99 @@ def convert(
11571157
)
11581158

11591159

1160-
def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType[t.Any]:
1160+
def _guess_type(
1161+
ty: type[t.Any] | ParamType[t.Any] | None,
1162+
default: t.Any | None,
1163+
) -> type[t.Any] | tuple[type[t.Any], ...] | ParamType[t.Any] | None:
1164+
"""Infer a type from *ty* or *default*.
1165+
1166+
Returns *ty* unchanged when it is not ``None``. Otherwise inspects
1167+
*default* to produce a ``type``, a ``tuple`` of types (for tuple
1168+
defaults), or ``None``.
1169+
"""
1170+
if ty is not None:
1171+
return ty
1172+
1173+
if default is None:
1174+
return None
1175+
1176+
if not isinstance(default, (tuple, list)):
1177+
return type(default)
1178+
1179+
# If the default is empty, return None so convert_type falls
1180+
# through to STRING.
1181+
if not default:
1182+
return None
1183+
1184+
item = default[0]
1185+
1186+
# A sequence of iterables needs to detect the inner types.
1187+
# Can't call convert_type recursively because that would
1188+
# incorrectly unwind the tuple to a single type.
1189+
if isinstance(item, (tuple, list)):
1190+
return tuple(map(type, item))
1191+
1192+
return type(item)
1193+
1194+
1195+
@t.overload
1196+
def convert_type(ty: None, default: None = None) -> StringParamType: ...
1197+
1198+
1199+
@t.overload
1200+
def convert_type(
1201+
ty: type[t.Any] | ParamType[t.Any], default: t.Any | None = None
1202+
) -> ParamType[t.Any]: ...
1203+
1204+
1205+
@t.overload
1206+
def convert_type(
1207+
ty: t.Any | None, default: t.Any | None = None
1208+
) -> ParamType[t.Any]: ...
1209+
1210+
1211+
def convert_type(
1212+
ty: t.Any | None = None, default: t.Any | None = None
1213+
) -> ParamType[t.Any]:
11611214
"""Find the most appropriate :class:`ParamType` for the given Python
11621215
type. If the type isn't provided, it can be inferred from a default
11631216
value.
11641217
"""
1165-
guessed_type = False
1166-
1167-
if ty is None and default is not None:
1168-
if isinstance(default, (tuple, list)):
1169-
# If the default is empty, ty will remain None and will
1170-
# return STRING.
1171-
if default:
1172-
item = default[0]
1173-
1174-
# A tuple of tuples needs to detect the inner types.
1175-
# Can't call convert recursively because that would
1176-
# incorrectly unwind the tuple to a single type.
1177-
if isinstance(item, (tuple, list)):
1178-
ty = tuple(map(type, item))
1179-
else:
1180-
ty = type(item)
1181-
else:
1182-
ty = type(default)
1218+
guessed = _guess_type(ty, default)
1219+
is_guessed = guessed is not ty
11831220

1184-
guessed_type = True
1221+
if isinstance(guessed, tuple):
1222+
return Tuple(guessed)
11851223

1186-
if isinstance(ty, tuple):
1187-
return Tuple(ty)
1188-
1189-
if isinstance(ty, ParamType):
1190-
return ty
1224+
if isinstance(guessed, ParamType):
1225+
return guessed
11911226

1192-
if ty is str or ty is None:
1227+
if guessed is str or guessed is None:
11931228
return STRING
11941229

1195-
if ty is int:
1230+
if guessed is int:
11961231
return INT
11971232

1198-
if ty is float:
1233+
if guessed is float:
11991234
return FLOAT
12001235

1201-
if ty is bool:
1236+
if guessed is bool:
12021237
return BOOL
12031238

1204-
if guessed_type:
1239+
if is_guessed:
12051240
return STRING
12061241

12071242
if __debug__:
12081243
try:
1209-
if issubclass(ty, ParamType):
1244+
if issubclass(guessed, ParamType):
12101245
raise AssertionError(
1211-
f"Attempted to use an uninstantiated parameter type ({ty})."
1246+
f"Attempted to use an uninstantiated parameter type ({guessed})."
12121247
)
12131248
except TypeError:
1214-
# ty is an instance (correct), so issubclass fails.
1249+
# guessed is an instance (correct), so issubclass fails.
12151250
pass
12161251

1217-
return FuncParamType(ty)
1252+
return FuncParamType(guessed)
12181253

12191254

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

0 commit comments

Comments
 (0)