diff options
author | Yilei Yang (杨一磊) <yileiyang@google.com> | 2022-03-29 18:54:58 +0000 |
---|---|---|
committer | Yilei Yang (杨一磊) <yileiyang@google.com> | 2022-03-29 18:54:58 +0000 |
commit | bb7e02c301813d6543a590eebe46dc65d0e6136c (patch) | |
tree | d026deb8daab98f63787cc22986026643e59251d | |
parent | 3e4749af698201224165a98930c6845d8c102e0d (diff) | |
parent | f6122a6f743fcc0402a9f7a27ae5d9ccb5e45c4e (diff) | |
download | absl-py-bb7e02c301813d6543a590eebe46dc65d0e6136c.tar.gz |
Merge commit for internal changes.
-rw-r--r-- | CHANGELOG.md | 4 | ||||
-rw-r--r-- | WORKSPACE | 17 | ||||
-rw-r--r-- | absl/BUILD | 1 | ||||
-rw-r--r-- | absl/flags/BUILD | 3 | ||||
-rw-r--r-- | absl/flags/_defines.py | 2 | ||||
-rw-r--r-- | absl/flags/_flag.py | 4 | ||||
-rw-r--r-- | absl/flags/_flagvalues.py | 8 | ||||
-rw-r--r-- | absl/flags/tests/_flag_test.py | 16 | ||||
-rw-r--r-- | absl/flags/tests/flags_helpxml_test.py | 4 | ||||
-rw-r--r-- | absl/flags/tests/flags_numeric_bounds_test.py | 6 | ||||
-rw-r--r-- | absl/flags/tests/flags_test.py | 29 | ||||
-rw-r--r-- | absl/logging/BUILD | 4 | ||||
-rw-r--r-- | absl/logging/__init__.py | 61 | ||||
-rw-r--r-- | absl/logging/converter.py | 4 | ||||
-rw-r--r-- | absl/logging/tests/log_before_import_test.py | 6 | ||||
-rw-r--r-- | absl/logging/tests/logging_functional_test.py | 4 | ||||
-rw-r--r-- | absl/logging/tests/logging_functional_test_helper.py | 3 | ||||
-rw-r--r-- | absl/logging/tests/logging_test.py | 46 | ||||
-rw-r--r-- | absl/testing/BUILD | 5 | ||||
-rw-r--r-- | absl/testing/absltest.py | 209 | ||||
-rw-r--r-- | absl/testing/parameterized.py | 24 | ||||
-rw-r--r-- | absl/testing/xml_reporter.py | 18 | ||||
-rw-r--r-- | absl/tests/command_name_test.py | 6 | ||||
-rw-r--r-- | third_party/mock.BUILD | 13 |
24 files changed, 211 insertions, 286 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cdfa92..7b41a67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com). ## Unreleased -Nothing notable unreleased. +* `Flag` instances now raise an error if used in a bool context. This prevents + the occasional mistake of testing an instance for truthiness rather than + testing `flag.value`. ## 1.0.0 (2021-11-09) @@ -17,22 +17,11 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "six_archive", - urls = [ - "http://mirror.bazel.build/pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz", - "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz", - ], + build_file = "@//third_party:six.BUILD", sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a", strip_prefix = "six-1.10.0", - build_file = "@//third_party:six.BUILD", -) - -http_archive( - name = "mock_archive", urls = [ - "http://mirror.bazel.build/pypi.python.org/packages/a2/52/7edcd94f0afb721a2d559a5b9aae8af4f8f2c79bc63fdbe8a8a6c9b23bbe/mock-1.0.1.tar.gz", - "https://pypi.python.org/packages/a2/52/7edcd94f0afb721a2d559a5b9aae8af4f8f2c79bc63fdbe8a8a6c9b23bbe/mock-1.0.1.tar.gz", + "http://mirror.bazel.build/pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz", + "https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz", ], - sha256 = "b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f", - strip_prefix = "mock-1.0.1", - build_file = "@//third_party:mock.BUILD", ) @@ -76,7 +76,6 @@ py_test( deps = [ ":command_name", "//absl/testing:absltest", - "@mock_archive//:mock", ], ) diff --git a/absl/flags/BUILD b/absl/flags/BUILD index d54af1d..c180599 100644 --- a/absl/flags/BUILD +++ b/absl/flags/BUILD @@ -1,4 +1,4 @@ -licenses(["notice"]) # Apache 2.0 +licenses(["notice"]) py_library( name = "flags", @@ -256,7 +256,6 @@ py_test( ":_validators", ":flags", "//absl/testing:absltest", - "@mock_archive//:mock", ], ) diff --git a/absl/flags/_defines.py b/absl/flags/_defines.py index f655714..4494c3b 100644 --- a/absl/flags/_defines.py +++ b/absl/flags/_defines.py @@ -798,7 +798,7 @@ def DEFINE_multi_enum( # pylint: disable=invalid-name,redefined-builtin serializer, name, default, - help, + '<%s>: %s' % ('|'.join(enum_values), help), flag_values, required=required, **args) diff --git a/absl/flags/_flag.py b/absl/flags/_flag.py index a893b22..a1c53ff 100644 --- a/absl/flags/_flag.py +++ b/absl/flags/_flag.py @@ -128,6 +128,10 @@ class Flag(object): return id(self) < id(other) return NotImplemented + def __bool__(self): + raise TypeError('A Flag instance would always be True. ' + 'Did you mean to test the `.value` attribute?') + def __getstate__(self): raise TypeError("can't pickle Flag objects") diff --git a/absl/flags/_flagvalues.py b/absl/flags/_flagvalues.py index dab6091..c9be720 100644 --- a/absl/flags/_flagvalues.py +++ b/absl/flags/_flagvalues.py @@ -774,7 +774,7 @@ class FlagValues(object): continue flag = flag_dict.get(name) - if flag: + if flag is not None: if flag.boolean and value is None: value = 'true' else: @@ -782,13 +782,13 @@ class FlagValues(object): elif name.startswith('no') and len(name) > 2: # Boolean flags can take the form of --noflag, with no value. noflag = flag_dict.get(name[2:]) - if noflag and noflag.boolean: + if noflag is not None and noflag.boolean: if value is not None: raise ValueError(arg + ' does not take an argument') flag = noflag value = 'false' - if retired_flag_func and not flag: + if retired_flag_func and flag is None: is_retired, is_bool = retired_flag_func(name) # If we didn't recognize that flag, but it starts with @@ -808,7 +808,7 @@ class FlagValues(object): 'be specified. See go/totw/90.', name) continue - if flag: + if flag is not None: flag.parse(value) flag.using_default_value = False else: diff --git a/absl/flags/tests/_flag_test.py b/absl/flags/tests/_flag_test.py index 800a00c..492f117 100644 --- a/absl/flags/tests/_flag_test.py +++ b/absl/flags/tests/_flag_test.py @@ -35,6 +35,7 @@ from absl.testing import parameterized class FlagTest(absltest.TestCase): def setUp(self): + super().setUp() self.flag = _flag.Flag( _argument_parser.ArgumentParser(), _argument_parser.ArgumentSerializer(), @@ -59,6 +60,11 @@ class FlagTest(absltest.TestCase): 'number', 1, 'help') self.assertEqual(1, flag.default_unparsed) + def test_no_truthiness(self): + with self.assertRaises(TypeError): + if self.flag: + self.fail('Flag instances must raise rather than be truthy.') + def test_set_default_overrides_current_value(self): self.assertEqual('apple', self.flag.value) self.flag._set_default('orange') @@ -71,14 +77,14 @@ class FlagTest(absltest.TestCase): self.assertEqual('apple', self.flag.value) def test_pickle(self): - with self.assertRaisesRegexp(TypeError, "can't pickle Flag objects"): + with self.assertRaisesRegex(TypeError, "can't pickle Flag objects"): pickle.dumps(self.flag) def test_copy(self): self.flag.value = 'orange' - with self.assertRaisesRegexp( - TypeError, 'Flag does not support shallow copies'): + with self.assertRaisesRegex(TypeError, + 'Flag does not support shallow copies'): copy.copy(self.flag) flag2 = copy.deepcopy(self.flag) @@ -172,10 +178,10 @@ class EnumClassFlagTest(parameterized.TestCase): class MultiEnumClassFlagTest(parameterized.TestCase): @parameterized.named_parameters( - ('NoHelpSupplied', '', '<apple|orange>: (no help available);\n ' + ('NoHelpSupplied', '', '<apple|orange>: (no help available);\n ' + 'repeat this option to specify a list of values', False), ('WithHelpSupplied', 'Type of fruit.', - '<APPLE|ORANGE>: Type of fruit.;\n ' + '<APPLE|ORANGE>: Type of fruit.;\n ' + 'repeat this option to specify a list of values', True)) def test_help_text(self, helptext_input, helptext_output, case_sensitive): f = _flag.MultiEnumClassFlag( diff --git a/absl/flags/tests/flags_helpxml_test.py b/absl/flags/tests/flags_helpxml_test.py index 424c3dd..e2168ac 100644 --- a/absl/flags/tests/flags_helpxml_test.py +++ b/absl/flags/tests/flags_helpxml_test.py @@ -340,7 +340,7 @@ class FlagCreateXMLDOMElement(absltest.TestCase): '<flag>\n' ' <file>tool</file>\n' ' <name>flavours</name>\n' - ' <meaning>Compilation flavour.;\n' + ' <meaning><APPLE|BANANA|CHERRY>: Compilation flavour.;\n' ' repeat this option to specify a list of values</meaning>\n' ' <default>[\'APPLE\', \'BANANA\']</default>\n' ' <current>[\'APPLE\', \'BANANA\']</current>\n' @@ -474,7 +474,7 @@ EXPECTED_HELP_XML_FOR_FLAGS_FROM_MAIN_MODULE = """\ <key>yes</key> <file>%(main_module_name)s</file> <name>flavours</name> - <meaning>Compilation flavour.; + <meaning><APPLE|BANANA|CHERRY>: Compilation flavour.; repeat this option to specify a list of values</meaning> <default>['APPLE', 'BANANA']</default> <current>['APPLE', 'BANANA']</current> diff --git a/absl/flags/tests/flags_numeric_bounds_test.py b/absl/flags/tests/flags_numeric_bounds_test.py index 5743258..d3c2a95 100644 --- a/absl/flags/tests/flags_numeric_bounds_test.py +++ b/absl/flags/tests/flags_numeric_bounds_test.py @@ -14,14 +14,10 @@ """Tests for lower/upper bounds validators for numeric flags.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - +from unittest import mock from absl import flags from absl.flags import _validators from absl.testing import absltest -import mock class NumericFlagBoundsTest(absltest.TestCase): diff --git a/absl/flags/tests/flags_test.py b/absl/flags/tests/flags_test.py index 75a61d5..8a42bc9 100644 --- a/absl/flags/tests/flags_test.py +++ b/absl/flags/tests/flags_test.py @@ -1511,6 +1511,20 @@ class MultiEnumFlagsTest(absltest.TestCase): fv(argv) self.assertListEqual(fv.get_flag_value('m_enum', None), ['WHOOSH', 'FOO']) + def test_help_text(self): + """Test multi_enum flag's help text.""" + fv = flags.FlagValues() + + flags.DEFINE_multi_enum( + 'm_enum', + None, ['FOO', 'BAR'], + 'Enum option that can occur multiple times', + flag_values=fv) + self.assertRegex( + fv['m_enum'].help, + r'<FOO\|BAR>: Enum option that can occur multiple times;\s+' + 'repeat this option to specify a list of values') + def test_single_value_default(self): """Test multi_enum flags with a single default value.""" fv = flags.FlagValues() @@ -1590,6 +1604,21 @@ class MultiEnumClassFlagsTest(absltest.TestCase): self.assertIsNone(fv.fruit) + def test_help_text(self): + fv = flags.FlagValues() + enum_defaults = None + flags.DEFINE_multi_enum_class( + 'fruit', + enum_defaults, + Fruit, + 'Enum option that can occur multiple times', + flag_values=fv) + + self.assertRegex( + fv['fruit'].help, + r'<apple\|orange>: Enum option that can occur multiple times;\s+' + 'repeat this option to specify a list of values') + def test_define_results_in_registered_flag_with_string(self): fv = flags.FlagValues() enum_defaults = 'apple' diff --git a/absl/logging/BUILD b/absl/logging/BUILD index d83a2b6..e666d7a 100644 --- a/absl/logging/BUILD +++ b/absl/logging/BUILD @@ -1,4 +1,4 @@ -licenses(["notice"]) # Apache 2.0 +licenses(["notice"]) py_library( name = "logging", @@ -9,7 +9,6 @@ py_library( ":converter", "//absl:_collections_abc", "//absl/flags", - "@six_archive//:six", ], ) @@ -57,7 +56,6 @@ py_test( deps = [ ":logging", "//absl/testing:absltest", - "@mock_archive//:mock", ], ) diff --git a/absl/logging/__init__.py b/absl/logging/__init__.py index c79643f..a475bd5 100644 --- a/absl/logging/__init__.py +++ b/absl/logging/__init__.py @@ -71,10 +71,6 @@ program. The differences in behavior are historical and unfortunate. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import collections import getpass import io @@ -84,6 +80,7 @@ import os import socket import struct import sys +import threading import time import timeit import traceback @@ -93,12 +90,6 @@ import warnings from absl import flags from absl._collections_abc import abc from absl.logging import converter -import six - -if six.PY2: - import thread as _thread_lib # For .get_ident(). -else: - import threading as _thread_lib # For .get_ident(). try: from typing import NoReturn @@ -257,7 +248,7 @@ class _LoggerLevelsSerializer(object): """Serializer for --logger_levels flag.""" def serialize(self, value): - if isinstance(value, six.string_types): + if isinstance(value, str): return value return ','.join( '{}:{}'.format(name, level) for name, level in value.items()) @@ -399,15 +390,11 @@ def warning(msg, *args, **kwargs): log(WARNING, msg, *args, **kwargs) -if six.PY2: - warn = warning # Deprecated function. -else: - - def warn(msg, *args, **kwargs): - """Deprecated, use 'warning' instead.""" - warnings.warn("The 'warn' function is deprecated, use 'warning' instead", - DeprecationWarning, 2) - log(WARNING, msg, *args, **kwargs) +def warn(msg, *args, **kwargs): + """Deprecated, use 'warning' instead.""" + warnings.warn("The 'warn' function is deprecated, use 'warning' instead", + DeprecationWarning, 2) + log(WARNING, msg, *args, **kwargs) def info(msg, *args, **kwargs): @@ -729,8 +716,7 @@ def find_log_dir(log_dir=None): for d in dirs: if os.path.isdir(d) and os.access(d, os.W_OK): return d - exception_class = OSError if six.PY2 else FileNotFoundError - raise exception_class( + raise FileNotFoundError( "Can't find a writable directory for logs, tried %s" % dirs) @@ -795,7 +781,7 @@ def skip_log_prefix(func): file_name = func_code.co_filename func_name = func_code.co_name func_lineno = func_code.co_firstlineno - elif isinstance(func, six.string_types): + elif isinstance(func, str): file_name = get_absl_logger().findCaller()[0] func_name = func func_lineno = None @@ -839,10 +825,7 @@ class PythonHandler(logging.StreamHandler): os.getpid()) filename = os.path.join(actual_log_dir, basename) - if six.PY2: - self.stream = open(filename, 'a') - else: - self.stream = open(filename, 'a', encoding='utf-8') + self.stream = open(filename, 'a', encoding='utf-8') # os.symlink is not available on Windows Python 2. if getattr(os, 'symlink', None): @@ -1072,16 +1055,13 @@ class ABSLLogger(logging.getLoggerClass()): (code.co_filename, code.co_name, code.co_firstlineno) not in f_to_skip and (code.co_filename, code.co_name) not in f_to_skip): - if six.PY2 and not stack_info: - return (code.co_filename, frame.f_lineno, code.co_name) - else: - sinfo = None - if stack_info: - out = io.StringIO() - out.write(u'Stack (most recent call last):\n') - traceback.print_stack(frame, file=out) - sinfo = out.getvalue().rstrip(u'\n') - return (code.co_filename, frame.f_lineno, code.co_name, sinfo) + sinfo = None + if stack_info: + out = io.StringIO() + out.write(u'Stack (most recent call last):\n') + traceback.print_stack(frame, file=out) + sinfo = out.getvalue().rstrip(u'\n') + return (code.co_filename, frame.f_lineno, code.co_name, sinfo) frame = frame.f_back def critical(self, msg, *args, **kwargs): @@ -1098,9 +1078,8 @@ class ABSLLogger(logging.getLoggerClass()): def warn(self, msg, *args, **kwargs): """Logs 'msg % args' with severity 'WARN'.""" - if six.PY3: - warnings.warn("The 'warn' method is deprecated, use 'warning' instead", - DeprecationWarning, 2) + warnings.warn("The 'warn' method is deprecated, use 'warning' instead", + DeprecationWarning, 2) self.log(logging.WARN, msg, *args, **kwargs) def warning(self, msg, *args, **kwargs): @@ -1183,7 +1162,7 @@ def _get_thread_id(): Returns: Thread ID unique to this process (unsigned) """ - thread_id = _thread_lib.get_ident() + thread_id = threading.get_ident() return thread_id & _THREAD_ID_MASK diff --git a/absl/logging/converter.py b/absl/logging/converter.py index 87f4324..53dd46d 100644 --- a/absl/logging/converter.py +++ b/absl/logging/converter.py @@ -43,10 +43,6 @@ representation, before manipulating the levels, and then only to cpp or absl if those level schemes are absolutely necessary. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import logging STANDARD_CRITICAL = logging.CRITICAL diff --git a/absl/logging/tests/log_before_import_test.py b/absl/logging/tests/log_before_import_test.py index d1ba61f..903af16 100644 --- a/absl/logging/tests/log_before_import_test.py +++ b/absl/logging/tests/log_before_import_test.py @@ -14,20 +14,16 @@ """Test of logging behavior before app.run(), aka flag and logging init().""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import contextlib import io import os import re import sys import tempfile +from unittest import mock from absl import logging from absl.testing import absltest -import mock logging.get_verbosity() # Access --verbosity before flag parsing. # Access --logtostderr before flag parsing. diff --git a/absl/logging/tests/logging_functional_test.py b/absl/logging/tests/logging_functional_test.py index faa0de4..98a2fab 100644 --- a/absl/logging/tests/logging_functional_test.py +++ b/absl/logging/tests/logging_functional_test.py @@ -324,6 +324,7 @@ class FunctionalTest(parameterized.TestCase): pass_logtostderr=False, use_absl_log_file=False, show_info_prefix=1, + call_dict_config=False, extra_args=()): """Execute the helper script and verify its output. @@ -343,6 +344,8 @@ class FunctionalTest(parameterized.TestCase): logging.get_absl_handler().use_absl_log_file() before test_fn in logging_functional_test_helper. show_info_prefix: --showprefixforinfo value passed to the helper script. + call_dict_config: True if helper script should call + logging.config.dictConfig. extra_args: Iterable of str (optional, defaults to ()) - extra arguments to pass to the helper script. @@ -361,6 +364,7 @@ class FunctionalTest(parameterized.TestCase): env.update({ 'TEST_NAME': test_name, 'USE_ABSL_LOG_FILE': '%d' % (use_absl_log_file,), + 'CALL_DICT_CONFIG': '%d' % (call_dict_config,), }) cmd = [self._get_helper()] + args diff --git a/absl/logging/tests/logging_functional_test_helper.py b/absl/logging/tests/logging_functional_test_helper.py index 0eccc74..b95647b 100644 --- a/absl/logging/tests/logging_functional_test_helper.py +++ b/absl/logging/tests/logging_functional_test_helper.py @@ -15,6 +15,7 @@ """Helper script for logging_functional_test.""" import logging as std_logging +import logging.config as std_logging_config import os import sys import threading @@ -306,4 +307,6 @@ def main(argv): if __name__ == '__main__': sys.argv[0] = 'py_argv_0' + if os.environ.get('CALL_DICT_CONFIG') == '1': + std_logging_config.dictConfig({'version': 1}) app.run(main) diff --git a/absl/logging/tests/logging_test.py b/absl/logging/tests/logging_test.py index c399f37..e5c4fcc 100644 --- a/absl/logging/tests/logging_test.py +++ b/absl/logging/tests/logging_test.py @@ -366,6 +366,7 @@ class PythonHandlerTest(absltest.TestCase): class ABSLHandlerTest(absltest.TestCase): def setUp(self): + super().setUp() formatter = logging.PythonFormatter() self.absl_handler = logging.ABSLHandler(formatter) @@ -438,12 +439,14 @@ class ABSLLoggerTest(absltest.TestCase): sys._getframe.return_value = mock_frame_0 def setUp(self): + super().setUp() self.message = 'Hello Nurse' self.logger = logging.ABSLLogger('') def tearDown(self): mock.patch.stopall() self.logger._frames_to_skip.clear() + super().tearDown() def test_constructor_without_level(self): self.logger = logging.ABSLLogger('') @@ -579,6 +582,7 @@ class ABSLLoggerTest(absltest.TestCase): class ABSLLogPrefixTest(parameterized.TestCase): def setUp(self): + super().setUp() self.record = std_logging.LogRecord( 'name', std_logging.INFO, 'path/to/source.py', 13, 'log message', None, None) @@ -804,28 +808,28 @@ class LoggingTest(absltest.TestCase): old_level = logging.get_verbosity() logging.set_verbosity(logging.DEBUG) - self.assertEquals(logging.get_verbosity(), logging.DEBUG) + self.assertEqual(logging.get_verbosity(), logging.DEBUG) self.assertTrue(logging.level_debug()) self.assertTrue(logging.level_info()) self.assertTrue(logging.level_warning()) self.assertTrue(logging.level_error()) logging.set_verbosity(logging.INFO) - self.assertEquals(logging.get_verbosity(), logging.INFO) + self.assertEqual(logging.get_verbosity(), logging.INFO) self.assertFalse(logging.level_debug()) self.assertTrue(logging.level_info()) self.assertTrue(logging.level_warning()) self.assertTrue(logging.level_error()) logging.set_verbosity(logging.WARNING) - self.assertEquals(logging.get_verbosity(), logging.WARNING) + self.assertEqual(logging.get_verbosity(), logging.WARNING) self.assertFalse(logging.level_debug()) self.assertFalse(logging.level_info()) self.assertTrue(logging.level_warning()) self.assertTrue(logging.level_error()) logging.set_verbosity(logging.ERROR) - self.assertEquals(logging.get_verbosity(), logging.ERROR) + self.assertEqual(logging.get_verbosity(), logging.ERROR) self.assertFalse(logging.level_debug()) self.assertFalse(logging.level_info()) self.assertTrue(logging.level_error()) @@ -837,43 +841,43 @@ class LoggingTest(absltest.TestCase): # Lowercase names. logging.set_verbosity('debug') - self.assertEquals(logging.get_verbosity(), logging.DEBUG) + self.assertEqual(logging.get_verbosity(), logging.DEBUG) logging.set_verbosity('info') - self.assertEquals(logging.get_verbosity(), logging.INFO) + self.assertEqual(logging.get_verbosity(), logging.INFO) logging.set_verbosity('warning') - self.assertEquals(logging.get_verbosity(), logging.WARNING) + self.assertEqual(logging.get_verbosity(), logging.WARNING) logging.set_verbosity('warn') - self.assertEquals(logging.get_verbosity(), logging.WARNING) + self.assertEqual(logging.get_verbosity(), logging.WARNING) logging.set_verbosity('error') - self.assertEquals(logging.get_verbosity(), logging.ERROR) + self.assertEqual(logging.get_verbosity(), logging.ERROR) logging.set_verbosity('fatal') # Uppercase names. - self.assertEquals(logging.get_verbosity(), logging.FATAL) + self.assertEqual(logging.get_verbosity(), logging.FATAL) logging.set_verbosity('DEBUG') - self.assertEquals(logging.get_verbosity(), logging.DEBUG) + self.assertEqual(logging.get_verbosity(), logging.DEBUG) logging.set_verbosity('INFO') - self.assertEquals(logging.get_verbosity(), logging.INFO) + self.assertEqual(logging.get_verbosity(), logging.INFO) logging.set_verbosity('WARNING') - self.assertEquals(logging.get_verbosity(), logging.WARNING) + self.assertEqual(logging.get_verbosity(), logging.WARNING) logging.set_verbosity('WARN') - self.assertEquals(logging.get_verbosity(), logging.WARNING) + self.assertEqual(logging.get_verbosity(), logging.WARNING) logging.set_verbosity('ERROR') - self.assertEquals(logging.get_verbosity(), logging.ERROR) + self.assertEqual(logging.get_verbosity(), logging.ERROR) logging.set_verbosity('FATAL') - self.assertEquals(logging.get_verbosity(), logging.FATAL) + self.assertEqual(logging.get_verbosity(), logging.FATAL) # Integers as strings. logging.set_verbosity(str(logging.DEBUG)) - self.assertEquals(logging.get_verbosity(), logging.DEBUG) + self.assertEqual(logging.get_verbosity(), logging.DEBUG) logging.set_verbosity(str(logging.INFO)) - self.assertEquals(logging.get_verbosity(), logging.INFO) + self.assertEqual(logging.get_verbosity(), logging.INFO) logging.set_verbosity(str(logging.WARNING)) - self.assertEquals(logging.get_verbosity(), logging.WARNING) + self.assertEqual(logging.get_verbosity(), logging.WARNING) logging.set_verbosity(str(logging.ERROR)) - self.assertEquals(logging.get_verbosity(), logging.ERROR) + self.assertEqual(logging.get_verbosity(), logging.ERROR) logging.set_verbosity(str(logging.FATAL)) - self.assertEquals(logging.get_verbosity(), logging.FATAL) + self.assertEqual(logging.get_verbosity(), logging.FATAL) logging.set_verbosity(old_level) diff --git a/absl/testing/BUILD b/absl/testing/BUILD index de77bcc..6dbbaea 100644 --- a/absl/testing/BUILD +++ b/absl/testing/BUILD @@ -1,4 +1,4 @@ -licenses(["notice"]) # Apache 2.0 +licenses(["notice"]) py_library( name = "absltest", @@ -12,7 +12,6 @@ py_library( "//absl:app", "//absl/flags", "//absl/logging", - "@six_archive//:six", ], ) @@ -36,7 +35,6 @@ py_library( deps = [ ":absltest", "//absl:_collections_abc", - "@six_archive//:six", ], ) @@ -47,7 +45,6 @@ py_library( visibility = ["//visibility:public"], deps = [ ":_pretty_print_reporter", - "@six_archive//:six", ], ) diff --git a/absl/testing/absltest.py b/absl/testing/absltest.py index 1ade38e..1303fd4 100644 --- a/absl/testing/absltest.py +++ b/absl/testing/absltest.py @@ -18,10 +18,6 @@ This module contains base classes and high-level functions for Abseil-style tests. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import contextlib import difflib import enum @@ -43,6 +39,8 @@ import sys import tempfile import textwrap import unittest +from unittest import mock # pylint: disable=unused-import Allow absltest.mock. +from urllib import parse try: # The faulthandler module isn't always available, and pytype doesn't @@ -60,9 +58,6 @@ from absl import logging from absl._collections_abc import abc from absl.testing import _pretty_print_reporter from absl.testing import xml_reporter -import six -from six.moves import urllib -from six.moves import xrange # pylint: disable=redefined-builtin # Make typing an optional import to avoid it being a required dependency # in Python 2. Type checkers will still understand the imports. @@ -84,14 +79,6 @@ else: _OutcomeType = unittest.case._Outcome # pytype: disable=module-attr -if six.PY3: - from unittest import mock # pylint: disable=unused-import -else: - try: - import mock # type: ignore - except ImportError: - mock = None - # Re-export a bunch of unittest functions we support so that people don't # have to import unittest to get them @@ -107,7 +94,7 @@ expectedFailure = unittest.expectedFailure FLAGS = flags.FLAGS -_TEXT_OR_BINARY_TYPES = (six.text_type, six.binary_type) +_TEXT_OR_BINARY_TYPES = (str, bytes) # Suppress surplus entries in AssertionError stack traces. __unittest = True # pylint: disable=invalid-name @@ -296,8 +283,8 @@ def _open(filepath, mode, _open_func=open): # type: (Text, Text, Callable[..., IO]) -> IO """Opens a file. - Like open(), but compatible with Python 2 and 3. Also ensures that we can open - real files even if tests stub out open(). + Like open(), but ensure that we can open real files even if tests stub out + open(). Args: filepath: A filepath. @@ -307,10 +294,7 @@ def _open(filepath, mode, _open_func=open): Returns: The opened file object. """ - if six.PY2: - return _open_func(filepath, mode) - else: - return _open_func(filepath, mode, encoding='utf-8') + return _open_func(filepath, mode, encoding='utf-8') class _TempDir(object): @@ -390,7 +374,7 @@ class _TempDir(object): # Note: there's no need to clear the directory since the containing # dir was cleared by the tempdir() function. - _makedirs_exist_ok(path) + os.makedirs(path, exist_ok=True) return _TempDir(path) @@ -418,14 +402,14 @@ class _TempFile(object): if file_path: 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)) + os.makedirs(os.path.dirname(path), exist_ok=True) # 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) + os.makedirs(base_path, exist_ok=True) fd, path = tempfile.mkstemp(dir=str(base_path)) os.close(fd) cleanup_path = path @@ -433,7 +417,7 @@ class _TempFile(object): tf = cls(path) if content: - if isinstance(content, six.text_type): + if isinstance(content, str): tf.write_text(content, mode=mode, encoding=encoding, errors=errors) else: tf.write_bytes(content, mode) @@ -482,8 +466,6 @@ class _TempFile(object): encoding: The encoding to use when writing the text to the file. errors: The error handling strategy to use when converting text to bytes. """ - if six.PY2 and isinstance(text, bytes): - text = text.decode(encoding, errors) with self.open_text(mode, encoding=encoding, errors=errors) as fp: fp.write(text) @@ -673,12 +655,12 @@ class TestCase(unittest.TestCase): path = os.path.join(test_path, name) cleanup_path = os.path.join(test_path, _get_first_part(name)) else: - _makedirs_exist_ok(test_path) + os.makedirs(test_path, exist_ok=True) path = tempfile.mkdtemp(dir=test_path) cleanup_path = path _rmtree_ignore_errors(cleanup_path) - _makedirs_exist_ok(path) + os.makedirs(path, exist_ok=True) self._maybe_add_temp_path_cleanup(cleanup_path, cleanup) @@ -783,7 +765,8 @@ class TestCase(unittest.TestCase): @classmethod def _get_tempdir_path_cls(cls): # type: () -> Text - return os.path.join(TEST_TMPDIR.value, _get_qualname(cls)) + return os.path.join(TEST_TMPDIR.value, + cls.__qualname__.replace('__main__.', '')) def _get_tempdir_path_test(self): # type: () -> Text @@ -1053,51 +1036,14 @@ class TestCase(unittest.TestCase): def assertItemsEqual(self, expected_seq, actual_seq, msg=None): """Deprecated, please use assertCountEqual instead. - This is equivalent to assertCountEqual in Python 3. An implementation of - assertCountEqual is also provided by absltest.TestCase for Python 2. + This is equivalent to assertCountEqual. Args: expected_seq: A sequence containing elements we are expecting. actual_seq: The sequence that we are testing. msg: The message to be printed if the test fails. """ - if six.PY3: - # The assertItemsEqual method was renamed assertCountEqual in Python 3.2 - super(TestCase, self).assertCountEqual(expected_seq, actual_seq, msg) - else: - super(TestCase, self).assertItemsEqual(expected_seq, actual_seq, msg) - - # Only override assertCountEqual in Python 2 to avoid unnecessary calls. - if six.PY2: - - def assertCountEqual(self, expected_seq, actual_seq, msg=None): - """Tests two sequences have the same elements regardless of order. - - It tests that the first sequence contains the same elements as the - second, regardless of their order. When they don't, an error message - listing the differences between the sequences will be generated. - - Duplicate elements are not ignored when comparing first and second. - It verifies whether each element has the same count in both sequences. - Equivalent to: - - self.assertEqual(Counter(list(expected_seq)), - Counter(list(actual_seq))) - - but works with sequences of unhashable objects as well. - - Example: - - [0, 1, 1] and [1, 0, 1] compare equal. - - [0, 0, 1] and [0, 1] compare unequal. - - Args: - expected_seq: A sequence containing elements we are expecting. - actual_seq: The sequence that we are testing. - msg: The message to be printed if the test fails. - - """ - # Only call super's method to avoid potential infinite recursions. - super(TestCase, self).assertItemsEqual(expected_seq, actual_seq, msg) + super().assertCountEqual(expected_seq, actual_seq, msg) def assertSameElements(self, expected_seq, actual_seq, msg=None): """Asserts that two sequences have the same elements (in any order). @@ -1157,10 +1103,10 @@ class TestCase(unittest.TestCase): # has a different error format. However, I find this slightly more readable. def assertMultiLineEqual(self, first, second, msg=None, **kwargs): """Asserts that two multi-line strings are equal.""" - assert isinstance(first, six.string_types), ( - 'First argument is not a string: %r' % (first,)) - assert isinstance(second, six.string_types), ( - 'Second argument is not a string: %r' % (second,)) + assert isinstance(first, + str), ('First argument is not a string: %r' % (first,)) + assert isinstance(second, + str), ('Second argument is not a string: %r' % (second,)) line_limit = kwargs.pop('line_limit', 0) if kwargs: raise TypeError('Unexpected keyword args {}'.format(tuple(kwargs))) @@ -1237,14 +1183,14 @@ class TestCase(unittest.TestCase): if type(regex) is not regex_type: # pylint: disable=unidiomatic-typecheck self.fail('regexes list must all be the same type.', message) - if regex_type is bytes and isinstance(actual_str, six.text_type): + if regex_type is bytes and isinstance(actual_str, str): regexes = [regex.decode('utf-8') for regex in regexes] - regex_type = six.text_type - elif regex_type is six.text_type and isinstance(actual_str, bytes): + regex_type = str + elif regex_type is str and isinstance(actual_str, bytes): regexes = [regex.encode('utf-8') for regex in regexes] regex_type = bytes - if regex_type is six.text_type: + if regex_type is str: regex = u'(?:%s)' % u')|(?:'.join(regexes) elif regex_type is bytes: regex = b'(?:' + (b')|(?:'.join(regexes)) + b')' @@ -1276,7 +1222,7 @@ class TestCase(unittest.TestCase): # We need bytes regexes here because `err` is bytes. # Accommodate code which listed their output regexes w/o the b'' prefix by # converting them to bytes for the user. - if isinstance(regexes[0], six.text_type): + if isinstance(regexes[0], str): regexes = [regex.encode('utf-8') for regex in regexes] command_string = get_command_string(command) @@ -1322,7 +1268,7 @@ class TestCase(unittest.TestCase): # We need bytes regexes here because `err` is bytes. # Accommodate code which listed their output regexes w/o the b'' prefix by # converting them to bytes for the user. - if isinstance(regexes[0], six.text_type): + if isinstance(regexes[0], str): regexes = [regex.encode('utf-8') for regex in regexes] command_string = get_command_string(command) @@ -1364,6 +1310,21 @@ class TestCase(unittest.TestCase): self.test_func(exc_value) return True + @typing.overload + def assertRaisesWithPredicateMatch( + self, expected_exception, predicate) -> _AssertRaisesContext: + # The purpose of this return statement is to work around + # https://github.com/PyCQA/pylint/issues/5273; it is otherwise ignored. + return self._AssertRaisesContext(None, None, None) + + @typing.overload + def assertRaisesWithPredicateMatch( + self, expected_exception, predicate, callable_obj: Callable[..., Any], + *args, **kwargs) -> None: + # The purpose of this return statement is to work around + # https://github.com/PyCQA/pylint/issues/5273; it is otherwise ignored. + return self._AssertRaisesContext(None, None, None) + def assertRaisesWithPredicateMatch(self, expected_exception, predicate, callable_obj=None, *args, **kwargs): """Asserts that exception is thrown and predicate(exception) is true. @@ -1392,6 +1353,22 @@ class TestCase(unittest.TestCase): with context: callable_obj(*args, **kwargs) + @typing.overload + def assertRaisesWithLiteralMatch( + self, expected_exception, expected_exception_message + ) -> _AssertRaisesContext: + # The purpose of this return statement is to work around + # https://github.com/PyCQA/pylint/issues/5273; it is otherwise ignored. + return self._AssertRaisesContext(None, None, None) + + @typing.overload + def assertRaisesWithLiteralMatch( + self, expected_exception, expected_exception_message, + callable_obj: Callable[..., Any], *args, **kwargs) -> None: + # The purpose of this return statement is to work around + # https://github.com/PyCQA/pylint/issues/5273; it is otherwise ignored. + return self._AssertRaisesContext(None, None, None) + def assertRaisesWithLiteralMatch(self, expected_exception, expected_exception_message, callable_obj=None, *args, **kwargs): @@ -1502,7 +1479,7 @@ class TestCase(unittest.TestCase): subsequence = list(subsequence) longest_match = 0 - for start in xrange(1 + len(container) - len(subsequence)): + for start in range(1 + len(container) - len(subsequence)): if longest_match == len(subsequence): break index = 0 @@ -1666,8 +1643,8 @@ class TestCase(unittest.TestCase): if a == b: return - a_items = Sorted(list(six.iteritems(a))) - b_items = Sorted(list(six.iteritems(b))) + a_items = Sorted(list(a.items())) + b_items = Sorted(list(b.items())) unexpected = [] missing = [] @@ -1679,8 +1656,7 @@ class TestCase(unittest.TestCase): """Deterministic repr for dict.""" # Sort the entries based on their repr, not based on their sort order, # which will be non-deterministic across executions, for many types. - entries = sorted((safe_repr(k), safe_repr(v)) - for k, v in six.iteritems(dikt)) + entries = sorted((safe_repr(k), safe_repr(v)) for k, v in dikt.items()) return '{%s}' % (', '.join('%s: %s' % pair for pair in entries)) message = ['%s != %s%s' % (Repr(a), Repr(b), ' (%s)' % msg if msg else '')] @@ -1718,8 +1694,8 @@ class TestCase(unittest.TestCase): def assertUrlEqual(self, a, b, msg=None): """Asserts that urls are equal, ignoring ordering of query params.""" - parsed_a = urllib.parse.urlparse(a) - parsed_b = urllib.parse.urlparse(b) + parsed_a = parse.urlparse(a) + parsed_b = parse.urlparse(b) self.assertEqual(parsed_a.scheme, parsed_b.scheme, msg) self.assertEqual(parsed_a.netloc, parsed_b.netloc, msg) self.assertEqual(parsed_a.path, parsed_b.path, msg) @@ -1727,8 +1703,8 @@ class TestCase(unittest.TestCase): self.assertEqual(sorted(parsed_a.params.split(';')), sorted(parsed_b.params.split(';')), msg) self.assertDictEqual( - urllib.parse.parse_qs(parsed_a.query, keep_blank_values=True), - urllib.parse.parse_qs(parsed_b.query, keep_blank_values=True), msg) + parse.parse_qs(parsed_a.query, keep_blank_values=True), + parse.parse_qs(parsed_b.query, keep_blank_values=True), msg) def assertSameStructure(self, a, b, aname='a', bname='b', msg=None): """Asserts that two values contain the same structural content. @@ -1866,7 +1842,7 @@ def _sorted_list_difference(expected, actual): def _are_both_of_integer_type(a, b): # type: (object, object) -> bool - return isinstance(a, six.integer_types) and isinstance(b, six.integer_types) + return isinstance(a, int) and isinstance(b, int) def _are_both_of_sequence_type(a, b): @@ -1930,14 +1906,14 @@ def _walk_structure_for_problems(a, b, aname, bname, problem_list): elif (isinstance(a, abc.Sequence) and not isinstance(a, _TEXT_OR_BINARY_TYPES)): minlen = min(len(a), len(b)) - for i in xrange(minlen): + for i in range(minlen): _walk_structure_for_problems( a[i], b[i], '%s[%d]' % (aname, i), '%s[%d]' % (bname, i), problem_list) - for i in xrange(minlen, len(a)): + for i in range(minlen, len(a)): problem_list.append('%s has [%i] with value %r but %s does not' % (aname, i, a[i], bname)) - for i in xrange(minlen, len(b)): + for i in range(minlen, len(b)): problem_list.append('%s lacks [%i] but %s has it with value %r' % (aname, i, bname, b[i])) @@ -1954,7 +1930,7 @@ def get_command_string(command): Returns: A string suitable for use as a shell command. """ - if isinstance(command, six.string_types): + if isinstance(command, str): return command else: if os.name == 'nt': @@ -1989,7 +1965,7 @@ def get_command_stderr(command, env=None, close_fds=True): # standard handles. close_fds = False - use_shell = isinstance(command, six.string_types) + use_shell = isinstance(command, str) process = subprocess.Popen( command, close_fds=close_fds, @@ -2054,7 +2030,7 @@ def _is_in_app_main(): """Returns True iff app.run is active.""" f = sys._getframe().f_back # pylint: disable=protected-access while f: - if f.f_code == six.get_function_code(app.run): # pytype: disable=wrong-arg-types + if f.f_code == app.run.__code__: return True f = f.f_back return False @@ -2150,7 +2126,7 @@ def _run_in_app(function, args, kwargs): # 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 six.itervalues(saved_flags): + for saved_flag in saved_flags.values(): saved_flag.restore_flag() function(argv, args, kwargs) @@ -2172,15 +2148,10 @@ def _is_suspicious_attribute(testCaseClass, name): if name.startswith('Test') and len(name) > 4 and name[4].isupper(): attr = getattr(testCaseClass, name) if inspect.isfunction(attr) or inspect.ismethod(attr): - if six.PY2: - args = inspect.getargspec(attr) - return (len(args.args) == 1 and args.args[0] == 'self' - and args.varargs is None and args.keywords is None) - else: - args = inspect.getfullargspec(attr) - return (len(args.args) == 1 and args.args[0] == 'self' - and args.varargs is None and args.varkw is None and - not args.kwonlyargs) + args = inspect.getfullargspec(attr) + return (len(args.args) == 1 and args.args[0] == 'self' and + args.varargs is None and args.varkw is None and + not args.kwonlyargs) return False @@ -2418,7 +2389,7 @@ def _setup_sharding(custom_loader=None): # the test case names for this shard. delegate_get_names = base_loader.getTestCaseNames - bucket_iterator = itertools.cycle(xrange(total_shards)) + bucket_iterator = itertools.cycle(range(total_shards)) def getShardedTestCaseNames(testCaseClass): filtered_names = [] @@ -2491,7 +2462,7 @@ def _run_and_get_tests_result(argv, args, kwargs, xml_test_runner_class): # Use an in-memory buffer (not backed by the actual file) to store the XML # report, because some tools modify the file (e.g., create a placeholder # with partial information, in case the test process crashes). - xml_buffer = six.StringIO() + xml_buffer = io.StringIO() kwargs['testRunner'].set_default_xml_stream(xml_buffer) # pytype: disable=attribute-error # If we've used a seed to randomize test case ordering, we want to record it @@ -2566,15 +2537,6 @@ def run_tests(argv, args, kwargs): # pylint: disable=line-too-long sys.exit(not result.wasSuccessful()) -def _get_qualname(cls): - # type: (Type) -> Text - if six.PY3: - name = cls.__qualname__ - else: - name = '{}.{}'.format(cls.__module__, cls.__name__) - return name.replace('__main__.', '') - - def _rmtree_ignore_errors(path): # type: (Text) -> None if os.path.isfile(path): @@ -2586,19 +2548,6 @@ def _rmtree_ignore_errors(path): shutil.rmtree(path, ignore_errors=True) -def _makedirs_exist_ok(dir_name): - # type: (Text) -> None - if six.PY3: - os.makedirs(dir_name, exist_ok=True) # pylint: disable=unexpected-keyword-arg - else: - # Python 2 doesn't have the exist_ok arg, so we roll it ourselves - try: - os.makedirs(dir_name) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - def _get_first_part(path): # type: (Text) -> Text parts = path.split(os.sep, 1) diff --git a/absl/testing/parameterized.py b/absl/testing/parameterized.py index 4d02c4e..f318b98 100644 --- a/absl/testing/parameterized.py +++ b/absl/testing/parameterized.py @@ -217,7 +217,6 @@ import unittest from absl._collections_abc import abc from absl.testing import absltest -import six _ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>') @@ -247,15 +246,14 @@ def _clean_repr(obj): def _non_string_or_bytes_iterable(obj): - return (isinstance(obj, abc.Iterable) and - not isinstance(obj, six.text_type) and - not isinstance(obj, six.binary_type)) + return (isinstance(obj, abc.Iterable) and not isinstance(obj, str) and + not isinstance(obj, bytes)) def _format_parameter_list(testcase_params): if isinstance(testcase_params, abc.Mapping): return ', '.join('%s=%s' % (argname, _clean_repr(value)) - for argname, value in six.iteritems(testcase_params)) + for argname, value in testcase_params.items()) elif _non_string_or_bytes_iterable(testcase_params): return ', '.join(map(_clean_repr, testcase_params)) else: @@ -333,10 +331,11 @@ class _ParameterizedTestIter(object): 'Dict for named tests must contain key "%s"' % _NAMED_DICT_KEY) # Create a new dict to avoid modifying the supplied testcase_params. testcase_name = testcase_params[_NAMED_DICT_KEY] - testcase_params = {k: v for k, v in six.iteritems(testcase_params) - if k != _NAMED_DICT_KEY} + testcase_params = { + k: v for k, v in testcase_params.items() if k != _NAMED_DICT_KEY + } elif _non_string_or_bytes_iterable(testcase_params): - if not isinstance(testcase_params[0], six.string_types): + if not isinstance(testcase_params[0], str): raise RuntimeError( 'The first element of named test parameters is the test name ' 'suffix and must be a string') @@ -388,7 +387,7 @@ def _modify_class(class_object, testcases, naming_type): # NOTE: _test_params_repr is private to parameterized.TestCase and it's # metaclass; do not use it outside of those classes. class_object._test_params_reprs = test_params_reprs = {} - for name, obj in six.iteritems(class_object.__dict__.copy()): + for name, obj in class_object.__dict__.copy().items(): if (name.startswith(unittest.TestLoader.testMethodPrefix) and isinstance(obj, types.FunctionType)): delattr(class_object, name) @@ -396,7 +395,7 @@ def _modify_class(class_object, testcases, naming_type): _update_class_dict_for_param_test_case( class_object.__name__, methods, test_params_reprs, name, _ParameterizedTestIter(obj, testcases, naming_type, name)) - for meth_name, meth in six.iteritems(methods): + for meth_name, meth in methods.items(): setattr(class_object, meth_name, meth) @@ -554,7 +553,7 @@ class TestGeneratorMetaclass(type): # NOTE: _test_params_repr is private to parameterized.TestCase and it's # metaclass; do not use it outside of those classes. test_params_reprs = dct.setdefault('_test_params_reprs', {}) - for name, obj in six.iteritems(dct.copy()): + for name, obj in dct.copy().items(): if (name.startswith(unittest.TestLoader.testMethodPrefix) and _non_string_or_bytes_iterable(obj)): # NOTE: `obj` might not be a _ParameterizedTestIter in two cases: @@ -637,8 +636,7 @@ def _update_class_dict_for_param_test_case( test_params_reprs[new_name] = getattr(func, '__x_params_repr__', '') -@six.add_metaclass(TestGeneratorMetaclass) -class TestCase(absltest.TestCase): +class TestCase(absltest.TestCase, metaclass=TestGeneratorMetaclass): """Base class for test cases using the parameters decorator.""" # visibility: private; do not call outside this class. diff --git a/absl/testing/xml_reporter.py b/absl/testing/xml_reporter.py index 103827b..da56e39 100644 --- a/absl/testing/xml_reporter.py +++ b/absl/testing/xml_reporter.py @@ -27,7 +27,6 @@ import traceback import unittest from xml.sax import saxutils from absl.testing import _pretty_print_reporter -import six # See http://www.w3.org/TR/REC-xml/#NT-Char @@ -74,7 +73,7 @@ def _escape_cdata(s): Returns: An escaped version of the input string. """ - for char, escaped in six.iteritems(_control_character_conversions): + for char, escaped in _control_character_conversions.items(): s = s.replace(char, escaped) return s.replace(']]>', ']] >') @@ -90,13 +89,8 @@ def _iso8601_timestamp(timestamp): """ if timestamp is None or timestamp < 0: return None - # 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() + return datetime.datetime.fromtimestamp( + timestamp, tz=datetime.timezone.utc).isoformat() def _print_xml_element_header(element, attributes, stream, indentation=''): @@ -110,8 +104,8 @@ def _print_xml_element_header(element, attributes, stream, indentation=''): """ stream.write('%s<%s' % (indentation, element)) for attribute in attributes: - if len(attribute) == 2 \ - and attribute[0] is not None and attribute[1] is not None: + if (len(attribute) == 2 and attribute[0] is not None and + attribute[1] is not None): stream.write(' %s="%s"' % (attribute[0], attribute[1])) stream.write('>\n') @@ -279,7 +273,7 @@ class _TestSuiteResult(object): _print_xml_element_header('testsuites', overall_attributes, stream) if self._testsuites_properties: stream.write(' <properties>\n') - for name, value in sorted(six.iteritems(self._testsuites_properties)): + for name, value in sorted(self._testsuites_properties.items()): stream.write(' <property name="%s" value="%s"></property>\n' % (_escape_xml_attr(name), _escape_xml_attr(str(value)))) stream.write(' </properties>\n') diff --git a/absl/tests/command_name_test.py b/absl/tests/command_name_test.py index 61af1bb..2679521 100644 --- a/absl/tests/command_name_test.py +++ b/absl/tests/command_name_test.py @@ -15,18 +15,14 @@ """Tests for absl.command_name.""" -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - import ctypes import errno import os import unittest +from unittest import mock from absl import command_name from absl.testing import absltest -import mock def _get_kernel_process_name(): diff --git a/third_party/mock.BUILD b/third_party/mock.BUILD deleted file mode 100644 index 534ff65..0000000 --- a/third_party/mock.BUILD +++ /dev/null @@ -1,13 +0,0 @@ -# Description: -# mock is a library for testing in Python. - -licenses(["notice"]) # BSD - -exports_files(["LICENSE.txt"]) - -py_library( - name = "mock", - srcs = ["mock.py"], - srcs_version = "PY2AND3", - visibility = ["//visibility:public"], -) |