Skip to content

Commit 9ac99c1

Browse files
authored
Merge pull request #201 from yilei/push_up_to_480399279
Push up to 480399279
2 parents a0ae316 + 042ca20 commit 9ac99c1

17 files changed

+501
-98
lines changed

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,45 @@ The format is based on [Keep a Changelog](https://keepachangelog.com).
66

77
## Unreleased
88

9+
Nothing notable unreleased.
10+
11+
## 1.3.0 (2022-10-11)
12+
13+
### Added
14+
15+
* (flags) Added a new `absl.flags.set_default` function that updates the flag
16+
default for a provided `FlagHolder`. This parallels the
17+
`absl.flags.FlagValues.set_default` interface which takes a flag name.
18+
* (flags) The following functions now also accept `FlagHolder` instance(s) in
19+
addition to flag name(s) as their first positional argument:
20+
- `flags.register_validator`
21+
- `flags.validator`
22+
- `flags.register_multi_flags_validator`
23+
- `flags.multi_flags_validator`
24+
- `flags.mark_flag_as_required`
25+
- `flags.mark_flags_as_required`
26+
- `flags.mark_flags_as_mutual_exclusive`
27+
- `flags.mark_bool_flags_as_mutual_exclusive`
28+
- `flags.declare_key_flag`
29+
930
### Changed
1031

1132
* (testing) Assertions `assertRaisesWithPredicateMatch` and
1233
`assertRaisesWithLiteralMatch` now capture the raised `Exception` for
1334
further analysis when used as a context manager.
35+
* (testing) TextAndXMLTestRunner now produces time duration values with
36+
millisecond precision in XML test result output.
37+
* (flags) Keyword access to `flag_name` arguments in the following functions
38+
is deprecated. This parameter will be renamed in a future 2.0.0 release.
39+
- `flags.register_validator`
40+
- `flags.validator`
41+
- `flags.register_multi_flags_validator`
42+
- `flags.multi_flags_validator`
43+
- `flags.mark_flag_as_required`
44+
- `flags.mark_flags_as_required`
45+
- `flags.mark_flags_as_mutual_exclusive`
46+
- `flags.mark_bool_flags_as_mutual_exclusive`
47+
- `flags.declare_key_flag`
1448

1549
## 1.2.0 (2022-07-18)
1650

absl/flags/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
'mark_flags_as_required',
6969
'mark_flags_as_mutual_exclusive',
7070
'mark_bool_flags_as_mutual_exclusive',
71+
# Flag modifiers.
72+
'set_default',
7173
# Key flag related functions.
7274
'declare_key_flag',
7375
'adopt_module_key_flags',
@@ -152,6 +154,9 @@
152154
mark_flags_as_mutual_exclusive = _validators.mark_flags_as_mutual_exclusive
153155
mark_bool_flags_as_mutual_exclusive = _validators.mark_bool_flags_as_mutual_exclusive
154156

157+
# Flag modifiers.
158+
set_default = _defines.set_default
159+
155160
# Key flag related functions.
156161
declare_key_flag = _defines.declare_key_flag
157162
adopt_module_key_flags = _defines.adopt_module_key_flags

absl/flags/_argument_parser.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class ArgumentSerializer(object):
147147

148148
def serialize(self, value):
149149
"""Returns a serialized string of the value."""
150-
return _helpers.str_or_unicode(value)
150+
return str(value)
151151

152152

153153
class NumericParser(ArgumentParser):
@@ -454,7 +454,7 @@ def __init__(self, list_sep):
454454

455455
def serialize(self, value):
456456
"""See base class."""
457-
return self.list_sep.join([_helpers.str_or_unicode(x) for x in value])
457+
return self.list_sep.join([str(x) for x in value])
458458

459459

460460
class EnumClassListSerializer(ListSerializer):
@@ -498,7 +498,7 @@ def serialize(self, value):
498498

499499
# We need the returned value to be pure ascii or Unicodes so that
500500
# when the xml help is generated they are usefully encodable.
501-
return _helpers.str_or_unicode(serialized_value)
501+
return str(serialized_value)
502502

503503

504504
class EnumClassSerializer(ArgumentSerializer):
@@ -514,7 +514,7 @@ def __init__(self, lowercase):
514514

515515
def serialize(self, value):
516516
"""Returns a serialized string of the Enum class value."""
517-
as_string = _helpers.str_or_unicode(value.name)
517+
as_string = str(value.name)
518518
return as_string.lower() if self._lowercase else as_string
519519

520520

absl/flags/_defines.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,23 @@ def DEFINE_flag( # pylint: disable=invalid-name
148148
fv, flag, ensure_non_none_value=ensure_non_none_value)
149149

150150

151+
def set_default(flag_holder, value):
152+
"""Changes the default value of the provided flag object.
153+
154+
The flag's current value is also updated if the flag is currently using
155+
the default value, i.e. not specified in the command line, and not set
156+
by FLAGS.name = value.
157+
158+
Args:
159+
flag_holder: FlagHolder, the flag to modify.
160+
value: The new default value.
161+
162+
Raises:
163+
IllegalFlagValueError: Raised when value is not valid.
164+
"""
165+
flag_holder._flagvalues.set_default(flag_holder.name, value) # pylint: disable=protected-access
166+
167+
151168
def _internal_declare_key_flags(flag_names,
152169
flag_values=_flagvalues.FLAGS,
153170
key_flag_values=None):
@@ -157,8 +174,7 @@ def _internal_declare_key_flags(flag_names,
157174
adopt_module_key_flags instead.
158175
159176
Args:
160-
flag_names: [str], a list of strings that are names of already-registered
161-
Flag objects.
177+
flag_names: [str], a list of names of already-registered Flag objects.
162178
flag_values: :class:`FlagValues`, the FlagValues instance with which the
163179
flags listed in flag_names have registered (the value of the flag_values
164180
argument from the ``DEFINE_*`` calls that defined those flags). This
@@ -176,8 +192,7 @@ def _internal_declare_key_flags(flag_names,
176192
module = _helpers.get_calling_module()
177193

178194
for flag_name in flag_names:
179-
flag = flag_values[flag_name]
180-
key_flag_values.register_key_flag_for_module(module, flag)
195+
key_flag_values.register_key_flag_for_module(module, flag_values[flag_name])
181196

182197

183198
def declare_key_flag(flag_name, flag_values=_flagvalues.FLAGS):
@@ -194,16 +209,18 @@ def declare_key_flag(flag_name, flag_values=_flagvalues.FLAGS):
194209
flags.declare_key_flag('flag_1')
195210
196211
Args:
197-
flag_name: str, the name of an already declared flag. (Redeclaring flags as
198-
key, including flags implicitly key because they were declared in this
199-
module, is a no-op.)
212+
flag_name: str | :class:`FlagHolder`, the name or holder of an already
213+
declared flag. (Redeclaring flags as key, including flags implicitly key
214+
because they were declared in this module, is a no-op.)
215+
Positional-only parameter.
200216
flag_values: :class:`FlagValues`, the FlagValues instance in which the
201217
flag will be declared as a key flag. This should almost never need to be
202218
overridden.
203219
204220
Raises:
205221
ValueError: Raised if flag_name not defined as a Python flag.
206222
"""
223+
flag_name, flag_values = _flagvalues.resolve_flag_ref(flag_name, flag_values)
207224
if flag_name in _helpers.SPECIAL_FLAGS:
208225
# Take care of the special flags, e.g., --flagfile, --undefok.
209226
# These flags are defined in SPECIAL_FLAGS, and are treated

absl/flags/_defines.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,11 @@ def DEFINE_alias(
650650
...
651651

652652

653+
def set_default(flag_holder: _flagvalues.FlagHolder[_T], value: _T) -> None:
654+
...
655+
653656

654-
def declare_key_flag(flag_name: Text,
657+
def declare_key_flag(flag_name: Union[Text, _flagvalues.FlagHolder],
655658
flag_values: _flagvalues.FlagValues = ...) -> None:
656659
...
657660

absl/flags/_flag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def _get_parsed_value_as_string(self, value):
153153
return repr('true')
154154
else:
155155
return repr('false')
156-
return repr(_helpers.str_or_unicode(value))
156+
return repr(str(value))
157157

158158
def parse(self, argument):
159159
"""Parses string and sets flag value.

absl/flags/_flagvalues.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,7 @@ def __setitem__(self, name, flag):
412412
fl = self._flags()
413413
if not isinstance(flag, _flag.Flag):
414414
raise _exceptions.IllegalFlagValueError(flag)
415-
if str is bytes and isinstance(name, unicode):
416-
# When using Python 2 with unicode_literals, allow it but encode it
417-
# into the bytes type we require.
418-
name = name.encode('utf-8')
419-
if not isinstance(name, type('')):
415+
if not isinstance(name, str):
420416
raise _exceptions.Error('Flag name must be a string')
421417
if not name:
422418
raise _exceptions.Error('Flag name cannot be empty')
@@ -632,7 +628,7 @@ def __call__(self, argv, known_only=False):
632628
TypeError: Raised on passing wrong type of arguments.
633629
ValueError: Raised on flag value parsing error.
634630
"""
635-
if _helpers.is_bytes_or_string(argv):
631+
if isinstance(argv, (str, bytes)):
636632
raise TypeError(
637633
'argv should be a tuple/list of strings, not bytes or string.')
638634
if not argv:
@@ -1006,7 +1002,7 @@ def get_flag_value(self, name, default): # pylint: disable=invalid-name
10061002

10071003
def _is_flag_file_directive(self, flag_string):
10081004
"""Checks whether flag_string contain a --flagfile=<foo> directive."""
1009-
if isinstance(flag_string, type('')):
1005+
if isinstance(flag_string, str):
10101006
if flag_string.startswith('--flagfile='):
10111007
return 1
10121008
elif flag_string == '--flagfile':
@@ -1388,3 +1384,35 @@ def default(self):
13881384
def present(self):
13891385
"""Returns True if the flag was parsed from command-line flags."""
13901386
return bool(self._flagvalues[self._name].present)
1387+
1388+
1389+
def resolve_flag_ref(flag_ref, flag_values):
1390+
"""Helper to validate and resolve a flag reference argument."""
1391+
if isinstance(flag_ref, FlagHolder):
1392+
new_flag_values = flag_ref._flagvalues # pylint: disable=protected-access
1393+
if flag_values != FLAGS and flag_values != new_flag_values:
1394+
raise ValueError(
1395+
'flag_values must not be customized when operating on a FlagHolder')
1396+
return flag_ref.name, new_flag_values
1397+
return flag_ref, flag_values
1398+
1399+
1400+
def resolve_flag_refs(flag_refs, flag_values):
1401+
"""Helper to validate and resolve flag reference list arguments."""
1402+
fv = None
1403+
names = []
1404+
for ref in flag_refs:
1405+
if isinstance(ref, FlagHolder):
1406+
newfv = ref._flagvalues # pylint: disable=protected-access
1407+
name = ref.name
1408+
else:
1409+
newfv = flag_values
1410+
name = ref
1411+
if fv and fv != newfv:
1412+
raise ValueError(
1413+
'multiple FlagValues instances used in invocation. '
1414+
'FlagHolders must be registered to the same FlagValues instance as '
1415+
'do flag names, if provided.')
1416+
fv = newfv
1417+
names.append(name)
1418+
return names, fv

absl/flags/_helpers.py

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@
3232

3333

3434
_DEFAULT_HELP_WIDTH = 80 # Default width of help output.
35-
_MIN_HELP_WIDTH = 40 # Minimal "sane" width of help output. We assume that any
36-
# value below 40 is unreasonable.
35+
# Minimal "sane" width of help output. We assume that any value below 40 is
36+
# unreasonable.
37+
_MIN_HELP_WIDTH = 40
3738

3839
# Define the allowed error rate in an input string to get suggestions.
3940
#
@@ -125,32 +126,6 @@ def get_calling_module():
125126
return get_calling_module_object_and_name().module_name
126127

127128

128-
def str_or_unicode(value):
129-
"""Converts a value to a python string.
130-
131-
Behavior of this function is intentionally different in Python2/3.
132-
133-
In Python2, the given value is attempted to convert to a str (byte string).
134-
If it contains non-ASCII characters, it is converted to a unicode instead.
135-
136-
In Python3, the given value is always converted to a str (unicode string).
137-
138-
This behavior reflects the (bad) practice in Python2 to try to represent
139-
a string as str as long as it contains ASCII characters only.
140-
141-
Args:
142-
value: An object to be converted to a string.
143-
144-
Returns:
145-
A string representation of the given value. See the description above
146-
for its type.
147-
"""
148-
try:
149-
return str(value)
150-
except UnicodeEncodeError:
151-
return unicode(value) # Python3 should never come here
152-
153-
154129
def create_xml_dom_element(doc, name, value):
155130
"""Returns an XML DOM element with name and text value.
156131
@@ -164,7 +139,7 @@ def create_xml_dom_element(doc, name, value):
164139
Returns:
165140
An instance of minidom.Element.
166141
"""
167-
s = str_or_unicode(value)
142+
s = str(value)
168143
if isinstance(value, bool):
169144
# Display boolean values as the C++ flag library does: no caps.
170145
s = s.lower()
@@ -424,10 +399,3 @@ def doc_to_help(doc):
424399
doc = re.sub(r'(?<=\S)\n(?=\S)', ' ', doc, flags=re.M)
425400

426401
return doc
427-
428-
429-
def is_bytes_or_string(maybe_string):
430-
if str is bytes:
431-
return isinstance(maybe_string, basestring)
432-
else:
433-
return isinstance(maybe_string, (str, bytes))

0 commit comments

Comments
 (0)