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"""Tests for absl.flags used as a package.""" 15 16import contextlib 17import enum 18import io 19import os 20import shutil 21import sys 22import tempfile 23import unittest 24 25from absl import flags 26from absl.flags import _exceptions 27from absl.flags import _helpers 28from absl.flags.tests import module_bar 29from absl.flags.tests import module_baz 30from absl.flags.tests import module_foo 31from absl.testing import absltest 32 33FLAGS = flags.FLAGS 34 35 36@contextlib.contextmanager 37def _use_gnu_getopt(flag_values, use_gnu_get_opt): 38 old_use_gnu_get_opt = flag_values.is_gnu_getopt() 39 flag_values.set_gnu_getopt(use_gnu_get_opt) 40 yield 41 flag_values.set_gnu_getopt(old_use_gnu_get_opt) 42 43 44class FlagDictToArgsTest(absltest.TestCase): 45 46 def test_flatten_google_flag_map(self): 47 arg_dict = { 48 'week-end': None, 49 'estudia': False, 50 'trabaja': False, 51 'party': True, 52 'monday': 'party', 53 'score': 42, 54 'loadthatstuff': [42, 'hello', 'goodbye'], 55 } 56 self.assertSameElements( 57 ('--week-end', '--noestudia', '--notrabaja', '--party', 58 '--monday=party', '--score=42', '--loadthatstuff=42,hello,goodbye'), 59 flags.flag_dict_to_args(arg_dict)) 60 61 def test_flatten_google_flag_map_with_multi_flag(self): 62 arg_dict = { 63 'some_list': ['value1', 'value2'], 64 'some_multi_string': ['value3', 'value4'], 65 } 66 self.assertSameElements( 67 ('--some_list=value1,value2', '--some_multi_string=value3', 68 '--some_multi_string=value4'), 69 flags.flag_dict_to_args(arg_dict, multi_flags={'some_multi_string'})) 70 71 72class Fruit(enum.Enum): 73 APPLE = object() 74 ORANGE = object() 75 76 77class CaseSensitiveFruit(enum.Enum): 78 apple = 1 79 orange = 2 80 APPLE = 3 81 82 83class EmptyEnum(enum.Enum): 84 pass 85 86 87class AliasFlagsTest(absltest.TestCase): 88 89 def setUp(self): 90 super(AliasFlagsTest, self).setUp() 91 self.flags = flags.FlagValues() 92 93 @property 94 def alias(self): 95 return self.flags['alias'] 96 97 @property 98 def aliased(self): 99 return self.flags['aliased'] 100 101 def define_alias(self, *args, **kwargs): 102 flags.DEFINE_alias(*args, flag_values=self.flags, **kwargs) 103 104 def define_integer(self, *args, **kwargs): 105 flags.DEFINE_integer(*args, flag_values=self.flags, **kwargs) 106 107 def define_multi_integer(self, *args, **kwargs): 108 flags.DEFINE_multi_integer(*args, flag_values=self.flags, **kwargs) 109 110 def define_string(self, *args, **kwargs): 111 flags.DEFINE_string(*args, flag_values=self.flags, **kwargs) 112 113 def assert_alias_mirrors_aliased(self, alias, aliased, ignore_due_to_bug=()): 114 # A few sanity checks to avoid false success 115 self.assertIn('FlagAlias', alias.__class__.__qualname__) 116 self.assertIsNot(alias, aliased) 117 self.assertNotEqual(aliased.name, alias.name) 118 119 alias_state = {} 120 aliased_state = {} 121 attrs = { 122 'allow_hide_cpp', 123 'allow_override', 124 'allow_override_cpp', 125 'allow_overwrite', 126 'allow_using_method_names', 127 'boolean', 128 'default', 129 'default_as_str', 130 'default_unparsed', 131 # TODO(rlevasseur): This should match, but a bug prevents it from being 132 # in sync. 133 # 'using_default_value', 134 'value', 135 } 136 attrs.difference_update(ignore_due_to_bug) 137 138 for attr in attrs: 139 alias_state[attr] = getattr(alias, attr) 140 aliased_state[attr] = getattr(aliased, attr) 141 142 self.assertEqual(aliased_state, alias_state, 'LHS is aliased; RHS is alias') 143 144 def test_serialize_multi(self): 145 self.define_multi_integer('aliased', [0, 1], '') 146 self.define_alias('alias', 'aliased') 147 148 actual = self.alias.serialize() 149 # TODO(rlevasseur): This should check for --alias=0\n--alias=1, but 150 # a bug causes it to serialize incorrectly. 151 self.assertEqual('--alias=[0, 1]', actual) 152 153 def test_allow_overwrite_false(self): 154 self.define_integer('aliased', None, 'help', allow_overwrite=False) 155 self.define_alias('alias', 'aliased') 156 157 with self.assertRaisesRegex(flags.IllegalFlagValueError, 'already defined'): 158 self.flags(['./program', '--alias=1', '--aliased=2']) 159 160 self.assertEqual(1, self.alias.value) 161 self.assertEqual(1, self.aliased.value) 162 163 def test_aliasing_multi_no_default(self): 164 165 def define_flags(): 166 self.flags = flags.FlagValues() 167 self.define_multi_integer('aliased', None, 'help') 168 self.define_alias('alias', 'aliased') 169 170 with self.subTest('after defining'): 171 define_flags() 172 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 173 self.assertIsNone(self.alias.value) 174 175 with self.subTest('set alias'): 176 define_flags() 177 self.flags(['./program', '--alias=1', '--alias=2']) 178 self.assertEqual([1, 2], self.alias.value) 179 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 180 181 with self.subTest('set aliased'): 182 define_flags() 183 self.flags(['./program', '--aliased=1', '--aliased=2']) 184 self.assertEqual([1, 2], self.alias.value) 185 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 186 187 with self.subTest('not setting anything'): 188 define_flags() 189 self.flags(['./program']) 190 self.assertEqual(None, self.alias.value) 191 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 192 193 def test_aliasing_multi_with_default(self): 194 195 def define_flags(): 196 self.flags = flags.FlagValues() 197 self.define_multi_integer('aliased', [0], 'help') 198 self.define_alias('alias', 'aliased') 199 200 with self.subTest('after defining'): 201 define_flags() 202 self.assertEqual([0], self.alias.default) 203 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 204 205 with self.subTest('set alias'): 206 define_flags() 207 self.flags(['./program', '--alias=1', '--alias=2']) 208 self.assertEqual([1, 2], self.alias.value) 209 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 210 211 self.assertEqual(2, self.alias.present) 212 # TODO(rlevasseur): This should assert 0, but a bug with aliases and 213 # MultiFlag causes the alias to increment aliased's present counter. 214 self.assertEqual(2, self.aliased.present) 215 216 with self.subTest('set aliased'): 217 define_flags() 218 self.flags(['./program', '--aliased=1', '--aliased=2']) 219 self.assertEqual([1, 2], self.alias.value) 220 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 221 self.assertEqual(0, self.alias.present) 222 223 # TODO(rlevasseur): This should assert 0, but a bug with aliases and 224 # MultiFlag causes the alias to increment aliased present counter. 225 self.assertEqual(2, self.aliased.present) 226 227 with self.subTest('not setting anything'): 228 define_flags() 229 self.flags(['./program']) 230 self.assertEqual([0], self.alias.value) 231 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 232 self.assertEqual(0, self.alias.present) 233 self.assertEqual(0, self.aliased.present) 234 235 def test_aliasing_regular(self): 236 237 def define_flags(): 238 self.flags = flags.FlagValues() 239 self.define_string('aliased', '', 'help') 240 self.define_alias('alias', 'aliased') 241 242 define_flags() 243 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 244 245 self.flags(['./program', '--alias=1']) 246 self.assertEqual('1', self.alias.value) 247 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 248 self.assertEqual(1, self.alias.present) 249 self.assertEqual('--alias=1', self.alias.serialize()) 250 self.assertEqual(1, self.aliased.present) 251 252 define_flags() 253 self.flags(['./program', '--aliased=2']) 254 self.assertEqual('2', self.alias.value) 255 self.assert_alias_mirrors_aliased(self.alias, self.aliased) 256 self.assertEqual(0, self.alias.present) 257 self.assertEqual('--alias=2', self.alias.serialize()) 258 self.assertEqual(1, self.aliased.present) 259 260 def test_defining_alias_doesnt_affect_aliased_state_regular(self): 261 self.define_string('aliased', 'default', 'help') 262 self.define_alias('alias', 'aliased') 263 264 self.assertEqual(0, self.aliased.present) 265 self.assertEqual(0, self.alias.present) 266 267 def test_defining_alias_doesnt_affect_aliased_state_multi(self): 268 self.define_multi_integer('aliased', [0], 'help') 269 self.define_alias('alias', 'aliased') 270 271 self.assertEqual([0], self.aliased.value) 272 self.assertEqual([0], self.aliased.default) 273 self.assertEqual(0, self.aliased.present) 274 275 self.assertEqual([0], self.aliased.value) 276 self.assertEqual([0], self.aliased.default) 277 self.assertEqual(0, self.alias.present) 278 279 280class FlagsUnitTest(absltest.TestCase): 281 """Flags Unit Test.""" 282 283 maxDiff = None 284 285 def test_flags(self): 286 """Test normal usage with no (expected) errors.""" 287 # Define flags 288 number_test_framework_flags = len(FLAGS) 289 repeat_help = 'how many times to repeat (0-5)' 290 flags.DEFINE_integer( 291 'repeat', 4, repeat_help, lower_bound=0, short_name='r') 292 flags.DEFINE_string('name', 'Bob', 'namehelp') 293 flags.DEFINE_boolean('debug', 0, 'debughelp') 294 flags.DEFINE_boolean('q', 1, 'quiet mode') 295 flags.DEFINE_boolean('quack', 0, "superstring of 'q'") 296 flags.DEFINE_boolean('noexec', 1, 'boolean flag with no as prefix') 297 flags.DEFINE_float('float', 3.14, 'using floats') 298 flags.DEFINE_integer('octal', '0o666', 'using octals') 299 flags.DEFINE_integer('decimal', '666', 'using decimals') 300 flags.DEFINE_integer('hexadecimal', '0x666', 'using hexadecimals') 301 flags.DEFINE_integer('x', 3, 'how eXtreme to be') 302 flags.DEFINE_integer('l', 0x7fffffff00000000, 'how long to be') 303 flags.DEFINE_list('args', 'v=1,"vmodule=a=0,b=2"', 'a list of arguments') 304 flags.DEFINE_list('letters', 'a,b,c', 'a list of letters') 305 flags.DEFINE_list('numbers', [1, 2, 3], 'a list of numbers') 306 flags.DEFINE_enum('kwery', None, ['who', 'what', 'Why', 'where', 'when'], 307 '?') 308 flags.DEFINE_enum( 309 'sense', None, ['Case', 'case', 'CASE'], '?', case_sensitive=True) 310 flags.DEFINE_enum( 311 'cases', 312 None, ['UPPER', 'lower', 'Initial', 'Ot_HeR'], 313 '?', 314 case_sensitive=False) 315 flags.DEFINE_enum( 316 'funny', 317 None, ['Joke', 'ha', 'ha', 'ha', 'ha'], 318 '?', 319 case_sensitive=True) 320 flags.DEFINE_enum( 321 'blah', 322 None, ['bla', 'Blah', 'BLAH', 'blah'], 323 '?', 324 case_sensitive=False) 325 flags.DEFINE_string( 326 'only_once', None, 'test only sets this once', allow_overwrite=False) 327 flags.DEFINE_string( 328 'universe', 329 None, 330 'test tries to set this three times', 331 allow_overwrite=False) 332 333 # Specify number of flags defined above. The short_name defined 334 # for 'repeat' counts as an extra flag. 335 number_defined_flags = 22 + 1 336 self.assertLen(FLAGS, number_defined_flags + number_test_framework_flags) 337 338 self.assertEqual(FLAGS.repeat, 4) 339 self.assertEqual(FLAGS.name, 'Bob') 340 self.assertEqual(FLAGS.debug, 0) 341 self.assertEqual(FLAGS.q, 1) 342 self.assertEqual(FLAGS.octal, 0o666) 343 self.assertEqual(FLAGS.decimal, 666) 344 self.assertEqual(FLAGS.hexadecimal, 0x666) 345 self.assertEqual(FLAGS.x, 3) 346 self.assertEqual(FLAGS.l, 0x7fffffff00000000) 347 self.assertEqual(FLAGS.args, ['v=1', 'vmodule=a=0,b=2']) 348 self.assertEqual(FLAGS.letters, ['a', 'b', 'c']) 349 self.assertEqual(FLAGS.numbers, [1, 2, 3]) 350 self.assertIsNone(FLAGS.kwery) 351 self.assertIsNone(FLAGS.sense) 352 self.assertIsNone(FLAGS.cases) 353 self.assertIsNone(FLAGS.funny) 354 self.assertIsNone(FLAGS.blah) 355 356 flag_values = FLAGS.flag_values_dict() 357 self.assertEqual(flag_values['repeat'], 4) 358 self.assertEqual(flag_values['name'], 'Bob') 359 self.assertEqual(flag_values['debug'], 0) 360 self.assertEqual(flag_values['r'], 4) # Short for repeat. 361 self.assertEqual(flag_values['q'], 1) 362 self.assertEqual(flag_values['quack'], 0) 363 self.assertEqual(flag_values['x'], 3) 364 self.assertEqual(flag_values['l'], 0x7fffffff00000000) 365 self.assertEqual(flag_values['args'], ['v=1', 'vmodule=a=0,b=2']) 366 self.assertEqual(flag_values['letters'], ['a', 'b', 'c']) 367 self.assertEqual(flag_values['numbers'], [1, 2, 3]) 368 self.assertIsNone(flag_values['kwery']) 369 self.assertIsNone(flag_values['sense']) 370 self.assertIsNone(flag_values['cases']) 371 self.assertIsNone(flag_values['funny']) 372 self.assertIsNone(flag_values['blah']) 373 374 # Verify string form of defaults 375 self.assertEqual(FLAGS['repeat'].default_as_str, "'4'") 376 self.assertEqual(FLAGS['name'].default_as_str, "'Bob'") 377 self.assertEqual(FLAGS['debug'].default_as_str, "'false'") 378 self.assertEqual(FLAGS['q'].default_as_str, "'true'") 379 self.assertEqual(FLAGS['quack'].default_as_str, "'false'") 380 self.assertEqual(FLAGS['noexec'].default_as_str, "'true'") 381 self.assertEqual(FLAGS['x'].default_as_str, "'3'") 382 self.assertEqual(FLAGS['l'].default_as_str, "'9223372032559808512'") 383 self.assertEqual(FLAGS['args'].default_as_str, '\'v=1,"vmodule=a=0,b=2"\'') 384 self.assertEqual(FLAGS['letters'].default_as_str, "'a,b,c'") 385 self.assertEqual(FLAGS['numbers'].default_as_str, "'1,2,3'") 386 387 # Verify that the iterator for flags yields all the keys 388 keys = list(FLAGS) 389 keys.sort() 390 reg_flags = list(FLAGS._flags()) 391 reg_flags.sort() 392 self.assertEqual(keys, reg_flags) 393 394 # Parse flags 395 # .. empty command line 396 argv = ('./program',) 397 argv = FLAGS(argv) 398 self.assertLen(argv, 1, 'wrong number of arguments pulled') 399 self.assertEqual(argv[0], './program', 'program name not preserved') 400 401 # .. non-empty command line 402 argv = ('./program', '--debug', '--name=Bob', '-q', '--x=8') 403 argv = FLAGS(argv) 404 self.assertLen(argv, 1, 'wrong number of arguments pulled') 405 self.assertEqual(argv[0], './program', 'program name not preserved') 406 self.assertEqual(FLAGS['debug'].present, 1) 407 FLAGS['debug'].present = 0 # Reset 408 self.assertEqual(FLAGS['name'].present, 1) 409 FLAGS['name'].present = 0 # Reset 410 self.assertEqual(FLAGS['q'].present, 1) 411 FLAGS['q'].present = 0 # Reset 412 self.assertEqual(FLAGS['x'].present, 1) 413 FLAGS['x'].present = 0 # Reset 414 415 # Flags list. 416 self.assertLen(FLAGS, number_defined_flags + number_test_framework_flags) 417 self.assertIn('name', FLAGS) 418 self.assertIn('debug', FLAGS) 419 self.assertIn('repeat', FLAGS) 420 self.assertIn('r', FLAGS) 421 self.assertIn('q', FLAGS) 422 self.assertIn('quack', FLAGS) 423 self.assertIn('x', FLAGS) 424 self.assertIn('l', FLAGS) 425 self.assertIn('args', FLAGS) 426 self.assertIn('letters', FLAGS) 427 self.assertIn('numbers', FLAGS) 428 429 # __contains__ 430 self.assertIn('name', FLAGS) 431 self.assertNotIn('name2', FLAGS) 432 433 # try deleting a flag 434 del FLAGS.r 435 self.assertLen(FLAGS, 436 number_defined_flags - 1 + number_test_framework_flags) 437 self.assertNotIn('r', FLAGS) 438 439 # .. command line with extra stuff 440 argv = ('./program', '--debug', '--name=Bob', 'extra') 441 argv = FLAGS(argv) 442 self.assertLen(argv, 2, 'wrong number of arguments pulled') 443 self.assertEqual(argv[0], './program', 'program name not preserved') 444 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 445 self.assertEqual(FLAGS['debug'].present, 1) 446 FLAGS['debug'].present = 0 # Reset 447 self.assertEqual(FLAGS['name'].present, 1) 448 FLAGS['name'].present = 0 # Reset 449 450 # Test reset 451 argv = ('./program', '--debug') 452 argv = FLAGS(argv) 453 self.assertLen(argv, 1, 'wrong number of arguments pulled') 454 self.assertEqual(argv[0], './program', 'program name not preserved') 455 self.assertEqual(FLAGS['debug'].present, 1) 456 self.assertTrue(FLAGS['debug'].value) 457 FLAGS.unparse_flags() 458 self.assertEqual(FLAGS['debug'].present, 0) 459 self.assertFalse(FLAGS['debug'].value) 460 461 # Test that reset restores default value when default value is None. 462 argv = ('./program', '--kwery=who') 463 argv = FLAGS(argv) 464 self.assertLen(argv, 1, 'wrong number of arguments pulled') 465 self.assertEqual(argv[0], './program', 'program name not preserved') 466 self.assertEqual(FLAGS['kwery'].present, 1) 467 self.assertEqual(FLAGS['kwery'].value, 'who') 468 FLAGS.unparse_flags() 469 argv = ('./program', '--kwery=Why') 470 argv = FLAGS(argv) 471 self.assertLen(argv, 1, 'wrong number of arguments pulled') 472 self.assertEqual(argv[0], './program', 'program name not preserved') 473 self.assertEqual(FLAGS['kwery'].present, 1) 474 self.assertEqual(FLAGS['kwery'].value, 'Why') 475 FLAGS.unparse_flags() 476 self.assertEqual(FLAGS['kwery'].present, 0) 477 self.assertIsNone(FLAGS['kwery'].value) 478 479 # Test case sensitive enum. 480 argv = ('./program', '--sense=CASE') 481 argv = FLAGS(argv) 482 self.assertLen(argv, 1, 'wrong number of arguments pulled') 483 self.assertEqual(argv[0], './program', 'program name not preserved') 484 self.assertEqual(FLAGS['sense'].present, 1) 485 self.assertEqual(FLAGS['sense'].value, 'CASE') 486 FLAGS.unparse_flags() 487 argv = ('./program', '--sense=Case') 488 argv = FLAGS(argv) 489 self.assertLen(argv, 1, 'wrong number of arguments pulled') 490 self.assertEqual(argv[0], './program', 'program name not preserved') 491 self.assertEqual(FLAGS['sense'].present, 1) 492 self.assertEqual(FLAGS['sense'].value, 'Case') 493 FLAGS.unparse_flags() 494 495 # Test case insensitive enum. 496 argv = ('./program', '--cases=upper') 497 argv = FLAGS(argv) 498 self.assertLen(argv, 1, 'wrong number of arguments pulled') 499 self.assertEqual(argv[0], './program', 'program name not preserved') 500 self.assertEqual(FLAGS['cases'].present, 1) 501 self.assertEqual(FLAGS['cases'].value, 'UPPER') 502 FLAGS.unparse_flags() 503 504 # Test case sensitive enum with duplicates. 505 argv = ('./program', '--funny=ha') 506 argv = FLAGS(argv) 507 self.assertLen(argv, 1, 'wrong number of arguments pulled') 508 self.assertEqual(argv[0], './program', 'program name not preserved') 509 self.assertEqual(FLAGS['funny'].present, 1) 510 self.assertEqual(FLAGS['funny'].value, 'ha') 511 FLAGS.unparse_flags() 512 513 # Test case insensitive enum with duplicates. 514 argv = ('./program', '--blah=bLah') 515 argv = FLAGS(argv) 516 self.assertLen(argv, 1, 'wrong number of arguments pulled') 517 self.assertEqual(argv[0], './program', 'program name not preserved') 518 self.assertEqual(FLAGS['blah'].present, 1) 519 self.assertEqual(FLAGS['blah'].value, 'Blah') 520 FLAGS.unparse_flags() 521 argv = ('./program', '--blah=BLAH') 522 argv = FLAGS(argv) 523 self.assertLen(argv, 1, 'wrong number of arguments pulled') 524 self.assertEqual(argv[0], './program', 'program name not preserved') 525 self.assertEqual(FLAGS['blah'].present, 1) 526 self.assertEqual(FLAGS['blah'].value, 'Blah') 527 FLAGS.unparse_flags() 528 529 # Test integer argument passing 530 argv = ('./program', '--x', '0x12345') 531 argv = FLAGS(argv) 532 self.assertEqual(FLAGS.x, 0x12345) 533 self.assertEqual(type(FLAGS.x), int) 534 535 argv = ('./program', '--x', '0x1234567890ABCDEF1234567890ABCDEF') 536 argv = FLAGS(argv) 537 self.assertEqual(FLAGS.x, 0x1234567890ABCDEF1234567890ABCDEF) 538 self.assertIsInstance(FLAGS.x, int) 539 540 argv = ('./program', '--x', '0o12345') 541 argv = FLAGS(argv) 542 self.assertEqual(FLAGS.x, 0o12345) 543 self.assertEqual(type(FLAGS.x), int) 544 545 # Treat 0-prefixed parameters as base-10, not base-8 546 argv = ('./program', '--x', '012345') 547 argv = FLAGS(argv) 548 self.assertEqual(FLAGS.x, 12345) 549 self.assertEqual(type(FLAGS.x), int) 550 551 argv = ('./program', '--x', '0123459') 552 argv = FLAGS(argv) 553 self.assertEqual(FLAGS.x, 123459) 554 self.assertEqual(type(FLAGS.x), int) 555 556 argv = ('./program', '--x', '0x123efg') 557 with self.assertRaises(flags.IllegalFlagValueError): 558 argv = FLAGS(argv) 559 560 # Test boolean argument parsing 561 flags.DEFINE_boolean('test0', None, 'test boolean parsing') 562 argv = ('./program', '--notest0') 563 argv = FLAGS(argv) 564 self.assertEqual(FLAGS.test0, 0) 565 566 flags.DEFINE_boolean('test1', None, 'test boolean parsing') 567 argv = ('./program', '--test1') 568 argv = FLAGS(argv) 569 self.assertEqual(FLAGS.test1, 1) 570 571 FLAGS.test0 = None 572 argv = ('./program', '--test0=false') 573 argv = FLAGS(argv) 574 self.assertEqual(FLAGS.test0, 0) 575 576 FLAGS.test1 = None 577 argv = ('./program', '--test1=true') 578 argv = FLAGS(argv) 579 self.assertEqual(FLAGS.test1, 1) 580 581 FLAGS.test0 = None 582 argv = ('./program', '--test0=0') 583 argv = FLAGS(argv) 584 self.assertEqual(FLAGS.test0, 0) 585 586 FLAGS.test1 = None 587 argv = ('./program', '--test1=1') 588 argv = FLAGS(argv) 589 self.assertEqual(FLAGS.test1, 1) 590 591 # Test booleans that already have 'no' as a prefix 592 FLAGS.noexec = None 593 argv = ('./program', '--nonoexec', '--name', 'Bob') 594 argv = FLAGS(argv) 595 self.assertEqual(FLAGS.noexec, 0) 596 597 FLAGS.noexec = None 598 argv = ('./program', '--name', 'Bob', '--noexec') 599 argv = FLAGS(argv) 600 self.assertEqual(FLAGS.noexec, 1) 601 602 # Test unassigned booleans 603 flags.DEFINE_boolean('testnone', None, 'test boolean parsing') 604 argv = ('./program',) 605 argv = FLAGS(argv) 606 self.assertIsNone(FLAGS.testnone) 607 608 # Test get with default 609 flags.DEFINE_boolean('testget1', None, 'test parsing with defaults') 610 flags.DEFINE_boolean('testget2', None, 'test parsing with defaults') 611 flags.DEFINE_boolean('testget3', None, 'test parsing with defaults') 612 flags.DEFINE_integer('testget4', None, 'test parsing with defaults') 613 argv = ('./program', '--testget1', '--notestget2') 614 argv = FLAGS(argv) 615 self.assertEqual(FLAGS.get_flag_value('testget1', 'foo'), 1) 616 self.assertEqual(FLAGS.get_flag_value('testget2', 'foo'), 0) 617 self.assertEqual(FLAGS.get_flag_value('testget3', 'foo'), 'foo') 618 self.assertEqual(FLAGS.get_flag_value('testget4', 'foo'), 'foo') 619 620 # test list code 621 lists = [['hello', 'moo', 'boo', '1'], []] 622 623 flags.DEFINE_list('testcomma_list', '', 'test comma list parsing') 624 flags.DEFINE_spaceseplist('testspace_list', '', 'tests space list parsing') 625 flags.DEFINE_spaceseplist( 626 'testspace_or_comma_list', 627 '', 628 'tests space list parsing with comma compatibility', 629 comma_compat=True) 630 631 for name, sep in (('testcomma_list', ','), ('testspace_list', 632 ' '), ('testspace_list', '\n'), 633 ('testspace_or_comma_list', 634 ' '), ('testspace_or_comma_list', 635 '\n'), ('testspace_or_comma_list', ',')): 636 for lst in lists: 637 argv = ('./program', '--%s=%s' % (name, sep.join(lst))) 638 argv = FLAGS(argv) 639 self.assertEqual(getattr(FLAGS, name), lst) 640 641 # Test help text 642 flags_help = str(FLAGS) 643 self.assertNotEqual( 644 flags_help.find('repeat'), -1, 'cannot find flag in help') 645 self.assertNotEqual( 646 flags_help.find(repeat_help), -1, 'cannot find help string in help') 647 648 # Test flag specified twice 649 argv = ('./program', '--repeat=4', '--repeat=2', '--debug', '--nodebug') 650 argv = FLAGS(argv) 651 self.assertEqual(FLAGS.get_flag_value('repeat', None), 2) 652 self.assertEqual(FLAGS.get_flag_value('debug', None), 0) 653 654 # Test MultiFlag with single default value 655 flags.DEFINE_multi_string( 656 's_str', 657 'sing1', 658 'string option that can occur multiple times', 659 short_name='s') 660 self.assertEqual(FLAGS.get_flag_value('s_str', None), ['sing1']) 661 662 # Test MultiFlag with list of default values 663 multi_string_defs = ['def1', 'def2'] 664 flags.DEFINE_multi_string( 665 'm_str', 666 multi_string_defs, 667 'string option that can occur multiple times', 668 short_name='m') 669 self.assertEqual(FLAGS.get_flag_value('m_str', None), multi_string_defs) 670 671 # Test flag specified multiple times with a MultiFlag 672 argv = ('./program', '--m_str=str1', '-m', 'str2') 673 argv = FLAGS(argv) 674 self.assertEqual(FLAGS.get_flag_value('m_str', None), ['str1', 'str2']) 675 676 # A flag with allow_overwrite set to False should behave normally when it 677 # is only specified once 678 argv = ('./program', '--only_once=singlevalue') 679 argv = FLAGS(argv) 680 self.assertEqual(FLAGS.get_flag_value('only_once', None), 'singlevalue') 681 682 # A flag with allow_overwrite set to False should complain when it is 683 # specified more than once 684 argv = ('./program', '--universe=ptolemaic', '--universe=copernicean', 685 '--universe=euclidean') 686 self.assertRaisesWithLiteralMatch( 687 flags.IllegalFlagValueError, 688 'flag --universe=copernicean: already defined as ptolemaic', FLAGS, 689 argv) 690 691 # Test single-letter flags; should support both single and double dash 692 argv = ('./program', '-q') 693 argv = FLAGS(argv) 694 self.assertEqual(FLAGS.get_flag_value('q', None), 1) 695 696 argv = ('./program', '--q', '--x', '9', '--noquack') 697 argv = FLAGS(argv) 698 self.assertEqual(FLAGS.get_flag_value('q', None), 1) 699 self.assertEqual(FLAGS.get_flag_value('x', None), 9) 700 self.assertEqual(FLAGS.get_flag_value('quack', None), 0) 701 702 argv = ('./program', '--noq', '--x=10', '--quack') 703 argv = FLAGS(argv) 704 self.assertEqual(FLAGS.get_flag_value('q', None), 0) 705 self.assertEqual(FLAGS.get_flag_value('x', None), 10) 706 self.assertEqual(FLAGS.get_flag_value('quack', None), 1) 707 708 #################################### 709 # Test flag serialization code: 710 711 old_testcomma_list = FLAGS.testcomma_list 712 old_testspace_list = FLAGS.testspace_list 713 old_testspace_or_comma_list = FLAGS.testspace_or_comma_list 714 715 argv = ('./program', FLAGS['test0'].serialize(), FLAGS['test1'].serialize(), 716 FLAGS['s_str'].serialize()) 717 718 argv = FLAGS(argv) 719 self.assertEqual(FLAGS['test0'].serialize(), '--notest0') 720 self.assertEqual(FLAGS['test1'].serialize(), '--test1') 721 self.assertEqual(FLAGS['s_str'].serialize(), '--s_str=sing1') 722 723 self.assertEqual(FLAGS['testnone'].serialize(), '') 724 725 testcomma_list1 = ['aa', 'bb'] 726 testspace_list1 = ['aa', 'bb', 'cc'] 727 testspace_or_comma_list1 = ['aa', 'bb', 'cc', 'dd'] 728 FLAGS.testcomma_list = list(testcomma_list1) 729 FLAGS.testspace_list = list(testspace_list1) 730 FLAGS.testspace_or_comma_list = list(testspace_or_comma_list1) 731 argv = ('./program', FLAGS['testcomma_list'].serialize(), 732 FLAGS['testspace_list'].serialize(), 733 FLAGS['testspace_or_comma_list'].serialize()) 734 argv = FLAGS(argv) 735 self.assertEqual(FLAGS.testcomma_list, testcomma_list1) 736 self.assertEqual(FLAGS.testspace_list, testspace_list1) 737 self.assertEqual(FLAGS.testspace_or_comma_list, testspace_or_comma_list1) 738 739 testcomma_list1 = ['aa some spaces', 'bb'] 740 testspace_list1 = ['aa', 'bb,some,commas,', 'cc'] 741 testspace_or_comma_list1 = ['aa', 'bb,some,commas,', 'cc'] 742 FLAGS.testcomma_list = list(testcomma_list1) 743 FLAGS.testspace_list = list(testspace_list1) 744 FLAGS.testspace_or_comma_list = list(testspace_or_comma_list1) 745 argv = ('./program', FLAGS['testcomma_list'].serialize(), 746 FLAGS['testspace_list'].serialize(), 747 FLAGS['testspace_or_comma_list'].serialize()) 748 argv = FLAGS(argv) 749 self.assertEqual(FLAGS.testcomma_list, testcomma_list1) 750 self.assertEqual(FLAGS.testspace_list, testspace_list1) 751 # We don't expect idempotency when commas are placed in an item value and 752 # comma_compat is enabled. 753 self.assertEqual(FLAGS.testspace_or_comma_list, 754 ['aa', 'bb', 'some', 'commas', 'cc']) 755 756 FLAGS.testcomma_list = old_testcomma_list 757 FLAGS.testspace_list = old_testspace_list 758 FLAGS.testspace_or_comma_list = old_testspace_or_comma_list 759 760 #################################### 761 # Test flag-update: 762 763 def args_list(): 764 # Exclude flags that have different default values based on the 765 # environment. 766 flags_to_exclude = {'log_dir', 'test_srcdir', 'test_tmpdir'} 767 flagnames = set(FLAGS) - flags_to_exclude 768 769 nonbool_flags = [] 770 truebool_flags = [] 771 falsebool_flags = [] 772 for name in flagnames: 773 flag_value = FLAGS.get_flag_value(name, None) 774 if not isinstance(FLAGS[name], flags.BooleanFlag): 775 nonbool_flags.append('--%s %s' % (name, flag_value)) 776 elif flag_value: 777 truebool_flags.append('--%s' % name) 778 else: 779 falsebool_flags.append('--no%s' % name) 780 all_flags = nonbool_flags + truebool_flags + falsebool_flags 781 all_flags.sort() 782 return all_flags 783 784 argv = ('./program', '--repeat=3', '--name=giants', '--nodebug') 785 786 FLAGS(argv) 787 self.assertEqual(FLAGS.get_flag_value('repeat', None), 3) 788 self.assertEqual(FLAGS.get_flag_value('name', None), 'giants') 789 self.assertEqual(FLAGS.get_flag_value('debug', None), 0) 790 self.assertListEqual([ 791 '--alsologtostderr', 792 "--args ['v=1', 'vmodule=a=0,b=2']", 793 '--blah None', 794 '--cases None', 795 '--decimal 666', 796 '--float 3.14', 797 '--funny None', 798 '--hexadecimal 1638', 799 '--kwery None', 800 '--l 9223372032559808512', 801 "--letters ['a', 'b', 'c']", 802 '--logger_levels {}', 803 "--m ['str1', 'str2']", 804 "--m_str ['str1', 'str2']", 805 '--name giants', 806 '--no?', 807 '--nodebug', 808 '--noexec', 809 '--nohelp', 810 '--nohelpfull', 811 '--nohelpshort', 812 '--nohelpxml', 813 '--nologtostderr', 814 '--noonly_check_args', 815 '--nopdb_post_mortem', 816 '--noq', 817 '--norun_with_pdb', 818 '--norun_with_profiling', 819 '--notest0', 820 '--notestget2', 821 '--notestget3', 822 '--notestnone', 823 '--numbers [1, 2, 3]', 824 '--octal 438', 825 '--only_once singlevalue', 826 '--pdb False', 827 '--profile_file None', 828 '--quack', 829 '--repeat 3', 830 "--s ['sing1']", 831 "--s_str ['sing1']", 832 '--sense None', 833 '--showprefixforinfo', 834 '--stderrthreshold fatal', 835 '--test1', 836 '--test_random_seed 301', 837 '--test_randomize_ordering_seed ', 838 '--testcomma_list []', 839 '--testget1', 840 '--testget4 None', 841 '--testspace_list []', 842 '--testspace_or_comma_list []', 843 '--tmod_baz_x', 844 '--universe ptolemaic', 845 '--use_cprofile_for_profiling', 846 '--v -1', 847 '--verbosity -1', 848 '--x 10', 849 '--xml_output_file ', 850 ], args_list()) 851 852 argv = ('./program', '--debug', '--m_str=upd1', '-s', 'upd2') 853 FLAGS(argv) 854 self.assertEqual(FLAGS.get_flag_value('repeat', None), 3) 855 self.assertEqual(FLAGS.get_flag_value('name', None), 'giants') 856 self.assertEqual(FLAGS.get_flag_value('debug', None), 1) 857 858 # items appended to existing non-default value lists for --m/--m_str 859 # new value overwrites default value (not appended to it) for --s/--s_str 860 self.assertListEqual([ 861 '--alsologtostderr', 862 "--args ['v=1', 'vmodule=a=0,b=2']", 863 '--blah None', 864 '--cases None', 865 '--debug', 866 '--decimal 666', 867 '--float 3.14', 868 '--funny None', 869 '--hexadecimal 1638', 870 '--kwery None', 871 '--l 9223372032559808512', 872 "--letters ['a', 'b', 'c']", 873 '--logger_levels {}', 874 "--m ['str1', 'str2', 'upd1']", 875 "--m_str ['str1', 'str2', 'upd1']", 876 '--name giants', 877 '--no?', 878 '--noexec', 879 '--nohelp', 880 '--nohelpfull', 881 '--nohelpshort', 882 '--nohelpxml', 883 '--nologtostderr', 884 '--noonly_check_args', 885 '--nopdb_post_mortem', 886 '--noq', 887 '--norun_with_pdb', 888 '--norun_with_profiling', 889 '--notest0', 890 '--notestget2', 891 '--notestget3', 892 '--notestnone', 893 '--numbers [1, 2, 3]', 894 '--octal 438', 895 '--only_once singlevalue', 896 '--pdb False', 897 '--profile_file None', 898 '--quack', 899 '--repeat 3', 900 "--s ['sing1', 'upd2']", 901 "--s_str ['sing1', 'upd2']", 902 '--sense None', 903 '--showprefixforinfo', 904 '--stderrthreshold fatal', 905 '--test1', 906 '--test_random_seed 301', 907 '--test_randomize_ordering_seed ', 908 '--testcomma_list []', 909 '--testget1', 910 '--testget4 None', 911 '--testspace_list []', 912 '--testspace_or_comma_list []', 913 '--tmod_baz_x', 914 '--universe ptolemaic', 915 '--use_cprofile_for_profiling', 916 '--v -1', 917 '--verbosity -1', 918 '--x 10', 919 '--xml_output_file ', 920 ], args_list()) 921 922 #################################### 923 # Test all kind of error conditions. 924 925 # Argument not in enum exception 926 argv = ('./program', '--kwery=WHEN') 927 self.assertRaises(flags.IllegalFlagValueError, FLAGS, argv) 928 argv = ('./program', '--kwery=why') 929 self.assertRaises(flags.IllegalFlagValueError, FLAGS, argv) 930 931 # Duplicate flag detection 932 with self.assertRaises(flags.DuplicateFlagError): 933 flags.DEFINE_boolean('run', 0, 'runhelp', short_name='q') 934 935 # Duplicate short flag detection 936 with self.assertRaisesRegex( 937 flags.DuplicateFlagError, 938 r"The flag 'z' is defined twice\. .*First from.*, Second from"): 939 flags.DEFINE_boolean('zoom1', 0, 'runhelp z1', short_name='z') 940 flags.DEFINE_boolean('zoom2', 0, 'runhelp z2', short_name='z') 941 raise AssertionError('duplicate short flag detection failed') 942 943 # Duplicate mixed flag detection 944 with self.assertRaisesRegex( 945 flags.DuplicateFlagError, 946 r"The flag 's' is defined twice\. .*First from.*, Second from"): 947 flags.DEFINE_boolean('short1', 0, 'runhelp s1', short_name='s') 948 flags.DEFINE_boolean('s', 0, 'runhelp s2') 949 950 # Check that duplicate flag detection detects definition sites 951 # correctly. 952 flagnames = ['repeated'] 953 original_flags = flags.FlagValues() 954 flags.DEFINE_boolean( 955 flagnames[0], 956 False, 957 'Flag about to be repeated.', 958 flag_values=original_flags) 959 duplicate_flags = module_foo.duplicate_flags(flagnames) 960 with self.assertRaisesRegex(flags.DuplicateFlagError, 961 'flags_test.*module_foo'): 962 original_flags.append_flag_values(duplicate_flags) 963 964 # Make sure allow_override works 965 try: 966 flags.DEFINE_boolean( 967 'dup1', 0, 'runhelp d11', short_name='u', allow_override=0) 968 flag = FLAGS._flags()['dup1'] 969 self.assertEqual(flag.default, 0) 970 971 flags.DEFINE_boolean( 972 'dup1', 1, 'runhelp d12', short_name='u', allow_override=1) 973 flag = FLAGS._flags()['dup1'] 974 self.assertEqual(flag.default, 1) 975 except flags.DuplicateFlagError: 976 raise AssertionError('allow_override did not permit a flag duplication') 977 978 # Make sure allow_override works 979 try: 980 flags.DEFINE_boolean( 981 'dup2', 0, 'runhelp d21', short_name='u', allow_override=1) 982 flag = FLAGS._flags()['dup2'] 983 self.assertEqual(flag.default, 0) 984 985 flags.DEFINE_boolean( 986 'dup2', 1, 'runhelp d22', short_name='u', allow_override=0) 987 flag = FLAGS._flags()['dup2'] 988 self.assertEqual(flag.default, 1) 989 except flags.DuplicateFlagError: 990 raise AssertionError('allow_override did not permit a flag duplication') 991 992 # Make sure that re-importing a module does not cause a DuplicateFlagError 993 # to be raised. 994 try: 995 sys.modules.pop('absl.flags.tests.module_baz') 996 import absl.flags.tests.module_baz 997 del absl 998 except flags.DuplicateFlagError: 999 raise AssertionError('Module reimport caused flag duplication error') 1000 1001 # Make sure that when we override, the help string gets updated correctly 1002 flags.DEFINE_boolean( 1003 'dup3', 0, 'runhelp d31', short_name='u', allow_override=1) 1004 flags.DEFINE_boolean( 1005 'dup3', 1, 'runhelp d32', short_name='u', allow_override=1) 1006 self.assertEqual(str(FLAGS).find('runhelp d31'), -1) 1007 self.assertNotEqual(str(FLAGS).find('runhelp d32'), -1) 1008 1009 # Make sure append_flag_values works 1010 new_flags = flags.FlagValues() 1011 flags.DEFINE_boolean('new1', 0, 'runhelp n1', flag_values=new_flags) 1012 flags.DEFINE_boolean('new2', 0, 'runhelp n2', flag_values=new_flags) 1013 self.assertEqual(len(new_flags._flags()), 2) 1014 old_len = len(FLAGS._flags()) 1015 FLAGS.append_flag_values(new_flags) 1016 self.assertEqual(len(FLAGS._flags()) - old_len, 2) 1017 self.assertEqual('new1' in FLAGS._flags(), True) 1018 self.assertEqual('new2' in FLAGS._flags(), True) 1019 1020 # Then test that removing those flags works 1021 FLAGS.remove_flag_values(new_flags) 1022 self.assertEqual(len(FLAGS._flags()), old_len) 1023 self.assertFalse('new1' in FLAGS._flags()) 1024 self.assertFalse('new2' in FLAGS._flags()) 1025 1026 # Make sure append_flag_values works with flags with shortnames. 1027 new_flags = flags.FlagValues() 1028 flags.DEFINE_boolean('new3', 0, 'runhelp n3', flag_values=new_flags) 1029 flags.DEFINE_boolean( 1030 'new4', 0, 'runhelp n4', flag_values=new_flags, short_name='n4') 1031 self.assertEqual(len(new_flags._flags()), 3) 1032 old_len = len(FLAGS._flags()) 1033 FLAGS.append_flag_values(new_flags) 1034 self.assertEqual(len(FLAGS._flags()) - old_len, 3) 1035 self.assertIn('new3', FLAGS._flags()) 1036 self.assertIn('new4', FLAGS._flags()) 1037 self.assertIn('n4', FLAGS._flags()) 1038 self.assertEqual(FLAGS._flags()['n4'], FLAGS._flags()['new4']) 1039 1040 # Then test removing them 1041 FLAGS.remove_flag_values(new_flags) 1042 self.assertEqual(len(FLAGS._flags()), old_len) 1043 self.assertFalse('new3' in FLAGS._flags()) 1044 self.assertFalse('new4' in FLAGS._flags()) 1045 self.assertFalse('n4' in FLAGS._flags()) 1046 1047 # Make sure append_flag_values fails on duplicates 1048 flags.DEFINE_boolean('dup4', 0, 'runhelp d41') 1049 new_flags = flags.FlagValues() 1050 flags.DEFINE_boolean('dup4', 0, 'runhelp d42', flag_values=new_flags) 1051 with self.assertRaises(flags.DuplicateFlagError): 1052 FLAGS.append_flag_values(new_flags) 1053 1054 # Integer out of bounds 1055 with self.assertRaises(flags.IllegalFlagValueError): 1056 argv = ('./program', '--repeat=-4') 1057 FLAGS(argv) 1058 1059 # Non-integer 1060 with self.assertRaises(flags.IllegalFlagValueError): 1061 argv = ('./program', '--repeat=2.5') 1062 FLAGS(argv) 1063 1064 # Missing required argument 1065 with self.assertRaises(flags.Error): 1066 argv = ('./program', '--name') 1067 FLAGS(argv) 1068 1069 # Non-boolean arguments for boolean 1070 with self.assertRaises(flags.IllegalFlagValueError): 1071 argv = ('./program', '--debug=goofup') 1072 FLAGS(argv) 1073 1074 with self.assertRaises(flags.IllegalFlagValueError): 1075 argv = ('./program', '--debug=42') 1076 FLAGS(argv) 1077 1078 # Non-numeric argument for integer flag --repeat 1079 with self.assertRaises(flags.IllegalFlagValueError): 1080 argv = ('./program', '--repeat', 'Bob', 'extra') 1081 FLAGS(argv) 1082 1083 # Aliases of existing flags 1084 with self.assertRaises(flags.UnrecognizedFlagError): 1085 flags.DEFINE_alias('alias_not_a_flag', 'not_a_flag') 1086 1087 # Programmtically modify alias and aliased flag 1088 flags.DEFINE_alias('alias_octal', 'octal') 1089 FLAGS.octal = 0o2222 1090 self.assertEqual(0o2222, FLAGS.octal) 1091 self.assertEqual(0o2222, FLAGS.alias_octal) 1092 FLAGS.alias_octal = 0o4444 1093 self.assertEqual(0o4444, FLAGS.octal) 1094 self.assertEqual(0o4444, FLAGS.alias_octal) 1095 1096 # Setting alias preserves the default of the original 1097 flags.DEFINE_alias('alias_name', 'name') 1098 flags.DEFINE_alias('alias_debug', 'debug') 1099 flags.DEFINE_alias('alias_decimal', 'decimal') 1100 flags.DEFINE_alias('alias_float', 'float') 1101 flags.DEFINE_alias('alias_letters', 'letters') 1102 self.assertEqual(FLAGS['name'].default, FLAGS.alias_name) 1103 self.assertEqual(FLAGS['debug'].default, FLAGS.alias_debug) 1104 self.assertEqual(int(FLAGS['decimal'].default), FLAGS.alias_decimal) 1105 self.assertEqual(float(FLAGS['float'].default), FLAGS.alias_float) 1106 self.assertSameElements(FLAGS['letters'].default, FLAGS.alias_letters) 1107 1108 # Original flags set on command line 1109 argv = ('./program', '--name=Martin', '--debug=True', '--decimal=777', 1110 '--letters=x,y,z') 1111 FLAGS(argv) 1112 self.assertEqual('Martin', FLAGS.name) 1113 self.assertEqual('Martin', FLAGS.alias_name) 1114 self.assertTrue(FLAGS.debug) 1115 self.assertTrue(FLAGS.alias_debug) 1116 self.assertEqual(777, FLAGS.decimal) 1117 self.assertEqual(777, FLAGS.alias_decimal) 1118 self.assertSameElements(['x', 'y', 'z'], FLAGS.letters) 1119 self.assertSameElements(['x', 'y', 'z'], FLAGS.alias_letters) 1120 1121 # Alias flags set on command line 1122 argv = ('./program', '--alias_name=Auston', '--alias_debug=False', 1123 '--alias_decimal=888', '--alias_letters=l,m,n') 1124 FLAGS(argv) 1125 self.assertEqual('Auston', FLAGS.name) 1126 self.assertEqual('Auston', FLAGS.alias_name) 1127 self.assertFalse(FLAGS.debug) 1128 self.assertFalse(FLAGS.alias_debug) 1129 self.assertEqual(888, FLAGS.decimal) 1130 self.assertEqual(888, FLAGS.alias_decimal) 1131 self.assertSameElements(['l', 'm', 'n'], FLAGS.letters) 1132 self.assertSameElements(['l', 'm', 'n'], FLAGS.alias_letters) 1133 1134 # Make sure importing a module does not change flag value parsed 1135 # from commandline. 1136 flags.DEFINE_integer( 1137 'dup5', 1, 'runhelp d51', short_name='u5', allow_override=0) 1138 self.assertEqual(FLAGS.dup5, 1) 1139 self.assertEqual(FLAGS.dup5, 1) 1140 argv = ('./program', '--dup5=3') 1141 FLAGS(argv) 1142 self.assertEqual(FLAGS.dup5, 3) 1143 flags.DEFINE_integer( 1144 'dup5', 2, 'runhelp d52', short_name='u5', allow_override=1) 1145 self.assertEqual(FLAGS.dup5, 3) 1146 1147 # Make sure importing a module does not change user defined flag value. 1148 flags.DEFINE_integer( 1149 'dup6', 1, 'runhelp d61', short_name='u6', allow_override=0) 1150 self.assertEqual(FLAGS.dup6, 1) 1151 FLAGS.dup6 = 3 1152 self.assertEqual(FLAGS.dup6, 3) 1153 flags.DEFINE_integer( 1154 'dup6', 2, 'runhelp d62', short_name='u6', allow_override=1) 1155 self.assertEqual(FLAGS.dup6, 3) 1156 1157 # Make sure importing a module does not change user defined flag value 1158 # even if it is the 'default' value. 1159 flags.DEFINE_integer( 1160 'dup7', 1, 'runhelp d71', short_name='u7', allow_override=0) 1161 self.assertEqual(FLAGS.dup7, 1) 1162 FLAGS.dup7 = 1 1163 self.assertEqual(FLAGS.dup7, 1) 1164 flags.DEFINE_integer( 1165 'dup7', 2, 'runhelp d72', short_name='u7', allow_override=1) 1166 self.assertEqual(FLAGS.dup7, 1) 1167 1168 # Test module_help(). 1169 helpstr = FLAGS.module_help(module_baz) 1170 1171 expected_help = '\n' + module_baz.__name__ + ':' + """ 1172 --[no]tmod_baz_x: Boolean flag. 1173 (default: 'true')""" 1174 1175 self.assertMultiLineEqual(expected_help, helpstr) 1176 1177 # Test main_module_help(). This must be part of test_flags because 1178 # it depends on dup1/2/3/etc being introduced first. 1179 helpstr = FLAGS.main_module_help() 1180 1181 expected_help = '\n' + sys.argv[0] + ':' + """ 1182 --[no]alias_debug: Alias for --debug. 1183 (default: 'false') 1184 --alias_decimal: Alias for --decimal. 1185 (default: '666') 1186 (an integer) 1187 --alias_float: Alias for --float. 1188 (default: '3.14') 1189 (a number) 1190 --alias_letters: Alias for --letters. 1191 (default: 'a,b,c') 1192 (a comma separated list) 1193 --alias_name: Alias for --name. 1194 (default: 'Bob') 1195 --alias_octal: Alias for --octal. 1196 (default: '438') 1197 (an integer) 1198 --args: a list of arguments 1199 (default: 'v=1,"vmodule=a=0,b=2"') 1200 (a comma separated list) 1201 --blah: <bla|Blah|BLAH|blah>: ? 1202 --cases: <UPPER|lower|Initial|Ot_HeR>: ? 1203 --[no]debug: debughelp 1204 (default: 'false') 1205 --decimal: using decimals 1206 (default: '666') 1207 (an integer) 1208 -u,--[no]dup1: runhelp d12 1209 (default: 'true') 1210 -u,--[no]dup2: runhelp d22 1211 (default: 'true') 1212 -u,--[no]dup3: runhelp d32 1213 (default: 'true') 1214 --[no]dup4: runhelp d41 1215 (default: 'false') 1216 -u5,--dup5: runhelp d51 1217 (default: '1') 1218 (an integer) 1219 -u6,--dup6: runhelp d61 1220 (default: '1') 1221 (an integer) 1222 -u7,--dup7: runhelp d71 1223 (default: '1') 1224 (an integer) 1225 --float: using floats 1226 (default: '3.14') 1227 (a number) 1228 --funny: <Joke|ha|ha|ha|ha>: ? 1229 --hexadecimal: using hexadecimals 1230 (default: '1638') 1231 (an integer) 1232 --kwery: <who|what|Why|where|when>: ? 1233 --l: how long to be 1234 (default: '9223372032559808512') 1235 (an integer) 1236 --letters: a list of letters 1237 (default: 'a,b,c') 1238 (a comma separated list) 1239 -m,--m_str: string option that can occur multiple times; 1240 repeat this option to specify a list of values 1241 (default: "['def1', 'def2']") 1242 --name: namehelp 1243 (default: 'Bob') 1244 --[no]noexec: boolean flag with no as prefix 1245 (default: 'true') 1246 --numbers: a list of numbers 1247 (default: '1,2,3') 1248 (a comma separated list) 1249 --octal: using octals 1250 (default: '438') 1251 (an integer) 1252 --only_once: test only sets this once 1253 --[no]q: quiet mode 1254 (default: 'true') 1255 --[no]quack: superstring of 'q' 1256 (default: 'false') 1257 -r,--repeat: how many times to repeat (0-5) 1258 (default: '4') 1259 (a non-negative integer) 1260 -s,--s_str: string option that can occur multiple times; 1261 repeat this option to specify a list of values 1262 (default: "['sing1']") 1263 --sense: <Case|case|CASE>: ? 1264 --[no]test0: test boolean parsing 1265 --[no]test1: test boolean parsing 1266 --testcomma_list: test comma list parsing 1267 (default: '') 1268 (a comma separated list) 1269 --[no]testget1: test parsing with defaults 1270 --[no]testget2: test parsing with defaults 1271 --[no]testget3: test parsing with defaults 1272 --testget4: test parsing with defaults 1273 (an integer) 1274 --[no]testnone: test boolean parsing 1275 --testspace_list: tests space list parsing 1276 (default: '') 1277 (a whitespace separated list) 1278 --testspace_or_comma_list: tests space list parsing with comma compatibility 1279 (default: '') 1280 (a whitespace or comma separated list) 1281 --universe: test tries to set this three times 1282 --x: how eXtreme to be 1283 (default: '3') 1284 (an integer) 1285 -z,--[no]zoom1: runhelp z1 1286 (default: 'false')""" 1287 1288 self.assertMultiLineEqual(expected_help, helpstr) 1289 1290 def test_string_flag_with_wrong_type(self): 1291 fv = flags.FlagValues() 1292 with self.assertRaises(flags.IllegalFlagValueError): 1293 flags.DEFINE_string('name', False, 'help', flag_values=fv) 1294 with self.assertRaises(flags.IllegalFlagValueError): 1295 flags.DEFINE_string('name2', 0, 'help', flag_values=fv) 1296 1297 def test_integer_flag_with_wrong_type(self): 1298 fv = flags.FlagValues() 1299 with self.assertRaises(flags.IllegalFlagValueError): 1300 flags.DEFINE_integer('name', 1e2, 'help', flag_values=fv) 1301 with self.assertRaises(flags.IllegalFlagValueError): 1302 flags.DEFINE_integer('name', [], 'help', flag_values=fv) 1303 with self.assertRaises(flags.IllegalFlagValueError): 1304 flags.DEFINE_integer('name', False, 'help', flag_values=fv) 1305 1306 def test_float_flag_with_wrong_type(self): 1307 fv = flags.FlagValues() 1308 with self.assertRaises(flags.IllegalFlagValueError): 1309 flags.DEFINE_float('name', False, 'help', flag_values=fv) 1310 1311 def test_enum_flag_with_empty_values(self): 1312 fv = flags.FlagValues() 1313 with self.assertRaises(ValueError): 1314 flags.DEFINE_enum('fruit', None, [], 'help', flag_values=fv) 1315 1316 def test_define_enum_class_flag(self): 1317 fv = flags.FlagValues() 1318 flags.DEFINE_enum_class('fruit', None, Fruit, '?', flag_values=fv) 1319 fv.mark_as_parsed() 1320 1321 self.assertIsNone(fv.fruit) 1322 1323 def test_parse_enum_class_flag(self): 1324 fv = flags.FlagValues() 1325 flags.DEFINE_enum_class('fruit', None, Fruit, '?', flag_values=fv) 1326 1327 argv = ('./program', '--fruit=orange') 1328 argv = fv(argv) 1329 self.assertEqual(len(argv), 1, 'wrong number of arguments pulled') 1330 self.assertEqual(argv[0], './program', 'program name not preserved') 1331 self.assertEqual(fv['fruit'].present, 1) 1332 self.assertEqual(fv['fruit'].value, Fruit.ORANGE) 1333 fv.unparse_flags() 1334 argv = ('./program', '--fruit=APPLE') 1335 argv = fv(argv) 1336 self.assertEqual(len(argv), 1, 'wrong number of arguments pulled') 1337 self.assertEqual(argv[0], './program', 'program name not preserved') 1338 self.assertEqual(fv['fruit'].present, 1) 1339 self.assertEqual(fv['fruit'].value, Fruit.APPLE) 1340 fv.unparse_flags() 1341 1342 def test_enum_class_flag_help_message(self): 1343 fv = flags.FlagValues() 1344 flags.DEFINE_enum_class('fruit', None, Fruit, '?', flag_values=fv) 1345 1346 helpstr = fv.main_module_help() 1347 expected_help = '\n%s:\n --fruit: <apple|orange>: ?' % sys.argv[0] 1348 1349 self.assertEqual(helpstr, expected_help) 1350 1351 def test_enum_class_flag_with_wrong_default_value_type(self): 1352 fv = flags.FlagValues() 1353 with self.assertRaises(_exceptions.IllegalFlagValueError): 1354 flags.DEFINE_enum_class('fruit', 1, Fruit, 'help', flag_values=fv) 1355 1356 def test_enum_class_flag_requires_enum_class(self): 1357 fv = flags.FlagValues() 1358 with self.assertRaises(TypeError): 1359 flags.DEFINE_enum_class( 1360 'fruit', None, ['apple', 'orange'], 'help', flag_values=fv) 1361 1362 def test_enum_class_flag_requires_non_empty_enum_class(self): 1363 fv = flags.FlagValues() 1364 with self.assertRaises(ValueError): 1365 flags.DEFINE_enum_class('empty', None, EmptyEnum, 'help', flag_values=fv) 1366 1367 def test_required_flag(self): 1368 fv = flags.FlagValues() 1369 fl = flags.DEFINE_integer( 1370 name='int_flag', 1371 default=None, 1372 help='help', 1373 required=True, 1374 flag_values=fv) 1375 # Since the flag is required, the FlagHolder should ensure value returned 1376 # is not None. 1377 self.assertTrue(fl._ensure_non_none_value) 1378 1379 def test_illegal_required_flag(self): 1380 fv = flags.FlagValues() 1381 with self.assertRaises(ValueError): 1382 flags.DEFINE_integer( 1383 name='int_flag', 1384 default=3, 1385 help='help', 1386 required=True, 1387 flag_values=fv) 1388 1389 1390class MultiNumericalFlagsTest(absltest.TestCase): 1391 1392 def test_multi_numerical_flags(self): 1393 """Test multi_int and multi_float flags.""" 1394 fv = flags.FlagValues() 1395 int_defaults = [77, 88] 1396 flags.DEFINE_multi_integer( 1397 'm_int', 1398 int_defaults, 1399 'integer option that can occur multiple times', 1400 short_name='mi', 1401 flag_values=fv) 1402 self.assertListEqual(fv['m_int'].default, int_defaults) 1403 argv = ('./program', '--m_int=-99', '--mi=101') 1404 fv(argv) 1405 self.assertListEqual(fv.get_flag_value('m_int', None), [-99, 101]) 1406 1407 float_defaults = [2.2, 3] 1408 flags.DEFINE_multi_float( 1409 'm_float', 1410 float_defaults, 1411 'float option that can occur multiple times', 1412 short_name='mf', 1413 flag_values=fv) 1414 for (expected, actual) in zip(float_defaults, 1415 fv.get_flag_value('m_float', None)): 1416 self.assertAlmostEqual(expected, actual) 1417 argv = ('./program', '--m_float=-17', '--mf=2.78e9') 1418 fv(argv) 1419 expected_floats = [-17.0, 2.78e9] 1420 for (expected, actual) in zip(expected_floats, 1421 fv.get_flag_value('m_float', None)): 1422 self.assertAlmostEqual(expected, actual) 1423 1424 def test_multi_numerical_with_tuples(self): 1425 """Verify multi_int/float accept tuples as default values.""" 1426 flags.DEFINE_multi_integer( 1427 'm_int_tuple', (77, 88), 1428 'integer option that can occur multiple times', 1429 short_name='mi_tuple') 1430 self.assertListEqual(FLAGS.get_flag_value('m_int_tuple', None), [77, 88]) 1431 1432 dict_with_float_keys = {2.2: 'hello', 3: 'happy'} 1433 float_defaults = dict_with_float_keys.keys() 1434 flags.DEFINE_multi_float( 1435 'm_float_tuple', 1436 float_defaults, 1437 'float option that can occur multiple times', 1438 short_name='mf_tuple') 1439 for (expected, actual) in zip(float_defaults, 1440 FLAGS.get_flag_value('m_float_tuple', None)): 1441 self.assertAlmostEqual(expected, actual) 1442 1443 def test_single_value_default(self): 1444 """Test multi_int and multi_float flags with a single default value.""" 1445 int_default = 77 1446 flags.DEFINE_multi_integer('m_int1', int_default, 1447 'integer option that can occur multiple times') 1448 self.assertListEqual(FLAGS.get_flag_value('m_int1', None), [int_default]) 1449 1450 float_default = 2.2 1451 flags.DEFINE_multi_float('m_float1', float_default, 1452 'float option that can occur multiple times') 1453 actual = FLAGS.get_flag_value('m_float1', None) 1454 self.assertEqual(1, len(actual)) 1455 self.assertAlmostEqual(actual[0], float_default) 1456 1457 def test_bad_multi_numerical_flags(self): 1458 """Test multi_int and multi_float flags with non-parseable values.""" 1459 1460 # Test non-parseable defaults. 1461 self.assertRaisesRegex( 1462 flags.IllegalFlagValueError, 1463 r"flag --m_int2=abc: invalid literal for int\(\) with base 10: 'abc'", 1464 flags.DEFINE_multi_integer, 'm_int2', ['abc'], 'desc') 1465 1466 self.assertRaisesRegex( 1467 flags.IllegalFlagValueError, r'flag --m_float2=abc: ' 1468 r'(invalid literal for float\(\)|could not convert string to float): ' 1469 r"'?abc'?", flags.DEFINE_multi_float, 'm_float2', ['abc'], 'desc') 1470 1471 # Test non-parseable command line values. 1472 fv = flags.FlagValues() 1473 flags.DEFINE_multi_integer( 1474 'm_int2', 1475 '77', 1476 'integer option that can occur multiple times', 1477 flag_values=fv) 1478 argv = ('./program', '--m_int2=def') 1479 self.assertRaisesRegex( 1480 flags.IllegalFlagValueError, 1481 r"flag --m_int2=def: invalid literal for int\(\) with base 10: 'def'", 1482 fv, argv) 1483 1484 flags.DEFINE_multi_float( 1485 'm_float2', 1486 2.2, 1487 'float option that can occur multiple times', 1488 flag_values=fv) 1489 argv = ('./program', '--m_float2=def') 1490 self.assertRaisesRegex( 1491 flags.IllegalFlagValueError, r'flag --m_float2=def: ' 1492 r'(invalid literal for float\(\)|could not convert string to float): ' 1493 r"'?def'?", fv, argv) 1494 1495 1496class MultiEnumFlagsTest(absltest.TestCase): 1497 1498 def test_multi_enum_flags(self): 1499 """Test multi_enum flags.""" 1500 fv = flags.FlagValues() 1501 1502 enum_defaults = ['FOO', 'BAZ'] 1503 flags.DEFINE_multi_enum( 1504 'm_enum', 1505 enum_defaults, ['FOO', 'BAR', 'BAZ', 'WHOOSH'], 1506 'Enum option that can occur multiple times', 1507 short_name='me', 1508 flag_values=fv) 1509 self.assertListEqual(fv['m_enum'].default, enum_defaults) 1510 argv = ('./program', '--m_enum=WHOOSH', '--me=FOO') 1511 fv(argv) 1512 self.assertListEqual(fv.get_flag_value('m_enum', None), ['WHOOSH', 'FOO']) 1513 1514 def test_help_text(self): 1515 """Test multi_enum flag's help text.""" 1516 fv = flags.FlagValues() 1517 1518 flags.DEFINE_multi_enum( 1519 'm_enum', 1520 None, ['FOO', 'BAR'], 1521 'Enum option that can occur multiple times', 1522 flag_values=fv) 1523 self.assertRegex( 1524 fv['m_enum'].help, 1525 r'<FOO\|BAR>: Enum option that can occur multiple times;\s+' 1526 'repeat this option to specify a list of values') 1527 1528 def test_single_value_default(self): 1529 """Test multi_enum flags with a single default value.""" 1530 fv = flags.FlagValues() 1531 enum_default = 'FOO' 1532 flags.DEFINE_multi_enum( 1533 'm_enum1', 1534 enum_default, ['FOO', 'BAR', 'BAZ', 'WHOOSH'], 1535 'enum option that can occur multiple times', 1536 flag_values=fv) 1537 self.assertListEqual(fv['m_enum1'].default, [enum_default]) 1538 1539 def test_case_sensitivity(self): 1540 """Test case sensitivity of multi_enum flag.""" 1541 fv = flags.FlagValues() 1542 # Test case insensitive enum. 1543 flags.DEFINE_multi_enum( 1544 'm_enum2', ['whoosh'], ['FOO', 'BAR', 'BAZ', 'WHOOSH'], 1545 'Enum option that can occur multiple times', 1546 short_name='me2', 1547 case_sensitive=False, 1548 flag_values=fv) 1549 argv = ('./program', '--m_enum2=bar', '--me2=fOo') 1550 fv(argv) 1551 self.assertListEqual(fv.get_flag_value('m_enum2', None), ['BAR', 'FOO']) 1552 1553 # Test case sensitive enum. 1554 flags.DEFINE_multi_enum( 1555 'm_enum3', ['BAR'], ['FOO', 'BAR', 'BAZ', 'WHOOSH'], 1556 'Enum option that can occur multiple times', 1557 short_name='me3', 1558 case_sensitive=True, 1559 flag_values=fv) 1560 argv = ('./program', '--m_enum3=bar', '--me3=fOo') 1561 self.assertRaisesRegex( 1562 flags.IllegalFlagValueError, 1563 r'flag --m_enum3=invalid: value should be one of <FOO|BAR|BAZ|WHOOSH>', 1564 fv, argv) 1565 1566 def test_bad_multi_enum_flags(self): 1567 """Test multi_enum with invalid values.""" 1568 1569 # Test defaults that are not in the permitted list of enums. 1570 self.assertRaisesRegex( 1571 flags.IllegalFlagValueError, 1572 r'flag --m_enum=INVALID: value should be one of <FOO|BAR|BAZ>', 1573 flags.DEFINE_multi_enum, 'm_enum', ['INVALID'], ['FOO', 'BAR', 'BAZ'], 1574 'desc') 1575 1576 self.assertRaisesRegex( 1577 flags.IllegalFlagValueError, 1578 r'flag --m_enum=1234: value should be one of <FOO|BAR|BAZ>', 1579 flags.DEFINE_multi_enum, 'm_enum2', [1234], ['FOO', 'BAR', 'BAZ'], 1580 'desc') 1581 1582 # Test command-line values that are not in the permitted list of enums. 1583 flags.DEFINE_multi_enum('m_enum4', 'FOO', ['FOO', 'BAR', 'BAZ'], 1584 'enum option that can occur multiple times') 1585 argv = ('./program', '--m_enum4=INVALID') 1586 self.assertRaisesRegex( 1587 flags.IllegalFlagValueError, 1588 r'flag --m_enum4=invalid: value should be one of <FOO|BAR|BAZ>', FLAGS, 1589 argv) 1590 1591 1592class MultiEnumClassFlagsTest(absltest.TestCase): 1593 1594 def test_define_results_in_registered_flag_with_none(self): 1595 fv = flags.FlagValues() 1596 enum_defaults = None 1597 flags.DEFINE_multi_enum_class( 1598 'fruit', 1599 enum_defaults, 1600 Fruit, 1601 'Enum option that can occur multiple times', 1602 flag_values=fv) 1603 fv.mark_as_parsed() 1604 1605 self.assertIsNone(fv.fruit) 1606 1607 def test_help_text(self): 1608 fv = flags.FlagValues() 1609 enum_defaults = None 1610 flags.DEFINE_multi_enum_class( 1611 'fruit', 1612 enum_defaults, 1613 Fruit, 1614 'Enum option that can occur multiple times', 1615 flag_values=fv) 1616 1617 self.assertRegex( 1618 fv['fruit'].help, 1619 r'<apple\|orange>: Enum option that can occur multiple times;\s+' 1620 'repeat this option to specify a list of values') 1621 1622 def test_define_results_in_registered_flag_with_string(self): 1623 fv = flags.FlagValues() 1624 enum_defaults = 'apple' 1625 flags.DEFINE_multi_enum_class( 1626 'fruit', 1627 enum_defaults, 1628 Fruit, 1629 'Enum option that can occur multiple times', 1630 flag_values=fv) 1631 fv.mark_as_parsed() 1632 1633 self.assertListEqual(fv.fruit, [Fruit.APPLE]) 1634 1635 def test_define_results_in_registered_flag_with_enum(self): 1636 fv = flags.FlagValues() 1637 enum_defaults = Fruit.APPLE 1638 flags.DEFINE_multi_enum_class( 1639 'fruit', 1640 enum_defaults, 1641 Fruit, 1642 'Enum option that can occur multiple times', 1643 flag_values=fv) 1644 fv.mark_as_parsed() 1645 1646 self.assertListEqual(fv.fruit, [Fruit.APPLE]) 1647 1648 def test_define_results_in_registered_flag_with_string_list(self): 1649 fv = flags.FlagValues() 1650 enum_defaults = ['apple', 'APPLE'] 1651 flags.DEFINE_multi_enum_class( 1652 'fruit', 1653 enum_defaults, 1654 CaseSensitiveFruit, 1655 'Enum option that can occur multiple times', 1656 flag_values=fv, 1657 case_sensitive=True) 1658 fv.mark_as_parsed() 1659 1660 self.assertListEqual(fv.fruit, 1661 [CaseSensitiveFruit.apple, CaseSensitiveFruit.APPLE]) 1662 1663 def test_define_results_in_registered_flag_with_enum_list(self): 1664 fv = flags.FlagValues() 1665 enum_defaults = [Fruit.APPLE, Fruit.ORANGE] 1666 flags.DEFINE_multi_enum_class( 1667 'fruit', 1668 enum_defaults, 1669 Fruit, 1670 'Enum option that can occur multiple times', 1671 flag_values=fv) 1672 fv.mark_as_parsed() 1673 1674 self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE]) 1675 1676 def test_from_command_line_returns_multiple(self): 1677 fv = flags.FlagValues() 1678 enum_defaults = [Fruit.APPLE] 1679 flags.DEFINE_multi_enum_class( 1680 'fruit', 1681 enum_defaults, 1682 Fruit, 1683 'Enum option that can occur multiple times', 1684 flag_values=fv) 1685 argv = ('./program', '--fruit=Apple', '--fruit=orange') 1686 fv(argv) 1687 self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE]) 1688 1689 def test_bad_multi_enum_class_flags_from_definition(self): 1690 with self.assertRaisesRegex( 1691 flags.IllegalFlagValueError, 1692 'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'): 1693 flags.DEFINE_multi_enum_class('fruit', ['INVALID'], Fruit, 'desc') 1694 1695 def test_bad_multi_enum_class_flags_from_commandline(self): 1696 fv = flags.FlagValues() 1697 enum_defaults = [Fruit.APPLE] 1698 flags.DEFINE_multi_enum_class( 1699 'fruit', enum_defaults, Fruit, 'desc', flag_values=fv) 1700 argv = ('./program', '--fruit=INVALID') 1701 with self.assertRaisesRegex( 1702 flags.IllegalFlagValueError, 1703 'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'): 1704 fv(argv) 1705 1706 1707class UnicodeFlagsTest(absltest.TestCase): 1708 """Testing proper unicode support for flags.""" 1709 1710 def test_unicode_default_and_helpstring(self): 1711 fv = flags.FlagValues() 1712 flags.DEFINE_string( 1713 'unicode_str', 1714 b'\xC3\x80\xC3\xBD'.decode('utf-8'), 1715 b'help:\xC3\xAA'.decode('utf-8'), 1716 flag_values=fv) 1717 argv = ('./program',) 1718 fv(argv) # should not raise any exceptions 1719 1720 argv = ('./program', '--unicode_str=foo') 1721 fv(argv) # should not raise any exceptions 1722 1723 def test_unicode_in_list(self): 1724 fv = flags.FlagValues() 1725 flags.DEFINE_list( 1726 'unicode_list', 1727 ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')], 1728 b'help:\xC3\xAB'.decode('utf-8'), 1729 flag_values=fv) 1730 argv = ('./program',) 1731 fv(argv) # should not raise any exceptions 1732 1733 argv = ('./program', '--unicode_list=hello,there') 1734 fv(argv) # should not raise any exceptions 1735 1736 def test_xmloutput(self): 1737 fv = flags.FlagValues() 1738 flags.DEFINE_string( 1739 'unicode1', 1740 b'\xC3\x80\xC3\xBD'.decode('utf-8'), 1741 b'help:\xC3\xAC'.decode('utf-8'), 1742 flag_values=fv) 1743 flags.DEFINE_list( 1744 'unicode2', 1745 ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')], 1746 b'help:\xC3\xAD'.decode('utf-8'), 1747 flag_values=fv) 1748 flags.DEFINE_list( 1749 'non_unicode', ['abc', 'def', 'ghi'], 1750 b'help:\xC3\xAD'.decode('utf-8'), 1751 flag_values=fv) 1752 1753 outfile = io.StringIO() 1754 fv.write_help_in_xml_format(outfile) 1755 actual_output = outfile.getvalue() 1756 1757 # The xml output is large, so we just check parts of it. 1758 self.assertIn( 1759 b'<name>unicode1</name>\n' 1760 b' <meaning>help:\xc3\xac</meaning>\n' 1761 b' <default>\xc3\x80\xc3\xbd</default>\n' 1762 b' <current>\xc3\x80\xc3\xbd</current>'.decode('utf-8'), 1763 actual_output) 1764 self.assertIn( 1765 b'<name>unicode2</name>\n' 1766 b' <meaning>help:\xc3\xad</meaning>\n' 1767 b' <default>abc,\xc3\x80,\xc3\xbd</default>\n' 1768 b" <current>['abc', '\xc3\x80', '\xc3\xbd']" 1769 b'</current>'.decode('utf-8'), actual_output) 1770 self.assertIn( 1771 b'<name>non_unicode</name>\n' 1772 b' <meaning>help:\xc3\xad</meaning>\n' 1773 b' <default>abc,def,ghi</default>\n' 1774 b" <current>['abc', 'def', 'ghi']" 1775 b'</current>'.decode('utf-8'), actual_output) 1776 1777 1778class LoadFromFlagFileTest(absltest.TestCase): 1779 """Testing loading flags from a file and parsing them.""" 1780 1781 def setUp(self): 1782 self.flag_values = flags.FlagValues() 1783 flags.DEFINE_string( 1784 'unittest_message1', 1785 'Foo!', 1786 'You Add Here.', 1787 flag_values=self.flag_values) 1788 flags.DEFINE_string( 1789 'unittest_message2', 1790 'Bar!', 1791 'Hello, Sailor!', 1792 flag_values=self.flag_values) 1793 flags.DEFINE_boolean( 1794 'unittest_boolflag', 1795 0, 1796 'Some Boolean thing', 1797 flag_values=self.flag_values) 1798 flags.DEFINE_integer( 1799 'unittest_number', 1800 12345, 1801 'Some integer', 1802 lower_bound=0, 1803 flag_values=self.flag_values) 1804 flags.DEFINE_list( 1805 'UnitTestList', '1,2,3', 'Some list', flag_values=self.flag_values) 1806 self.tmp_path = None 1807 self.flag_values.mark_as_parsed() 1808 1809 def tearDown(self): 1810 self._remove_test_files() 1811 1812 def _setup_test_files(self): 1813 """Creates and sets up some dummy flagfile files with bogus flags.""" 1814 1815 # Figure out where to create temporary files 1816 self.assertFalse(self.tmp_path) 1817 self.tmp_path = tempfile.mkdtemp() 1818 1819 tmp_flag_file_1 = open(self.tmp_path + '/UnitTestFile1.tst', 'w') 1820 tmp_flag_file_2 = open(self.tmp_path + '/UnitTestFile2.tst', 'w') 1821 tmp_flag_file_3 = open(self.tmp_path + '/UnitTestFile3.tst', 'w') 1822 tmp_flag_file_4 = open(self.tmp_path + '/UnitTestFile4.tst', 'w') 1823 1824 # put some dummy flags in our test files 1825 tmp_flag_file_1.write('#A Fake Comment\n') 1826 tmp_flag_file_1.write('--unittest_message1=tempFile1!\n') 1827 tmp_flag_file_1.write('\n') 1828 tmp_flag_file_1.write('--unittest_number=54321\n') 1829 tmp_flag_file_1.write('--nounittest_boolflag\n') 1830 file_list = [tmp_flag_file_1.name] 1831 # this one includes test file 1 1832 tmp_flag_file_2.write('//A Different Fake Comment\n') 1833 tmp_flag_file_2.write('--flagfile=%s\n' % tmp_flag_file_1.name) 1834 tmp_flag_file_2.write('--unittest_message2=setFromTempFile2\n') 1835 tmp_flag_file_2.write('\t\t\n') 1836 tmp_flag_file_2.write('--unittest_number=6789a\n') 1837 file_list.append(tmp_flag_file_2.name) 1838 # this file points to itself 1839 tmp_flag_file_3.write('--flagfile=%s\n' % tmp_flag_file_3.name) 1840 tmp_flag_file_3.write('--unittest_message1=setFromTempFile3\n') 1841 tmp_flag_file_3.write('#YAFC\n') 1842 tmp_flag_file_3.write('--unittest_boolflag\n') 1843 file_list.append(tmp_flag_file_3.name) 1844 # this file is unreadable 1845 tmp_flag_file_4.write('--flagfile=%s\n' % tmp_flag_file_3.name) 1846 tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n') 1847 tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n') 1848 os.chmod(self.tmp_path + '/UnitTestFile4.tst', 0) 1849 file_list.append(tmp_flag_file_4.name) 1850 1851 tmp_flag_file_1.close() 1852 tmp_flag_file_2.close() 1853 tmp_flag_file_3.close() 1854 tmp_flag_file_4.close() 1855 1856 return file_list # these are just the file names 1857 1858 def _remove_test_files(self): 1859 """Removes the files we just created.""" 1860 if self.tmp_path: 1861 shutil.rmtree(self.tmp_path, ignore_errors=True) 1862 self.tmp_path = None 1863 1864 def _read_flags_from_files(self, argv, force_gnu): 1865 return argv[:1] + self.flag_values.read_flags_from_files( 1866 argv[1:], force_gnu=force_gnu) 1867 1868 #### Flagfile Unit Tests #### 1869 def test_method_flagfiles_1(self): 1870 """Test trivial case with no flagfile based options.""" 1871 fake_cmd_line = 'fooScript --unittest_boolflag' 1872 fake_argv = fake_cmd_line.split(' ') 1873 self.flag_values(fake_argv) 1874 self.assertEqual(self.flag_values.unittest_boolflag, 1) 1875 self.assertListEqual(fake_argv, 1876 self._read_flags_from_files(fake_argv, False)) 1877 1878 def test_method_flagfiles_2(self): 1879 """Tests parsing one file + arguments off simulated argv.""" 1880 tmp_files = self._setup_test_files() 1881 # specify our temp file on the fake cmd line 1882 fake_cmd_line = 'fooScript --q --flagfile=%s' % tmp_files[0] 1883 fake_argv = fake_cmd_line.split(' ') 1884 1885 # We should see the original cmd line with the file's contents spliced in. 1886 # Flags from the file will appear in the order order they are specified 1887 # in the file, in the same position as the flagfile argument. 1888 expected_results = [ 1889 'fooScript', '--q', '--unittest_message1=tempFile1!', 1890 '--unittest_number=54321', '--nounittest_boolflag' 1891 ] 1892 test_results = self._read_flags_from_files(fake_argv, False) 1893 self.assertListEqual(expected_results, test_results) 1894 1895 # end testTwo def 1896 1897 def test_method_flagfiles_3(self): 1898 """Tests parsing nested files + arguments of simulated argv.""" 1899 tmp_files = self._setup_test_files() 1900 # specify our temp file on the fake cmd line 1901 fake_cmd_line = ('fooScript --unittest_number=77 --flagfile=%s' % 1902 tmp_files[1]) 1903 fake_argv = fake_cmd_line.split(' ') 1904 1905 expected_results = [ 1906 'fooScript', '--unittest_number=77', '--unittest_message1=tempFile1!', 1907 '--unittest_number=54321', '--nounittest_boolflag', 1908 '--unittest_message2=setFromTempFile2', '--unittest_number=6789a' 1909 ] 1910 test_results = self._read_flags_from_files(fake_argv, False) 1911 self.assertListEqual(expected_results, test_results) 1912 1913 # end testThree def 1914 1915 def test_method_flagfiles_3_spaces(self): 1916 """Tests parsing nested files + arguments of simulated argv. 1917 1918 The arguments include a pair that is actually an arg with a value, so it 1919 doesn't stop processing. 1920 """ 1921 tmp_files = self._setup_test_files() 1922 # specify our temp file on the fake cmd line 1923 fake_cmd_line = ('fooScript --unittest_number 77 --flagfile=%s' % 1924 tmp_files[1]) 1925 fake_argv = fake_cmd_line.split(' ') 1926 1927 expected_results = [ 1928 'fooScript', '--unittest_number', '77', 1929 '--unittest_message1=tempFile1!', '--unittest_number=54321', 1930 '--nounittest_boolflag', '--unittest_message2=setFromTempFile2', 1931 '--unittest_number=6789a' 1932 ] 1933 test_results = self._read_flags_from_files(fake_argv, False) 1934 self.assertListEqual(expected_results, test_results) 1935 1936 def test_method_flagfiles_3_spaces_boolean(self): 1937 """Tests parsing nested files + arguments of simulated argv. 1938 1939 The arguments include a pair that looks like a --x y arg with value, but 1940 since the flag is a boolean it's actually not. 1941 """ 1942 tmp_files = self._setup_test_files() 1943 # specify our temp file on the fake cmd line 1944 fake_cmd_line = ('fooScript --unittest_boolflag 77 --flagfile=%s' % 1945 tmp_files[1]) 1946 fake_argv = fake_cmd_line.split(' ') 1947 1948 expected_results = [ 1949 'fooScript', '--unittest_boolflag', '77', 1950 '--flagfile=%s' % tmp_files[1] 1951 ] 1952 with _use_gnu_getopt(self.flag_values, False): 1953 test_results = self._read_flags_from_files(fake_argv, False) 1954 self.assertListEqual(expected_results, test_results) 1955 1956 def test_method_flagfiles_4(self): 1957 """Tests parsing self-referential files + arguments of simulated argv. 1958 1959 This test should print a warning to stderr of some sort. 1960 """ 1961 tmp_files = self._setup_test_files() 1962 # specify our temp file on the fake cmd line 1963 fake_cmd_line = ('fooScript --flagfile=%s --nounittest_boolflag' % 1964 tmp_files[2]) 1965 fake_argv = fake_cmd_line.split(' ') 1966 expected_results = [ 1967 'fooScript', '--unittest_message1=setFromTempFile3', 1968 '--unittest_boolflag', '--nounittest_boolflag' 1969 ] 1970 1971 test_results = self._read_flags_from_files(fake_argv, False) 1972 self.assertListEqual(expected_results, test_results) 1973 1974 def test_method_flagfiles_5(self): 1975 """Test that --flagfile parsing respects the '--' end-of-options marker.""" 1976 tmp_files = self._setup_test_files() 1977 # specify our temp file on the fake cmd line 1978 fake_cmd_line = 'fooScript --some_flag -- --flagfile=%s' % tmp_files[0] 1979 fake_argv = fake_cmd_line.split(' ') 1980 expected_results = [ 1981 'fooScript', '--some_flag', '--', 1982 '--flagfile=%s' % tmp_files[0] 1983 ] 1984 1985 test_results = self._read_flags_from_files(fake_argv, False) 1986 self.assertListEqual(expected_results, test_results) 1987 1988 def test_method_flagfiles_6(self): 1989 """Test that --flagfile parsing stops at non-options (non-GNU behavior).""" 1990 tmp_files = self._setup_test_files() 1991 # specify our temp file on the fake cmd line 1992 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 1993 tmp_files[0]) 1994 fake_argv = fake_cmd_line.split(' ') 1995 expected_results = [ 1996 'fooScript', '--some_flag', 'some_arg', 1997 '--flagfile=%s' % tmp_files[0] 1998 ] 1999 2000 with _use_gnu_getopt(self.flag_values, False): 2001 test_results = self._read_flags_from_files(fake_argv, False) 2002 self.assertListEqual(expected_results, test_results) 2003 2004 def test_method_flagfiles_7(self): 2005 """Test that --flagfile parsing skips over a non-option (GNU behavior).""" 2006 self.flag_values.set_gnu_getopt() 2007 tmp_files = self._setup_test_files() 2008 # specify our temp file on the fake cmd line 2009 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2010 tmp_files[0]) 2011 fake_argv = fake_cmd_line.split(' ') 2012 expected_results = [ 2013 'fooScript', '--some_flag', 'some_arg', 2014 '--unittest_message1=tempFile1!', '--unittest_number=54321', 2015 '--nounittest_boolflag' 2016 ] 2017 2018 test_results = self._read_flags_from_files(fake_argv, False) 2019 self.assertListEqual(expected_results, test_results) 2020 2021 def test_method_flagfiles_8(self): 2022 """Test that --flagfile parsing respects force_gnu=True.""" 2023 tmp_files = self._setup_test_files() 2024 # specify our temp file on the fake cmd line 2025 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2026 tmp_files[0]) 2027 fake_argv = fake_cmd_line.split(' ') 2028 expected_results = [ 2029 'fooScript', '--some_flag', 'some_arg', 2030 '--unittest_message1=tempFile1!', '--unittest_number=54321', 2031 '--nounittest_boolflag' 2032 ] 2033 2034 test_results = self._read_flags_from_files(fake_argv, True) 2035 self.assertListEqual(expected_results, test_results) 2036 2037 def test_method_flagfiles_repeated_non_circular(self): 2038 """Tests that parsing repeated non-circular flagfiles works.""" 2039 tmp_files = self._setup_test_files() 2040 # specify our temp files on the fake cmd line 2041 fake_cmd_line = ('fooScript --flagfile=%s --flagfile=%s' % 2042 (tmp_files[1], tmp_files[0])) 2043 fake_argv = fake_cmd_line.split(' ') 2044 expected_results = [ 2045 'fooScript', '--unittest_message1=tempFile1!', 2046 '--unittest_number=54321', '--nounittest_boolflag', 2047 '--unittest_message2=setFromTempFile2', '--unittest_number=6789a', 2048 '--unittest_message1=tempFile1!', '--unittest_number=54321', 2049 '--nounittest_boolflag' 2050 ] 2051 2052 test_results = self._read_flags_from_files(fake_argv, False) 2053 self.assertListEqual(expected_results, test_results) 2054 2055 @unittest.skipIf( 2056 os.name == 'nt', 2057 'There is no good way to create an unreadable file on Windows.') 2058 def test_method_flagfiles_no_permissions(self): 2059 """Test that --flagfile raises except on file that is unreadable.""" 2060 tmp_files = self._setup_test_files() 2061 # specify our temp file on the fake cmd line 2062 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2063 tmp_files[3]) 2064 fake_argv = fake_cmd_line.split(' ') 2065 self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files, 2066 fake_argv, True) 2067 2068 def test_method_flagfiles_not_found(self): 2069 """Test that --flagfile raises except on file that does not exist.""" 2070 tmp_files = self._setup_test_files() 2071 # specify our temp file on the fake cmd line 2072 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%sNOTEXIST' % 2073 tmp_files[3]) 2074 fake_argv = fake_cmd_line.split(' ') 2075 self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files, 2076 fake_argv, True) 2077 2078 def test_flagfiles_user_path_expansion(self): 2079 """Test that user directory referenced paths are correctly expanded. 2080 2081 Test paths like ~/foo. This test depends on whatever account's running 2082 the unit test to have read/write access to their own home directory, 2083 otherwise it'll FAIL. 2084 """ 2085 fake_flagfile_item_style_1 = '--flagfile=~/foo.file' 2086 fake_flagfile_item_style_2 = '-flagfile=~/foo.file' 2087 2088 expected_results = os.path.expanduser('~/foo.file') 2089 2090 test_results = self.flag_values._extract_filename( 2091 fake_flagfile_item_style_1) 2092 self.assertEqual(expected_results, test_results) 2093 2094 test_results = self.flag_values._extract_filename( 2095 fake_flagfile_item_style_2) 2096 self.assertEqual(expected_results, test_results) 2097 2098 def test_no_touchy_non_flags(self): 2099 """Test that the flags parser does not mutilate arguments. 2100 2101 The arguments are not supposed to be flags 2102 """ 2103 fake_argv = [ 2104 'fooScript', '--unittest_boolflag', 'command', '--command_arg1', 2105 '--UnitTestBoom', '--UnitTestB' 2106 ] 2107 with _use_gnu_getopt(self.flag_values, False): 2108 argv = self.flag_values(fake_argv) 2109 self.assertListEqual(argv, fake_argv[:1] + fake_argv[2:]) 2110 2111 def test_parse_flags_after_args_if_using_gnugetopt(self): 2112 """Test that flags given after arguments are parsed if using gnu_getopt.""" 2113 self.flag_values.set_gnu_getopt() 2114 fake_argv = [ 2115 'fooScript', '--unittest_boolflag', 'command', '--unittest_number=54321' 2116 ] 2117 argv = self.flag_values(fake_argv) 2118 self.assertListEqual(argv, ['fooScript', 'command']) 2119 2120 def test_set_default(self): 2121 """Test changing flag defaults.""" 2122 # Test that set_default changes both the default and the value, 2123 # and that the value is changed when one is given as an option. 2124 self.flag_values.set_default('unittest_message1', 'New value') 2125 self.assertEqual(self.flag_values.unittest_message1, 'New value') 2126 self.assertEqual(self.flag_values['unittest_message1'].default_as_str, 2127 "'New value'") 2128 self.flag_values(['dummyscript', '--unittest_message1=Newer value']) 2129 self.assertEqual(self.flag_values.unittest_message1, 'Newer value') 2130 2131 # Test that setting the default to None works correctly. 2132 self.flag_values.set_default('unittest_number', None) 2133 self.assertEqual(self.flag_values.unittest_number, None) 2134 self.assertEqual(self.flag_values['unittest_number'].default_as_str, None) 2135 self.flag_values(['dummyscript', '--unittest_number=56']) 2136 self.assertEqual(self.flag_values.unittest_number, 56) 2137 2138 # Test that setting the default to zero works correctly. 2139 self.flag_values.set_default('unittest_number', 0) 2140 self.assertEqual(self.flag_values['unittest_number'].default, 0) 2141 self.assertEqual(self.flag_values.unittest_number, 56) 2142 self.assertEqual(self.flag_values['unittest_number'].default_as_str, "'0'") 2143 self.flag_values(['dummyscript', '--unittest_number=56']) 2144 self.assertEqual(self.flag_values.unittest_number, 56) 2145 2146 # Test that setting the default to '' works correctly. 2147 self.flag_values.set_default('unittest_message1', '') 2148 self.assertEqual(self.flag_values['unittest_message1'].default, '') 2149 self.assertEqual(self.flag_values.unittest_message1, 'Newer value') 2150 self.assertEqual(self.flag_values['unittest_message1'].default_as_str, "''") 2151 self.flag_values(['dummyscript', '--unittest_message1=fifty-six']) 2152 self.assertEqual(self.flag_values.unittest_message1, 'fifty-six') 2153 2154 # Test that setting the default to false works correctly. 2155 self.flag_values.set_default('unittest_boolflag', False) 2156 self.assertEqual(self.flag_values.unittest_boolflag, False) 2157 self.assertEqual(self.flag_values['unittest_boolflag'].default_as_str, 2158 "'false'") 2159 self.flag_values(['dummyscript', '--unittest_boolflag=true']) 2160 self.assertEqual(self.flag_values.unittest_boolflag, True) 2161 2162 # Test that setting a list default works correctly. 2163 self.flag_values.set_default('UnitTestList', '4,5,6') 2164 self.assertListEqual(self.flag_values.UnitTestList, ['4', '5', '6']) 2165 self.assertEqual(self.flag_values['UnitTestList'].default_as_str, "'4,5,6'") 2166 self.flag_values(['dummyscript', '--UnitTestList=7,8,9']) 2167 self.assertListEqual(self.flag_values.UnitTestList, ['7', '8', '9']) 2168 2169 # Test that setting invalid defaults raises exceptions 2170 with self.assertRaises(flags.IllegalFlagValueError): 2171 self.flag_values.set_default('unittest_number', 'oops') 2172 with self.assertRaises(flags.IllegalFlagValueError): 2173 self.flag_values.set_default('unittest_number', -1) 2174 2175 2176class FlagsParsingTest(absltest.TestCase): 2177 """Testing different aspects of parsing: '-f' vs '--flag', etc.""" 2178 2179 def setUp(self): 2180 self.flag_values = flags.FlagValues() 2181 2182 def test_two_dash_arg_first(self): 2183 flags.DEFINE_string( 2184 'twodash_name', 'Bob', 'namehelp', flag_values=self.flag_values) 2185 flags.DEFINE_string( 2186 'twodash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values) 2187 argv = ('./program', '--', '--twodash_name=Harry') 2188 argv = self.flag_values(argv) 2189 self.assertEqual('Bob', self.flag_values.twodash_name) 2190 self.assertEqual(argv[1], '--twodash_name=Harry') 2191 2192 def test_two_dash_arg_middle(self): 2193 flags.DEFINE_string( 2194 'twodash2_name', 'Bob', 'namehelp', flag_values=self.flag_values) 2195 flags.DEFINE_string( 2196 'twodash2_blame', 'Rob', 'blamehelp', flag_values=self.flag_values) 2197 argv = ('./program', '--twodash2_blame=Larry', '--', 2198 '--twodash2_name=Harry') 2199 argv = self.flag_values(argv) 2200 self.assertEqual('Bob', self.flag_values.twodash2_name) 2201 self.assertEqual('Larry', self.flag_values.twodash2_blame) 2202 self.assertEqual(argv[1], '--twodash2_name=Harry') 2203 2204 def test_one_dash_arg_first(self): 2205 flags.DEFINE_string( 2206 'onedash_name', 'Bob', 'namehelp', flag_values=self.flag_values) 2207 flags.DEFINE_string( 2208 'onedash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values) 2209 argv = ('./program', '-', '--onedash_name=Harry') 2210 with _use_gnu_getopt(self.flag_values, False): 2211 argv = self.flag_values(argv) 2212 self.assertEqual(len(argv), 3) 2213 self.assertEqual(argv[1], '-') 2214 self.assertEqual(argv[2], '--onedash_name=Harry') 2215 2216 def test_required_flag_not_specified(self): 2217 flags.DEFINE_string( 2218 'str_flag', 2219 default=None, 2220 help='help', 2221 required=True, 2222 flag_values=self.flag_values) 2223 argv = ('./program',) 2224 with _use_gnu_getopt(self.flag_values, False): 2225 with self.assertRaises(flags.IllegalFlagValueError): 2226 self.flag_values(argv) 2227 2228 def test_required_arg_works_with_other_validators(self): 2229 flags.DEFINE_integer( 2230 'int_flag', 2231 default=None, 2232 help='help', 2233 required=True, 2234 lower_bound=4, 2235 flag_values=self.flag_values) 2236 argv = ('./program', '--int_flag=2') 2237 with _use_gnu_getopt(self.flag_values, False): 2238 with self.assertRaises(flags.IllegalFlagValueError): 2239 self.flag_values(argv) 2240 2241 def test_unrecognized_flags(self): 2242 flags.DEFINE_string('name', 'Bob', 'namehelp', flag_values=self.flag_values) 2243 # Unknown flag --nosuchflag 2244 try: 2245 argv = ('./program', '--nosuchflag', '--name=Bob', 'extra') 2246 self.flag_values(argv) 2247 raise AssertionError('Unknown flag exception not raised') 2248 except flags.UnrecognizedFlagError as e: 2249 self.assertEqual(e.flagname, 'nosuchflag') 2250 self.assertEqual(e.flagvalue, '--nosuchflag') 2251 2252 # Unknown flag -w (short option) 2253 try: 2254 argv = ('./program', '-w', '--name=Bob', 'extra') 2255 self.flag_values(argv) 2256 raise AssertionError('Unknown flag exception not raised') 2257 except flags.UnrecognizedFlagError as e: 2258 self.assertEqual(e.flagname, 'w') 2259 self.assertEqual(e.flagvalue, '-w') 2260 2261 # Unknown flag --nosuchflagwithparam=foo 2262 try: 2263 argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 'extra') 2264 self.flag_values(argv) 2265 raise AssertionError('Unknown flag exception not raised') 2266 except flags.UnrecognizedFlagError as e: 2267 self.assertEqual(e.flagname, 'nosuchflagwithparam') 2268 self.assertEqual(e.flagvalue, '--nosuchflagwithparam=foo') 2269 2270 # Allow unknown flag --nosuchflag if specified with undefok 2271 argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchflag', 2272 'extra') 2273 argv = self.flag_values(argv) 2274 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2275 self.assertEqual(argv[0], './program', 'program name not preserved') 2276 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2277 2278 # Allow unknown flag --noboolflag if undefok=boolflag is specified 2279 argv = ('./program', '--noboolflag', '--name=Bob', '--undefok=boolflag', 2280 'extra') 2281 argv = self.flag_values(argv) 2282 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2283 self.assertEqual(argv[0], './program', 'program name not preserved') 2284 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2285 2286 # But not if the flagname is misspelled: 2287 try: 2288 argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchfla', 2289 'extra') 2290 self.flag_values(argv) 2291 raise AssertionError('Unknown flag exception not raised') 2292 except flags.UnrecognizedFlagError as e: 2293 self.assertEqual(e.flagname, 'nosuchflag') 2294 2295 try: 2296 argv = ('./program', '--nosuchflag', '--name=Bob', 2297 '--undefok=nosuchflagg', 'extra') 2298 self.flag_values(argv) 2299 raise AssertionError('Unknown flag exception not raised') 2300 except flags.UnrecognizedFlagError as e: 2301 self.assertEqual(e.flagname, 'nosuchflag') 2302 2303 # Allow unknown short flag -w if specified with undefok 2304 argv = ('./program', '-w', '--name=Bob', '--undefok=w', 'extra') 2305 argv = self.flag_values(argv) 2306 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2307 self.assertEqual(argv[0], './program', 'program name not preserved') 2308 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2309 2310 # Allow unknown flag --nosuchflagwithparam=foo if specified 2311 # with undefok 2312 argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 2313 '--undefok=nosuchflagwithparam', 'extra') 2314 argv = self.flag_values(argv) 2315 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2316 self.assertEqual(argv[0], './program', 'program name not preserved') 2317 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2318 2319 # Even if undefok specifies multiple flags 2320 argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo', 2321 '--name=Bob', '--undefok=nosuchflag,w,nosuchflagwithparam', 'extra') 2322 argv = self.flag_values(argv) 2323 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2324 self.assertEqual(argv[0], './program', 'program name not preserved') 2325 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2326 2327 # However, not if undefok doesn't specify the flag 2328 try: 2329 argv = ('./program', '--nosuchflag', '--name=Bob', 2330 '--undefok=another_such', 'extra') 2331 self.flag_values(argv) 2332 raise AssertionError('Unknown flag exception not raised') 2333 except flags.UnrecognizedFlagError as e: 2334 self.assertEqual(e.flagname, 'nosuchflag') 2335 2336 # Make sure --undefok doesn't mask other option errors. 2337 try: 2338 # Provide an option requiring a parameter but not giving it one. 2339 argv = ('./program', '--undefok=name', '--name') 2340 self.flag_values(argv) 2341 raise AssertionError('Missing option parameter exception not raised') 2342 except flags.UnrecognizedFlagError: 2343 raise AssertionError('Wrong kind of error exception raised') 2344 except flags.Error: 2345 pass 2346 2347 # Test --undefok <list> 2348 argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo', 2349 '--name=Bob', '--undefok', 'nosuchflag,w,nosuchflagwithparam', 2350 'extra') 2351 argv = self.flag_values(argv) 2352 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2353 self.assertEqual(argv[0], './program', 'program name not preserved') 2354 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2355 2356 # Test incorrect --undefok with no value. 2357 argv = ('./program', '--name=Bob', '--undefok') 2358 with self.assertRaises(flags.Error): 2359 self.flag_values(argv) 2360 2361 2362class NonGlobalFlagsTest(absltest.TestCase): 2363 2364 def test_nonglobal_flags(self): 2365 """Test use of non-global FlagValues.""" 2366 nonglobal_flags = flags.FlagValues() 2367 flags.DEFINE_string('nonglobal_flag', 'Bob', 'flaghelp', nonglobal_flags) 2368 argv = ('./program', '--nonglobal_flag=Mary', 'extra') 2369 argv = nonglobal_flags(argv) 2370 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2371 self.assertEqual(argv[0], './program', 'program name not preserved') 2372 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2373 self.assertEqual(nonglobal_flags['nonglobal_flag'].value, 'Mary') 2374 2375 def test_unrecognized_nonglobal_flags(self): 2376 """Test unrecognized non-global flags.""" 2377 nonglobal_flags = flags.FlagValues() 2378 argv = ('./program', '--nosuchflag') 2379 try: 2380 argv = nonglobal_flags(argv) 2381 raise AssertionError('Unknown flag exception not raised') 2382 except flags.UnrecognizedFlagError as e: 2383 self.assertEqual(e.flagname, 'nosuchflag') 2384 2385 argv = ('./program', '--nosuchflag', '--undefok=nosuchflag') 2386 2387 argv = nonglobal_flags(argv) 2388 self.assertEqual(len(argv), 1, 'wrong number of arguments pulled') 2389 self.assertEqual(argv[0], './program', 'program name not preserved') 2390 2391 def test_create_flag_errors(self): 2392 # Since the exception classes are exposed, nothing stops users 2393 # from creating their own instances. This test makes sure that 2394 # people modifying the flags module understand that the external 2395 # mechanisms for creating the exceptions should continue to work. 2396 _ = flags.Error() 2397 _ = flags.Error('message') 2398 _ = flags.DuplicateFlagError() 2399 _ = flags.DuplicateFlagError('message') 2400 _ = flags.IllegalFlagValueError() 2401 _ = flags.IllegalFlagValueError('message') 2402 2403 def test_flag_values_del_attr(self): 2404 """Checks that del self.flag_values.flag_id works.""" 2405 default_value = 'default value for test_flag_values_del_attr' 2406 # 1. Declare and delete a flag with no short name. 2407 flag_values = flags.FlagValues() 2408 flags.DEFINE_string( 2409 'delattr_foo', default_value, 'A simple flag.', flag_values=flag_values) 2410 2411 flag_values.mark_as_parsed() 2412 self.assertEqual(flag_values.delattr_foo, default_value) 2413 flag_obj = flag_values['delattr_foo'] 2414 # We also check that _FlagIsRegistered works as expected :) 2415 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2416 del flag_values.delattr_foo 2417 self.assertFalse('delattr_foo' in flag_values._flags()) 2418 self.assertFalse(flag_values._flag_is_registered(flag_obj)) 2419 # If the previous del FLAGS.delattr_foo did not work properly, the 2420 # next definition will trigger a redefinition error. 2421 flags.DEFINE_integer( 2422 'delattr_foo', 3, 'A simple flag.', flag_values=flag_values) 2423 del flag_values.delattr_foo 2424 2425 self.assertFalse('delattr_foo' in flag_values) 2426 2427 # 2. Declare and delete a flag with a short name. 2428 flags.DEFINE_string( 2429 'delattr_bar', 2430 default_value, 2431 'flag with short name', 2432 short_name='x5', 2433 flag_values=flag_values) 2434 flag_obj = flag_values['delattr_bar'] 2435 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2436 del flag_values.x5 2437 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2438 del flag_values.delattr_bar 2439 self.assertFalse(flag_values._flag_is_registered(flag_obj)) 2440 2441 # 3. Just like 2, but del flag_values.name last 2442 flags.DEFINE_string( 2443 'delattr_bar', 2444 default_value, 2445 'flag with short name', 2446 short_name='x5', 2447 flag_values=flag_values) 2448 flag_obj = flag_values['delattr_bar'] 2449 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2450 del flag_values.delattr_bar 2451 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2452 del flag_values.x5 2453 self.assertFalse(flag_values._flag_is_registered(flag_obj)) 2454 2455 self.assertFalse('delattr_bar' in flag_values) 2456 self.assertFalse('x5' in flag_values) 2457 2458 def test_list_flag_format(self): 2459 """Tests for correctly-formatted list flags.""" 2460 fv = flags.FlagValues() 2461 flags.DEFINE_list('listflag', '', 'A list of arguments', flag_values=fv) 2462 2463 def _check_parsing(listval): 2464 """Parse a particular value for our test flag, --listflag.""" 2465 argv = fv(['./program', '--listflag=' + listval, 'plain-arg']) 2466 self.assertEqual(['./program', 'plain-arg'], argv) 2467 return fv.listflag 2468 2469 # Basic success case 2470 self.assertEqual(_check_parsing('foo,bar'), ['foo', 'bar']) 2471 # Success case: newline in argument is quoted. 2472 self.assertEqual(_check_parsing('"foo","bar\nbar"'), ['foo', 'bar\nbar']) 2473 # Failure case: newline in argument is unquoted. 2474 self.assertRaises(flags.IllegalFlagValueError, _check_parsing, 2475 '"foo",bar\nbar') 2476 # Failure case: unmatched ". 2477 self.assertRaises(flags.IllegalFlagValueError, _check_parsing, 2478 '"foo,barbar') 2479 2480 def test_flag_definition_via_setitem(self): 2481 with self.assertRaises(flags.IllegalFlagValueError): 2482 flag_values = flags.FlagValues() 2483 flag_values['flag_name'] = 'flag_value' 2484 2485 2486class SetDefaultTest(absltest.TestCase): 2487 2488 def setUp(self): 2489 super().setUp() 2490 self.flag_values = flags.FlagValues() 2491 2492 def test_success(self): 2493 int_holder = flags.DEFINE_integer( 2494 'an_int', 1, 'an int', flag_values=self.flag_values) 2495 2496 flags.set_default(int_holder, 2) 2497 self.flag_values.mark_as_parsed() 2498 2499 self.assertEqual(int_holder.value, 2) 2500 2501 def test_update_after_parse(self): 2502 int_holder = flags.DEFINE_integer( 2503 'an_int', 1, 'an int', flag_values=self.flag_values) 2504 2505 self.flag_values.mark_as_parsed() 2506 flags.set_default(int_holder, 2) 2507 2508 self.assertEqual(int_holder.value, 2) 2509 2510 def test_overridden_by_explicit_assignment(self): 2511 int_holder = flags.DEFINE_integer( 2512 'an_int', 1, 'an int', flag_values=self.flag_values) 2513 2514 self.flag_values.mark_as_parsed() 2515 self.flag_values.an_int = 3 2516 flags.set_default(int_holder, 2) 2517 2518 self.assertEqual(int_holder.value, 3) 2519 2520 def test_restores_back_to_none(self): 2521 int_holder = flags.DEFINE_integer( 2522 'an_int', None, 'an int', flag_values=self.flag_values) 2523 2524 self.flag_values.mark_as_parsed() 2525 flags.set_default(int_holder, 3) 2526 flags.set_default(int_holder, None) 2527 2528 self.assertIsNone(int_holder.value) 2529 2530 def test_failure_on_invalid_type(self): 2531 int_holder = flags.DEFINE_integer( 2532 'an_int', 1, 'an int', flag_values=self.flag_values) 2533 2534 self.flag_values.mark_as_parsed() 2535 2536 with self.assertRaises(flags.IllegalFlagValueError): 2537 flags.set_default(int_holder, 'a') 2538 2539 def test_failure_on_type_protected_none_default(self): 2540 int_holder = flags.DEFINE_integer( 2541 'an_int', 1, 'an int', flag_values=self.flag_values) 2542 2543 self.flag_values.mark_as_parsed() 2544 2545 flags.set_default(int_holder, None) # NOTE: should be a type failure 2546 2547 with self.assertRaises(flags.IllegalFlagValueError): 2548 _ = int_holder.value # Will also fail on later access. 2549 2550 2551class KeyFlagsTest(absltest.TestCase): 2552 2553 def setUp(self): 2554 self.flag_values = flags.FlagValues() 2555 2556 def _get_names_of_defined_flags(self, module, flag_values): 2557 """Returns the list of names of flags defined by a module. 2558 2559 Auxiliary for the test_key_flags* methods. 2560 2561 Args: 2562 module: A module object or a string module name. 2563 flag_values: A FlagValues object. 2564 2565 Returns: 2566 A list of strings. 2567 """ 2568 return [f.name for f in flag_values.get_flags_for_module(module)] 2569 2570 def _get_names_of_key_flags(self, module, flag_values): 2571 """Returns the list of names of key flags for a module. 2572 2573 Auxiliary for the test_key_flags* methods. 2574 2575 Args: 2576 module: A module object or a string module name. 2577 flag_values: A FlagValues object. 2578 2579 Returns: 2580 A list of strings. 2581 """ 2582 return [f.name for f in flag_values.get_key_flags_for_module(module)] 2583 2584 def _assert_lists_have_same_elements(self, list_1, list_2): 2585 # Checks that two lists have the same elements with the same 2586 # multiplicity, in possibly different order. 2587 list_1 = list(list_1) 2588 list_1.sort() 2589 list_2 = list(list_2) 2590 list_2.sort() 2591 self.assertListEqual(list_1, list_2) 2592 2593 def test_key_flags(self): 2594 flag_values = flags.FlagValues() 2595 # Before starting any testing, make sure no flags are already 2596 # defined for module_foo and module_bar. 2597 self.assertListEqual( 2598 self._get_names_of_key_flags(module_foo, flag_values), []) 2599 self.assertListEqual( 2600 self._get_names_of_key_flags(module_bar, flag_values), []) 2601 self.assertListEqual( 2602 self._get_names_of_defined_flags(module_foo, flag_values), []) 2603 self.assertListEqual( 2604 self._get_names_of_defined_flags(module_bar, flag_values), []) 2605 2606 # Defines a few flags in module_foo and module_bar. 2607 module_foo.define_flags(flag_values=flag_values) 2608 2609 try: 2610 # Part 1. Check that all flags defined by module_foo are key for 2611 # that module, and similarly for module_bar. 2612 for module in [module_foo, module_bar]: 2613 self._assert_lists_have_same_elements( 2614 flag_values.get_flags_for_module(module), 2615 flag_values.get_key_flags_for_module(module)) 2616 # Also check that each module defined the expected flags. 2617 self._assert_lists_have_same_elements( 2618 self._get_names_of_defined_flags(module, flag_values), 2619 module.names_of_defined_flags()) 2620 2621 # Part 2. Check that flags.declare_key_flag works fine. 2622 # Declare that some flags from module_bar are key for 2623 # module_foo. 2624 module_foo.declare_key_flags(flag_values=flag_values) 2625 2626 # Check that module_foo has the expected list of defined flags. 2627 self._assert_lists_have_same_elements( 2628 self._get_names_of_defined_flags(module_foo, flag_values), 2629 module_foo.names_of_defined_flags()) 2630 2631 # Check that module_foo has the expected list of key flags. 2632 self._assert_lists_have_same_elements( 2633 self._get_names_of_key_flags(module_foo, flag_values), 2634 module_foo.names_of_declared_key_flags()) 2635 2636 # Part 3. Check that flags.adopt_module_key_flags works fine. 2637 # Trigger a call to flags.adopt_module_key_flags(module_bar) 2638 # inside module_foo. This should declare a few more key 2639 # flags in module_foo. 2640 module_foo.declare_extra_key_flags(flag_values=flag_values) 2641 2642 # Check that module_foo has the expected list of key flags. 2643 self._assert_lists_have_same_elements( 2644 self._get_names_of_key_flags(module_foo, flag_values), 2645 module_foo.names_of_declared_key_flags() + 2646 module_foo.names_of_declared_extra_key_flags()) 2647 finally: 2648 module_foo.remove_flags(flag_values=flag_values) 2649 2650 def test_key_flags_with_non_default_flag_values_object(self): 2651 # Check that key flags work even when we use a FlagValues object 2652 # that is not the default flags.self.flag_values object. Otherwise, this 2653 # test is similar to test_key_flags, but it uses only module_bar. 2654 # The other test module (module_foo) uses only the default values 2655 # for the flag_values keyword arguments. This way, test_key_flags 2656 # and this method test both the default FlagValues, the explicitly 2657 # specified one, and a mixed usage of the two. 2658 2659 # A brand-new FlagValues object, to use instead of flags.self.flag_values. 2660 fv = flags.FlagValues() 2661 2662 # Before starting any testing, make sure no flags are already 2663 # defined for module_foo and module_bar. 2664 self.assertListEqual(self._get_names_of_key_flags(module_bar, fv), []) 2665 self.assertListEqual(self._get_names_of_defined_flags(module_bar, fv), []) 2666 2667 module_bar.define_flags(flag_values=fv) 2668 2669 # Check that all flags defined by module_bar are key for that 2670 # module, and that module_bar defined the expected flags. 2671 self._assert_lists_have_same_elements( 2672 fv.get_flags_for_module(module_bar), 2673 fv.get_key_flags_for_module(module_bar)) 2674 self._assert_lists_have_same_elements( 2675 self._get_names_of_defined_flags(module_bar, fv), 2676 module_bar.names_of_defined_flags()) 2677 2678 # Pick two flags from module_bar, declare them as key for the 2679 # current (i.e., main) module (via flags.declare_key_flag), and 2680 # check that we get the expected effect. The important thing is 2681 # that we always use flags_values=fv (instead of the default 2682 # self.flag_values). 2683 main_module = sys.argv[0] 2684 names_of_flags_defined_by_bar = module_bar.names_of_defined_flags() 2685 flag_name_0 = names_of_flags_defined_by_bar[0] 2686 flag_name_2 = names_of_flags_defined_by_bar[2] 2687 2688 flags.declare_key_flag(flag_name_0, flag_values=fv) 2689 self._assert_lists_have_same_elements( 2690 self._get_names_of_key_flags(main_module, fv), [flag_name_0]) 2691 2692 flags.declare_key_flag(flag_name_2, flag_values=fv) 2693 self._assert_lists_have_same_elements( 2694 self._get_names_of_key_flags(main_module, fv), 2695 [flag_name_0, flag_name_2]) 2696 2697 # Try with a special (not user-defined) flag too: 2698 flags.declare_key_flag('undefok', flag_values=fv) 2699 self._assert_lists_have_same_elements( 2700 self._get_names_of_key_flags(main_module, fv), 2701 [flag_name_0, flag_name_2, 'undefok']) 2702 2703 flags.adopt_module_key_flags(module_bar, fv) 2704 self._assert_lists_have_same_elements( 2705 self._get_names_of_key_flags(main_module, fv), 2706 names_of_flags_defined_by_bar + ['undefok']) 2707 2708 # Adopt key flags from the flags module itself. 2709 flags.adopt_module_key_flags(flags, flag_values=fv) 2710 self._assert_lists_have_same_elements( 2711 self._get_names_of_key_flags(main_module, fv), 2712 names_of_flags_defined_by_bar + ['flagfile', 'undefok']) 2713 2714 def test_key_flags_with_flagholders(self): 2715 main_module = sys.argv[0] 2716 2717 self.assertListEqual( 2718 self._get_names_of_key_flags(main_module, self.flag_values), []) 2719 self.assertListEqual( 2720 self._get_names_of_defined_flags(main_module, self.flag_values), []) 2721 2722 int_holder = flags.DEFINE_integer( 2723 'main_module_int_fg', 2724 1, 2725 'Integer flag in the main module.', 2726 flag_values=self.flag_values) 2727 2728 flags.declare_key_flag(int_holder, self.flag_values) 2729 2730 self.assertCountEqual( 2731 self.flag_values.get_flags_for_module(main_module), 2732 self.flag_values.get_key_flags_for_module(main_module)) 2733 2734 bool_holder = flags.DEFINE_boolean( 2735 'main_module_bool_fg', 2736 False, 2737 'Boolean flag in the main module.', 2738 flag_values=self.flag_values) 2739 2740 flags.declare_key_flag(bool_holder) # omitted flag_values 2741 2742 self.assertCountEqual( 2743 self.flag_values.get_flags_for_module(main_module), 2744 self.flag_values.get_key_flags_for_module(main_module)) 2745 2746 self.assertLen(self.flag_values.get_flags_for_module(main_module), 2) 2747 2748 def test_main_module_help_with_key_flags(self): 2749 # Similar to test_main_module_help, but this time we make sure to 2750 # declare some key flags. 2751 2752 # Safety check that the main module does not declare any flags 2753 # at the beginning of this test. 2754 expected_help = '' 2755 self.assertMultiLineEqual(expected_help, 2756 self.flag_values.main_module_help()) 2757 2758 # Define one flag in this main module and some flags in modules 2759 # a and b. Also declare one flag from module a and one flag 2760 # from module b as key flags for the main module. 2761 flags.DEFINE_integer( 2762 'main_module_int_fg', 2763 1, 2764 'Integer flag in the main module.', 2765 flag_values=self.flag_values) 2766 2767 try: 2768 main_module_int_fg_help = ( 2769 ' --main_module_int_fg: Integer flag in the main module.\n' 2770 " (default: '1')\n" 2771 ' (an integer)') 2772 2773 expected_help += '\n%s:\n%s' % (sys.argv[0], main_module_int_fg_help) 2774 self.assertMultiLineEqual(expected_help, 2775 self.flag_values.main_module_help()) 2776 2777 # The following call should be a no-op: any flag declared by a 2778 # module is automatically key for that module. 2779 flags.declare_key_flag('main_module_int_fg', flag_values=self.flag_values) 2780 self.assertMultiLineEqual(expected_help, 2781 self.flag_values.main_module_help()) 2782 2783 # The definition of a few flags in an imported module should not 2784 # change the main module help. 2785 module_foo.define_flags(flag_values=self.flag_values) 2786 self.assertMultiLineEqual(expected_help, 2787 self.flag_values.main_module_help()) 2788 2789 flags.declare_key_flag('tmod_foo_bool', flag_values=self.flag_values) 2790 tmod_foo_bool_help = ( 2791 ' --[no]tmod_foo_bool: Boolean flag from module foo.\n' 2792 " (default: 'true')") 2793 expected_help += '\n' + tmod_foo_bool_help 2794 self.assertMultiLineEqual(expected_help, 2795 self.flag_values.main_module_help()) 2796 2797 flags.declare_key_flag('tmod_bar_z', flag_values=self.flag_values) 2798 tmod_bar_z_help = ( 2799 ' --[no]tmod_bar_z: Another boolean flag from module bar.\n' 2800 " (default: 'false')") 2801 # Unfortunately, there is some flag sorting inside 2802 # main_module_help, so we can't keep incrementally extending 2803 # the expected_help string ... 2804 expected_help = ('\n%s:\n%s\n%s\n%s' % 2805 (sys.argv[0], main_module_int_fg_help, tmod_bar_z_help, 2806 tmod_foo_bool_help)) 2807 self.assertMultiLineEqual(self.flag_values.main_module_help(), 2808 expected_help) 2809 2810 finally: 2811 # At the end, delete all the flag information we created. 2812 self.flag_values.__delattr__('main_module_int_fg') 2813 module_foo.remove_flags(flag_values=self.flag_values) 2814 2815 def test_adoptmodule_key_flags(self): 2816 # Check that adopt_module_key_flags raises an exception when 2817 # called with a module name (as opposed to a module object). 2818 self.assertRaises(flags.Error, flags.adopt_module_key_flags, 'pyglib.app') 2819 2820 def test_disclaimkey_flags(self): 2821 original_disclaim_module_ids = _helpers.disclaim_module_ids 2822 _helpers.disclaim_module_ids = set(_helpers.disclaim_module_ids) 2823 try: 2824 module_bar.disclaim_key_flags() 2825 module_foo.define_bar_flags(flag_values=self.flag_values) 2826 module_name = self.flag_values.find_module_defining_flag('tmod_bar_x') 2827 self.assertEqual(module_foo.__name__, module_name) 2828 finally: 2829 _helpers.disclaim_module_ids = original_disclaim_module_ids 2830 2831 2832class FindModuleTest(absltest.TestCase): 2833 """Testing methods that find a module that defines a given flag.""" 2834 2835 def test_find_module_defining_flag(self): 2836 self.assertEqual( 2837 'default', 2838 FLAGS.find_module_defining_flag('__NON_EXISTENT_FLAG__', 'default')) 2839 self.assertEqual(module_baz.__name__, 2840 FLAGS.find_module_defining_flag('tmod_baz_x')) 2841 2842 def test_find_module_id_defining_flag(self): 2843 self.assertEqual( 2844 'default', 2845 FLAGS.find_module_id_defining_flag('__NON_EXISTENT_FLAG__', 'default')) 2846 self.assertEqual( 2847 id(module_baz), FLAGS.find_module_id_defining_flag('tmod_baz_x')) 2848 2849 def test_find_module_defining_flag_passing_module_name(self): 2850 my_flags = flags.FlagValues() 2851 module_name = sys.__name__ # Must use an existing module. 2852 flags.DEFINE_boolean( 2853 'flag_name', 2854 True, 2855 'Flag with a different module name.', 2856 flag_values=my_flags, 2857 module_name=module_name) 2858 self.assertEqual(module_name, 2859 my_flags.find_module_defining_flag('flag_name')) 2860 2861 def test_find_module_id_defining_flag_passing_module_name(self): 2862 my_flags = flags.FlagValues() 2863 module_name = sys.__name__ # Must use an existing module. 2864 flags.DEFINE_boolean( 2865 'flag_name', 2866 True, 2867 'Flag with a different module name.', 2868 flag_values=my_flags, 2869 module_name=module_name) 2870 self.assertEqual( 2871 id(sys), my_flags.find_module_id_defining_flag('flag_name')) 2872 2873 2874class FlagsErrorMessagesTest(absltest.TestCase): 2875 """Testing special cases for integer and float flags error messages.""" 2876 2877 def setUp(self): 2878 self.flag_values = flags.FlagValues() 2879 2880 def test_integer_error_text(self): 2881 # Make sure we get proper error text 2882 flags.DEFINE_integer( 2883 'positive', 2884 4, 2885 'non-negative flag', 2886 lower_bound=1, 2887 flag_values=self.flag_values) 2888 flags.DEFINE_integer( 2889 'non_negative', 2890 4, 2891 'positive flag', 2892 lower_bound=0, 2893 flag_values=self.flag_values) 2894 flags.DEFINE_integer( 2895 'negative', 2896 -4, 2897 'negative flag', 2898 upper_bound=-1, 2899 flag_values=self.flag_values) 2900 flags.DEFINE_integer( 2901 'non_positive', 2902 -4, 2903 'non-positive flag', 2904 upper_bound=0, 2905 flag_values=self.flag_values) 2906 flags.DEFINE_integer( 2907 'greater', 2908 19, 2909 'greater-than flag', 2910 lower_bound=4, 2911 flag_values=self.flag_values) 2912 flags.DEFINE_integer( 2913 'smaller', 2914 -19, 2915 'smaller-than flag', 2916 upper_bound=4, 2917 flag_values=self.flag_values) 2918 flags.DEFINE_integer( 2919 'usual', 2920 4, 2921 'usual flag', 2922 lower_bound=0, 2923 upper_bound=10000, 2924 flag_values=self.flag_values) 2925 flags.DEFINE_integer( 2926 'another_usual', 2927 0, 2928 'usual flag', 2929 lower_bound=-1, 2930 upper_bound=1, 2931 flag_values=self.flag_values) 2932 2933 self._check_error_message('positive', -4, 'a positive integer') 2934 self._check_error_message('non_negative', -4, 'a non-negative integer') 2935 self._check_error_message('negative', 0, 'a negative integer') 2936 self._check_error_message('non_positive', 4, 'a non-positive integer') 2937 self._check_error_message('usual', -4, 'an integer in the range [0, 10000]') 2938 self._check_error_message('another_usual', 4, 2939 'an integer in the range [-1, 1]') 2940 self._check_error_message('greater', -5, 'integer >= 4') 2941 self._check_error_message('smaller', 5, 'integer <= 4') 2942 2943 def test_float_error_text(self): 2944 flags.DEFINE_float( 2945 'positive', 2946 4, 2947 'non-negative flag', 2948 lower_bound=1, 2949 flag_values=self.flag_values) 2950 flags.DEFINE_float( 2951 'non_negative', 2952 4, 2953 'positive flag', 2954 lower_bound=0, 2955 flag_values=self.flag_values) 2956 flags.DEFINE_float( 2957 'negative', 2958 -4, 2959 'negative flag', 2960 upper_bound=-1, 2961 flag_values=self.flag_values) 2962 flags.DEFINE_float( 2963 'non_positive', 2964 -4, 2965 'non-positive flag', 2966 upper_bound=0, 2967 flag_values=self.flag_values) 2968 flags.DEFINE_float( 2969 'greater', 2970 19, 2971 'greater-than flag', 2972 lower_bound=4, 2973 flag_values=self.flag_values) 2974 flags.DEFINE_float( 2975 'smaller', 2976 -19, 2977 'smaller-than flag', 2978 upper_bound=4, 2979 flag_values=self.flag_values) 2980 flags.DEFINE_float( 2981 'usual', 2982 4, 2983 'usual flag', 2984 lower_bound=0, 2985 upper_bound=10000, 2986 flag_values=self.flag_values) 2987 flags.DEFINE_float( 2988 'another_usual', 2989 0, 2990 'usual flag', 2991 lower_bound=-1, 2992 upper_bound=1, 2993 flag_values=self.flag_values) 2994 2995 self._check_error_message('positive', 0.5, 'number >= 1') 2996 self._check_error_message('non_negative', -4.0, 'a non-negative number') 2997 self._check_error_message('negative', 0.5, 'number <= -1') 2998 self._check_error_message('non_positive', 4.0, 'a non-positive number') 2999 self._check_error_message('usual', -4.0, 'a number in the range [0, 10000]') 3000 self._check_error_message('another_usual', 4.0, 3001 'a number in the range [-1, 1]') 3002 self._check_error_message('smaller', 5.0, 'number <= 4') 3003 3004 def _check_error_message(self, flag_name, flag_value, 3005 expected_message_suffix): 3006 """Set a flag to a given value and make sure we get expected message.""" 3007 3008 try: 3009 self.flag_values.__setattr__(flag_name, flag_value) 3010 raise AssertionError('Bounds exception not raised!') 3011 except flags.IllegalFlagValueError as e: 3012 expected = ('flag --%(name)s=%(value)s: %(value)s is not %(suffix)s' % { 3013 'name': flag_name, 3014 'value': flag_value, 3015 'suffix': expected_message_suffix 3016 }) 3017 self.assertEqual(str(e), expected) 3018 3019 3020if __name__ == '__main__': 3021 absltest.main() 3022