pythonargparse

In python argparse package when adding "formatter_class" MetavarTypeHelpFormatter the "--help" is not working any more


I'm using the python package argparse, with simple configuration

When I try to add to my parser formatter_class=argparse.MetavarTypeHelpFormatter I get error:

AttributeError: 'NoneType' object has no attribute '__name__'

did anyone else encounter that? and maybe know why?

this is my code:

import argparse

argParser = argparse.ArgumentParser(
    formatter_class=argparse.MetavarTypeHelpFormatter)

argParser.add_argument(
    "models",
    default='',
    nargs='+',
    help="Which model(s) to execute")

args = argParser.parse_args()
print(args)

When I try it with out adding the formatter_class it is working It is also working with other formatter class like formatter_class=argparse.RawDescriptionHelpFormatter

I also tried it with prog attribute and without


Solution

  • Short answer: the type argument to add_argument defaults to None, not str.


    Less short answer: a type of None behaves like a type of str, but doesn't work with MetaVarTypeHelpFormatter.

    MetaVarTypeHelpFormatter requires an explicit type for each argument.

    argParser.add_argument(
        "models",
        default='',
        nargs='+',
        type=str,
        help="Which model(s) to execute")
    

    Its documented purpose is to use the name of the argument's type attribute as the metavariable, and that attribute defaults to None.

    Although the default type of an argument is str, that just means the str value taken from the argument list is preserved if the argument's type attribute is None, or converted to the given type if it is not None.

    >>> p = argparse.ArgumentParser()
    >>> print(p.add_argument("foo").type)
    None
    >>> print(p.add_argument("foo", type=int).type)
    <class 'int'>
    

    Each parser maintains a type registry, which means you can add your own arbitrary mappings of values to callables to produce types. For instance,

    >>> import argparse
    >>> p = argparse.ArgumentParser()
    >>> p.register('type', 'lowercase', lambda x: x.lower())
    >>> p.add_argument("foo", type='lowercase')
    _StoreAction(option_strings=[], dest='foo', nargs=None, const=None, default=None, type='lowercase', choices=None, required=True, help=None, metavar=None)
    >>> p.parse_args(["HELLO WORLD"])
    Namespace(foo='hello world')
    

    Initially, the entry in the type registry maps None to

    def identity(string):
        return string
    

    which is why an argument with "type" None otherwise behaves as if you had supplied str explicitly.

    The type registry isn't documented and, aside from this single entry, isn't used again, so it's not clear why it exists. The author may have had plans to use it more that never came to fruition. (Notice that each parser also has an action registry that gets used more often, which is why you can specify actions like 'append' and 'store_const' instead of specifying non-public classes like _AppendAction and _StoreConstAction directly.)