From 80a662bfbae30f6295a3beb3a0970b77d2bd8910 Mon Sep 17 00:00:00 2001 From: Igor Davydenko Date: Mon, 11 Mar 2024 13:50:38 +0100 Subject: [PATCH] feat: Allow to pass entry point to clipstick parse function This is helpful, when list of CLI args comes not from `sys.argv` and, as result, entry point cannot be parsed from `sys.argv[0]`. This is also might be helpful for cases, when some CLI called via `python3 -m ...` and `sys.argv[0]` as result contain meaningless value of `something/__main__.py` (however, looks like, the proper fix for that case is out of scope of current change). --- src/clipstick/_clipstick.py | 11 +++++++++-- tests/conftest.py | 6 ++++-- .../test_command_name_from_args.png | Bin 0 -> 21282 bytes .../test_command_name_from_args.txt | 7 +++++++ tests/test_help_command_name.py | 8 ++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 tests/help_output/test_help_command_name/test_command_name_from_args.png create mode 100644 tests/help_output/test_help_command_name/test_command_name_from_args.txt diff --git a/src/clipstick/_clipstick.py b/src/clipstick/_clipstick.py index e4005b1..1705b91 100644 --- a/src/clipstick/_clipstick.py +++ b/src/clipstick/_clipstick.py @@ -9,7 +9,11 @@ DUMMY_ENTRY_POINT: Final[str] = "my-cli-app" -def parse(model: type[TPydanticModel], args: list[str] | None = None) -> TPydanticModel: +def parse( + model: type[TPydanticModel], + args: list[str] | None = None, + entry_point: str | None = None, +) -> TPydanticModel: """Create an instance of the provided model. Leave `args` to None in production. Only use it for testing. @@ -19,6 +23,9 @@ def parse(model: type[TPydanticModel], args: list[str] | None = None) -> TPydant args: The list of arguments. This is useful for testing. Provide a list and check if your model is parsed correctly. If not provided clipstick will evaluate the arguments from `sys.argv`. + entry_point: Entry point name. This is useful for testing. + Provide an entry point name and check for value in help output. + If not provided clipstick will evaluate an entry point from `sys.argv`. Returns: An instance of the pydantic class we provided as argument populated with the provided args. @@ -30,7 +37,7 @@ def parse(model: type[TPydanticModel], args: list[str] | None = None) -> TPydant sys.exit(1) if args is None: entry_point, args = sys.argv[0], sys.argv[1:] - else: + elif entry_point is None: # Normally the first item in your sys.argv is the command/entrypoint you've entered. # During testing you don't provide that (only the actual arguments you enter after that). entry_point = DUMMY_ENTRY_POINT diff --git a/tests/conftest.py b/tests/conftest.py index e8a7a64..7d3e4f4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,11 +17,13 @@ def __init__(self, fixture_request) -> None: self.captured_output: str | None = None self._fixture_request = fixture_request - def __call__(self, model: type[BaseModel], args: list[str]) -> None: + def __call__( + self, model: type[BaseModel], args: list[str], entry_point: str | None = None + ) -> None: try: console.width = 1000 console.record = True - parse(model, args) + parse(model, args, entry_point) finally: self.captured_output = console.export_text(clear=False) diff --git a/tests/help_output/test_help_command_name/test_command_name_from_args.png b/tests/help_output/test_help_command_name/test_command_name_from_args.png new file mode 100644 index 0000000000000000000000000000000000000000..4e1592000e696fb29aee7072db005981f83b6fc6 GIT binary patch literal 21282 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