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_short_name(self): 1595 fv = flags.FlagValues() 1596 flags.DEFINE_multi_enum_class( 1597 'fruit', 1598 None, 1599 Fruit, 1600 'Enum option that can occur multiple times', 1601 flag_values=fv, 1602 short_name='me') 1603 self.assertEqual(fv['fruit'].short_name, 'me') 1604 1605 def test_define_results_in_registered_flag_with_none(self): 1606 fv = flags.FlagValues() 1607 enum_defaults = None 1608 flags.DEFINE_multi_enum_class( 1609 'fruit', 1610 enum_defaults, 1611 Fruit, 1612 'Enum option that can occur multiple times', 1613 flag_values=fv) 1614 fv.mark_as_parsed() 1615 1616 self.assertIsNone(fv.fruit) 1617 1618 def test_help_text(self): 1619 fv = flags.FlagValues() 1620 enum_defaults = None 1621 flags.DEFINE_multi_enum_class( 1622 'fruit', 1623 enum_defaults, 1624 Fruit, 1625 'Enum option that can occur multiple times', 1626 flag_values=fv) 1627 1628 self.assertRegex( 1629 fv['fruit'].help, 1630 r'<apple\|orange>: Enum option that can occur multiple times;\s+' 1631 'repeat this option to specify a list of values') 1632 1633 def test_define_results_in_registered_flag_with_string(self): 1634 fv = flags.FlagValues() 1635 enum_defaults = 'apple' 1636 flags.DEFINE_multi_enum_class( 1637 'fruit', 1638 enum_defaults, 1639 Fruit, 1640 'Enum option that can occur multiple times', 1641 flag_values=fv) 1642 fv.mark_as_parsed() 1643 1644 self.assertListEqual(fv.fruit, [Fruit.APPLE]) 1645 1646 def test_define_results_in_registered_flag_with_enum(self): 1647 fv = flags.FlagValues() 1648 enum_defaults = Fruit.APPLE 1649 flags.DEFINE_multi_enum_class( 1650 'fruit', 1651 enum_defaults, 1652 Fruit, 1653 'Enum option that can occur multiple times', 1654 flag_values=fv) 1655 fv.mark_as_parsed() 1656 1657 self.assertListEqual(fv.fruit, [Fruit.APPLE]) 1658 1659 def test_define_results_in_registered_flag_with_string_list(self): 1660 fv = flags.FlagValues() 1661 enum_defaults = ['apple', 'APPLE'] 1662 flags.DEFINE_multi_enum_class( 1663 'fruit', 1664 enum_defaults, 1665 CaseSensitiveFruit, 1666 'Enum option that can occur multiple times', 1667 flag_values=fv, 1668 case_sensitive=True) 1669 fv.mark_as_parsed() 1670 1671 self.assertListEqual(fv.fruit, 1672 [CaseSensitiveFruit.apple, CaseSensitiveFruit.APPLE]) 1673 1674 def test_define_results_in_registered_flag_with_enum_list(self): 1675 fv = flags.FlagValues() 1676 enum_defaults = [Fruit.APPLE, Fruit.ORANGE] 1677 flags.DEFINE_multi_enum_class( 1678 'fruit', 1679 enum_defaults, 1680 Fruit, 1681 'Enum option that can occur multiple times', 1682 flag_values=fv) 1683 fv.mark_as_parsed() 1684 1685 self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE]) 1686 1687 def test_from_command_line_returns_multiple(self): 1688 fv = flags.FlagValues() 1689 enum_defaults = [Fruit.APPLE] 1690 flags.DEFINE_multi_enum_class( 1691 'fruit', 1692 enum_defaults, 1693 Fruit, 1694 'Enum option that can occur multiple times', 1695 flag_values=fv) 1696 argv = ('./program', '--fruit=Apple', '--fruit=orange') 1697 fv(argv) 1698 self.assertListEqual(fv.fruit, [Fruit.APPLE, Fruit.ORANGE]) 1699 1700 def test_bad_multi_enum_class_flags_from_definition(self): 1701 with self.assertRaisesRegex( 1702 flags.IllegalFlagValueError, 1703 'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'): 1704 flags.DEFINE_multi_enum_class('fruit', ['INVALID'], Fruit, 'desc') 1705 1706 def test_bad_multi_enum_class_flags_from_commandline(self): 1707 fv = flags.FlagValues() 1708 enum_defaults = [Fruit.APPLE] 1709 flags.DEFINE_multi_enum_class( 1710 'fruit', enum_defaults, Fruit, 'desc', flag_values=fv) 1711 argv = ('./program', '--fruit=INVALID') 1712 with self.assertRaisesRegex( 1713 flags.IllegalFlagValueError, 1714 'flag --fruit=INVALID: value should be one of <apple|orange|APPLE>'): 1715 fv(argv) 1716 1717 1718class UnicodeFlagsTest(absltest.TestCase): 1719 """Testing proper unicode support for flags.""" 1720 1721 def test_unicode_default_and_helpstring(self): 1722 fv = flags.FlagValues() 1723 flags.DEFINE_string( 1724 'unicode_str', 1725 b'\xC3\x80\xC3\xBD'.decode('utf-8'), 1726 b'help:\xC3\xAA'.decode('utf-8'), 1727 flag_values=fv) 1728 argv = ('./program',) 1729 fv(argv) # should not raise any exceptions 1730 1731 argv = ('./program', '--unicode_str=foo') 1732 fv(argv) # should not raise any exceptions 1733 1734 def test_unicode_in_list(self): 1735 fv = flags.FlagValues() 1736 flags.DEFINE_list( 1737 'unicode_list', 1738 ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')], 1739 b'help:\xC3\xAB'.decode('utf-8'), 1740 flag_values=fv) 1741 argv = ('./program',) 1742 fv(argv) # should not raise any exceptions 1743 1744 argv = ('./program', '--unicode_list=hello,there') 1745 fv(argv) # should not raise any exceptions 1746 1747 def test_xmloutput(self): 1748 fv = flags.FlagValues() 1749 flags.DEFINE_string( 1750 'unicode1', 1751 b'\xC3\x80\xC3\xBD'.decode('utf-8'), 1752 b'help:\xC3\xAC'.decode('utf-8'), 1753 flag_values=fv) 1754 flags.DEFINE_list( 1755 'unicode2', 1756 ['abc', b'\xC3\x80'.decode('utf-8'), b'\xC3\xBD'.decode('utf-8')], 1757 b'help:\xC3\xAD'.decode('utf-8'), 1758 flag_values=fv) 1759 flags.DEFINE_list( 1760 'non_unicode', ['abc', 'def', 'ghi'], 1761 b'help:\xC3\xAD'.decode('utf-8'), 1762 flag_values=fv) 1763 1764 outfile = io.StringIO() 1765 fv.write_help_in_xml_format(outfile) 1766 actual_output = outfile.getvalue() 1767 1768 # The xml output is large, so we just check parts of it. 1769 self.assertIn( 1770 b'<name>unicode1</name>\n' 1771 b' <meaning>help:\xc3\xac</meaning>\n' 1772 b' <default>\xc3\x80\xc3\xbd</default>\n' 1773 b' <current>\xc3\x80\xc3\xbd</current>'.decode('utf-8'), 1774 actual_output) 1775 self.assertIn( 1776 b'<name>unicode2</name>\n' 1777 b' <meaning>help:\xc3\xad</meaning>\n' 1778 b' <default>abc,\xc3\x80,\xc3\xbd</default>\n' 1779 b" <current>['abc', '\xc3\x80', '\xc3\xbd']" 1780 b'</current>'.decode('utf-8'), actual_output) 1781 self.assertIn( 1782 b'<name>non_unicode</name>\n' 1783 b' <meaning>help:\xc3\xad</meaning>\n' 1784 b' <default>abc,def,ghi</default>\n' 1785 b" <current>['abc', 'def', 'ghi']" 1786 b'</current>'.decode('utf-8'), actual_output) 1787 1788 1789class LoadFromFlagFileTest(absltest.TestCase): 1790 """Testing loading flags from a file and parsing them.""" 1791 1792 def setUp(self): 1793 self.flag_values = flags.FlagValues() 1794 flags.DEFINE_string( 1795 'unittest_message1', 1796 'Foo!', 1797 'You Add Here.', 1798 flag_values=self.flag_values) 1799 flags.DEFINE_string( 1800 'unittest_message2', 1801 'Bar!', 1802 'Hello, Sailor!', 1803 flag_values=self.flag_values) 1804 flags.DEFINE_boolean( 1805 'unittest_boolflag', 1806 0, 1807 'Some Boolean thing', 1808 flag_values=self.flag_values) 1809 flags.DEFINE_integer( 1810 'unittest_number', 1811 12345, 1812 'Some integer', 1813 lower_bound=0, 1814 flag_values=self.flag_values) 1815 flags.DEFINE_list( 1816 'UnitTestList', '1,2,3', 'Some list', flag_values=self.flag_values) 1817 self.tmp_path = None 1818 self.flag_values.mark_as_parsed() 1819 1820 def tearDown(self): 1821 self._remove_test_files() 1822 1823 def _setup_test_files(self): 1824 """Creates and sets up some dummy flagfile files with bogus flags.""" 1825 1826 # Figure out where to create temporary files 1827 self.assertFalse(self.tmp_path) 1828 self.tmp_path = tempfile.mkdtemp() 1829 1830 tmp_flag_file_1 = open(self.tmp_path + '/UnitTestFile1.tst', 'w') 1831 tmp_flag_file_2 = open(self.tmp_path + '/UnitTestFile2.tst', 'w') 1832 tmp_flag_file_3 = open(self.tmp_path + '/UnitTestFile3.tst', 'w') 1833 tmp_flag_file_4 = open(self.tmp_path + '/UnitTestFile4.tst', 'w') 1834 1835 # put some dummy flags in our test files 1836 tmp_flag_file_1.write('#A Fake Comment\n') 1837 tmp_flag_file_1.write('--unittest_message1=tempFile1!\n') 1838 tmp_flag_file_1.write('\n') 1839 tmp_flag_file_1.write('--unittest_number=54321\n') 1840 tmp_flag_file_1.write('--nounittest_boolflag\n') 1841 file_list = [tmp_flag_file_1.name] 1842 # this one includes test file 1 1843 tmp_flag_file_2.write('//A Different Fake Comment\n') 1844 tmp_flag_file_2.write('--flagfile=%s\n' % tmp_flag_file_1.name) 1845 tmp_flag_file_2.write('--unittest_message2=setFromTempFile2\n') 1846 tmp_flag_file_2.write('\t\t\n') 1847 tmp_flag_file_2.write('--unittest_number=6789a\n') 1848 file_list.append(tmp_flag_file_2.name) 1849 # this file points to itself 1850 tmp_flag_file_3.write('--flagfile=%s\n' % tmp_flag_file_3.name) 1851 tmp_flag_file_3.write('--unittest_message1=setFromTempFile3\n') 1852 tmp_flag_file_3.write('#YAFC\n') 1853 tmp_flag_file_3.write('--unittest_boolflag\n') 1854 file_list.append(tmp_flag_file_3.name) 1855 # this file is unreadable 1856 tmp_flag_file_4.write('--flagfile=%s\n' % tmp_flag_file_3.name) 1857 tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n') 1858 tmp_flag_file_4.write('--unittest_message1=setFromTempFile4\n') 1859 os.chmod(self.tmp_path + '/UnitTestFile4.tst', 0) 1860 file_list.append(tmp_flag_file_4.name) 1861 1862 tmp_flag_file_1.close() 1863 tmp_flag_file_2.close() 1864 tmp_flag_file_3.close() 1865 tmp_flag_file_4.close() 1866 1867 return file_list # these are just the file names 1868 1869 def _remove_test_files(self): 1870 """Removes the files we just created.""" 1871 if self.tmp_path: 1872 shutil.rmtree(self.tmp_path, ignore_errors=True) 1873 self.tmp_path = None 1874 1875 def _read_flags_from_files(self, argv, force_gnu): 1876 return argv[:1] + self.flag_values.read_flags_from_files( 1877 argv[1:], force_gnu=force_gnu) 1878 1879 #### Flagfile Unit Tests #### 1880 def test_method_flagfiles_1(self): 1881 """Test trivial case with no flagfile based options.""" 1882 fake_cmd_line = 'fooScript --unittest_boolflag' 1883 fake_argv = fake_cmd_line.split(' ') 1884 self.flag_values(fake_argv) 1885 self.assertEqual(self.flag_values.unittest_boolflag, 1) 1886 self.assertListEqual(fake_argv, 1887 self._read_flags_from_files(fake_argv, False)) 1888 1889 def test_method_flagfiles_2(self): 1890 """Tests parsing one file + arguments off simulated argv.""" 1891 tmp_files = self._setup_test_files() 1892 # specify our temp file on the fake cmd line 1893 fake_cmd_line = 'fooScript --q --flagfile=%s' % tmp_files[0] 1894 fake_argv = fake_cmd_line.split(' ') 1895 1896 # We should see the original cmd line with the file's contents spliced in. 1897 # Flags from the file will appear in the order order they are specified 1898 # in the file, in the same position as the flagfile argument. 1899 expected_results = [ 1900 'fooScript', '--q', '--unittest_message1=tempFile1!', 1901 '--unittest_number=54321', '--nounittest_boolflag' 1902 ] 1903 test_results = self._read_flags_from_files(fake_argv, False) 1904 self.assertListEqual(expected_results, test_results) 1905 1906 # end testTwo def 1907 1908 def test_method_flagfiles_3(self): 1909 """Tests parsing nested files + arguments of simulated argv.""" 1910 tmp_files = self._setup_test_files() 1911 # specify our temp file on the fake cmd line 1912 fake_cmd_line = ('fooScript --unittest_number=77 --flagfile=%s' % 1913 tmp_files[1]) 1914 fake_argv = fake_cmd_line.split(' ') 1915 1916 expected_results = [ 1917 'fooScript', '--unittest_number=77', '--unittest_message1=tempFile1!', 1918 '--unittest_number=54321', '--nounittest_boolflag', 1919 '--unittest_message2=setFromTempFile2', '--unittest_number=6789a' 1920 ] 1921 test_results = self._read_flags_from_files(fake_argv, False) 1922 self.assertListEqual(expected_results, test_results) 1923 1924 # end testThree def 1925 1926 def test_method_flagfiles_3_spaces(self): 1927 """Tests parsing nested files + arguments of simulated argv. 1928 1929 The arguments include a pair that is actually an arg with a value, so it 1930 doesn't stop processing. 1931 """ 1932 tmp_files = self._setup_test_files() 1933 # specify our temp file on the fake cmd line 1934 fake_cmd_line = ('fooScript --unittest_number 77 --flagfile=%s' % 1935 tmp_files[1]) 1936 fake_argv = fake_cmd_line.split(' ') 1937 1938 expected_results = [ 1939 'fooScript', '--unittest_number', '77', 1940 '--unittest_message1=tempFile1!', '--unittest_number=54321', 1941 '--nounittest_boolflag', '--unittest_message2=setFromTempFile2', 1942 '--unittest_number=6789a' 1943 ] 1944 test_results = self._read_flags_from_files(fake_argv, False) 1945 self.assertListEqual(expected_results, test_results) 1946 1947 def test_method_flagfiles_3_spaces_boolean(self): 1948 """Tests parsing nested files + arguments of simulated argv. 1949 1950 The arguments include a pair that looks like a --x y arg with value, but 1951 since the flag is a boolean it's actually not. 1952 """ 1953 tmp_files = self._setup_test_files() 1954 # specify our temp file on the fake cmd line 1955 fake_cmd_line = ('fooScript --unittest_boolflag 77 --flagfile=%s' % 1956 tmp_files[1]) 1957 fake_argv = fake_cmd_line.split(' ') 1958 1959 expected_results = [ 1960 'fooScript', '--unittest_boolflag', '77', 1961 '--flagfile=%s' % tmp_files[1] 1962 ] 1963 with _use_gnu_getopt(self.flag_values, False): 1964 test_results = self._read_flags_from_files(fake_argv, False) 1965 self.assertListEqual(expected_results, test_results) 1966 1967 def test_method_flagfiles_4(self): 1968 """Tests parsing self-referential files + arguments of simulated argv. 1969 1970 This test should print a warning to stderr of some sort. 1971 """ 1972 tmp_files = self._setup_test_files() 1973 # specify our temp file on the fake cmd line 1974 fake_cmd_line = ('fooScript --flagfile=%s --nounittest_boolflag' % 1975 tmp_files[2]) 1976 fake_argv = fake_cmd_line.split(' ') 1977 expected_results = [ 1978 'fooScript', '--unittest_message1=setFromTempFile3', 1979 '--unittest_boolflag', '--nounittest_boolflag' 1980 ] 1981 1982 test_results = self._read_flags_from_files(fake_argv, False) 1983 self.assertListEqual(expected_results, test_results) 1984 1985 def test_method_flagfiles_5(self): 1986 """Test that --flagfile parsing respects the '--' end-of-options marker.""" 1987 tmp_files = self._setup_test_files() 1988 # specify our temp file on the fake cmd line 1989 fake_cmd_line = 'fooScript --some_flag -- --flagfile=%s' % tmp_files[0] 1990 fake_argv = fake_cmd_line.split(' ') 1991 expected_results = [ 1992 'fooScript', '--some_flag', '--', 1993 '--flagfile=%s' % tmp_files[0] 1994 ] 1995 1996 test_results = self._read_flags_from_files(fake_argv, False) 1997 self.assertListEqual(expected_results, test_results) 1998 1999 def test_method_flagfiles_6(self): 2000 """Test that --flagfile parsing stops at non-options (non-GNU behavior).""" 2001 tmp_files = self._setup_test_files() 2002 # specify our temp file on the fake cmd line 2003 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2004 tmp_files[0]) 2005 fake_argv = fake_cmd_line.split(' ') 2006 expected_results = [ 2007 'fooScript', '--some_flag', 'some_arg', 2008 '--flagfile=%s' % tmp_files[0] 2009 ] 2010 2011 with _use_gnu_getopt(self.flag_values, False): 2012 test_results = self._read_flags_from_files(fake_argv, False) 2013 self.assertListEqual(expected_results, test_results) 2014 2015 def test_method_flagfiles_7(self): 2016 """Test that --flagfile parsing skips over a non-option (GNU behavior).""" 2017 self.flag_values.set_gnu_getopt() 2018 tmp_files = self._setup_test_files() 2019 # specify our temp file on the fake cmd line 2020 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2021 tmp_files[0]) 2022 fake_argv = fake_cmd_line.split(' ') 2023 expected_results = [ 2024 'fooScript', '--some_flag', 'some_arg', 2025 '--unittest_message1=tempFile1!', '--unittest_number=54321', 2026 '--nounittest_boolflag' 2027 ] 2028 2029 test_results = self._read_flags_from_files(fake_argv, False) 2030 self.assertListEqual(expected_results, test_results) 2031 2032 def test_method_flagfiles_8(self): 2033 """Test that --flagfile parsing respects force_gnu=True.""" 2034 tmp_files = self._setup_test_files() 2035 # specify our temp file on the fake cmd line 2036 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2037 tmp_files[0]) 2038 fake_argv = fake_cmd_line.split(' ') 2039 expected_results = [ 2040 'fooScript', '--some_flag', 'some_arg', 2041 '--unittest_message1=tempFile1!', '--unittest_number=54321', 2042 '--nounittest_boolflag' 2043 ] 2044 2045 test_results = self._read_flags_from_files(fake_argv, True) 2046 self.assertListEqual(expected_results, test_results) 2047 2048 def test_method_flagfiles_repeated_non_circular(self): 2049 """Tests that parsing repeated non-circular flagfiles works.""" 2050 tmp_files = self._setup_test_files() 2051 # specify our temp files on the fake cmd line 2052 fake_cmd_line = ('fooScript --flagfile=%s --flagfile=%s' % 2053 (tmp_files[1], tmp_files[0])) 2054 fake_argv = fake_cmd_line.split(' ') 2055 expected_results = [ 2056 'fooScript', '--unittest_message1=tempFile1!', 2057 '--unittest_number=54321', '--nounittest_boolflag', 2058 '--unittest_message2=setFromTempFile2', '--unittest_number=6789a', 2059 '--unittest_message1=tempFile1!', '--unittest_number=54321', 2060 '--nounittest_boolflag' 2061 ] 2062 2063 test_results = self._read_flags_from_files(fake_argv, False) 2064 self.assertListEqual(expected_results, test_results) 2065 2066 @unittest.skipIf( 2067 os.name == 'nt', 2068 'There is no good way to create an unreadable file on Windows.') 2069 def test_method_flagfiles_no_permissions(self): 2070 """Test that --flagfile raises except on file that is unreadable.""" 2071 tmp_files = self._setup_test_files() 2072 # specify our temp file on the fake cmd line 2073 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%s' % 2074 tmp_files[3]) 2075 fake_argv = fake_cmd_line.split(' ') 2076 self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files, 2077 fake_argv, True) 2078 2079 def test_method_flagfiles_not_found(self): 2080 """Test that --flagfile raises except on file that does not exist.""" 2081 tmp_files = self._setup_test_files() 2082 # specify our temp file on the fake cmd line 2083 fake_cmd_line = ('fooScript --some_flag some_arg --flagfile=%sNOTEXIST' % 2084 tmp_files[3]) 2085 fake_argv = fake_cmd_line.split(' ') 2086 self.assertRaises(flags.CantOpenFlagFileError, self._read_flags_from_files, 2087 fake_argv, True) 2088 2089 def test_flagfiles_user_path_expansion(self): 2090 """Test that user directory referenced paths are correctly expanded. 2091 2092 Test paths like ~/foo. This test depends on whatever account's running 2093 the unit test to have read/write access to their own home directory, 2094 otherwise it'll FAIL. 2095 """ 2096 fake_flagfile_item_style_1 = '--flagfile=~/foo.file' 2097 fake_flagfile_item_style_2 = '-flagfile=~/foo.file' 2098 2099 expected_results = os.path.expanduser('~/foo.file') 2100 2101 test_results = self.flag_values._extract_filename( 2102 fake_flagfile_item_style_1) 2103 self.assertEqual(expected_results, test_results) 2104 2105 test_results = self.flag_values._extract_filename( 2106 fake_flagfile_item_style_2) 2107 self.assertEqual(expected_results, test_results) 2108 2109 def test_no_touchy_non_flags(self): 2110 """Test that the flags parser does not mutilate arguments. 2111 2112 The arguments are not supposed to be flags 2113 """ 2114 fake_argv = [ 2115 'fooScript', '--unittest_boolflag', 'command', '--command_arg1', 2116 '--UnitTestBoom', '--UnitTestB' 2117 ] 2118 with _use_gnu_getopt(self.flag_values, False): 2119 argv = self.flag_values(fake_argv) 2120 self.assertListEqual(argv, fake_argv[:1] + fake_argv[2:]) 2121 2122 def test_parse_flags_after_args_if_using_gnugetopt(self): 2123 """Test that flags given after arguments are parsed if using gnu_getopt.""" 2124 self.flag_values.set_gnu_getopt() 2125 fake_argv = [ 2126 'fooScript', '--unittest_boolflag', 'command', '--unittest_number=54321' 2127 ] 2128 argv = self.flag_values(fake_argv) 2129 self.assertListEqual(argv, ['fooScript', 'command']) 2130 2131 def test_set_default(self): 2132 """Test changing flag defaults.""" 2133 # Test that set_default changes both the default and the value, 2134 # and that the value is changed when one is given as an option. 2135 self.flag_values.set_default('unittest_message1', 'New value') 2136 self.assertEqual(self.flag_values.unittest_message1, 'New value') 2137 self.assertEqual(self.flag_values['unittest_message1'].default_as_str, 2138 "'New value'") 2139 self.flag_values(['dummyscript', '--unittest_message1=Newer value']) 2140 self.assertEqual(self.flag_values.unittest_message1, 'Newer value') 2141 2142 # Test that setting the default to None works correctly. 2143 self.flag_values.set_default('unittest_number', None) 2144 self.assertEqual(self.flag_values.unittest_number, None) 2145 self.assertEqual(self.flag_values['unittest_number'].default_as_str, None) 2146 self.flag_values(['dummyscript', '--unittest_number=56']) 2147 self.assertEqual(self.flag_values.unittest_number, 56) 2148 2149 # Test that setting the default to zero works correctly. 2150 self.flag_values.set_default('unittest_number', 0) 2151 self.assertEqual(self.flag_values['unittest_number'].default, 0) 2152 self.assertEqual(self.flag_values.unittest_number, 56) 2153 self.assertEqual(self.flag_values['unittest_number'].default_as_str, "'0'") 2154 self.flag_values(['dummyscript', '--unittest_number=56']) 2155 self.assertEqual(self.flag_values.unittest_number, 56) 2156 2157 # Test that setting the default to '' works correctly. 2158 self.flag_values.set_default('unittest_message1', '') 2159 self.assertEqual(self.flag_values['unittest_message1'].default, '') 2160 self.assertEqual(self.flag_values.unittest_message1, 'Newer value') 2161 self.assertEqual(self.flag_values['unittest_message1'].default_as_str, "''") 2162 self.flag_values(['dummyscript', '--unittest_message1=fifty-six']) 2163 self.assertEqual(self.flag_values.unittest_message1, 'fifty-six') 2164 2165 # Test that setting the default to false works correctly. 2166 self.flag_values.set_default('unittest_boolflag', False) 2167 self.assertEqual(self.flag_values.unittest_boolflag, False) 2168 self.assertEqual(self.flag_values['unittest_boolflag'].default_as_str, 2169 "'false'") 2170 self.flag_values(['dummyscript', '--unittest_boolflag=true']) 2171 self.assertEqual(self.flag_values.unittest_boolflag, True) 2172 2173 # Test that setting a list default works correctly. 2174 self.flag_values.set_default('UnitTestList', '4,5,6') 2175 self.assertListEqual(self.flag_values.UnitTestList, ['4', '5', '6']) 2176 self.assertEqual(self.flag_values['UnitTestList'].default_as_str, "'4,5,6'") 2177 self.flag_values(['dummyscript', '--UnitTestList=7,8,9']) 2178 self.assertListEqual(self.flag_values.UnitTestList, ['7', '8', '9']) 2179 2180 # Test that setting invalid defaults raises exceptions 2181 with self.assertRaises(flags.IllegalFlagValueError): 2182 self.flag_values.set_default('unittest_number', 'oops') 2183 with self.assertRaises(flags.IllegalFlagValueError): 2184 self.flag_values.set_default('unittest_number', -1) 2185 2186 2187class FlagsParsingTest(absltest.TestCase): 2188 """Testing different aspects of parsing: '-f' vs '--flag', etc.""" 2189 2190 def setUp(self): 2191 self.flag_values = flags.FlagValues() 2192 2193 def test_two_dash_arg_first(self): 2194 flags.DEFINE_string( 2195 'twodash_name', 'Bob', 'namehelp', flag_values=self.flag_values) 2196 flags.DEFINE_string( 2197 'twodash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values) 2198 argv = ('./program', '--', '--twodash_name=Harry') 2199 argv = self.flag_values(argv) 2200 self.assertEqual('Bob', self.flag_values.twodash_name) 2201 self.assertEqual(argv[1], '--twodash_name=Harry') 2202 2203 def test_two_dash_arg_middle(self): 2204 flags.DEFINE_string( 2205 'twodash2_name', 'Bob', 'namehelp', flag_values=self.flag_values) 2206 flags.DEFINE_string( 2207 'twodash2_blame', 'Rob', 'blamehelp', flag_values=self.flag_values) 2208 argv = ('./program', '--twodash2_blame=Larry', '--', 2209 '--twodash2_name=Harry') 2210 argv = self.flag_values(argv) 2211 self.assertEqual('Bob', self.flag_values.twodash2_name) 2212 self.assertEqual('Larry', self.flag_values.twodash2_blame) 2213 self.assertEqual(argv[1], '--twodash2_name=Harry') 2214 2215 def test_one_dash_arg_first(self): 2216 flags.DEFINE_string( 2217 'onedash_name', 'Bob', 'namehelp', flag_values=self.flag_values) 2218 flags.DEFINE_string( 2219 'onedash_blame', 'Rob', 'blamehelp', flag_values=self.flag_values) 2220 argv = ('./program', '-', '--onedash_name=Harry') 2221 with _use_gnu_getopt(self.flag_values, False): 2222 argv = self.flag_values(argv) 2223 self.assertEqual(len(argv), 3) 2224 self.assertEqual(argv[1], '-') 2225 self.assertEqual(argv[2], '--onedash_name=Harry') 2226 2227 def test_required_flag_not_specified(self): 2228 flags.DEFINE_string( 2229 'str_flag', 2230 default=None, 2231 help='help', 2232 required=True, 2233 flag_values=self.flag_values) 2234 argv = ('./program',) 2235 with _use_gnu_getopt(self.flag_values, False): 2236 with self.assertRaises(flags.IllegalFlagValueError): 2237 self.flag_values(argv) 2238 2239 def test_required_arg_works_with_other_validators(self): 2240 flags.DEFINE_integer( 2241 'int_flag', 2242 default=None, 2243 help='help', 2244 required=True, 2245 lower_bound=4, 2246 flag_values=self.flag_values) 2247 argv = ('./program', '--int_flag=2') 2248 with _use_gnu_getopt(self.flag_values, False): 2249 with self.assertRaises(flags.IllegalFlagValueError): 2250 self.flag_values(argv) 2251 2252 def test_unrecognized_flags(self): 2253 flags.DEFINE_string('name', 'Bob', 'namehelp', flag_values=self.flag_values) 2254 # Unknown flag --nosuchflag 2255 try: 2256 argv = ('./program', '--nosuchflag', '--name=Bob', 'extra') 2257 self.flag_values(argv) 2258 raise AssertionError('Unknown flag exception not raised') 2259 except flags.UnrecognizedFlagError as e: 2260 self.assertEqual(e.flagname, 'nosuchflag') 2261 self.assertEqual(e.flagvalue, '--nosuchflag') 2262 2263 # Unknown flag -w (short option) 2264 try: 2265 argv = ('./program', '-w', '--name=Bob', 'extra') 2266 self.flag_values(argv) 2267 raise AssertionError('Unknown flag exception not raised') 2268 except flags.UnrecognizedFlagError as e: 2269 self.assertEqual(e.flagname, 'w') 2270 self.assertEqual(e.flagvalue, '-w') 2271 2272 # Unknown flag --nosuchflagwithparam=foo 2273 try: 2274 argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 'extra') 2275 self.flag_values(argv) 2276 raise AssertionError('Unknown flag exception not raised') 2277 except flags.UnrecognizedFlagError as e: 2278 self.assertEqual(e.flagname, 'nosuchflagwithparam') 2279 self.assertEqual(e.flagvalue, '--nosuchflagwithparam=foo') 2280 2281 # Allow unknown flag --nosuchflag if specified with undefok 2282 argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchflag', 2283 'extra') 2284 argv = self.flag_values(argv) 2285 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2286 self.assertEqual(argv[0], './program', 'program name not preserved') 2287 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2288 2289 # Allow unknown flag --noboolflag if undefok=boolflag is specified 2290 argv = ('./program', '--noboolflag', '--name=Bob', '--undefok=boolflag', 2291 'extra') 2292 argv = self.flag_values(argv) 2293 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2294 self.assertEqual(argv[0], './program', 'program name not preserved') 2295 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2296 2297 # But not if the flagname is misspelled: 2298 try: 2299 argv = ('./program', '--nosuchflag', '--name=Bob', '--undefok=nosuchfla', 2300 'extra') 2301 self.flag_values(argv) 2302 raise AssertionError('Unknown flag exception not raised') 2303 except flags.UnrecognizedFlagError as e: 2304 self.assertEqual(e.flagname, 'nosuchflag') 2305 2306 try: 2307 argv = ('./program', '--nosuchflag', '--name=Bob', 2308 '--undefok=nosuchflagg', 'extra') 2309 self.flag_values(argv) 2310 raise AssertionError('Unknown flag exception not raised') 2311 except flags.UnrecognizedFlagError as e: 2312 self.assertEqual(e.flagname, 'nosuchflag') 2313 2314 # Allow unknown short flag -w if specified with undefok 2315 argv = ('./program', '-w', '--name=Bob', '--undefok=w', 'extra') 2316 argv = self.flag_values(argv) 2317 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2318 self.assertEqual(argv[0], './program', 'program name not preserved') 2319 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2320 2321 # Allow unknown flag --nosuchflagwithparam=foo if specified 2322 # with undefok 2323 argv = ('./program', '--nosuchflagwithparam=foo', '--name=Bob', 2324 '--undefok=nosuchflagwithparam', 'extra') 2325 argv = self.flag_values(argv) 2326 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2327 self.assertEqual(argv[0], './program', 'program name not preserved') 2328 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2329 2330 # Even if undefok specifies multiple flags 2331 argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo', 2332 '--name=Bob', '--undefok=nosuchflag,w,nosuchflagwithparam', 'extra') 2333 argv = self.flag_values(argv) 2334 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2335 self.assertEqual(argv[0], './program', 'program name not preserved') 2336 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2337 2338 # However, not if undefok doesn't specify the flag 2339 try: 2340 argv = ('./program', '--nosuchflag', '--name=Bob', 2341 '--undefok=another_such', 'extra') 2342 self.flag_values(argv) 2343 raise AssertionError('Unknown flag exception not raised') 2344 except flags.UnrecognizedFlagError as e: 2345 self.assertEqual(e.flagname, 'nosuchflag') 2346 2347 # Make sure --undefok doesn't mask other option errors. 2348 try: 2349 # Provide an option requiring a parameter but not giving it one. 2350 argv = ('./program', '--undefok=name', '--name') 2351 self.flag_values(argv) 2352 raise AssertionError('Missing option parameter exception not raised') 2353 except flags.UnrecognizedFlagError: 2354 raise AssertionError('Wrong kind of error exception raised') 2355 except flags.Error: 2356 pass 2357 2358 # Test --undefok <list> 2359 argv = ('./program', '--nosuchflag', '-w', '--nosuchflagwithparam=foo', 2360 '--name=Bob', '--undefok', 'nosuchflag,w,nosuchflagwithparam', 2361 'extra') 2362 argv = self.flag_values(argv) 2363 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2364 self.assertEqual(argv[0], './program', 'program name not preserved') 2365 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2366 2367 # Test incorrect --undefok with no value. 2368 argv = ('./program', '--name=Bob', '--undefok') 2369 with self.assertRaises(flags.Error): 2370 self.flag_values(argv) 2371 2372 2373class NonGlobalFlagsTest(absltest.TestCase): 2374 2375 def test_nonglobal_flags(self): 2376 """Test use of non-global FlagValues.""" 2377 nonglobal_flags = flags.FlagValues() 2378 flags.DEFINE_string('nonglobal_flag', 'Bob', 'flaghelp', nonglobal_flags) 2379 argv = ('./program', '--nonglobal_flag=Mary', 'extra') 2380 argv = nonglobal_flags(argv) 2381 self.assertEqual(len(argv), 2, 'wrong number of arguments pulled') 2382 self.assertEqual(argv[0], './program', 'program name not preserved') 2383 self.assertEqual(argv[1], 'extra', 'extra argument not preserved') 2384 self.assertEqual(nonglobal_flags['nonglobal_flag'].value, 'Mary') 2385 2386 def test_unrecognized_nonglobal_flags(self): 2387 """Test unrecognized non-global flags.""" 2388 nonglobal_flags = flags.FlagValues() 2389 argv = ('./program', '--nosuchflag') 2390 try: 2391 argv = nonglobal_flags(argv) 2392 raise AssertionError('Unknown flag exception not raised') 2393 except flags.UnrecognizedFlagError as e: 2394 self.assertEqual(e.flagname, 'nosuchflag') 2395 2396 argv = ('./program', '--nosuchflag', '--undefok=nosuchflag') 2397 2398 argv = nonglobal_flags(argv) 2399 self.assertEqual(len(argv), 1, 'wrong number of arguments pulled') 2400 self.assertEqual(argv[0], './program', 'program name not preserved') 2401 2402 def test_create_flag_errors(self): 2403 # Since the exception classes are exposed, nothing stops users 2404 # from creating their own instances. This test makes sure that 2405 # people modifying the flags module understand that the external 2406 # mechanisms for creating the exceptions should continue to work. 2407 _ = flags.Error() 2408 _ = flags.Error('message') 2409 _ = flags.DuplicateFlagError() 2410 _ = flags.DuplicateFlagError('message') 2411 _ = flags.IllegalFlagValueError() 2412 _ = flags.IllegalFlagValueError('message') 2413 2414 def test_flag_values_del_attr(self): 2415 """Checks that del self.flag_values.flag_id works.""" 2416 default_value = 'default value for test_flag_values_del_attr' 2417 # 1. Declare and delete a flag with no short name. 2418 flag_values = flags.FlagValues() 2419 flags.DEFINE_string( 2420 'delattr_foo', default_value, 'A simple flag.', flag_values=flag_values) 2421 2422 flag_values.mark_as_parsed() 2423 self.assertEqual(flag_values.delattr_foo, default_value) 2424 flag_obj = flag_values['delattr_foo'] 2425 # We also check that _FlagIsRegistered works as expected :) 2426 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2427 del flag_values.delattr_foo 2428 self.assertFalse('delattr_foo' in flag_values._flags()) 2429 self.assertFalse(flag_values._flag_is_registered(flag_obj)) 2430 # If the previous del FLAGS.delattr_foo did not work properly, the 2431 # next definition will trigger a redefinition error. 2432 flags.DEFINE_integer( 2433 'delattr_foo', 3, 'A simple flag.', flag_values=flag_values) 2434 del flag_values.delattr_foo 2435 2436 self.assertFalse('delattr_foo' in flag_values) 2437 2438 # 2. Declare and delete a flag with a short name. 2439 flags.DEFINE_string( 2440 'delattr_bar', 2441 default_value, 2442 'flag with short name', 2443 short_name='x5', 2444 flag_values=flag_values) 2445 flag_obj = flag_values['delattr_bar'] 2446 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2447 del flag_values.x5 2448 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2449 del flag_values.delattr_bar 2450 self.assertFalse(flag_values._flag_is_registered(flag_obj)) 2451 2452 # 3. Just like 2, but del flag_values.name last 2453 flags.DEFINE_string( 2454 'delattr_bar', 2455 default_value, 2456 'flag with short name', 2457 short_name='x5', 2458 flag_values=flag_values) 2459 flag_obj = flag_values['delattr_bar'] 2460 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2461 del flag_values.delattr_bar 2462 self.assertTrue(flag_values._flag_is_registered(flag_obj)) 2463 del flag_values.x5 2464 self.assertFalse(flag_values._flag_is_registered(flag_obj)) 2465 2466 self.assertFalse('delattr_bar' in flag_values) 2467 self.assertFalse('x5' in flag_values) 2468 2469 def test_list_flag_format(self): 2470 """Tests for correctly-formatted list flags.""" 2471 fv = flags.FlagValues() 2472 flags.DEFINE_list('listflag', '', 'A list of arguments', flag_values=fv) 2473 2474 def _check_parsing(listval): 2475 """Parse a particular value for our test flag, --listflag.""" 2476 argv = fv(['./program', '--listflag=' + listval, 'plain-arg']) 2477 self.assertEqual(['./program', 'plain-arg'], argv) 2478 return fv.listflag 2479 2480 # Basic success case 2481 self.assertEqual(_check_parsing('foo,bar'), ['foo', 'bar']) 2482 # Success case: newline in argument is quoted. 2483 self.assertEqual(_check_parsing('"foo","bar\nbar"'), ['foo', 'bar\nbar']) 2484 # Failure case: newline in argument is unquoted. 2485 self.assertRaises(flags.IllegalFlagValueError, _check_parsing, 2486 '"foo",bar\nbar') 2487 # Failure case: unmatched ". 2488 self.assertRaises(flags.IllegalFlagValueError, _check_parsing, 2489 '"foo,barbar') 2490 2491 def test_flag_definition_via_setitem(self): 2492 with self.assertRaises(flags.IllegalFlagValueError): 2493 flag_values = flags.FlagValues() 2494 flag_values['flag_name'] = 'flag_value' 2495 2496 2497class SetDefaultTest(absltest.TestCase): 2498 2499 def setUp(self): 2500 super().setUp() 2501 self.flag_values = flags.FlagValues() 2502 2503 def test_success(self): 2504 int_holder = flags.DEFINE_integer( 2505 'an_int', 1, 'an int', flag_values=self.flag_values) 2506 2507 flags.set_default(int_holder, 2) 2508 self.flag_values.mark_as_parsed() 2509 2510 self.assertEqual(int_holder.value, 2) 2511 2512 def test_update_after_parse(self): 2513 int_holder = flags.DEFINE_integer( 2514 'an_int', 1, 'an int', flag_values=self.flag_values) 2515 2516 self.flag_values.mark_as_parsed() 2517 flags.set_default(int_holder, 2) 2518 2519 self.assertEqual(int_holder.value, 2) 2520 2521 def test_overridden_by_explicit_assignment(self): 2522 int_holder = flags.DEFINE_integer( 2523 'an_int', 1, 'an int', flag_values=self.flag_values) 2524 2525 self.flag_values.mark_as_parsed() 2526 self.flag_values.an_int = 3 2527 flags.set_default(int_holder, 2) 2528 2529 self.assertEqual(int_holder.value, 3) 2530 2531 def test_restores_back_to_none(self): 2532 int_holder = flags.DEFINE_integer( 2533 'an_int', None, 'an int', flag_values=self.flag_values) 2534 2535 self.flag_values.mark_as_parsed() 2536 flags.set_default(int_holder, 3) 2537 flags.set_default(int_holder, None) 2538 2539 self.assertIsNone(int_holder.value) 2540 2541 def test_failure_on_invalid_type(self): 2542 int_holder = flags.DEFINE_integer( 2543 'an_int', 1, 'an int', flag_values=self.flag_values) 2544 2545 self.flag_values.mark_as_parsed() 2546 2547 with self.assertRaises(flags.IllegalFlagValueError): 2548 flags.set_default(int_holder, 'a') 2549 2550 def test_failure_on_type_protected_none_default(self): 2551 int_holder = flags.DEFINE_integer( 2552 'an_int', 1, 'an int', flag_values=self.flag_values) 2553 2554 self.flag_values.mark_as_parsed() 2555 2556 flags.set_default(int_holder, None) # NOTE: should be a type failure 2557 2558 with self.assertRaises(flags.IllegalFlagValueError): 2559 _ = int_holder.value # Will also fail on later access. 2560 2561 2562class KeyFlagsTest(absltest.TestCase): 2563 2564 def setUp(self): 2565 self.flag_values = flags.FlagValues() 2566 2567 def _get_names_of_defined_flags(self, module, flag_values): 2568 """Returns the list of names of flags defined by a module. 2569 2570 Auxiliary for the test_key_flags* methods. 2571 2572 Args: 2573 module: A module object or a string module name. 2574 flag_values: A FlagValues object. 2575 2576 Returns: 2577 A list of strings. 2578 """ 2579 return [f.name for f in flag_values.get_flags_for_module(module)] 2580 2581 def _get_names_of_key_flags(self, module, flag_values): 2582 """Returns the list of names of key flags for a module. 2583 2584 Auxiliary for the test_key_flags* methods. 2585 2586 Args: 2587 module: A module object or a string module name. 2588 flag_values: A FlagValues object. 2589 2590 Returns: 2591 A list of strings. 2592 """ 2593 return [f.name for f in flag_values.get_key_flags_for_module(module)] 2594 2595 def _assert_lists_have_same_elements(self, list_1, list_2): 2596 # Checks that two lists have the same elements with the same 2597 # multiplicity, in possibly different order. 2598 list_1 = list(list_1) 2599 list_1.sort() 2600 list_2 = list(list_2) 2601 list_2.sort() 2602 self.assertListEqual(list_1, list_2) 2603 2604 def test_key_flags(self): 2605 flag_values = flags.FlagValues() 2606 # Before starting any testing, make sure no flags are already 2607 # defined for module_foo and module_bar. 2608 self.assertListEqual( 2609 self._get_names_of_key_flags(module_foo, flag_values), []) 2610 self.assertListEqual( 2611 self._get_names_of_key_flags(module_bar, flag_values), []) 2612 self.assertListEqual( 2613 self._get_names_of_defined_flags(module_foo, flag_values), []) 2614 self.assertListEqual( 2615 self._get_names_of_defined_flags(module_bar, flag_values), []) 2616 2617 # Defines a few flags in module_foo and module_bar. 2618 module_foo.define_flags(flag_values=flag_values) 2619 2620 try: 2621 # Part 1. Check that all flags defined by module_foo are key for 2622 # that module, and similarly for module_bar. 2623 for module in [module_foo, module_bar]: 2624 self._assert_lists_have_same_elements( 2625 flag_values.get_flags_for_module(module), 2626 flag_values.get_key_flags_for_module(module)) 2627 # Also check that each module defined the expected flags. 2628 self._assert_lists_have_same_elements( 2629 self._get_names_of_defined_flags(module, flag_values), 2630 module.names_of_defined_flags()) 2631 2632 # Part 2. Check that flags.declare_key_flag works fine. 2633 # Declare that some flags from module_bar are key for 2634 # module_foo. 2635 module_foo.declare_key_flags(flag_values=flag_values) 2636 2637 # Check that module_foo has the expected list of defined flags. 2638 self._assert_lists_have_same_elements( 2639 self._get_names_of_defined_flags(module_foo, flag_values), 2640 module_foo.names_of_defined_flags()) 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 2647 # Part 3. Check that flags.adopt_module_key_flags works fine. 2648 # Trigger a call to flags.adopt_module_key_flags(module_bar) 2649 # inside module_foo. This should declare a few more key 2650 # flags in module_foo. 2651 module_foo.declare_extra_key_flags(flag_values=flag_values) 2652 2653 # Check that module_foo has the expected list of key flags. 2654 self._assert_lists_have_same_elements( 2655 self._get_names_of_key_flags(module_foo, flag_values), 2656 module_foo.names_of_declared_key_flags() + 2657 module_foo.names_of_declared_extra_key_flags()) 2658 finally: 2659 module_foo.remove_flags(flag_values=flag_values) 2660 2661 def test_key_flags_with_non_default_flag_values_object(self): 2662 # Check that key flags work even when we use a FlagValues object 2663 # that is not the default flags.self.flag_values object. Otherwise, this 2664 # test is similar to test_key_flags, but it uses only module_bar. 2665 # The other test module (module_foo) uses only the default values 2666 # for the flag_values keyword arguments. This way, test_key_flags 2667 # and this method test both the default FlagValues, the explicitly 2668 # specified one, and a mixed usage of the two. 2669 2670 # A brand-new FlagValues object, to use instead of flags.self.flag_values. 2671 fv = flags.FlagValues() 2672 2673 # Before starting any testing, make sure no flags are already 2674 # defined for module_foo and module_bar. 2675 self.assertListEqual(self._get_names_of_key_flags(module_bar, fv), []) 2676 self.assertListEqual(self._get_names_of_defined_flags(module_bar, fv), []) 2677 2678 module_bar.define_flags(flag_values=fv) 2679 2680 # Check that all flags defined by module_bar are key for that 2681 # module, and that module_bar defined the expected flags. 2682 self._assert_lists_have_same_elements( 2683 fv.get_flags_for_module(module_bar), 2684 fv.get_key_flags_for_module(module_bar)) 2685 self._assert_lists_have_same_elements( 2686 self._get_names_of_defined_flags(module_bar, fv), 2687 module_bar.names_of_defined_flags()) 2688 2689 # Pick two flags from module_bar, declare them as key for the 2690 # current (i.e., main) module (via flags.declare_key_flag), and 2691 # check that we get the expected effect. The important thing is 2692 # that we always use flags_values=fv (instead of the default 2693 # self.flag_values). 2694 main_module = sys.argv[0] 2695 names_of_flags_defined_by_bar = module_bar.names_of_defined_flags() 2696 flag_name_0 = names_of_flags_defined_by_bar[0] 2697 flag_name_2 = names_of_flags_defined_by_bar[2] 2698 2699 flags.declare_key_flag(flag_name_0, flag_values=fv) 2700 self._assert_lists_have_same_elements( 2701 self._get_names_of_key_flags(main_module, fv), [flag_name_0]) 2702 2703 flags.declare_key_flag(flag_name_2, flag_values=fv) 2704 self._assert_lists_have_same_elements( 2705 self._get_names_of_key_flags(main_module, fv), 2706 [flag_name_0, flag_name_2]) 2707 2708 # Try with a special (not user-defined) flag too: 2709 flags.declare_key_flag('undefok', flag_values=fv) 2710 self._assert_lists_have_same_elements( 2711 self._get_names_of_key_flags(main_module, fv), 2712 [flag_name_0, flag_name_2, 'undefok']) 2713 2714 flags.adopt_module_key_flags(module_bar, fv) 2715 self._assert_lists_have_same_elements( 2716 self._get_names_of_key_flags(main_module, fv), 2717 names_of_flags_defined_by_bar + ['undefok']) 2718 2719 # Adopt key flags from the flags module itself. 2720 flags.adopt_module_key_flags(flags, flag_values=fv) 2721 self._assert_lists_have_same_elements( 2722 self._get_names_of_key_flags(main_module, fv), 2723 names_of_flags_defined_by_bar + ['flagfile', 'undefok']) 2724 2725 def test_key_flags_with_flagholders(self): 2726 main_module = sys.argv[0] 2727 2728 self.assertListEqual( 2729 self._get_names_of_key_flags(main_module, self.flag_values), []) 2730 self.assertListEqual( 2731 self._get_names_of_defined_flags(main_module, self.flag_values), []) 2732 2733 int_holder = flags.DEFINE_integer( 2734 'main_module_int_fg', 2735 1, 2736 'Integer flag in the main module.', 2737 flag_values=self.flag_values) 2738 2739 flags.declare_key_flag(int_holder, self.flag_values) 2740 2741 self.assertCountEqual( 2742 self.flag_values.get_flags_for_module(main_module), 2743 self.flag_values.get_key_flags_for_module(main_module)) 2744 2745 bool_holder = flags.DEFINE_boolean( 2746 'main_module_bool_fg', 2747 False, 2748 'Boolean flag in the main module.', 2749 flag_values=self.flag_values) 2750 2751 flags.declare_key_flag(bool_holder) # omitted flag_values 2752 2753 self.assertCountEqual( 2754 self.flag_values.get_flags_for_module(main_module), 2755 self.flag_values.get_key_flags_for_module(main_module)) 2756 2757 self.assertLen(self.flag_values.get_flags_for_module(main_module), 2) 2758 2759 def test_main_module_help_with_key_flags(self): 2760 # Similar to test_main_module_help, but this time we make sure to 2761 # declare some key flags. 2762 2763 # Safety check that the main module does not declare any flags 2764 # at the beginning of this test. 2765 expected_help = '' 2766 self.assertMultiLineEqual(expected_help, 2767 self.flag_values.main_module_help()) 2768 2769 # Define one flag in this main module and some flags in modules 2770 # a and b. Also declare one flag from module a and one flag 2771 # from module b as key flags for the main module. 2772 flags.DEFINE_integer( 2773 'main_module_int_fg', 2774 1, 2775 'Integer flag in the main module.', 2776 flag_values=self.flag_values) 2777 2778 try: 2779 main_module_int_fg_help = ( 2780 ' --main_module_int_fg: Integer flag in the main module.\n' 2781 " (default: '1')\n" 2782 ' (an integer)') 2783 2784 expected_help += '\n%s:\n%s' % (sys.argv[0], main_module_int_fg_help) 2785 self.assertMultiLineEqual(expected_help, 2786 self.flag_values.main_module_help()) 2787 2788 # The following call should be a no-op: any flag declared by a 2789 # module is automatically key for that module. 2790 flags.declare_key_flag('main_module_int_fg', flag_values=self.flag_values) 2791 self.assertMultiLineEqual(expected_help, 2792 self.flag_values.main_module_help()) 2793 2794 # The definition of a few flags in an imported module should not 2795 # change the main module help. 2796 module_foo.define_flags(flag_values=self.flag_values) 2797 self.assertMultiLineEqual(expected_help, 2798 self.flag_values.main_module_help()) 2799 2800 flags.declare_key_flag('tmod_foo_bool', flag_values=self.flag_values) 2801 tmod_foo_bool_help = ( 2802 ' --[no]tmod_foo_bool: Boolean flag from module foo.\n' 2803 " (default: 'true')") 2804 expected_help += '\n' + tmod_foo_bool_help 2805 self.assertMultiLineEqual(expected_help, 2806 self.flag_values.main_module_help()) 2807 2808 flags.declare_key_flag('tmod_bar_z', flag_values=self.flag_values) 2809 tmod_bar_z_help = ( 2810 ' --[no]tmod_bar_z: Another boolean flag from module bar.\n' 2811 " (default: 'false')") 2812 # Unfortunately, there is some flag sorting inside 2813 # main_module_help, so we can't keep incrementally extending 2814 # the expected_help string ... 2815 expected_help = ('\n%s:\n%s\n%s\n%s' % 2816 (sys.argv[0], main_module_int_fg_help, tmod_bar_z_help, 2817 tmod_foo_bool_help)) 2818 self.assertMultiLineEqual(self.flag_values.main_module_help(), 2819 expected_help) 2820 2821 finally: 2822 # At the end, delete all the flag information we created. 2823 self.flag_values.__delattr__('main_module_int_fg') 2824 module_foo.remove_flags(flag_values=self.flag_values) 2825 2826 def test_adoptmodule_key_flags(self): 2827 # Check that adopt_module_key_flags raises an exception when 2828 # called with a module name (as opposed to a module object). 2829 self.assertRaises(flags.Error, flags.adopt_module_key_flags, 'pyglib.app') 2830 2831 def test_disclaimkey_flags(self): 2832 original_disclaim_module_ids = _helpers.disclaim_module_ids 2833 _helpers.disclaim_module_ids = set(_helpers.disclaim_module_ids) 2834 try: 2835 module_bar.disclaim_key_flags() 2836 module_foo.define_bar_flags(flag_values=self.flag_values) 2837 module_name = self.flag_values.find_module_defining_flag('tmod_bar_x') 2838 self.assertEqual(module_foo.__name__, module_name) 2839 finally: 2840 _helpers.disclaim_module_ids = original_disclaim_module_ids 2841 2842 2843class FindModuleTest(absltest.TestCase): 2844 """Testing methods that find a module that defines a given flag.""" 2845 2846 def test_find_module_defining_flag(self): 2847 self.assertEqual( 2848 'default', 2849 FLAGS.find_module_defining_flag('__NON_EXISTENT_FLAG__', 'default')) 2850 self.assertEqual(module_baz.__name__, 2851 FLAGS.find_module_defining_flag('tmod_baz_x')) 2852 2853 def test_find_module_id_defining_flag(self): 2854 self.assertEqual( 2855 'default', 2856 FLAGS.find_module_id_defining_flag('__NON_EXISTENT_FLAG__', 'default')) 2857 self.assertEqual( 2858 id(module_baz), FLAGS.find_module_id_defining_flag('tmod_baz_x')) 2859 2860 def test_find_module_defining_flag_passing_module_name(self): 2861 my_flags = flags.FlagValues() 2862 module_name = sys.__name__ # Must use an existing module. 2863 flags.DEFINE_boolean( 2864 'flag_name', 2865 True, 2866 'Flag with a different module name.', 2867 flag_values=my_flags, 2868 module_name=module_name) 2869 self.assertEqual(module_name, 2870 my_flags.find_module_defining_flag('flag_name')) 2871 2872 def test_find_module_id_defining_flag_passing_module_name(self): 2873 my_flags = flags.FlagValues() 2874 module_name = sys.__name__ # Must use an existing module. 2875 flags.DEFINE_boolean( 2876 'flag_name', 2877 True, 2878 'Flag with a different module name.', 2879 flag_values=my_flags, 2880 module_name=module_name) 2881 self.assertEqual( 2882 id(sys), my_flags.find_module_id_defining_flag('flag_name')) 2883 2884 2885class FlagsErrorMessagesTest(absltest.TestCase): 2886 """Testing special cases for integer and float flags error messages.""" 2887 2888 def setUp(self): 2889 self.flag_values = flags.FlagValues() 2890 2891 def test_integer_error_text(self): 2892 # Make sure we get proper error text 2893 flags.DEFINE_integer( 2894 'positive', 2895 4, 2896 'non-negative flag', 2897 lower_bound=1, 2898 flag_values=self.flag_values) 2899 flags.DEFINE_integer( 2900 'non_negative', 2901 4, 2902 'positive flag', 2903 lower_bound=0, 2904 flag_values=self.flag_values) 2905 flags.DEFINE_integer( 2906 'negative', 2907 -4, 2908 'negative flag', 2909 upper_bound=-1, 2910 flag_values=self.flag_values) 2911 flags.DEFINE_integer( 2912 'non_positive', 2913 -4, 2914 'non-positive flag', 2915 upper_bound=0, 2916 flag_values=self.flag_values) 2917 flags.DEFINE_integer( 2918 'greater', 2919 19, 2920 'greater-than flag', 2921 lower_bound=4, 2922 flag_values=self.flag_values) 2923 flags.DEFINE_integer( 2924 'smaller', 2925 -19, 2926 'smaller-than flag', 2927 upper_bound=4, 2928 flag_values=self.flag_values) 2929 flags.DEFINE_integer( 2930 'usual', 2931 4, 2932 'usual flag', 2933 lower_bound=0, 2934 upper_bound=10000, 2935 flag_values=self.flag_values) 2936 flags.DEFINE_integer( 2937 'another_usual', 2938 0, 2939 'usual flag', 2940 lower_bound=-1, 2941 upper_bound=1, 2942 flag_values=self.flag_values) 2943 2944 self._check_error_message('positive', -4, 'a positive integer') 2945 self._check_error_message('non_negative', -4, 'a non-negative integer') 2946 self._check_error_message('negative', 0, 'a negative integer') 2947 self._check_error_message('non_positive', 4, 'a non-positive integer') 2948 self._check_error_message('usual', -4, 'an integer in the range [0, 10000]') 2949 self._check_error_message('another_usual', 4, 2950 'an integer in the range [-1, 1]') 2951 self._check_error_message('greater', -5, 'integer >= 4') 2952 self._check_error_message('smaller', 5, 'integer <= 4') 2953 2954 def test_float_error_text(self): 2955 flags.DEFINE_float( 2956 'positive', 2957 4, 2958 'non-negative flag', 2959 lower_bound=1, 2960 flag_values=self.flag_values) 2961 flags.DEFINE_float( 2962 'non_negative', 2963 4, 2964 'positive flag', 2965 lower_bound=0, 2966 flag_values=self.flag_values) 2967 flags.DEFINE_float( 2968 'negative', 2969 -4, 2970 'negative flag', 2971 upper_bound=-1, 2972 flag_values=self.flag_values) 2973 flags.DEFINE_float( 2974 'non_positive', 2975 -4, 2976 'non-positive flag', 2977 upper_bound=0, 2978 flag_values=self.flag_values) 2979 flags.DEFINE_float( 2980 'greater', 2981 19, 2982 'greater-than flag', 2983 lower_bound=4, 2984 flag_values=self.flag_values) 2985 flags.DEFINE_float( 2986 'smaller', 2987 -19, 2988 'smaller-than flag', 2989 upper_bound=4, 2990 flag_values=self.flag_values) 2991 flags.DEFINE_float( 2992 'usual', 2993 4, 2994 'usual flag', 2995 lower_bound=0, 2996 upper_bound=10000, 2997 flag_values=self.flag_values) 2998 flags.DEFINE_float( 2999 'another_usual', 3000 0, 3001 'usual flag', 3002 lower_bound=-1, 3003 upper_bound=1, 3004 flag_values=self.flag_values) 3005 3006 self._check_error_message('positive', 0.5, 'number >= 1') 3007 self._check_error_message('non_negative', -4.0, 'a non-negative number') 3008 self._check_error_message('negative', 0.5, 'number <= -1') 3009 self._check_error_message('non_positive', 4.0, 'a non-positive number') 3010 self._check_error_message('usual', -4.0, 'a number in the range [0, 10000]') 3011 self._check_error_message('another_usual', 4.0, 3012 'a number in the range [-1, 1]') 3013 self._check_error_message('smaller', 5.0, 'number <= 4') 3014 3015 def _check_error_message(self, flag_name, flag_value, 3016 expected_message_suffix): 3017 """Set a flag to a given value and make sure we get expected message.""" 3018 3019 try: 3020 self.flag_values.__setattr__(flag_name, flag_value) 3021 raise AssertionError('Bounds exception not raised!') 3022 except flags.IllegalFlagValueError as e: 3023 expected = ('flag --%(name)s=%(value)s: %(value)s is not %(suffix)s' % { 3024 'name': flag_name, 3025 'value': flag_value, 3026 'suffix': expected_message_suffix 3027 }) 3028 self.assertEqual(str(e), expected) 3029 3030 3031if __name__ == '__main__': 3032 absltest.main() 3033