From 898eb9f40f083a12acde720ee5f6281d1ea29836 Mon Sep 17 00:00:00 2001 From: HUANG SIZHE Date: Wed, 19 Jun 2024 13:40:02 +0800 Subject: [PATCH] update --- Changelog.md | 10 +++++++ build.sh | 1 + schema_entry/entrypoint.py | 18 ++++++++----- schema_entry/entrypoint_base.py | 9 +++++-- schema_entry/version.py | 2 +- test.sh | 2 ++ tests/test_entrypoint.py | 47 ++++++++++++++++++++++++++++----- typecheck.sh | 2 ++ 8 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 build.sh create mode 100644 test.sh create mode 100644 typecheck.sh diff --git a/Changelog.md b/Changelog.md index 9f802c1..b3c5c7e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,13 @@ +# 0.2.1 + +## bug修复 + ++ 修复多层节点情况下无法返回返回值 + +## 改进 + ++ 在有返回值时由__call__中返回的值会包含节点信息 + # 0.2.0 ## 新增特性 diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..792ce66 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +python -m build --wheel \ No newline at end of file diff --git a/schema_entry/entrypoint.py b/schema_entry/entrypoint.py index 345e532..218e014 100644 --- a/schema_entry/entrypoint.py +++ b/schema_entry/entrypoint.py @@ -24,7 +24,7 @@ from .protocol import SUPPORT_SCHEMA from .utils import get_parent_tree, parse_value_string_by_schema, parse_schema_as_cmd, pydantic_schema_to_protocol -from .entrypoint_base import SchemaType, PropertyType, EntryPointABC, PydanticModelLike +from .entrypoint_base import SchemaType, PropertyType, EntryPointABC, PydanticModelLike, CallerReturnType class EntryPoint(EntryPointABC): @@ -185,7 +185,7 @@ def with_schema(self, schemaObj: Union[str, dict, PydanticModelLike]) -> Union[s self.__doc__ = schemaObj.__doc__ return schemaObj - def __call__(self, argv: Sequence[str]) -> Optional[Any]: + def __call__(self, argv: Sequence[str]) -> Optional[CallerReturnType]: if not self.usage: if len(self._subcmds) == 0: self.usage = f"{self.prog} [options]" @@ -215,23 +215,27 @@ def __call__(self, argv: Sequence[str]) -> Optional[Any]: description=self.__doc__, usage=self.usage, formatter_class=argparse.RawDescriptionHelpFormatter) - self.pass_args_to_sub(parser, argv) - return None + return self.pass_args_to_sub(parser, argv) + else: parser = argparse.ArgumentParser( prog=self.prog, epilog=self.epilog, description=self.__doc__, usage=self.usage) - return self.parse_args(parser, argv) + result = self.parse_args(parser, argv) + if result is None: + return result + else: + return {"caller": self.name, "result": result} - def pass_args_to_sub(self, parser: argparse.ArgumentParser, argv: Sequence[str]) -> None: + def pass_args_to_sub(self, parser: argparse.ArgumentParser, argv: Sequence[str]) -> Optional[CallerReturnType]: scmds = list(self._subcmds.keys()) scmdss = ",".join(scmds) parser.add_argument('subcmd', help=f'执行子命令,可选的子命有{scmdss}') args = parser.parse_args(argv[0:1]) if self._subcmds.get(args.subcmd): - self._subcmds[args.subcmd](argv[1:]) + return self._subcmds[args.subcmd](argv[1:]) else: print(f'未知的子命令 `{argv[0]}`') parser.print_help() diff --git a/schema_entry/entrypoint_base.py b/schema_entry/entrypoint_base.py index 4240bdb..31c884b 100644 --- a/schema_entry/entrypoint_base.py +++ b/schema_entry/entrypoint_base.py @@ -16,6 +16,11 @@ def model_json_schema(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: ... +class CallerReturnType(TypedDict): + caller: str + result: Any + + class ItemType(TypedDict): type: str enum: List[Union[int, float, str]] @@ -148,7 +153,7 @@ def with_schema(self, schemaObj: Union[str, dict, PydanticModelLike]) -> Union[s """ @abc.abstractmethod - def __call__(self, argv: Sequence[str]) -> Optional[Any]: + def __call__(self, argv: Sequence[str]) -> Optional[CallerReturnType]: """执行命令. 如果当前的命令节点不是终点(也就是下面还有子命令)则传递参数到下一级; @@ -160,7 +165,7 @@ def __call__(self, argv: Sequence[str]) -> Optional[Any]: """ @abc.abstractmethod - def pass_args_to_sub(self, parser: argparse.ArgumentParser, argv: Sequence[str]) -> None: + def pass_args_to_sub(self, parser: argparse.ArgumentParser, argv: Sequence[str]) -> Optional[CallerReturnType]: """解析复杂命令行参数并将参数传递至下一级.""" @abc.abstractmethod diff --git a/schema_entry/version.py b/schema_entry/version.py index d3ec452..3ced358 100644 --- a/schema_entry/version.py +++ b/schema_entry/version.py @@ -1 +1 @@ -__version__ = "0.2.0" +__version__ = "0.2.1" diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..f2b1eb4 --- /dev/null +++ b/test.sh @@ -0,0 +1,2 @@ +python -m coverage run --source=schema_entry -m unittest discover -v -s . +python -m coverage report \ No newline at end of file diff --git a/tests/test_entrypoint.py b/tests/test_entrypoint.py index 6e98042..3198dd1 100644 --- a/tests/test_entrypoint.py +++ b/tests/test_entrypoint.py @@ -38,7 +38,6 @@ class Test_A(EntryPoint): root = Test_A() assert root.name == "test_b" - def test_default_entry_usage(self) -> None: class Test_A(EntryPoint): schema = { @@ -78,10 +77,13 @@ class Test_A(EntryPoint): root = Test_A() config = root(["--a-a=4.2"]) target = { - "a_a": 4.2 + "caller": "test_a", + "result": { + "a_a": 4.2 + } } - self.assertDictEqual(config,target) - + self.assertDictEqual(config, target) + def test_main_return(self) -> None: class Test_A(EntryPoint): schema = { @@ -95,13 +97,14 @@ class Test_A(EntryPoint): }, "required": ["a_a"] } + def do_main(self) -> str: return "a test" root = Test_A() get_value = root(["--a-a=4.2"]) - target = "a test" + target = {"caller": "test_a", "result": "a test"} assert get_value == target - + def test_override_do_main(self) -> None: class Test_A(EntryPoint): schema = { @@ -177,6 +180,38 @@ def _(a: int) -> None: "a": 2 }) + def test_subcmd_return(self) -> None: + class A(EntryPoint): + pass + + class B(EntryPoint): + pass + + class C(EntryPoint): + schema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "a": { + "type": "integer" + } + }, + "required": ["a"] + } + root = A() + a_b_c = root.regist_sub(B).regist_sub(C) + + @a_b_c.as_main + def _(a: int) -> int: + return a + os.environ['A_B_C_A'] = "2" + call_result = root(["b", "c"]) + + self.assertDictEqual(call_result, { + "caller": "c", + "result": 2 + }) + class LoadConfigTest(unittest.TestCase): @classmethod diff --git a/typecheck.sh b/typecheck.sh new file mode 100644 index 0000000..5d65c63 --- /dev/null +++ b/typecheck.sh @@ -0,0 +1,2 @@ +python -m pycodestyle --max-line-length=140 --ignore=E501 --first --statistics schema_entry +python -m mypy --ignore-missing-imports --show-column-numbers --follow-imports=silent --check-untyped-defs --disallow-untyped-defs --no-implicit-optional --warn-unused-ignores schema_entry \ No newline at end of file