aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/py/gflags/gflags/flagvalues.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/py/gflags/gflags/flagvalues.py')
-rw-r--r--third_party/py/gflags/gflags/flagvalues.py1261
1 files changed, 0 insertions, 1261 deletions
diff --git a/third_party/py/gflags/gflags/flagvalues.py b/third_party/py/gflags/gflags/flagvalues.py
deleted file mode 100644
index a47b40308f..0000000000
--- a/third_party/py/gflags/gflags/flagvalues.py
+++ /dev/null
@@ -1,1261 +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.
-
-"""Flagvalues module - Registry of 'Flag' objects.
-
-Instead of importing this module directly, it's preferable to import the
-flags package and use the aliases defined at the package level.
-"""
-
-import hashlib
-import logging
-import os
-import struct
-import sys
-import traceback
-import warnings
-from xml.dom import minidom
-
-import six
-
-import _helpers
-import exceptions
-import flag as _flag
-
-# Add flagvalues module to disclaimed module ids.
-_helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
-
-# The MOE directives in this file cause the docstring indentation
-# linter to go nuts.
-# pylint: disable=g-doc-bad-indent
-
-# Environment variable that controls whether to allow unparsed flag access.
-# Do not rely on, it will be removed later.
-_UNPARSED_FLAG_ACCESS_ENV_NAME = 'GFLAGS_ALLOW_UNPARSED_FLAG_ACCESS'
-
-# Percentage of the flag names for which unparsed flag access will fail by
-# default.
-_UNPARSED_ACCESS_DISABLED_PERCENT = 0
-
-# b/32278439 will change flag parsing to use GNU-style scanning by default.
-# This environment variable allows users to force setting the default parsing
-# style. Do NOT rely on it. It will be removed as part of b/32278439.
-_USE_GNU_GET_OPT_ENV_NAME = 'GFLAGS_USE_GNU_GET_OPT'
-
-
-
-
-class FlagValues(object):
- """Registry of 'Flag' objects.
-
- A 'FlagValues' can then scan command line arguments, passing flag
- arguments through to the 'Flag' objects that it owns. It also
- provides easy access to the flag values. Typically only one
- 'FlagValues' object is needed by an application: gflags.FLAGS
-
- This class is heavily overloaded:
-
- 'Flag' objects are registered via __setitem__:
- FLAGS['longname'] = x # register a new flag
-
- The .value attribute of the registered 'Flag' objects can be accessed
- as attributes of this 'FlagValues' object, through __getattr__. Both
- the long and short name of the original 'Flag' objects can be used to
- access its value:
- FLAGS.longname # parsed flag value
- FLAGS.x # parsed flag value (short name)
-
- Command line arguments are scanned and passed to the registered 'Flag'
- objects through the __call__ method. Unparsed arguments, including
- argv[0] (e.g. the program name) are returned.
- argv = FLAGS(sys.argv) # scan command line arguments
-
- The original registered Flag objects can be retrieved through the use
- of the dictionary-like operator, __getitem__:
- x = FLAGS['longname'] # access the registered Flag object
-
- The str() operator of a 'FlagValues' object provides help for all of
- the registered 'Flag' objects.
- """
-
- def __init__(self):
- # Since everything in this class is so heavily overloaded, the only
- # way of defining and using fields is to access __dict__ directly.
-
- # Dictionary: flag name (string) -> Flag object.
- self.__dict__['__flags'] = {}
-
- # Set: name of hidden flag (string).
- # Holds flags that should not be directly accessible from Python.
- self.__dict__['__hiddenflags'] = set()
-
- # Dictionary: module name (string) -> list of Flag objects that are defined
- # by that module.
- self.__dict__['__flags_by_module'] = {}
- # Dictionary: module id (int) -> list of Flag objects that are defined by
- # that module.
- self.__dict__['__flags_by_module_id'] = {}
- # Dictionary: module name (string) -> list of Flag objects that are
- # key for that module.
- self.__dict__['__key_flags_by_module'] = {}
-
- # Bool: True if flags were parsed.
- self.__dict__['__flags_parsed'] = False
-
- # Bool: True if Reset() was called.
- self.__dict__['__reset_called'] = False
-
- # None or Method(name, value) to call from __setattr__ for an unknown flag.
- self.__dict__['__set_unknown'] = None
-
- if _USE_GNU_GET_OPT_ENV_NAME in os.environ:
- self.__dict__['__use_gnu_getopt'] = (
- os.environ[_USE_GNU_GET_OPT_ENV_NAME] == '1')
- else:
- # By default don't use the GNU-style scanning when parsing the args.
- self.__dict__['__use_gnu_getopt'] = False
-
- def UseGnuGetOpt(self, use_gnu_getopt=True):
- """Use GNU-style scanning. Allows mixing of flag and non-flag arguments.
-
- See http://docs.python.org/library/getopt.html#getopt.gnu_getopt
-
- Args:
- use_gnu_getopt: wether or not to use GNU style scanning.
- """
- self.__dict__['__use_gnu_getopt'] = use_gnu_getopt
-
- def IsGnuGetOpt(self):
- return self.__dict__['__use_gnu_getopt']
-
- def FlagDict(self):
- return self.__dict__['__flags']
-
- def FlagsByModuleDict(self):
- """Returns the dictionary of module_name -> list of defined flags.
-
- Returns:
- A dictionary. Its keys are module names (strings). Its values
- are lists of Flag objects.
- """
- return self.__dict__['__flags_by_module']
-
- def FlagsByModuleIdDict(self):
- """Returns the dictionary of module_id -> list of defined flags.
-
- Returns:
- A dictionary. Its keys are module IDs (ints). Its values
- are lists of Flag objects.
- """
- return self.__dict__['__flags_by_module_id']
-
- def KeyFlagsByModuleDict(self):
- """Returns the dictionary of module_name -> list of key flags.
-
- Returns:
- A dictionary. Its keys are module names (strings). Its values
- are lists of Flag objects.
- """
- return self.__dict__['__key_flags_by_module']
-
- def _RegisterFlagByModule(self, module_name, flag):
- """Records the module that defines a specific flag.
-
- We keep track of which flag is defined by which module so that we
- can later sort the flags by module.
-
- Args:
- module_name: A string, the name of a Python module.
- flag: A Flag object, a flag that is key to the module.
- """
- flags_by_module = self.FlagsByModuleDict()
- flags_by_module.setdefault(module_name, []).append(flag)
-
- def _RegisterFlagByModuleId(self, module_id, flag):
- """Records the module that defines a specific flag.
-
- Args:
- module_id: An int, the ID of the Python module.
- flag: A Flag object, a flag that is key to the module.
- """
- flags_by_module_id = self.FlagsByModuleIdDict()
- flags_by_module_id.setdefault(module_id, []).append(flag)
-
- def _RegisterKeyFlagForModule(self, module_name, flag):
- """Specifies that a flag is a key flag for a module.
-
- Args:
- module_name: A string, the name of a Python module.
- flag: A Flag object, a flag that is key to the module.
- """
- key_flags_by_module = self.KeyFlagsByModuleDict()
- # The list of key flags for the module named module_name.
- key_flags = key_flags_by_module.setdefault(module_name, [])
- # Add flag, but avoid duplicates.
- if flag not in key_flags:
- key_flags.append(flag)
-
- def _FlagIsRegistered(self, flag_obj):
- """Checks whether a Flag object is registered under long name or short name.
-
- Args:
- flag_obj: A Flag object.
-
- Returns:
- A boolean: True iff flag_obj is registered under long name or short name.
- """
- flag_dict = self.FlagDict()
- # Check whether flag_obj is registered under its long name.
- name = flag_obj.name
- if flag_dict.get(name, None) == flag_obj:
- return True
- # Check whether flag_obj is registered under its short name.
- short_name = flag_obj.short_name
- if (short_name is not None and
- flag_dict.get(short_name, None) == flag_obj):
- return True
- return False
-
- def _CleanupUnregisteredFlagFromModuleDicts(self, flag_obj):
- """Cleanup unregistered flags from all module -> [flags] dictionaries.
-
- If flag_obj is registered under either its long name or short name, it
- won't be removed from the dictionaries.
-
- Args:
- flag_obj: A flag object.
- """
- if self._FlagIsRegistered(flag_obj):
- return
- for flags_by_module_dict in (self.FlagsByModuleDict(),
- self.FlagsByModuleIdDict(),
- self.KeyFlagsByModuleDict()):
- for flags_in_module in six.itervalues(flags_by_module_dict):
- # While (as opposed to if) takes care of multiple occurrences of a
- # flag in the list for the same module.
- while flag_obj in flags_in_module:
- flags_in_module.remove(flag_obj)
-
- def _GetFlagsDefinedByModule(self, module):
- """Returns the list of flags defined by a module.
-
- Args:
- module: A module object or a module name (a string).
-
- Returns:
- A new list of Flag objects. Caller may update this list as he
- wishes: none of those changes will affect the internals of this
- FlagValue object.
- """
- if not isinstance(module, str):
- module = module.__name__
-
- return list(self.FlagsByModuleDict().get(module, []))
-
- def _GetKeyFlagsForModule(self, module):
- """Returns the list of key flags for a module.
-
- Args:
- module: A module object or a module name (a string)
-
- Returns:
- A new list of Flag objects. Caller may update this list as he
- wishes: none of those changes will affect the internals of this
- FlagValue object.
- """
- if not isinstance(module, str):
- module = module.__name__
-
- # Any flag is a key flag for the module that defined it. NOTE:
- # key_flags is a fresh list: we can update it without affecting the
- # internals of this FlagValues object.
- key_flags = self._GetFlagsDefinedByModule(module)
-
- # Take into account flags explicitly declared as key for a module.
- for flag in self.KeyFlagsByModuleDict().get(module, []):
- if flag not in key_flags:
- key_flags.append(flag)
- return key_flags
-
- def FindModuleDefiningFlag(self, flagname, default=None):
- """Return the name of the module defining this flag, or default.
-
- Args:
- flagname: Name of the flag to lookup.
- default: Value to return if flagname is not defined. Defaults
- to None.
-
- Returns:
- The name of the module which registered the flag with this name.
- If no such module exists (i.e. no flag with this name exists),
- we return default.
- """
- registered_flag = self.FlagDict().get(flagname)
- if registered_flag is None:
- return default
- for module, flags in six.iteritems(self.FlagsByModuleDict()):
- for flag in flags:
- # It must compare the flag with the one in FlagDict. This is because a
- # flag might be overridden only for its long name (or short name),
- # and only its short name (or long name) is considered registered.
- if (flag.name == registered_flag.name and
- flag.short_name == registered_flag.short_name):
- return module
- return default
-
- def FindModuleIdDefiningFlag(self, flagname, default=None):
- """Return the ID of the module defining this flag, or default.
-
- Args:
- flagname: Name of the flag to lookup.
- default: Value to return if flagname is not defined. Defaults
- to None.
-
- Returns:
- The ID of the module which registered the flag with this name.
- If no such module exists (i.e. no flag with this name exists),
- we return default.
- """
- registered_flag = self.FlagDict().get(flagname)
- if registered_flag is None:
- return default
- for module_id, flags in six.iteritems(self.FlagsByModuleIdDict()):
- for flag in flags:
- # It must compare the flag with the one in FlagDict. This is because a
- # flag might be overridden only for its long name (or short name),
- # and only its short name (or long name) is considered registered.
- if (flag.name == registered_flag.name and
- flag.short_name == registered_flag.short_name):
- return module_id
- return default
-
- def _RegisterUnknownFlagSetter(self, setter):
- """Allow set default values for undefined flags.
-
- Args:
- setter: Method(name, value) to call to __setattr__ an unknown flag.
- Must raise NameError or ValueError for invalid name/value.
- """
- self.__dict__['__set_unknown'] = setter
-
- def _SetUnknownFlag(self, name, value):
- """Returns value if setting flag |name| to |value| returned True.
-
- Args:
- name: Name of the flag to set.
- value: Value to set.
-
- Returns:
- Flag value on successful call.
-
- Raises:
- UnrecognizedFlagError
- IllegalFlagValueError
- """
- setter = self.__dict__['__set_unknown']
- if setter:
- try:
- setter(name, value)
- return value
- except (TypeError, ValueError): # Flag value is not valid.
- raise exceptions.IllegalFlagValueError('"{1}" is not valid for --{0}'
- .format(name, value))
- except NameError: # Flag name is not valid.
- pass
- raise exceptions.UnrecognizedFlagError(name, value)
-
- def AppendFlagValues(self, flag_values):
- """Appends flags registered in another FlagValues instance.
-
- Args:
- flag_values: registry to copy from
- """
- for flag_name, flag in six.iteritems(flag_values.FlagDict()):
- # Each flags with shortname appears here twice (once under its
- # normal name, and again with its short name). To prevent
- # problems (DuplicateFlagError) with double flag registration, we
- # perform a check to make sure that the entry we're looking at is
- # for its normal name.
- if flag_name == flag.name:
- try:
- self[flag_name] = flag
- except exceptions.DuplicateFlagError:
- raise exceptions.DuplicateFlagError.from_flag(
- flag_name, self, other_flag_values=flag_values)
-
- def RemoveFlagValues(self, flag_values):
- """Remove flags that were previously appended from another FlagValues.
-
- Args:
- flag_values: registry containing flags to remove.
- """
- for flag_name in flag_values.FlagDict():
- self.__delattr__(flag_name)
-
- def __setitem__(self, name, flag):
- """Registers a new flag variable."""
- fl = self.FlagDict()
- if not isinstance(flag, _flag.Flag):
- raise exceptions.IllegalFlagValueError(flag)
- if str is bytes and isinstance(name, unicode):
- # When using Python 2 with unicode_literals, allow it but encode it
- # into the bytes type we require.
- name = name.encode('utf-8')
- if not isinstance(name, type('')):
- raise exceptions.Error('Flag name must be a string')
- if not name:
- raise exceptions.Error('Flag name cannot be empty')
- if name in fl and not flag.allow_override and not fl[name].allow_override:
- module, module_name = _helpers.GetCallingModuleObjectAndName()
- if (self.FindModuleDefiningFlag(name) == module_name and
- id(module) != self.FindModuleIdDefiningFlag(name)):
- # If the flag has already been defined by a module with the same name,
- # but a different ID, we can stop here because it indicates that the
- # module is simply being imported a subsequent time.
- return
- raise exceptions.DuplicateFlagError.from_flag(name, self)
- short_name = flag.short_name
- # If a new flag overrides an old one, we need to cleanup the old flag's
- # modules if it's not registered.
- flags_to_cleanup = set()
- if short_name is not None:
- if (short_name in fl and not flag.allow_override and
- not fl[short_name].allow_override):
- raise exceptions.DuplicateFlagError.from_flag(short_name, self)
- if short_name in fl and fl[short_name] != flag:
- flags_to_cleanup.add(fl[short_name])
- fl[short_name] = flag
- if (name not in fl # new flag
- or fl[name].using_default_value
- or not flag.using_default_value):
- if name in fl and fl[name] != flag:
- flags_to_cleanup.add(fl[name])
- fl[name] = flag
- for f in flags_to_cleanup:
- self._CleanupUnregisteredFlagFromModuleDicts(f)
-
- def __dir__(self):
- """Returns list of names of all defined flags.
-
- Useful for TAB-completion in ipython.
-
- Returns:
- list(str)
- """
- return sorted(self.__dict__['__flags'])
-
- # TODO(olexiy): Call GetFlag() to raise UnrecognizedFlagError if name is
- # unknown.
- def __getitem__(self, name):
- """Retrieves the Flag object for the flag --name."""
- return self.FlagDict()[name]
-
- def GetFlag(self, name):
- """Same as __getitem__, but raises a specific error."""
- res = self.FlagDict().get(name)
- if res is None:
- raise exceptions.UnrecognizedFlagError(name)
- return res
-
- def HideFlag(self, name):
- """Mark the flag --name as hidden."""
- self.__dict__['__hiddenflags'].add(name)
-
- def _IsUnparsedFlagAccessAllowed(self, name):
- """Determine whether to allow unparsed flag access or not."""
- if _UNPARSED_FLAG_ACCESS_ENV_NAME in os.environ:
- # We've been told explicitly what to do.
- allow_unparsed_flag_access = (
- os.getenv(_UNPARSED_FLAG_ACCESS_ENV_NAME) == '1')
- elif self.__dict__['__reset_called']:
- # Raise exception if .Reset() was called. This mostly happens in tests.
- allow_unparsed_flag_access = False
- elif _helpers.IsRunningTest():
- # Staged "rollout", based on name of the flag so that we don't break
- # everyone. Hashing the flag is a way of choosing a random but
- # consistent subset of flags to lock down which we can make larger
- # over time.
- name_bytes = name.encode('utf8') if not isinstance(name, bytes) else name
- flag_percentile = (
- struct.unpack('<I', hashlib.md5(name_bytes).digest()[:4])[0] % 100)
- allow_unparsed_flag_access = (
- _UNPARSED_ACCESS_DISABLED_PERCENT <= flag_percentile)
- else:
- allow_unparsed_flag_access = True
- return allow_unparsed_flag_access
-
- def __getattr__(self, name):
- """Retrieves the 'value' attribute of the flag --name."""
- fl = self.FlagDict()
- if name not in fl:
- raise AttributeError(name)
- if name in self.__dict__['__hiddenflags']:
- raise AttributeError(name)
-
- if self.__dict__['__flags_parsed'] or fl[name].present:
- return fl[name].value
- else:
- error_message = (
- 'Trying to access flag %s before flags were parsed.' % name)
- if self._IsUnparsedFlagAccessAllowed(name):
- # Print warning to stderr. Messages in logs are often ignored/unnoticed.
- warnings.warn(
- error_message + ' This will raise an exception in the future.',
- RuntimeWarning,
- stacklevel=2)
- # Force logging.exception() to behave realistically, but don't propagate
- # exception up. Allow flag value to be returned (for now).
- try:
- raise exceptions.UnparsedFlagAccessError(error_message)
- except exceptions.UnparsedFlagAccessError:
- logging.exception(error_message)
- return fl[name].value
- else:
- raise exceptions.UnparsedFlagAccessError(error_message)
-
- def __setattr__(self, name, value):
- """Sets the 'value' attribute of the flag --name."""
- fl = self.FlagDict()
- if name in self.__dict__['__hiddenflags']:
- raise AttributeError(name)
- if name not in fl:
- return self._SetUnknownFlag(name, value)
- fl[name].value = value
- self._AssertValidators(fl[name].validators)
- fl[name].using_default_value = False
- return value
-
- def _AssertAllValidators(self):
- all_validators = set()
- for flag in six.itervalues(self.FlagDict()):
- for validator in flag.validators:
- all_validators.add(validator)
- self._AssertValidators(all_validators)
-
- def _AssertValidators(self, validators):
- """Assert if all validators in the list are satisfied.
-
- Asserts validators in the order they were created.
- Args:
- validators: Iterable(validators.Validator), validators to be
- verified
- Raises:
- AttributeError: if validators work with a non-existing flag.
- IllegalFlagValueError: if validation fails for at least one validator
- """
- for validator in sorted(
- validators, key=lambda validator: validator.insertion_index):
- try:
- validator.verify(self)
- except exceptions.ValidationError as e:
- message = validator.print_flags_with_values(self)
- raise exceptions.IllegalFlagValueError('%s: %s' % (message, str(e)))
-
- def __delattr__(self, flag_name):
- """Deletes a previously-defined flag from a flag object.
-
- This method makes sure we can delete a flag by using
-
- del FLAGS.<flag_name>
-
- E.g.,
-
- gflags.DEFINE_integer('foo', 1, 'Integer flag.')
- del gflags.FLAGS.foo
-
- If a flag is also registered by its the other name (long name or short
- name), the other name won't be deleted.
-
- Args:
- flag_name: A string, the name of the flag to be deleted.
-
- Raises:
- AttributeError: When there is no registered flag named flag_name.
- """
- fl = self.FlagDict()
- if flag_name not in fl:
- raise AttributeError(flag_name)
-
- flag_obj = fl[flag_name]
- del fl[flag_name]
-
- self._CleanupUnregisteredFlagFromModuleDicts(flag_obj)
-
- def _RemoveAllFlagAppearances(self, name):
- """Removes flag with name for all appearances.
-
- A flag can be registered with its long name and an optional short name.
- This method removes both of them. This is different than __delattr__.
-
- Args:
- name: Either flag's long name or short name.
-
- Raises:
- UnrecognizedFlagError: When flag name is not found.
- """
- flag_dict = self.FlagDict()
- if name not in flag_dict:
- raise exceptions.UnrecognizedFlagError(name)
- flag = flag_dict[name]
- names_to_remove = {name}
- names_to_remove.add(flag.name)
- if flag.short_name:
- names_to_remove.add(flag.short_name)
- for n in names_to_remove:
- self.__delattr__(n)
-
- def SetDefault(self, name, value):
- """Changes the default value (and current value) of the named flag object.
-
- Call this method at the top level of a module to avoid overwriting the value
- passed at the command line.
-
- Args:
- name: A string, the name of the flag to modify.
- value: The new default value.
-
- Raises:
- UnrecognizedFlagError: When there is no registered flag named name.
- IllegalFlagValueError: When value is not valid.
- """
- fl = self.FlagDict()
- if name not in fl:
- self._SetUnknownFlag(name, value)
- return
- if self.IsParsed():
- logging.warn(
- 'FLAGS.SetDefault called on flag "%s" after flag parsing. Call this '
- 'method at the top level of a module to avoid overwriting the value '
- 'passed at the command line.',
- name)
- fl[name]._set_default(value) # pylint: disable=protected-access
- self._AssertValidators(fl[name].validators)
-
- def __contains__(self, name):
- """Returns True if name is a value (flag) in the dict."""
- return name in self.FlagDict()
-
- has_key = __contains__ # a synonym for __contains__()
-
- def __iter__(self):
- return iter(self.FlagDict())
-
- def __call__(self, argv, known_only=False):
- """Parses flags from argv; stores parsed flags into this FlagValues object.
-
- All unparsed arguments are returned.
-
- Args:
- argv: argument list. Can be of any type that may be converted to a list.
- known_only: parse and remove known flags, return rest untouched.
-
- Returns:
- The list of arguments not parsed as options, including argv[0].
-
- Raises:
- Error: on any parsing error.
- ValueError: on flag value parsing error.
- """
- if not argv:
- # Unfortunately, the old parser used to accept an empty argv, and some
- # users rely on that behaviour. Allow it as a special case for now.
- self.MarkAsParsed()
- self._AssertAllValidators()
- return []
-
- # This pre parses the argv list for --flagfile=<> options.
- program_name = argv[0]
- args = self.ReadFlagsFromFiles(argv[1:], force_gnu=False)
-
- # Parse the arguments.
- unknown_flags, unparsed_args, undefok = self._ParseArgs(args, known_only)
-
- # Handle unknown flags by raising UnrecognizedFlagError.
- # Note some users depend on us raising this particular error.
- for name, value in unknown_flags:
- if name in undefok:
- continue
-
- suggestions = _helpers.GetFlagSuggestions(
- name, self.RegisteredFlags())
- raise exceptions.UnrecognizedFlagError(
- name, value, suggestions=suggestions)
-
- self.MarkAsParsed()
- self._AssertAllValidators()
- return [program_name] + unparsed_args
-
- def _ParseArgs(self, args, known_only):
- """Helper function to do the main argument parsing.
-
- This function goes through args and does the bulk of the flag parsing.
- It will find the corresponding flag in our flag dictionary, and call its
- .parse() method on the flag value.
-
- Args:
- args: List of strings with the arguments to parse.
- known_only: parse and remove known flags, return rest in unparsed_args
-
- Returns:
- A tuple with the following:
- unknown_flags: List of (flag name, arg) for flags we don't know about.
- unparsed_args: List of arguments we did not parse.
- undefok: Set of flags that were given via --undefok.
-
- Raises:
- Error: on any parsing error.
- ValueError: on flag value parsing error.
- """
- unknown_flags, unparsed_args, undefok = [], [], set()
-
- flag_dict = self.FlagDict()
- args = iter(args)
- for arg in args:
- value = None
-
- def GetValue():
- # pylint: disable=cell-var-from-loop
- try:
- return next(args) if value is None else value
- except StopIteration:
- raise exceptions.Error('Missing value for flag ' + arg)
-
- if not arg.startswith('-'):
- # A non-argument: default is break, GNU is skip.
- unparsed_args.append(arg)
- if self.IsGnuGetOpt():
- continue
- else:
- break
-
- if arg == '--':
- if known_only:
- unparsed_args.append(arg)
- break
-
- if '=' in arg:
- name, value = arg.lstrip('-').split('=', 1)
- else:
- name, value = arg.lstrip('-'), None
-
- if not name:
- # The argument is all dashes (including one dash).
- unparsed_args.append(arg)
- if self.IsGnuGetOpt():
- continue
- else:
- break
-
- # --undefok is a special case.
- if name == 'undefok':
- if known_only:
- unparsed_args.append(arg)
- value = GetValue()
- undefok.update(v.strip() for v in value.split(','))
- undefok.update('no' + v.strip() for v in value.split(','))
- continue
-
- flag = flag_dict.get(name)
- if flag:
- value = (flag.boolean and value is None) or GetValue()
- elif name.startswith('no') and len(name) > 2:
- # Boolean flags can take the form of --noflag, with no value.
- noflag = flag_dict.get(name[2:])
- if noflag and noflag.boolean:
- if value is not None:
- raise ValueError(arg + ' does not take an argument')
- flag = noflag
- value = False
-
-
- if flag:
- flag.parse(value)
- flag.using_default_value = False
- elif known_only:
- unparsed_args.append(arg)
- else:
- unknown_flags.append((name, arg))
-
- unparsed_args.extend(args)
- return unknown_flags, unparsed_args, undefok
-
- def IsParsed(self):
- """Whether flags were parsed."""
- return self.__dict__['__flags_parsed']
-
- def MarkAsParsed(self):
- """Explicitly mark parsed.
-
- Use this when the caller knows that this FlagValues has been parsed as if
- a __call__() invocation has happened. This is only a public method for
- use by things like appcommands which do additional command like parsing.
- """
- self.__dict__['__flags_parsed'] = True
-
- def Reset(self):
- """Resets the values to the point before FLAGS(argv) was called."""
- for f in self.FlagDict().values():
- f.unparse()
- # We log this message before marking flags as unparsed to avoid a
- # problem when the logging library causes flags access.
- logging.info('Reset() called; flags access will now raise errors.')
- self.__dict__['__flags_parsed'] = False
- self.__dict__['__reset_called'] = True
-
- def RegisteredFlags(self):
- """Returns: a list of the names and short names of all registered flags."""
- return list(self.FlagDict())
-
- def FlagValuesDict(self):
- """Returns: a dictionary that maps flag names to flag values."""
- flag_values = {}
-
- for flag_name in self.RegisteredFlags():
- flag = self.FlagDict()[flag_name]
- flag_values[flag_name] = flag.value
-
- return flag_values
-
- def __str__(self):
- """Generates a help string for all known flags."""
- return self.GetHelp()
-
- def GetHelp(self, prefix='', include_special_flags=True):
- """Generates a help string for all known flags.
-
- Args:
- prefix: str, per-line output prefix.
- include_special_flags: bool, whether to include description of
- _SPECIAL_FLAGS, i.e. --flagfile and --undefok.
-
- Returns:
- str, formatted help message.
- """
- # TODO(vrusinov): this function needs a test.
- helplist = []
-
- flags_by_module = self.FlagsByModuleDict()
- if flags_by_module:
- modules = sorted(flags_by_module)
-
- # Print the help for the main module first, if possible.
- main_module = sys.argv[0]
- if main_module in modules:
- modules.remove(main_module)
- modules = [main_module] + modules
-
- for module in modules:
- self.__RenderOurModuleFlags(module, helplist)
- if include_special_flags:
- self.__RenderModuleFlags('gflags',
- _helpers.SPECIAL_FLAGS.FlagDict().values(),
- helplist)
- else:
- # Just print one long list of flags.
- values = self.FlagDict().values()
- if include_special_flags:
- values.append(_helpers.SPECIAL_FLAGS.FlagDict().values())
- self.__RenderFlagList(values, helplist, prefix)
-
- return '\n'.join(helplist)
-
- def __RenderModuleFlags(self, module, flags, output_lines, prefix=''):
- """Generates a help string for a given module."""
- if not isinstance(module, str):
- module = module.__name__
- output_lines.append('\n%s%s:' % (prefix, module))
- self.__RenderFlagList(flags, output_lines, prefix + ' ')
-
- def __RenderOurModuleFlags(self, module, output_lines, prefix=''):
- """Generates a help string for a given module."""
- flags = self._GetFlagsDefinedByModule(module)
- if flags:
- self.__RenderModuleFlags(module, flags, output_lines, prefix)
-
- def __RenderOurModuleKeyFlags(self, module, output_lines, prefix=''):
- """Generates a help string for the key flags of a given module.
-
- Args:
- module: A module object or a module name (a string).
- output_lines: A list of strings. The generated help message
- lines will be appended to this list.
- prefix: A string that is prepended to each generated help line.
- """
- key_flags = self._GetKeyFlagsForModule(module)
- if key_flags:
- self.__RenderModuleFlags(module, key_flags, output_lines, prefix)
-
- def ModuleHelp(self, module):
- """Describe the key flags of a module.
-
- Args:
- module: A module object or a module name (a string).
-
- Returns:
- string describing the key flags of a module.
- """
- helplist = []
- self.__RenderOurModuleKeyFlags(module, helplist)
- return '\n'.join(helplist)
-
- def MainModuleHelp(self):
- """Describe the key flags of the main module.
-
- Returns:
- string describing the key flags of a module.
- """
- return self.ModuleHelp(sys.argv[0])
-
- def __RenderFlagList(self, flaglist, output_lines, prefix=' '):
- fl = self.FlagDict()
- special_fl = _helpers.SPECIAL_FLAGS.FlagDict()
- flaglist = [(flag.name, flag) for flag in flaglist]
- flaglist.sort()
- flagset = {}
- for (name, flag) in flaglist:
- # It's possible this flag got deleted or overridden since being
- # registered in the per-module flaglist. Check now against the
- # canonical source of current flag information, the FlagDict.
- if fl.get(name, None) != flag and special_fl.get(name, None) != flag:
- # a different flag is using this name now
- continue
- # only print help once
- if flag in flagset: continue
- flagset[flag] = 1
- flaghelp = ''
- if flag.short_name: flaghelp += '-%s,' % flag.short_name
- if flag.boolean:
- flaghelp += '--[no]%s:' % flag.name
- else:
- flaghelp += '--%s:' % flag.name
- flaghelp += ' '
- if flag.help:
- flaghelp += flag.help
- flaghelp = _helpers.TextWrap(
- flaghelp, indent=prefix+' ', firstline_indent=prefix)
- if flag.default_as_str:
- flaghelp += '\n'
- flaghelp += _helpers.TextWrap(
- '(default: %s)' % flag.default_as_str, indent=prefix+' ')
- if flag.parser.syntactic_help:
- flaghelp += '\n'
- flaghelp += _helpers.TextWrap(
- '(%s)' % flag.parser.syntactic_help, indent=prefix+' ')
- output_lines.append(flaghelp)
-
- def get_flag_value(self, name, default): # pylint: disable=invalid-name
- """Returns the value of a flag (if not None) or a default value.
-
- Args:
- name: A string, the name of a flag.
- default: Default value to use if the flag value is None.
-
- Returns:
- Requested flag value or default.
- """
-
- value = self.__getattr__(name)
- if value is not None: # Can't do if not value, b/c value might be '0' or ""
- return value
- else:
- return default
-
- # TODO(b/32098517): Remove this.
- get = get_flag_value
-
- def __IsFlagFileDirective(self, flag_string):
- """Checks whether flag_string contain a --flagfile=<foo> directive."""
- if isinstance(flag_string, type('')):
- if flag_string.startswith('--flagfile='):
- return 1
- elif flag_string == '--flagfile':
- return 1
- elif flag_string.startswith('-flagfile='):
- return 1
- elif flag_string == '-flagfile':
- return 1
- else:
- return 0
- return 0
-
- def ExtractFilename(self, flagfile_str):
- """Returns filename from a flagfile_str of form -[-]flagfile=filename.
-
- The cases of --flagfile foo and -flagfile foo shouldn't be hitting
- this function, as they are dealt with in the level above this
- function.
-
- Args:
- flagfile_str: flagfile string.
-
- Returns:
- str filename from a flagfile_str of form -[-]flagfile=filename.
-
- Raises:
- Error: when illegal --flagfile provided.
- """
- if flagfile_str.startswith('--flagfile='):
- return os.path.expanduser((flagfile_str[(len('--flagfile=')):]).strip())
- elif flagfile_str.startswith('-flagfile='):
- return os.path.expanduser((flagfile_str[(len('-flagfile=')):]).strip())
- else:
- raise exceptions.Error(
- 'Hit illegal --flagfile type: %s' % flagfile_str)
-
- def __GetFlagFileLines(self, filename, parsed_file_stack=None):
- """Returns the useful (!=comments, etc) lines from a file with flags.
-
- Args:
- filename: A string, the name of the flag file.
- parsed_file_stack: A list of the names of the files that we have
- recursively encountered at the current depth. MUTATED BY THIS FUNCTION
- (but the original value is preserved upon successfully returning from
- function call).
-
- Returns:
- List of strings. See the note below.
-
- NOTE(springer): This function checks for a nested --flagfile=<foo>
- tag and handles the lower file recursively. It returns a list of
- all the lines that _could_ contain command flags. This is
- EVERYTHING except whitespace lines and comments (lines starting
- with '#' or '//').
- """
- if parsed_file_stack is None:
- parsed_file_stack = []
- # We do a little safety check for reparsing a file we've already encountered
- # at a previous depth.
- if filename in parsed_file_stack:
- sys.stderr.write('Warning: Hit circular flagfile dependency. Ignoring'
- ' flagfile: %s\n' % (filename,))
- return []
- else:
- parsed_file_stack.append(filename)
-
- line_list = [] # All line from flagfile.
- flag_line_list = [] # Subset of lines w/o comments, blanks, flagfile= tags.
- try:
- file_obj = open(filename, 'r')
- except IOError as e_msg:
- raise exceptions.CantOpenFlagFileError(
- 'ERROR:: Unable to open flagfile: %s' % e_msg)
-
- with file_obj:
- line_list = file_obj.readlines()
-
- # This is where we check each line in the file we just read.
- for line in line_list:
- if line.isspace():
- pass
- # Checks for comment (a line that starts with '#').
- elif line.startswith('#') or line.startswith('//'):
- pass
- # Checks for a nested "--flagfile=<bar>" flag in the current file.
- # If we find one, recursively parse down into that file.
- elif self.__IsFlagFileDirective(line):
- sub_filename = self.ExtractFilename(line)
- included_flags = self.__GetFlagFileLines(
- sub_filename, parsed_file_stack=parsed_file_stack)
- flag_line_list.extend(included_flags)
- else:
- # Any line that's not a comment or a nested flagfile should get
- # copied into 2nd position. This leaves earlier arguments
- # further back in the list, thus giving them higher priority.
- flag_line_list.append(line.strip())
-
- parsed_file_stack.pop()
- return flag_line_list
-
- def ReadFlagsFromFiles(self, argv, force_gnu=True):
- """Processes command line args, but also allow args to be read from file.
-
- Args:
- argv: A list of strings, usually sys.argv[1:], which may contain one or
- more flagfile directives of the form --flagfile="./filename".
- Note that the name of the program (sys.argv[0]) should be omitted.
- force_gnu: If False, --flagfile parsing obeys normal flag semantics.
- If True, --flagfile parsing instead follows gnu_getopt semantics.
- *** WARNING *** force_gnu=False may become the future default!
-
- Returns:
- A new list which has the original list combined with what we read
- from any flagfile(s).
-
- Raises:
- IllegalFlagValueError: when --flagfile provided with no argument.
-
- References: Global gflags.FLAG class instance.
-
- This function should be called before the normal FLAGS(argv) call.
- This function scans the input list for a flag that looks like:
- --flagfile=<somefile>. Then it opens <somefile>, reads all valid key
- and value pairs and inserts them into the input list in exactly the
- place where the --flagfile arg is found.
-
- Note that your application's flags are still defined the usual way
- using gflags DEFINE_flag() type functions.
-
- Notes (assuming we're getting a commandline of some sort as our input):
- --> For duplicate flags, the last one we hit should "win".
- --> Since flags that appear later win, a flagfile's settings can be "weak"
- if the --flagfile comes at the beginning of the argument sequence,
- and it can be "strong" if the --flagfile comes at the end.
- --> A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile.
- It will be expanded in exactly the spot where it is found.
- --> In a flagfile, a line beginning with # or // is a comment.
- --> Entirely blank lines _should_ be ignored.
- """
- rest_of_args = argv
- new_argv = []
- while rest_of_args:
- current_arg = rest_of_args[0]
- rest_of_args = rest_of_args[1:]
- if self.__IsFlagFileDirective(current_arg):
- # This handles the case of -(-)flagfile foo. In this case the
- # next arg really is part of this one.
- if current_arg == '--flagfile' or current_arg == '-flagfile':
- if not rest_of_args:
- raise exceptions.IllegalFlagValueError(
- '--flagfile with no argument')
- flag_filename = os.path.expanduser(rest_of_args[0])
- rest_of_args = rest_of_args[1:]
- else:
- # This handles the case of (-)-flagfile=foo.
- flag_filename = self.ExtractFilename(current_arg)
- new_argv.extend(self.__GetFlagFileLines(flag_filename))
- else:
- new_argv.append(current_arg)
- # Stop parsing after '--', like getopt and gnu_getopt.
- if current_arg == '--':
- break
- # Stop parsing after a non-flag, like getopt.
- if not current_arg.startswith('-'):
- if not force_gnu and not self.__dict__['__use_gnu_getopt']:
- break
- else:
- if ('=' not in current_arg and
- rest_of_args and not rest_of_args[0].startswith('-')):
- # If this is an occurence of a legitimate --x y, skip the value
- # so that it won't be mistaken for a standalone arg.
- fl = self.FlagDict()
- name = current_arg.lstrip('-')
- if name in fl and not fl[name].boolean:
- current_arg = rest_of_args[0]
- rest_of_args = rest_of_args[1:]
- new_argv.append(current_arg)
-
- if rest_of_args:
- new_argv.extend(rest_of_args)
-
- return new_argv
-
- def FlagsIntoString(self):
- """Returns a string with the flags assignments from this FlagValues object.
-
- This function ignores flags whose value is None. Each flag
- assignment is separated by a newline.
-
- NOTE: MUST mirror the behavior of the C++ CommandlineFlagsIntoString
- from http://code.google.com/p/google-gflags
-
- Returns:
- string with the flags assignments from this FlagValues object.
- """
- s = ''
- for flag in self.FlagDict().values():
- if flag.value is not None:
- s += flag.serialize() + '\n'
- return s
-
- def AppendFlagsIntoFile(self, filename):
- """Appends all flags assignments from this FlagInfo object to a file.
-
- Output will be in the format of a flagfile.
-
- NOTE: MUST mirror the behavior of the C++ AppendFlagsIntoFile
- from http://code.google.com/p/google-gflags
-
- Args:
- filename: string, name of the file.
- """
- with open(filename, 'a') as out_file:
- out_file.write(self.FlagsIntoString())
-
- def WriteHelpInXMLFormat(self, outfile=None):
- """Outputs flag documentation in XML format.
-
- NOTE: We use element names that are consistent with those used by
- the C++ command-line flag library, from
- http://code.google.com/p/google-gflags
- We also use a few new elements (e.g., <key>), but we do not
- interfere / overlap with existing XML elements used by the C++
- library. Please maintain this consistency.
-
- Args:
- outfile: File object we write to. Default None means sys.stdout.
- """
- doc = minidom.Document()
- all_flag = doc.createElement('AllFlags')
- doc.appendChild(all_flag)
-
- all_flag.appendChild(_helpers.CreateXMLDOMElement(
- doc, 'program', os.path.basename(sys.argv[0])))
-
- usage_doc = sys.modules['__main__'].__doc__
- if not usage_doc:
- usage_doc = '\nUSAGE: %s [flags]\n' % sys.argv[0]
- else:
- usage_doc = usage_doc.replace('%s', sys.argv[0])
- all_flag.appendChild(_helpers.CreateXMLDOMElement(doc, 'usage', usage_doc))
-
- # Get list of key flags for the main module.
- key_flags = self._GetKeyFlagsForModule(sys.argv[0])
-
- # Sort flags by declaring module name and next by flag name.
- flags_by_module = self.FlagsByModuleDict()
- all_module_names = list(flags_by_module.keys())
- all_module_names.sort()
- for module_name in all_module_names:
- flag_list = [(f.name, f) for f in flags_by_module[module_name]]
- flag_list.sort()
- for unused_flag_name, flag in flag_list:
- is_key = flag in key_flags
- all_flag.appendChild(flag._create_xml_dom_element( # pylint: disable=protected-access
- doc, module_name, is_key=is_key))
-
- outfile = outfile or sys.stdout
- if six.PY2:
- outfile.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
- else:
- outfile.write(
- doc.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8'))
- outfile.flush()
-
-
-_helpers.SPECIAL_FLAGS = FlagValues()