Skip to content

Instantly share code, notes, and snippets.

@bockel
Created March 23, 2020 18:51
Show Gist options
  • Select an option

  • Save bockel/484766532281eaf29bcbe943cc27cfa6 to your computer and use it in GitHub Desktop.

Select an option

Save bockel/484766532281eaf29bcbe943cc27cfa6 to your computer and use it in GitHub Desktop.
argparse for PowerShell: case insensitive option handling
# Drop in replacement for argparse for PowerShell/pwsh argument handling compatibility
# - argparse already supports abbreviated matches
# - ADD: support for case insensitive options
# - ADD: support for automated -Help -? and -Verbose flags
from argparse import ArgumentParser as _ArgumentParser
from argparse import SUPPRESS
from sys import exit
from collections.abc import MutableMapping
try:
_cmp = str.casefold # support starting in python 3.3
except:
_cmp = str.lower
class CaseInsensitiveDict(MutableMapping):
"""A minimal implementation of a case insensitive dict.
Implementation requires string keys, but supports arbitrary values.
"""
def __init__(self, *args, **kwargs):
self.__d = dict()
for k, v in dict(*args, **kwargs).items():
self[k] = v
def __getitem__(self, k):
# print('get', k)
# print(self.__d)
return self.__d[_cmp(k)]
def __setitem__(self, k, v):
# print('set', k, v)
self.__d[_cmp(k)] = v
def __delitem__(self, k):
return self.__d.__delitem__(k)
def __iter__(self):
return iter(self.__d)
def __len__(self):
return len(self.__d)
def __str__(self):
return self.__d.__str__()
class ArgumentParser(_ArgumentParser):
"""Case insenstive option parser.
Extend the built-in python argparse.ArgumentParser to add PowerShell
features, including:
- Case insensitive option matching
- Use of -Help, -? for command usage help
- Adds common options: -Verbose, -Version, -Quiet
- Allows automated handling of -Version via the "version" kwarg
"""
def __init__(self, *args, **kwargs):
# kwargs['add_help'] = False
prefix = kwargs.get('prefix_chars', '-')[0]
defaults = kwargs.pop('add_defaults', True)
self.ver = kwargs.pop('version')
super().__init__(*args, **kwargs)
self._option_string_actions = CaseInsensitiveDict(self._option_string_actions)
if kwargs.get('add_help', True):
_help = self._option_string_actions[prefix+'h']
# remove the default -h --help
del self._option_string_actions[prefix + 'h']
del self._option_string_actions[prefix*2 + 'help']
helps = ['-Help', '-?'] # map to PowerShell defaults
for _hopt in helps:
self._option_string_actions[_hopt] = _help
_help.option_strings = helps
if self.ver:
self.add_argument(prefix+'Version', action='store_true',
help='Display the version information and exit')
if defaults:
self.add_argument(prefix+'Verbose', action='count', default=0,
help='Display additional runtime information')
self.add_argument(prefix+'Quiet', action='store_true',
help='Display no information, including errors. Overrides, -Verbose')
def add_argument(self, *args, **kwargs):
ret = super().add_argument(*args, **kwargs)
# Add our option strings to our case insensitive dict
for option_string in ret.option_strings:
self._option_string_actions[option_string] = ret
return ret
def parse_args(self, *args, **kwargs):
ret = super().parse_args(*args, **kwargs)
if ret.Version:
print(self.ver)
exit(0)
return ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment