kwparse: Tools to map, parse, and validate keyword arguments

This module provides the class KwargParser that allows for convenient and powerful parsing of functions that use the **kw convention in their signature, such as

def f(a, b, **kw):
    ...

Users of this module create subclasses of KwargParser that process the expected keyword arguments to f(). The capabilities of KwargParser include

Suppose you have a function

def f(a, b, **kw):
    ...

Where a should be a str, b should be an int, and the only kwargs are verbose and help, which should both be bool. However, users can use h as an alias for help and v for verbose. Then we could write a subclass of KwargParser to parse and validate args to this function.

class FKwargs(KwargParser):
    _optlist = ("help", "verbose")
    _optmap = {
        "h": "help",
        "v": "verbose",
    }
    _opttypes = {
        "a": str,
        "b": int,
        "help": bool,
        "verbose": bool,
    }
    _arglist = ("a", "b")
    _nargmin = 2
    _nargmax = 2

Here is how this parser handles an example with expected inputs.

>>> opts = FKwargs("me", 33, v=True)
>>> print(opts)
{'verbose': True}
>>> print(opts.get_args())
('me', 33)

In many cases it is preferable to use

within KwargParser._opttypes, e.g.

class FKwargs(KwargParser):
    _optlist = ("help", "verbose")
    _optmap = {
        "h": "help",
        "v": "verbose",
    }
    _opttypes = {
        "a": str,
        "b": INT_TYPES,
        "help": BOOL_TYPES,
        "verbose": BOOL_TYPES,
    }
    _arglist = ("a", "b")
    _nargmin = 2
    _nargmax = 2

so that values taken from numpy arrays are also recognized as valid “integers,” “floats,” or “booleans.”

Here are some examples of how FKwargs might handle bad inputs.

>>> FKwargs("my", help=True)
File "kwparse.py", line 172, in wrapper
    raise err.__class__(msg) from None
kwparse.KWTypeError: FKwargs() takes 2 arguments, but 1 were given
>>> FKwargs(2, 3)
File "kwparse.py", line 172, in wrapper
    raise err.__class__(msg) from None
kwparse.KWTypeError: FKwargs() arg 0 (name='a'): got type 'int';
expected 'str'
>>> FKwargs("my", 10, b=True)
File "kwparse.py", line 172, in wrapper
    raise err.__class__(msg) from None
kwparse.KWNameError: FKwargs() unknown kwarg 'b'
>>> FKwargs("my", 10, h=1)
File "kwparse.py", line 172, in wrapper
    raise err.__class__(msg) from None
kwparse.KWTypeError: FKwargs() kwarg 'help': got type 'int';
expected 'bool'

In order to use an instance of this FKwargs there are several approaches. The first is to call the parser class directly:

def f(a, b, **kw):
    opts = FKwargs(a, b, **kw)
    ...

Another method is to use FKwargs as a decorator

@FKwargs.parse
def f(a, b, **kw):
    ...

The decorator option ensures that a, b, and kw have all been validated. Users can then use kw.get("help") without needing to check for h.

class lfc._vendor.argread._vendor.kwparse.KwargParser(*args, **kw)

A class to parse args and keyword args, check types, etc.

Call:
>>> opts = KwargParser(*a, **kw)
Inputs:
a: tuple

Arbitrary tuple of positional parameters to a function

kw: dict

Arbitrary dict of keyword arguments to a function

Outputs:
opts: KwargParser

Dictionary of validated kwargs and positional parameters

Attributes:
_arglist = ()

Names for positional parameters (in order): tuple[set]

_name = ''

Subclass name used in error messages str

_nargmax = None

Maximum number of positional parameters: None | int > 0

_nargmin = 0

Minimum required number of positional parameters: int >= 0

_optconverters = {}

Functions to convert raw value of specified options: dict[callable]

_optlist = ()

Allowed keyword (option) names: (tuple | set)[str]

_optlistreq = ()

Required kwargs: tuple[str]

_optmap = {}

Aliases for kwarg names; key gets replaced with value: dict[str]

_opttypes = {}

Allowed types for option values, after using converter: dict[type | tuple[type]]

_optvalmap = {}

Aliases for option values: dict[object]

_optvals = {}

Specified allowed values for specified options: dict[tuple | set]

_rawopttypes = {}

Allowed types for option values, before using converter: dict[type | tuple[type]]

_rc = {}

Default values for specified options: dict[object]

apply_argconverter(j: int, argname, rawval)

Apply option converter function to raw positional arg value

