diff --git a/src/clapper/click.py b/src/clapper/click.py index 05d48845f671b59620f3d54ea3622c0331592e4b..913779696518969d590480b7fef61d640a178721 100644 --- a/src/clapper/click.py +++ b/src/clapper/click.py @@ -15,6 +15,7 @@ import time import typing from importlib.metadata import EntryPoint +from textwrap import dedent import click import tomli @@ -70,7 +71,7 @@ def verbosity_option( name: Long name of the option. If not set, then use ``verbose`` -- this will also become the name of the contextual parameter for click. - dlft: The default verbosity level to use (defaults to 0). + dflt: The default verbosity level to use (defaults to 0). **kwargs: Further keyword-arguments to be forwarded to the underlying :py:func:`click.option` @@ -105,13 +106,15 @@ def verbosity_option( type=click.IntRange(min=0, max=3, clamp=True), default=dflt, show_default=True, - help=( - f"Increase the verbosity level from 0 (only error and " - f"critical) messages will be displayed, to 1 (like 0, but adds " - f"warnings), 2 (like 1, but adds info messags), and 3 (like 2, " - f"but also adds debugging messages) by adding the --{name} " - f"option as often as desired (e.g. '-vvv' for debug)." - ), + help=dedent( + f"""\ + Increase the verbosity level from 0 (only error and critical) + messages will be displayed, to 1 (like 0, but adds warnings), 2 + (like 1, but adds info messages), and 3 (like 2, but also adds + debugging messages) by adding the --{name} option as often as + desired (e.g. '-vvv' for debug). + """ + ).replace("\n", " "), callback=callback, **kwargs, )(f) @@ -119,6 +122,13 @@ def verbosity_option( return custom_verbosity_option +def _format_entry_points(entry_points_group: str | None) -> str: + """Returns the list of a group's entry points as str.""" + if entry_points_group is None: + return "" + return ", ".join(resource_keys(entry_points_group)) + + class ConfigCommand(click.Command): """A :py:class:`click.Command` that can read options from config files. @@ -159,13 +169,31 @@ class ConfigCommand(click.Command): self.entry_point_group = entry_point_group configs_argument_name = "CONFIG" + entry_points_str = _format_entry_points(entry_point_group) + # Augment help for the config file argument - self.extra_help = f"""\n\nIt is possible to pass one or several Python -files (or names of ``{entry_point_group}`` entry points or module names) as -{configs_argument_name} arguments to the command line which contain the parameters listed below as Python variables. The options through the command-line (see below) -will override the values of configuration files. You can run this command with -``<COMMAND> -H example_config.py`` to create a template config file.""" - help = (help or "").rstrip() + self.extra_help + self.extra_help = dedent( + f""" + It is possible to pass one or several Python files (or names of + ``{entry_point_group}`` entry points or module names) as + {configs_argument_name} arguments to the command line which contain + the parameters listed below as Python variables. The options through + the command-line (see below) will override the values of + configuration files. You can run this command with + ``<COMMAND> -H example_config.py`` to create a template config file. + """ + ) + + entry_points = dedent( + f""" + Available configs entry points are: + + {entry_points_str} + + """ + ) + self.extra_help = "\n\n".join((self.extra_help, entry_points)) + help = "\n\n".join(((help or "").rstrip(), self.extra_help)) super().__init__(name, *args, help=help, **kwargs) # Add the config argument to the command @@ -303,12 +331,12 @@ class ResourceOption(click.Option): 1. Using this class (without using :py:class:`ConfigCommand`) AND (providing ``entry_point_group``). 2. Using this class (with :py:class:`ConfigCommand`) AND (providing - `entry_point_group`). + ``entry_point_group``). 3. Using this class (with :py:class:`ConfigCommand`) AND (without providing - `entry_point_group`). + ``entry_point_group``). Using this class without :py:class:`ConfigCommand` and without providing - `entry_point_group` does nothing and is not allowed. + ``entry_point_group`` does nothing and is not allowed. Attributes: @@ -359,16 +387,24 @@ class ResourceOption(click.Option): type = CustomParamType() self.entry_point_group = entry_point_group + + entry_points_str = _format_entry_points(entry_point_group) + if entry_point_group is not None: name, _, _ = self._parse_decls( param_decls, kwargs.get("expose_value") ) help = help or "" - help += ( - f" Can be a `{entry_point_group}' entry point, a module name, or " - f"a path to a Python file which contains a variable named `{name}'." + self.extra_help = dedent( + f"""\ + Can be a `{entry_point_group}' entry point, a module name, or a + path to a Python file which contains a variable named '{name}'. + Available entry points are: + + {entry_points_str} + """ ) - help = help.format(entry_point_group=entry_point_group, name=name) + help = " ".join((help, self.extra_help)) super().__init__( param_decls=param_decls, @@ -393,7 +429,7 @@ class ResourceOption(click.Option): ) -> tuple[typing.Any, ParameterSource]: """Retrieves value for parameter from appropriate context. - This method will retrive the value of its own parameter from the + This method will retrieve the value of its own parameter from the appropriate context, by trying various sources. @@ -667,7 +703,7 @@ def config_group( configurations. This decorator adds a whole command group to a user predefined function - which is part of the user's CLI. The command group provdes an interface to + which is part of the user's CLI. The command group provides an interface to list, fully describe or locally copy configuration files distributed with the package. Commands accept both entry-point or module names to be provided as input. diff --git a/src/clapper/config.py b/src/clapper/config.py index 8dcabc16c703e53771c3a85ba4081f809d7f9b3c..5854e0be427ed5ca4141ea8431a67d20a466b3f0 100644 --- a/src/clapper/config.py +++ b/src/clapper/config.py @@ -131,7 +131,7 @@ def _resolve_entry_point_or_modules( entry-point names and module names to a set of file system paths. Examples of things that can be resolved by this function are: - ``["/tmp/config.py", "my-config", "expose.config"]`` (an actualy filesystem + ``["/tmp/config.py", "my-config", "expose.config"]`` (an actual filesystem path, an entry-point described in a ``setup.py`` file, or the name of a python module. @@ -291,7 +291,7 @@ def load( # remove the keys that might break the loading of the next config file. ctxt.__dict__.pop("__name__", None) ctxt.__dict__.pop("__package__", None) - # do not propogate __ variables + # do not propagate __ variables context = { k: v for k, v in ctxt.__dict__.items() if not k.startswith("__") } @@ -350,7 +350,7 @@ def resource_keys( that entry point distribution (``.dist`` attribute) was only added to Python in version 3.10. We therefore currently only verify if the named resource does not start with any of the strings provided in - `exclude_package``. + ``exclude_package``. Arguments: diff --git a/tests/data/test_dump_config.py b/tests/data/test_dump_config.py index a4ce209e84e7fa8d37afc62aaeb657283919d6c3..f528f11f9bb44aff969d7c66d9ac9fddb4b2b796 100644 --- a/tests/data/test_dump_config.py +++ b/tests/data/test_dump_config.py @@ -13,4 +13,4 @@ Path leading to test blablabla""" # verbose = 0 """Optional parameter: verbose (-v, --verbose) [default: 0] -Increase the verbosity level from 0 (only error and critical) messages will be displayed, to 1 (like 0, but adds warnings), 2 (like 1, but adds info messags), and 3 (like 2, but also adds debugging messages) by adding the --verbose option as often as desired (e.g. '-vvv' for debug).""" +Increase the verbosity level from 0 (only error and critical) messages will be displayed, to 1 (like 0, but adds warnings), 2 (like 1, but adds info messages), and 3 (like 2, but also adds debugging messages) by adding the --verbose option as often as desired (e.g. '-vvv' for debug).""" diff --git a/tests/data/test_dump_config2.py b/tests/data/test_dump_config2.py index d0e7d51d797f960fcd24f95911dafccd9df7944b..80f6a93c281bcbfd84864dbd9edb84edeabd1675 100644 --- a/tests/data/test_dump_config2.py +++ b/tests/data/test_dump_config2.py @@ -42,4 +42,4 @@ lklklklk""" # verbose = 0 """Optional parameter: verbose (-v, --verbose) [default: 0] -Increase the verbosity level from 0 (only error and critical) messages will be displayed, to 1 (like 0, but adds warnings), 2 (like 1, but adds info messags), and 3 (like 2, but also adds debugging messages) by adding the --verbose option as often as desired (e.g. '-vvv' for debug).""" +Increase the verbosity level from 0 (only error and critical) messages will be displayed, to 1 (like 0, but adds warnings), 2 (like 1, but adds info messages), and 3 (like 2, but also adds debugging messages) by adding the --verbose option as often as desired (e.g. '-vvv' for debug)."""