Created
March 23, 2020 18:51
-
-
Save bockel/484766532281eaf29bcbe943cc27cfa6 to your computer and use it in GitHub Desktop.
argparse for PowerShell: case insensitive option handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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