diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4edf1f8..e536e5e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,6 +32,7 @@ repos: hooks: - id: pyupgrade args: [--py38-plus] + exclude: tests - repo: https://github.com/hhatto/autopep8 rev: v2.1.0 hooks: diff --git a/settngs/__init__.py b/settngs/__init__.py index 573a294..4a72812 100644 --- a/settngs/__init__.py +++ b/settngs/__init__.py @@ -13,11 +13,14 @@ import warnings from argparse import Namespace from collections import defaultdict from collections.abc import Sequence +from collections.abc import Set from typing import Any from typing import Callable from typing import cast +from typing import Collection from typing import Dict from typing import Generic +from typing import get_args from typing import NoReturn from typing import TYPE_CHECKING from typing import TypeVar @@ -25,6 +28,8 @@ from typing import Union logger = logging.getLogger(__name__) +NoneType = type(None) + if sys.version_info < (3, 11): # pragma: no cover from typing_extensions import NamedTuple else: # pragma: no cover @@ -43,6 +48,8 @@ if sys.version_info < (3, 9): # pragma: no cover def get_typing_type(t: type) -> type: if t.__module__ == 'builtins': + if t is NoneType: + return None return getattr(typing, t.__name__.title(), t) return t @@ -91,8 +98,8 @@ else: # pragma: no cover from argparse import BooleanOptionalAction removeprefix = str.removeprefix - def get_typing_type(t: type) -> type: - return t + def get_typing_type(t: type) -> type | None: + return None if t is NoneType else t def _isnamedtupleinstance(x: Any) -> bool: # pragma: no cover @@ -216,47 +223,115 @@ class Setting: return NotImplemented return self.__dict__ == other.__dict__ - def _guess_type(self) -> tuple[type | str | None, bool]: - if isinstance(self.type, type): - return self.type, self.default is None + __no_type = object() - __action_to_type = { - 'store_true': (bool, False), - 'store_false': (bool, False), - BooleanOptionalAction: (bool, self.default is None), - 'store_const': (type(self.const), self.default is None), - 'count': (int, self.default is None), - 'append': (List[str], self.default is None), - 'extend': (List[str], self.default is None), - 'append_const': (List[type(self.const)], self.default is None), # type: ignore[misc] - 'help': (None, self.default is None), - 'version': (None, self.default is None), - } + def _guess_collection(self) -> tuple[type | str | None, bool]: + def get_item_type(x: Any) -> type | None: + if x is None or not isinstance(x, (Set, Sequence)) or len(x) == 0: + t = self._process_type() # Specifically this is needed when using the extend action + if typing.get_args(t): # We need the item type not the type of the collection + return typing.get_args(t)[0] # type: ignore[no-any-return] - if self.action in __action_to_type: - return __action_to_type[self.action] + # Return None so that we get the default + return None if t is None else self.__no_type # type: ignore[return-value] + if isinstance(x, Set): + return type(next(iter(x))) + return type(x[0]) - if self.type is not None: - type_hints = typing.get_type_hints(self.type) - if 'return' in type_hints: - t: type | str = type_hints['return'] - return t, self.default is None + try: + list_type = self._process_type() + # if the type is a generic alias than return it immediately + if isinstance(list_type, types_GenericAlias) and issubclass(list_type.__origin__, Collection): + return list_type, self.default is None - 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]: + # Ensure that generic aliases work for python 3.8 + if list_type is not None: + list_type = get_typing_type(list_type) + else: + list_type = get_typing_type(type(self.default)) + + # Default to a list if we don't know what type of collection this is + if list_type is None or not issubclass(list_type, Collection): + list_type = List + + # Get the item type (int) in list[int] + it = get_item_type(self.default) + if isinstance(self.type, type): + it = self.type + + if it is self.__no_type: + return self._process_type() or List[str], self.default is None + + # Try to get the generic alias for this type + if it is not None: try: - t = get_typing_type(type(self.default)) - ret = cast(type, t[type(self.default[0])]), self.default is None # type: ignore[index] + ret = cast(type, list_type[it]), self.default is None # type: ignore[index] return ret except Exception: ... - return type(self.default), self.default is None - if self.cmdline and self.action is None and self.type is None: - if self.nargs in ('+', '*') or isinstance(self.nargs, int) and self.nargs > 1: - return List[str], self.default is None - return str, self.default is None - return 'Any', self.default is None + # Fall back to list[str] if anything fails + return list_type[str], self.default is None # type: ignore[index] + except Exception: + return None, self.default is None + + def _process_type(self) -> type | None: + if self.type is None: + return None + if isinstance(self.type, type): + return self.type + + return typing.get_type_hints(self.type).get('return', None) # type: ignore[no-any-return] + + def _guess_type_internal(self) -> tuple[type | str | None, bool]: + default_is_none = self.default is None + __action_to_type = { + 'store_true': (bool, False), + 'store_false': (bool, False), + BooleanOptionalAction: (bool, default_is_none), + 'store_const': (type(self.const), default_is_none), + 'count': (int, default_is_none), + 'extend': self._guess_collection(), + 'append_const': (List[type(self.const)], default_is_none), # type: ignore[misc] + 'help': (None, default_is_none), + 'version': (None, default_is_none), + } + + # Process standard actions + if self.action in __action_to_type: + return __action_to_type[self.action] + + # nargs > 1 is always a list + if self.nargs in ('+', '*') or isinstance(self.nargs, int) and self.nargs > 1: + return self._guess_collection() + + # Process the type argument + type_type = self._process_type() + if type_type is not None: + return type_type, default_is_none + + # Check if a default value was given. + if self.default is not None: + if not isinstance(self.default, str) and not _isnamedtupleinstance(self.default) and isinstance(self.default, (Set, Sequence)): + return self._guess_collection() + # The type argument will convert this if it is a string. We only get here if type is a function without type hints + if not (isinstance(self.default, str) and self.type is not None): + return type(self.default), default_is_none + + # There is no way to detemine the type from an action + if callable(self.action): + return 'Any', default_is_none + + # Finally if this is a commandline argument it will default to a string + if self.cmdline and self.type is None: + return str, default_is_none + # For file only settings it will default to Any + return 'Any', default_is_none + + def _guess_type(self) -> tuple[type | str | None, bool]: + if self.action == 'append': + return List[self._guess_type_internal()[0]], self.default is None # type: ignore[misc] + return self._guess_type_internal() def get_dest(self, prefix: str, names: Sequence[str], dest: str | None) -> tuple[str, str, str, bool]: setting_name = None @@ -316,6 +391,32 @@ if TYPE_CHECKING: ns = Namespace | TypedNS | Config[T] | None +def _type_to_string(t: type | str) -> tuple[str, str]: + type_name = 'Any' + import_needed = '' + # Take a string as is + if isinstance(t, str): + type_name = t + # Handle generic aliases eg dict[str, str] instead of dict + elif isinstance(t, types_GenericAlias): + if not get_args(t): + t = t.__origin__.__name__ + type_name = str(t) + # Handle standard type objects + elif isinstance(t, type): + type_name = t.__name__ + # Builtin types don't need an import + if t.__module__ != 'builtins': + import_needed = f'import {t.__module__}' + # Use the full imported name + type_name = t.__module__ + '.' + type_name + + # Expand Any to typing.Any + if type_name == 'Any': + type_name = 'typing.Any' + return type_name, import_needed + + def generate_ns(definitions: Definitions) -> tuple[str, str]: initial_imports = ['from __future__ import annotations', '', 'import settngs'] imports: Sequence[str] | set[str] @@ -328,27 +429,8 @@ def generate_ns(definitions: Definitions) -> tuple[str, str]: t, noneable = setting._guess_type() if t is None: continue - # Default to any - type_name = 'Any' - - # Take a string as is - if isinstance(t, str): - type_name = t - # Handle generic aliases eg dict[str, str] instead of dict - elif isinstance(t, types_GenericAlias): - type_name = str(t) - # Handle standard type objects - elif isinstance(t, type): - type_name = t.__name__ - # Builtin types don't need an import - if t.__module__ != 'builtins': - imports.add(f'import {t.__module__}') - # Use the full imported name - type_name = t.__module__ + '.' + type_name - - # Expand Any to typing.Any - if type_name == 'Any': - type_name = 'typing.Any' + type_name, import_needed = _type_to_string(t) + imports.add(import_needed) if noneable and type_name not in ('typing.Any', 'None'): attribute = f' {setting.internal_name}: {type_name} | None' @@ -372,7 +454,7 @@ def generate_ns(definitions: Definitions) -> tuple[str, str]: initial_imports.append('import typing') # Remove the possible duplicate typing import - imports = sorted(list(imports - {'import typing'})) + imports = sorted(imports - {'import typing', ''}) # Merge the imports the ns class definition and the attributes return '\n'.join(initial_imports + imports), ns + '\n'.join(attributes) @@ -392,27 +474,8 @@ def generate_dict(definitions: Definitions) -> tuple[str, str]: t, no_default = setting._guess_type() if t is None: continue - # Default to any - type_name = 'Any' - - # Take a string as is - if isinstance(t, str): - type_name = t - # Handle generic aliases eg dict[str, str] instead of dict - elif isinstance(t, types_GenericAlias): - type_name = str(t) - # Handle standard type objects - elif isinstance(t, type): - type_name = t.__name__ - # Builtin types don't need an import - if t.__module__ != 'builtins': - imports.add(f'import {t.__module__}') - # Use the full imported name - type_name = t.__module__ + '.' + type_name - - # Expand Any to typing.Any - if type_name == 'Any': - type_name = 'typing.Any' + type_name, import_needed = _type_to_string(t) + imports.add(import_needed) if no_default and type_name not in ('typing.Any', 'None'): attribute = f' {setting.dest}: {type_name} | None' @@ -429,7 +492,7 @@ def generate_dict(definitions: Definitions) -> tuple[str, str]: ) # Remove the possible duplicate typing import - imports = sorted(list(imports - {'import typing'})) + imports = sorted(list(imports - {'import typing', ''})) if groups_are_identifiers: ns = '\nclass SettngsDict(typing.TypedDict):\n' diff --git a/tests/settngs_test.py b/tests/settngs_test.py index db5fd38..4ae77e0 100644 --- a/tests/settngs_test.py +++ b/tests/settngs_test.py @@ -19,6 +19,7 @@ from testing.settngs import success if sys.version_info >= (3, 10): # pragma: no cover List = list + Set = set help_output = '''\ usage: __main__.py [-h] [TEST ...] @@ -30,6 +31,7 @@ options: ''' elif sys.version_info < (3, 9): # pragma: no cover from typing import List + from typing import Set help_output = '''\ usage: __main__.py [-h] [TEST [TEST ...]] @@ -42,6 +44,7 @@ optional arguments: else: # pragma: no cover List = list + Set = set help_output = '''\ usage: __main__.py [-h] [TEST ...] @@ -618,6 +621,18 @@ def _typed_function(something: str) -> test_type: # pragma: no cover return test_type() +def _typed_list_generic_function(something: test_type) -> List[test_type]: # pragma: no cover + return [test_type()] + + +def _typed_list_function() -> List: # type: ignore[type-arg] # pragma: no cover + return [] + + +def _typed_set_function() -> Set: # type: ignore[type-arg] # pragma: no cover + return set() + + def _untyped_function(something): ... @@ -652,23 +667,34 @@ types = ( (0, settngs.Setting('-t', '--test'), str, True), (1, settngs.Setting('-t', '--test', cmdline=False), 'Any', True), (2, settngs.Setting('-t', '--test', default=1, file=True, cmdline=False), int, False), - (3, settngs.Setting('-t', '--test', action='count'), int, True), - (4, settngs.Setting('-t', '--test', action='append'), List[str], True), - (5, settngs.Setting('-t', '--test', action='extend'), List[str], True), - (6, settngs.Setting('-t', '--test', nargs='+'), List[str], True), - (7, settngs.Setting('-t', '--test', action='store_const', const=1), int, True), - (8, settngs.Setting('-t', '--test', action='append_const', const=1), List[int], True), - (9, settngs.Setting('-t', '--test', action='store_true'), bool, False), - (10, settngs.Setting('-t', '--test', action='store_false'), bool, False), - (11, settngs.Setting('-t', '--test', action=settngs.BooleanOptionalAction), bool, True), - (12, settngs.Setting('-t', '--test', action=_customAction), 'Any', True), - (13, settngs.Setting('-t', '--test', action='help'), None, True), - (14, settngs.Setting('-t', '--test', action='version'), None, True), - (15, settngs.Setting('-t', '--test', type=int), int, True), - (16, settngs.Setting('-t', '--test', type=_typed_function), test_type, True), - (17, settngs.Setting('-t', '--test', type=_untyped_function, default=1), int, False), - (18, settngs.Setting('-t', '--test', type=_untyped_function, default=[1]), List[int], False), - (19, settngs.Setting('-t', '--test', type=_untyped_function), 'Any', True), + (3, settngs.Setting('-t', '--test', default='test'), str, False), + (4, settngs.Setting('-t', '--test', default='test', file=True, cmdline=False), str, False), + (5, settngs.Setting('-t', '--test', action='count'), int, True), + (6, settngs.Setting('-t', '--test', action='append'), List[str], True), + (7, settngs.Setting('-t', '--test', action='extend'), List[str], True), + (8, settngs.Setting('-t', '--test', nargs='+'), List[str], True), + (9, settngs.Setting('-t', '--test', action='store_const', const=1), int, True), + (10, settngs.Setting('-t', '--test', action='append_const', const=1), List[int], True), + (11, settngs.Setting('-t', '--test', action='store_true'), bool, False), + (12, settngs.Setting('-t', '--test', action='store_false'), bool, False), + (13, settngs.Setting('-t', '--test', action=settngs.BooleanOptionalAction), bool, True), + (14, settngs.Setting('-t', '--test', action=_customAction), 'Any', True), + (15, settngs.Setting('-t', '--test', action='help'), None, True), + (16, settngs.Setting('-t', '--test', action='version'), None, True), + (17, settngs.Setting('-t', '--test', type=int), int, True), + (18, settngs.Setting('-t', '--test', type=int, nargs='+'), List[int], True), + (19, settngs.Setting('-t', '--test', type=_typed_function), test_type, True), + (20, settngs.Setting('-t', '--test', type=_untyped_function, default=1), int, False), + (21, settngs.Setting('-t', '--test', type=_untyped_function, default=[1]), List[int], False), + (22, settngs.Setting('-t', '--test', type=_untyped_function), 'Any', True), + (23, settngs.Setting('-t', '--test', type=_untyped_function, default={1}), Set[int], False), + (24, settngs.Setting('-t', '--test', action='append', type=int), List[int], True), + (25, settngs.Setting('-t', '--test', action='extend', type=int, nargs=2), List[int], True), + (26, settngs.Setting('-t', '--test', action='append', type=int, nargs=2), List[List[int]], True), + (27, settngs.Setting('-t', '--test', action='extend', nargs='+'), List[str], True), + (28, settngs.Setting('-t', '--test', action='extend', type=_typed_list_generic_function), List[test_type], True), + (29, settngs.Setting('-t', '--test', action='extend', type=_typed_list_function), List, True), + (30, settngs.Setting('-t', '--test', action='extend', type=_typed_set_function), Set, True), ) @@ -700,23 +726,34 @@ settings = ( (0, lambda parser: parser.add_setting('-t', '--test'), expected_src.format(extra_imports='', typ='str | None')), (1, lambda parser: parser.add_setting('-t', '--test', cmdline=False), expected_src.format(extra_imports='import typing\n', typ='typing.Any')), (2, lambda parser: parser.add_setting('-t', '--test', default=1, file=True, cmdline=False), expected_src.format(extra_imports='', typ='int')), - (3, lambda parser: parser.add_setting('-t', '--test', action='count'), expected_src.format(extra_imports='', typ='int | None')), - (4, lambda parser: parser.add_setting('-t', '--test', action='append'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ='typing.List[str] | None' if sys.version_info < (3, 9) else 'list[str] | None')), - (5, lambda parser: parser.add_setting('-t', '--test', action='extend'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ='typing.List[str] | None' if sys.version_info < (3, 9) else 'list[str] | None')), - (6, lambda parser: parser.add_setting('-t', '--test', nargs='+'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ='typing.List[str] | None' if sys.version_info < (3, 9) else 'list[str] | None')), - (7, lambda parser: parser.add_setting('-t', '--test', action='store_const', const=1), expected_src.format(extra_imports='', typ='int | None')), - (8, lambda parser: parser.add_setting('-t', '--test', action='append_const', const=1), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ='typing.List[int] | None' if sys.version_info < (3, 9) else 'list[int] | None')), - (9, lambda parser: parser.add_setting('-t', '--test', action='store_true'), expected_src.format(extra_imports='', typ='bool')), - (10, lambda parser: parser.add_setting('-t', '--test', action='store_false'), expected_src.format(extra_imports='', typ='bool')), - (11, lambda parser: parser.add_setting('-t', '--test', action=settngs.BooleanOptionalAction), expected_src.format(extra_imports='', typ='bool | None')), - (12, lambda parser: parser.add_setting('-t', '--test', action=_customAction), expected_src.format(extra_imports='import typing\n', typ='typing.Any')), - (13, lambda parser: parser.add_setting('-t', '--test', action='help'), no_type_expected_src), - (14, lambda parser: parser.add_setting('-t', '--test', action='version'), no_type_expected_src), - (15, lambda parser: parser.add_setting('-t', '--test', type=int), expected_src.format(extra_imports='', typ='int | None')), - (16, lambda parser: parser.add_setting('-t', '--test', type=_typed_function), expected_src.format(extra_imports='import tests.settngs_test\n', typ='tests.settngs_test.test_type | None')), - (17, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=1), expected_src.format(extra_imports='', typ='int')), - (18, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=[1]), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ='typing.List[int]' if sys.version_info < (3, 9) else 'list[int]')), - (19, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function), expected_src.format(extra_imports='import typing\n', typ='typing.Any')), + (3, lambda parser: parser.add_setting('-t', '--test', default='test'), expected_src.format(extra_imports='', typ='str')), + (4, lambda parser: parser.add_setting('-t', '--test', default='test', file=True, cmdline=False), expected_src.format(extra_imports='', typ='str')), + (5, lambda parser: parser.add_setting('-t', '--test', action='count'), expected_src.format(extra_imports='', typ='int | None')), + (6, lambda parser: parser.add_setting('-t', '--test', action='append'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[str]} | None')), + (7, lambda parser: parser.add_setting('-t', '--test', action='extend'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[str]} | None')), + (8, lambda parser: parser.add_setting('-t', '--test', nargs='+'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[str]} | None')), + (9, lambda parser: parser.add_setting('-t', '--test', action='store_const', const=1), expected_src.format(extra_imports='', typ='int | None')), + (10, lambda parser: parser.add_setting('-t', '--test', action='append_const', const=1), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[int]} | None')), + (11, lambda parser: parser.add_setting('-t', '--test', action='store_true'), expected_src.format(extra_imports='', typ='bool')), + (12, lambda parser: parser.add_setting('-t', '--test', action='store_false'), expected_src.format(extra_imports='', typ='bool')), + (13, lambda parser: parser.add_setting('-t', '--test', action=settngs.BooleanOptionalAction), expected_src.format(extra_imports='', typ='bool | None')), + (14, lambda parser: parser.add_setting('-t', '--test', action=_customAction), expected_src.format(extra_imports='import typing\n', typ='typing.Any')), + (15, lambda parser: parser.add_setting('-t', '--test', action='help'), no_type_expected_src), + (16, lambda parser: parser.add_setting('-t', '--test', action='version'), no_type_expected_src), + (17, lambda parser: parser.add_setting('-t', '--test', type=int), expected_src.format(extra_imports='', typ='int | None')), + (18, lambda parser: parser.add_setting('-t', '--test', type=int, nargs='+'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[int]} | None')), + (19, lambda parser: parser.add_setting('-t', '--test', type=_typed_function), expected_src.format(extra_imports='import tests.settngs_test\n', typ='tests.settngs_test.test_type | None')), + (20, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=1), expected_src.format(extra_imports='', typ='int')), + (21, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=[1]), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[int]}')), + (22, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function), expected_src.format(extra_imports='import typing\n', typ='typing.Any')), + (23, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default={1}), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{Set[int]}')), + (24, lambda parser: parser.add_setting('-t', '--test', action='append', type=int), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[int]} | None')), + (25, lambda parser: parser.add_setting('-t', '--test', action='extend', type=int, nargs=2), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[int]} | None')), + (26, lambda parser: parser.add_setting('-t', '--test', action='append', type=int, nargs=2), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[List[int]]} | None')), + (27, lambda parser: parser.add_setting('-t', '--test', action='extend', nargs='+'), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[str]} | None')), + (28, lambda parser: parser.add_setting('-t', '--test', action='extend', type=_typed_list_generic_function), expected_src.format(extra_imports='import typing\n' if sys.version_info < (3, 9) else '', typ=f'{List[test_type]} | None')), + (29, lambda parser: parser.add_setting('-t', '--test', action='extend', type=_typed_list_function), expected_src.format(extra_imports='', typ=f'{settngs._type_to_string(List)[0]} | None')), + (30, lambda parser: parser.add_setting('-t', '--test', action='extend', type=_typed_set_function), expected_src.format(extra_imports='', typ=f'{settngs._type_to_string(Set)[0]} | None')), ) @@ -760,23 +797,34 @@ settings_dict = ( (0, lambda parser: parser.add_setting('-t', '--test'), expected_src_dict.format(extra_imports='', typ='str | None')), (1, lambda parser: parser.add_setting('-t', '--test', cmdline=False), expected_src_dict.format(extra_imports='', typ='typing.Any')), (2, lambda parser: parser.add_setting('-t', '--test', default=1, file=True, cmdline=False), expected_src_dict.format(extra_imports='', typ='int')), - (3, lambda parser: parser.add_setting('-t', '--test', action='count'), expected_src_dict.format(extra_imports='', typ='int | None')), - (4, lambda parser: parser.add_setting('-t', '--test', action='append'), expected_src_dict.format(extra_imports='', typ='typing.List[str] | None' if sys.version_info < (3, 9) else 'list[str] | None')), - (5, lambda parser: parser.add_setting('-t', '--test', action='extend'), expected_src_dict.format(extra_imports='', typ='typing.List[str] | None' if sys.version_info < (3, 9) else 'list[str] | None')), - (6, lambda parser: parser.add_setting('-t', '--test', nargs='+'), expected_src_dict.format(extra_imports='', typ='typing.List[str] | None' if sys.version_info < (3, 9) else 'list[str] | None')), - (7, lambda parser: parser.add_setting('-t', '--test', action='store_const', const=1), expected_src_dict.format(extra_imports='', typ='int | None')), - (8, lambda parser: parser.add_setting('-t', '--test', action='append_const', const=1), expected_src_dict.format(extra_imports='', typ='typing.List[int] | None' if sys.version_info < (3, 9) else 'list[int] | None')), - (9, lambda parser: parser.add_setting('-t', '--test', action='store_true'), expected_src_dict.format(extra_imports='', typ='bool')), - (10, lambda parser: parser.add_setting('-t', '--test', action='store_false'), expected_src_dict.format(extra_imports='', typ='bool')), - (11, lambda parser: parser.add_setting('-t', '--test', action=settngs.BooleanOptionalAction), expected_src_dict.format(extra_imports='', typ='bool | None')), - (12, lambda parser: parser.add_setting('-t', '--test', action=_customAction), expected_src_dict.format(extra_imports='', typ='typing.Any')), - (13, lambda parser: parser.add_setting('-t', '--test', action='help'), no_type_expected_src_dict), - (14, lambda parser: parser.add_setting('-t', '--test', action='version'), no_type_expected_src_dict), - (15, lambda parser: parser.add_setting('-t', '--test', type=int), expected_src_dict.format(extra_imports='', typ='int | None')), - (16, lambda parser: parser.add_setting('-t', '--test', type=_typed_function), expected_src_dict.format(extra_imports='import tests.settngs_test\n', typ='tests.settngs_test.test_type | None')), - (17, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=1), expected_src_dict.format(extra_imports='', typ='int')), - (18, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=[1]), expected_src_dict.format(extra_imports='', typ='typing.List[int]' if sys.version_info < (3, 9) else 'list[int]')), - (19, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function), expected_src_dict.format(extra_imports='', typ='typing.Any')), + (3, lambda parser: parser.add_setting('-t', '--test', default='test'), expected_src_dict.format(extra_imports='', typ='str')), + (4, lambda parser: parser.add_setting('-t', '--test', default='test', file=True, cmdline=False), expected_src_dict.format(extra_imports='', typ='str')), + (5, lambda parser: parser.add_setting('-t', '--test', action='count'), expected_src_dict.format(extra_imports='', typ='int | None')), + (6, lambda parser: parser.add_setting('-t', '--test', action='append'), expected_src_dict.format(extra_imports='', typ=f'{List[str]} | None')), + (7, lambda parser: parser.add_setting('-t', '--test', action='extend'), expected_src_dict.format(extra_imports='', typ=f'{List[str]} | None')), + (8, lambda parser: parser.add_setting('-t', '--test', nargs='+'), expected_src_dict.format(extra_imports='', typ=f'{List[str]} | None')), + (9, lambda parser: parser.add_setting('-t', '--test', action='store_const', const=1), expected_src_dict.format(extra_imports='', typ='int | None')), + (10, lambda parser: parser.add_setting('-t', '--test', action='append_const', const=1), expected_src_dict.format(extra_imports='', typ=f'{List[int]} | None')), + (11, lambda parser: parser.add_setting('-t', '--test', action='store_true'), expected_src_dict.format(extra_imports='', typ='bool')), + (12, lambda parser: parser.add_setting('-t', '--test', action='store_false'), expected_src_dict.format(extra_imports='', typ='bool')), + (13, lambda parser: parser.add_setting('-t', '--test', action=settngs.BooleanOptionalAction), expected_src_dict.format(extra_imports='', typ='bool | None')), + (14, lambda parser: parser.add_setting('-t', '--test', action=_customAction), expected_src_dict.format(extra_imports='', typ='typing.Any')), + (15, lambda parser: parser.add_setting('-t', '--test', action='help'), no_type_expected_src_dict), + (16, lambda parser: parser.add_setting('-t', '--test', action='version'), no_type_expected_src_dict), + (17, lambda parser: parser.add_setting('-t', '--test', type=int), expected_src_dict.format(extra_imports='', typ='int | None')), + (18, lambda parser: parser.add_setting('-t', '--test', type=int, nargs='+'), expected_src_dict.format(extra_imports='', typ=f'{List[int]} | None')), + (19, lambda parser: parser.add_setting('-t', '--test', type=_typed_function), expected_src_dict.format(extra_imports='import tests.settngs_test\n', typ=f'{test_type.__module__}.{test_type.__name__} | None')), + (20, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=1), expected_src_dict.format(extra_imports='', typ='int')), + (21, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default=[1]), expected_src_dict.format(extra_imports='', typ=f'{List[int]}')), + (22, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function), expected_src_dict.format(extra_imports='', typ='typing.Any')), + (23, lambda parser: parser.add_setting('-t', '--test', type=_untyped_function, default={1}), expected_src_dict.format(extra_imports='', typ=f'{Set[int]}')), + (24, lambda parser: parser.add_setting('-t', '--test', action='append', type=int), expected_src_dict.format(extra_imports='', typ=f'{List[int]} | None')), + (25, lambda parser: parser.add_setting('-t', '--test', action='extend', type=int, nargs=2), expected_src_dict.format(extra_imports='', typ=f'{List[int]} | None')), + (26, lambda parser: parser.add_setting('-t', '--test', action='append', type=int, nargs=2), expected_src_dict.format(extra_imports='', typ=f'{List[List[int]]} | None')), + (27, lambda parser: parser.add_setting('-t', '--test', action='extend', nargs='+'), expected_src_dict.format(extra_imports='', typ=f'{List[str]} | None')), + (28, lambda parser: parser.add_setting('-t', '--test', action='extend', type=_typed_list_generic_function), expected_src_dict.format(extra_imports='', typ=f'{List[test_type]} | None')), + (29, lambda parser: parser.add_setting('-t', '--test', action='extend', type=_typed_list_function), expected_src_dict.format(extra_imports='', typ=f'{settngs._type_to_string(List)[0]} | None')), + (30, lambda parser: parser.add_setting('-t', '--test', action='extend', type=_typed_set_function), expected_src_dict.format(extra_imports='', typ=f'{settngs._type_to_string(Set)[0]} | None')), )