From 8d5b30546ebad13d2bf19f2a464abb13064f3fa3 Mon Sep 17 00:00:00 2001 From: Timmy Welch Date: Thu, 22 Feb 2024 14:42:07 -0800 Subject: [PATCH] Improve type guessing for generic Sequence types --- settngs/__init__.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/settngs/__init__.py b/settngs/__init__.py index 929dd6c..077114a 100644 --- a/settngs/__init__.py +++ b/settngs/__init__.py @@ -13,6 +13,7 @@ from collections import defaultdict from collections.abc import Sequence from typing import Any from typing import Callable +from typing import cast from typing import Dict from typing import Generic from typing import NoReturn @@ -84,6 +85,20 @@ else: # pragma: no cover removeprefix = str.removeprefix +def _isnamedtupleinstance(x: Any) -> bool: + t = type(x) + b = t.__bases__ + + if len(b) != 1 or b[0] != tuple: + return False + + f = getattr(t, '_fields', None) + if not isinstance(f, tuple): + return False + + return all(isinstance(n, str) for n in f) + + class Setting: def __init__( self, @@ -199,6 +214,11 @@ class Setting: return str else: if not self.cmdline and self.default is not None: + if not isinstance(self.default, str) and not _isnamedtupleinstance(self.default) and isinstance(self.default, Sequence) and self.default and self.default[0]: + try: + return cast(type, type(self.default)[type(self.default[0])]) + except Exception: + ... return type(self.default) return 'Any' @@ -211,6 +231,11 @@ class Setting: t: type | str = type_hints['return'] return t if self.default is not None: + if not isinstance(self.default, str) and not _isnamedtupleinstance(self.default) and isinstance(self.default, Sequence) and self.default and self.default[0]: + try: + return cast(type, type(self.default)[type(self.default[0])]) + except Exception: + ... return type(self.default) return 'Any'