diff --git a/TypeSaveArgParse/autoargs.py b/TypeSaveArgParse/autoargs.py index e79fa3c..a424854 100644 --- a/TypeSaveArgParse/autoargs.py +++ b/TypeSaveArgParse/autoargs.py @@ -16,7 +16,15 @@ except Exception: doc_parse = None -from TypeSaveArgParse.utils import cast_all, class_to_str, enum_to_str, extract_sub_annotation, len_checker, translation_enum_to_str +from TypeSaveArgParse.utils import ( + cast_all, + class_to_str, + enum_to_str, + extract_sub_annotation, + is_union, + len_checker, + translation_enum_to_str, +) config_help = "config file path" @@ -93,7 +101,8 @@ def data_class_to_arg_parse( annotation = parameters[name].annotation # Handling :A |B |...| None (None means Optional argument) annotations = [] - if get_origin(annotation) == Union: + + if is_union(annotation): # : for i in get_args(annotation): if i == type(None): can_be_none = True @@ -231,7 +240,7 @@ def add_comments_to_yaml(cls, data: ruamel.yaml.CommentedMap, _addendum: str = " # Handling :A |B |...| None (None means Optional argument) annotations = [] - if get_origin(annotation) == Union: + if is_union(annotation): for i in get_args(annotation): if i != type(None): annotations.append(i) diff --git a/TypeSaveArgParse/utils.py b/TypeSaveArgParse/utils.py index 607a741..ef9c8d4 100644 --- a/TypeSaveArgParse/utils.py +++ b/TypeSaveArgParse/utils.py @@ -70,7 +70,7 @@ def extract_sub_annotation(annotation): def _cast_all(val, annotation: types.GenericAlias, enum): # -> tuple[Any, ...] | set[Any] | Any | list[Any]: - if get_origin(annotation) == Union: + if is_union(annotation): annotation = extract_sub_annotation(annotation)[0] if isinstance(val, list): @@ -87,3 +87,7 @@ def cast_all(val, parameter: Parameter, enum): return val val_out = _cast_all(val, parameter.annotation, enum) return val_out + + +def is_union(annotation): + return (hasattr(types, "UnionType") and get_origin(annotation) == types.UnionType) or get_origin(annotation) == Union diff --git a/test/test_autoargs.py b/test/test_autoargs.py index d0018c7..f5fbf41 100644 --- a/test/test_autoargs.py +++ b/test/test_autoargs.py @@ -2,6 +2,7 @@ # coverage run -m unittest # coverage report # coverage html +import platform import random import sys import unittest @@ -15,6 +16,7 @@ sys.path.append(str(Path(__file__).parent.parent.parent / "TypeSaveArgParse")) + from TypeSaveArgParse import Class_to_ArgParse DEFAULT_STR = str(random.randint(0, 1000)) @@ -22,19 +24,6 @@ DEFAULT_FLOAT = random.random() -@dataclass -class BASE_CASES(Class_to_ArgParse): - x: str = DEFAULT_STR - y: int = DEFAULT_INT - f: float = DEFAULT_FLOAT - z: Optional[int] = None - p: Optional[Path] = None - l_s: list[str] = field(default_factory=list) - l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) - tup: tuple[str, ...] = field(default_factory=tuple) - set_: set[str] = field(default_factory=set) - - @dataclass class TUP_CASES(Class_to_ArgParse): tup: tuple[int, ...] = field(default_factory=tuple) @@ -50,11 +39,45 @@ class Dummy_Enum(Enum): THIRD = auto() -@dataclass -class ENUM_CASES(Class_to_ArgParse): - enu: Dummy_Enum = Dummy_Enum.ONE - enu_list: Optional[list[Dummy_Enum]] = None - enu_list2: list[Dummy_Enum] = field(default_factory=list) +py_version = int(platform.python_version().split(".")[1]) +if py_version <= 9: + + @dataclass + class BASE_CASES(Class_to_ArgParse): # type: ignore + x: str = DEFAULT_STR + y: int = DEFAULT_INT + f: float = DEFAULT_FLOAT + z: Optional[int] = None + p: Optional[Path] = None + l_s: list[str] = field(default_factory=list) + l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) + tup: tuple[str, ...] = field(default_factory=tuple) + set_: set[str] = field(default_factory=set) + + @dataclass + class ENUM_CASES(Class_to_ArgParse): # type: ignore + enu: Dummy_Enum = Dummy_Enum.ONE + enu_list: Optional[list[Dummy_Enum]] = None + enu_list2: list[Dummy_Enum] = field(default_factory=list) +else: + + @dataclass + class BASE_CASES(Class_to_ArgParse): + x: str = DEFAULT_STR + y: int = DEFAULT_INT + f: float = DEFAULT_FLOAT + z: int | None = None + p: Path | None = None + l_s: list[str] = field(default_factory=list) + l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) + tup: tuple[str, ...] = field(default_factory=tuple) + set_: set[str] = field(default_factory=set) + + @dataclass + class ENUM_CASES(Class_to_ArgParse): + enu: Dummy_Enum = Dummy_Enum.ONE + enu_list: list[Dummy_Enum] | None = None + enu_list2: list[Dummy_Enum] = field(default_factory=list) def assert_(value, x, type_): diff --git a/test/test_recursive.py b/test/test_recursive.py index bf0ea06..ce01eb8 100644 --- a/test/test_recursive.py +++ b/test/test_recursive.py @@ -2,6 +2,7 @@ # coverage run -m unittest # coverage report # coverage html +import platform import random import sys import unittest @@ -21,34 +22,103 @@ DEFAULT_STR = str(random.randint(0, 1000)) DEFAULT_INT = random.randint(-1000, 1000) DEFAULT_FLOAT = random.random() +py_version = int(platform.python_version().split(".")[1]) -@dataclass -class BASE_CASES(Class_to_ArgParse): - """ - Class representing base cases for argument parsing. +class Dummy_Enum(Enum): + ONE = auto() + SECOND = auto() + THIRD = auto() - Attributes: - x (str): String attribute with default value DEFAULT_STR. - y (int): Integer attribute with default value DEFAULT_INT. - f (float): Float attribute with default value DEFAULT_FLOAT. - z (Optional[int]): Optional integer attribute. - p (Optional[Path]): Optional Path attribute. - l_s (List[str]): List of strings. - l_i (List[int]): List of integers with default value [1, 2, 3]. - tup (Tuple[str, ...]): Tuple of strings. - set_ (Set[str]): Set of strings. - """ - x: str = DEFAULT_STR - y: int = DEFAULT_INT - f: float = DEFAULT_FLOAT - z: Optional[int] = None - p: Optional[Path] = None - l_s: list[str] = field(default_factory=list) - l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) - tup: tuple[str, ...] = field(default_factory=tuple) - set_: set[str] = field(default_factory=set) +if py_version <= 9: + + @dataclass + class BASE_CASES(Class_to_ArgParse): # type: ignore + """ + Class representing base cases for argument parsing. + + Attributes: + x (str): String attribute with default value DEFAULT_STR. + y (int): Integer attribute with default value DEFAULT_INT. + f (float): Float attribute with default value DEFAULT_FLOAT. + z (Optional[int]): Optional integer attribute. + p (Optional[Path]): Optional Path attribute. + l_s (List[str]): List of strings. + l_i (List[int]): List of integers with default value [1, 2, 3]. + tup (Tuple[str, ...]): Tuple of strings. + set_ (Set[str]): Set of strings. + """ + + x: str = DEFAULT_STR + y: int = DEFAULT_INT + f: float = DEFAULT_FLOAT + z: Optional[int] = None + p: Optional[Path] = None + l_s: list[str] = field(default_factory=list) + l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) + tup: tuple[str, ...] = field(default_factory=tuple) + set_: set[str] = field(default_factory=set) + + @dataclass + class ENUM_CASES(Class_to_ArgParse): # type: ignore + """ + Class representing enum cases for argument parsing. + + Attributes: + enu (Dummy_Enum): Enum attribute with default value Dummy_Enum.ONE. + enu_list (Optional[List[Dummy_Enum]]): Optional list of enum instances. + enu_list2 (List[Dummy_Enum]): List of enum instances. + """ + + enu: Dummy_Enum = Dummy_Enum.ONE + enu_list: Optional[list[Dummy_Enum]] = None + enu_list2: list[Dummy_Enum] = field(default_factory=list) + + +else: + + @dataclass + class BASE_CASES(Class_to_ArgParse): + """ + Class representing base cases for argument parsing. + + Attributes: + x (str): String attribute with default value DEFAULT_STR. + y (int): Integer attribute with default value DEFAULT_INT. + f (float): Float attribute with default value DEFAULT_FLOAT. + z (Optional[int]): Optional integer attribute. + p (Optional[Path]): Optional Path attribute. + l_s (List[str]): List of strings. + l_i (List[int]): List of integers with default value [1, 2, 3]. + tup (Tuple[str, ...]): Tuple of strings. + set_ (Set[str]): Set of strings. + """ + + x: str = DEFAULT_STR + y: int = DEFAULT_INT + f: float = DEFAULT_FLOAT + z: int | None = None + p: Path | None = None + l_s: list[str] = field(default_factory=list) + l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) + tup: tuple[str, ...] = field(default_factory=tuple) + set_: set[str] = field(default_factory=set) + + @dataclass + class ENUM_CASES(Class_to_ArgParse): + """ + Class representing enum cases for argument parsing. + + Attributes: + enu (Dummy_Enum): Enum attribute with default value Dummy_Enum.ONE. + enu_list (Optional[List[Dummy_Enum]]): Optional list of enum instances. + enu_list2 (List[Dummy_Enum]): List of enum instances. + """ + + enu: Dummy_Enum = Dummy_Enum.ONE + enu_list: list[Dummy_Enum] | None = None + enu_list2: list[Dummy_Enum] = field(default_factory=list) @dataclass @@ -85,37 +155,6 @@ class TUP_CASES(Class_to_ArgParse): tup4: tuple[int, int, int, int] = field(default_factory=tuple) -class Dummy_Enum(Enum): - """ - Class representing enum cases for argument parsing. - - Attributes: - enu (Dummy_Enum): Enum attribute with default value Dummy_Enum.ONE. - enu_list (Optional[List[Dummy_Enum]]): Optional list of enum instances. - enu_list2 (List[Dummy_Enum]): List of enum instances. - """ - - ONE = auto() - SECOND = auto() - THIRD = auto() - - -@dataclass -class ENUM_CASES(Class_to_ArgParse): - """ - Class representing enum cases for argument parsing. - - Attributes: - enu (Dummy_Enum): Enum attribute with default value Dummy_Enum.ONE. - enu_list (Optional[List[Dummy_Enum]]): Optional list of enum instances. - enu_list2 (List[Dummy_Enum]): List of enum instances. - """ - - enu: Dummy_Enum = Dummy_Enum.ONE - enu_list: Optional[list[Dummy_Enum]] = None - enu_list2: list[Dummy_Enum] = field(default_factory=list) - - @dataclass() class REC(Class_to_ArgParse): """ diff --git a/test/test_save_load.py b/test/test_save_load.py index 1830f81..edad0ad 100644 --- a/test/test_save_load.py +++ b/test/test_save_load.py @@ -2,6 +2,7 @@ # coverage run -m unittest # coverage report # coverage html +import platform import random import sys import unittest @@ -22,6 +23,8 @@ DEFAULT_INT = random.randint(-1000, 1000) DEFAULT_FLOAT = random.random() +py_version = int(platform.python_version().split(".")[1]) + class Dummy_Enum(Enum): ONE = auto() @@ -29,21 +32,40 @@ class Dummy_Enum(Enum): THIRD = auto() -@dataclass -class BASE_CASES(Class_to_ArgParse): - x: str = "" - y: int = -1000000 - f: float = -0.3 - enum: Dummy_Enum = Dummy_Enum.ONE - enum_tuple: tuple[Dummy_Enum, Dummy_Enum] = field(default_factory=lambda: (Dummy_Enum.ONE, Dummy_Enum.ONE)) - z: Optional[int] = None - p: Optional[Path] = None - l_s: list[str] = field(default_factory=lambda: ["Wam", "Bam"]) - l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) - tup: tuple[str, ...] = field(default_factory=tuple) - set_s: set[str] = field(default_factory=set) - set_i: set[int] = field(default_factory=set) - b: bool = False +if py_version <= 9: + + @dataclass + class BASE_CASES(Class_to_ArgParse): # type: ignore + x: str = "" + y: int = -1000000 + f: float = -0.3 + enum: Dummy_Enum = Dummy_Enum.ONE + enum_tuple: tuple[Dummy_Enum, Dummy_Enum] = field(default_factory=lambda: (Dummy_Enum.ONE, Dummy_Enum.ONE)) + z: Optional[int] = None + p: Optional[Path] = None + l_s: list[str] = field(default_factory=lambda: ["Wam", "Bam"]) + l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) + tup: tuple[str, ...] = field(default_factory=tuple) + set_s: set[str] = field(default_factory=set) + set_i: set[int] = field(default_factory=set) + b: bool = False +else: + + @dataclass + class BASE_CASES(Class_to_ArgParse): + x: str = "" + y: int = -1000000 + f: float = -0.3 + enum: Dummy_Enum = Dummy_Enum.ONE + enum_tuple: tuple[Dummy_Enum, Dummy_Enum] = field(default_factory=lambda: (Dummy_Enum.ONE, Dummy_Enum.ONE)) + z: int | None = None + p: Path | None = None + l_s: list[str] = field(default_factory=lambda: ["Wam", "Bam"]) + l_i: list[int] = field(default_factory=lambda: [1, 2, 3]) + tup: tuple[str, ...] = field(default_factory=tuple) + set_s: set[str] = field(default_factory=set) + set_i: set[int] = field(default_factory=set) + b: bool = False class Test_save_load(unittest.TestCase):