• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The Abseil Authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Defines the FlagValues class - registry of 'Flag' objects.
15
16Do NOT import this module directly. Import the flags package and use the
17aliases defined at the package level instead.
18"""
19
20import copy
21import itertools
22import logging
23import os
24import sys
25from typing import Generic, TypeVar
26from xml.dom import minidom
27
28from absl.flags import _exceptions
29from absl.flags import _flag
30from absl.flags import _helpers
31from absl.flags import _validators_classes
32
33# Add flagvalues module to disclaimed module ids.
34_helpers.disclaim_module_ids.add(id(sys.modules[__name__]))
35
36_T = TypeVar('_T')
37
38
39class FlagValues:
40  """Registry of :class:`~absl.flags.Flag` objects.
41
42  A :class:`FlagValues` can then scan command line arguments, passing flag
43  arguments through to the 'Flag' objects that it owns.  It also
44  provides easy access to the flag values.  Typically only one
45  :class:`FlagValues` object is needed by an application:
46  :const:`FLAGS`.
47
48  This class is heavily overloaded:
49
50  :class:`Flag` objects are registered via ``__setitem__``::
51
52       FLAGS['longname'] = x   # register a new flag
53
54  The ``.value`` attribute of the registered :class:`~absl.flags.Flag` objects
55  can be accessed as attributes of this :class:`FlagValues` object, through
56  ``__getattr__``.  Both the long and short name of the original
57  :class:`~absl.flags.Flag` objects can be used to access its value::
58
59       FLAGS.longname  # parsed flag value
60       FLAGS.x  # parsed flag value (short name)
61
62  Command line arguments are scanned and passed to the registered
63  :class:`~absl.flags.Flag` objects through the ``__call__`` method.  Unparsed
64  arguments, including ``argv[0]`` (e.g. the program name) are returned::
65
66       argv = FLAGS(sys.argv)  # scan command line arguments
67
68  The original registered :class:`~absl.flags.Flag` objects can be retrieved
69  through the use of the dictionary-like operator, ``__getitem__``::
70
71       x = FLAGS['longname']   # access the registered Flag object
72
73  The ``str()`` operator of a :class:`absl.flags.FlagValues` object provides
74  help for all of the registered :class:`~absl.flags.Flag` objects.
75  """
76
77  # A note on collections.abc.Mapping:
78  # FlagValues defines __getitem__, __iter__, and __len__. It makes perfect
79  # sense to let it be a collections.abc.Mapping class. However, we are not
80  # able to do so. The mixin methods, e.g. keys, values, are not uncommon flag
81  # names. Those flag values would not be accessible via the FLAGS.xxx form.
82
83  def __init__(self):
84    # Since everything in this class is so heavily overloaded, the only
85    # way of defining and using fields is to access __dict__ directly.
86
87    # Dictionary: flag name (string) -> Flag object.
88    self.__dict__['__flags'] = {}
89
90    # Set: name of hidden flag (string).
91    # Holds flags that should not be directly accessible from Python.
92    self.__dict__['__hiddenflags'] = set()
93
94    # Dictionary: module name (string) -> list of Flag objects that are defined
95    # by that module.
96    self.__dict__['__flags_by_module'] = {}
97    # Dictionary: module id (int) -> list of Flag objects that are defined by
98    # that module.
99    self.__dict__['__flags_by_module_id'] = {}
100    # Dictionary: module name (string) -> list of Flag objects that are
101    # key for that module.
102    self.__dict__['__key_flags_by_module'] = {}
103
104    # Bool: True if flags were parsed.
105    self.__dict__['__flags_parsed'] = False
106
107    # Bool: True if unparse_flags() was called.
108    self.__dict__['__unparse_flags_called'] = False
109
110    # None or Method(name, value) to call from __setattr__ for an unknown flag.
111    self.__dict__['__set_unknown'] = None
112
113    # A set of banned flag names. This is to prevent users from accidentally
114    # defining a flag that has the same name as a method on this class.
115    # Users can still allow defining the flag by passing
116    # allow_using_method_names=True in DEFINE_xxx functions.
117    self.__dict__['__banned_flag_names'] = frozenset(dir(FlagValues))
118
119    # Bool: Whether to use GNU style scanning.
120    self.__dict__['__use_gnu_getopt'] = True
121
122    # Bool: Whether use_gnu_getopt has been explicitly set by the user.
123    self.__dict__['__use_gnu_getopt_explicitly_set'] = False
124
125    # Function: Takes a flag name as parameter, returns a tuple
126    # (is_retired, type_is_bool).
127    self.__dict__['__is_retired_flag_func'] = None
128
129  def set_gnu_getopt(self, gnu_getopt=True):
130    """Sets whether or not to use GNU style scanning.
131
132    GNU style allows mixing of flag and non-flag arguments. See
133    http://docs.python.org/library/getopt.html#getopt.gnu_getopt
134
135    Args:
136      gnu_getopt: bool, whether or not to use GNU style scanning.
137    """
138    self.__dict__['__use_gnu_getopt'] = gnu_getopt
139    self.__dict__['__use_gnu_getopt_explicitly_set'] = True
140
141  def is_gnu_getopt(self):
142    return self.__dict__['__use_gnu_getopt']
143
144  def _flags(self):
145    return self.__dict__['__flags']
146
147  def flags_by_module_dict(self):
148    """Returns the dictionary of module_name -> list of defined flags.
149
150    Returns:
151      A dictionary.  Its keys are module names (strings).  Its values
152      are lists of Flag objects.
153    """
154    return self.__dict__['__flags_by_module']
155
156  def flags_by_module_id_dict(self):
157    """Returns the dictionary of module_id -> list of defined flags.
158
159    Returns:
160      A dictionary.  Its keys are module IDs (ints).  Its values
161      are lists of Flag objects.
162    """
163    return self.__dict__['__flags_by_module_id']
164
165  def key_flags_by_module_dict(self):
166    """Returns the dictionary of module_name -> list of key flags.
167
168    Returns:
169      A dictionary.  Its keys are module names (strings).  Its values
170      are lists of Flag objects.
171    """
172    return self.__dict__['__key_flags_by_module']
173
174  def register_flag_by_module(self, module_name, flag):
175    """Records the module that defines a specific flag.
176
177    We keep track of which flag is defined by which module so that we
178    can later sort the flags by module.
179
180    Args:
181      module_name: str, the name of a Python module.
182      flag: Flag, the Flag instance that is key to the module.
183    """
184    flags_by_module = self.flags_by_module_dict()
185    flags_by_module.setdefault(module_name, []).append(flag)
186
187  def register_flag_by_module_id(self, module_id, flag):
188    """Records the module that defines a specific flag.
189
190    Args:
191      module_id: int, the ID of the Python module.
192      flag: Flag, the Flag instance that is key to the module.
193    """
194    flags_by_module_id = self.flags_by_module_id_dict()
195    flags_by_module_id.setdefault(module_id, []).append(flag)
196
197  def register_key_flag_for_module(self, module_name, flag):
198    """Specifies that a flag is a key flag for a module.
199
200    Args:
201      module_name: str, the name of a Python module.
202      flag: Flag, the Flag instance that is key to the module.
203    """
204    key_flags_by_module = self.key_flags_by_module_dict()
205    # The list of key flags for the module named module_name.
206    key_flags = key_flags_by_module.setdefault(module_name, [])
207    # Add flag, but avoid duplicates.
208    if flag not in key_flags:
209      key_flags.append(flag)
210
211  def _flag_is_registered(self, flag_obj):
212    """Checks whether a Flag object is registered under long name or short name.
213
214    Args:
215      flag_obj: Flag, the Flag instance to check for.
216
217    Returns:
218      bool, True iff flag_obj is registered under long name or short name.
219    """
220    flag_dict = self._flags()
221    # Check whether flag_obj is registered under its long name.
222    name = flag_obj.name
223    if flag_dict.get(name, None) == flag_obj:
224      return True
225    # Check whether flag_obj is registered under its short name.
226    short_name = flag_obj.short_name
227    if (short_name is not None and flag_dict.get(short_name, None) == flag_obj):
228      return True
229    return False
230
231  def _cleanup_unregistered_flag_from_module_dicts(self, flag_obj):
232    """Cleans up unregistered flags from all module -> [flags] dictionaries.
233
234    If flag_obj is registered under either its long name or short name, it
235    won't be removed from the dictionaries.
236
237    Args:
238      flag_obj: Flag, the Flag instance to clean up for.
239    """
240    if self._flag_is_registered(flag_obj):
241      return
242    for flags_by_module_dict in (self.flags_by_module_dict(),
243                                 self.flags_by_module_id_dict(),
244                                 self.key_flags_by_module_dict()):
245      for flags_in_module in flags_by_module_dict.values():
246        # While (as opposed to if) takes care of multiple occurrences of a
247        # flag in the list for the same module.
248        while flag_obj in flags_in_module:
249          flags_in_module.remove(flag_obj)
250
251  def get_flags_for_module(self, module):
252    """Returns the list of flags defined by a module.
253
254    Args:
255      module: module|str, the module to get flags from.
256
257    Returns:
258      [Flag], a new list of Flag instances.  Caller may update this list as
259      desired: none of those changes will affect the internals of this
260      FlagValue instance.
261    """
262    if not isinstance(module, str):
263      module = module.__name__
264    if module == '__main__':
265      module = sys.argv[0]
266
267    return list(self.flags_by_module_dict().get(module, []))
268
269  def get_key_flags_for_module(self, module):
270    """Returns the list of key flags for a module.
271
272    Args:
273      module: module|str, the module to get key flags from.
274
275    Returns:
276      [Flag], a new list of Flag instances.  Caller may update this list as
277      desired: none of those changes will affect the internals of this
278      FlagValue instance.
279    """
280    if not isinstance(module, str):
281      module = module.__name__
282    if module == '__main__':
283      module = sys.argv[0]
284
285    # Any flag is a key flag for the module that defined it.  NOTE:
286    # key_flags is a fresh list: we can update it without affecting the
287    # internals of this FlagValues object.
288    key_flags = self.get_flags_for_module(module)
289
290    # Take into account flags explicitly declared as key for a module.
291    for flag in self.key_flags_by_module_dict().get(module, []):
292      if flag not in key_flags:
293        key_flags.append(flag)
294    return key_flags
295
296  def find_module_defining_flag(self, flagname, default=None):
297    """Return the name of the module defining this flag, or default.
298
299    Args:
300      flagname: str, name of the flag to lookup.
301      default: Value to return if flagname is not defined. Defaults to None.
302
303    Returns:
304      The name of the module which registered the flag with this name.
305      If no such module exists (i.e. no flag with this name exists),
306      we return default.
307    """
308    registered_flag = self._flags().get(flagname)
309    if registered_flag is None:
310      return default
311    for module, flags in self.flags_by_module_dict().items():
312      for flag in flags:
313        # It must compare the flag with the one in _flags. This is because a
314        # flag might be overridden only for its long name (or short name),
315        # and only its short name (or long name) is considered registered.
316        if (flag.name == registered_flag.name and
317            flag.short_name == registered_flag.short_name):
318          return module
319    return default
320
321  def find_module_id_defining_flag(self, flagname, default=None):
322    """Return the ID of the module defining this flag, or default.
323
324    Args:
325      flagname: str, name of the flag to lookup.
326      default: Value to return if flagname is not defined. Defaults to None.
327
328    Returns:
329      The ID of the module which registered the flag with this name.
330      If no such module exists (i.e. no flag with this name exists),
331      we return default.
332    """
333    registered_flag = self._flags().get(flagname)
334    if registered_flag is None:
335      return default
336    for module_id, flags in self.flags_by_module_id_dict().items():
337      for flag in flags:
338        # It must compare the flag with the one in _flags. This is because a
339        # flag might be overridden only for its long name (or short name),
340        # and only its short name (or long name) is considered registered.
341        if (flag.name == registered_flag.name and
342            flag.short_name == registered_flag.short_name):
343          return module_id
344    return default
345
346  def _register_unknown_flag_setter(self, setter):
347    """Allow set default values for undefined flags.
348
349    Args:
350      setter: Method(name, value) to call to __setattr__ an unknown flag. Must
351        raise NameError or ValueError for invalid name/value.
352    """
353    self.__dict__['__set_unknown'] = setter
354
355  def _set_unknown_flag(self, name, value):
356    """Returns value if setting flag |name| to |value| returned True.
357
358    Args:
359      name: str, name of the flag to set.
360      value: Value to set.
361
362    Returns:
363      Flag value on successful call.
364
365    Raises:
366      UnrecognizedFlagError
367      IllegalFlagValueError
368    """
369    setter = self.__dict__['__set_unknown']
370    if setter:
371      try:
372        setter(name, value)
373        return value
374      except (TypeError, ValueError):  # Flag value is not valid.
375        raise _exceptions.IllegalFlagValueError(
376            '"{1}" is not valid for --{0}'.format(name, value))
377      except NameError:  # Flag name is not valid.
378        pass
379    raise _exceptions.UnrecognizedFlagError(name, value)
380
381  def append_flag_values(self, flag_values):
382    """Appends flags registered in another FlagValues instance.
383
384    Args:
385      flag_values: FlagValues, the FlagValues instance from which to copy flags.
386    """
387    for flag_name, flag in flag_values._flags().items():  # pylint: disable=protected-access
388      # Each flags with short_name appears here twice (once under its
389      # normal name, and again with its short name).  To prevent
390      # problems (DuplicateFlagError) with double flag registration, we
391      # perform a check to make sure that the entry we're looking at is
392      # for its normal name.
393      if flag_name == flag.name:
394        try:
395          self[flag_name] = flag
396        except _exceptions.DuplicateFlagError:
397          raise _exceptions.DuplicateFlagError.from_flag(
398              flag_name, self, other_flag_values=flag_values)
399
400  def remove_flag_values(self, flag_values):
401    """Remove flags that were previously appended from another FlagValues.
402
403    Args:
404      flag_values: FlagValues, the FlagValues instance containing flags to
405        remove.
406    """
407    for flag_name in flag_values:
408      self.__delattr__(flag_name)
409
410  def __setitem__(self, name, flag):
411    """Registers a new flag variable."""
412    fl = self._flags()
413    if not isinstance(flag, _flag.Flag):
414      raise _exceptions.IllegalFlagValueError(
415          f'Expect Flag instances, found type {type(flag)}. '
416          "Maybe you didn't mean to use FlagValue.__setitem__?")
417    if not isinstance(name, str):
418      raise _exceptions.Error('Flag name must be a string')
419    if not name:
420      raise _exceptions.Error('Flag name cannot be empty')
421    if ' ' in name:
422      raise _exceptions.Error('Flag name cannot contain a space')
423    self._check_method_name_conflicts(name, flag)
424    if name in fl and not flag.allow_override and not fl[name].allow_override:
425      module, module_name = _helpers.get_calling_module_object_and_name()
426      if (self.find_module_defining_flag(name) == module_name and
427          id(module) != self.find_module_id_defining_flag(name)):
428        # If the flag has already been defined by a module with the same name,
429        # but a different ID, we can stop here because it indicates that the
430        # module is simply being imported a subsequent time.
431        return
432      raise _exceptions.DuplicateFlagError.from_flag(name, self)
433    short_name = flag.short_name
434    # If a new flag overrides an old one, we need to cleanup the old flag's
435    # modules if it's not registered.
436    flags_to_cleanup = set()
437    if short_name is not None:
438      if (short_name in fl and not flag.allow_override and
439          not fl[short_name].allow_override):
440        raise _exceptions.DuplicateFlagError.from_flag(short_name, self)
441      if short_name in fl and fl[short_name] != flag:
442        flags_to_cleanup.add(fl[short_name])
443      fl[short_name] = flag
444    if (name not in fl  # new flag
445        or fl[name].using_default_value or not flag.using_default_value):
446      if name in fl and fl[name] != flag:
447        flags_to_cleanup.add(fl[name])
448      fl[name] = flag
449    for f in flags_to_cleanup:
450      self._cleanup_unregistered_flag_from_module_dicts(f)
451
452  def __dir__(self):
453    """Returns list of names of all defined flags.
454
455    Useful for TAB-completion in ipython.
456
457    Returns:
458      [str], a list of names of all defined flags.
459    """
460    return sorted(self.__dict__['__flags'])
461
462  def __getitem__(self, name):
463    """Returns the Flag object for the flag --name."""
464    return self._flags()[name]
465
466  def _hide_flag(self, name):
467    """Marks the flag --name as hidden."""
468    self.__dict__['__hiddenflags'].add(name)
469
470  def __getattr__(self, name):
471    """Retrieves the 'value' attribute of the flag --name."""
472    fl = self._flags()
473    if name not in fl:
474      raise AttributeError(name)
475    if name in self.__dict__['__hiddenflags']:
476      raise AttributeError(name)
477
478    if self.__dict__['__flags_parsed'] or fl[name].present:
479      return fl[name].value
480    else:
481      raise _exceptions.UnparsedFlagAccessError(
482          'Trying to access flag --%s before flags were parsed.' % name)
483
484  def __setattr__(self, name, value):
485    """Sets the 'value' attribute of the flag --name."""
486    self._set_attributes(**{name: value})
487    return value
488
489  def _set_attributes(self, **attributes):
490    """Sets multiple flag values together, triggers validators afterwards."""
491    fl = self._flags()
492    known_flags = set()
493    for name, value in attributes.items():
494      if name in self.__dict__['__hiddenflags']:
495        raise AttributeError(name)
496      if name in fl:
497        fl[name].value = value
498        known_flags.add(name)
499      else:
500        self._set_unknown_flag(name, value)
501    for name in known_flags:
502      self._assert_validators(fl[name].validators)
503      fl[name].using_default_value = False
504
505  def validate_all_flags(self):
506    """Verifies whether all flags pass validation.
507
508    Raises:
509      AttributeError: Raised if validators work with a non-existing flag.
510      IllegalFlagValueError: Raised if validation fails for at least one
511          validator.
512    """
513    all_validators = set()
514    for flag in self._flags().values():
515      all_validators.update(flag.validators)
516    self._assert_validators(all_validators)
517
518  def _assert_validators(self, validators):
519    """Asserts if all validators in the list are satisfied.
520
521    It asserts validators in the order they were created.
522
523    Args:
524      validators: Iterable(validators.Validator), validators to be verified.
525
526    Raises:
527      AttributeError: Raised if validators work with a non-existing flag.
528      IllegalFlagValueError: Raised if validation fails for at least one
529          validator.
530    """
531    messages = []
532    bad_flags = set()
533    for validator in sorted(
534        validators, key=lambda validator: validator.insertion_index):
535      try:
536        if isinstance(validator, _validators_classes.SingleFlagValidator):
537          if validator.flag_name in bad_flags:
538            continue
539        elif isinstance(validator, _validators_classes.MultiFlagsValidator):
540          if bad_flags & set(validator.flag_names):
541            continue
542        validator.verify(self)
543      except _exceptions.ValidationError as e:
544        if isinstance(validator, _validators_classes.SingleFlagValidator):
545          bad_flags.add(validator.flag_name)
546        elif isinstance(validator, _validators_classes.MultiFlagsValidator):
547          bad_flags.update(set(validator.flag_names))
548        message = validator.print_flags_with_values(self)
549        messages.append('%s: %s' % (message, str(e)))
550    if messages:
551      raise _exceptions.IllegalFlagValueError('\n'.join(messages))
552
553  def __delattr__(self, flag_name):
554    """Deletes a previously-defined flag from a flag object.
555
556    This method makes sure we can delete a flag by using
557
558      del FLAGS.<flag_name>
559
560    E.g.,
561
562      flags.DEFINE_integer('foo', 1, 'Integer flag.')
563      del flags.FLAGS.foo
564
565    If a flag is also registered by its the other name (long name or short
566    name), the other name won't be deleted.
567
568    Args:
569      flag_name: str, the name of the flag to be deleted.
570
571    Raises:
572      AttributeError: Raised when there is no registered flag named flag_name.
573    """
574    fl = self._flags()
575    if flag_name not in fl:
576      raise AttributeError(flag_name)
577
578    flag_obj = fl[flag_name]
579    del fl[flag_name]
580
581    self._cleanup_unregistered_flag_from_module_dicts(flag_obj)
582
583  def set_default(self, name, value):
584    """Changes the default value of the named flag object.
585
586    The flag's current value is also updated if the flag is currently using
587    the default value, i.e. not specified in the command line, and not set
588    by FLAGS.name = value.
589
590    Args:
591      name: str, the name of the flag to modify.
592      value: The new default value.
593
594    Raises:
595      UnrecognizedFlagError: Raised when there is no registered flag named name.
596      IllegalFlagValueError: Raised when value is not valid.
597    """
598    fl = self._flags()
599    if name not in fl:
600      self._set_unknown_flag(name, value)
601      return
602    fl[name]._set_default(value)  # pylint: disable=protected-access
603    self._assert_validators(fl[name].validators)
604
605  def __contains__(self, name):
606    """Returns True if name is a value (flag) in the dict."""
607    return name in self._flags()
608
609  def __len__(self):
610    return len(self.__dict__['__flags'])
611
612  def __iter__(self):
613    return iter(self._flags())
614
615  def __call__(self, argv, known_only=False):
616    """Parses flags from argv; stores parsed flags into this FlagValues object.
617
618    All unparsed arguments are returned.
619
620    Args:
621       argv: a tuple/list of strings.
622       known_only: bool, if True, parse and remove known flags; return the rest
623         untouched. Unknown flags specified by --undefok are not returned.
624
625    Returns:
626       The list of arguments not parsed as options, including argv[0].
627
628    Raises:
629       Error: Raised on any parsing error.
630       TypeError: Raised on passing wrong type of arguments.
631       ValueError: Raised on flag value parsing error.
632    """
633    if isinstance(argv, (str, bytes)):
634      raise TypeError(
635          'argv should be a tuple/list of strings, not bytes or string.')
636    if not argv:
637      raise ValueError(
638          'argv cannot be an empty list, and must contain the program name as '
639          'the first element.')
640
641    # This pre parses the argv list for --flagfile=<> options.
642    program_name = argv[0]
643    args = self.read_flags_from_files(argv[1:], force_gnu=False)
644
645    # Parse the arguments.
646    unknown_flags, unparsed_args = self._parse_args(args, known_only)
647
648    # Handle unknown flags by raising UnrecognizedFlagError.
649    # Note some users depend on us raising this particular error.
650    for name, value in unknown_flags:
651      suggestions = _helpers.get_flag_suggestions(name, list(self))
652      raise _exceptions.UnrecognizedFlagError(
653          name, value, suggestions=suggestions)
654
655    self.mark_as_parsed()
656    self.validate_all_flags()
657    return [program_name] + unparsed_args
658
659  def __getstate__(self):
660    raise TypeError("can't pickle FlagValues")
661
662  def __copy__(self):
663    raise TypeError('FlagValues does not support shallow copies. '
664                    'Use absl.testing.flagsaver or copy.deepcopy instead.')
665
666  def __deepcopy__(self, memo):
667    result = object.__new__(type(self))
668    result.__dict__.update(copy.deepcopy(self.__dict__, memo))
669    return result
670
671  def _set_is_retired_flag_func(self, is_retired_flag_func):
672    """Sets a function for checking retired flags.
673
674    Do not use it. This is a private absl API used to check retired flags
675    registered by the absl C++ flags library.
676
677    Args:
678      is_retired_flag_func: Callable(str) -> (bool, bool), a function takes flag
679        name as parameter, returns a tuple (is_retired, type_is_bool).
680    """
681    self.__dict__['__is_retired_flag_func'] = is_retired_flag_func
682
683  def _parse_args(self, args, known_only):
684    """Helper function to do the main argument parsing.
685
686    This function goes through args and does the bulk of the flag parsing.
687    It will find the corresponding flag in our flag dictionary, and call its
688    .parse() method on the flag value.
689
690    Args:
691      args: [str], a list of strings with the arguments to parse.
692      known_only: bool, if True, parse and remove known flags; return the rest
693        untouched. Unknown flags specified by --undefok are not returned.
694
695    Returns:
696      A tuple with the following:
697          unknown_flags: List of (flag name, arg) for flags we don't know about.
698          unparsed_args: List of arguments we did not parse.
699
700    Raises:
701       Error: Raised on any parsing error.
702       ValueError: Raised on flag value parsing error.
703    """
704    unparsed_names_and_args = []  # A list of (flag name or None, arg).
705    undefok = set()
706    retired_flag_func = self.__dict__['__is_retired_flag_func']
707
708    flag_dict = self._flags()
709    args = iter(args)
710    for arg in args:
711      value = None
712
713      def get_value():
714        # pylint: disable=cell-var-from-loop
715        try:
716          return next(args) if value is None else value
717        except StopIteration:
718          raise _exceptions.Error('Missing value for flag ' + arg)  # pylint: disable=undefined-loop-variable
719
720      if not arg.startswith('-'):
721        # A non-argument: default is break, GNU is skip.
722        unparsed_names_and_args.append((None, arg))
723        if self.is_gnu_getopt():
724          continue
725        else:
726          break
727
728      if arg == '--':
729        if known_only:
730          unparsed_names_and_args.append((None, arg))
731        break
732
733      # At this point, arg must start with '-'.
734      if arg.startswith('--'):
735        arg_without_dashes = arg[2:]
736      else:
737        arg_without_dashes = arg[1:]
738
739      if '=' in arg_without_dashes:
740        name, value = arg_without_dashes.split('=', 1)
741      else:
742        name, value = arg_without_dashes, None
743
744      if not name:
745        # The argument is all dashes (including one dash).
746        unparsed_names_and_args.append((None, arg))
747        if self.is_gnu_getopt():
748          continue
749        else:
750          break
751
752      # --undefok is a special case.
753      if name == 'undefok':
754        value = get_value()
755        undefok.update(v.strip() for v in value.split(','))
756        undefok.update('no' + v.strip() for v in value.split(','))
757        continue
758
759      flag = flag_dict.get(name)
760      if flag is not None:
761        if flag.boolean and value is None:
762          value = 'true'
763        else:
764          value = get_value()
765      elif name.startswith('no') and len(name) > 2:
766        # Boolean flags can take the form of --noflag, with no value.
767        noflag = flag_dict.get(name[2:])
768        if noflag is not None and noflag.boolean:
769          if value is not None:
770            raise ValueError(arg + ' does not take an argument')
771          flag = noflag
772          value = 'false'
773
774      if retired_flag_func and flag is None:
775        is_retired, is_bool = retired_flag_func(name)
776
777        # If we didn't recognize that flag, but it starts with
778        # "no" then maybe it was a boolean flag specified in the
779        # --nofoo form.
780        if not is_retired and name.startswith('no'):
781          is_retired, is_bool = retired_flag_func(name[2:])
782          is_retired = is_retired and is_bool
783
784        if is_retired:
785          if not is_bool and value is None:
786            # This happens when a non-bool retired flag is specified
787            # in format of "--flag value".
788            get_value()
789          logging.error(
790              'Flag "%s" is retired and should no longer '
791              'be specified. See go/totw/90.', name)
792          continue
793
794      if flag is not None:
795        # LINT.IfChange
796        flag.parse(value)
797        flag.using_default_value = False
798        # LINT.ThenChange(../testing/flagsaver.py:flag_override_parsing)
799      else:
800        unparsed_names_and_args.append((name, arg))
801
802    unknown_flags = []
803    unparsed_args = []
804    for name, arg in unparsed_names_and_args:
805      if name is None:
806        # Positional arguments.
807        unparsed_args.append(arg)
808      elif name in undefok:
809        # Remove undefok flags.
810        continue
811      else:
812        # This is an unknown flag.
813        if known_only:
814          unparsed_args.append(arg)
815        else:
816          unknown_flags.append((name, arg))
817
818    unparsed_args.extend(list(args))
819    return unknown_flags, unparsed_args
820
821  def is_parsed(self):
822    """Returns whether flags were parsed."""
823    return self.__dict__['__flags_parsed']
824
825  def mark_as_parsed(self):
826    """Explicitly marks flags as parsed.
827
828    Use this when the caller knows that this FlagValues has been parsed as if
829    a ``__call__()`` invocation has happened.  This is only a public method for
830    use by things like appcommands which do additional command like parsing.
831    """
832    self.__dict__['__flags_parsed'] = True
833
834  def unparse_flags(self):
835    """Unparses all flags to the point before any FLAGS(argv) was called."""
836    for f in self._flags().values():
837      f.unparse()
838    # We log this message before marking flags as unparsed to avoid a
839    # problem when the logging library causes flags access.
840    logging.info('unparse_flags() called; flags access will now raise errors.')
841    self.__dict__['__flags_parsed'] = False
842    self.__dict__['__unparse_flags_called'] = True
843
844  def flag_values_dict(self):
845    """Returns a dictionary that maps flag names to flag values."""
846    return {name: flag.value for name, flag in self._flags().items()}
847
848  def __str__(self):
849    """Returns a help string for all known flags."""
850    return self.get_help()
851
852  def get_help(self, prefix='', include_special_flags=True):
853    """Returns a help string for all known flags.
854
855    Args:
856      prefix: str, per-line output prefix.
857      include_special_flags: bool, whether to include description of
858        SPECIAL_FLAGS, i.e. --flagfile and --undefok.
859
860    Returns:
861      str, formatted help message.
862    """
863    flags_by_module = self.flags_by_module_dict()
864    if flags_by_module:
865      modules = sorted(flags_by_module)
866      # Print the help for the main module first, if possible.
867      main_module = sys.argv[0]
868      if main_module in modules:
869        modules.remove(main_module)
870        modules = [main_module] + modules
871      return self._get_help_for_modules(modules, prefix, include_special_flags)
872    else:
873      output_lines = []
874      # Just print one long list of flags.
875      values = self._flags().values()
876      if include_special_flags:
877        values = itertools.chain(
878            values, _helpers.SPECIAL_FLAGS._flags().values())  # pylint: disable=protected-access
879      self._render_flag_list(values, output_lines, prefix)
880      return '\n'.join(output_lines)
881
882  def _get_help_for_modules(self, modules, prefix, include_special_flags):
883    """Returns the help string for a list of modules.
884
885    Private to absl.flags package.
886
887    Args:
888      modules: List[str], a list of modules to get the help string for.
889      prefix: str, a string that is prepended to each generated help line.
890      include_special_flags: bool, whether to include description of
891        SPECIAL_FLAGS, i.e. --flagfile and --undefok.
892    """
893    output_lines = []
894    for module in modules:
895      self._render_our_module_flags(module, output_lines, prefix)
896    if include_special_flags:
897      self._render_module_flags(
898          'absl.flags',
899          _helpers.SPECIAL_FLAGS._flags().values(),  # pylint: disable=protected-access
900          output_lines,
901          prefix)
902    return '\n'.join(output_lines)
903
904  def _render_module_flags(self, module, flags, output_lines, prefix=''):
905    """Returns a help string for a given module."""
906    if not isinstance(module, str):
907      module = module.__name__
908    output_lines.append('\n%s%s:' % (prefix, module))
909    self._render_flag_list(flags, output_lines, prefix + '  ')
910
911  def _render_our_module_flags(self, module, output_lines, prefix=''):
912    """Returns a help string for a given module."""
913    flags = self.get_flags_for_module(module)
914    if flags:
915      self._render_module_flags(module, flags, output_lines, prefix)
916
917  def _render_our_module_key_flags(self, module, output_lines, prefix=''):
918    """Returns a help string for the key flags of a given module.
919
920    Args:
921      module: module|str, the module to render key flags for.
922      output_lines: [str], a list of strings.  The generated help message lines
923        will be appended to this list.
924      prefix: str, a string that is prepended to each generated help line.
925    """
926    key_flags = self.get_key_flags_for_module(module)
927    if key_flags:
928      self._render_module_flags(module, key_flags, output_lines, prefix)
929
930  def module_help(self, module):
931    """Describes the key flags of a module.
932
933    Args:
934      module: module|str, the module to describe the key flags for.
935
936    Returns:
937      str, describing the key flags of a module.
938    """
939    helplist = []
940    self._render_our_module_key_flags(module, helplist)
941    return '\n'.join(helplist)
942
943  def main_module_help(self):
944    """Describes the key flags of the main module.
945
946    Returns:
947      str, describing the key flags of the main module.
948    """
949    return self.module_help(sys.argv[0])
950
951  def _render_flag_list(self, flaglist, output_lines, prefix='  '):
952    fl = self._flags()
953    special_fl = _helpers.SPECIAL_FLAGS._flags()  # pylint: disable=protected-access
954    flaglist = [(flag.name, flag) for flag in flaglist]
955    flaglist.sort()
956    flagset = {}
957    for (name, flag) in flaglist:
958      # It's possible this flag got deleted or overridden since being
959      # registered in the per-module flaglist.  Check now against the
960      # canonical source of current flag information, the _flags.
961      if fl.get(name, None) != flag and special_fl.get(name, None) != flag:
962        # a different flag is using this name now
963        continue
964      # only print help once
965      if flag in flagset:
966        continue
967      flagset[flag] = 1
968      flaghelp = ''
969      if flag.short_name:
970        flaghelp += '-%s,' % flag.short_name
971      if flag.boolean:
972        flaghelp += '--[no]%s:' % flag.name
973      else:
974        flaghelp += '--%s:' % flag.name
975      flaghelp += ' '
976      if flag.help:
977        flaghelp += flag.help
978      flaghelp = _helpers.text_wrap(
979          flaghelp, indent=prefix + '  ', firstline_indent=prefix)
980      if flag.default_as_str:
981        flaghelp += '\n'
982        flaghelp += _helpers.text_wrap(
983            '(default: %s)' % flag.default_as_str, indent=prefix + '  ')
984      if flag.parser.syntactic_help:
985        flaghelp += '\n'
986        flaghelp += _helpers.text_wrap(
987            '(%s)' % flag.parser.syntactic_help, indent=prefix + '  ')
988      output_lines.append(flaghelp)
989
990  def get_flag_value(self, name, default):  # pylint: disable=invalid-name
991    """Returns the value of a flag (if not None) or a default value.
992
993    Args:
994      name: str, the name of a flag.
995      default: Default value to use if the flag value is None.
996
997    Returns:
998      Requested flag value or default.
999    """
1000
1001    value = self.__getattr__(name)
1002    if value is not None:  # Can't do if not value, b/c value might be '0' or ""
1003      return value
1004    else:
1005      return default
1006
1007  def _is_flag_file_directive(self, flag_string):
1008    """Checks whether flag_string contain a --flagfile=<foo> directive."""
1009    if isinstance(flag_string, str):
1010      if flag_string.startswith('--flagfile='):
1011        return 1
1012      elif flag_string == '--flagfile':
1013        return 1
1014      elif flag_string.startswith('-flagfile='):
1015        return 1
1016      elif flag_string == '-flagfile':
1017        return 1
1018      else:
1019        return 0
1020    return 0
1021
1022  def _extract_filename(self, flagfile_str):
1023    """Returns filename from a flagfile_str of form -[-]flagfile=filename.
1024
1025    The cases of --flagfile foo and -flagfile foo shouldn't be hitting
1026    this function, as they are dealt with in the level above this
1027    function.
1028
1029    Args:
1030      flagfile_str: str, the flagfile string.
1031
1032    Returns:
1033      str, the filename from a flagfile_str of form -[-]flagfile=filename.
1034
1035    Raises:
1036      Error: Raised when illegal --flagfile is provided.
1037    """
1038    if flagfile_str.startswith('--flagfile='):
1039      return os.path.expanduser((flagfile_str[(len('--flagfile=')):]).strip())
1040    elif flagfile_str.startswith('-flagfile='):
1041      return os.path.expanduser((flagfile_str[(len('-flagfile=')):]).strip())
1042    else:
1043      raise _exceptions.Error('Hit illegal --flagfile type: %s' % flagfile_str)
1044
1045  def _get_flag_file_lines(self, filename, parsed_file_stack=None):
1046    """Returns the useful (!=comments, etc) lines from a file with flags.
1047
1048    Args:
1049      filename: str, the name of the flag file.
1050      parsed_file_stack: [str], a list of the names of the files that we have
1051        recursively encountered at the current depth. MUTATED BY THIS FUNCTION
1052        (but the original value is preserved upon successfully returning from
1053        function call).
1054
1055    Returns:
1056      List of strings. See the note below.
1057
1058    NOTE(springer): This function checks for a nested --flagfile=<foo>
1059    tag and handles the lower file recursively. It returns a list of
1060    all the lines that _could_ contain command flags. This is
1061    EVERYTHING except whitespace lines and comments (lines starting
1062    with '#' or '//').
1063    """
1064    # For consistency with the cpp version, ignore empty values.
1065    if not filename:
1066      return []
1067    if parsed_file_stack is None:
1068      parsed_file_stack = []
1069    # We do a little safety check for reparsing a file we've already encountered
1070    # at a previous depth.
1071    if filename in parsed_file_stack:
1072      sys.stderr.write('Warning: Hit circular flagfile dependency. Ignoring'
1073                       ' flagfile: %s\n' % (filename,))
1074      return []
1075    else:
1076      parsed_file_stack.append(filename)
1077
1078    line_list = []  # All line from flagfile.
1079    flag_line_list = []  # Subset of lines w/o comments, blanks, flagfile= tags.
1080    try:
1081      file_obj = open(filename, 'r')
1082    except IOError as e_msg:
1083      raise _exceptions.CantOpenFlagFileError(
1084          'ERROR:: Unable to open flagfile: %s' % e_msg)
1085
1086    with file_obj:
1087      line_list = file_obj.readlines()
1088
1089    # This is where we check each line in the file we just read.
1090    for line in line_list:
1091      if line.isspace():
1092        pass
1093      # Checks for comment (a line that starts with '#').
1094      elif line.startswith('#') or line.startswith('//'):
1095        pass
1096      # Checks for a nested "--flagfile=<bar>" flag in the current file.
1097      # If we find one, recursively parse down into that file.
1098      elif self._is_flag_file_directive(line):
1099        sub_filename = self._extract_filename(line)
1100        included_flags = self._get_flag_file_lines(
1101            sub_filename, parsed_file_stack=parsed_file_stack)
1102        flag_line_list.extend(included_flags)
1103      else:
1104        # Any line that's not a comment or a nested flagfile should get
1105        # copied into 2nd position.  This leaves earlier arguments
1106        # further back in the list, thus giving them higher priority.
1107        flag_line_list.append(line.strip())
1108
1109    parsed_file_stack.pop()
1110    return flag_line_list
1111
1112  def read_flags_from_files(self, argv, force_gnu=True):
1113    """Processes command line args, but also allow args to be read from file.
1114
1115    Args:
1116      argv: [str], a list of strings, usually sys.argv[1:], which may contain
1117        one or more flagfile directives of the form --flagfile="./filename".
1118        Note that the name of the program (sys.argv[0]) should be omitted.
1119      force_gnu: bool, if False, --flagfile parsing obeys the
1120        FLAGS.is_gnu_getopt() value. If True, ignore the value and always follow
1121        gnu_getopt semantics.
1122
1123    Returns:
1124      A new list which has the original list combined with what we read
1125      from any flagfile(s).
1126
1127    Raises:
1128      IllegalFlagValueError: Raised when --flagfile is provided with no
1129          argument.
1130
1131    This function is called by FLAGS(argv).
1132    It scans the input list for a flag that looks like:
1133    --flagfile=<somefile>. Then it opens <somefile>, reads all valid key
1134    and value pairs and inserts them into the input list in exactly the
1135    place where the --flagfile arg is found.
1136
1137    Note that your application's flags are still defined the usual way
1138    using absl.flags DEFINE_flag() type functions.
1139
1140    Notes (assuming we're getting a commandline of some sort as our input):
1141
1142    * For duplicate flags, the last one we hit should "win".
1143    * Since flags that appear later win, a flagfile's settings can be "weak"
1144        if the --flagfile comes at the beginning of the argument sequence,
1145        and it can be "strong" if the --flagfile comes at the end.
1146    * A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile.
1147        It will be expanded in exactly the spot where it is found.
1148    * In a flagfile, a line beginning with # or // is a comment.
1149    * Entirely blank lines _should_ be ignored.
1150    """
1151    rest_of_args = argv
1152    new_argv = []
1153    while rest_of_args:
1154      current_arg = rest_of_args[0]
1155      rest_of_args = rest_of_args[1:]
1156      if self._is_flag_file_directive(current_arg):
1157        # This handles the case of -(-)flagfile foo.  In this case the
1158        # next arg really is part of this one.
1159        if current_arg == '--flagfile' or current_arg == '-flagfile':
1160          if not rest_of_args:
1161            raise _exceptions.IllegalFlagValueError(
1162                '--flagfile with no argument')
1163          flag_filename = os.path.expanduser(rest_of_args[0])
1164          rest_of_args = rest_of_args[1:]
1165        else:
1166          # This handles the case of (-)-flagfile=foo.
1167          flag_filename = self._extract_filename(current_arg)
1168        new_argv.extend(self._get_flag_file_lines(flag_filename))
1169      else:
1170        new_argv.append(current_arg)
1171        # Stop parsing after '--', like getopt and gnu_getopt.
1172        if current_arg == '--':
1173          break
1174        # Stop parsing after a non-flag, like getopt.
1175        if not current_arg.startswith('-'):
1176          if not force_gnu and not self.__dict__['__use_gnu_getopt']:
1177            break
1178        else:
1179          if ('=' not in current_arg and rest_of_args and
1180              not rest_of_args[0].startswith('-')):
1181            # If this is an occurrence of a legitimate --x y, skip the value
1182            # so that it won't be mistaken for a standalone arg.
1183            fl = self._flags()
1184            name = current_arg.lstrip('-')
1185            if name in fl and not fl[name].boolean:
1186              current_arg = rest_of_args[0]
1187              rest_of_args = rest_of_args[1:]
1188              new_argv.append(current_arg)
1189
1190    if rest_of_args:
1191      new_argv.extend(rest_of_args)
1192
1193    return new_argv
1194
1195  def flags_into_string(self):
1196    """Returns a string with the flags assignments from this FlagValues object.
1197
1198    This function ignores flags whose value is None.  Each flag
1199    assignment is separated by a newline.
1200
1201    NOTE: MUST mirror the behavior of the C++ CommandlineFlagsIntoString
1202    from https://github.com/gflags/gflags.
1203
1204    Returns:
1205      str, the string with the flags assignments from this FlagValues object.
1206      The flags are ordered by (module_name, flag_name).
1207    """
1208    module_flags = sorted(self.flags_by_module_dict().items())
1209    s = ''
1210    for unused_module_name, flags in module_flags:
1211      flags = sorted(flags, key=lambda f: f.name)
1212      for flag in flags:
1213        if flag.value is not None:
1214          s += flag.serialize() + '\n'
1215    return s
1216
1217  def append_flags_into_file(self, filename):
1218    """Appends all flags assignments from this FlagInfo object to a file.
1219
1220    Output will be in the format of a flagfile.
1221
1222    NOTE: MUST mirror the behavior of the C++ AppendFlagsIntoFile
1223    from https://github.com/gflags/gflags.
1224
1225    Args:
1226      filename: str, name of the file.
1227    """
1228    with open(filename, 'a') as out_file:
1229      out_file.write(self.flags_into_string())
1230
1231  def write_help_in_xml_format(self, outfile=None):
1232    """Outputs flag documentation in XML format.
1233
1234    NOTE: We use element names that are consistent with those used by
1235    the C++ command-line flag library, from
1236    https://github.com/gflags/gflags.
1237    We also use a few new elements (e.g., <key>), but we do not
1238    interfere / overlap with existing XML elements used by the C++
1239    library.  Please maintain this consistency.
1240
1241    Args:
1242      outfile: File object we write to.  Default None means sys.stdout.
1243    """
1244    doc = minidom.Document()
1245    all_flag = doc.createElement('AllFlags')
1246    doc.appendChild(all_flag)
1247
1248    all_flag.appendChild(
1249        _helpers.create_xml_dom_element(doc, 'program',
1250                                        os.path.basename(sys.argv[0])))
1251
1252    usage_doc = sys.modules['__main__'].__doc__
1253    if not usage_doc:
1254      usage_doc = '\nUSAGE: %s [flags]\n' % sys.argv[0]
1255    else:
1256      usage_doc = usage_doc.replace('%s', sys.argv[0])
1257    all_flag.appendChild(
1258        _helpers.create_xml_dom_element(doc, 'usage', usage_doc))
1259
1260    # Get list of key flags for the main module.
1261    key_flags = self.get_key_flags_for_module(sys.argv[0])
1262
1263    # Sort flags by declaring module name and next by flag name.
1264    flags_by_module = self.flags_by_module_dict()
1265    all_module_names = list(flags_by_module.keys())
1266    all_module_names.sort()
1267    for module_name in all_module_names:
1268      flag_list = [(f.name, f) for f in flags_by_module[module_name]]
1269      flag_list.sort()
1270      for unused_flag_name, flag in flag_list:
1271        is_key = flag in key_flags
1272        all_flag.appendChild(
1273            flag._create_xml_dom_element(  # pylint: disable=protected-access
1274                doc,
1275                module_name,
1276                is_key=is_key))
1277
1278    outfile = outfile or sys.stdout
1279    outfile.write(
1280        doc.toprettyxml(indent='  ', encoding='utf-8').decode('utf-8'))
1281    outfile.flush()
1282
1283  def _check_method_name_conflicts(self, name, flag):
1284    if flag.allow_using_method_names:
1285      return
1286    short_name = flag.short_name
1287    flag_names = {name} if short_name is None else {name, short_name}
1288    for flag_name in flag_names:
1289      if flag_name in self.__dict__['__banned_flag_names']:
1290        raise _exceptions.FlagNameConflictsWithMethodError(
1291            'Cannot define a flag named "{name}". It conflicts with a method '
1292            'on class "{class_name}". To allow defining it, use '
1293            'allow_using_method_names and access the flag value with '
1294            "FLAGS['{name}'].value. FLAGS.{name} returns the method, "
1295            'not the flag value.'.format(
1296                name=flag_name, class_name=type(self).__name__))
1297
1298
1299FLAGS = FlagValues()
1300
1301
1302class FlagHolder(Generic[_T]):
1303  """Holds a defined flag.
1304
1305  This facilitates a cleaner api around global state. Instead of::
1306
1307      flags.DEFINE_integer('foo', ...)
1308      flags.DEFINE_integer('bar', ...)
1309
1310      def method():
1311        # prints parsed value of 'bar' flag
1312        print(flags.FLAGS.foo)
1313        # runtime error due to typo or possibly bad coding style.
1314        print(flags.FLAGS.baz)
1315
1316  it encourages code like::
1317
1318      _FOO_FLAG = flags.DEFINE_integer('foo', ...)
1319      _BAR_FLAG = flags.DEFINE_integer('bar', ...)
1320
1321      def method():
1322        print(_FOO_FLAG.value)
1323        print(_BAR_FLAG.value)
1324
1325  since the name of the flag appears only once in the source code.
1326  """
1327
1328  def __init__(self, flag_values, flag, ensure_non_none_value=False):
1329    """Constructs a FlagHolder instance providing typesafe access to flag.
1330
1331    Args:
1332      flag_values: The container the flag is registered to.
1333      flag: The flag object for this flag.
1334      ensure_non_none_value: Is the value of the flag allowed to be None.
1335    """
1336    self._flagvalues = flag_values
1337    # We take the entire flag object, but only keep the name. Why?
1338    # - We want FlagHolder[T] to be generic container
1339    # - flag_values contains all flags, so has no reference to T.
1340    # - typecheckers don't like to see a generic class where none of the ctor
1341    #   arguments refer to the generic type.
1342    self._name = flag.name
1343    # We intentionally do NOT check if the default value is None.
1344    # This allows future use of this for "required flags with None default"
1345    self._ensure_non_none_value = ensure_non_none_value
1346
1347  def __eq__(self, other):
1348    raise TypeError(
1349        "unsupported operand type(s) for ==: '{0}' and '{1}' "
1350        "(did you mean to use '{0}.value' instead?)".format(
1351            type(self).__name__, type(other).__name__))
1352
1353  def __bool__(self):
1354    raise TypeError(
1355        "bool() not supported for instances of type '{0}' "
1356        "(did you mean to use '{0}.value' instead?)".format(
1357            type(self).__name__))
1358
1359  __nonzero__ = __bool__
1360
1361  @property
1362  def name(self):
1363    return self._name
1364
1365  @property
1366  def value(self):
1367    """Returns the value of the flag.
1368
1369    If ``_ensure_non_none_value`` is ``True``, then return value is not
1370    ``None``.
1371
1372    Raises:
1373      UnparsedFlagAccessError: if flag parsing has not finished.
1374      IllegalFlagValueError: if value is None unexpectedly.
1375    """
1376    val = getattr(self._flagvalues, self._name)
1377    if self._ensure_non_none_value and val is None:
1378      raise _exceptions.IllegalFlagValueError(
1379          'Unexpected None value for flag %s' % self._name)
1380    return val
1381
1382  @property
1383  def default(self):
1384    """Returns the default value of the flag."""
1385    return self._flagvalues[self._name].default
1386
1387  @property
1388  def present(self):
1389    """Returns True if the flag was parsed from command-line flags."""
1390    return bool(self._flagvalues[self._name].present)
1391
1392
1393def resolve_flag_ref(flag_ref, flag_values):
1394  """Helper to validate and resolve a flag reference argument."""
1395  if isinstance(flag_ref, FlagHolder):
1396    new_flag_values = flag_ref._flagvalues  # pylint: disable=protected-access
1397    if flag_values != FLAGS and flag_values != new_flag_values:
1398      raise ValueError(
1399          'flag_values must not be customized when operating on a FlagHolder')
1400    return flag_ref.name, new_flag_values
1401  return flag_ref, flag_values
1402
1403
1404def resolve_flag_refs(flag_refs, flag_values):
1405  """Helper to validate and resolve flag reference list arguments."""
1406  fv = None
1407  names = []
1408  for ref in flag_refs:
1409    if isinstance(ref, FlagHolder):
1410      newfv = ref._flagvalues  # pylint: disable=protected-access
1411      name = ref.name
1412    else:
1413      newfv = flag_values
1414      name = ref
1415    if fv and fv != newfv:
1416      raise ValueError(
1417          'multiple FlagValues instances used in invocation. '
1418          'FlagHolders must be registered to the same FlagValues instance as '
1419          'do flag names, if provided.')
1420    fv = newfv
1421    names.append(name)
1422  return names, fv
1423