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(flag) 415 if not isinstance(name, str): 416 raise _exceptions.Error('Flag name must be a string') 417 if not name: 418 raise _exceptions.Error('Flag name cannot be empty') 419 if ' ' in name: 420 raise _exceptions.Error('Flag name cannot contain a space') 421 self._check_method_name_conflicts(name, flag) 422 if name in fl and not flag.allow_override and not fl[name].allow_override: 423 module, module_name = _helpers.get_calling_module_object_and_name() 424 if (self.find_module_defining_flag(name) == module_name and 425 id(module) != self.find_module_id_defining_flag(name)): 426 # If the flag has already been defined by a module with the same name, 427 # but a different ID, we can stop here because it indicates that the 428 # module is simply being imported a subsequent time. 429 return 430 raise _exceptions.DuplicateFlagError.from_flag(name, self) 431 short_name = flag.short_name 432 # If a new flag overrides an old one, we need to cleanup the old flag's 433 # modules if it's not registered. 434 flags_to_cleanup = set() 435 if short_name is not None: 436 if (short_name in fl and not flag.allow_override and 437 not fl[short_name].allow_override): 438 raise _exceptions.DuplicateFlagError.from_flag(short_name, self) 439 if short_name in fl and fl[short_name] != flag: 440 flags_to_cleanup.add(fl[short_name]) 441 fl[short_name] = flag 442 if (name not in fl # new flag 443 or fl[name].using_default_value or not flag.using_default_value): 444 if name in fl and fl[name] != flag: 445 flags_to_cleanup.add(fl[name]) 446 fl[name] = flag 447 for f in flags_to_cleanup: 448 self._cleanup_unregistered_flag_from_module_dicts(f) 449 450 def __dir__(self): 451 """Returns list of names of all defined flags. 452 453 Useful for TAB-completion in ipython. 454 455 Returns: 456 [str], a list of names of all defined flags. 457 """ 458 return sorted(self.__dict__['__flags']) 459 460 def __getitem__(self, name): 461 """Returns the Flag object for the flag --name.""" 462 return self._flags()[name] 463 464 def _hide_flag(self, name): 465 """Marks the flag --name as hidden.""" 466 self.__dict__['__hiddenflags'].add(name) 467 468 def __getattr__(self, name): 469 """Retrieves the 'value' attribute of the flag --name.""" 470 fl = self._flags() 471 if name not in fl: 472 raise AttributeError(name) 473 if name in self.__dict__['__hiddenflags']: 474 raise AttributeError(name) 475 476 if self.__dict__['__flags_parsed'] or fl[name].present: 477 return fl[name].value 478 else: 479 raise _exceptions.UnparsedFlagAccessError( 480 'Trying to access flag --%s before flags were parsed.' % name) 481 482 def __setattr__(self, name, value): 483 """Sets the 'value' attribute of the flag --name.""" 484 self._set_attributes(**{name: value}) 485 return value 486 487 def _set_attributes(self, **attributes): 488 """Sets multiple flag values together, triggers validators afterwards.""" 489 fl = self._flags() 490 known_flags = set() 491 for name, value in attributes.items(): 492 if name in self.__dict__['__hiddenflags']: 493 raise AttributeError(name) 494 if name in fl: 495 fl[name].value = value 496 known_flags.add(name) 497 else: 498 self._set_unknown_flag(name, value) 499 for name in known_flags: 500 self._assert_validators(fl[name].validators) 501 fl[name].using_default_value = False 502 503 def validate_all_flags(self): 504 """Verifies whether all flags pass validation. 505 506 Raises: 507 AttributeError: Raised if validators work with a non-existing flag. 508 IllegalFlagValueError: Raised if validation fails for at least one 509 validator. 510 """ 511 all_validators = set() 512 for flag in self._flags().values(): 513 all_validators.update(flag.validators) 514 self._assert_validators(all_validators) 515 516 def _assert_validators(self, validators): 517 """Asserts if all validators in the list are satisfied. 518 519 It asserts validators in the order they were created. 520 521 Args: 522 validators: Iterable(validators.Validator), validators to be verified. 523 524 Raises: 525 AttributeError: Raised if validators work with a non-existing flag. 526 IllegalFlagValueError: Raised if validation fails for at least one 527 validator. 528 """ 529 messages = [] 530 bad_flags = set() 531 for validator in sorted( 532 validators, key=lambda validator: validator.insertion_index): 533 try: 534 if isinstance(validator, _validators_classes.SingleFlagValidator): 535 if validator.flag_name in bad_flags: 536 continue 537 elif isinstance(validator, _validators_classes.MultiFlagsValidator): 538 if bad_flags & set(validator.flag_names): 539 continue 540 validator.verify(self) 541 except _exceptions.ValidationError as e: 542 if isinstance(validator, _validators_classes.SingleFlagValidator): 543 bad_flags.add(validator.flag_name) 544 elif isinstance(validator, _validators_classes.MultiFlagsValidator): 545 bad_flags.update(set(validator.flag_names)) 546 message = validator.print_flags_with_values(self) 547 messages.append('%s: %s' % (message, str(e))) 548 if messages: 549 raise _exceptions.IllegalFlagValueError('\n'.join(messages)) 550 551 def __delattr__(self, flag_name): 552 """Deletes a previously-defined flag from a flag object. 553 554 This method makes sure we can delete a flag by using 555 556 del FLAGS.<flag_name> 557 558 E.g., 559 560 flags.DEFINE_integer('foo', 1, 'Integer flag.') 561 del flags.FLAGS.foo 562 563 If a flag is also registered by its the other name (long name or short 564 name), the other name won't be deleted. 565 566 Args: 567 flag_name: str, the name of the flag to be deleted. 568 569 Raises: 570 AttributeError: Raised when there is no registered flag named flag_name. 571 """ 572 fl = self._flags() 573 if flag_name not in fl: 574 raise AttributeError(flag_name) 575 576 flag_obj = fl[flag_name] 577 del fl[flag_name] 578 579 self._cleanup_unregistered_flag_from_module_dicts(flag_obj) 580 581 def set_default(self, name, value): 582 """Changes the default value of the named flag object. 583 584 The flag's current value is also updated if the flag is currently using 585 the default value, i.e. not specified in the command line, and not set 586 by FLAGS.name = value. 587 588 Args: 589 name: str, the name of the flag to modify. 590 value: The new default value. 591 592 Raises: 593 UnrecognizedFlagError: Raised when there is no registered flag named name. 594 IllegalFlagValueError: Raised when value is not valid. 595 """ 596 fl = self._flags() 597 if name not in fl: 598 self._set_unknown_flag(name, value) 599 return 600 fl[name]._set_default(value) # pylint: disable=protected-access 601 self._assert_validators(fl[name].validators) 602 603 def __contains__(self, name): 604 """Returns True if name is a value (flag) in the dict.""" 605 return name in self._flags() 606 607 def __len__(self): 608 return len(self.__dict__['__flags']) 609 610 def __iter__(self): 611 return iter(self._flags()) 612 613 def __call__(self, argv, known_only=False): 614 """Parses flags from argv; stores parsed flags into this FlagValues object. 615 616 All unparsed arguments are returned. 617 618 Args: 619 argv: a tuple/list of strings. 620 known_only: bool, if True, parse and remove known flags; return the rest 621 untouched. Unknown flags specified by --undefok are not returned. 622 623 Returns: 624 The list of arguments not parsed as options, including argv[0]. 625 626 Raises: 627 Error: Raised on any parsing error. 628 TypeError: Raised on passing wrong type of arguments. 629 ValueError: Raised on flag value parsing error. 630 """ 631 if isinstance(argv, (str, bytes)): 632 raise TypeError( 633 'argv should be a tuple/list of strings, not bytes or string.') 634 if not argv: 635 raise ValueError( 636 'argv cannot be an empty list, and must contain the program name as ' 637 'the first element.') 638 639 # This pre parses the argv list for --flagfile=<> options. 640 program_name = argv[0] 641 args = self.read_flags_from_files(argv[1:], force_gnu=False) 642 643 # Parse the arguments. 644 unknown_flags, unparsed_args = self._parse_args(args, known_only) 645 646 # Handle unknown flags by raising UnrecognizedFlagError. 647 # Note some users depend on us raising this particular error. 648 for name, value in unknown_flags: 649 suggestions = _helpers.get_flag_suggestions(name, list(self)) 650 raise _exceptions.UnrecognizedFlagError( 651 name, value, suggestions=suggestions) 652 653 self.mark_as_parsed() 654 self.validate_all_flags() 655 return [program_name] + unparsed_args 656 657 def __getstate__(self): 658 raise TypeError("can't pickle FlagValues") 659 660 def __copy__(self): 661 raise TypeError('FlagValues does not support shallow copies. ' 662 'Use absl.testing.flagsaver or copy.deepcopy instead.') 663 664 def __deepcopy__(self, memo): 665 result = object.__new__(type(self)) 666 result.__dict__.update(copy.deepcopy(self.__dict__, memo)) 667 return result 668 669 def _set_is_retired_flag_func(self, is_retired_flag_func): 670 """Sets a function for checking retired flags. 671 672 Do not use it. This is a private absl API used to check retired flags 673 registered by the absl C++ flags library. 674 675 Args: 676 is_retired_flag_func: Callable(str) -> (bool, bool), a function takes flag 677 name as parameter, returns a tuple (is_retired, type_is_bool). 678 """ 679 self.__dict__['__is_retired_flag_func'] = is_retired_flag_func 680 681 def _parse_args(self, args, known_only): 682 """Helper function to do the main argument parsing. 683 684 This function goes through args and does the bulk of the flag parsing. 685 It will find the corresponding flag in our flag dictionary, and call its 686 .parse() method on the flag value. 687 688 Args: 689 args: [str], a list of strings with the arguments to parse. 690 known_only: bool, if True, parse and remove known flags; return the rest 691 untouched. Unknown flags specified by --undefok are not returned. 692 693 Returns: 694 A tuple with the following: 695 unknown_flags: List of (flag name, arg) for flags we don't know about. 696 unparsed_args: List of arguments we did not parse. 697 698 Raises: 699 Error: Raised on any parsing error. 700 ValueError: Raised on flag value parsing error. 701 """ 702 unparsed_names_and_args = [] # A list of (flag name or None, arg). 703 undefok = set() 704 retired_flag_func = self.__dict__['__is_retired_flag_func'] 705 706 flag_dict = self._flags() 707 args = iter(args) 708 for arg in args: 709 value = None 710 711 def get_value(): 712 # pylint: disable=cell-var-from-loop 713 try: 714 return next(args) if value is None else value 715 except StopIteration: 716 raise _exceptions.Error('Missing value for flag ' + arg) # pylint: disable=undefined-loop-variable 717 718 if not arg.startswith('-'): 719 # A non-argument: default is break, GNU is skip. 720 unparsed_names_and_args.append((None, arg)) 721 if self.is_gnu_getopt(): 722 continue 723 else: 724 break 725 726 if arg == '--': 727 if known_only: 728 unparsed_names_and_args.append((None, arg)) 729 break 730 731 # At this point, arg must start with '-'. 732 if arg.startswith('--'): 733 arg_without_dashes = arg[2:] 734 else: 735 arg_without_dashes = arg[1:] 736 737 if '=' in arg_without_dashes: 738 name, value = arg_without_dashes.split('=', 1) 739 else: 740 name, value = arg_without_dashes, None 741 742 if not name: 743 # The argument is all dashes (including one dash). 744 unparsed_names_and_args.append((None, arg)) 745 if self.is_gnu_getopt(): 746 continue 747 else: 748 break 749 750 # --undefok is a special case. 751 if name == 'undefok': 752 value = get_value() 753 undefok.update(v.strip() for v in value.split(',')) 754 undefok.update('no' + v.strip() for v in value.split(',')) 755 continue 756 757 flag = flag_dict.get(name) 758 if flag is not None: 759 if flag.boolean and value is None: 760 value = 'true' 761 else: 762 value = get_value() 763 elif name.startswith('no') and len(name) > 2: 764 # Boolean flags can take the form of --noflag, with no value. 765 noflag = flag_dict.get(name[2:]) 766 if noflag is not None and noflag.boolean: 767 if value is not None: 768 raise ValueError(arg + ' does not take an argument') 769 flag = noflag 770 value = 'false' 771 772 if retired_flag_func and flag is None: 773 is_retired, is_bool = retired_flag_func(name) 774 775 # If we didn't recognize that flag, but it starts with 776 # "no" then maybe it was a boolean flag specified in the 777 # --nofoo form. 778 if not is_retired and name.startswith('no'): 779 is_retired, is_bool = retired_flag_func(name[2:]) 780 is_retired = is_retired and is_bool 781 782 if is_retired: 783 if not is_bool and value is None: 784 # This happens when a non-bool retired flag is specified 785 # in format of "--flag value". 786 get_value() 787 logging.error( 788 'Flag "%s" is retired and should no longer ' 789 'be specified. See go/totw/90.', name) 790 continue 791 792 if flag is not None: 793 flag.parse(value) 794 flag.using_default_value = False 795 else: 796 unparsed_names_and_args.append((name, arg)) 797 798 unknown_flags = [] 799 unparsed_args = [] 800 for name, arg in unparsed_names_and_args: 801 if name is None: 802 # Positional arguments. 803 unparsed_args.append(arg) 804 elif name in undefok: 805 # Remove undefok flags. 806 continue 807 else: 808 # This is an unknown flag. 809 if known_only: 810 unparsed_args.append(arg) 811 else: 812 unknown_flags.append((name, arg)) 813 814 unparsed_args.extend(list(args)) 815 return unknown_flags, unparsed_args 816 817 def is_parsed(self): 818 """Returns whether flags were parsed.""" 819 return self.__dict__['__flags_parsed'] 820 821 def mark_as_parsed(self): 822 """Explicitly marks flags as parsed. 823 824 Use this when the caller knows that this FlagValues has been parsed as if 825 a ``__call__()`` invocation has happened. This is only a public method for 826 use by things like appcommands which do additional command like parsing. 827 """ 828 self.__dict__['__flags_parsed'] = True 829 830 def unparse_flags(self): 831 """Unparses all flags to the point before any FLAGS(argv) was called.""" 832 for f in self._flags().values(): 833 f.unparse() 834 # We log this message before marking flags as unparsed to avoid a 835 # problem when the logging library causes flags access. 836 logging.info('unparse_flags() called; flags access will now raise errors.') 837 self.__dict__['__flags_parsed'] = False 838 self.__dict__['__unparse_flags_called'] = True 839 840 def flag_values_dict(self): 841 """Returns a dictionary that maps flag names to flag values.""" 842 return {name: flag.value for name, flag in self._flags().items()} 843 844 def __str__(self): 845 """Returns a help string for all known flags.""" 846 return self.get_help() 847 848 def get_help(self, prefix='', include_special_flags=True): 849 """Returns a help string for all known flags. 850 851 Args: 852 prefix: str, per-line output prefix. 853 include_special_flags: bool, whether to include description of 854 SPECIAL_FLAGS, i.e. --flagfile and --undefok. 855 856 Returns: 857 str, formatted help message. 858 """ 859 flags_by_module = self.flags_by_module_dict() 860 if flags_by_module: 861 modules = sorted(flags_by_module) 862 # Print the help for the main module first, if possible. 863 main_module = sys.argv[0] 864 if main_module in modules: 865 modules.remove(main_module) 866 modules = [main_module] + modules 867 return self._get_help_for_modules(modules, prefix, include_special_flags) 868 else: 869 output_lines = [] 870 # Just print one long list of flags. 871 values = self._flags().values() 872 if include_special_flags: 873 values = itertools.chain( 874 values, _helpers.SPECIAL_FLAGS._flags().values()) # pylint: disable=protected-access 875 self._render_flag_list(values, output_lines, prefix) 876 return '\n'.join(output_lines) 877 878 def _get_help_for_modules(self, modules, prefix, include_special_flags): 879 """Returns the help string for a list of modules. 880 881 Private to absl.flags package. 882 883 Args: 884 modules: List[str], a list of modules to get the help string for. 885 prefix: str, a string that is prepended to each generated help line. 886 include_special_flags: bool, whether to include description of 887 SPECIAL_FLAGS, i.e. --flagfile and --undefok. 888 """ 889 output_lines = [] 890 for module in modules: 891 self._render_our_module_flags(module, output_lines, prefix) 892 if include_special_flags: 893 self._render_module_flags( 894 'absl.flags', 895 _helpers.SPECIAL_FLAGS._flags().values(), # pylint: disable=protected-access 896 output_lines, 897 prefix) 898 return '\n'.join(output_lines) 899 900 def _render_module_flags(self, module, flags, output_lines, prefix=''): 901 """Returns a help string for a given module.""" 902 if not isinstance(module, str): 903 module = module.__name__ 904 output_lines.append('\n%s%s:' % (prefix, module)) 905 self._render_flag_list(flags, output_lines, prefix + ' ') 906 907 def _render_our_module_flags(self, module, output_lines, prefix=''): 908 """Returns a help string for a given module.""" 909 flags = self.get_flags_for_module(module) 910 if flags: 911 self._render_module_flags(module, flags, output_lines, prefix) 912 913 def _render_our_module_key_flags(self, module, output_lines, prefix=''): 914 """Returns a help string for the key flags of a given module. 915 916 Args: 917 module: module|str, the module to render key flags for. 918 output_lines: [str], a list of strings. The generated help message lines 919 will be appended to this list. 920 prefix: str, a string that is prepended to each generated help line. 921 """ 922 key_flags = self.get_key_flags_for_module(module) 923 if key_flags: 924 self._render_module_flags(module, key_flags, output_lines, prefix) 925 926 def module_help(self, module): 927 """Describes the key flags of a module. 928 929 Args: 930 module: module|str, the module to describe the key flags for. 931 932 Returns: 933 str, describing the key flags of a module. 934 """ 935 helplist = [] 936 self._render_our_module_key_flags(module, helplist) 937 return '\n'.join(helplist) 938 939 def main_module_help(self): 940 """Describes the key flags of the main module. 941 942 Returns: 943 str, describing the key flags of the main module. 944 """ 945 return self.module_help(sys.argv[0]) 946 947 def _render_flag_list(self, flaglist, output_lines, prefix=' '): 948 fl = self._flags() 949 special_fl = _helpers.SPECIAL_FLAGS._flags() # pylint: disable=protected-access 950 flaglist = [(flag.name, flag) for flag in flaglist] 951 flaglist.sort() 952 flagset = {} 953 for (name, flag) in flaglist: 954 # It's possible this flag got deleted or overridden since being 955 # registered in the per-module flaglist. Check now against the 956 # canonical source of current flag information, the _flags. 957 if fl.get(name, None) != flag and special_fl.get(name, None) != flag: 958 # a different flag is using this name now 959 continue 960 # only print help once 961 if flag in flagset: 962 continue 963 flagset[flag] = 1 964 flaghelp = '' 965 if flag.short_name: 966 flaghelp += '-%s,' % flag.short_name 967 if flag.boolean: 968 flaghelp += '--[no]%s:' % flag.name 969 else: 970 flaghelp += '--%s:' % flag.name 971 flaghelp += ' ' 972 if flag.help: 973 flaghelp += flag.help 974 flaghelp = _helpers.text_wrap( 975 flaghelp, indent=prefix + ' ', firstline_indent=prefix) 976 if flag.default_as_str: 977 flaghelp += '\n' 978 flaghelp += _helpers.text_wrap( 979 '(default: %s)' % flag.default_as_str, indent=prefix + ' ') 980 if flag.parser.syntactic_help: 981 flaghelp += '\n' 982 flaghelp += _helpers.text_wrap( 983 '(%s)' % flag.parser.syntactic_help, indent=prefix + ' ') 984 output_lines.append(flaghelp) 985 986 def get_flag_value(self, name, default): # pylint: disable=invalid-name 987 """Returns the value of a flag (if not None) or a default value. 988 989 Args: 990 name: str, the name of a flag. 991 default: Default value to use if the flag value is None. 992 993 Returns: 994 Requested flag value or default. 995 """ 996 997 value = self.__getattr__(name) 998 if value is not None: # Can't do if not value, b/c value might be '0' or "" 999 return value 1000 else: 1001 return default 1002 1003 def _is_flag_file_directive(self, flag_string): 1004 """Checks whether flag_string contain a --flagfile=<foo> directive.""" 1005 if isinstance(flag_string, str): 1006 if flag_string.startswith('--flagfile='): 1007 return 1 1008 elif flag_string == '--flagfile': 1009 return 1 1010 elif flag_string.startswith('-flagfile='): 1011 return 1 1012 elif flag_string == '-flagfile': 1013 return 1 1014 else: 1015 return 0 1016 return 0 1017 1018 def _extract_filename(self, flagfile_str): 1019 """Returns filename from a flagfile_str of form -[-]flagfile=filename. 1020 1021 The cases of --flagfile foo and -flagfile foo shouldn't be hitting 1022 this function, as they are dealt with in the level above this 1023 function. 1024 1025 Args: 1026 flagfile_str: str, the flagfile string. 1027 1028 Returns: 1029 str, the filename from a flagfile_str of form -[-]flagfile=filename. 1030 1031 Raises: 1032 Error: Raised when illegal --flagfile is provided. 1033 """ 1034 if flagfile_str.startswith('--flagfile='): 1035 return os.path.expanduser((flagfile_str[(len('--flagfile=')):]).strip()) 1036 elif flagfile_str.startswith('-flagfile='): 1037 return os.path.expanduser((flagfile_str[(len('-flagfile=')):]).strip()) 1038 else: 1039 raise _exceptions.Error('Hit illegal --flagfile type: %s' % flagfile_str) 1040 1041 def _get_flag_file_lines(self, filename, parsed_file_stack=None): 1042 """Returns the useful (!=comments, etc) lines from a file with flags. 1043 1044 Args: 1045 filename: str, the name of the flag file. 1046 parsed_file_stack: [str], a list of the names of the files that we have 1047 recursively encountered at the current depth. MUTATED BY THIS FUNCTION 1048 (but the original value is preserved upon successfully returning from 1049 function call). 1050 1051 Returns: 1052 List of strings. See the note below. 1053 1054 NOTE(springer): This function checks for a nested --flagfile=<foo> 1055 tag and handles the lower file recursively. It returns a list of 1056 all the lines that _could_ contain command flags. This is 1057 EVERYTHING except whitespace lines and comments (lines starting 1058 with '#' or '//'). 1059 """ 1060 # For consistency with the cpp version, ignore empty values. 1061 if not filename: 1062 return [] 1063 if parsed_file_stack is None: 1064 parsed_file_stack = [] 1065 # We do a little safety check for reparsing a file we've already encountered 1066 # at a previous depth. 1067 if filename in parsed_file_stack: 1068 sys.stderr.write('Warning: Hit circular flagfile dependency. Ignoring' 1069 ' flagfile: %s\n' % (filename,)) 1070 return [] 1071 else: 1072 parsed_file_stack.append(filename) 1073 1074 line_list = [] # All line from flagfile. 1075 flag_line_list = [] # Subset of lines w/o comments, blanks, flagfile= tags. 1076 try: 1077 file_obj = open(filename, 'r') 1078 except IOError as e_msg: 1079 raise _exceptions.CantOpenFlagFileError( 1080 'ERROR:: Unable to open flagfile: %s' % e_msg) 1081 1082 with file_obj: 1083 line_list = file_obj.readlines() 1084 1085 # This is where we check each line in the file we just read. 1086 for line in line_list: 1087 if line.isspace(): 1088 pass 1089 # Checks for comment (a line that starts with '#'). 1090 elif line.startswith('#') or line.startswith('//'): 1091 pass 1092 # Checks for a nested "--flagfile=<bar>" flag in the current file. 1093 # If we find one, recursively parse down into that file. 1094 elif self._is_flag_file_directive(line): 1095 sub_filename = self._extract_filename(line) 1096 included_flags = self._get_flag_file_lines( 1097 sub_filename, parsed_file_stack=parsed_file_stack) 1098 flag_line_list.extend(included_flags) 1099 else: 1100 # Any line that's not a comment or a nested flagfile should get 1101 # copied into 2nd position. This leaves earlier arguments 1102 # further back in the list, thus giving them higher priority. 1103 flag_line_list.append(line.strip()) 1104 1105 parsed_file_stack.pop() 1106 return flag_line_list 1107 1108 def read_flags_from_files(self, argv, force_gnu=True): 1109 """Processes command line args, but also allow args to be read from file. 1110 1111 Args: 1112 argv: [str], a list of strings, usually sys.argv[1:], which may contain 1113 one or more flagfile directives of the form --flagfile="./filename". 1114 Note that the name of the program (sys.argv[0]) should be omitted. 1115 force_gnu: bool, if False, --flagfile parsing obeys the 1116 FLAGS.is_gnu_getopt() value. If True, ignore the value and always follow 1117 gnu_getopt semantics. 1118 1119 Returns: 1120 A new list which has the original list combined with what we read 1121 from any flagfile(s). 1122 1123 Raises: 1124 IllegalFlagValueError: Raised when --flagfile is provided with no 1125 argument. 1126 1127 This function is called by FLAGS(argv). 1128 It scans the input list for a flag that looks like: 1129 --flagfile=<somefile>. Then it opens <somefile>, reads all valid key 1130 and value pairs and inserts them into the input list in exactly the 1131 place where the --flagfile arg is found. 1132 1133 Note that your application's flags are still defined the usual way 1134 using absl.flags DEFINE_flag() type functions. 1135 1136 Notes (assuming we're getting a commandline of some sort as our input): 1137 1138 * For duplicate flags, the last one we hit should "win". 1139 * Since flags that appear later win, a flagfile's settings can be "weak" 1140 if the --flagfile comes at the beginning of the argument sequence, 1141 and it can be "strong" if the --flagfile comes at the end. 1142 * A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile. 1143 It will be expanded in exactly the spot where it is found. 1144 * In a flagfile, a line beginning with # or // is a comment. 1145 * Entirely blank lines _should_ be ignored. 1146 """ 1147 rest_of_args = argv 1148 new_argv = [] 1149 while rest_of_args: 1150 current_arg = rest_of_args[0] 1151 rest_of_args = rest_of_args[1:] 1152 if self._is_flag_file_directive(current_arg): 1153 # This handles the case of -(-)flagfile foo. In this case the 1154 # next arg really is part of this one. 1155 if current_arg == '--flagfile' or current_arg == '-flagfile': 1156 if not rest_of_args: 1157 raise _exceptions.IllegalFlagValueError( 1158 '--flagfile with no argument') 1159 flag_filename = os.path.expanduser(rest_of_args[0]) 1160 rest_of_args = rest_of_args[1:] 1161 else: 1162 # This handles the case of (-)-flagfile=foo. 1163 flag_filename = self._extract_filename(current_arg) 1164 new_argv.extend(self._get_flag_file_lines(flag_filename)) 1165 else: 1166 new_argv.append(current_arg) 1167 # Stop parsing after '--', like getopt and gnu_getopt. 1168 if current_arg == '--': 1169 break 1170 # Stop parsing after a non-flag, like getopt. 1171 if not current_arg.startswith('-'): 1172 if not force_gnu and not self.__dict__['__use_gnu_getopt']: 1173 break 1174 else: 1175 if ('=' not in current_arg and rest_of_args and 1176 not rest_of_args[0].startswith('-')): 1177 # If this is an occurrence of a legitimate --x y, skip the value 1178 # so that it won't be mistaken for a standalone arg. 1179 fl = self._flags() 1180 name = current_arg.lstrip('-') 1181 if name in fl and not fl[name].boolean: 1182 current_arg = rest_of_args[0] 1183 rest_of_args = rest_of_args[1:] 1184 new_argv.append(current_arg) 1185 1186 if rest_of_args: 1187 new_argv.extend(rest_of_args) 1188 1189 return new_argv 1190 1191 def flags_into_string(self): 1192 """Returns a string with the flags assignments from this FlagValues object. 1193 1194 This function ignores flags whose value is None. Each flag 1195 assignment is separated by a newline. 1196 1197 NOTE: MUST mirror the behavior of the C++ CommandlineFlagsIntoString 1198 from https://github.com/gflags/gflags. 1199 1200 Returns: 1201 str, the string with the flags assignments from this FlagValues object. 1202 The flags are ordered by (module_name, flag_name). 1203 """ 1204 module_flags = sorted(self.flags_by_module_dict().items()) 1205 s = '' 1206 for unused_module_name, flags in module_flags: 1207 flags = sorted(flags, key=lambda f: f.name) 1208 for flag in flags: 1209 if flag.value is not None: 1210 s += flag.serialize() + '\n' 1211 return s 1212 1213 def append_flags_into_file(self, filename): 1214 """Appends all flags assignments from this FlagInfo object to a file. 1215 1216 Output will be in the format of a flagfile. 1217 1218 NOTE: MUST mirror the behavior of the C++ AppendFlagsIntoFile 1219 from https://github.com/gflags/gflags. 1220 1221 Args: 1222 filename: str, name of the file. 1223 """ 1224 with open(filename, 'a') as out_file: 1225 out_file.write(self.flags_into_string()) 1226 1227 def write_help_in_xml_format(self, outfile=None): 1228 """Outputs flag documentation in XML format. 1229 1230 NOTE: We use element names that are consistent with those used by 1231 the C++ command-line flag library, from 1232 https://github.com/gflags/gflags. 1233 We also use a few new elements (e.g., <key>), but we do not 1234 interfere / overlap with existing XML elements used by the C++ 1235 library. Please maintain this consistency. 1236 1237 Args: 1238 outfile: File object we write to. Default None means sys.stdout. 1239 """ 1240 doc = minidom.Document() 1241 all_flag = doc.createElement('AllFlags') 1242 doc.appendChild(all_flag) 1243 1244 all_flag.appendChild( 1245 _helpers.create_xml_dom_element(doc, 'program', 1246 os.path.basename(sys.argv[0]))) 1247 1248 usage_doc = sys.modules['__main__'].__doc__ 1249 if not usage_doc: 1250 usage_doc = '\nUSAGE: %s [flags]\n' % sys.argv[0] 1251 else: 1252 usage_doc = usage_doc.replace('%s', sys.argv[0]) 1253 all_flag.appendChild( 1254 _helpers.create_xml_dom_element(doc, 'usage', usage_doc)) 1255 1256 # Get list of key flags for the main module. 1257 key_flags = self.get_key_flags_for_module(sys.argv[0]) 1258 1259 # Sort flags by declaring module name and next by flag name. 1260 flags_by_module = self.flags_by_module_dict() 1261 all_module_names = list(flags_by_module.keys()) 1262 all_module_names.sort() 1263 for module_name in all_module_names: 1264 flag_list = [(f.name, f) for f in flags_by_module[module_name]] 1265 flag_list.sort() 1266 for unused_flag_name, flag in flag_list: 1267 is_key = flag in key_flags 1268 all_flag.appendChild( 1269 flag._create_xml_dom_element( # pylint: disable=protected-access 1270 doc, 1271 module_name, 1272 is_key=is_key)) 1273 1274 outfile = outfile or sys.stdout 1275 outfile.write( 1276 doc.toprettyxml(indent=' ', encoding='utf-8').decode('utf-8')) 1277 outfile.flush() 1278 1279 def _check_method_name_conflicts(self, name, flag): 1280 if flag.allow_using_method_names: 1281 return 1282 short_name = flag.short_name 1283 flag_names = {name} if short_name is None else {name, short_name} 1284 for flag_name in flag_names: 1285 if flag_name in self.__dict__['__banned_flag_names']: 1286 raise _exceptions.FlagNameConflictsWithMethodError( 1287 'Cannot define a flag named "{name}". It conflicts with a method ' 1288 'on class "{class_name}". To allow defining it, use ' 1289 'allow_using_method_names and access the flag value with ' 1290 "FLAGS['{name}'].value. FLAGS.{name} returns the method, " 1291 'not the flag value.'.format( 1292 name=flag_name, class_name=type(self).__name__)) 1293 1294 1295FLAGS = FlagValues() 1296 1297 1298class FlagHolder(Generic[_T]): 1299 """Holds a defined flag. 1300 1301 This facilitates a cleaner api around global state. Instead of:: 1302 1303 flags.DEFINE_integer('foo', ...) 1304 flags.DEFINE_integer('bar', ...) 1305 1306 def method(): 1307 # prints parsed value of 'bar' flag 1308 print(flags.FLAGS.foo) 1309 # runtime error due to typo or possibly bad coding style. 1310 print(flags.FLAGS.baz) 1311 1312 it encourages code like:: 1313 1314 _FOO_FLAG = flags.DEFINE_integer('foo', ...) 1315 _BAR_FLAG = flags.DEFINE_integer('bar', ...) 1316 1317 def method(): 1318 print(_FOO_FLAG.value) 1319 print(_BAR_FLAG.value) 1320 1321 since the name of the flag appears only once in the source code. 1322 """ 1323 1324 def __init__(self, flag_values, flag, ensure_non_none_value=False): 1325 """Constructs a FlagHolder instance providing typesafe access to flag. 1326 1327 Args: 1328 flag_values: The container the flag is registered to. 1329 flag: The flag object for this flag. 1330 ensure_non_none_value: Is the value of the flag allowed to be None. 1331 """ 1332 self._flagvalues = flag_values 1333 # We take the entire flag object, but only keep the name. Why? 1334 # - We want FlagHolder[T] to be generic container 1335 # - flag_values contains all flags, so has no reference to T. 1336 # - typecheckers don't like to see a generic class where none of the ctor 1337 # arguments refer to the generic type. 1338 self._name = flag.name 1339 # We intentionally do NOT check if the default value is None. 1340 # This allows future use of this for "required flags with None default" 1341 self._ensure_non_none_value = ensure_non_none_value 1342 1343 def __eq__(self, other): 1344 raise TypeError( 1345 "unsupported operand type(s) for ==: '{0}' and '{1}' " 1346 "(did you mean to use '{0}.value' instead?)".format( 1347 type(self).__name__, type(other).__name__)) 1348 1349 def __bool__(self): 1350 raise TypeError( 1351 "bool() not supported for instances of type '{0}' " 1352 "(did you mean to use '{0}.value' instead?)".format( 1353 type(self).__name__)) 1354 1355 __nonzero__ = __bool__ 1356 1357 @property 1358 def name(self): 1359 return self._name 1360 1361 @property 1362 def value(self): 1363 """Returns the value of the flag. 1364 1365 If ``_ensure_non_none_value`` is ``True``, then return value is not 1366 ``None``. 1367 1368 Raises: 1369 UnparsedFlagAccessError: if flag parsing has not finished. 1370 IllegalFlagValueError: if value is None unexpectedly. 1371 """ 1372 val = getattr(self._flagvalues, self._name) 1373 if self._ensure_non_none_value and val is None: 1374 raise _exceptions.IllegalFlagValueError( 1375 'Unexpected None value for flag %s' % self._name) 1376 return val 1377 1378 @property 1379 def default(self): 1380 """Returns the default value of the flag.""" 1381 return self._flagvalues[self._name].default 1382 1383 @property 1384 def present(self): 1385 """Returns True if the flag was parsed from command-line flags.""" 1386 return bool(self._flagvalues[self._name].present) 1387 1388 1389def resolve_flag_ref(flag_ref, flag_values): 1390 """Helper to validate and resolve a flag reference argument.""" 1391 if isinstance(flag_ref, FlagHolder): 1392 new_flag_values = flag_ref._flagvalues # pylint: disable=protected-access 1393 if flag_values != FLAGS and flag_values != new_flag_values: 1394 raise ValueError( 1395 'flag_values must not be customized when operating on a FlagHolder') 1396 return flag_ref.name, new_flag_values 1397 return flag_ref, flag_values 1398 1399 1400def resolve_flag_refs(flag_refs, flag_values): 1401 """Helper to validate and resolve flag reference list arguments.""" 1402 fv = None 1403 names = [] 1404 for ref in flag_refs: 1405 if isinstance(ref, FlagHolder): 1406 newfv = ref._flagvalues # pylint: disable=protected-access 1407 name = ref.name 1408 else: 1409 newfv = flag_values 1410 name = ref 1411 if fv and fv != newfv: 1412 raise ValueError( 1413 'multiple FlagValues instances used in invocation. ' 1414 'FlagHolders must be registered to the same FlagValues instance as ' 1415 'do flag names, if provided.') 1416 fv = newfv 1417 names.append(name) 1418 return names, fv 1419