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&#x20;\[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&#x20;\[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&#x20;\[msg\]&#x20;\(case=&apos;a.b.c&apos;\)',
         '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&#x20;\[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&#x20;\[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&#x20;\[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&#x20;\[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(&apos;a&#x20;(b.c)&apos;)'),
-        '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(&apos;a&#x20;(b.c)&apos;)'),
+        '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',


Reply via email to