930 lines
32 KiB
Python
930 lines
32 KiB
Python
# Copyright 2017 The Abseil Authors.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Tests for flags.FlagValues class."""
|
|
|
|
import collections
|
|
import copy
|
|
import pickle
|
|
import types
|
|
from unittest import mock
|
|
|
|
from absl import logging
|
|
from absl.flags import _defines
|
|
from absl.flags import _exceptions
|
|
from absl.flags import _flagvalues
|
|
from absl.flags import _helpers
|
|
from absl.flags import _validators
|
|
from absl.flags.tests import module_foo
|
|
from absl.testing import absltest
|
|
from absl.testing import parameterized
|
|
|
|
|
|
class FlagValuesTest(absltest.TestCase):
|
|
|
|
def test_bool_flags(self):
|
|
for arg, expected in (('--nothing', True),
|
|
('--nothing=true', True),
|
|
('--nothing=false', False),
|
|
('--nonothing', False)):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_boolean('nothing', None, '', flag_values=fv)
|
|
fv(('./program', arg))
|
|
self.assertIs(expected, fv.nothing)
|
|
|
|
for arg in ('--nonothing=true', '--nonothing=false'):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_boolean('nothing', None, '', flag_values=fv)
|
|
with self.assertRaises(ValueError):
|
|
fv(('./program', arg))
|
|
|
|
def test_boolean_flag_parser_gets_string_argument(self):
|
|
for arg, expected in (('--nothing', 'true'),
|
|
('--nothing=true', 'true'),
|
|
('--nothing=false', 'false'),
|
|
('--nonothing', 'false')):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_boolean('nothing', None, '', flag_values=fv)
|
|
with mock.patch.object(fv['nothing'].parser, 'parse') as mock_parse:
|
|
fv(('./program', arg))
|
|
mock_parse.assert_called_once_with(expected)
|
|
|
|
def test_unregistered_flags_are_cleaned_up(self):
|
|
fv = _flagvalues.FlagValues()
|
|
module, module_name = _helpers.get_calling_module_object_and_name()
|
|
|
|
# Define first flag.
|
|
_defines.DEFINE_integer('cores', 4, '', flag_values=fv, short_name='c')
|
|
old_cores_flag = fv['cores']
|
|
fv.register_key_flag_for_module(module_name, old_cores_flag)
|
|
self.assertEqual(fv.flags_by_module_dict(),
|
|
{module_name: [old_cores_flag]})
|
|
self.assertEqual(fv.flags_by_module_id_dict(),
|
|
{id(module): [old_cores_flag]})
|
|
self.assertEqual(fv.key_flags_by_module_dict(),
|
|
{module_name: [old_cores_flag]})
|
|
|
|
# Redefine the same flag.
|
|
_defines.DEFINE_integer(
|
|
'cores', 4, '', flag_values=fv, short_name='c', allow_override=True)
|
|
new_cores_flag = fv['cores']
|
|
self.assertNotEqual(old_cores_flag, new_cores_flag)
|
|
self.assertEqual(fv.flags_by_module_dict(),
|
|
{module_name: [new_cores_flag]})
|
|
self.assertEqual(fv.flags_by_module_id_dict(),
|
|
{id(module): [new_cores_flag]})
|
|
# old_cores_flag is removed from key flags, and the new_cores_flag is
|
|
# not automatically added because it must be registered explicitly.
|
|
self.assertEqual(fv.key_flags_by_module_dict(), {module_name: []})
|
|
|
|
# Define a new flag but with the same short_name.
|
|
_defines.DEFINE_integer(
|
|
'changelist',
|
|
0,
|
|
'',
|
|
flag_values=fv,
|
|
short_name='c',
|
|
allow_override=True)
|
|
old_changelist_flag = fv['changelist']
|
|
fv.register_key_flag_for_module(module_name, old_changelist_flag)
|
|
# The short named flag -c is overridden to be the old_changelist_flag.
|
|
self.assertEqual(fv['c'], old_changelist_flag)
|
|
self.assertNotEqual(fv['c'], new_cores_flag)
|
|
self.assertEqual(fv.flags_by_module_dict(),
|
|
{module_name: [new_cores_flag, old_changelist_flag]})
|
|
self.assertEqual(fv.flags_by_module_id_dict(),
|
|
{id(module): [new_cores_flag, old_changelist_flag]})
|
|
self.assertEqual(fv.key_flags_by_module_dict(),
|
|
{module_name: [old_changelist_flag]})
|
|
|
|
# Define a flag only with the same long name.
|
|
_defines.DEFINE_integer(
|
|
'changelist',
|
|
0,
|
|
'',
|
|
flag_values=fv,
|
|
short_name='l',
|
|
allow_override=True)
|
|
new_changelist_flag = fv['changelist']
|
|
self.assertNotEqual(old_changelist_flag, new_changelist_flag)
|
|
self.assertEqual(fv.flags_by_module_dict(),
|
|
{module_name: [new_cores_flag,
|
|
old_changelist_flag,
|
|
new_changelist_flag]})
|
|
self.assertEqual(fv.flags_by_module_id_dict(),
|
|
{id(module): [new_cores_flag,
|
|
old_changelist_flag,
|
|
new_changelist_flag]})
|
|
self.assertEqual(fv.key_flags_by_module_dict(),
|
|
{module_name: [old_changelist_flag]})
|
|
|
|
# Delete the new changelist's long name, it should still be registered
|
|
# because of its short name.
|
|
del fv.changelist
|
|
self.assertNotIn('changelist', fv)
|
|
self.assertEqual(fv.flags_by_module_dict(),
|
|
{module_name: [new_cores_flag,
|
|
old_changelist_flag,
|
|
new_changelist_flag]})
|
|
self.assertEqual(fv.flags_by_module_id_dict(),
|
|
{id(module): [new_cores_flag,
|
|
old_changelist_flag,
|
|
new_changelist_flag]})
|
|
self.assertEqual(fv.key_flags_by_module_dict(),
|
|
{module_name: [old_changelist_flag]})
|
|
|
|
# Delete the new changelist's short name, it should be removed.
|
|
del fv.l
|
|
self.assertNotIn('l', fv)
|
|
self.assertEqual(fv.flags_by_module_dict(),
|
|
{module_name: [new_cores_flag,
|
|
old_changelist_flag]})
|
|
self.assertEqual(fv.flags_by_module_id_dict(),
|
|
{id(module): [new_cores_flag,
|
|
old_changelist_flag]})
|
|
self.assertEqual(fv.key_flags_by_module_dict(),
|
|
{module_name: [old_changelist_flag]})
|
|
|
|
def _test_find_module_or_id_defining_flag(self, test_id):
|
|
"""Tests for find_module_defining_flag and find_module_id_defining_flag.
|
|
|
|
Args:
|
|
test_id: True to test find_module_id_defining_flag, False to test
|
|
find_module_defining_flag.
|
|
"""
|
|
fv = _flagvalues.FlagValues()
|
|
current_module, current_module_name = (
|
|
_helpers.get_calling_module_object_and_name())
|
|
alt_module_name = _flagvalues.__name__
|
|
|
|
if test_id:
|
|
current_module_or_id = id(current_module)
|
|
alt_module_or_id = id(_flagvalues)
|
|
testing_fn = fv.find_module_id_defining_flag
|
|
else:
|
|
current_module_or_id = current_module_name
|
|
alt_module_or_id = alt_module_name
|
|
testing_fn = fv.find_module_defining_flag
|
|
|
|
# Define first flag.
|
|
_defines.DEFINE_integer('cores', 4, '', flag_values=fv, short_name='c')
|
|
module_or_id_cores = testing_fn('cores')
|
|
self.assertEqual(module_or_id_cores, current_module_or_id)
|
|
module_or_id_c = testing_fn('c')
|
|
self.assertEqual(module_or_id_c, current_module_or_id)
|
|
|
|
# Redefine the same flag in another module.
|
|
_defines.DEFINE_integer(
|
|
'cores',
|
|
4,
|
|
'',
|
|
flag_values=fv,
|
|
module_name=alt_module_name,
|
|
short_name='c',
|
|
allow_override=True)
|
|
module_or_id_cores = testing_fn('cores')
|
|
self.assertEqual(module_or_id_cores, alt_module_or_id)
|
|
module_or_id_c = testing_fn('c')
|
|
self.assertEqual(module_or_id_c, alt_module_or_id)
|
|
|
|
# Define a new flag but with the same short_name.
|
|
_defines.DEFINE_integer(
|
|
'changelist',
|
|
0,
|
|
'',
|
|
flag_values=fv,
|
|
short_name='c',
|
|
allow_override=True)
|
|
module_or_id_cores = testing_fn('cores')
|
|
self.assertEqual(module_or_id_cores, alt_module_or_id)
|
|
module_or_id_changelist = testing_fn('changelist')
|
|
self.assertEqual(module_or_id_changelist, current_module_or_id)
|
|
module_or_id_c = testing_fn('c')
|
|
self.assertEqual(module_or_id_c, current_module_or_id)
|
|
|
|
# Define a flag in another module only with the same long name.
|
|
_defines.DEFINE_integer(
|
|
'changelist',
|
|
0,
|
|
'',
|
|
flag_values=fv,
|
|
module_name=alt_module_name,
|
|
short_name='l',
|
|
allow_override=True)
|
|
module_or_id_cores = testing_fn('cores')
|
|
self.assertEqual(module_or_id_cores, alt_module_or_id)
|
|
module_or_id_changelist = testing_fn('changelist')
|
|
self.assertEqual(module_or_id_changelist, alt_module_or_id)
|
|
module_or_id_c = testing_fn('c')
|
|
self.assertEqual(module_or_id_c, current_module_or_id)
|
|
module_or_id_l = testing_fn('l')
|
|
self.assertEqual(module_or_id_l, alt_module_or_id)
|
|
|
|
# Delete the changelist flag, its short name should still be registered.
|
|
del fv.changelist
|
|
module_or_id_changelist = testing_fn('changelist')
|
|
self.assertIsNone(module_or_id_changelist)
|
|
module_or_id_c = testing_fn('c')
|
|
self.assertEqual(module_or_id_c, current_module_or_id)
|
|
module_or_id_l = testing_fn('l')
|
|
self.assertEqual(module_or_id_l, alt_module_or_id)
|
|
|
|
def test_find_module_defining_flag(self):
|
|
self._test_find_module_or_id_defining_flag(test_id=False)
|
|
|
|
def test_find_module_id_defining_flag(self):
|
|
self._test_find_module_or_id_defining_flag(test_id=True)
|
|
|
|
def test_set_default(self):
|
|
fv = _flagvalues.FlagValues()
|
|
fv.mark_as_parsed()
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
fv.set_default('changelist', 1)
|
|
_defines.DEFINE_integer('changelist', 0, 'help', flag_values=fv)
|
|
self.assertEqual(0, fv.changelist)
|
|
fv.set_default('changelist', 2)
|
|
self.assertEqual(2, fv.changelist)
|
|
|
|
def test_default_gnu_getopt_value(self):
|
|
self.assertTrue(_flagvalues.FlagValues().is_gnu_getopt())
|
|
|
|
def test_known_only_flags_in_gnustyle(self):
|
|
|
|
def run_test(argv, defined_py_flags, expected_argv):
|
|
fv = _flagvalues.FlagValues()
|
|
fv.set_gnu_getopt(True)
|
|
for f in defined_py_flags:
|
|
if f.startswith('b'):
|
|
_defines.DEFINE_boolean(f, False, 'help', flag_values=fv)
|
|
else:
|
|
_defines.DEFINE_string(f, 'default', 'help', flag_values=fv)
|
|
output_argv = fv(argv, known_only=True)
|
|
self.assertEqual(expected_argv, output_argv)
|
|
|
|
run_test(
|
|
argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '),
|
|
defined_py_flags=[],
|
|
expected_argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '))
|
|
run_test(
|
|
argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '),
|
|
defined_py_flags=['f1'],
|
|
expected_argv='0 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '))
|
|
run_test(
|
|
argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '),
|
|
defined_py_flags=['f2'],
|
|
expected_argv='0 --f1=v1 cmd --b1 --f3 v3 --nob2'.split(' '))
|
|
run_test(
|
|
argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '),
|
|
defined_py_flags=['b1'],
|
|
expected_argv='0 --f1=v1 cmd --f2 v2 --f3 v3 --nob2'.split(' '))
|
|
run_test(
|
|
argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '),
|
|
defined_py_flags=['f3'],
|
|
expected_argv='0 --f1=v1 cmd --f2 v2 --b1 --nob2'.split(' '))
|
|
run_test(
|
|
argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3 --nob2'.split(' '),
|
|
defined_py_flags=['b2'],
|
|
expected_argv='0 --f1=v1 cmd --f2 v2 --b1 --f3 v3'.split(' '))
|
|
run_test(
|
|
argv=('0 --f1=v1 cmd --undefok=f1 --f2 v2 --b1 '
|
|
'--f3 v3 --nob2').split(' '),
|
|
defined_py_flags=['b2'],
|
|
expected_argv='0 cmd --f2 v2 --b1 --f3 v3'.split(' '))
|
|
run_test(
|
|
argv=('0 --f1=v1 cmd --undefok f1,f2 --f2 v2 --b1 '
|
|
'--f3 v3 --nob2').split(' '),
|
|
defined_py_flags=['b2'],
|
|
# Note v2 is preserved here, since undefok requires the flag being
|
|
# specified in the form of --flag=value.
|
|
expected_argv='0 cmd v2 --b1 --f3 v3'.split(' '))
|
|
|
|
def test_invalid_flag_name(self):
|
|
with self.assertRaises(_exceptions.Error):
|
|
_defines.DEFINE_boolean('test ', 0, '')
|
|
|
|
with self.assertRaises(_exceptions.Error):
|
|
_defines.DEFINE_boolean(' test', 0, '')
|
|
|
|
with self.assertRaises(_exceptions.Error):
|
|
_defines.DEFINE_boolean('te st', 0, '')
|
|
|
|
with self.assertRaises(_exceptions.Error):
|
|
_defines.DEFINE_boolean('', 0, '')
|
|
|
|
with self.assertRaises(_exceptions.Error):
|
|
_defines.DEFINE_boolean(1, 0, '')
|
|
|
|
def test_len(self):
|
|
fv = _flagvalues.FlagValues()
|
|
self.assertEmpty(fv)
|
|
self.assertFalse(fv)
|
|
|
|
_defines.DEFINE_boolean('boolean', False, 'help', flag_values=fv)
|
|
self.assertLen(fv, 1)
|
|
self.assertTrue(fv)
|
|
|
|
_defines.DEFINE_boolean(
|
|
'bool', False, 'help', short_name='b', flag_values=fv)
|
|
self.assertLen(fv, 3)
|
|
self.assertTrue(fv)
|
|
|
|
def test_pickle(self):
|
|
fv = _flagvalues.FlagValues()
|
|
with self.assertRaisesRegex(TypeError, "can't pickle FlagValues"):
|
|
pickle.dumps(fv)
|
|
|
|
def test_copy(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_integer('answer', 0, 'help', flag_values=fv)
|
|
fv(['', '--answer=1'])
|
|
|
|
with self.assertRaisesRegex(TypeError,
|
|
'FlagValues does not support shallow copies'):
|
|
copy.copy(fv)
|
|
|
|
fv2 = copy.deepcopy(fv)
|
|
self.assertEqual(fv2.answer, 1)
|
|
|
|
fv2.answer = 42
|
|
self.assertEqual(fv2.answer, 42)
|
|
self.assertEqual(fv.answer, 1)
|
|
|
|
def test_conflicting_flags(self):
|
|
fv = _flagvalues.FlagValues()
|
|
with self.assertRaises(_exceptions.FlagNameConflictsWithMethodError):
|
|
_defines.DEFINE_boolean('is_gnu_getopt', False, 'help', flag_values=fv)
|
|
_defines.DEFINE_boolean(
|
|
'is_gnu_getopt',
|
|
False,
|
|
'help',
|
|
flag_values=fv,
|
|
allow_using_method_names=True)
|
|
self.assertFalse(fv['is_gnu_getopt'].value)
|
|
self.assertIsInstance(fv.is_gnu_getopt, types.MethodType)
|
|
|
|
def test_get_flags_for_module(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('foo', None, 'help', flag_values=fv)
|
|
module_foo.define_flags(fv)
|
|
flags = fv.get_flags_for_module('__main__')
|
|
|
|
self.assertEqual({'foo'}, {flag.name for flag in flags})
|
|
|
|
flags = fv.get_flags_for_module(module_foo)
|
|
self.assertEqual({'tmod_foo_bool', 'tmod_foo_int', 'tmod_foo_str'},
|
|
{flag.name for flag in flags})
|
|
|
|
def test_get_help(self):
|
|
fv = _flagvalues.FlagValues()
|
|
self.assertMultiLineEqual('''\
|
|
--flagfile: Insert flag definitions from the given file into the command line.
|
|
(default: '')
|
|
--undefok: comma-separated list of flag names that it is okay to specify on the
|
|
command line even if the program does not define a flag with that name.
|
|
IMPORTANT: flags in this list that have arguments MUST use the --flag=value
|
|
format.
|
|
(default: '')''', fv.get_help())
|
|
|
|
module_foo.define_flags(fv)
|
|
self.assertMultiLineEqual('''
|
|
absl.flags.tests.module_bar:
|
|
--tmod_bar_t: Sample int flag.
|
|
(default: '4')
|
|
(an integer)
|
|
--tmod_bar_u: Sample int flag.
|
|
(default: '5')
|
|
(an integer)
|
|
--tmod_bar_v: Sample int flag.
|
|
(default: '6')
|
|
(an integer)
|
|
--[no]tmod_bar_x: Boolean flag.
|
|
(default: 'true')
|
|
--tmod_bar_y: String flag.
|
|
(default: 'default')
|
|
--[no]tmod_bar_z: Another boolean flag from module bar.
|
|
(default: 'false')
|
|
|
|
absl.flags.tests.module_foo:
|
|
--[no]tmod_foo_bool: Boolean flag from module foo.
|
|
(default: 'true')
|
|
--tmod_foo_int: Sample int flag.
|
|
(default: '3')
|
|
(an integer)
|
|
--tmod_foo_str: String flag.
|
|
(default: 'default')
|
|
|
|
absl.flags:
|
|
--flagfile: Insert flag definitions from the given file into the command line.
|
|
(default: '')
|
|
--undefok: comma-separated list of flag names that it is okay to specify on
|
|
the command line even if the program does not define a flag with that name.
|
|
IMPORTANT: flags in this list that have arguments MUST use the --flag=value
|
|
format.
|
|
(default: '')''', fv.get_help())
|
|
|
|
self.assertMultiLineEqual('''
|
|
xxxxabsl.flags.tests.module_bar:
|
|
xxxx --tmod_bar_t: Sample int flag.
|
|
xxxx (default: '4')
|
|
xxxx (an integer)
|
|
xxxx --tmod_bar_u: Sample int flag.
|
|
xxxx (default: '5')
|
|
xxxx (an integer)
|
|
xxxx --tmod_bar_v: Sample int flag.
|
|
xxxx (default: '6')
|
|
xxxx (an integer)
|
|
xxxx --[no]tmod_bar_x: Boolean flag.
|
|
xxxx (default: 'true')
|
|
xxxx --tmod_bar_y: String flag.
|
|
xxxx (default: 'default')
|
|
xxxx --[no]tmod_bar_z: Another boolean flag from module bar.
|
|
xxxx (default: 'false')
|
|
|
|
xxxxabsl.flags.tests.module_foo:
|
|
xxxx --[no]tmod_foo_bool: Boolean flag from module foo.
|
|
xxxx (default: 'true')
|
|
xxxx --tmod_foo_int: Sample int flag.
|
|
xxxx (default: '3')
|
|
xxxx (an integer)
|
|
xxxx --tmod_foo_str: String flag.
|
|
xxxx (default: 'default')
|
|
|
|
xxxxabsl.flags:
|
|
xxxx --flagfile: Insert flag definitions from the given file into the command
|
|
xxxx line.
|
|
xxxx (default: '')
|
|
xxxx --undefok: comma-separated list of flag names that it is okay to specify
|
|
xxxx on the command line even if the program does not define a flag with that
|
|
xxxx name. IMPORTANT: flags in this list that have arguments MUST use the
|
|
xxxx --flag=value format.
|
|
xxxx (default: '')''', fv.get_help(prefix='xxxx'))
|
|
|
|
self.assertMultiLineEqual('''
|
|
absl.flags.tests.module_bar:
|
|
--tmod_bar_t: Sample int flag.
|
|
(default: '4')
|
|
(an integer)
|
|
--tmod_bar_u: Sample int flag.
|
|
(default: '5')
|
|
(an integer)
|
|
--tmod_bar_v: Sample int flag.
|
|
(default: '6')
|
|
(an integer)
|
|
--[no]tmod_bar_x: Boolean flag.
|
|
(default: 'true')
|
|
--tmod_bar_y: String flag.
|
|
(default: 'default')
|
|
--[no]tmod_bar_z: Another boolean flag from module bar.
|
|
(default: 'false')
|
|
|
|
absl.flags.tests.module_foo:
|
|
--[no]tmod_foo_bool: Boolean flag from module foo.
|
|
(default: 'true')
|
|
--tmod_foo_int: Sample int flag.
|
|
(default: '3')
|
|
(an integer)
|
|
--tmod_foo_str: String flag.
|
|
(default: 'default')''', fv.get_help(include_special_flags=False))
|
|
|
|
def test_str(self):
|
|
fv = _flagvalues.FlagValues()
|
|
self.assertEqual(str(fv), fv.get_help())
|
|
module_foo.define_flags(fv)
|
|
self.assertEqual(str(fv), fv.get_help())
|
|
|
|
def test_empty_argv(self):
|
|
fv = _flagvalues.FlagValues()
|
|
with self.assertRaises(ValueError):
|
|
fv([])
|
|
|
|
def test_invalid_argv(self):
|
|
fv = _flagvalues.FlagValues()
|
|
with self.assertRaises(TypeError):
|
|
fv('./program')
|
|
with self.assertRaises(TypeError):
|
|
fv(b'./program')
|
|
with self.assertRaises(TypeError):
|
|
fv(u'./program')
|
|
|
|
def test_flags_dir(self):
|
|
flag_values = _flagvalues.FlagValues()
|
|
flag_name1 = 'bool_flag'
|
|
flag_name2 = 'string_flag'
|
|
flag_name3 = 'float_flag'
|
|
description = 'Description'
|
|
_defines.DEFINE_boolean(
|
|
flag_name1, None, description, flag_values=flag_values)
|
|
_defines.DEFINE_string(
|
|
flag_name2, None, description, flag_values=flag_values)
|
|
self.assertEqual(sorted([flag_name1, flag_name2]), dir(flag_values))
|
|
|
|
_defines.DEFINE_float(
|
|
flag_name3, None, description, flag_values=flag_values)
|
|
self.assertEqual(
|
|
sorted([flag_name1, flag_name2, flag_name3]), dir(flag_values))
|
|
|
|
def test_flags_into_string_deterministic(self):
|
|
flag_values = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string(
|
|
'fa', 'x', '', flag_values=flag_values, module_name='mb')
|
|
_defines.DEFINE_string(
|
|
'fb', 'x', '', flag_values=flag_values, module_name='mb')
|
|
_defines.DEFINE_string(
|
|
'fc', 'x', '', flag_values=flag_values, module_name='ma')
|
|
_defines.DEFINE_string(
|
|
'fd', 'x', '', flag_values=flag_values, module_name='ma')
|
|
|
|
expected = ('--fc=x\n'
|
|
'--fd=x\n'
|
|
'--fa=x\n'
|
|
'--fb=x\n')
|
|
|
|
flags_by_module_items = sorted(
|
|
flag_values.flags_by_module_dict().items(), reverse=True)
|
|
for _, module_flags in flags_by_module_items:
|
|
module_flags.sort(reverse=True)
|
|
|
|
flag_values.__dict__['__flags_by_module'] = collections.OrderedDict(
|
|
flags_by_module_items)
|
|
|
|
actual = flag_values.flags_into_string()
|
|
self.assertEqual(expected, actual)
|
|
|
|
def test_validate_all_flags(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('name', None, '', flag_values=fv)
|
|
_validators.mark_flag_as_required('name', flag_values=fv)
|
|
with self.assertRaises(_exceptions.IllegalFlagValueError):
|
|
fv.validate_all_flags()
|
|
fv.name = 'test'
|
|
fv.validate_all_flags()
|
|
|
|
|
|
class FlagValuesLoggingTest(absltest.TestCase):
|
|
"""Test to make sure logging.* functions won't recurse.
|
|
|
|
Logging may and does happen before flags initialization. We need to make
|
|
sure that any warnings trown by flagvalues do not result in unlimited
|
|
recursion.
|
|
"""
|
|
|
|
def test_logging_do_not_recurse(self):
|
|
logging.info('test info')
|
|
try:
|
|
raise ValueError('test exception')
|
|
except ValueError:
|
|
logging.exception('test message')
|
|
|
|
|
|
class FlagSubstrMatchingTests(parameterized.TestCase):
|
|
"""Tests related to flag substring matching."""
|
|
|
|
def _get_test_flag_values(self):
|
|
"""Get a _flagvalues.FlagValues() instance, set up for tests."""
|
|
flag_values = _flagvalues.FlagValues()
|
|
|
|
_defines.DEFINE_string('strf', '', '', flag_values=flag_values)
|
|
_defines.DEFINE_boolean('boolf', 0, '', flag_values=flag_values)
|
|
|
|
return flag_values
|
|
|
|
# Test cases that should always make parsing raise an error.
|
|
# Tuples of strings with the argv to use.
|
|
FAIL_TEST_CASES = [
|
|
('./program', '--boo', '0'),
|
|
('./program', '--boo=true', '0'),
|
|
('./program', '--boo=0'),
|
|
('./program', '--noboo'),
|
|
('./program', '--st=blah'),
|
|
('./program', '--st=de'),
|
|
('./program', '--st=blah', '--boo'),
|
|
('./program', '--st=blah', 'unused'),
|
|
('./program', '--st=--blah'),
|
|
('./program', '--st', '--blah'),
|
|
]
|
|
|
|
@parameterized.parameters(FAIL_TEST_CASES)
|
|
def test_raise(self, *argv):
|
|
"""Test that raising works."""
|
|
fv = self._get_test_flag_values()
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
fv(argv)
|
|
|
|
@parameterized.parameters(
|
|
FAIL_TEST_CASES + [('./program', 'unused', '--st=blah')])
|
|
def test_gnu_getopt_raise(self, *argv):
|
|
"""Test that raising works when combined with GNU-style getopt."""
|
|
fv = self._get_test_flag_values()
|
|
fv.set_gnu_getopt()
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
fv(argv)
|
|
|
|
|
|
class SettingUnknownFlagTest(absltest.TestCase):
|
|
|
|
def setUp(self):
|
|
super(SettingUnknownFlagTest, self).setUp()
|
|
self.setter_called = 0
|
|
|
|
def set_undef(self, unused_name, unused_val):
|
|
self.setter_called += 1
|
|
|
|
def test_raise_on_undefined(self):
|
|
new_flags = _flagvalues.FlagValues()
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
new_flags.undefined_flag = 0
|
|
|
|
def test_not_raise(self):
|
|
new_flags = _flagvalues.FlagValues()
|
|
new_flags._register_unknown_flag_setter(self.set_undef)
|
|
new_flags.undefined_flag = 0
|
|
self.assertEqual(self.setter_called, 1)
|
|
|
|
def test_not_raise_on_undefined_if_undefok(self):
|
|
new_flags = _flagvalues.FlagValues()
|
|
args = ['0', '--foo', '--bar=1', '--undefok=foo,bar']
|
|
unparsed = new_flags(args, known_only=True)
|
|
self.assertEqual(['0'], unparsed)
|
|
|
|
def test_re_raise_undefined(self):
|
|
def setter(unused_name, unused_val):
|
|
raise NameError()
|
|
new_flags = _flagvalues.FlagValues()
|
|
new_flags._register_unknown_flag_setter(setter)
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
new_flags.undefined_flag = 0
|
|
|
|
def test_re_raise_invalid(self):
|
|
def setter(unused_name, unused_val):
|
|
raise ValueError()
|
|
new_flags = _flagvalues.FlagValues()
|
|
new_flags._register_unknown_flag_setter(setter)
|
|
with self.assertRaises(_exceptions.IllegalFlagValueError):
|
|
new_flags.undefined_flag = 0
|
|
|
|
|
|
class SetAttributesTest(absltest.TestCase):
|
|
|
|
def setUp(self):
|
|
super(SetAttributesTest, self).setUp()
|
|
self.new_flags = _flagvalues.FlagValues()
|
|
_defines.DEFINE_boolean(
|
|
'defined_flag', None, '', flag_values=self.new_flags)
|
|
_defines.DEFINE_boolean(
|
|
'another_defined_flag', None, '', flag_values=self.new_flags)
|
|
self.setter_called = 0
|
|
|
|
def set_undef(self, unused_name, unused_val):
|
|
self.setter_called += 1
|
|
|
|
def test_two_defined_flags(self):
|
|
self.new_flags._set_attributes(
|
|
defined_flag=False, another_defined_flag=False)
|
|
self.assertEqual(self.setter_called, 0)
|
|
|
|
def test_one_defined_one_undefined_flag(self):
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
self.new_flags._set_attributes(defined_flag=False, undefined_flag=0)
|
|
|
|
def test_register_unknown_flag_setter(self):
|
|
self.new_flags._register_unknown_flag_setter(self.set_undef)
|
|
self.new_flags._set_attributes(defined_flag=False, undefined_flag=0)
|
|
self.assertEqual(self.setter_called, 1)
|
|
|
|
|
|
class FlagsDashSyntaxTest(absltest.TestCase):
|
|
|
|
def setUp(self):
|
|
super(FlagsDashSyntaxTest, self).setUp()
|
|
self.fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string(
|
|
'long_name', 'default', 'help', flag_values=self.fv, short_name='s')
|
|
|
|
def test_long_name_one_dash(self):
|
|
self.fv(['./program', '-long_name=new'])
|
|
self.assertEqual('new', self.fv.long_name)
|
|
|
|
def test_long_name_two_dashes(self):
|
|
self.fv(['./program', '--long_name=new'])
|
|
self.assertEqual('new', self.fv.long_name)
|
|
|
|
def test_long_name_three_dashes(self):
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
self.fv(['./program', '---long_name=new'])
|
|
|
|
def test_short_name_one_dash(self):
|
|
self.fv(['./program', '-s=new'])
|
|
self.assertEqual('new', self.fv.s)
|
|
|
|
def test_short_name_two_dashes(self):
|
|
self.fv(['./program', '--s=new'])
|
|
self.assertEqual('new', self.fv.s)
|
|
|
|
def test_short_name_three_dashes(self):
|
|
with self.assertRaises(_exceptions.UnrecognizedFlagError):
|
|
self.fv(['./program', '---s=new'])
|
|
|
|
|
|
class UnparseFlagsTest(absltest.TestCase):
|
|
|
|
def test_using_default_value_none(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('default_none', None, 'help', flag_values=fv)
|
|
self.assertTrue(fv['default_none'].using_default_value)
|
|
fv(['', '--default_none=notNone'])
|
|
self.assertFalse(fv['default_none'].using_default_value)
|
|
fv.unparse_flags()
|
|
self.assertTrue(fv['default_none'].using_default_value)
|
|
fv(['', '--default_none=alsoNotNone'])
|
|
self.assertFalse(fv['default_none'].using_default_value)
|
|
fv.unparse_flags()
|
|
self.assertTrue(fv['default_none'].using_default_value)
|
|
|
|
def test_using_default_value_not_none(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('default_foo', 'foo', 'help', flag_values=fv)
|
|
|
|
fv.mark_as_parsed()
|
|
self.assertTrue(fv['default_foo'].using_default_value)
|
|
|
|
fv(['', '--default_foo=foo'])
|
|
self.assertFalse(fv['default_foo'].using_default_value)
|
|
|
|
fv(['', '--default_foo=notFoo'])
|
|
self.assertFalse(fv['default_foo'].using_default_value)
|
|
|
|
fv.unparse_flags()
|
|
self.assertTrue(fv['default_foo'].using_default_value)
|
|
|
|
fv(['', '--default_foo=alsoNotFoo'])
|
|
self.assertFalse(fv['default_foo'].using_default_value)
|
|
|
|
def test_allow_overwrite_false(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string(
|
|
'default_none', None, 'help', allow_overwrite=False, flag_values=fv)
|
|
_defines.DEFINE_string(
|
|
'default_foo', 'foo', 'help', allow_overwrite=False, flag_values=fv)
|
|
|
|
fv.mark_as_parsed()
|
|
self.assertEqual('foo', fv.default_foo)
|
|
self.assertIsNone(fv.default_none)
|
|
|
|
fv(['', '--default_foo=notFoo', '--default_none=notNone'])
|
|
self.assertEqual('notFoo', fv.default_foo)
|
|
self.assertEqual('notNone', fv.default_none)
|
|
|
|
fv.unparse_flags()
|
|
self.assertEqual('foo', fv['default_foo'].value)
|
|
self.assertIsNone(fv['default_none'].value)
|
|
|
|
fv(['', '--default_foo=alsoNotFoo', '--default_none=alsoNotNone'])
|
|
self.assertEqual('alsoNotFoo', fv.default_foo)
|
|
self.assertEqual('alsoNotNone', fv.default_none)
|
|
|
|
def test_multi_string_default_none(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_multi_string('foo', None, 'help', flag_values=fv)
|
|
fv.mark_as_parsed()
|
|
self.assertIsNone(fv.foo)
|
|
fv(['', '--foo=aa'])
|
|
self.assertEqual(['aa'], fv.foo)
|
|
fv.unparse_flags()
|
|
self.assertIsNone(fv['foo'].value)
|
|
fv(['', '--foo=bb', '--foo=cc'])
|
|
self.assertEqual(['bb', 'cc'], fv.foo)
|
|
fv.unparse_flags()
|
|
self.assertIsNone(fv['foo'].value)
|
|
|
|
def test_multi_string_default_string(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_multi_string('foo', 'xyz', 'help', flag_values=fv)
|
|
expected_default = ['xyz']
|
|
fv.mark_as_parsed()
|
|
self.assertEqual(expected_default, fv.foo)
|
|
fv(['', '--foo=aa'])
|
|
self.assertEqual(['aa'], fv.foo)
|
|
fv.unparse_flags()
|
|
self.assertEqual(expected_default, fv['foo'].value)
|
|
fv(['', '--foo=bb', '--foo=cc'])
|
|
self.assertEqual(['bb', 'cc'], fv['foo'].value)
|
|
fv.unparse_flags()
|
|
self.assertEqual(expected_default, fv['foo'].value)
|
|
|
|
def test_multi_string_default_list(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_multi_string(
|
|
'foo', ['xx', 'yy', 'zz'], 'help', flag_values=fv)
|
|
expected_default = ['xx', 'yy', 'zz']
|
|
fv.mark_as_parsed()
|
|
self.assertEqual(expected_default, fv.foo)
|
|
fv(['', '--foo=aa'])
|
|
self.assertEqual(['aa'], fv.foo)
|
|
fv.unparse_flags()
|
|
self.assertEqual(expected_default, fv['foo'].value)
|
|
fv(['', '--foo=bb', '--foo=cc'])
|
|
self.assertEqual(['bb', 'cc'], fv.foo)
|
|
fv.unparse_flags()
|
|
self.assertEqual(expected_default, fv['foo'].value)
|
|
|
|
|
|
class UnparsedFlagAccessTest(absltest.TestCase):
|
|
|
|
def test_unparsed_flag_access(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('name', 'default', 'help', flag_values=fv)
|
|
with self.assertRaises(_exceptions.UnparsedFlagAccessError):
|
|
_ = fv.name
|
|
|
|
def test_hasattr_raises_in_py3(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('name', 'default', 'help', flag_values=fv)
|
|
with self.assertRaises(_exceptions.UnparsedFlagAccessError):
|
|
_ = hasattr(fv, 'name')
|
|
|
|
def test_unparsed_flags_access_raises_after_unparse_flags(self):
|
|
fv = _flagvalues.FlagValues()
|
|
_defines.DEFINE_string('a_str', 'default_value', 'help', flag_values=fv)
|
|
fv.mark_as_parsed()
|
|
self.assertEqual(fv.a_str, 'default_value')
|
|
fv.unparse_flags()
|
|
with self.assertRaises(_exceptions.UnparsedFlagAccessError):
|
|
_ = fv.a_str
|
|
|
|
|
|
class FlagHolderTest(absltest.TestCase):
|
|
|
|
def setUp(self):
|
|
super(FlagHolderTest, self).setUp()
|
|
self.fv = _flagvalues.FlagValues()
|
|
self.name_flag = _defines.DEFINE_string(
|
|
'name', 'default', 'help', flag_values=self.fv)
|
|
|
|
def parse_flags(self, *argv):
|
|
self.fv.unparse_flags()
|
|
self.fv(['binary_name'] + list(argv))
|
|
|
|
def test_name(self):
|
|
self.assertEqual('name', self.name_flag.name)
|
|
|
|
def test_value_before_flag_parsing(self):
|
|
with self.assertRaises(_exceptions.UnparsedFlagAccessError):
|
|
_ = self.name_flag.value
|
|
|
|
def test_value_returns_default_value_if_not_explicitly_set(self):
|
|
self.parse_flags()
|
|
self.assertEqual('default', self.name_flag.value)
|
|
|
|
def test_value_returns_explicitly_set_value(self):
|
|
self.parse_flags('--name=new_value')
|
|
self.assertEqual('new_value', self.name_flag.value)
|
|
|
|
def test_present_returns_false_before_flag_parsing(self):
|
|
self.assertFalse(self.name_flag.present)
|
|
|
|
def test_present_returns_false_if_not_explicitly_set(self):
|
|
self.parse_flags()
|
|
self.assertFalse(self.name_flag.present)
|
|
|
|
def test_present_returns_true_if_explicitly_set(self):
|
|
self.parse_flags('--name=new_value')
|
|
self.assertTrue(self.name_flag.present)
|
|
|
|
def test_allow_override(self):
|
|
first = _defines.DEFINE_integer(
|
|
'int_flag', 1, 'help', flag_values=self.fv, allow_override=1)
|
|
second = _defines.DEFINE_integer(
|
|
'int_flag', 2, 'help', flag_values=self.fv, allow_override=1)
|
|
self.parse_flags('--int_flag=3')
|
|
self.assertEqual(3, first.value)
|
|
self.assertEqual(3, second.value)
|
|
self.assertTrue(first.present)
|
|
self.assertTrue(second.present)
|
|
|
|
def test_eq(self):
|
|
with self.assertRaises(TypeError):
|
|
self.name_flag == 'value' # pylint: disable=pointless-statement
|
|
|
|
def test_eq_reflection(self):
|
|
with self.assertRaises(TypeError):
|
|
'value' == self.name_flag # pylint: disable=pointless-statement
|
|
|
|
def test_bool(self):
|
|
with self.assertRaises(TypeError):
|
|
bool(self.name_flag)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
absltest.main()
|