diff options
Diffstat (limited to 'third_party/py/gflags/gflags/argument_parser.py')
-rw-r--r-- | third_party/py/gflags/gflags/argument_parser.py | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/third_party/py/gflags/gflags/argument_parser.py b/third_party/py/gflags/gflags/argument_parser.py deleted file mode 100644 index 9f7262b231..0000000000 --- a/third_party/py/gflags/gflags/argument_parser.py +++ /dev/null @@ -1,480 +0,0 @@ -#!/usr/bin/env python -# Copyright 2002 Google Inc. All Rights Reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -"""Contains base classes used to parse and convert arguments. - -Instead of importing this module directly, it's preferable to import the -flags package and use the aliases defined at the package level. -""" - -import csv -import io -import string - -import six - -import _helpers - - -class _ArgumentParserCache(type): - """Metaclass used to cache and share argument parsers among flags.""" - - _instances = {} - - def __new__(mcs, name, bases, dct): - _helpers.define_both_methods(name, dct, 'Parse', 'parse') - _helpers.define_both_methods(name, dct, 'Type', 'flag_type') - _helpers.define_both_methods(name, dct, 'Convert', 'convert') - return type.__new__(mcs, name, bases, dct) - - def __call__(cls, *args, **kwargs): - """Returns an instance of the argument parser cls. - - This method overrides behavior of the __new__ methods in - all subclasses of ArgumentParser (inclusive). If an instance - for cls with the same set of arguments exists, this instance is - returned, otherwise a new instance is created. - - If any keyword arguments are defined, or the values in args - are not hashable, this method always returns a new instance of - cls. - - Args: - *args: Positional initializer arguments. - **kwargs: Initializer keyword arguments. - - Returns: - An instance of cls, shared or new. - """ - if kwargs: - return type.__call__(cls, *args, **kwargs) - else: - instances = cls._instances - key = (cls,) + tuple(args) - try: - return instances[key] - except KeyError: - # No cache entry for key exists, create a new one. - return instances.setdefault(key, type.__call__(cls, *args)) - except TypeError: - # An object in args cannot be hashed, always return - # a new instance. - return type.__call__(cls, *args) - - -class ArgumentParser(six.with_metaclass(_ArgumentParserCache, object)): - """Base class used to parse and convert arguments. - - The parse() method checks to make sure that the string argument is a - legal value and convert it to a native type. If the value cannot be - converted, it should throw a 'ValueError' exception with a human - readable explanation of why the value is illegal. - - Subclasses should also define a syntactic_help string which may be - presented to the user to describe the form of the legal values. - - Argument parser classes must be stateless, since instances are cached - and shared between flags. Initializer arguments are allowed, but all - member variables must be derived from initializer arguments only. - """ - - syntactic_help = '' - - def parse(self, argument): - """Parses the string argument and returns the native value. - - By default it returns its argument unmodified. - - Args: - argument: string argument passed in the commandline. - - Raises: - ValueError: Raised when it fails to parse the argument. - - Returns: - The parsed value in native type. - """ - return argument - - def flag_type(self): - """Returns a string representing the type of the flag.""" - return 'string' - - def _custom_xml_dom_elements(self, doc): # pylint: disable=unused-argument - """Returns a list of XML DOM elements to add additional flag information. - - Args: - doc: A minidom.Document, the DOM document it should create nodes from. - - Returns: - A list of minidom.Element. - """ - return [] - - -class _ArgumentSerializerMeta(type): - - def __new__(mcs, name, bases, dct): - _helpers.define_both_methods(name, dct, 'Serialize', 'serialize') - return type.__new__(mcs, name, bases, dct) - - -class ArgumentSerializer(six.with_metaclass(_ArgumentSerializerMeta, object)): - """Base class for generating string representations of a flag value.""" - - def serialize(self, value): - return _helpers.StrOrUnicode(value) - - -class NumericParser(ArgumentParser): - """Parser of numeric values. - - Parsed value may be bounded to a given upper and lower bound. - """ - - def is_outside_bounds(self, val): - return ((self.lower_bound is not None and val < self.lower_bound) or - (self.upper_bound is not None and val > self.upper_bound)) - - def parse(self, argument): - val = self.convert(argument) - if self.is_outside_bounds(val): - raise ValueError('%s is not %s' % (val, self.syntactic_help)) - return val - - def _custom_xml_dom_elements(self, doc): - elements = [] - if self.lower_bound is not None: - elements.append(_helpers.CreateXMLDOMElement( - doc, 'lower_bound', self.lower_bound)) - if self.upper_bound is not None: - elements.append(_helpers.CreateXMLDOMElement( - doc, 'upper_bound', self.upper_bound)) - return elements - - def convert(self, argument): - """Default implementation: always returns its argument unmodified.""" - return argument - - -class FloatParser(NumericParser): - """Parser of floating point values. - - Parsed value may be bounded to a given upper and lower bound. - """ - number_article = 'a' - number_name = 'number' - syntactic_help = ' '.join((number_article, number_name)) - - def __init__(self, lower_bound=None, upper_bound=None): - super(FloatParser, self).__init__() - self.lower_bound = lower_bound - self.upper_bound = upper_bound - sh = self.syntactic_help - if lower_bound is not None and upper_bound is not None: - sh = ('%s in the range [%s, %s]' % (sh, lower_bound, upper_bound)) - elif lower_bound == 0: - sh = 'a non-negative %s' % self.number_name - elif upper_bound == 0: - sh = 'a non-positive %s' % self.number_name - elif upper_bound is not None: - sh = '%s <= %s' % (self.number_name, upper_bound) - elif lower_bound is not None: - sh = '%s >= %s' % (self.number_name, lower_bound) - self.syntactic_help = sh - - def convert(self, argument): - """Converts argument to a float; raises ValueError on errors.""" - return float(argument) - - def flag_type(self): - return 'float' - - -class IntegerParser(NumericParser): - """Parser of an integer value. - - Parsed value may be bounded to a given upper and lower bound. - """ - number_article = 'an' - number_name = 'integer' - syntactic_help = ' '.join((number_article, number_name)) - - def __init__(self, lower_bound=None, upper_bound=None): - super(IntegerParser, self).__init__() - self.lower_bound = lower_bound - self.upper_bound = upper_bound - sh = self.syntactic_help - if lower_bound is not None and upper_bound is not None: - sh = ('%s in the range [%s, %s]' % (sh, lower_bound, upper_bound)) - elif lower_bound == 1: - sh = 'a positive %s' % self.number_name - elif upper_bound == -1: - sh = 'a negative %s' % self.number_name - elif lower_bound == 0: - sh = 'a non-negative %s' % self.number_name - elif upper_bound == 0: - sh = 'a non-positive %s' % self.number_name - elif upper_bound is not None: - sh = '%s <= %s' % (self.number_name, upper_bound) - elif lower_bound is not None: - sh = '%s >= %s' % (self.number_name, lower_bound) - self.syntactic_help = sh - - def convert(self, argument): - if isinstance(argument, str): - base = 10 - if len(argument) > 2 and argument[0] == '0': - if argument[1] == 'o': - base = 8 - elif argument[1] == 'x': - base = 16 - return int(argument, base) - else: - return int(argument) - - def flag_type(self): - return 'int' - - -class BooleanParser(ArgumentParser): - """Parser of boolean values.""" - - def convert(self, argument): - """Converts the argument to a boolean; raise ValueError on errors.""" - if isinstance(argument, str): - if argument.lower() in ['true', 't', '1']: - return True - elif argument.lower() in ['false', 'f', '0']: - return False - - bool_argument = bool(argument) - if argument == bool_argument: - # The argument is a valid boolean (True, False, 0, or 1), and not just - # something that always converts to bool (list, string, int, etc.). - return bool_argument - - raise ValueError('Non-boolean argument to boolean flag', argument) - - def parse(self, argument): - val = self.convert(argument) - return val - - def flag_type(self): - return 'bool' - - -class EnumParser(ArgumentParser): - """Parser of a string enum value (a string value from a given set). - - If enum_values (see below) is not specified, any string is allowed. - """ - - def __init__(self, enum_values=None, case_sensitive=True): - """Initialize EnumParser. - - Args: - enum_values: Array of values in the enum. - case_sensitive: Whether or not the enum is to be case-sensitive. - """ - super(EnumParser, self).__init__() - self.enum_values = enum_values - self.case_sensitive = case_sensitive - - def parse(self, argument): - """Determine validity of argument and return the correct element of enum. - - If self.enum_values is empty, then all arguments are valid and argument - will be returned. - - Otherwise, if argument matches an element in enum, then the first - matching element will be returned. - - Args: - argument: The supplied flag value. - - Returns: - The matching element from enum_values, or argument if enum_values is - empty. - - Raises: - ValueError: enum_values was non-empty, but argument didn't match - anything in enum. - """ - if not self.enum_values: - return argument - elif self.case_sensitive: - if argument not in self.enum_values: - raise ValueError('value should be one of <%s>' % - '|'.join(self.enum_values)) - else: - return argument - else: - if argument.upper() not in [value.upper() for value in self.enum_values]: - raise ValueError('value should be one of <%s>' % - '|'.join(self.enum_values)) - else: - return [value for value in self.enum_values - if value.upper() == argument.upper()][0] - - def flag_type(self): - return 'string enum' - - -class ListSerializer(ArgumentSerializer): - - def __init__(self, list_sep): - self.list_sep = list_sep - - def serialize(self, value): - return self.list_sep.join([_helpers.StrOrUnicode(x) for x in value]) - - -class CsvListSerializer(ArgumentSerializer): - - def __init__(self, list_sep): - self.list_sep = list_sep - - def serialize(self, value): - """Serialize a list as a string, if possible, or as a unicode string.""" - if six.PY2: - # In Python2 csv.writer doesn't accept unicode, so we convert to UTF-8. - output = io.BytesIO() - csv.writer(output).writerow([unicode(x).encode('utf-8') for x in value]) - serialized_value = output.getvalue().decode('utf-8').strip() - else: - # In Python3 csv.writer expects a text stream. - output = io.StringIO() - csv.writer(output).writerow([str(x) for x in value]) - serialized_value = output.getvalue().strip() - - # We need the returned value to be pure ascii or Unicodes so that - # when the xml help is generated they are usefully encodable. - return _helpers.StrOrUnicode(serialized_value) - - -class BaseListParser(ArgumentParser): - """Base class for a parser of lists of strings. - - To extend, inherit from this class; from the subclass __init__, call - - BaseListParser.__init__(self, token, name) - - where token is a character used to tokenize, and name is a description - of the separator. - """ - - def __init__(self, token=None, name=None): - assert name - super(BaseListParser, self).__init__() - self._token = token - self._name = name - self.syntactic_help = 'a %s separated list' % self._name - - def parse(self, argument): - if isinstance(argument, list): - return argument - elif not argument: - return [] - else: - return [s.strip() for s in argument.split(self._token)] - - def flag_type(self): - return '%s separated list of strings' % self._name - - -class ListParser(BaseListParser): - """Parser for a comma-separated list of strings.""" - - def __init__(self): - BaseListParser.__init__(self, ',', 'comma') - - def parse(self, argument): - """Override to support full CSV syntax.""" - if isinstance(argument, list): - return argument - elif not argument: - return [] - else: - try: - return [s.strip() for s in list(csv.reader([argument], strict=True))[0]] - except csv.Error as e: - # Provide a helpful report for case like - # --listflag="$(printf 'hello,\nworld')" - # IOW, list flag values containing naked newlines. This error - # was previously "reported" by allowing csv.Error to - # propagate. - raise ValueError('Unable to parse the value %r as a %s: %s' - % (argument, self.flag_type(), e)) - - def _custom_xml_dom_elements(self, doc): - elements = super(ListParser, self)._custom_xml_dom_elements(doc) - elements.append(_helpers.CreateXMLDOMElement( - doc, 'list_separator', repr(','))) - return elements - - -class WhitespaceSeparatedListParser(BaseListParser): - """Parser for a whitespace-separated list of strings.""" - - def __init__(self, comma_compat=False): - """Initializer. - - Args: - comma_compat: bool - Whether to support comma as an additional separator. - If false then only whitespace is supported. This is intended only for - backwards compatibility with flags that used to be comma-separated. - """ - self._comma_compat = comma_compat - name = 'whitespace or comma' if self._comma_compat else 'whitespace' - BaseListParser.__init__(self, None, name) - - def parse(self, argument): - """Override to support comma compatibility.""" - if isinstance(argument, list): - return argument - elif not argument: - return [] - else: - if self._comma_compat: - argument = argument.replace(',', ' ') - return argument.split() - - def _custom_xml_dom_elements(self, doc): - elements = super(WhitespaceSeparatedListParser, self - )._custom_xml_dom_elements(doc) - separators = list(string.whitespace) - if self._comma_compat: - separators.append(',') - separators.sort() - for sep_char in separators: - elements.append(_helpers.CreateXMLDOMElement( - doc, 'list_separator', repr(sep_char))) - return elements |