From 26370e2ca1ab2b3fc095152d35742009e96e25f0 Mon Sep 17 00:00:00 2001 From: Kamil Cukrowski Date: Wed, 9 Oct 2024 21:13:20 +0200 Subject: [PATCH] properly handle deserializing Tuple[str, ...] and str types --- README.md | 5 ++++- src/clickdc.py | 21 ++++++++++----------- tests/test.py | 11 ++++++++++- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 84c13fd..6a81985 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,10 @@ the `dataclass`, removing the arguments in the process. ```python @click.command(help="This is a command") -@clickdc("args", Args) +@clickdc.adddc("args", Args) def cli(args: Args): print(args) + print(clickdc.to_args(args)) # converts dataclass back to string '--option command' ``` If a keyword argument `clickdc` is missing, the field name is added with @@ -106,6 +107,8 @@ You can inherit `dataclasses` and decorate using multiple. It works just by decorating the function with the proper `click.` function inferred from the field type. + + # TODO `dataclasses(default, default_factory)` require some questionable polishing. diff --git a/src/clickdc.py b/src/clickdc.py index 2749ad8..34f2087 100644 --- a/src/clickdc.py +++ b/src/clickdc.py @@ -3,6 +3,7 @@ and get click arguments to parse. """ +import abc import dataclasses import functools import logging @@ -250,20 +251,18 @@ def to_args(self, obj: DataclassInstance) -> List[str]: ret: List[str] = [] if self.is_option() or self.is_argument(): value = getattr(obj, self.name) - name = self.dashdashoption() - if self.kwargs.get("is_flag"): + name = self.dashdashoption() if self.is_option() else "" + nameeq = (name + "=") if name else "" + if value is None: + pass + elif self.is_option() and self.kwargs.get("is_flag"): if value: ret.append(name) - elif is_tuple_arr(type(value)) or isinstance(value, Iterable): - if value: - for i in value: - if self.is_option(): - ret.append(name) - ret.append(str(i)) + elif isinstance(value, (list, tuple)): + for i in value: + ret.append(nameeq + str(i)) else: - if self.is_option(): - ret.append(name) - ret.append(str(value)) + ret.append(nameeq + str(value)) return ret diff --git a/tests/test.py b/tests/test.py index 1ba9d6b..fc008ed 100644 --- a/tests/test.py +++ b/tests/test.py @@ -243,6 +243,8 @@ def test_to_args(): class Args: opta: bool = clickdc.option("-a") optb: Tuple[int, ...] = clickdc.option("-b") + optc: Tuple[str, ...] = clickdc.option("-c") + optd: Optional[str] = clickdc.option("-d") cmda: int = clickdc.argument() cmdb: int = clickdc.argument() cmdc: Tuple[int, ...] = clickdc.argument() @@ -250,7 +252,14 @@ class Args: run(Args, "1 2 3 4 5 6", "1 2 3 4 5 6", toargs=True) run(Args, "--opta 1 2 3 4", "--opta 1 2 3 4", toargs=True) run(Args, "-a 1 2 3 4", "--opta 1 2 3 4", toargs=True) - run(Args, "-a -b 1 -b 2 1 2 3", "--opta --optb 1 --optb 2 1 2 3", toargs=True) + run(Args, "-a -b 1 -b 2 1 2 3", "--opta --optb=1 --optb=2 1 2 3", toargs=True) + run( + Args, + "-a -b 1 -b 2 -c aaa -c bbb -c ddd 1 2 3", + "--opta --optb=1 --optb=2 --optc=aaa --optc=bbb --optc=ddd 1 2 3", + toargs=True, + ) + run(Args, "-d aaa -d bbb -d ccc 1 2 3", "--optd=ccc 1 2 3", toargs=True) def test_to_list_option():