-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add base_command decorator (#22)
- chore: refactor project structure - feat: add base_command decorator - test: restructure and complete the test suite - fix: test coverage report generation - fix: publication to PyPiTest # Motivation The aim of these changes is to provide a simple and elegant way of integrating the essential basic logic of error handling and common options into a CLI command. These changes also complement unit testing. # Description All the CLI commands implemented so far share a number of common features. Firstly, they all use the same error handling logic (using the @error_handler decorator). Secondly, all these commands share a number of common options, such as the cluster endpoint (--endpoint), the output format option (--output) and the debug flag (--debug). For the moment, implementing these behaviors requires the addition of numerous decorators above each function defining a command. The aim of these changes is to streamline the code by providing a single decorator that abstracts this complexity. The aim is to centralize this logic to lighten the code and simplify future modifications. In addition, a number of unit tests are missing. These changes add a number of them and significantly improve test coverage. # Testing A number of unit tests have been added to ensure that the changes made do not alter the proper operation of the CLI. In addition, manual tests have been performed to validate end-to-end functionality. # Impact These changes have no impact on the rest of the ArmoniK project. They are purely internal to this project. # Checklist - [x] My code adheres to the coding and style guidelines of the project. - [x] I have performed a self-review of my code. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have made corresponding changes to the documentation. - [x] I have thoroughly tested my modifications and added tests when necessary. - [x] Tests pass locally and in the CI. - [x] I have assessed the performance impact of my modifications.
- Loading branch information
Showing
19 changed files
with
523 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[run] | ||
omit = | ||
*/_version.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from armonik_cli.core.console import console | ||
from armonik_cli.core.decorators import base_command | ||
from armonik_cli.core.params import KeyValuePairParam, TimeDeltaParam | ||
|
||
|
||
__all__ = ["base_command", "KeyValuePairParam", "TimeDeltaParam", "console"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
from functools import wraps, partial | ||
|
||
import grpc | ||
import rich_click as click | ||
|
||
from armonik_cli.core.console import console | ||
from armonik_cli.exceptions import NotFoundError, InternalError | ||
|
||
|
||
def error_handler(func=None): | ||
"""Decorator to ensure correct display of errors. | ||
Args: | ||
func: The command function to be decorated. If None, a partial function is returned, | ||
allowing the decorator to be used with parentheses. | ||
Returns: | ||
The wrapped function with added CLI options. | ||
""" | ||
# Allow to call the decorator with parenthesis. | ||
if not func: | ||
return partial(error_handler) | ||
|
||
@wraps(func) | ||
def wrapper(*args, **kwargs): | ||
try: | ||
return func(*args, **kwargs) | ||
except click.ClickException: | ||
raise | ||
except grpc.RpcError as err: | ||
status_code = err.code() | ||
error_details = f"{err.details()}." | ||
|
||
if status_code == grpc.StatusCode.NOT_FOUND: | ||
raise NotFoundError(error_details) | ||
else: | ||
raise InternalError("An internal fatal error occured.") | ||
except Exception: | ||
if "debug" in kwargs and kwargs["debug"]: | ||
console.print_exception() | ||
else: | ||
raise InternalError("An internal fatal error occured.") | ||
|
||
return wrapper | ||
|
||
|
||
def base_command(func=None): | ||
"""Decorator to add common CLI options to a Click command function, including | ||
'endpoint', 'output', and 'debug'. These options are automatically passed | ||
as arguments to the decorated function. | ||
The following options are added to the command: | ||
- `--endpoint` (required): Specifies the cluster endpoint. | ||
- `--output`: Sets the output format, with options 'yaml', 'json', or 'table' (default is 'json'). | ||
- `--debug`: Enables debug mode, printing additional logs if set. | ||
Warning: | ||
If the decorated function has parameters with the same names as the options added by | ||
this decorator, this can lead to conflicts and unpredictable behavior. | ||
Args: | ||
func: The command function to be decorated. If None, a partial function is returned, | ||
allowing the decorator to be used with parentheses. | ||
Returns: | ||
The wrapped function with added CLI options. | ||
""" | ||
|
||
# Allow to call the decorator with parenthesis. | ||
if not func: | ||
return partial(base_command) | ||
|
||
# Define the wrapper function with added Click options | ||
@click.option( | ||
"-e", | ||
"--endpoint", | ||
type=str, | ||
required=True, | ||
help="Endpoint of the cluster to connect to.", | ||
metavar="ENDPOINT", | ||
) | ||
@click.option( | ||
"-o", | ||
"--output", | ||
type=click.Choice(["yaml", "json", "table"], case_sensitive=False), | ||
default="json", | ||
show_default=True, | ||
help="Commands output format.", | ||
metavar="FORMAT", | ||
) | ||
@click.option( | ||
"--debug", is_flag=True, default=False, help="Print debug logs and internal errors." | ||
) | ||
@error_handler | ||
@wraps(func) | ||
def wrapper(endpoint: str, output: str, debug: bool, *args, **kwargs): | ||
kwargs["endpoint"] = endpoint | ||
kwargs["output"] = output | ||
kwargs["debug"] = debug | ||
return func(*args, **kwargs) | ||
|
||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Oops, something went wrong.