Search code examples
python-3.xpython-2.7args

I want to modify helper function to be python2 compatible


I would like to use this CLI template https://mike.depalatis.net/blog/simplifying-argparse.html for creating a tool for accessing the EMC Unity REST API.

It appears to be written with python3 in mind. Particularly the argument helper function.

def argument(*name_or_flags, **kwargs):
    return ([*name_or_flags], kwargs)

I don't believe I understand exactly how the argument function is supposed to work and thus how I can modify it to work with python2.

e.g. If I had a function create_lun that had a few options, I think I need argument to return a list of arguments defined and thus I would decorate it as so:

@subcommand([argument('-o', '--pool', dest='pool', default="pool_1", 
                   type=str, help='Name of Pool of str arg'),
          argument('lun_name', metavar='lun_name', type=str,
                    help='Name of LUN to create in format: ldom-vol#')])
def create_lun(args):

and thus cli.py create_lun lun_name would create the lun and -h would show me this syntax.

If that assumption is correct I would need to translate python3's ability to

return ([*name_or_flags], kwargs)

into a python2.7 equivalent. Any thoughts on this greatly appreciated.


Solution

  • The line

    return ([*name_or_flags], kwargs)
    

    is the same as

    return [*name_or_flags], kwargs
    

    which is the same as

    return name_or_flags, kwargs
    

    In python 3, the syntax [*a_list] expands the elements of a list into a new list literal. It's intended purpose was for inserting an existing list into a new list, not for simply making a copy of a list.

    In [1]: a = list(range(9))
    
    In [2]: a
    Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8]
    
    In [3]: [*a]
    Out[3]: [0, 1, 2, 3, 4, 5, 6, 7, 8]
    
    In [4]: ['hey', *a, 'there']
    Out[4]: ['hey', 0, 1, 2, 3, 4, 5, 6, 7, 8, 'there']
    

    To write [*name_or_flags] seems like an attempt at obfuscation. Possibly the author had wanted to create a new copy of name_or_flags, and in that case a slice would have been enough:

    def argument(*name_or_flags, **kwargs):
        return name_or_flags[:], kwargs
    

    If no copy was needed, then the following will suffice.

    def argument(*name_or_flags, **kwargs):
        return name_or_flags, kwargs
    

    This will work in both Python2 and Python3 and should yield the same results.