diff options
author | Yilei Yang (杨一磊) <yileiyang@google.com> | 2022-07-18 13:30:39 -0700 |
---|---|---|
committer | Yilei Yang (杨一磊) <yileiyang@google.com> | 2022-07-18 13:30:39 -0700 |
commit | 31a6e49b8cc3d8a9c2045874cfe8301cf7c6d13d (patch) | |
tree | f7e874f1f1d57d98d5e4001f23a6702620afa8f9 | |
parent | 58ead8c22230a2493006fa0ab9f76776b6e7280f (diff) | |
parent | 9aca0e4651e9845ab3a7e8f83a1852ff3f3752a2 (diff) | |
download | absl-py-31a6e49b8cc3d8a9c2045874cfe8301cf7c6d13d.tar.gz |
Merge commit for internal changes.
43 files changed, 176 insertions, 209 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c36751..ab288ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com). Nothing notable unreleased. +## 1.2.0 (2022-07-18) + +### Fixed + +* Fixed a crash in Python 3.11 when `TempFileCleanup.SUCCESS` is used. + ## 1.1.0 (2022-06-01) * `Flag` instances now raise an error if used in a bool context. This prevents diff --git a/absl/app.py b/absl/app.py index 037f75c..196a951 100644 --- a/absl/app.py +++ b/absl/app.py @@ -25,10 +25,6 @@ call app.run(main). For example: app.run(main) """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import collections import errno import os diff --git a/absl/command_name.py b/absl/command_name.py index 3bf9fad..1996493 100644 --- a/absl/command_name.py +++ b/absl/command_name.py @@ -14,10 +14,6 @@ """A tiny stand alone library to change the kernel process name on Linux.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys diff --git a/absl/flags/_defines.py b/absl/flags/_defines.py index 4494c3b..a102652 100644 --- a/absl/flags/_defines.py +++ b/absl/flags/_defines.py @@ -17,10 +17,6 @@ Do NOT import this module directly. Import the flags package and use the aliases defined at the package level instead. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import sys import types diff --git a/absl/flags/_defines.pyi b/absl/flags/_defines.pyi index 1f482a2..0fbe921 100644 --- a/absl/flags/_defines.pyi +++ b/absl/flags/_defines.pyi @@ -576,7 +576,23 @@ def DEFINE_multi_enum( @overload def DEFINE_multi_enum_class( name: Text, - default: Union[None, Iterable[_ET], _ET, Text], + # This is separate from `Union[None, _ET, Text]` to avoid a Pytype issue + # inferring the return value to FlagHolder[List[Union[_ET, enum.Enum]]] + # when an iterable of concrete enum subclasses are used. + default: Iterable[_ET], + enum_class: Type[_ET], + help: Text, + flag_values: _flagvalues.FlagValues = ..., + module_name: Optional[Text] = ..., + *, + required: Literal[True], + **args: Any) -> _flagvalues.FlagHolder[List[_ET]]: + ... + +@overload +def DEFINE_multi_enum_class( + name: Text, + default: Union[None, _ET, Text], enum_class: Type[_ET], help: Text, flag_values: _flagvalues.FlagValues = ..., @@ -601,7 +617,10 @@ def DEFINE_multi_enum_class( @overload def DEFINE_multi_enum_class( name: Text, - default: Union[Iterable[_ET], _ET, Text], + # This is separate from `Union[None, _ET, Text]` to avoid a Pytype issue + # inferring the return value to FlagHolder[List[Union[_ET, enum.Enum]]] + # when an iterable of concrete enum subclasses are used. + default: Iterable[_ET], enum_class: Type[_ET], help: Text, flag_values: _flagvalues.FlagValues = ..., @@ -610,6 +629,17 @@ def DEFINE_multi_enum_class( **args: Any) -> _flagvalues.FlagHolder[List[_ET]]: ... +@overload +def DEFINE_multi_enum_class( + name: Text, + default: Union[_ET, Text], + enum_class: Type[_ET], + help: Text, + flag_values: _flagvalues.FlagValues = ..., + module_name: Optional[Text] = ..., + required: bool = ..., + **args: Any) -> _flagvalues.FlagHolder[List[_ET]]: + ... def DEFINE_alias( diff --git a/absl/flags/_exceptions.py b/absl/flags/_exceptions.py index 254eb9b..0ca2777 100644 --- a/absl/flags/_exceptions.py +++ b/absl/flags/_exceptions.py @@ -18,10 +18,6 @@ Do NOT import this module directly. Import the flags package and use the aliases defined at the package level instead. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import sys from absl.flags import _helpers diff --git a/absl/flags/_helpers.py b/absl/flags/_helpers.py index 37ae360..96f0a85 100644 --- a/absl/flags/_helpers.py +++ b/absl/flags/_helpers.py @@ -14,10 +14,6 @@ """Internal helper functions for Abseil Python flags library.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import collections import os import re diff --git a/absl/flags/_validators.py b/absl/flags/_validators.py index af66050..26639c5 100644 --- a/absl/flags/_validators.py +++ b/absl/flags/_validators.py @@ -32,10 +32,6 @@ Do NOT import this module directly. Import the flags package and use the aliases defined at the package level instead. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import warnings from absl.flags import _exceptions diff --git a/absl/flags/_validators_classes.py b/absl/flags/_validators_classes.py index d8996e0..2881499 100644 --- a/absl/flags/_validators_classes.py +++ b/absl/flags/_validators_classes.py @@ -18,10 +18,6 @@ Do NOT import this module. DO NOT use anything from this module. They are private APIs. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl.flags import _exceptions diff --git a/absl/flags/argparse_flags.py b/absl/flags/argparse_flags.py index 4f78f50..69e4c8a 100644 --- a/absl/flags/argparse_flags.py +++ b/absl/flags/argparse_flags.py @@ -88,10 +88,6 @@ There are several differences between absl.flags and argparse_flags: 3) argparse_flags supports `-h`; absl.app does not. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import argparse import sys diff --git a/absl/flags/tests/_flag_test.py b/absl/flags/tests/_flag_test.py index 492f117..1625289 100644 --- a/absl/flags/tests/_flag_test.py +++ b/absl/flags/tests/_flag_test.py @@ -17,10 +17,6 @@ Most of the Flag classes are covered in the flags_test.py. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import copy import enum import pickle diff --git a/absl/flags/tests/_helpers_test.py b/absl/flags/tests/_helpers_test.py index 4746a79..2697d1c 100644 --- a/absl/flags/tests/_helpers_test.py +++ b/absl/flags/tests/_helpers_test.py @@ -14,10 +14,6 @@ """Unittests for helpers module.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import sys from absl.flags import _helpers diff --git a/absl/flags/tests/_validators_test.py b/absl/flags/tests/_validators_test.py index f724813..1cccf53 100644 --- a/absl/flags/tests/_validators_test.py +++ b/absl/flags/tests/_validators_test.py @@ -18,10 +18,6 @@ This file tests that each flag validator called when it should be, and that failed validator will throw an exception, etc. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import warnings diff --git a/absl/flags/tests/argparse_flags_test_helper.py b/absl/flags/tests/argparse_flags_test_helper.py index 8cf42e6..613c896 100644 --- a/absl/flags/tests/argparse_flags_test_helper.py +++ b/absl/flags/tests/argparse_flags_test_helper.py @@ -14,10 +14,6 @@ """Test helper for argparse_flags_test.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import random diff --git a/absl/flags/tests/flags_formatting_test.py b/absl/flags/tests/flags_formatting_test.py index bb547ce..ef55850 100644 --- a/absl/flags/tests/flags_formatting_test.py +++ b/absl/flags/tests/flags_formatting_test.py @@ -12,10 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl import flags from absl.flags import _helpers from absl.testing import absltest diff --git a/absl/flags/tests/flags_unicode_literals_test.py b/absl/flags/tests/flags_unicode_literals_test.py index e8ed5bf..1f72f23 100644 --- a/absl/flags/tests/flags_unicode_literals_test.py +++ b/absl/flags/tests/flags_unicode_literals_test.py @@ -14,11 +14,6 @@ """Test the use of flags when from __future__ import unicode_literals is on.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from absl import flags from absl.testing import absltest diff --git a/absl/flags/tests/module_bar.py b/absl/flags/tests/module_bar.py index 8714d2e..51dffa3 100644 --- a/absl/flags/tests/module_bar.py +++ b/absl/flags/tests/module_bar.py @@ -18,10 +18,6 @@ The purpose of this module is to define a few flags. We want to make sure the unit tests for flags.py involve more than one module. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl import flags from absl.flags import _helpers diff --git a/absl/flags/tests/module_baz.py b/absl/flags/tests/module_baz.py index 7199516..9bf03fd 100644 --- a/absl/flags/tests/module_baz.py +++ b/absl/flags/tests/module_baz.py @@ -18,10 +18,6 @@ The purpose of this module is to test the behavior of flags that are defined before main() executes. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl import flags FLAGS = flags.FLAGS diff --git a/absl/flags/tests/module_foo.py b/absl/flags/tests/module_foo.py index a1a2573..649047c 100644 --- a/absl/flags/tests/module_foo.py +++ b/absl/flags/tests/module_foo.py @@ -19,10 +19,6 @@ other flags as being important. We want to make sure the unit tests for flags.py involve more than one module. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl import flags from absl.flags import _helpers from absl.flags.tests import module_bar diff --git a/absl/logging/tests/converter_test.py b/absl/logging/tests/converter_test.py index bdc893a..2c95c4f 100644 --- a/absl/logging/tests/converter_test.py +++ b/absl/logging/tests/converter_test.py @@ -14,10 +14,6 @@ """Tests for converter.py.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import logging from absl import logging as absl_logging diff --git a/absl/logging/tests/verbosity_flag_test.py b/absl/logging/tests/verbosity_flag_test.py index 4609e64..ea9944d 100644 --- a/absl/logging/tests/verbosity_flag_test.py +++ b/absl/logging/tests/verbosity_flag_test.py @@ -14,10 +14,6 @@ """Tests -v/--verbosity flag and logging.root level's sync behavior.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import logging assert logging.root.getEffectiveLevel() == logging.WARN, ( diff --git a/absl/testing/BUILD b/absl/testing/BUILD index b608c8c..d428792 100644 --- a/absl/testing/BUILD +++ b/absl/testing/BUILD @@ -199,6 +199,7 @@ py_binary( srcs_version = "PY3", deps = [ ":absltest", + "//absl:app", "//absl/flags", ], ) diff --git a/absl/testing/_bazelize_command.py b/absl/testing/_bazelize_command.py index fdf6eb6..9380d27 100644 --- a/absl/testing/_bazelize_command.py +++ b/absl/testing/_bazelize_command.py @@ -14,10 +14,6 @@ """Internal helper for running tests on Windows Bazel.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os from absl import flags diff --git a/absl/testing/_pretty_print_reporter.py b/absl/testing/_pretty_print_reporter.py index ef03934..b0dde07 100644 --- a/absl/testing/_pretty_print_reporter.py +++ b/absl/testing/_pretty_print_reporter.py @@ -14,10 +14,6 @@ """TestResult implementing default output for test execution status.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import unittest diff --git a/absl/testing/absltest.py b/absl/testing/absltest.py index cebb1ca..b7a941b 100644 --- a/absl/testing/absltest.py +++ b/absl/testing/absltest.py @@ -531,8 +531,9 @@ class _TempFile(object): # Literal to express more precise return types. The contained type is # currently `Any` to avoid [bad-return-type] errors in the open_* methods. @contextlib.contextmanager - def _open(self, mode, encoding='utf8', errors='strict'): - # type: (Text, Text, Text) -> Iterator[Any] + def _open( + self, mode: str, encoding: str = 'utf8', errors: str = 'strict' + ) -> Iterator[Any]: with io.open( self.full_path, mode=mode, encoding=encoding, errors=errors) as fp: yield fp @@ -786,24 +787,49 @@ class TestCase(unittest.TestCase): elif cleanup == TempFileCleanup.ALWAYS: self.addCleanup(_rmtree_ignore_errors, path) elif cleanup == TempFileCleanup.SUCCESS: - self._internal_cleanup_on_success(_rmtree_ignore_errors, path) + self._internal_add_cleanup_on_success(_rmtree_ignore_errors, path) else: raise AssertionError('Unexpected cleanup value: {}'.format(cleanup)) - def _internal_cleanup_on_success(self, function, *args, **kwargs): - # type: (Callable[..., object], Any, Any) -> None + def _internal_add_cleanup_on_success( + self, + function: Callable[..., Any], + *args: Any, + **kwargs: Any, + ) -> None: + """Adds `function` as cleanup when the test case succeeds.""" + outcome = self._outcome + previous_failure_count = ( + len(outcome.result.failures) + + len(outcome.result.errors) + + len(outcome.result.unexpectedSuccesses) + ) def _call_cleaner_on_success(*args, **kwargs): - if not self._ran_and_passed(): + if not self._internal_ran_and_passed_when_called_during_cleanup( + previous_failure_count): return function(*args, **kwargs) self.addCleanup(_call_cleaner_on_success, *args, **kwargs) - def _ran_and_passed(self): - # type: () -> bool + def _internal_ran_and_passed_when_called_during_cleanup( + self, + previous_failure_count: int, + ) -> bool: + """Returns whether test is passed. Expected to be called during cleanup.""" outcome = self._outcome - result = self.defaultTestResult() - self._feedErrorsToResult(result, outcome.errors) # pytype: disable=attribute-error - return result.wasSuccessful() + if sys.version_info[:2] >= (3, 11): + current_failure_count = ( + len(outcome.result.failures) + + len(outcome.result.errors) + + len(outcome.result.unexpectedSuccesses) + ) + return current_failure_count == previous_failure_count + else: + # Before Python 3.11 https://github.com/python/cpython/pull/28180, errors + # were bufferred in _Outcome before calling cleanup. + result = self.defaultTestResult() + self._feedErrorsToResult(result, outcome.errors) # pytype: disable=attribute-error + return result.wasSuccessful() def shortDescription(self): # type: () -> Text @@ -2036,19 +2062,6 @@ def _is_in_app_main(): return False -class _SavedFlag(object): - """Helper class for saving and restoring a flag value.""" - - def __init__(self, flag): - self.flag = flag - self.value = flag.value - self.present = flag.present - - def restore_flag(self): - self.flag.value = self.value - self.flag.present = self.present - - def _register_sigterm_with_faulthandler(): # type: () -> None """Have faulthandler dump stacks on SIGTERM. Useful to diagnose timeouts.""" @@ -2105,29 +2118,30 @@ def _run_in_app(function, args, kwargs): if _is_in_app_main(): _register_sigterm_with_faulthandler() - # Save command-line flags so the side effects of FLAGS(sys.argv) can be - # undone. - flag_objects = (FLAGS[name] for name in FLAGS) - saved_flags = dict((f.name, _SavedFlag(f)) for f in flag_objects) - # Change the default of alsologtostderr from False to True, so the test # programs's stderr will contain all the log messages. # If --alsologtostderr=false is specified in the command-line, or user # has called FLAGS.alsologtostderr = False before, then the value is kept # False. FLAGS.set_default('alsologtostderr', True) - # Remove it from saved flags so it doesn't get restored later. - del saved_flags['alsologtostderr'] - - # The call FLAGS(sys.argv) parses sys.argv, returns the arguments - # without the flags, and -- as a side effect -- modifies flag values in - # FLAGS. We don't want the side effect, because we don't want to - # override flag changes the program did (e.g. in __main__.main) - # after the command-line has been parsed. So we have the for loop below - # to change back flags to their old values. - argv = FLAGS(sys.argv) - for saved_flag in saved_flags.values(): - saved_flag.restore_flag() + + # Here we only want to get the `argv` without the flags. To avoid any + # side effects of parsing flags, we temporarily stub out the `parse` method + stored_parse_methods = {} + noop_parse = lambda _: None + for name in FLAGS: + # Avoid any side effects of parsing flags. + stored_parse_methods[name] = FLAGS[name].parse + # This must be a separate loop since multiple flag names (short_name=) can + # point to the same flag object. + for name in FLAGS: + FLAGS[name].parse = noop_parse + try: + argv = FLAGS(sys.argv) + finally: + for name in FLAGS: + FLAGS[name].parse = stored_parse_methods[name] + sys.stdout.flush() function(argv, args, kwargs) else: diff --git a/absl/testing/flagsaver.py b/absl/testing/flagsaver.py index 7fe95fe..f87dbb1 100644 --- a/absl/testing/flagsaver.py +++ b/absl/testing/flagsaver.py @@ -59,10 +59,6 @@ exception will be raised. However if you *add* a flag after saving flag values, and then restore flag values, the added flag will be deleted with no errors. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import functools import inspect diff --git a/absl/testing/tests/absltest_fail_fast_test.py b/absl/testing/tests/absltest_fail_fast_test.py index dc967f9..efde8a0 100644 --- a/absl/testing/tests/absltest_fail_fast_test.py +++ b/absl/testing/tests/absltest_fail_fast_test.py @@ -14,10 +14,6 @@ """Tests for test fail fast protocol.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import subprocess from absl import logging diff --git a/absl/testing/tests/absltest_fail_fast_test_helper.py b/absl/testing/tests/absltest_fail_fast_test_helper.py index 339a569..a6ffb62 100644 --- a/absl/testing/tests/absltest_fail_fast_test_helper.py +++ b/absl/testing/tests/absltest_fail_fast_test_helper.py @@ -14,10 +14,6 @@ """A helper test program for absltest_fail_fast_test.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys diff --git a/absl/testing/tests/absltest_filtering_test.py b/absl/testing/tests/absltest_filtering_test.py index 30a81f6..3bbb219 100644 --- a/absl/testing/tests/absltest_filtering_test.py +++ b/absl/testing/tests/absltest_filtering_test.py @@ -13,10 +13,6 @@ # limitations under the License. """Tests for test filtering protocol.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import subprocess import sys diff --git a/absl/testing/tests/absltest_filtering_test_helper.py b/absl/testing/tests/absltest_filtering_test_helper.py index 2b741ed..b8bc55f 100644 --- a/absl/testing/tests/absltest_filtering_test_helper.py +++ b/absl/testing/tests/absltest_filtering_test_helper.py @@ -14,10 +14,6 @@ """A helper test program for absltest_filtering_test.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys diff --git a/absl/testing/tests/absltest_randomization_test.py b/absl/testing/tests/absltest_randomization_test.py index 75a3868..e73dfce 100644 --- a/absl/testing/tests/absltest_randomization_test.py +++ b/absl/testing/tests/absltest_randomization_test.py @@ -14,10 +14,6 @@ """Tests for test randomization.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import random import subprocess diff --git a/absl/testing/tests/absltest_randomization_testcase.py b/absl/testing/tests/absltest_randomization_testcase.py index 18b20ff..ac2cea0 100644 --- a/absl/testing/tests/absltest_randomization_testcase.py +++ b/absl/testing/tests/absltest_randomization_testcase.py @@ -14,10 +14,6 @@ """Stub tests, only for use in absltest_randomization_test.py.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys diff --git a/absl/testing/tests/absltest_sharding_test.py b/absl/testing/tests/absltest_sharding_test.py index 6411971..9bbb903 100644 --- a/absl/testing/tests/absltest_sharding_test.py +++ b/absl/testing/tests/absltest_sharding_test.py @@ -14,10 +14,6 @@ """Tests for test sharding protocol.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import subprocess diff --git a/absl/testing/tests/absltest_sharding_test_helper.py b/absl/testing/tests/absltest_sharding_test_helper.py index 7b2f20e..57a924c 100644 --- a/absl/testing/tests/absltest_sharding_test_helper.py +++ b/absl/testing/tests/absltest_sharding_test_helper.py @@ -14,10 +14,6 @@ """A helper test program for absltest_sharding_test.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import sys from absl.testing import absltest diff --git a/absl/testing/tests/absltest_test.py b/absl/testing/tests/absltest_test.py index 48eeca8..43201bd 100644 --- a/absl/testing/tests/absltest_test.py +++ b/absl/testing/tests/absltest_test.py @@ -186,6 +186,15 @@ class TestCaseTest(absltest.TestCase, HelperMixin): }, expect_success=True) + def test_app_run(self): + stdout, _ = self.run_helper( + 7, + ['--name=cat', '--name=dog'], + {'ABSLTEST_TEST_HELPER_USE_APP_RUN': '1'}, + expect_success=True) + self.assertIn('Names in main() are: cat dog', stdout) + self.assertIn('Names in test_name_flag() are: cat dog', stdout) + def test_assert_in(self): animals = {'monkey': 'banana', 'cow': 'grass', 'seal': 'fish'} @@ -2136,6 +2145,11 @@ class TempFileTest(absltest.TestCase, HelperMixin): 'TempFileHelperTest/test_failure', 'TempFileHelperTest/test_failure/failure', 'TempFileHelperTest/test_success', + 'TempFileHelperTest/test_subtest_failure', + 'TempFileHelperTest/test_subtest_failure/parent', + 'TempFileHelperTest/test_subtest_failure/successful_child', + 'TempFileHelperTest/test_subtest_failure/failed_child', + 'TempFileHelperTest/test_subtest_success', } self.run_tempfile_helper('SUCCESS', expected) @@ -2144,6 +2158,8 @@ class TempFileTest(absltest.TestCase, HelperMixin): 'TempFileHelperTest', 'TempFileHelperTest/test_failure', 'TempFileHelperTest/test_success', + 'TempFileHelperTest/test_subtest_failure', + 'TempFileHelperTest/test_subtest_success', } self.run_tempfile_helper('ALWAYS', expected) @@ -2154,6 +2170,14 @@ class TempFileTest(absltest.TestCase, HelperMixin): 'TempFileHelperTest/test_failure/failure', 'TempFileHelperTest/test_success', 'TempFileHelperTest/test_success/success', + 'TempFileHelperTest/test_subtest_failure', + 'TempFileHelperTest/test_subtest_failure/parent', + 'TempFileHelperTest/test_subtest_failure/successful_child', + 'TempFileHelperTest/test_subtest_failure/failed_child', + 'TempFileHelperTest/test_subtest_success', + 'TempFileHelperTest/test_subtest_success/parent', + 'TempFileHelperTest/test_subtest_success/child0', + 'TempFileHelperTest/test_subtest_success/child1', } self.run_tempfile_helper('OFF', expected) @@ -2163,8 +2187,8 @@ class SkipClassTest(absltest.TestCase): def test_incorrect_decorator_call(self): with self.assertRaises(TypeError): - @absltest.skipThisClass # pylint: disable=unused-variable - class Test(absltest.TestCase): + @absltest.skipThisClass + class Test(absltest.TestCase): # pylint: disable=unused-variable pass def test_incorrect_decorator_subclass(self): diff --git a/absl/testing/tests/absltest_test_helper.py b/absl/testing/tests/absltest_test_helper.py index c6b2465..89b6721 100644 --- a/absl/testing/tests/absltest_test_helper.py +++ b/absl/testing/tests/absltest_test_helper.py @@ -14,26 +14,34 @@ """Helper binary for absltest_test.py.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import tempfile import unittest +from absl import app from absl import flags from absl.testing import absltest FLAGS = flags.FLAGS -flags.DEFINE_integer('test_id', 0, 'Which test to run.') +_TEST_ID = flags.DEFINE_integer('test_id', 0, 'Which test to run.') +_NAME = flags.DEFINE_multi_string('name', [], 'List of names to print.') + + +@flags.validator('name') +def validate_name(value): + # This validator makes sure that the second FLAGS(sys.argv) inside + # absltest.main() won't actually trigger side effects of the flag parsing. + if len(value) > 2: + raise flags.ValidationError( + f'No more than two names should be specified, found {len(value)} names') + return True class HelperTest(absltest.TestCase): def test_flags(self): - if FLAGS.test_id == 1: + if _TEST_ID.value == 1: self.assertEqual(FLAGS.test_random_seed, 301) if os.name == 'nt': # On Windows, it's always in the temp dir, which doesn't start with '/'. @@ -45,7 +53,7 @@ class HelperTest(absltest.TestCase): '--test_tmpdir={} does not start with {}'.format( absltest.TEST_TMPDIR.value, expected_prefix)) self.assertTrue(os.access(absltest.TEST_TMPDIR.value, os.W_OK)) - elif FLAGS.test_id == 2: + elif _TEST_ID.value == 2: self.assertEqual(FLAGS.test_random_seed, 321) self.assertEqual( absltest.TEST_SRCDIR.value, @@ -53,7 +61,7 @@ class HelperTest(absltest.TestCase): self.assertEqual( absltest.TEST_TMPDIR.value, os.environ['ABSLTEST_TEST_HELPER_EXPECTED_TEST_TMPDIR']) - elif FLAGS.test_id == 3: + elif _TEST_ID.value == 3: self.assertEqual(FLAGS.test_random_seed, 123) self.assertEqual( absltest.TEST_SRCDIR.value, @@ -61,7 +69,7 @@ class HelperTest(absltest.TestCase): self.assertEqual( absltest.TEST_TMPDIR.value, os.environ['ABSLTEST_TEST_HELPER_EXPECTED_TEST_TMPDIR']) - elif FLAGS.test_id == 4: + elif _TEST_ID.value == 4: self.assertEqual(FLAGS.test_random_seed, 221) self.assertEqual( absltest.TEST_SRCDIR.value, @@ -71,26 +79,35 @@ class HelperTest(absltest.TestCase): os.environ['ABSLTEST_TEST_HELPER_EXPECTED_TEST_TMPDIR']) else: raise unittest.SkipTest( - 'Not asked to run: --test_id={}'.format(FLAGS.test_id)) + 'Not asked to run: --test_id={}'.format(_TEST_ID.value)) @unittest.expectedFailure def test_expected_failure(self): - if FLAGS.test_id == 5: + if _TEST_ID.value == 5: self.assertEqual(1, 1) # Expected failure, got success. else: self.assertEqual(1, 2) # The expected failure. def test_xml_env_vars(self): - if FLAGS.test_id == 6: + if _TEST_ID.value == 6: self.assertEqual( FLAGS.xml_output_file, os.environ['ABSLTEST_TEST_HELPER_EXPECTED_XML_OUTPUT_FILE']) else: raise unittest.SkipTest( - 'Not asked to run: --test_id={}'.format(FLAGS.test_id)) + 'Not asked to run: --test_id={}'.format(_TEST_ID.value)) + + def test_name_flag(self): + if _TEST_ID.value == 7: + print('Names in test_name_flag() are:', ' '.join(_NAME.value)) + else: + raise unittest.SkipTest( + 'Not asked to run: --test_id={}'.format(_TEST_ID.value)) class TempFileHelperTest(absltest.TestCase): + """Helper test case for tempfile cleanup tests.""" + tempfile_cleanup = absltest.TempFileCleanup[os.environ.get( 'ABSLTEST_TEST_HELPER_TEMPFILE_CLEANUP', 'SUCCESS')] @@ -101,6 +118,29 @@ class TempFileHelperTest(absltest.TestCase): def test_success(self): self.create_tempfile('success') + def test_subtest_failure(self): + self.create_tempfile('parent') + with self.subTest('success'): + self.create_tempfile('successful_child') + with self.subTest('failure'): + self.create_tempfile('failed_child') + self.fail('expected failure') -if __name__ == '__main__': + def test_subtest_success(self): + self.create_tempfile('parent') + for i in range(2): + with self.subTest(f'success{i}'): + self.create_tempfile(f'child{i}') + + +def main(argv): + del argv # Unused. + print('Names in main() are:', ' '.join(_NAME.value)) absltest.main() + + +if __name__ == '__main__': + if os.environ.get('ABSLTEST_TEST_HELPER_USE_APP_RUN'): + app.run(main) + else: + absltest.main() diff --git a/absl/testing/tests/flagsaver_test.py b/absl/testing/tests/flagsaver_test.py index 3439a32..e98cd06 100644 --- a/absl/testing/tests/flagsaver_test.py +++ b/absl/testing/tests/flagsaver_test.py @@ -13,10 +13,6 @@ # limitations under the License. """Tests for flagsaver.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl import flags from absl.testing import absltest from absl.testing import flagsaver diff --git a/absl/testing/tests/xml_reporter_helper_test.py b/absl/testing/tests/xml_reporter_helper_test.py index 661bbdc..af3c63d 100644 --- a/absl/testing/tests/xml_reporter_helper_test.py +++ b/absl/testing/tests/xml_reporter_helper_test.py @@ -12,10 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import random from absl import flags diff --git a/absl/testing/xml_reporter.py b/absl/testing/xml_reporter.py index da56e39..5996ce2 100644 --- a/absl/testing/xml_reporter.py +++ b/absl/testing/xml_reporter.py @@ -14,10 +14,6 @@ """A Python test reporter that generates test reports in JUnit XML format.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import datetime import re import sys diff --git a/absl/tests/app_test_helper.py b/absl/tests/app_test_helper.py index 6bd1a89..f9fbdec 100644 --- a/absl/tests/app_test_helper.py +++ b/absl/tests/app_test_helper.py @@ -14,10 +14,6 @@ """Helper script used by app_test.py.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys @@ -14,10 +14,6 @@ """Abseil setup configuration.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import os import sys @@ -47,7 +43,7 @@ with open(_README_PATH, 'rb') as fp: setuptools.setup( name='absl-py', - version='1.1.0', + version='1.2.0', description=( 'Abseil Python Common Libraries, ' 'see https://github.com/abseil/abseil-py.'), @@ -68,6 +64,7 @@ setuptools.setup( 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Intended Audience :: Developers', 'Topic :: Software Development :: Libraries :: Python Modules', 'License :: OSI Approved :: Apache Software License', diff --git a/smoke_tests/sample_app.py b/smoke_tests/sample_app.py index 532a11e..d45be96 100644 --- a/smoke_tests/sample_app.py +++ b/smoke_tests/sample_app.py @@ -14,10 +14,6 @@ """Test helper for smoke_test.sh.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import sys from absl import app diff --git a/smoke_tests/sample_test.py b/smoke_tests/sample_test.py index 713677a..2d3f3e4 100644 --- a/smoke_tests/sample_test.py +++ b/smoke_tests/sample_test.py @@ -14,10 +14,6 @@ """Test helper for smoke_test.sh.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - from absl.testing import absltest |