Call:
>>> val = opts.apply_argconverter(j, argname, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

j: int

Positional parameter (arg) index

argname: None | str

Positional parameter (arg) name, if appropriate

rawval: object

Value of option, before _optconverters

Outputs:
val: {rawval} | object

Result of calling optconverter for opt on rawval

Raises:

KWTypeError if optconverter for opt is not callable

apply_optconverter(opt: str, rawval)

Apply option converter function to raw value

Call:
>>> val = opts.apply_optconverter(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name

rawval: object

Raw user value for opt before using optconverter

Outputs:
val: {rawval} | object

Result of calling optconverter for opt on rawval

Raises:

KWTypeError if optconverter for opt is not callable

apply_optmap(rawopt: str) str

Apply alias to raw option name, if applicable

Call:
>>> opt = opts.apply_optmap(rawopt)
Inputs:
opts: KwargParser

Keyword argument parser instance

rawopt: str

Option name or alias, before _optmap

Outputs:
opt: {rawopt} | str

De-aliased option name

apply_optvalmap(opt: str, rawval)

Apply option value map (aliases for value), if any

Call:
>>> val = opts.apply_optconverter(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name

rawval: object

Raw user value for opt before using optconverter

Outputs:
val: {rawval} | object

Dealiased (by _optvalmap[opt]) value

argvals

list – List of values of positional parameters that cannot be aliased to options (not in _optlist)

check_argtype(j: int, argname, val)

Check type of positional arg after conversion function

Call:
>>> opts.check_argtype(opt, val)
Inputs:
opts: KwargParser

Keyword argument parser instance

j: int

Positional parameter (arg) index

argname: None | str

Positional parameter (arg) name, if appropriate

val: object

Value for parameter in position j, after conversion

Raises:

KWTypeError if val has wrong type

check_argval(j: int, argname, val)

Check positional arg value against list of recognized values

Call:
>>> opts.check_optval(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

j: int

Positional parameter (arg) index

argname: None | str

Positional parameter (arg) name, if appropriate

val: object

Value for arg in position j

Raises:

KWValueError if argname has an optval setting and val is not in it

check_optname(opt: str)

Check validity of an option name

Call:
>>> opts.check_optname(opt)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name

Raises:

KWNameError if opt is not recognized

check_opttype(opt: str, val)

Check type of option value after conversion function

Call:
>>> opts.check_opttype(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name

val: object

Value for opt

Raises:

KWTypeError if val has wrong type

check_optval(opt: str, val)

Check option value against list of recognized values

Call:
>>> opts.check_optval(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name

val: object

Value for opt

Raises:

KWValueError if opt has an optval setting and val is not in it

check_rawargtype(j: int, argname, rawval)

Check type of positional arg prior to conversion function

Call:
>>> opts.check_rawargtype(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

j: int

Positional parameter (arg) index

argname: None | str

Positional parameter (arg) name, if appropriate

rawval: object

Value of option, before _optconverters

Raises:

KWTypeError if rawval has wrong type

check_rawopttype(opt: str, rawval)

Check type of option value prior to conversion function

Call:
>>> opts.check_rawopttype(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name

rawval: object

Raw user value for opt before using optconverter

Raises:

KWTypeError if rawval has wrong type

classmethod get_argname(j: int)

Get name for an argument by index, if applicable

Call:
>>> argname = cls.get_argname(j)
Inputs:
cls: type

A subclass of KwargParser

j: int

Positional parameter (arg) index

Outputs:
argname: None | str

Argument option name, if applicable

get_args() tuple

Return a copy of the current positional parameter values

Call:
>>> args = opts.get_args()
Inputs:
opts: KwargParser

Keyword argument parser instance

Outputs:
args: tuple[object]

Current values of positional parameters

classmethod get_cls_name() str

Get a name to use for a given class

Call:
>>> clsname = cls.get_cls_name()
Inputs:
cls: type

A subclass of KwargParser

Outputs:
clsname: str

cls._name if set, else cls.__name__

get_kwargs() dict

Get dictionary of kwargs, applying defaults

Call:
>>> kwargs = opts.get_kwargs()
Inputs:
opts: KwargParser

Keyword argument parser instance

Outputs:
kwargs: dict

Keyword arguments and values currently parsed

get_opt(opt: str, vdef=None)

Get value of one option

Call:
>>> val = opts.get_opt(opt, vdef=None)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

Name of option

vdef: {None} | object

Default value if opt not found in opts or _rc

classmethod get_optconverter(opt: str)

Get option value converter, if any, for option opt

Output must be a callable function that takes one argument

Call:
>>> func = cls.get_optconverter(opt)
Inputs:
cls: type

A subclass of KwargParser

opt: str

Full (non-aliased) name of option

Outputs:
func: None | function | callable

Function or other callable object

classmethod get_optlist() set

Get list of allowed options from cls and its bases

This combines the _optlist attribute from cls and any bases it might have that are also subclasses of KwargParser.

If optlist is an empty set, then no constraints are applied to option names.

Call:
>>> optlist = cls.get_opttype(opt)
Inputs:
cls: type

A subclass of KwargParser

Outputs:
optlist: set[str]

Single type or list of types for opt

classmethod get_opttype(opt: str)

Get the type(s) allowed for the value of option opt

If opttype is None, no constraints are placed on the value of opt. The “value” differs from the “raw value” in that the “value” is after any converters have been applied.

Call:
>>> opttype = cls.get_opttype(opt)
Inputs:
cls: type

A subclass of KwargParser

opt: str

Full (non-aliased) name of option

Outputs:
opttype: None | type | tuple

Single type or list of types for opt

classmethod get_optvalmap(opt: str)

Get option value aliases, if any, for option opt

Output must be a dict

Call:
>>> valmap = cls.get_optvalmap(opt)
Inputs:
cls: type

A subclass of KwargParser

opt: str

Full (non-aliased) name of option

Outputs:
valmap: None | dict

Map of alias values for opt

classmethod get_optvals(opt: str)

Get a set/list/tuple of allowed values for option opt

If optvals is not None, the full (post-optconverter) value will be checked if it is in optvals.

Call:
>>> optvals = cls.get_optvals(opt)
Inputs:
cls: type

A subclass of KwargParser

opt: str

Full (non-aliased) name of option

Outputs:
optvals: None | set | tuple

Tuple, list, set, or frozenset of allowed values

classmethod get_rawopttype(opt: str)

Get the type(s) allowed for the raw value of option opt

If opttype is None, no constraints are placed on the raw value of opt. The “raw value” is the value for opt before any converters have been applied.

Call:
>>> opttype = cls.get_rawopttype(opt)
Inputs:
cls: type

A subclass of KwargParser

opt: str

Full (non-aliased) name of option

Outputs:
opttype: None | type | tuple

Single type or list of types for raw opt

classmethod getx_cls_arg(attr: str, argname, vdef=None)

Get dict class attribute for positional parameter

If argname is None, the parameter (arg) has no name, and only "_arg_default_" and "_default_" can be used from getattr(cls, attr).

Otherwise, this will look in the bases of cls if getattr(cls, attr) does not have argname. If cls is a subclass of another KwargParser class, it will search through the bases of cls until the first time it finds a class attribute attr that is a dict containing key.

Call:
>>> v = cls.getx_cls_key(attr, key, vdef=None)
Inputs:
cls: type

A subclass of KwargParser

attr: str

Name of class attribute to search

key: str

Key name in cls.__dict__[attr]

vdef: {None} | object

Default value to use if not found in class attributes

Outputs:
v: None | ojbect

Any value, None if not found

classmethod getx_cls_dict(attr: str) dict

Get combined dict for cls and its bases

This allows a subclass of KwargParser to only add to the _opttypes or _optmap attribute rather than manually include contents of all the bases.

Call:
>>> clsdict = cls.getx_cls_dict(attr)
Inputs:
cls: type

A subclass of KwargParser

attr: str

Name of class attribute to search

Outputs:
clsdict: dict

Combination of getattr(cls, attr) and getattr(base, attr) for each base in cls.__bases__, etc.

classmethod getx_cls_key(attr: str, key: str, vdef=None)

Access key from a dict class attribute

This will look in the bases of cls if getattr(cls, attr) does not have key. If cls is a subclass of another KwargParser class, it will search through the bases of cls until the first time it finds a class attribute attr that is a dict containing key.

Call:
>>> v = cls.getx_cls_key(attr, key, vdef=None)
Inputs:
cls: type

A subclass of KwargParser

attr: str

Name of class attribute to search

key: str

Key name in cls.__dict__[attr]

vdef: {None} | object

Default value to use if not found in class attributes

Outputs:
v: None | ojbect

Any value, None if not found

classmethod getx_cls_set(attr: str) set

Get combined set for cls and its bases

This allows a subclass of KwargParser to only add to the _optlist attribute rather than manually include the _optlist of all the bases.

Call:
>>> v = cls.getx_cls_set(attr)
Inputs:
cls: type

A subclass of KwargParser

attr: str

Name of class attribute to search

Outputs:
v: set

Combination of getattr(cls, attr) and getattr(base, attr) for each base in cls.__bases__, etc.

init_post()

Custom post-initialization hook

This function is called in the standard __init__(). The default init_post() does nothing. Users may define custom actions in init_post() in subclasses to make certain changes at the end of parsing

Call:
>>> opts.init_post()
Inputs:
opts: KwargParser

Keyword argument parser instance

classmethod parse(func)

Decorator for a function to parse and validate its inputs

Call:
>>> wrapper = cls.parse(func)
Example:
@cls.parse
def func(*a, **kw):
    ...
Inputs:
func: callable

A function, class, or callable instance

Outputs:
cls: type

A subclass of KwargParser

wrap: callable

A wrapped version of func that parses and validates args and kwargs according to cls before calling func

set_arg(j: int, rawval)

Set the value of the j-th positional argument

Call:
>>> opts.set_arg(j, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

j: int >= 0

Argument index

rawval: object

Value for arg j, before _optconverters

set_args(args)

Set the values of positional arguments

Call:
>>> opts.set_args()
Inputs:
opts: KwargParser

Keyword argument parser instance

args: list | tuple

Ordered list of positional argument values

set_opt(rawopt: str, rawval)

Set the value of a single option

Call:
>>> opts.set_opt(rawopt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

rawopt: str

Name or alias of option to set

rawval: object

Pre-conversion value of rawopt

set_opts(a: dict)

Set a collection of options

Call:
>>> opts.set_opts(a)
Inputs:
opts: KwargParser

Keyword argument parser instance

a: dict

Dictionary of options to update into opts

validate_argval(j: int, argname, rawval)

Validate a raw positional parameter (arg) value

Call:
>>> val = opts.validate_argval(j, argname, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

j: int

Argument index

argname: None | str

Argument name, if applicable

rawval: object

Value of option, before _optconverters

Outputs:
val: object

Converted value, either rawval or optconverter(rawval)

validate_opt(rawopt: str, rawval) OptPair

Validate a raw option name and raw value

Replaces rawopt with non-aliased name and applies any optconverter to rawval. Raises an exception if option name, type, or value does not match expectations.

Call:
>>> optpair = opts.validate_opt(rawopt, rawval)
>>> opt, val = opts.validate_opt(rawopt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

rawopt: str

Name or alias of option, before _optlist

rawval: object

Value of option, before _optconverters

Outputs:
optpair: OptPair

tuple of de-aliased option name and converted value

opt: str

De-aliased option name (after optmap applied)

val: object

Converted value, either rawval or optconverter(rawval)

validate_optval(opt: str, rawval)

Validate a raw option value

Call:
>>> val = opts.validate_optval(opt, rawval)
Inputs:
opts: KwargParser

Keyword argument parser instance

opt: str

De-aliased option name (after optmap applied)

rawval: object

Value of option, before _optconverters

Outputs:
val: object

Converted value, either rawval or optconverter(rawval)

lfc._vendor.argread._vendor.kwparse.BOOL_TYPES = (<class 'bool'>, <class 'numpy.bool_'>)

Collection of boolean-like types: bool | numpy.bool_

lfc._vendor.argread._vendor.kwparse.FLOAT_TYPES = (<class 'float'>, <class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float128'>)

Collection of floating-point types: float | numpy.float16 | numpy.float32 | numpy.float64 | numpy.float128

lfc._vendor.argread._vendor.kwparse.INT_TYPES = (<class 'int'>, <class 'numpy.int8'>, <class 'numpy.int16'>, <class 'numpy.int32'>, <class 'numpy.int64'>, <class 'numpy.uint8'>, <class 'numpy.uint16'>, <class 'numpy.uint32'>, <class 'numpy.uint64'>)

Collection of integer (including unsigned) types: int | numpy.int8 | numpy.int16 | numpy.int32 | numpy.int64 | numpy.uint8 | numpy.uint16 | numpy.uint32 | numpy.uint64

exception lfc._vendor.argread._vendor.kwparse.KWKeyError

Errors for missing keys raised by kwparse

exception lfc._vendor.argread._vendor.kwparse.KWNameError

Errors for incorrect names raised by kwparse

exception lfc._vendor.argread._vendor.kwparse.KWParseError

Parent error class for kwparse errors

Inherts from Exception and enables general catching of all errors raised by kwparse

exception lfc._vendor.argread._vendor.kwparse.KWTypeError

Errors for incorrect type raised by kwparse

exception lfc._vendor.argread._vendor.kwparse.KWValueError

Errors for invalid values raised by kwparse

class lfc._vendor.argread._vendor.kwparse.OptPair(opt, val)

Option name/value pair

opt

Alias for field number 0

val

Alias for field number 1

lfc._vendor.argread._vendor.kwparse.STR_TYPES = (<class 'str'>, <class 'numpy.str_'>)

Collection of string-like types: str | numpy.str_