Argh currently uses the following approach to map a Python function signature onto CLI options and arguments:
no default value → required → positional;
has a default value → optional → named option (--foo).
Problem
While this mapping is simple and easy to understand, it's overly simplified:
the CLI and Python conventions differ in that Python allows passing the same argument both by position and name; in CLI it should be one or the other, so mapping the function's args (i.e. the part before the *) onto CLI is not straightforward.
a positional argument with a default value is essentially made kwonly-like ( PEP-3102);
the developer has no control over how the argument is mapped (positional vs named); doing it through default value is not always desirable.
the recent widespread adoption of static typing calls for a stricter approach in argument definitions; having None just to signify that the argument should be called by name became less acceptable.
Solution
The well-established PEP-3102 (2006) designates the syntax for separating positional and keyword-only arguments in function signature.
If we translate all "args" as positional CLI args and "kwonly args" as named ones ("options"), the mapping becomes far more straightforward and the developer has the ability to (not) define the default value and the positional/named way of calling independently.
Changing the classic implementation to the kwonly-driven one can break a lot of existing code that depends on Argh.
Moreover, this approach may turn out to be not as good in practice as it is on paper.
To ensure a smooth transition, the following steps should be considered:
add the new approach as optional, make it accessible via a new argument — e.g. dispatch(..., defaults_policy=DefaultsPolicy.KWONLY) — to be set;
if the approach proves to be superior to the classic simplified one, begin a slow deprecation of the latter:
if neither argument is passed, set this one to DefaultsPolicy.SIMPLIFIED and issue a warning;
switch to the new approach by default;
possibly deprecate the old one (if there's associated tech debt and no obvious value).
PyLint
The keyword-arg-before-vararg / W1113 warning is issued in the func(x=None, *args) case; it's recommended to replace it with func(*args, x=None). This supports the approach taken in this RFC.
Current state
Argh currently uses the following approach to map a Python function signature onto CLI options and arguments:
--foo
).Problem
While this mapping is simple and easy to understand, it's overly simplified:
*
) onto CLI is not straightforward.None
just to signify that the argument should be called by name became less acceptable.Solution
The well-established PEP-3102 (2006) designates the syntax for separating positional and keyword-only arguments in function signature.
If we translate all "args" as positional CLI args and "kwonly args" as named ones ("options"), the mapping becomes far more straightforward and the developer has the ability to (not) define the default value and the positional/named way of calling independently.
Example 1
Translates to:
Example 2
Translates to:
Concerns
Transition
Changing the classic implementation to the kwonly-driven one can break a lot of existing code that depends on Argh. Moreover, this approach may turn out to be not as good in practice as it is on paper. To ensure a smooth transition, the following steps should be considered:
dispatch(..., defaults_policy=DefaultsPolicy.KWONLY)
— to be set;DefaultsPolicy.SIMPLIFIED
and issue a warning;PyLint
The keyword-arg-before-vararg / W1113 warning is issued in the
func(x=None, *args)
case; it's recommended to replace it withfunc(*args, x=None)
. This supports the approach taken in this RFC.