Hello community, here is the log from the commit of package python-abseil for openSUSE:Leap:15.2 checked in at 2020-03-13 10:58:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/python-abseil (Old) and /work/SRC/openSUSE:Leap:15.2/.python-abseil.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-abseil" Fri Mar 13 10:58:05 2020 rev:5 rq:783444 version:0.9.0 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/python-abseil/python-abseil.changes 2020-03-09 18:02:00.328717433 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.python-abseil.new.3160/python-abseil.changes 2020-03-13 10:59:21.864519778 +0100 @@ -1,0 +2,6 @@ +Mon Mar 9 08:07:19 UTC 2020 - Tomáš Chvátal <[email protected]> + +- Update to 0.9.0: + * work with python 3.8 + +------------------------------------------------------------------- Old: ---- pypi-v0.8.0.tar.gz New: ---- pypi-v0.9.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-abseil.spec ++++++ --- /var/tmp/diff_new_pack.r9EZVF/_old 2020-03-13 10:59:22.216520029 +0100 +++ /var/tmp/diff_new_pack.r9EZVF/_new 2020-03-13 10:59:22.220520032 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-abseil # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,11 +18,10 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-abseil -Version: 0.8.0 +Version: 0.9.0 Release: 0 Summary: Abseil Python Common Libraries License: Apache-2.0 -Group: Development/Languages/Python URL: https://github.com/abseil/abseil-py Source0: https://github.com/abseil/abseil-py/archive/pypi-v%{version}.tar.gz BuildRequires: %{python_module setuptools} ++++++ pypi-v0.8.0.tar.gz -> pypi-v0.9.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/README.md new/abseil-py-pypi-v0.9.0/README.md --- old/abseil-py-pypi-v0.8.0/README.md 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/README.md 2019-12-17 23:46:20.000000000 +0100 @@ -40,8 +40,9 @@ ### Example Code -Please refer to [smoke_tests/sample_app.py](smoke_tests/sample_app.py) as an -example to get started. +Please refer to +[smoke_tests/sample_app.py](https://github.com/abseil/abseil-py/blob/master/smoke_tests/sample_app.py) +as an example to get started. ## Documentation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/BUILD new/abseil-py-pypi-v0.9.0/absl/BUILD --- old/abseil-py-pypi-v0.8.0/absl/BUILD 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/BUILD 2019-12-17 23:46:20.000000000 +0100 @@ -1,9 +1,9 @@ +load(":_build_defs.bzl", "py2and3_test", "py2py3_test_binary") + licenses(["notice"]) # Apache 2.0 exports_files(["LICENSE"]) -load(":_build_defs.bzl", "py2py3_test_binary", "py2and3_test") - py_library( name = "app", srcs = [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/CHANGELOG.md new/abseil-py-pypi-v0.9.0/absl/CHANGELOG.md --- old/abseil-py-pypi-v0.8.0/absl/CHANGELOG.md 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/CHANGELOG.md 2019-12-17 23:46:20.000000000 +0100 @@ -8,6 +8,26 @@ Nothing notable unreleased. +## 0.9.0 (2019-12-17) + +### Added + +* (testing) `TestCase.enter_context`: Allows using context managers in setUp + and having them automatically exited when a test finishes. + +### Fixed + +* #126: calling `logging.debug(msg, stack_info=...)` no longer throws an + exception in Python 3.8. + +## 0.8.1 (2019-10-08) + +### Fixed + +* (testing) `absl.testing`'s pretty print reporter no longer buffers + RUN/OK/FAILED messages. +* (testing) `create_tempfile` will overwrite pre-existing read-only files. + ## 0.8.0 (2019-08-26) ### Added diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/flags/tests/flags_test.py new/abseil-py-pypi-v0.9.0/absl/flags/tests/flags_test.py --- old/abseil-py-pypi-v0.8.0/absl/flags/tests/flags_test.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/flags/tests/flags_test.py 2019-12-17 23:46:20.000000000 +0100 @@ -626,7 +626,7 @@ '--stderrthreshold fatal', '--test1', '--test_random_seed 301', - '--test_randomize_ordering_seed None', + '--test_randomize_ordering_seed ', '--testcomma_list []', '--testget1', '--testget4 None', @@ -694,7 +694,7 @@ '--stderrthreshold fatal', '--test1', '--test_random_seed 301', - '--test_randomize_ordering_seed None', + '--test_randomize_ordering_seed ', '--testcomma_list []', '--testget1', '--testget4 None', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/logging/BUILD new/abseil-py-pypi-v0.9.0/absl/logging/BUILD --- old/abseil-py-pypi-v0.8.0/absl/logging/BUILD 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/logging/BUILD 2019-12-17 23:46:20.000000000 +0100 @@ -1,9 +1,9 @@ +load("//absl:_build_defs.bzl", "py2and3_test", "py2py3_test_binary") + licenses(["notice"]) # Apache 2.0 exports_files(["LICENSE"]) -load("//absl:_build_defs.bzl", "py2py3_test_binary", "py2and3_test") - py_library( name = "logging", srcs = ["__init__.py"], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/logging/__init__.py new/abseil-py-pypi-v0.9.0/absl/logging/__init__.py --- old/abseil-py-pypi-v0.8.0/absl/logging/__init__.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/logging/__init__.py 2019-12-17 23:46:20.000000000 +0100 @@ -858,7 +858,8 @@ # Do not close the stream if it's sys.stderr|stdout. They may be # redirected or overridden to files, which should be managed by users # explicitly. - if self.stream not in (sys.stderr, sys.stdout) and ( + user_managed = sys.stderr, sys.stdout, sys.__stderr__, sys.__stdout__ + if self.stream not in user_managed and ( not hasattr(self.stream, 'isatty') or not self.stream.isatty()): self.stream.close() except ValueError: @@ -951,7 +952,7 @@ """ _frames_to_skip = set() - def findCaller(self, stack_info=False): + def findCaller(self, stack_info=False, stacklevel=1): """Finds the frame of the calling method on the stack. This method skips any frames registered with the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/logging/tests/logging_test.py new/abseil-py-pypi-v0.9.0/absl/logging/tests/logging_test.py --- old/abseil-py-pypi-v0.8.0/absl/logging/tests/logging_test.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/logging/tests/logging_test.py 2019-12-17 23:46:20.000000000 +0100 @@ -262,6 +262,20 @@ handler.close() mock_stdout.close.assert_not_called() + def test_close_original_stderr(self): + with mock.patch.object(sys, '__stderr__') as mock_original_stderr: + mock_original_stderr.isatty.return_value = False + handler = logging.PythonHandler(sys.__stderr__) + handler.close() + mock_original_stderr.close.assert_not_called() + + def test_close_original_stdout(self): + with mock.patch.object(sys, '__stdout__') as mock_original_stdout: + mock_original_stdout.isatty.return_value = False + handler = logging.PythonHandler(sys.__stdout__) + handler.close() + mock_original_stdout.close.assert_not_called() + def test_close_fake_file(self): class FakeFile(object): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/BUILD new/abseil-py-pypi-v0.9.0/absl/testing/BUILD --- old/abseil-py-pypi-v0.8.0/absl/testing/BUILD 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/BUILD 2019-12-17 23:46:20.000000000 +0100 @@ -1,8 +1,29 @@ +load("//absl:_build_defs.bzl", "py2and3_test", "py2py3_test_binary") + licenses(["notice"]) # Apache 2.0 exports_files(["LICENSE"]) -load("//absl:_build_defs.bzl", "py2py3_test_binary", "py2and3_test") +config_setting( + name = "osx", + constraint_values = ["//third_party/bazel_platforms/os:osx"], +) + +config_setting( + name = "ios", + flag_values = {"//tools/cpp:cc_target_os": "apple"}, +) + +_absl_test_platform_deps = select({ + ":osx": [], + ":ios": [], + # TODO(b/75911467): Remove after :osx works in host mode + "//tools/cc_target_os:platform_macos": [], + "//conditions:default": [ + "//third_party/py/faulthandler", + "//third_party/py/readline", # Enables arrow keys and tab-completion in (pdb). + ], +}) py_library( name = "absltest", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/_pretty_print_reporter.py new/abseil-py-pypi-v0.9.0/absl/testing/_pretty_print_reporter.py --- old/abseil-py-pypi-v0.8.0/absl/testing/_pretty_print_reporter.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/_pretty_print_reporter.py 2019-12-17 23:46:20.000000000 +0100 @@ -37,6 +37,7 @@ if test_id.startswith('__main__.'): test_id = test_id[len('__main__.'):] print('[%s] %s' % (tag, test_id), file=self.stream) + self.stream.flush() def startTest(self, test): super(TextTestResult, self).startTest(test) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/absltest.py new/abseil-py-pypi-v0.9.0/absl/testing/absltest.py --- old/abseil-py-pypi-v0.8.0/absl/testing/absltest.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/absltest.py 2019-12-17 23:46:20.000000000 +0100 @@ -36,6 +36,7 @@ import shlex import shutil import signal +import stat import subprocess import sys import tempfile @@ -69,7 +70,7 @@ try: # pylint: disable=unused-import import typing - from typing import AnyStr, Callable, Text, Optional, ContextManager, TextIO, BinaryIO, Union, Type, Tuple, Any, MutableSequence, Sequence, Mapping, MutableMapping, IO, List + from typing import Any, AnyStr, BinaryIO, Callable, ContextManager, IO, Iterator, List, Mapping, MutableMapping, MutableSequence, Optional, Sequence, Text, TextIO, Tuple, Type, Union # pylint: enable=unused-import except ImportError: pass @@ -206,11 +207,8 @@ ValueError: Raised when the flag or env value is not one of the options above. """ - if FLAGS.test_randomize_ordering_seed is not None: - randomize = FLAGS.test_randomize_ordering_seed - else: - randomize = os.environ.get('TEST_RANDOMIZE_ORDERING_SEED') - if randomize is None: + randomize = FLAGS.test_randomize_ordering_seed + if not randomize: return 0 if randomize == 'random': return random.Random().randint(1, 4294967295) @@ -238,12 +236,14 @@ flags.DEFINE_string('test_tmpdir', get_default_test_tmpdir(), 'Directory for temporary testing files', allow_override_cpp=True) -flags.DEFINE_string('test_randomize_ordering_seed', None, +flags.DEFINE_string('test_randomize_ordering_seed', + os.environ.get('TEST_RANDOMIZE_ORDERING_SEED', ''), 'If positive, use this as a seed to randomize the ' 'execution order for test cases. If "random", pick a ' 'random seed to use. If 0 or not set, do not randomize ' 'test case execution order. This flag also overrides ' - 'the TEST_RANDOMIZE_ORDERING_SEED environment variable.') + 'the TEST_RANDOMIZE_ORDERING_SEED environment variable.', + allow_override_cpp=True) flags.DEFINE_string('xml_output_file', '', 'File to store XML test results') @@ -325,6 +325,8 @@ # type: (Optional[Text], Optional[AnyStr], Text, Text, Text) -> _TempFile """Create a file in the directory. + NOTE: If the file already exists, it will be made writable and overwritten. + 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; @@ -390,6 +392,11 @@ cleanup_path = os.path.join(base_path, _get_first_part(file_path)) path = os.path.join(base_path, file_path) _makedirs_exist_ok(os.path.dirname(path)) + # The file may already exist, in which case, ensure it's writable so that + # it can be truncated. + if os.path.exists(path) and not os.access(path, os.W_OK): + stat_info = os.stat(path) + os.chmod(path, stat_info.st_mode | stat.S_IWUSR) else: _makedirs_exist_ok(base_path) fd, path = tempfile.mkstemp(dir=str(base_path)) @@ -477,7 +484,8 @@ 'file in text mode'.format(mode)) if 't' not in mode: mode += 't' - return self._open(mode, encoding, errors) + cm = self._open(mode, encoding, errors) # type: ContextManager[TextIO] + return cm def open_bytes(self, mode='rb'): # type: (Text) -> ContextManager[BinaryIO] @@ -498,11 +506,15 @@ 'file in binary mode'.format(mode)) if 'b' not in mode: mode += 'b' - return self._open(mode, encoding=None, errors=None) + cm = self._open(mode, encoding=None, errors=None) # type: ContextManager[BinaryIO] + return cm + # TODO(b/123775699): Once pytype supports typing.Literal, use overload and + # Literal to express more precise return types and remove the type comments in + # open_text and open_bytes. @contextlib.contextmanager def _open(self, mode, encoding='utf8', errors='strict'): - # type: (Text, Text, Text) -> Union[TextIO, BinaryIO] + # type: (Text, Text, Text) -> Iterator[Union[IO[Text], IO[bytes]]] with io.open( self.full_path, mode=mode, encoding=encoding, errors=errors) as fp: yield fp @@ -526,6 +538,15 @@ super(TestCase, self).__init__(*args, **kwargs) # This is to work around missing type stubs in unittest.pyi self._outcome = getattr(self, '_outcome') # type: Optional[_OutcomeType] + # This is re-initialized by setUp(). + self._exit_stack = None + + def setUp(self): + super(TestCase, self).setUp() + # NOTE: Only Py3 contextlib has ExitStack + if hasattr(contextlib, 'ExitStack'): + self._exit_stack = contextlib.ExitStack() + self.addCleanup(self._exit_stack.close) def create_tempdir(self, name=None, cleanup=None): # type: (Optional[Text], Optional[TempFileCleanup]) -> _TempDir @@ -583,8 +604,10 @@ NOTE: This will zero-out the file. This ensures there is no pre-existing state. + NOTE: If the file already exists, it will be made writable and overwritten. - See also: `create_tempdir()` for creating temporary directories. + See also: `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 @@ -615,6 +638,32 @@ self._maybe_add_temp_path_cleanup(cleanup_path, cleanup) return tf + def enter_context(self, manager): + """Returns the CM's value after registering it with the exit stack. + + Entering a context pushes it onto a stack of contexts. The context is exited + when the test completes. Contexts are are exited in the reverse order of + entering. They will always be exited, regardless of test failure/success. + The context stack is specific to the test being run. + + This is useful to eliminate per-test boilerplate when context managers + are used. For example, instead of decorating every test with `@mock.patch`, + simply do `self.foo = self.enter_context(mock.patch(...))' in `setUp()`. + + NOTE: The context managers will always be exited without any error + information. This is an unfortunate implementation detail due to some + internals of how unittest runs tests. + + Args: + manager: The context manager to enter. + """ + # type: (ContextManager[_T]) -> _T + if not self._exit_stack: + raise AssertionError( + 'self._exit_stack is not set: enter_context is Py3-only; also make ' + 'sure that AbslTest.setUp() is called.') + return self._exit_stack.enter_context(manager) + @classmethod def _get_tempdir_path_cls(cls): # type: () -> Text diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/parameterized.py new/abseil-py-pypi-v0.9.0/absl/testing/parameterized.py --- old/abseil-py-pypi-v0.8.0/absl/testing/parameterized.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/parameterized.py 2019-12-17 23:46:20.000000000 +0100 @@ -281,6 +281,10 @@ testcase_params = {k: v for k, v in six.iteritems(testcase_params) if k != _NAMED_DICT_KEY} elif _non_string_or_bytes_iterable(testcase_params): + if not isinstance(testcase_params[0], six.string_types): + raise RuntimeError( + 'The first element of named test parameters is the test name ' + 'suffix and must be a string') testcase_name = testcase_params[0] testcase_params = testcase_params[1:] else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/tests/absltest_test.py new/abseil-py-pypi-v0.9.0/absl/testing/tests/absltest_test.py --- old/abseil-py-pypi-v0.8.0/absl/testing/tests/absltest_test.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/tests/absltest_test.py 2019-12-17 23:46:20.000000000 +0100 @@ -19,6 +19,7 @@ from __future__ import print_function import collections +import contextlib import io import os import re @@ -1466,6 +1467,37 @@ self.assertRegex(stderr, 'No such file or directory') [email protected](six.PY2, 'Python 2 does not have ExitStack') +class EnterContextTest(absltest.TestCase): + + def setUp(self): + self.cm_state = 'unset' + self.cm_value = 'unset' + + def assert_cm_exited(): + self.assertEqual(self.cm_state, 'exited') + + # Because cleanup functions are run in reverse order, we have to add + # our assert-cleanup before the exit stack registers its own cleanup. + # This ensures we see state after the stack cleanup runs. + self.addCleanup(assert_cm_exited) + + super(EnterContextTest, self).setUp() + self.cm_value = self.enter_context(self.cm_for_test()) + + @contextlib.contextmanager + def cm_for_test(self): + try: + self.cm_state = 'yielded' + yield 'value' + finally: + self.cm_state = 'exited' + + def test_enter_context(self): + self.assertEqual(self.cm_value, 'value') + self.assertEqual(self.cm_state, 'yielded') + + class EqualityAssertionTest(absltest.TestCase): """This test verifies that absltest.failIfEqual actually tests __ne__. @@ -2005,6 +2037,13 @@ } self.assertEqual(expected_paths, actual, output) + def test_create_file_pre_existing_readonly(self): + first = self.create_tempfile('foo', content='first') + os.chmod(first.full_path, 0o444) + second = self.create_tempfile('foo', content='second') + self.assertEqual('second', first.read_text()) + self.assertEqual('second', second.read_text()) + def test_unnamed(self): td = self.create_tempdir() self.assert_dir_exists(td) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/tests/parameterized_test.py new/abseil-py-pypi-v0.9.0/absl/testing/tests/parameterized_test.py --- old/abseil-py-pypi-v0.8.0/absl/testing/tests/parameterized_test.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/tests/parameterized_test.py 2019-12-17 23:46:20.000000000 +0100 @@ -18,6 +18,7 @@ from __future__ import division from __future__ import print_function +import sys import unittest from absl._collections_abc import abc @@ -389,6 +390,10 @@ class SubclassTestCase(SuperclassTestCase): pass + @unittest.skipIf( + (sys.version_info[:2] == (3, 7) and sys.version_info[2] in {0, 1, 2}), + 'Python 3.7.0 to 3.7.2 have a bug that breaks this test, see ' + 'https://bugs.python.org/issue35767') def test_missing_inheritance(self): ts = unittest.makeSuite(self.BadAdditionParams) self.assertEqual(1, ts.countTestCases()) @@ -672,6 +677,28 @@ def test_mixed_something(self, unused_obj): pass + def test_named_test_with_no_name_fails(self): + with self.assertRaises(RuntimeError): + + class _(parameterized.TestCase): + + @parameterized.named_parameters( + (0,), + ) + def test_something(self, unused_obj): + pass + + def test_named_test_dict_with_no_name_fails(self): + with self.assertRaises(RuntimeError): + + class _(parameterized.TestCase): + + @parameterized.named_parameters( + {'unused_obj': 0}, + ) + def test_something(self, unused_obj): + pass + def test_parameterized_test_iter_has_testcases_property(self): @parameterized.parameters(1, 2, 3, 4, 5, 6) def test_something(unused_self, unused_obj): # pylint: disable=invalid-name diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/tests/xml_reporter_test.py new/abseil-py-pypi-v0.9.0/absl/testing/tests/xml_reporter_test.py --- old/abseil-py-pypi-v0.8.0/absl/testing/tests/xml_reporter_test.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/tests/xml_reporter_test.py 2019-12-17 23:46:20.000000000 +0100 @@ -158,6 +158,9 @@ result.addSuccess(test) result.stopTest(test) + def _iso_timestamp(self, timestamp): + return datetime.datetime.utcfromtimestamp(timestamp).isoformat() + '+00:00' + def test_with_passing_test(self): start_time = 0 end_time = 2 @@ -173,30 +176,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'passing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - '' + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'passing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': '' } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -218,30 +209,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - r'passing_test \[msg\]', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - '' + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': r'passing_test \[msg\]', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': '' } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -279,7 +258,7 @@ 'run_time': run_time, 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), + re.escape(self._iso_timestamp(start_time),), 'test_name': r'passing_test \[msg\] \(case='a.b.c'\)', 'classname': @@ -345,30 +324,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 1, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - FAILURE_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 1, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': FAILURE_MESSAGE } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -390,30 +357,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 1, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - r'failing_test \[msg\]', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - FAILURE_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 1, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': r'failing_test \[msg\]', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': FAILURE_MESSAGE } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -435,30 +390,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 1, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - ERROR_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 1, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': ERROR_MESSAGE } self._assert_match(expected_re, xml) @@ -480,30 +423,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 1, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - r'error_test \[msg\]', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - ERROR_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 1, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': r'error_test \[msg\]', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': ERROR_MESSAGE } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -528,31 +459,19 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 1, # Only the failure is tallied (because it was first). - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 1, # Only the failure is tallied (because it was first). + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', # Messages from failure and error should be concatenated in order. - 'message': - FAILURE_MESSAGE + ERROR_MESSAGE + 'message': FAILURE_MESSAGE + ERROR_MESSAGE } self._assert_match(expected_re, xml) @@ -576,31 +495,19 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 1, # Only the error is tallied (because it was first). - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 1, # Only the error is tallied (because it was first). + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', # Messages from error and failure should be concatenated in order. - 'message': - ERROR_MESSAGE + FAILURE_MESSAGE + 'message': ERROR_MESSAGE + FAILURE_MESSAGE } self._assert_match(expected_re, xml) @@ -622,30 +529,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 1, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - NEWLINE_ERROR_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 1, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': NEWLINE_ERROR_MESSAGE } + '\n' self._assert_match(expected_re, xml) @@ -667,30 +562,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 1, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - UNICODE_ERROR_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 1, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': UNICODE_ERROR_MESSAGE } self._assert_match(expected_re, xml) @@ -730,30 +613,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'expected_failing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - '' + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'expected_failing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': '' } self._assert_match(re.compile(expected_re, re.DOTALL), self.xml_stream.getvalue()) @@ -773,30 +644,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 1, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'unexpectedly_passing_test', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - UNEXPECTED_SUCCESS_MESSAGE + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 1, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'unexpectedly_passing_test', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': UNEXPECTED_SUCCESS_MESSAGE } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -815,28 +674,17 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'skipped_test_with_reason', - 'classname': - '__main__.MockTest', - 'status': - 'notrun', - 'result': - 'suppressed', - 'message': - '' + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'skipped_test_with_reason', + 'classname': '__main__.MockTest', + 'status': 'notrun', + 'result': 'suppressed', + 'message': '' } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -863,7 +711,7 @@ result.printErrors() run_time = max(end_time1, end_time2) - min(start_time1, start_time2) - timestamp = datetime.datetime.utcfromtimestamp(start_time1).isoformat() + timestamp = self._iso_timestamp(start_time1) expected_prefix = """<?xml version="1.0"?> <testsuites name="" tests="2" failures="0" errors="0" time="%.1f" timestamp="%s"> <testsuite name="MockTest" tests="2" failures="0" errors="0" time="%.1f" timestamp="%s"> @@ -888,30 +736,18 @@ run_time = end_time - start_time expected_re = OUTPUT_STRING % { - 'suite_name': - 'MockTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - 'bad_name', - 'classname': - '__main__.MockTest', - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - '' + 'suite_name': 'MockTest', + 'tests': 1, + 'failures': 0, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': 'bad_name', + 'classname': '__main__.MockTest', + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': '' } self._assert_match(expected_re, self.xml_stream.getvalue()) @@ -944,30 +780,18 @@ classname = xml_reporter._escape_xml_attr( unittest.util.strclass(test.__class__)) expected_re = OUTPUT_STRING % { - 'suite_name': - 'ParameterizedTest', - 'tests': - 1, - 'failures': - 0, - 'errors': - 0, - 'run_time': - run_time, - 'start_time': - datetime.datetime.utcfromtimestamp(start_time).isoformat(), - 'test_name': - re.escape('test_prefix('a (b.c)')'), - 'classname': - classname, - 'status': - 'run', - 'result': - 'completed', - 'attributes': - '', - 'message': - '' + 'suite_name': 'ParameterizedTest', + 'tests': 1, + 'failures': 0, + 'errors': 0, + 'run_time': run_time, + 'start_time': re.escape(self._iso_timestamp(start_time),), + 'test_name': re.escape('test_prefix('a (b.c)')'), + 'classname': classname, + 'status': 'run', + 'result': 'completed', + 'attributes': '', + 'message': '' } self._assert_match(expected_re, self.xml_stream.getvalue()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/absl/testing/xml_reporter.py new/abseil-py-pypi-v0.9.0/absl/testing/xml_reporter.py --- old/abseil-py-pypi-v0.8.0/absl/testing/xml_reporter.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/absl/testing/xml_reporter.py 2019-12-17 23:46:20.000000000 +0100 @@ -91,7 +91,13 @@ """ if timestamp is None or timestamp < 0: return None - return datetime.datetime.utcfromtimestamp(timestamp).isoformat() + # Use utcfromtimestamp in PY2 because it doesn't have a built-in UTC object + if six.PY2: + return '%s+00:00' % datetime.datetime.utcfromtimestamp( + timestamp).isoformat() + else: + return datetime.datetime.fromtimestamp( + timestamp, tz=datetime.timezone.utc).isoformat() def _print_xml_element_header(element, attributes, stream, indentation=''): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/abseil-py-pypi-v0.8.0/setup.py new/abseil-py-pypi-v0.9.0/setup.py --- old/abseil-py-pypi-v0.8.0/setup.py 2019-08-27 00:20:23.000000000 +0200 +++ new/abseil-py-pypi-v0.9.0/setup.py 2019-12-17 23:46:20.000000000 +0100 @@ -64,7 +64,7 @@ setuptools.setup( name='absl-py', - version='0.8.0', + version='0.9.0', description=( 'Abseil Python Common Libraries, ' 'see https://github.com/abseil/abseil-py.'), @@ -86,6 +86,7 @@ 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Intended Audience :: Developers', 'Topic :: Software Development :: Libraries :: Python Modules', 'License :: OSI Approved :: Apache Software License',
