From 423a4843e49061486cb1edc333324b286ab6465b Mon Sep 17 00:00:00 2001 From: svalouch Date: Thu, 5 May 2022 13:48:46 +0200 Subject: [PATCH] Fix completion-related breakage Click introduced a new API in 8.1 and made it backwards-incompatible. They also changed the invocation with 8.0. Documentation was updated to include the new way to get the completion, along with some examples for Linux distributions that support the major version 7 or 8 of click. To support most click versions, the completion was changed to work from click 7.0 onwards, by conditionally changing the argument handed to the "option" decorator. Additionally, the completion function now simply uses kwargs, support the different calling conventions throughout the versions. Since it isn't yet known if there will be more breakage in future versions, this commit limits the allowed / supported versions of click to less than 8.2, which is expected to be the next release. Thanks to @poggenpower for finding this. Fixes #17 Fixes #18 --- CHANGELOG.md | 11 +++++++++++ docs/cli.rst | 10 +++++++--- setup.py | 2 +- src/rctclient/cli.py | 17 ++++++++++------- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f0c5b..1603139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file. - Mention checksum algorithm. - List all known commands as well as reserved ones. - Describe plant communication, which has not been tested yet. +- CLI invocation: Bash-completion activation changed with newer versions of `Click`. ### Features @@ -26,6 +27,16 @@ All notable changes to this project will be documented in this file. - `Command` learned about `READ_PERIODICALLY`, but it has not been tested yet. - `Command` learned about the `PLANT_` equivalents of the other commands. +### Bugfixes + +- CLI: Implement support for `Click 8.1` caused by API changes related to custom completions (Issue #17, PR #18). + +### Dependency changes + +- `Click`: Version `7.0` is the new minimum, it supported custom completion functions for the first time +- `Click`: Version `8.1` is the new maximum, to guard against API changes during unconditionally updating the + dependencies. + ## Release 0.0.3 - 2021-05-22 ### Breaking changes diff --git a/docs/cli.rst b/docs/cli.rst index d54642f..a36b0ec 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -10,9 +10,13 @@ The library comes with a CLI tool called ``rctclient`` that offers some useful s The tool is only installed if the `click `_ module's present. If installing from `pip`, the requirement can be pulled in by specifying ``rctclient[cli]``. -For certain parameters, the tool supports shell completion. Read more about this at the `click documentation -`_. For Bash, the completion can be activated using -the following command: ``eval "$(_RCTCLIENT_COMPLETE=source_bash rctclient)"`` +For certain parameters, the tool supports shell completion. Depending on your version of *Click*, there are different +ways to enable the completion: + +* ``< 8.0.0``: ``eval "$(_RCTCLIENT_COMPLETE=source_bash rctclient)"`` (e.g. Debian 11, Ubuntu 20.04) +* ``>= 8.0.0``: ``eval "$(_RCTCLIENT_COMPLETE=bash_source rctclient)"`` (e.g. Arch, Fedora 35+, Gentoo) + +Read more about this at the `click documentation `_. .. click:: rctclient.cli:cli :prog: rctclient diff --git a/setup.py b/setup.py index bdee3ef..6424110 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ extras_require={ 'cli': [ - 'click', + 'click>=7.0<8.2', ], 'tests': [ 'mypy', diff --git a/src/rctclient/cli.py b/src/rctclient/cli.py index 0179c47..2c15813 100644 --- a/src/rctclient/cli.py +++ b/src/rctclient/cli.py @@ -52,16 +52,20 @@ def cli(ctx, debug: bool, frame_debug: bool) -> None: log.info('rctclient CLI starting') -def autocomplete_registry_name(_ctx, _args: List, incomplete: str) -> List[str]: +def autocomplete_registry_name(*args, **kwargs) -> List[str]: # pylint: disable=unused-argument ''' Provides autocompletion for the object IDs name parameter. - :param _ctx: Click context (ignored). - :param _args: Arguments (ignored). - :param incomplete: Incomplete (or empty) string from the user. :return: A list of names that either start with `incomplete` or all if `incomplete` is empty. ''' - return R.prefix_complete_name(incomplete) + if 'incomplete' not in kwargs: + kwargs['incomplete'] = '' + return R.prefix_complete_name(kwargs['incomplete']) + +if click.__version__ >= '8.1.0': + autocomp_registry = {'shell_complete': autocomplete_registry_name} +else: + autocomp_registry = {'autocompletion': autocomplete_registry_name} def receive_frame(sock: socket.socket, timeout: int = 2) -> ReceiveFrame: @@ -102,8 +106,7 @@ def receive_frame(sock: socket.socket, timeout: int = 2) -> ReceiveFrame: @click.option('-h', '--host', required=True, type=click.STRING, help='Host address or IP of the device', metavar='') @click.option('-i', '--id', type=click.STRING, help='Object ID to query, of the form "0xXXXX"', metavar='') -@click.option('-n', '--name', help='Object name to query', type=click.STRING, metavar='', - autocompletion=autocomplete_registry_name) +@click.option('-n', '--name', help='Object name to query', type=click.STRING, metavar='', **autocomp_registry) @click.option('-v', '--verbose', is_flag=True, default=False, help='Enable verbose output') def read_value(ctx, port: int, host: str, id: Optional[str], name: Optional[str], verbose: bool) -> None: '''