Do a lot of changes

- Add ty to dev deps;
- Add some tests covering previously uncovered cases;
- Fix some bugs;
- Introduce argfield for nicer argparse interface for things that can't
  be expressed via the type system;
- Fix line length.
This commit is contained in:
2026-04-01 20:56:44 +02:00
parent 96af0718ee
commit 02ee0dab3d
4 changed files with 164 additions and 80 deletions

113
test.py
View File

@@ -1,7 +1,9 @@
# type: ignore[ty:unresolved-attribute]
# type: ignore[ty:unknown-argument]
import unittest
from typing import List
from enum import Enum
from argclass import argclass
from argclass import argclass, argfield
class TestArgClass(unittest.TestCase):
@@ -11,19 +13,7 @@ class TestArgClass(unittest.TestCase):
arg1: str
assert A.parse_args(["--arg1", "hello"]) == A(arg1="hello")
def test__required_argument_missing(self):
@argclass
class A:
arg1: str
self.assertRaises(SystemExit, A.parse_args, [])
def test__required_argument_wrong_given(self):
@argclass
class A:
arg1: str
self.assertRaises(SystemExit, A.parse_args, ["--arg2", "hello"])
def test__optional_argument_missing(self):
@@ -32,33 +22,50 @@ class TestArgClass(unittest.TestCase):
arg2: str = "world"
assert A.parse_args([]) == A(arg2="world")
def test__optional_argument_given(self):
@argclass
class A:
arg2: str = "world"
assert A.parse_args(["--arg2", "welt"]) == A(arg2="welt")
def test__optional_argument_wrong_given(self):
@argclass
class A:
arg2: str = "world"
self.assertRaises(SystemExit, A.parse_args, ["--arg3", "welt"])
def test__boolean_true(self):
def test__str_enum_choices(self):
class MyEnum(str, Enum):
hello = "hello"
world = "world"
@argclass
class A:
arg3: MyEnum
assert A.parse_args(["--arg3", "hello"]) == A(arg3=MyEnum.hello)
self.assertRaises(SystemExit, A.parse_args, ["--arg3", "foo"])
def test__str_enum_default(self):
class MyEnum(str, Enum):
hello = "hello"
world = "world"
@argclass
class A:
arg3: MyEnum = MyEnum.hello
assert A.parse_args([]) == A(arg3=MyEnum.hello)
assert A.parse_args(["--arg3", "world"]) == A(arg3=MyEnum.world)
def test__boolean(self):
@argclass
class A:
arg3: bool
assert A.parse_args(["--arg3"]) == A(arg3=True)
assert A.parse_args(["--no-arg3"]) == A(arg3=False)
def test__boolean_false(self):
def test__boolean_default_true(self):
@argclass
class A:
arg3: bool
arg3: bool = True
assert A.parse_args([]) == A(arg3=True)
assert A.parse_args(["--arg3"]) == A(arg3=True)
assert A.parse_args(["--no-arg3"]) == A(arg3=False)
def test__int(self):
@@ -67,27 +74,12 @@ class TestArgClass(unittest.TestCase):
arg4: int
assert A.parse_args(["--arg4", "42"]) == A(arg4=42)
def test__int_malformed(self):
@argclass
class A:
arg4: int
self.assertRaises(SystemExit, A.parse_args, ["--arg4", "4e2"])
def test__list(self):
@argclass
class A:
arg5: List
assert A.parse_args(["--arg5", "hello", "world"]) == A(
arg5=["hello", "world"]
)
def test__list_str(self):
@argclass
class A:
arg5: List[str]
arg5: list[str]
assert A.parse_args(["--arg5", "hello", "world"]) == A(
arg5=["hello", "world"]
@@ -96,10 +88,39 @@ class TestArgClass(unittest.TestCase):
def test__list_int(self):
@argclass
class A:
arg5: List[int]
arg5: list[int]
assert A.parse_args(["--arg5", "23", "42"]) == A(arg5=[23, 42])
def test__list_empty(self):
@argclass
class A:
arg5: list[str] = argfield(allow_empty=True)
assert A.parse_args(["--arg5"]) == A(arg5=[])
def test__shortoptions(self):
@argclass
class A:
world: str = argfield(shortopt="w")
assert A.parse_args(["-w", "hello"]) == A(world="hello")
def test__choices_str_valid(self):
@argclass
class A:
world: str = argfield(choices=["hello", "goodbye"])
assert A.parse_args(["--world", "hello"]) == A(world="hello")
self.assertRaises(SystemExit, A.parse_args, ["--world", "foo"])
def test__choices_int(self):
@argclass
class A:
number: int = argfield(choices=[4, 5, 6])
assert A.parse_args(["--number", "5"]) == A(number=5)
if __name__ == "__main__":
unittest.main()