aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYilei Yang (杨一磊) <yileiyang@google.com>2022-08-24 10:47:14 -0700
committerYilei Yang (杨一磊) <yileiyang@google.com>2022-08-24 10:47:14 -0700
commit51aaeb70269943ee968866856a5d1297691d5991 (patch)
treef5cfe340188f5ccc6cac107f9d74a4617f41e4eb
parentf0679ed8e79d1352f23b80965981b704bd48e1a4 (diff)
parent0930779ec458c5345b85c93dfdf4fe35877fe88b (diff)
downloadabsl-py-51aaeb70269943ee968866856a5d1297691d5991.tar.gz
Merge commit for internal changes.
-rw-r--r--.readthedocs.yaml21
-rw-r--r--CHANGELOG.md10
-rw-r--r--absl/app.py14
-rw-r--r--absl/flags/__init__.py75
-rw-r--r--absl/flags/_argument_parser.py10
-rw-r--r--absl/flags/_defines.py160
-rw-r--r--absl/flags/_exceptions.py18
-rw-r--r--absl/flags/_flag.py83
-rw-r--r--absl/flags/_flagvalues.py97
-rw-r--r--absl/flags/_helpers.py18
-rw-r--r--absl/flags/_validators.py80
-rw-r--r--absl/flags/argparse_flags.py28
-rw-r--r--absl/logging/__init__.py88
-rw-r--r--absl/logging/converter.py51
-rw-r--r--absl/testing/absltest.py141
-rw-r--r--absl/testing/flagsaver.py76
-rw-r--r--absl/testing/parameterized.py214
-rw-r--r--absl/testing/tests/absltest_test.py23
-rw-r--r--docs/Makefile37
-rw-r--r--docs/source/conf.py60
-rw-r--r--docs/source/index.rst16
-rw-r--r--docs/source/readme_link.rst1
22 files changed, 801 insertions, 520 deletions
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000..e7b7d9b
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,21 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python and other tools you might need
+python:
+ version: "3"
+ install:
+ - method: pip
+ path: .
+ extra_requirements:
+ - m2r2
+ - sphinxcontrib-apidoc
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+ builder: html
+ configuration: docs/source/conf.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab288ff..5464857 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com).
## Unreleased
-Nothing notable unreleased.
+### Changed
+
+* (testing) Assertions `assertRaisesWithPredicateMatch` and
+ `assertRaisesWithLiteralMatch` now capture the raised `Exception` for
+ further analysis when used as a context manager.
## 1.2.0 (2022-07-18)
@@ -241,8 +245,8 @@ Nothing notable unreleased.
* (flags) An empty --flagfile value (e.g. "--flagfile=" or "--flagfile=''"
doesn't raise an error; its not just ignored. This matches Abseil C++
behavior.
-* (bazel) Building with Bazel 0.2.0 works without extra incompatibility disable
- build flags.
+* (bazel) Building with Bazel 0.2.0 works without extra incompatibility
+ disable build flags.
### Changed
diff --git a/absl/app.py b/absl/app.py
index 196a951..43d8ca3 100644
--- a/absl/app.py
+++ b/absl/app.py
@@ -14,8 +14,8 @@
"""Generic entry point for Abseil Python applications.
-To use this module, define a 'main' function with a single 'argv' argument and
-call app.run(main). For example:
+To use this module, define a ``main`` function with a single ``argv`` argument
+and call ``app.run(main)``. For example::
def main(argv):
if len(argv) > 1:
@@ -336,14 +336,14 @@ _init_callbacks = collections.deque()
def call_after_init(callback):
"""Calls the given callback only once ABSL has finished initialization.
- If ABSL has already finished initialization when `call_after_init` is
+ If ABSL has already finished initialization when ``call_after_init`` is
called then the callback is executed immediately, otherwise `callback` is
- stored to be executed after `app.run` has finished initializing (aka. just
+ stored to be executed after ``app.run`` has finished initializing (aka. just
before the main function is called).
- If called after `app.run`, this is equivalent to calling `callback()` in the
- caller thread. If called before `app.run`, callbacks are run sequentially (in
- an undefined order) in the same thread as `app.run`.
+ If called after ``app.run``, this is equivalent to calling ``callback()`` in
+ the caller thread. If called before ``app.run``, callbacks are run
+ sequentially (in an undefined order) in the same thread as ``app.run``.
Args:
callback: a callable to be called once ABSL has finished initialization.
diff --git a/absl/flags/__init__.py b/absl/flags/__init__.py
index e6014a6..45e64f3 100644
--- a/absl/flags/__init__.py
+++ b/absl/flags/__init__.py
@@ -40,6 +40,79 @@ from absl.flags import _flagvalues
from absl.flags import _helpers
from absl.flags import _validators
+__all__ = (
+ 'DEFINE',
+ 'DEFINE_flag',
+ 'DEFINE_string',
+ 'DEFINE_boolean',
+ 'DEFINE_bool',
+ 'DEFINE_float',
+ 'DEFINE_integer',
+ 'DEFINE_enum',
+ 'DEFINE_enum_class',
+ 'DEFINE_list',
+ 'DEFINE_spaceseplist',
+ 'DEFINE_multi',
+ 'DEFINE_multi_string',
+ 'DEFINE_multi_integer',
+ 'DEFINE_multi_float',
+ 'DEFINE_multi_enum',
+ 'DEFINE_multi_enum_class',
+ 'DEFINE_alias',
+ # Flag validators.
+ 'register_validator',
+ 'validator',
+ 'register_multi_flags_validator',
+ 'multi_flags_validator',
+ 'mark_flag_as_required',
+ 'mark_flags_as_required',
+ 'mark_flags_as_mutual_exclusive',
+ 'mark_bool_flags_as_mutual_exclusive',
+ # Key flag related functions.
+ 'declare_key_flag',
+ 'adopt_module_key_flags',
+ 'disclaim_key_flags',
+ # Module exceptions.
+ 'Error',
+ 'CantOpenFlagFileError',
+ 'DuplicateFlagError',
+ 'IllegalFlagValueError',
+ 'UnrecognizedFlagError',
+ 'UnparsedFlagAccessError',
+ 'ValidationError',
+ 'FlagNameConflictsWithMethodError',
+ # Public classes.
+ 'Flag',
+ 'BooleanFlag',
+ 'EnumFlag',
+ 'EnumClassFlag',
+ 'MultiFlag',
+ 'MultiEnumClassFlag',
+ 'FlagHolder',
+ 'FlagValues',
+ 'ArgumentParser',
+ 'BooleanParser',
+ 'EnumParser',
+ 'EnumClassParser',
+ 'ArgumentSerializer',
+ 'FloatParser',
+ 'IntegerParser',
+ 'BaseListParser',
+ 'ListParser',
+ 'ListSerializer',
+ 'EnumClassListSerializer',
+ 'CsvListSerializer',
+ 'WhitespaceSeparatedListParser',
+ 'EnumClassSerializer',
+ # Helper functions.
+ 'get_help_width',
+ 'text_wrap',
+ 'flag_dict_to_args',
+ 'doc_to_help',
+ # The global FlagValues instance.
+ 'FLAGS',
+)
+
# Initialize the FLAGS_MODULE as early as possible.
# It's only used by adopt_module_key_flags to take SPECIAL_FLAGS into account.
_helpers.FLAGS_MODULE = sys.modules[__name__]
@@ -141,5 +214,5 @@ DEFINE_string('undefok', '',
'arguments MUST use the --flag=value format.',
_helpers.SPECIAL_FLAGS) # pytype: disable=wrong-arg-types
-# The global FlagValues instance.
+#: The global FlagValues instance.
FLAGS = _flagvalues.FLAGS
diff --git a/absl/flags/_argument_parser.py b/absl/flags/_argument_parser.py
index 9c6c8c6..7a94c69 100644
--- a/absl/flags/_argument_parser.py
+++ b/absl/flags/_argument_parser.py
@@ -93,9 +93,9 @@ class _ArgumentParserCache(type):
class ArgumentParser(metaclass=_ArgumentParserCache):
"""Base class used to parse and convert arguments.
- The parse() method checks to make sure that the string argument is a
+ The :meth:`parse` method checks to make sure that the string argument is a
legal value and convert it to a native type. If the value cannot be
- converted, it should throw a 'ValueError' exception with a human
+ converted, it should throw a ``ValueError`` exception with a human
readable explanation of why the value is illegal.
Subclasses should also define a syntactic_help string which may be
@@ -458,7 +458,7 @@ class ListSerializer(ArgumentSerializer):
class EnumClassListSerializer(ListSerializer):
- """A serializer for MultiEnumClass flags.
+ """A serializer for :class:`MultiEnumClass` flags.
This serializer simply joins the output of `EnumClassSerializer` using a
provided separator.
@@ -521,9 +521,9 @@ class EnumClassSerializer(ArgumentSerializer):
class BaseListParser(ArgumentParser):
"""Base class for a parser of lists of strings.
- To extend, inherit from this class; from the subclass __init__, call
+ To extend, inherit from this class; from the subclass ``__init__``, call::
- BaseListParser.__init__(self, token, name)
+ super().__init__(token, name)
where token is a character used to tokenize, and name is a description
of the separator.
diff --git a/absl/flags/_defines.py b/absl/flags/_defines.py
index a102652..12335e5 100644
--- a/absl/flags/_defines.py
+++ b/absl/flags/_defines.py
@@ -77,22 +77,22 @@ def DEFINE( # pylint: disable=invalid-name
NOTE: in the docstrings of all DEFINE* functions, "registers" is short
for "creates a new flag and registers it".
- Auxiliary function: clients should use the specialized DEFINE_<type>
+ Auxiliary function: clients should use the specialized ``DEFINE_<type>``
function instead.
Args:
- parser: ArgumentParser, used to parse the flag arguments.
+ parser: :class:`ArgumentParser`, used to parse the flag arguments.
name: str, the flag name.
default: The default value of the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
- serializer: ArgumentSerializer, the flag serializer instance.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
+ serializer: :class:`ArgumentSerializer`, the flag serializer instance.
module_name: str, the name of the Python module declaring this flag. If not
provided, it will be computed using the stack trace of this call.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: dict, the extra keyword args that are passed to Flag __init__.
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -107,19 +107,19 @@ def DEFINE_flag( # pylint: disable=invalid-name
flag_values=_flagvalues.FLAGS,
module_name=None,
required=False):
- """Registers a 'Flag' object with a 'FlagValues' object.
+ """Registers a :class:`Flag` object with a :class:`FlagValues` object.
- By default, the global FLAGS 'FlagValue' object is used.
+ By default, the global :const:`FLAGS` ``FlagValue`` object is used.
Typical users will use one of the more specialized DEFINE_xxx
- functions, such as DEFINE_string or DEFINE_integer. But developers
- who need to create Flag objects themselves should use this function
- to register their flags.
+ functions, such as :func:`DEFINE_string` or :func:`DEFINE_integer`. But
+ developers who need to create :class:`Flag` objects themselves should use
+ this function to register their flags.
Args:
- flag: Flag, a flag that is key to the module.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag: :class:`Flag`, a flag that is key to the module.
+ flag_values: :class:`FlagValues`, the ``FlagValues`` instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: str, the name of the Python module declaring this flag. If not
provided, it will be computed using the stack trace of this call.
required: bool, is this a required flag. This must be used as a keyword
@@ -159,14 +159,14 @@ def _internal_declare_key_flags(flag_names,
Args:
flag_names: [str], a list of strings that are names of already-registered
Flag objects.
- flag_values: FlagValues, the FlagValues instance with which the flags listed
- in flag_names have registered (the value of the flag_values argument from
- the DEFINE_* calls that defined those flags). This should almost never
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flags listed in flag_names have registered (the value of the flag_values
+ argument from the ``DEFINE_*`` calls that defined those flags). This
+ should almost never need to be overridden.
+ key_flag_values: :class:`FlagValues`, the FlagValues instance that (among
+ possibly many other things) keeps track of the key flags for each module.
+ Default ``None`` means "same as flag_values". This should almost never
need to be overridden.
- key_flag_values: FlagValues, the FlagValues instance that (among possibly
- many other things) keeps track of the key flags for each module. Default
- None means "same as flag_values". This should almost never need to be
- overridden.
Raises:
UnrecognizedFlagError: Raised when the flag is not defined.
@@ -189,16 +189,17 @@ def declare_key_flag(flag_name, flag_values=_flagvalues.FLAGS):
main module are listed (instead of all flags, as in the case of
--helpfull).
- Sample usage:
+ Sample usage::
- flags.declare_key_flag('flag_1')
+ flags.declare_key_flag('flag_1')
Args:
flag_name: str, the name of an already declared flag. (Redeclaring flags as
key, including flags implicitly key because they were declared in this
module, is a no-op.)
- flag_values: FlagValues, the FlagValues instance in which the flag will be
- declared as a key flag. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance in which the
+ flag will be declared as a key flag. This should almost never need to be
+ overridden.
Raises:
ValueError: Raised if flag_name not defined as a Python flag.
@@ -225,8 +226,9 @@ def adopt_module_key_flags(module, flag_values=_flagvalues.FLAGS):
Args:
module: module, the module object from which all key flags will be declared
as key flags to the current module.
- flag_values: FlagValues, the FlagValues instance in which the flags will be
- declared as key flags. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance in which the
+ flags will be declared as key flags. This should almost never need to be
+ overridden.
Raises:
Error: Raised when given an argument that is a module name (a string),
@@ -312,13 +314,13 @@ def DEFINE_boolean( # pylint: disable=invalid-name,redefined-builtin
name: str, the flag name.
default: bool|str|None, the default value of the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: str, the name of the Python module declaring this flag. If not
provided, it will be computed using the stack trace of this call.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: dict, the extra keyword args that are passed to Flag __init__.
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -339,7 +341,7 @@ def DEFINE_float( # pylint: disable=invalid-name,redefined-builtin
**args):
"""Registers a flag whose value must be a float.
- If lower_bound or upper_bound are set, then this flag must be
+ If ``lower_bound`` or ``upper_bound`` are set, then this flag must be
within the given range.
Args:
@@ -348,11 +350,11 @@ def DEFINE_float( # pylint: disable=invalid-name,redefined-builtin
help: str, the help message.
lower_bound: float, min value of the flag.
upper_bound: float, max value of the flag.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: dict, the extra keyword args that are passed to DEFINE.
+ **args: dict, the extra keyword args that are passed to :func:`DEFINE`.
Returns:
a handle to defined flag.
@@ -383,7 +385,7 @@ def DEFINE_integer( # pylint: disable=invalid-name,redefined-builtin
**args):
"""Registers a flag whose value must be an integer.
- If lower_bound, or upper_bound are set, then this flag must be
+ If ``lower_bound``, or ``upper_bound`` are set, then this flag must be
within the given range.
Args:
@@ -392,11 +394,11 @@ def DEFINE_integer( # pylint: disable=invalid-name,redefined-builtin
help: str, the help message.
lower_bound: int, min value of the flag.
upper_bound: int, max value of the flag.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: dict, the extra keyword args that are passed to DEFINE.
+ **args: dict, the extra keyword args that are passed to :func:`DEFINE`.
Returns:
a handle to defined flag.
@@ -436,13 +438,13 @@ def DEFINE_enum( # pylint: disable=invalid-name,redefined-builtin
enum_values: [str], a non-empty list of strings with the possible values for
the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: str, the name of the Python module declaring this flag. If not
provided, it will be computed using the stack trace of this call.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: dict, the extra keyword args that are passed to Flag __init__.
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -469,15 +471,15 @@ def DEFINE_enum_class( # pylint: disable=invalid-name,redefined-builtin
default: Enum|str|None, the default value of the flag.
enum_class: class, the Enum class with all the possible values for the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: str, the name of the Python module declaring this flag. If not
provided, it will be computed using the stack trace of this call.
case_sensitive: bool, whether to map strings to members of the enum_class
without considering case.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: dict, the extra keyword args that are passed to Flag __init__.
+ **args: dict, the extra keyword args that are passed to ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -507,12 +509,12 @@ def DEFINE_list( # pylint: disable=invalid-name,redefined-builtin
name: str, the flag name.
default: list|str|None, the default value of the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -549,12 +551,12 @@ def DEFINE_spaceseplist( # pylint: disable=invalid-name,redefined-builtin
comma_compat: bool - Whether to support comma as an additional separator. If
false then only whitespace is supported. This is intended only for
backwards compatibility with flags that used to be comma-separated.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -601,14 +603,14 @@ def DEFINE_multi( # pylint: disable=invalid-name,redefined-builtin
over to create a shallow copy of the values. If it is None, it is left
as-is.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: A string, the name of the Python module declaring this flag. If
not provided, it will be computed using the stack trace of this call.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -636,14 +638,14 @@ def DEFINE_multi_string( # pylint: disable=invalid-name,redefined-builtin
Args:
name: str, the flag name.
default: Union[Iterable[Text], Text, None], the default value of the flag;
- see `DEFINE_multi`.
+ see :func:`DEFINE_multi`.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -684,12 +686,12 @@ def DEFINE_multi_integer( # pylint: disable=invalid-name,redefined-builtin
help: str, the help message.
lower_bound: int, min values of the flag.
upper_bound: int, max values of the flag.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -730,12 +732,12 @@ def DEFINE_multi_float( # pylint: disable=invalid-name,redefined-builtin
help: str, the help message.
lower_bound: float, min values of the flag.
upper_bound: float, max values of the flag.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -776,13 +778,13 @@ def DEFINE_multi_enum( # pylint: disable=invalid-name,redefined-builtin
enum_values: [str], a non-empty list of strings with the possible values for
the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
case_sensitive: Whether or not the enum is to be case-sensitive.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -824,16 +826,16 @@ def DEFINE_multi_enum_class( # pylint: disable=invalid-name,redefined-builtin
within the iterable will be converted to the equivalent Enum objects.
enum_class: class, the Enum class with all the possible values for the flag.
help: str, the help message.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: A string, the name of the Python module declaring this flag. If
not provided, it will be computed using the stack trace of this call.
case_sensitive: bool, whether to map strings to members of the enum_class
without considering case.
required: bool, is this a required flag. This must be used as a keyword
argument.
- **args: Dictionary with extra keyword args that are passed to the Flag
- __init__.
+ **args: Dictionary with extra keyword args that are passed to the
+ ``Flag.__init__``.
Returns:
a handle to defined flag.
@@ -857,8 +859,8 @@ def DEFINE_alias( # pylint: disable=invalid-name
Args:
name: str, the flag name.
original_name: str, the original flag name.
- flag_values: FlagValues, the FlagValues instance with which the flag will be
- registered. This should almost never need to be overridden.
+ flag_values: :class:`FlagValues`, the FlagValues instance with which the
+ flag will be registered. This should almost never need to be overridden.
module_name: A string, the name of the module that defines this flag.
Returns:
diff --git a/absl/flags/_exceptions.py b/absl/flags/_exceptions.py
index 0ca2777..b569d94 100644
--- a/absl/flags/_exceptions.py
+++ b/absl/flags/_exceptions.py
@@ -46,13 +46,13 @@ class DuplicateFlagError(Error):
Args:
flagname: str, the name of the flag being redefined.
- flag_values: FlagValues, the FlagValues instance containing the first
- definition of flagname.
- other_flag_values: FlagValues, if it is not None, it should be the
- FlagValues object where the second definition of flagname occurs.
- If it is None, we assume that we're being called when attempting
- to create the flag a second time, and we use the module calling
- this one as the source of the second definition.
+ flag_values: :class:`FlagValues`, the FlagValues instance containing the
+ first definition of flagname.
+ other_flag_values: :class:`FlagValues`, if it is not None, it should be
+ the FlagValues object where the second definition of flagname occurs.
+ If it is None, we assume that we're being called when attempting to
+ create the flag a second time, and we use the module calling this one
+ as the source of the second definition.
Returns:
An instance of DuplicateFlagError.
@@ -97,7 +97,7 @@ class UnrecognizedFlagError(Error):
class UnparsedFlagAccessError(Error):
- """Raised when accessing the flag value from unparsed FlagValues."""
+ """Raised when accessing the flag value from unparsed :class:`FlagValues`."""
class ValidationError(Error):
@@ -105,4 +105,4 @@ class ValidationError(Error):
class FlagNameConflictsWithMethodError(Error):
- """Raised when a flag name conflicts with FlagValues methods."""
+ """Raised when a flag name conflicts with :class:`FlagValues` methods."""
diff --git a/absl/flags/_flag.py b/absl/flags/_flag.py
index d7ad944..28d9219 100644
--- a/absl/flags/_flag.py
+++ b/absl/flags/_flag.py
@@ -31,42 +31,45 @@ from absl.flags import _helpers
class Flag(object):
"""Information about a command-line flag.
- 'Flag' objects define the following fields:
- .name - the name for this flag;
- .default - the default value for this flag;
- .default_unparsed - the unparsed default value for this flag.
- .default_as_str - default value as repr'd string, e.g., "'true'" (or None);
- .value - the most recent parsed value of this flag; set by parse();
- .help - a help string or None if no help is available;
- .short_name - the single letter alias for this flag (or None);
- .boolean - if 'true', this flag does not accept arguments;
- .present - true if this flag was parsed from command line flags;
- .parser - an ArgumentParser object;
- .serializer - an ArgumentSerializer object;
- .allow_override - the flag may be redefined without raising an error, and
- newly defined flag overrides the old one.
- .allow_override_cpp - use the flag from C++ if available; the flag
- definition is replaced by the C++ flag after init;
- .allow_hide_cpp - use the Python flag despite having a C++ flag with
- the same name (ignore the C++ flag);
- .using_default_value - the flag value has not been set by user;
- .allow_overwrite - the flag may be parsed more than once without raising
- an error, the last set value will be used;
- .allow_using_method_names - whether this flag can be defined even if it has
- a name that conflicts with a FlagValues method.
-
- The only public method of a 'Flag' object is parse(), but it is
- typically only called by a 'FlagValues' object. The parse() method is
- a thin wrapper around the 'ArgumentParser' parse() method. The parsed
- value is saved in .value, and the .present attribute is updated. If
- this flag was already present, an Error is raised.
-
- parse() is also called during __init__ to parse the default value and
- initialize the .value attribute. This enables other python modules to
- safely use flags even if the __main__ module neglects to parse the
- command line arguments. The .present attribute is cleared after
- __init__ parsing. If the default value is set to None, then the
- __init__ parsing step is skipped and the .value attribute is
+ Attributes:
+ name: the name for this flag
+ default: the default value for this flag
+ default_unparsed: the unparsed default value for this flag.
+ default_as_str: default value as repr'd string, e.g., "'true'"
+ (or None)
+ value: the most recent parsed value of this flag set by :meth:`parse`
+ help: a help string or None if no help is available
+ short_name: the single letter alias for this flag (or None)
+ boolean: if 'true', this flag does not accept arguments
+ present: true if this flag was parsed from command line flags
+ parser: an :class:`~absl.flags.ArgumentParser` object
+ serializer: an ArgumentSerializer object
+ allow_override: the flag may be redefined without raising an error,
+ and newly defined flag overrides the old one.
+ allow_override_cpp: use the flag from C++ if available the flag
+ definition is replaced by the C++ flag after init
+ allow_hide_cpp: use the Python flag despite having a C++ flag with
+ the same name (ignore the C++ flag)
+ using_default_value: the flag value has not been set by user
+ allow_overwrite: the flag may be parsed more than once without
+ raising an error, the last set value will be used
+ allow_using_method_names: whether this flag can be defined even if
+ it has a name that conflicts with a FlagValues method.
+ validators: list of the flag validators.
+
+ The only public method of a ``Flag`` object is :meth:`parse`, but it is
+ typically only called by a :class:`~absl.flags.FlagValues` object. The
+ :meth:`parse` method is a thin wrapper around the
+ :meth:`ArgumentParser.parse()<absl.flags.ArgumentParser.parse>` method. The
+ parsed value is saved in ``.value``, and the ``.present`` attribute is
+ updated. If this flag was already present, an Error is raised.
+
+ :meth:`parse` is also called during ``__init__`` to parse the default value
+ and initialize the ``.value`` attribute. This enables other python modules to
+ safely use flags even if the ``__main__`` module neglects to parse the
+ command line arguments. The ``.present`` attribute is cleared after
+ ``__init__`` parsing. If the default value is set to ``None``, then the
+ ``__init__`` parsing step is skipped and the ``.value`` attribute is
initialized to None.
Note: The default value is also presented to the user in the help
@@ -307,13 +310,13 @@ class BooleanFlag(Flag):
"""Basic boolean flag.
Boolean flags do not take any arguments, and their value is either
- True (1) or False (0). The false value is specified on the command
- line by prepending the word 'no' to either the long or the short flag
+ ``True`` (1) or ``False`` (0). The false value is specified on the command
+ line by prepending the word ``'no'`` to either the long or the short flag
name.
For example, if a Boolean flag was created whose long name was
- 'update' and whose short name was 'x', then this flag could be
- explicitly unset through either --noupdate or --nox.
+ ``'update'`` and whose short name was ``'x'``, then this flag could be
+ explicitly unset through either ``--noupdate`` or ``--nox``.
"""
def __init__(self, name, default, help, short_name=None, **args): # pylint: disable=redefined-builtin
diff --git a/absl/flags/_flagvalues.py b/absl/flags/_flagvalues.py
index 1b54fb3..c52990c 100644
--- a/absl/flags/_flagvalues.py
+++ b/absl/flags/_flagvalues.py
@@ -37,36 +37,41 @@ _T = TypeVar('_T')
class FlagValues:
- """Registry of 'Flag' objects.
+ """Registry of :class:`~absl.flags.Flag` objects.
- A 'FlagValues' can then scan command line arguments, passing flag
+ A :class:`FlagValues` can then scan command line arguments, passing flag
arguments through to the 'Flag' objects that it owns. It also
provides easy access to the flag values. Typically only one
- 'FlagValues' object is needed by an application: flags.FLAGS
+ :class:`FlagValues` object is needed by an application:
+ :const:`FLAGS`.
This class is heavily overloaded:
- 'Flag' objects are registered via __setitem__:
+ :class:`Flag` objects are registered via ``__setitem__``::
+
FLAGS['longname'] = x # register a new flag
- The .value attribute of the registered 'Flag' objects can be accessed
- as attributes of this 'FlagValues' object, through __getattr__. Both
- the long and short name of the original 'Flag' objects can be used to
- access its value:
- FLAGS.longname # parsed flag value
- FLAGS.x # parsed flag value (short name)
+ The ``.value`` attribute of the registered :class:`~absl.flags.Flag` objects
+ can be accessed as attributes of this :class:`FlagValues` object, through
+ ``__getattr__``. Both the long and short name of the original
+ :class:`~absl.flags.Flag` objects can be used to access its value::
+
+ FLAGS.longname # parsed flag value
+ FLAGS.x # parsed flag value (short name)
+
+ Command line arguments are scanned and passed to the registered
+ :class:`~absl.flags.Flag` objects through the ``__call__`` method. Unparsed
+ arguments, including ``argv[0]`` (e.g. the program name) are returned::
- Command line arguments are scanned and passed to the registered 'Flag'
- objects through the __call__ method. Unparsed arguments, including
- argv[0] (e.g. the program name) are returned.
argv = FLAGS(sys.argv) # scan command line arguments
- The original registered Flag objects can be retrieved through the use
- of the dictionary-like operator, __getitem__:
+ The original registered :class:`~absl.flags.Flag` objects can be retrieved
+ through the use of the dictionary-like operator, ``__getitem__``::
+
x = FLAGS['longname'] # access the registered Flag object
- The str() operator of a 'FlagValues' object provides help for all of
- the registered 'Flag' objects.
+ The ``str()`` operator of a :class:`absl.flags.FlagValues` object provides
+ help for all of the registered :class:`~absl.flags.Flag` objects.
"""
# A note on collections.abc.Mapping:
@@ -821,7 +826,7 @@ class FlagValues:
"""Explicitly marks flags as parsed.
Use this when the caller knows that this FlagValues has been parsed as if
- a __call__() invocation has happened. This is only a public method for
+ a ``__call__()`` invocation has happened. This is only a public method for
use by things like appcommands which do additional command like parsing.
"""
self.__dict__['__flags_parsed'] = True
@@ -1133,14 +1138,15 @@ class FlagValues:
using absl.flags DEFINE_flag() type functions.
Notes (assuming we're getting a commandline of some sort as our input):
- --> For duplicate flags, the last one we hit should "win".
- --> Since flags that appear later win, a flagfile's settings can be "weak"
+
+ * For duplicate flags, the last one we hit should "win".
+ * Since flags that appear later win, a flagfile's settings can be "weak"
if the --flagfile comes at the beginning of the argument sequence,
and it can be "strong" if the --flagfile comes at the end.
- --> A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile.
+ * A further "--flagfile=<otherfile.cfg>" CAN be nested in a flagfile.
It will be expanded in exactly the spot where it is found.
- --> In a flagfile, a line beginning with # or // is a comment.
- --> Entirely blank lines _should_ be ignored.
+ * In a flagfile, a line beginning with # or // is a comment.
+ * Entirely blank lines _should_ be ignored.
"""
rest_of_args = argv
new_argv = []
@@ -1296,29 +1302,25 @@ FLAGS = FlagValues()
class FlagHolder(Generic[_T]):
"""Holds a defined flag.
- This facilitates a cleaner api around global state. Instead of
-
- ```
- flags.DEFINE_integer('foo', ...)
- flags.DEFINE_integer('bar', ...)
- ...
- def method():
- # prints parsed value of 'bar' flag
- print(flags.FLAGS.foo)
- # runtime error due to typo or possibly bad coding style.
- print(flags.FLAGS.baz)
- ```
-
- it encourages code like
-
- ```
- FOO_FLAG = flags.DEFINE_integer('foo', ...)
- BAR_FLAG = flags.DEFINE_integer('bar', ...)
- ...
- def method():
- print(FOO_FLAG.value)
- print(BAR_FLAG.value)
- ```
+ This facilitates a cleaner api around global state. Instead of::
+
+ flags.DEFINE_integer('foo', ...)
+ flags.DEFINE_integer('bar', ...)
+
+ def method():
+ # prints parsed value of 'bar' flag
+ print(flags.FLAGS.foo)
+ # runtime error due to typo or possibly bad coding style.
+ print(flags.FLAGS.baz)
+
+ it encourages code like::
+
+ _FOO_FLAG = flags.DEFINE_integer('foo', ...)
+ _BAR_FLAG = flags.DEFINE_integer('bar', ...)
+
+ def method():
+ print(_FOO_FLAG.value)
+ print(_BAR_FLAG.value)
since the name of the flag appears only once in the source code.
"""
@@ -1364,7 +1366,8 @@ class FlagHolder(Generic[_T]):
def value(self):
"""Returns the value of the flag.
- If _ensure_non_none_value is True, then return value is not None.
+ If ``_ensure_non_none_value`` is ``True``, then return value is not
+ ``None``.
Raises:
UnparsedFlagAccessError: if flag parsing has not finished.
diff --git a/absl/flags/_helpers.py b/absl/flags/_helpers.py
index 96f0a85..cb0cfb2 100644
--- a/absl/flags/_helpers.py
+++ b/absl/flags/_helpers.py
@@ -317,14 +317,18 @@ def flag_dict_to_args(flag_map, multi_flags=None):
Args:
flag_map: dict, a mapping where the keys are flag names (strings).
values are treated according to their type:
- * If value is None, then only the name is emitted.
- * If value is True, then only the name is emitted.
- * If value is False, then only the name prepended with 'no' is emitted.
- * If value is a string then --name=value is emitted.
- * If value is a collection, this will emit --name=value1,value2,value3,
- unless the flag name is in multi_flags, in which case this will emit
- --name=value1 --name=value2 --name=value3.
+
+ * If value is ``None``, then only the name is emitted.
+ * If value is ``True``, then only the name is emitted.
+ * If value is ``False``, then only the name prepended with 'no' is
+ emitted.
+ * If value is a string then ``--name=value`` is emitted.
+ * If value is a collection, this will emit
+ ``--name=value1,value2,value3``, unless the flag name is in
+ ``multi_flags``, in which case this will emit
+ ``--name=value1 --name=value2 --name=value3``.
* Everything else is converted to string an passed as such.
+
multi_flags: set, names (strings) of flags that should be treated as
multi-flags.
Yields:
diff --git a/absl/flags/_validators.py b/absl/flags/_validators.py
index 26639c5..c4e1139 100644
--- a/absl/flags/_validators.py
+++ b/absl/flags/_validators.py
@@ -14,13 +14,15 @@
"""Module to enforce different constraints on flags.
-Flags validators can be registered using following functions / decorators:
+Flags validators can be registered using following functions / decorators::
+
flags.register_validator
@flags.validator
flags.register_multi_flags_validator
@flags.multi_flags_validator
-Three convenience functions are also provided for common flag constraints:
+Three convenience functions are also provided for common flag constraints::
+
flags.mark_flag_as_required
flags.mark_flags_as_required
flags.mark_flags_as_mutual_exclusive
@@ -47,20 +49,24 @@ def register_validator(flag_name,
The constraint is validated when flags are initially parsed, and after each
change of the corresponding flag's value.
+
Args:
flag_name: str, name of the flag to be checked.
checker: callable, a function to validate the flag.
- input - A single positional argument: The value of the corresponding
- flag (string, boolean, etc. This value will be passed to checker
- by the library).
- output - bool, True if validator constraint is satisfied.
- If constraint is not satisfied, it should either return False or
- raise flags.ValidationError(desired_error_message).
+
+ * input - A single positional argument: The value of the corresponding
+ flag (string, boolean, etc. This value will be passed to checker
+ by the library).
+ * output - bool, True if validator constraint is satisfied.
+ If constraint is not satisfied, it should either ``return False`` or
+ ``raise flags.ValidationError(desired_error_message)``.
+
message: str, error text to be shown to the user if checker returns False.
If checker raises flags.ValidationError, message from the raised
error will be shown.
flag_values: flags.FlagValues, optional FlagValues instance to validate
against.
+
Raises:
AttributeError: Raised when flag_name is not registered as a valid flag
name.
@@ -73,13 +79,13 @@ def validator(flag_name, message='Flag validation failed',
flag_values=_flagvalues.FLAGS):
"""A function decorator for defining a flag validator.
- Registers the decorated function as a validator for flag_name, e.g.
+ Registers the decorated function as a validator for flag_name, e.g.::
- @flags.validator('foo')
- def _CheckFoo(foo):
- ...
+ @flags.validator('foo')
+ def _CheckFoo(foo):
+ ...
- See register_validator() for the specification of checker function.
+ See :func:`register_validator` for the specification of checker function.
Args:
flag_name: str, name of the flag to be checked.
@@ -115,11 +121,13 @@ def register_multi_flags_validator(flag_names,
Args:
flag_names: [str], a list of the flag names to be checked.
multi_flags_checker: callable, a function to validate the flag.
- input - dict, with keys() being flag_names, and value for each key
+
+ * input - dict, with keys() being flag_names, and value for each key
being the value of the corresponding flag (string, boolean, etc).
- output - bool, True if validator constraint is satisfied.
+ * output - bool, True if validator constraint is satisfied.
If constraint is not satisfied, it should either return False or
raise flags.ValidationError.
+
message: str, error text to be shown to the user if checker returns False.
If checker raises flags.ValidationError, message from the raised
error will be shown.
@@ -139,13 +147,13 @@ def multi_flags_validator(flag_names,
flag_values=_flagvalues.FLAGS):
"""A function decorator for defining a multi-flag validator.
- Registers the decorated function as a validator for flag_names, e.g.
+ Registers the decorated function as a validator for flag_names, e.g.::
- @flags.multi_flags_validator(['foo', 'bar'])
- def _CheckFooBar(flags_dict):
- ...
+ @flags.multi_flags_validator(['foo', 'bar'])
+ def _CheckFooBar(flags_dict):
+ ...
- See register_multi_flags_validator() for the specification of checker
+ See :func:`register_multi_flags_validator` for the specification of checker
function.
Args:
@@ -177,20 +185,20 @@ def mark_flag_as_required(flag_name, flag_values=_flagvalues.FLAGS):
"""Ensures that flag is not None during program execution.
Registers a flag validator, which will follow usual validator rules.
- Important note: validator will pass for any non-None value, such as False,
- 0 (zero), '' (empty string) and so on.
+ Important note: validator will pass for any non-``None`` value, such as
+ ``False``, ``0`` (zero), ``''`` (empty string) and so on.
If your module might be imported by others, and you only wish to make the flag
- required when the module is directly executed, call this method like this:
+ required when the module is directly executed, call this method like this::
- if __name__ == '__main__':
- flags.mark_flag_as_required('your_flag_name')
- app.run()
+ if __name__ == '__main__':
+ flags.mark_flag_as_required('your_flag_name')
+ app.run()
Args:
flag_name: str, name of the flag
- flag_values: flags.FlagValues, optional FlagValues instance where the flag
- is defined.
+ flag_values: flags.FlagValues, optional :class:`~absl.flags.FlagValues`
+ instance where the flag is defined.
Raises:
AttributeError: Raised when flag_name is not registered as a valid flag
name.
@@ -212,11 +220,11 @@ def mark_flags_as_required(flag_names, flag_values=_flagvalues.FLAGS):
"""Ensures that flags are not None during program execution.
If your module might be imported by others, and you only wish to make the flag
- required when the module is directly executed, call this method like this:
+ required when the module is directly executed, call this method like this::
- if __name__ == '__main__':
- flags.mark_flags_as_required(['flag1', 'flag2', 'flag3'])
- app.run()
+ if __name__ == '__main__':
+ flags.mark_flags_as_required(['flag1', 'flag2', 'flag3'])
+ app.run()
Args:
flag_names: Sequence[str], names of the flags.
@@ -233,11 +241,11 @@ def mark_flags_as_mutual_exclusive(flag_names, required=False,
flag_values=_flagvalues.FLAGS):
"""Ensures that only one flag among flag_names is not None.
- Important note: This validator checks if flag values are None, and it does not
- distinguish between default and explicit values. Therefore, this validator
+ Important note: This validator checks if flag values are ``None``, and it does
+ not distinguish between default and explicit values. Therefore, this validator
does not make sense when applied to flags with default values other than None,
- including other false values (e.g. False, 0, '', []). That includes multi
- flags with a default value of [] instead of None.
+ including other false values (e.g. ``False``, ``0``, ``''``, ``[]``). That
+ includes multi flags with a default value of ``[]`` instead of None.
Args:
flag_names: [str], names of the flags.
diff --git a/absl/flags/argparse_flags.py b/absl/flags/argparse_flags.py
index 69e4c8a..dd8b505 100644
--- a/absl/flags/argparse_flags.py
+++ b/absl/flags/argparse_flags.py
@@ -14,11 +14,11 @@
"""This module provides argparse integration with absl.flags.
-argparse_flags.ArgumentParser is a drop-in replacement for
-argparse.ArgumentParser. It takes care of collecting and defining absl flags
-in argparse.
+``argparse_flags.ArgumentParser`` is a drop-in replacement for
+:class:`argparse.ArgumentParser`. It takes care of collecting and defining absl
+flags in :mod:`argparse`.
-Here is a simple example:
+Here is a simple example::
# Assume the following absl.flags is defined in another module:
#
@@ -40,7 +40,7 @@ Here is a simple example:
# ./program --header 'A header' --echo 'A message.'
-Here is another example demonstrates subparsers:
+Here is another example demonstrates subparsers::
parser = argparse_flags.ArgumentParser(description='A subcommands demo.')
parser.add_argument('--header', help='The header message to print.')
@@ -69,23 +69,25 @@ Here is another example demonstrates subparsers:
# ./program shuffle --echo='A message.' 1 2 3 4
-There are several differences between absl.flags and argparse_flags:
+There are several differences between :mod:`absl.flags` and
+:mod:`~absl.flags.argparse_flags`:
1. Flags defined with absl.flags are parsed differently when using the
argparse parser. Notably:
1) absl.flags allows both single-dash and double-dash for any flag, and
doesn't distinguish them; argparse_flags only allows double-dash for
- flag's regular name, and single-dash for flag's `short_name`.
- 2) Boolean flags in absl.flags can be specified with `--bool`, `--nobool`,
- as well as `--bool=true/false` (though not recommended);
- in argparse_flags, it only allows `--bool`, `--nobool`.
+ flag's regular name, and single-dash for flag's ``short_name``.
+ 2) Boolean flags in absl.flags can be specified with ``--bool``,
+ ``--nobool``, as well as ``--bool=true/false`` (though not recommended);
+ in argparse_flags, it only allows ``--bool``, ``--nobool``.
2. Help related flag differences:
+
1) absl.flags does not define help flags, absl.app does that; argparse_flags
- defines help flags unless passed with `add_help=False`.
- 2) absl.app supports `--helpxml`; argparse_flags does not.
- 3) argparse_flags supports `-h`; absl.app does not.
+ defines help flags unless passed with ``add_help=False``.
+ 2) absl.app supports ``--helpxml``; argparse_flags does not.
+ 3) argparse_flags supports ``-h``; absl.app does not.
"""
import argparse
diff --git a/absl/logging/__init__.py b/absl/logging/__init__.py
index 8804490..c0ba4b0 100644
--- a/absl/logging/__init__.py
+++ b/absl/logging/__init__.py
@@ -14,7 +14,7 @@
"""Abseil Python logging module implemented on top of standard logging.
-Simple usage:
+Simple usage::
from absl import logging
@@ -34,29 +34,34 @@ Usage note: Do not pre-format the strings in your program code.
Instead, let the logging module perform argument interpolation.
This saves cycles because strings that don't need to be printed
are never formatted. Note that this module does not attempt to
-interpolate arguments when no arguments are given. In other words
+interpolate arguments when no arguments are given. In other words::
logging.info('Interesting Stuff: %s')
does not raise an exception because logging.info() has only one
argument, the message string.
-"Lazy" evaluation for debugging:
+"Lazy" evaluation for debugging
+-------------------------------
+
+If you do something like this::
-If you do something like this:
logging.debug('Thing: %s', thing.ExpensiveOp())
+
then the ExpensiveOp will be evaluated even if nothing
-is printed to the log. To avoid this, use the level_debug() function:
+is printed to the log. To avoid this, use the level_debug() function::
+
if logging.level_debug():
logging.debug('Thing: %s', thing.ExpensiveOp())
Per file level logging is supported by logging.vlog() and
-logging.vlog_is_on(). For example:
+logging.vlog_is_on(). For example::
if logging.vlog_is_on(2):
logging.vlog(2, very_expensive_debug_message())
-Notes on Unicode:
+Notes on Unicode
+----------------
The log output is encoded as UTF-8. Don't pass data in other encodings in
bytes() instances -- instead pass unicode string instances when you need to
@@ -407,9 +412,9 @@ def debug(msg, *args, **kwargs):
log(DEBUG, msg, *args, **kwargs)
-def exception(msg, *args):
+def exception(msg, *args, **kwargs):
"""Logs an exception, with traceback and message."""
- error(msg, *args, exc_info=True)
+ error(msg, *args, **kwargs, exc_info=True)
# Counter to keep track of number of log entries per token.
@@ -432,7 +437,7 @@ def _get_next_log_count_per_token(token):
def log_every_n(level, msg, n, *args):
- """Logs 'msg % args' at level 'level' once per 'n' times.
+ """Logs ``msg % args`` at level 'level' once per 'n' times.
Logs the 1st call, (N+1)st call, (2N+1)st call, etc.
Not threadsafe.
@@ -479,7 +484,7 @@ def _seconds_have_elapsed(token, num_seconds):
def log_every_n_seconds(level, msg, n_seconds, *args):
- """Logs 'msg % args' at level 'level' iff 'n_seconds' elapsed since last call.
+ """Logs ``msg % args`` at level ``level`` iff ``n_seconds`` elapsed since last call.
Logs the first call, logs subsequent calls if 'n' seconds have elapsed since
the last logging call from the same call site (file + line). Not thread-safe.
@@ -495,7 +500,7 @@ def log_every_n_seconds(level, msg, n_seconds, *args):
def log_first_n(level, msg, n, *args):
- """Logs 'msg % args' at level 'level' only first 'n' times.
+ """Logs ``msg % args`` at level ``level`` only first ``n`` times.
Not threadsafe.
@@ -510,13 +515,13 @@ def log_first_n(level, msg, n, *args):
def log_if(level, msg, condition, *args):
- """Logs 'msg % args' at level 'level' only if condition is fulfilled."""
+ """Logs ``msg % args`` at level ``level`` only if condition is fulfilled."""
if condition:
log(level, msg, *args)
def log(level, msg, *args, **kwargs):
- """Logs 'msg % args' at absl logging level 'level'.
+ """Logs ``msg % args`` at absl logging level ``level``.
If no args are given just print msg, ignoring any interpolation specifiers.
@@ -550,7 +555,7 @@ def log(level, msg, *args, **kwargs):
def vlog(level, msg, *args, **kwargs):
- """Log 'msg % args' at C++ vlog level 'level'.
+ """Log ``msg % args`` at C++ vlog level ``level``.
Args:
level: int, the C++ verbose logging level at which to log the message,
@@ -645,13 +650,13 @@ def find_log_dir_and_names(program_name=None, log_dir=None):
Args:
program_name: str|None, the filename part of the path to the program that
is running without its extension. e.g: if your program is called
- 'usr/bin/foobar.py' this method should probably be called with
- program_name='foobar' However, this is just a convention, you can
+ ``usr/bin/foobar.py`` this method should probably be called with
+ ``program_name='foobar`` However, this is just a convention, you can
pass in any string you want, and it will be used as part of the
log filename. If you don't pass in anything, the default behavior
is as described in the example. In python standard logging mode,
- the program_name will be prepended with py_ if it is the program_name
- argument is omitted.
+ the program_name will be prepended with ``py_`` if it is the
+ ``program_name`` argument is omitted.
log_dir: str|None, the desired log directory.
Returns:
@@ -753,10 +758,10 @@ def get_absl_log_prefix(record):
def skip_log_prefix(func):
- """Skips reporting the prefix of a given function or name by ABSLLogger.
+ """Skips reporting the prefix of a given function or name by :class:`~absl.logging.ABSLLogger`.
This is a convenience wrapper function / decorator for
- `ABSLLogger.register_frame_to_skip`.
+ :meth:`~absl.logging.ABSLLogger.register_frame_to_skip`.
If a callable function is provided, only that function will be skipped.
If a function name is provided, all functions with the same name in the
@@ -880,13 +885,13 @@ class PythonHandler(logging.StreamHandler):
def emit(self, record):
"""Prints a record out to some streams.
- If FLAGS.logtostderr is set, it will print to sys.stderr ONLY.
- If FLAGS.alsologtostderr is set, it will print to sys.stderr.
- If FLAGS.logtostderr is not set, it will log to the stream
- associated with the current thread.
+ 1. If ``FLAGS.logtostderr`` is set, it will print to ``sys.stderr`` ONLY.
+ 2. If ``FLAGS.alsologtostderr`` is set, it will print to ``sys.stderr``.
+ 3. If ``FLAGS.logtostderr`` is not set, it will log to the stream
+ associated with the current thread.
Args:
- record: logging.LogRecord, the record to emit.
+ record: :class:`logging.LogRecord`, the record to emit.
"""
# People occasionally call logging functions at import time before
# our flags may have even been defined yet, let alone even parsed, as we
@@ -987,7 +992,7 @@ class ABSLHandler(logging.Handler):
class PythonFormatter(logging.Formatter):
- """Formatter class used by PythonHandler."""
+ """Formatter class used by :class:`~absl.logging.PythonHandler`."""
def format(self, record):
"""Appends the message from the record to the results of the prefix.
@@ -1065,33 +1070,33 @@ class ABSLLogger(logging.getLoggerClass()):
frame = frame.f_back
def critical(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'CRITICAL'."""
+ """Logs ``msg % args`` with severity ``CRITICAL``."""
self.log(logging.CRITICAL, msg, *args, **kwargs)
def fatal(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'FATAL'."""
+ """Logs ``msg % args`` with severity ``FATAL``."""
self.log(logging.FATAL, msg, *args, **kwargs)
def error(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'ERROR'."""
+ """Logs ``msg % args`` with severity ``ERROR``."""
self.log(logging.ERROR, msg, *args, **kwargs)
def warn(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'WARN'."""
+ """Logs ``msg % args`` with severity ``WARN``."""
warnings.warn("The 'warn' method is deprecated, use 'warning' instead",
DeprecationWarning, 2)
self.log(logging.WARN, msg, *args, **kwargs)
def warning(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'WARNING'."""
+ """Logs ``msg % args`` with severity ``WARNING``."""
self.log(logging.WARNING, msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'INFO'."""
+ """Logs ``msg % args`` with severity ``INFO``."""
self.log(logging.INFO, msg, *args, **kwargs)
def debug(self, msg, *args, **kwargs):
- """Logs 'msg % args' with severity 'DEBUG'."""
+ """Logs ``msg % args`` with severity ``DEBUG``."""
self.log(logging.DEBUG, msg, *args, **kwargs)
def log(self, level, msg, *args, **kwargs):
@@ -1114,12 +1119,12 @@ class ABSLLogger(logging.getLoggerClass()):
super(ABSLLogger, self).log(level, msg, *args, **kwargs)
def handle(self, record):
- """Calls handlers without checking Logger.disabled.
+ """Calls handlers without checking ``Logger.disabled``.
- Non-root loggers are set to disabled after setup with logging.config if
- it's not explicitly specified. Historically, absl logging will not be
+ Non-root loggers are set to disabled after setup with :func:`logging.config`
+ if it's not explicitly specified. Historically, absl logging will not be
disabled by that. To maintaining this behavior, this function skips
- checking the Logger.disabled bit.
+ checking the ``Logger.disabled`` bit.
This logger can still be disabled by adding a filter that filters out
everything.
@@ -1134,8 +1139,8 @@ class ABSLLogger(logging.getLoggerClass()):
def register_frame_to_skip(cls, file_name, function_name, line_number=None):
"""Registers a function name to skip when walking the stack.
- The ABSLLogger sometimes skips method calls on the stack
- to make the log messages meaningful in their appropriate context.
+ The :class:`~absl.logging.ABSLLogger` sometimes skips method calls on the
+ stack to make the log messages meaningful in their appropriate context.
This method registers a function from a particular file as one
which should be skipped.
@@ -1193,7 +1198,8 @@ _attempted_to_remove_stderr_stream_handlers = False
def use_absl_handler():
"""Uses the ABSL logging handler for logging.
- This method is called in app.run() so the absl handler is used in absl apps.
+ This method is called in :func:`app.run()<absl.app.run>` so the absl handler
+ is used in absl apps.
"""
global _attempted_to_remove_stderr_stream_handlers
if not _attempted_to_remove_stderr_stream_handlers:
diff --git a/absl/logging/converter.py b/absl/logging/converter.py
index 53dd46d..0239ab4 100644
--- a/absl/logging/converter.py
+++ b/absl/logging/converter.py
@@ -16,25 +16,26 @@
This converter has to convert (best effort) between three different
logging level schemes:
- cpp = The C++ logging level scheme used in Abseil C++.
- absl = The absl.logging level scheme used in Abseil Python.
- standard = The python standard library logging level scheme.
-
-Here is a handy ascii chart for easy mental mapping.
-
- LEVEL | cpp | absl | standard |
- ---------+-----+--------+----------+
- DEBUG | 0 | 1 | 10 |
- INFO | 0 | 0 | 20 |
- WARNING | 1 | -1 | 30 |
- ERROR | 2 | -2 | 40 |
- CRITICAL | 3 | -3 | 50 |
- FATAL | 3 | -3 | 50 |
-
-Note: standard logging CRITICAL is mapped to absl/cpp FATAL.
-However, only CRITICAL logs from the absl logger (or absl.logging.fatal) will
-terminate the program. CRITICAL logs from non-absl loggers are treated as
-error logs with a message prefix "CRITICAL - ".
+
+ * **cpp**: The C++ logging level scheme used in Abseil C++.
+ * **absl**: The absl.logging level scheme used in Abseil Python.
+ * **standard**: The python standard library logging level scheme.
+
+Here is a handy ascii chart for easy mental mapping::
+
+ LEVEL | cpp | absl | standard |
+ ---------+-----+--------+----------+
+ DEBUG | 0 | 1 | 10 |
+ INFO | 0 | 0 | 20 |
+ WARNING | 1 | -1 | 30 |
+ ERROR | 2 | -2 | 40 |
+ CRITICAL | 3 | -3 | 50 |
+ FATAL | 3 | -3 | 50 |
+
+Note: standard logging ``CRITICAL`` is mapped to absl/cpp ``FATAL``.
+However, only ``CRITICAL`` logs from the absl logger (or absl.logging.fatal)
+will terminate the program. ``CRITICAL`` logs from non-absl loggers are treated
+as error logs with a message prefix ``"CRITICAL - "``.
Converting from standard to absl or cpp is a lossy conversion.
Converting back to standard will lose granularity. For this reason,
@@ -89,10 +90,11 @@ def get_initial_for_level(level):
"""Gets the initial that should start the log line for the given level.
It returns:
- - 'I' when: level < STANDARD_WARNING.
- - 'W' when: STANDARD_WARNING <= level < STANDARD_ERROR.
- - 'E' when: STANDARD_ERROR <= level < STANDARD_CRITICAL.
- - 'F' when: level >= STANDARD_CRITICAL.
+
+ * ``'I'`` when: ``level < STANDARD_WARNING``.
+ * ``'W'`` when: ``STANDARD_WARNING <= level < STANDARD_ERROR``.
+ * ``'E'`` when: ``STANDARD_ERROR <= level < STANDARD_CRITICAL``.
+ * ``'F'`` when: ``level >= STANDARD_CRITICAL``.
Args:
level: int, a Python standard logging level.
@@ -157,7 +159,8 @@ def string_to_standard(level):
"""Converts a string level to standard logging level value.
Args:
- level: str, case-insensitive 'debug', 'info', 'warning', 'error', 'fatal'.
+ level: str, case-insensitive ``'debug'``, ``'info'``, ``'warning'``,
+ ``'error'``, ``'fatal'``.
Returns:
The corresponding integer level for use in standard logging.
diff --git a/absl/testing/absltest.py b/absl/testing/absltest.py
index b7a941b..d1b0e59 100644
--- a/absl/testing/absltest.py
+++ b/absl/testing/absltest.py
@@ -103,10 +103,11 @@ __unittest = True # pylint: disable=invalid-name
def expectedFailureIf(condition, reason): # pylint: disable=invalid-name
"""Expects the test to fail if the run condition is True.
- Example usage:
- @expectedFailureIf(sys.version.major == 2, "Not yet working in py2")
- def test_foo(self):
- ...
+ Example usage::
+
+ @expectedFailureIf(sys.version.major == 2, "Not yet working in py2")
+ def test_foo(self):
+ ...
Args:
condition: bool, whether to expect failure or not.
@@ -623,7 +624,7 @@ class TestCase(unittest.TestCase):
This creates a named directory on disk that is isolated to this test, and
will be properly cleaned up by the test. This avoids several pitfalls of
creating temporary directories for test purposes, as well as makes it easier
- to setup directories and verify their contents. For example:
+ to setup directories and verify their contents. For example::
def test_foo(self):
out_dir = self.create_tempdir()
@@ -637,14 +638,14 @@ class TestCase(unittest.TestCase):
self.assertTrue(os.path.exists(expected_paths[1]))
self.assertEqual('foo', out_log.read_text())
- See also: `create_tempfile()` for creating temporary files.
+ See also: :meth:`create_tempdir` for creating temporary files.
Args:
name: Optional name of the directory. If not given, a unique
name will be generated and used.
cleanup: Optional cleanup policy on when/if to remove the directory (and
all its contents) at the end of the test. If None, then uses
- `self.tempfile_cleanup`.
+ :attr:`tempfile_cleanup`.
Returns:
A _TempDir representing the created directory; see _TempDir class docs
@@ -678,7 +679,7 @@ class TestCase(unittest.TestCase):
be properly cleaned up by the test. This avoids several pitfalls of
creating temporary files for test purposes, as well as makes it easier
to setup files, their data, read them back, and inspect them when
- a test fails. For example:
+ a test fails. For example::
def test_foo(self):
output = self.create_tempfile()
@@ -690,15 +691,15 @@ class TestCase(unittest.TestCase):
state.
NOTE: If the file already exists, it will be made writable and overwritten.
- See also: `create_tempdir()` for creating temporary directories, and
- `_TempDir.create_file` for creating files within a temporary directory.
+ See also: :meth:`create_tempdir` for creating temporary directories, and
+ ``_TempDir.create_file`` for creating files within a temporary directory.
Args:
file_path: Optional file path for the temp file. If not given, a unique
file name will be generated and used. Slashes are allowed in the name;
any missing intermediate directories will be created. NOTE: This path is
the path that will be cleaned up, including any directories in the path,
- e.g., 'foo/bar/baz.txt' will `rm -r foo`.
+ e.g., ``'foo/bar/baz.txt'`` will ``rm -r foo``.
content: Optional string or
bytes to initially write to the file. If not
specified, then an empty file is created.
@@ -710,7 +711,7 @@ class TestCase(unittest.TestCase):
`content` is text.
cleanup: Optional cleanup policy on when/if to remove the directory (and
all its contents) at the end of the test. If None, then uses
- `self.tempfile_cleanup`.
+ :attr:`tempfile_cleanup`.
Returns:
A _TempFile representing the created file; see _TempFile class docs for
@@ -1075,10 +1076,10 @@ class TestCase(unittest.TestCase):
"""Asserts that two sequences have the same elements (in any order).
This method, unlike assertCountEqual, doesn't care about any
- duplicates in the expected and actual sequences.
+ duplicates in the expected and actual sequences::
- >> assertSameElements([1, 1, 1, 0, 0, 0], [0, 1])
- # Doesn't raise an AssertionError
+ # Doesn't raise an AssertionError
+ assertSameElements([1, 1, 1, 0, 0, 0], [0, 1])
If possible, you should use assertCountEqual instead of
assertSameElements.
@@ -1174,6 +1175,7 @@ class TestCase(unittest.TestCase):
expression (a string or re compiled object) instead of a list.
Notes:
+
1. This function uses substring matching, i.e. the matching
succeeds if *any* substring of the error message matches *any*
regex in the list. This is more convenient for the user than
@@ -1334,6 +1336,8 @@ class TestCase(unittest.TestCase):
if not issubclass(exc_type, self.expected_exception):
return False
self.test_func(exc_value)
+ if exc_value:
+ self.exception = exc_value.with_traceback(None)
return True
@typing.overload
@@ -1523,39 +1527,39 @@ class TestCase(unittest.TestCase):
"""Asserts that total ordering has been implemented correctly.
For example, say you have a class A that compares only on its attribute x.
- Comparators other than __lt__ are omitted for brevity.
+ Comparators other than ``__lt__`` are omitted for brevity::
- class A(object):
- def __init__(self, x, y):
- self.x = x
- self.y = y
+ class A(object):
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
- def __hash__(self):
- return hash(self.x)
+ def __hash__(self):
+ return hash(self.x)
- def __lt__(self, other):
- try:
- return self.x < other.x
- except AttributeError:
- return NotImplemented
+ def __lt__(self, other):
+ try:
+ return self.x < other.x
+ except AttributeError:
+ return NotImplemented
assertTotallyOrdered will check that instances can be ordered correctly.
- For example,
+ For example::
- self.assertTotallyOrdered(
- [None], # None should come before everything else.
- [1], # Integers sort earlier.
- [A(1, 'a')],
- [A(2, 'b')], # 2 is after 1.
- [A(3, 'c'), A(3, 'd')], # The second argument is irrelevant.
- [A(4, 'z')],
- ['foo']) # Strings sort last.
+ self.assertTotallyOrdered(
+ [None], # None should come before everything else.
+ [1], # Integers sort earlier.
+ [A(1, 'a')],
+ [A(2, 'b')], # 2 is after 1.
+ [A(3, 'c'), A(3, 'd')], # The second argument is irrelevant.
+ [A(4, 'z')],
+ ['foo']) # Strings sort last.
Args:
- *groups: A list of groups of elements. Each group of elements is a list
- of objects that are equal. The elements in each group must be less
- than the elements in the group after it. For example, these groups are
- totally ordered: [None], [1], [2, 2], [3].
+ *groups: A list of groups of elements. Each group of elements is a list
+ of objects that are equal. The elements in each group must be less
+ than the elements in the group after it. For example, these groups are
+ totally ordered: ``[None]``, ``[1]``, ``[2, 2]``, ``[3]``.
**kwargs: optional msg keyword argument can be passed.
"""
@@ -2040,12 +2044,14 @@ def main(*args, **kwargs):
Usually this function is called without arguments, so the
unittest.TestProgram instance will get created with the default settings,
- so it will run all test methods of all TestCase classes in the __main__
+ so it will run all test methods of all TestCase classes in the ``__main__``
module.
Args:
- *args: Positional arguments passed through to unittest.TestProgram.__init__.
- **kwargs: Keyword arguments passed through to unittest.TestProgram.__init__.
+ *args: Positional arguments passed through to
+ ``unittest.TestProgram.__init__``.
+ **kwargs: Keyword arguments passed through to
+ ``unittest.TestProgram.__init__``.
"""
print_python_version()
_run_in_app(run_tests, args, kwargs)
@@ -2178,29 +2184,29 @@ def skipThisClass(reason):
implementations between a number of concrete testcase classes.
Example usage, showing how you can share some common test methods between
- subclasses. In this example, only 'BaseTest' will be marked as skipped, and
- not RealTest or SecondRealTest:
+ subclasses. In this example, only ``BaseTest`` will be marked as skipped, and
+ not RealTest or SecondRealTest::
- @absltest.skipThisClass("Shared functionality")
- class BaseTest(absltest.TestCase):
- def test_simple_functionality(self):
- self.assertEqual(self.system_under_test.method(), 1)
+ @absltest.skipThisClass("Shared functionality")
+ class BaseTest(absltest.TestCase):
+ def test_simple_functionality(self):
+ self.assertEqual(self.system_under_test.method(), 1)
- class RealTest(BaseTest):
- def setUp(self):
- super().setUp()
- self.system_under_test = MakeSystem(argument)
+ class RealTest(BaseTest):
+ def setUp(self):
+ super().setUp()
+ self.system_under_test = MakeSystem(argument)
- def test_specific_behavior(self):
- ...
+ def test_specific_behavior(self):
+ ...
- class SecondRealTest(BaseTest):
- def setUp(self):
- super().setUp()
- self.system_under_test = MakeSystem(other_arguments)
+ class SecondRealTest(BaseTest):
+ def setUp(self):
+ super().setUp()
+ self.system_under_test = MakeSystem(other_arguments)
- def test_other_behavior(self):
- ...
+ def test_other_behavior(self):
+ ...
Args:
reason: The reason we have a skip in place. For instance: 'shared test
@@ -2540,11 +2546,14 @@ def run_tests(argv, args, kwargs): # pylint: disable=line-too-long
Args:
argv: sys.argv with the command-line flags removed from the front, i.e. the
- argv with which app.run() has called __main__.main. It is passed to
- unittest.TestProgram.__init__(argv=), which does its own flag parsing. It
- is ignored if kwargs contains an argv entry.
- args: Positional arguments passed through to unittest.TestProgram.__init__.
- kwargs: Keyword arguments passed through to unittest.TestProgram.__init__.
+ argv with which :func:`app.run()<absl.app.run>` has called
+ ``__main__.main``. It is passed to
+ ``unittest.TestProgram.__init__(argv=)``, which does its own flag parsing.
+ It is ignored if kwargs contains an argv entry.
+ args: Positional arguments passed through to
+ ``unittest.TestProgram.__init__``.
+ kwargs: Keyword arguments passed through to
+ ``unittest.TestProgram.__init__``.
"""
result = _run_and_get_tests_result(
argv, args, kwargs, xml_reporter.TextAndXMLTestRunner)
diff --git a/absl/testing/flagsaver.py b/absl/testing/flagsaver.py
index f87dbb1..37926d7 100644
--- a/absl/testing/flagsaver.py
+++ b/absl/testing/flagsaver.py
@@ -17,40 +17,40 @@
There are many ways to save and restore. Always use the most convenient method
for a given use case.
-Here are examples of each method. They all call do_stuff() while FLAGS.someflag
-is temporarily set to 'foo'.
-
- from absl.testing import flagsaver
-
- # Use a decorator which can optionally override flags via arguments.
- @flagsaver.flagsaver(someflag='foo')
- def some_func():
- do_stuff()
-
- # Use a decorator which can optionally override flags with flagholders.
- @flagsaver.flagsaver((module.FOO_FLAG, 'foo'), (other_mod.BAR_FLAG, 23))
- def some_func():
- do_stuff()
-
- # Use a decorator which does not override flags itself.
- @flagsaver.flagsaver
- def some_func():
- FLAGS.someflag = 'foo'
- do_stuff()
-
- # Use a context manager which can optionally override flags via arguments.
- with flagsaver.flagsaver(someflag='foo'):
- do_stuff()
-
- # Save and restore the flag values yourself.
- saved_flag_values = flagsaver.save_flag_values()
- try:
- FLAGS.someflag = 'foo'
- do_stuff()
- finally:
- flagsaver.restore_flag_values(saved_flag_values)
-
-We save and restore a shallow copy of each Flag object's __dict__ attribute.
+Here are examples of each method. They all call ``do_stuff()`` while
+``FLAGS.someflag`` is temporarily set to ``'foo'``::
+
+ from absl.testing import flagsaver
+
+ # Use a decorator which can optionally override flags via arguments.
+ @flagsaver.flagsaver(someflag='foo')
+ def some_func():
+ do_stuff()
+
+ # Use a decorator which can optionally override flags with flagholders.
+ @flagsaver.flagsaver((module.FOO_FLAG, 'foo'), (other_mod.BAR_FLAG, 23))
+ def some_func():
+ do_stuff()
+
+ # Use a decorator which does not override flags itself.
+ @flagsaver.flagsaver
+ def some_func():
+ FLAGS.someflag = 'foo'
+ do_stuff()
+
+ # Use a context manager which can optionally override flags via arguments.
+ with flagsaver.flagsaver(someflag='foo'):
+ do_stuff()
+
+ # Save and restore the flag values yourself.
+ saved_flag_values = flagsaver.save_flag_values()
+ try:
+ FLAGS.someflag = 'foo'
+ do_stuff()
+ finally:
+ flagsaver.restore_flag_values(saved_flag_values)
+
+We save and restore a shallow copy of each Flag object's ``__dict__`` attribute.
This preserves all attributes of the flag, such as whether or not it was
overridden from its default value.
@@ -102,7 +102,7 @@ def save_flag_values(flag_values=FLAGS):
be saved. This should almost never need to be overridden.
Returns:
Dictionary mapping keys to values. Keys are flag names, values are
- corresponding __dict__ members. E.g. {'key': value_dict, ...}.
+ corresponding ``__dict__`` members. E.g. ``{'key': value_dict, ...}``.
"""
return {name: _copy_flag_dict(flag_values[name]) for name in flag_values}
@@ -177,16 +177,16 @@ class _FlagOverrider(object):
def _copy_flag_dict(flag):
- """Returns a copy of the flag object's __dict__.
+ """Returns a copy of the flag object's ``__dict__``.
- It's mostly a shallow copy of the __dict__, except it also does a shallow
+ It's mostly a shallow copy of the ``__dict__``, except it also does a shallow
copy of the validator list.
Args:
flag: flags.Flag, the flag to copy.
Returns:
- A copy of the flag object's __dict__.
+ A copy of the flag object's ``__dict__``.
"""
copy = flag.__dict__.copy()
copy['_value'] = flag.value # Ensure correct restore for C++ flags.
diff --git a/absl/testing/parameterized.py b/absl/testing/parameterized.py
index ec6a529..650d6cf 100644
--- a/absl/testing/parameterized.py
+++ b/absl/testing/parameterized.py
@@ -17,16 +17,15 @@
A parameterized test is a method in a test case that is invoked with different
argument tuples.
-A simple example:
-
- class AdditionExample(parameterized.TestCase):
- @parameterized.parameters(
- (1, 2, 3),
- (4, 5, 9),
- (1, 1, 3))
- def testAddition(self, op1, op2, result):
- self.assertEqual(result, op1 + op2)
+A simple example::
+ class AdditionExample(parameterized.TestCase):
+ @parameterized.parameters(
+ (1, 2, 3),
+ (4, 5, 9),
+ (1, 1, 3))
+ def testAddition(self, op1, op2, result):
+ self.assertEqual(result, op1 + op2)
Each invocation is a separate test case and properly isolated just
like a normal test method, with its own setUp/tearDown cycle. In the
@@ -34,15 +33,15 @@ example above, there are three separate testcases, one of which will
fail due to an assertion error (1 + 1 != 3).
Parameters for individual test cases can be tuples (with positional parameters)
-or dictionaries (with named parameters):
+or dictionaries (with named parameters)::
- class AdditionExample(parameterized.TestCase):
- @parameterized.parameters(
- {'op1': 1, 'op2': 2, 'result': 3},
- {'op1': 4, 'op2': 5, 'result': 9},
- )
- def testAddition(self, op1, op2, result):
- self.assertEqual(result, op1 + op2)
+ class AdditionExample(parameterized.TestCase):
+ @parameterized.parameters(
+ {'op1': 1, 'op2': 2, 'result': 3},
+ {'op1': 4, 'op2': 5, 'result': 9},
+ )
+ def testAddition(self, op1, op2, result):
+ self.assertEqual(result, op1 + op2)
If a parameterized test fails, the error message will show the
original test name and the parameters for that test.
@@ -50,129 +49,135 @@ original test name and the parameters for that test.
The id method of the test, used internally by the unittest framework, is also
modified to show the arguments (but note that the name reported by `id()`
doesn't match the actual test name, see below). To make sure that test names
-stay the same across several invocations, object representations like
+stay the same across several invocations, object representations like::
- >>> class Foo(object):
- ... pass
- >>> repr(Foo())
- '<__main__.Foo object at 0x23d8610>'
+ >>> class Foo(object):
+ ... pass
+ >>> repr(Foo())
+ '<__main__.Foo object at 0x23d8610>'
-are turned into '<__main__.Foo>'. When selecting a subset of test cases to run
+are turned into ``__main__.Foo``. When selecting a subset of test cases to run
on the command-line, the test cases contain an index suffix for each argument
-in the order they were passed to `parameters()` (eg. testAddition0,
+in the order they were passed to :func:`parameters` (eg. testAddition0,
testAddition1, etc.) This naming scheme is subject to change; for more reliable
-and stable names, especially in test logs, use `named_parameters()` instead.
+and stable names, especially in test logs, use :func:`named_parameters` instead.
-Tests using `named_parameters()` are similar to `parameters()`, except only
-tuples or dicts of args are supported. For tuples, the first parameter arg
+Tests using :func:`named_parameters` are similar to :func:`parameters`, except
+only tuples or dicts of args are supported. For tuples, the first parameter arg
has to be a string (or an object that returns an apt name when converted via
-str()). For dicts, a value for the key 'testcase_name' must be present and must
-be a string (or an object that returns an apt name when converted via str()):
-
- class NamedExample(parameterized.TestCase):
- @parameterized.named_parameters(
- ('Normal', 'aa', 'aaa', True),
- ('EmptyPrefix', '', 'abc', True),
- ('BothEmpty', '', '', True))
- def testStartsWith(self, prefix, string, result):
- self.assertEqual(result, string.startswith(prefix))
-
- class NamedExample(parameterized.TestCase):
- @parameterized.named_parameters(
- {'testcase_name': 'Normal',
- 'result': True, 'string': 'aaa', 'prefix': 'aa'},
- {'testcase_name': 'EmptyPrefix',
- 'result': True, 'string': 'abc', 'prefix': ''},
- {'testcase_name': 'BothEmpty',
- 'result': True, 'string': '', 'prefix': ''})
- def testStartsWith(self, prefix, string, result):
- self.assertEqual(result, string.startswith(prefix))
+``str()``). For dicts, a value for the key ``testcase_name`` must be present and
+must be a string (or an object that returns an apt name when converted via
+``str()``)::
+
+ class NamedExample(parameterized.TestCase):
+ @parameterized.named_parameters(
+ ('Normal', 'aa', 'aaa', True),
+ ('EmptyPrefix', '', 'abc', True),
+ ('BothEmpty', '', '', True))
+ def testStartsWith(self, prefix, string, result):
+ self.assertEqual(result, string.startswith(prefix))
+
+ class NamedExample(parameterized.TestCase):
+ @parameterized.named_parameters(
+ {'testcase_name': 'Normal',
+ 'result': True, 'string': 'aaa', 'prefix': 'aa'},
+ {'testcase_name': 'EmptyPrefix',
+ 'result': True, 'string': 'abc', 'prefix': ''},
+ {'testcase_name': 'BothEmpty',
+ 'result': True, 'string': '', 'prefix': ''})
+ def testStartsWith(self, prefix, string, result):
+ self.assertEqual(result, string.startswith(prefix))
Named tests also have the benefit that they can be run individually
-from the command line:
+from the command line::
- $ testmodule.py NamedExample.testStartsWithNormal
- .
- --------------------------------------------------------------------
- Ran 1 test in 0.000s
+ $ testmodule.py NamedExample.testStartsWithNormal
+ .
+ --------------------------------------------------------------------
+ Ran 1 test in 0.000s
- OK
+ OK
Parameterized Classes
=====================
+
If invocation arguments are shared across test methods in a single
TestCase class, instead of decorating all test methods
-individually, the class itself can be decorated:
+individually, the class itself can be decorated::
- @parameterized.parameters(
- (1, 2, 3),
- (4, 5, 9))
- class ArithmeticTest(parameterized.TestCase):
- def testAdd(self, arg1, arg2, result):
- self.assertEqual(arg1 + arg2, result)
+ @parameterized.parameters(
+ (1, 2, 3),
+ (4, 5, 9))
+ class ArithmeticTest(parameterized.TestCase):
+ def testAdd(self, arg1, arg2, result):
+ self.assertEqual(arg1 + arg2, result)
- def testSubtract(self, arg1, arg2, result):
- self.assertEqual(result - arg1, arg2)
+ def testSubtract(self, arg1, arg2, result):
+ self.assertEqual(result - arg1, arg2)
Inputs from Iterables
=====================
+
If parameters should be shared across several test cases, or are dynamically
created from other sources, a single non-tuple iterable can be passed into
-the decorator. This iterable will be used to obtain the test cases:
+the decorator. This iterable will be used to obtain the test cases::
- class AdditionExample(parameterized.TestCase):
- @parameterized.parameters(
- c.op1, c.op2, c.result for c in testcases
- )
- def testAddition(self, op1, op2, result):
- self.assertEqual(result, op1 + op2)
+ class AdditionExample(parameterized.TestCase):
+ @parameterized.parameters(
+ c.op1, c.op2, c.result for c in testcases
+ )
+ def testAddition(self, op1, op2, result):
+ self.assertEqual(result, op1 + op2)
Single-Argument Test Methods
============================
+
If a test method takes only one argument, the single arguments must not be
-wrapped into a tuple:
+wrapped into a tuple::
- class NegativeNumberExample(parameterized.TestCase):
- @parameterized.parameters(
- -1, -3, -4, -5
- )
- def testIsNegative(self, arg):
- self.assertTrue(IsNegative(arg))
+ class NegativeNumberExample(parameterized.TestCase):
+ @parameterized.parameters(
+ -1, -3, -4, -5
+ )
+ def testIsNegative(self, arg):
+ self.assertTrue(IsNegative(arg))
List/tuple as a Single Argument
===============================
+
If a test method takes a single argument of a list/tuple, it must be wrapped
-inside a tuple:
+inside a tuple::
- class ZeroSumExample(parameterized.TestCase):
- @parameterized.parameters(
- ([-1, 0, 1], ),
- ([-2, 0, 2], ),
- )
- def testSumIsZero(self, arg):
- self.assertEqual(0, sum(arg))
+ class ZeroSumExample(parameterized.TestCase):
+ @parameterized.parameters(
+ ([-1, 0, 1], ),
+ ([-2, 0, 2], ),
+ )
+ def testSumIsZero(self, arg):
+ self.assertEqual(0, sum(arg))
Cartesian product of Parameter Values as Parametrized Test Cases
-======================================================
+================================================================
+
If required to test method over a cartesian product of parameters,
`parameterized.product` may be used to facilitate generation of parameters
-test combinations:
+test combinations::
- class TestModuloExample(parameterized.TestCase):
- @parameterized.product(
- num=[0, 20, 80],
- modulo=[2, 4],
- expected=[0]
- )
- def testModuloResult(self, num, modulo, expected):
- self.assertEqual(expected, num % modulo)
+ class TestModuloExample(parameterized.TestCase):
+ @parameterized.product(
+ num=[0, 20, 80],
+ modulo=[2, 4],
+ expected=[0]
+ )
+ def testModuloResult(self, num, modulo, expected):
+ self.assertEqual(expected, num % modulo)
This results in 6 test cases being created - one for each combination of the
parameters. It is also possible to supply sequences of keyword argument dicts
-as elements of the cartesian product:
+as elements of the cartesian product::
@parameterized.product(
(dict(num=5, modulo=3, expected=2),
@@ -187,10 +192,11 @@ data (supplied as kwarg dicts) and for each of the two data types (supplied as
a named parameter). Multiple keyword argument dicts may be supplied if required.
Async Support
-===============================
+=============
+
If a test needs to call async functions, it can inherit from both
parameterized.TestCase and another TestCase that supports async calls, such
-as [asynctest](https://github.com/Martiusweb/asynctest):
+as [asynctest](https://github.com/Martiusweb/asynctest)::
import asynctest
@@ -674,16 +680,16 @@ def CoopTestCase(other_base_class): # pylint: disable=invalid-name
This enables the TestCase to be used in combination
with other base classes that have custom metaclasses, such as
- mox.MoxTestBase.
+ ``mox.MoxTestBase``.
- Only works with metaclasses that do not override type.__new__.
+ Only works with metaclasses that do not override ``type.__new__``.
- Example:
+ Example::
- from absl.testing import parameterized
+ from absl.testing import parameterized
- class ExampleTest(parameterized.CoopTestCase(OtherTestCase)):
- ...
+ class ExampleTest(parameterized.CoopTestCase(OtherTestCase)):
+ ...
Args:
other_base_class: (class) A test case base class.
diff --git a/absl/testing/tests/absltest_test.py b/absl/testing/tests/absltest_test.py
index 43201bd..68067cf 100644
--- a/absl/testing/tests/absltest_test.py
+++ b/absl/testing/tests/absltest_test.py
@@ -975,6 +975,29 @@ test case
with self.assertRaisesWithPredicateMatch(ValueError, lambda e: True):
raise ValueError
+ def test_assert_raises_with_predicate_match_exception_captured(self):
+ def _raise_value_error():
+ raise ValueError
+
+ predicate = lambda e: e is not None
+ with self.assertRaisesWithPredicateMatch(ValueError, predicate) as ctx_mgr:
+ _raise_value_error()
+
+ expected = getattr(ctx_mgr, 'exception', None)
+ self.assertIsInstance(expected, ValueError)
+
+ def test_assert_raises_with_literal_match_exception_captured(self):
+ message = 'some value error'
+ def _raise_value_error():
+ raise ValueError(message)
+
+ # predicate = lambda e: e is not None
+ with self.assertRaisesWithLiteralMatch(ValueError, message) as ctx_mgr:
+ _raise_value_error()
+
+ expected = getattr(ctx_mgr, 'exception', None)
+ self.assertIsInstance(expected, ValueError)
+
def test_assert_contains_in_order(self):
# Valids
self.assertContainsInOrder(
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..8f39a96
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,37 @@
+# Minimal makefile for Sphinx documentation
+#
+# To generate html docs locally:
+# Recommend doing this from a virtual environment:
+# $ sudo apt-get install virtualenv python3-venv
+# $ virtualenv myproject # or python3 -m venv myproject
+# $ source myproject/bin/activate
+#
+# Then install sphinx packages (if running locally)
+# $ pip install m2r2
+# $ pip install sphinxcontrib-apidoc
+# $ pip install sphinx-rtd-theme
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SOURCEDIR = ../absl
+RSTDIR = source
+HTMLDIR = build
+HTMLDIR = build
+# If you change the conf.py apidoc_excluded_paths, you need to update
+# the excluded paths in APIDOC_EXCLUDE too. The paths are relative
+# to the docs/ directory (if you want to filter out absl/tests you need
+# to use "../*/tests".)
+APIDOC_EXCLUDE = ../*/*/tests/* ../*/tests/*
+SPHINXBUILD ?= sphinx-build
+SPHINXAPIDOC ?= sphinx-apidoc
+
+# Build .rst files for all Python sources in SOURCEDIR.
+# This rule isn't called by readthedocs, its only used for manual testing.
+rstfiles:
+ @$(SPHINXAPIDOC) -o $(RSTDIR) $(SOURCEDIR) $(APIDOC_EXCLUDE)
+
+# Run after "make rstfiles"
+# You can review sphinx generated files in docs/build directory.
+htmlfiles:
+ @$(SPHINXBUILD) -b html -c $(RSTDIR) $(RSTDIR) $(HTMLDIR)
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000..364c154
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,60 @@
+"""Sphinx config file for https://github.com/abseil/abseil-py."""
+
+import os
+import sys
+
+# -- Project information
+project = 'Abseil Python Common Libraries'
+copyright = '2022, Abseil' # pylint: disable=redefined-builtin
+author = 'The Abseil Authors'
+
+release = ''
+version = ''
+
+# -- General configuration
+
+extensions = [
+ 'sphinx.ext.duration',
+ 'sphinx.ext.doctest',
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.autosummary',
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.napoleon',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.coverage',
+ 'sphinxcontrib.apidoc', # convert .py sources to .rst docs.
+ 'm2r2', # for .md files
+]
+
+# sphinxcontrib.apidoc vars
+apidoc_module_dir = '../../absl'
+apidoc_output_dir = '.'
+apidoc_toc_file = False
+apidoc_excluded_paths = [
+ '*/tests/*',
+ 'tests/*',
+]
+apidoc_separate_modules = True
+
+intersphinx_mapping = {
+ 'python': ('https://docs.python.org/3/', None),
+ 'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
+}
+intersphinx_disabled_domains = ['std']
+
+source_suffix = {
+ '.rst': 'restructuredtext',
+ '.md': 'markdown',
+}
+
+templates_path = ['_templates']
+
+# -- Options for HTML output
+
+html_theme = 'sphinx_rtd_theme'
+
+# -- Options for EPUB output
+epub_show_urls = 'footnote'
+
+sys.path.insert(0, os.path.abspath('../..')) # access to README.md
+sys.path.insert(0, os.path.abspath('../../absl')) # access to python sources
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..4bd00f9
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,16 @@
+.. include:: readme_link.rst
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+ :glob:
+
+ *
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/docs/source/readme_link.rst b/docs/source/readme_link.rst
new file mode 100644
index 0000000..3bd447c
--- /dev/null
+++ b/docs/source/readme_link.rst
@@ -0,0 +1 @@
+.. mdinclude:: ../../README.md