Extending paramspecli
There are a few extension points to the paramspecli.
Type converters
The most common extension is a custom type converter. Type converter is a callable converting string to the parameter type.
Example of int converter with some validation:
class IntConv:
def __init__(self, min: int | None = None, max: int | None = None, base: int = 10):
self.min = min
self.max = max
self.base = base
def __call__(self, arg: str) -> int:
val = int(arg, base=self.base) # may rise ValueError
if self.min is not None and self.val < self.min:
raise ArgumentTypeError(f"{val} is too small")
# more checks follows
return val
cmd.bind(foo=-option("--foo", type=IntConv(min=0, max=42)))
Option factories
In some cases, it's worth to code a custom option factory function.
Example of custom regexp option:
import re
from paramspecli.fake import Option
from paramspecli.util import catch_all
def regexp(*names: str, help: str | bool | None = None) -> Option[re.Pattern[str], None]:
conv = catch_all(re.compile)
return Option(names=names, type=conv, help=help, metavar="REGEXP")
cmd.bind(match_re=-regexp("--match"))
The factory function should return the instance of the generic Option class.
To play nice with the rest of the typing, Option must be specialized by two type parameters:
- T - type of result if option is present
- D - type of result if option is missing
In most cases Option resulting type would be Union[T, D]. D is starting to be important when option is mixed with another options.
class Option[T, D](names, *, type=None, help=None, nargs=None, default=None, const=None, required=False, choices=None, metavar=None, action=None, deprecated=False, extra=None)
class Argument[T, D](metavar, *, type=None, help=None, nargs=None, choices=None, default=None, extra=None)
- names - tuple of names
- type - type converter
- help - help message
- str: this string
None: nothingFalse: hide option from the--helpoutput
- hard_show_default - show default in help message
True: show defaultFalse: show nothing- str: show this very string
None: consult the soft_show_default
- soft_show_default - show default in help message unless globally disabled
True: show defaultFalse: show nothing- str: show this very string
- required, choices, metavar, action, nargs, default, const, deprecated - forwarded to the
ArgumentParser.add_argument() - extra - dict of extra **kwargs for the
ArgumentParser.add_argument()
If option is repeated (that is, action is extend, append, or append_const), factory should return the RepeatedOption[T] class. This is a list-producing variant of Option.
Actions
Custom actions should return the instance of the Action class. The Action has a same constructor as an Option, but since actions are not bound to parameters, there is no need for type specialization.
This is how the version_action() factory function is defined:
def version_action(
version: str,
*,
help: str | Markup | bool = "Show program's version number and exit"
) -> Action:
return Action(("--version",), action="version", help=help, extra={"version": version})