Source code for bpc_utils.argparse

"""Utility functions for argument parsing."""

from .typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .typing import Dict, Final, Linesep, Optional, Union


[docs]def parse_positive_integer(s: 'Optional[Union[str, int]]') -> 'Optional[int]': """Parse a positive integer from a string representation. Args: s: string representation of a positive integer, or just an integer Returns: the parsed integer result, return :data:`None` if input is :data:`None` or empty string Raises: TypeError: if ``s`` is not :obj:`str` or :obj:`int` ValueError: if ``s`` is an invalid positive integer value """ if s is None or s == '': # pylint: disable=compare-to-empty-string return None if not isinstance(s, (str, int)): raise TypeError('expect str or int, got {!r}'.format(s)) try: value = int(s) except ValueError: raise ValueError('expect an integer value, got {!r}'.format(s)) from None if value <= 0: raise ValueError('expect integer value to be positive, got {!r}'.format(value)) return value
_boolean_state_lookup = { '1': True, 'yes': True, 'y': True, 'true': True, 'on': True, '0': False, 'no': False, 'n': False, 'false': False, 'off': False, } # type: Final[Dict[str, bool]]
[docs]def parse_boolean_state(s: 'Optional[str]') -> 'Optional[bool]': """Parse a boolean state from a string representation. * These values are regarded as :data:`True`: ``'1'``, ``'yes'``, ``'y'``, ``'true'``, ``'on'`` * These values are regarded as :data:`False`: ``'0'``, ``'no'``, ``'n'``, ``'false'``, ``'off'`` Value matching is case **insensitive**. Args: s: string representation of a boolean state Returns: the parsed boolean result, return :data:`None` if input is :data:`None` Raises: ValueError: if ``s`` is an invalid boolean state value See Also: See :data:`~bpc_utils.argparse._boolean_state_lookup` for default lookup mapping values. """ if s is None: return None try: return _boolean_state_lookup[s.lower()] except KeyError: raise ValueError('invalid boolean state value {!r}'.format(s)) from None
_linesep_lookup = { '\n': '\n', 'lf': '\n', '\r\n': '\r\n', 'crlf': '\r\n', '\r': '\r', 'cr': '\r', } # type: Final[Dict[str, Linesep]]
[docs]def parse_linesep(s: 'Optional[str]') -> 'Optional[Linesep]': r"""Parse linesep from a string representation. * These values are regarded as ``'\n'``: ``'\n'``, ``'lf'`` * These values are regarded as ``'\r\n'``: ``'\r\n'``, ``'crlf'`` * These values are regarded as ``'\r'``: ``'\r'``, ``'cr'`` Value matching is **case insensitive**. Args: s: string representation of linesep Returns: Optional[:data:`~bpc_utils.Linesep`]: the parsed linesep result, return :data:`None` if input is :data:`None` or empty string Raises: ValueError: if ``s`` is an invalid linesep value See Also: See :data:`~bpc_utils.argparse._linesep_lookup` for default lookup mapping values. """ if not s: return None try: return _linesep_lookup[s.lower()] except KeyError: raise ValueError('invalid linesep value {!r}'.format(s)) from None
[docs]def parse_indentation(s: 'Optional[Union[str, int]]') -> 'Optional[str]': r"""Parse indentation from a string representation. * If an integer or a string of positive integer ``n`` is specified, then indentation is ``n`` spaces. * If ``'t'`` or ``'tab'`` is specified, then indentation is tab. * If ``'\t'`` (the tab character itself) or a string consisting only of the space character (U+0020) is specified, it is returned directly. Value matching is **case insensitive**. Args: s: string representation of indentation Returns: the parsed indentation result, return :data:`None` if input is :data:`None` or empty string Raises: TypeError: if ``s`` is not :obj:`str` or :obj:`int` ValueError: if ``s`` is an invalid indentation value """ if s is None or s == '': # pylint: disable=compare-to-empty-string return None if not isinstance(s, (str, int)): raise TypeError('expect str or int, got {!r}'.format(s)) if isinstance(s, str): if s.lower() in {'t', 'tab', '\t'}: return '\t' if s == ' ' * len(s): return s try: n = int(s) if n <= 0: raise ValueError return ' ' * n except ValueError: raise ValueError('invalid indentation value {!r}'.format(s)) from None
__all__ = ['parse_positive_integer', 'parse_boolean_state', 'parse_linesep', 'parse_indentation']