Snap for 8426163 from 2b23d118222109ef59376b69d15cf366dcbecad5 to mainline-tzdata2-release

Change-Id: I9df1a7c03e8fab933f269705702e79395a208880
diff --git a/.travis.yml b/.travis.yml
index 453e56d..627bf3d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,5 @@
 language: python
+sudo: false
 matrix:
   include:
   - python: "2.7"
@@ -11,6 +12,8 @@
     env: TOX_ENV=py27-oauth2client3
   - python: "2.7"
     env: TOX_ENV=py27-oauth2client4
+  - python: "3.4"
+    env: TOX_ENV=py34-oauth2client4
   - python: "3.5"
     env: TOX_ENV=py35-oauth2client1
   - python: "3.5"
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 94bbf8f..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
-    default_applicable_licenses: ["external_python_apitools_license"],
-}
-
-// Added automatically by a large-scale-change
-// See: http://go/android-license-faq
-license {
-    name: "external_python_apitools_license",
-    visibility: [":__subpackages__"],
-    license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
-    ],
-    license_text: [
-        "LICENSE",
-    ],
-}
diff --git a/METADATA b/METADATA
index e5ecb93..9c9b51c 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,10 @@
     type: GIT
     value: "https://github.com/google/apitools"
   }
-  version: "v0.5.31"
-  license_type: NOTICE
+  version: "v0.5.30"
   last_upgrade_date {
-    year: 2020
-    month: 5
-    day: 14
+    year: 2019
+    month: 6
+    day: 26
   }
 }
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..61a80b2
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit" : [
+    {
+      "name" : "acloud_test",
+      "host" : true
+    }
+  ]
+}
diff --git a/apitools/Android.bp b/apitools/Android.bp
index e329208..67dd2b6 100644
--- a/apitools/Android.bp
+++ b/apitools/Android.bp
@@ -11,15 +11,6 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "external_python_apitools_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["external_python_apitools_license"],
-}
-
 python_library {
     name: "py-apitools",
     host_supported: true,
@@ -45,3 +36,4 @@
     ],
     pkg_path: "apitools",
 }
+
diff --git a/apitools/base/protorpclite/descriptor.py b/apitools/base/protorpclite/descriptor.py
index 70b7ed1..add0e4c 100644
--- a/apitools/base/protorpclite/descriptor.py
+++ b/apitools/base/protorpclite/descriptor.py
@@ -292,7 +292,7 @@
     enum_descriptor.name = enum_definition.definition_name().split('.')[-1]
 
     values = []
-    for number in sorted(enum_definition.numbers()):
+    for number in enum_definition.numbers():
         value = enum_definition.lookup_by_number(number)
         values.append(describe_enum_value(value))
 
diff --git a/apitools/base/protorpclite/descriptor_test.py b/apitools/base/protorpclite/descriptor_test.py
index 5fbed35..fc27ec4 100644
--- a/apitools/base/protorpclite/descriptor_test.py
+++ b/apitools/base/protorpclite/descriptor_test.py
@@ -18,9 +18,9 @@
 """Tests for apitools.base.protorpclite.descriptor."""
 import platform
 import types
-import unittest
 
 import six
+import unittest2
 
 from apitools.base.protorpclite import descriptor
 from apitools.base.protorpclite import message_types
@@ -78,8 +78,8 @@
         described.check_initialized()
         self.assertEquals(expected, described)
 
-    @unittest.skipIf('PyPy' in platform.python_implementation(),
-                     'todo: reenable this')
+    @unittest2.skipIf('PyPy' in platform.python_implementation(),
+                      'todo: reenable this')
     def testEnumWithItems(self):
         class EnumWithItems(messages.Enum):
             A = 3
@@ -512,4 +512,4 @@
 
 
 if __name__ == '__main__':
-    unittest.main()
+    unittest2.main()
diff --git a/apitools/base/protorpclite/test_util.py b/apitools/base/protorpclite/test_util.py
index 89e3a68..43345fc 100644
--- a/apitools/base/protorpclite/test_util.py
+++ b/apitools/base/protorpclite/test_util.py
@@ -33,10 +33,10 @@
 import re
 import socket
 import types
-import unittest
 
 import six
 from six.moves import range  # pylint: disable=redefined-builtin
+import unittest2 as unittest
 
 from apitools.base.protorpclite import message_types
 from apitools.base.protorpclite import messages
diff --git a/apitools/base/py/base_api_test.py b/apitools/base/py/base_api_test.py
index 27b1727..b00085c 100644
--- a/apitools/base/py/base_api_test.py
+++ b/apitools/base/py/base_api_test.py
@@ -17,11 +17,11 @@
 import datetime
 import sys
 import contextlib
-import unittest
 
 import six
 from six.moves import http_client
 from six.moves import urllib_parse
+import unittest2
 
 from apitools.base.protorpclite import message_types
 from apitools.base.protorpclite import messages
@@ -96,7 +96,7 @@
         super(FakeService, self).__init__(client)
 
 
-class BaseApiTest(unittest.TestCase):
+class BaseApiTest(unittest2.TestCase):
 
     def __GetFakeClient(self):
         return FakeClient('', credentials=FakeCredentials())
@@ -331,4 +331,4 @@
 
 
 if __name__ == '__main__':
-    unittest.main()
+    unittest2.main()
diff --git a/apitools/base/py/batch_test.py b/apitools/base/py/batch_test.py
index 90cf4fb..0574dc6 100644
--- a/apitools/base/py/batch_test.py
+++ b/apitools/base/py/batch_test.py
@@ -16,12 +16,12 @@
 """Tests for apitools.base.py.batch."""
 
 import textwrap
-import unittest
 
 import mock
 from six.moves import http_client
 from six.moves import range  # pylint:disable=redefined-builtin
 from six.moves.urllib import parse
+import unittest2
 
 from apitools.base.py import batch
 from apitools.base.py import exceptions
@@ -69,7 +69,7 @@
         return http_response
 
 
-class BatchTest(unittest.TestCase):
+class BatchTest(unittest2.TestCase):
 
     def assertUrlEqual(self, expected_url, provided_url):
 
diff --git a/apitools/base/py/buffered_stream_test.py b/apitools/base/py/buffered_stream_test.py
index 4de231d..2098fb1 100644
--- a/apitools/base/py/buffered_stream_test.py
+++ b/apitools/base/py/buffered_stream_test.py
@@ -16,15 +16,15 @@
 """Tests for buffered_stream."""
 
 import string
-import unittest
 
 import six
+import unittest2
 
 from apitools.base.py import buffered_stream
 from apitools.base.py import exceptions
 
 
-class BufferedStreamTest(unittest.TestCase):
+class BufferedStreamTest(unittest2.TestCase):
 
     def setUp(self):
         self.stream = six.StringIO(string.ascii_letters)
diff --git a/apitools/base/py/compression_test.py b/apitools/base/py/compression_test.py
index 9832b31..c8ecdac 100644
--- a/apitools/base/py/compression_test.py
+++ b/apitools/base/py/compression_test.py
@@ -16,15 +16,14 @@
 
 """Tests for compression."""
 
-import unittest
-
 from apitools.base.py import compression
 from apitools.base.py import gzip
 
 import six
+import unittest2
 
 
-class CompressionTest(unittest.TestCase):
+class CompressionTest(unittest2.TestCase):
 
     def setUp(self):
         # Sample highly compressible data (~50MB).
@@ -99,7 +98,7 @@
         self.assertTrue(exhausted)
 
 
-class StreamingBufferTest(unittest.TestCase):
+class StreamingBufferTest(unittest2.TestCase):
 
     def setUp(self):
         self.stream = compression.StreamingBuffer()
diff --git a/apitools/base/py/credentials_lib.py b/apitools/base/py/credentials_lib.py
index 0823f93..bf39285 100644
--- a/apitools/base/py/credentials_lib.py
+++ b/apitools/base/py/credentials_lib.py
@@ -17,7 +17,6 @@
 """Common credentials classes and constructors."""
 from __future__ import print_function
 
-import argparse
 import contextlib
 import datetime
 import json
@@ -516,6 +515,10 @@
     # since they're bringing their own credentials. So we just allow this
     # to fail with an ImportError in those cases.
     #
+    # TODO(craigcitro): Move this import back to the top when we drop
+    # python 2.6 support (eg when gsutil does).
+    import argparse
+
     parser = argparse.ArgumentParser(parents=[tools.argparser])
     # Get command line argparse flags.
     flags, _ = parser.parse_known_args(args=args)
@@ -718,6 +721,10 @@
         client_info, service_account_name=None, service_account_keyfile=None,
         service_account_json_keyfile=None, **unused_kwds):
     """Returns ServiceAccountCredentials from give file."""
+    if ((service_account_name and not service_account_keyfile) or
+            (service_account_keyfile and not service_account_name)):
+        raise exceptions.CredentialsError(
+            'Service account name or keyfile provided without the other')
     scopes = client_info['scope'].split()
     user_agent = client_info['user_agent']
     # Use the .json credentials, if provided.
@@ -725,10 +732,6 @@
         return ServiceAccountCredentialsFromFile(
             service_account_json_keyfile, scopes, user_agent=user_agent)
     # Fall back to .p12 if there's no .json credentials.
-    if ((service_account_name and not service_account_keyfile) or
-            (service_account_keyfile and not service_account_name)):
-        raise exceptions.CredentialsError(
-            'Service account name or keyfile provided without the other')
     if service_account_name is not None:
         return ServiceAccountCredentialsFromP12File(
             service_account_name, service_account_keyfile, scopes, user_agent)
diff --git a/apitools/base/py/credentials_lib_test.py b/apitools/base/py/credentials_lib_test.py
index 64f056d..80b970c 100644
--- a/apitools/base/py/credentials_lib_test.py
+++ b/apitools/base/py/credentials_lib_test.py
@@ -17,10 +17,10 @@
 import os.path
 import shutil
 import tempfile
-import unittest
 
 import mock
 import six
+import unittest2
 
 from apitools.base.py import credentials_lib
 from apitools.base.py import util
@@ -43,7 +43,7 @@
         self.fail('Unexpected HTTP request to %s' % request_url)
 
 
-class CredentialsLibTest(unittest.TestCase):
+class CredentialsLibTest(unittest2.TestCase):
 
     def _RunGceAssertionCredentials(
             self, service_account_name=None, scopes=None, cache_filename=None):
@@ -153,7 +153,7 @@
         self.assertIsNone(creds)
 
 
-class TestGetRunFlowFlags(unittest.TestCase):
+class TestGetRunFlowFlags(unittest2.TestCase):
 
     def setUp(self):
         self._flags_actual = credentials_lib.FLAGS
diff --git a/apitools/base/py/encoding_test.py b/apitools/base/py/encoding_test.py
index 54058a2..d130cc5 100644
--- a/apitools/base/py/encoding_test.py
+++ b/apitools/base/py/encoding_test.py
@@ -17,7 +17,8 @@
 import datetime
 import json
 import sys
-import unittest
+
+import unittest2
 
 from apitools.base.protorpclite import message_types
 from apitools.base.protorpclite import messages
@@ -237,7 +238,7 @@
                                    'repeated_field', 'repeatedField')
 
 
-class EncodingTest(unittest.TestCase):
+class EncodingTest(unittest2.TestCase):
 
     def testCopyProtoMessage(self):
         msg = SimpleMessage(field='abc')
diff --git a/apitools/base/py/exceptions_test.py b/apitools/base/py/exceptions_test.py
index 6e3a182..4937f73 100644
--- a/apitools/base/py/exceptions_test.py
+++ b/apitools/base/py/exceptions_test.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import unittest
+import unittest2
 
 from apitools.base.py import exceptions
 from apitools.base.py import http_wrapper
@@ -24,7 +24,7 @@
         request_url='http://www.google.com')
 
 
-class HttpErrorFromResponseTest(unittest.TestCase):
+class HttpErrorFromResponseTest(unittest2.TestCase):
 
     """Tests for exceptions.HttpError.FromResponse."""
 
diff --git a/apitools/base/py/extra_types.py b/apitools/base/py/extra_types.py
index e40a785..847dc91 100644
--- a/apitools/base/py/extra_types.py
+++ b/apitools/base/py/extra_types.py
@@ -16,6 +16,7 @@
 
 """Extra types understood by apitools."""
 
+import collections
 import datetime
 import json
 import numbers
@@ -29,11 +30,6 @@
 from apitools.base.py import exceptions
 from apitools.base.py import util
 
-if six.PY3:
-    from collections.abc import Iterable
-else:
-    from collections import Iterable
-
 __all__ = [
     'DateField',
     'DateTimeMessage',
@@ -133,7 +129,7 @@
         return JsonValue(double_value=float(py_value))
     if isinstance(py_value, dict):
         return JsonValue(object_value=_PythonValueToJsonObject(py_value))
-    if isinstance(py_value, Iterable):
+    if isinstance(py_value, collections.Iterable):
         return JsonValue(array_value=_PythonValueToJsonArray(py_value))
     raise exceptions.InvalidDataError(
         'Cannot convert "%s" to JsonValue' % py_value)
@@ -216,7 +212,7 @@
 def _PythonValueToJsonProto(py_value):
     if isinstance(py_value, dict):
         return _PythonValueToJsonObject(py_value)
-    if (isinstance(py_value, Iterable) and
+    if (isinstance(py_value, collections.Iterable) and
             not isinstance(py_value, six.string_types)):
         return _PythonValueToJsonArray(py_value)
     return _PythonValueToJsonValue(py_value)
diff --git a/apitools/base/py/extra_types_test.py b/apitools/base/py/extra_types_test.py
index 6a4092b..7e37f7c 100644
--- a/apitools/base/py/extra_types_test.py
+++ b/apitools/base/py/extra_types_test.py
@@ -16,7 +16,8 @@
 import datetime
 import json
 import math
-import unittest
+
+import unittest2
 
 from apitools.base.protorpclite import messages
 from apitools.base.py import encoding
@@ -24,7 +25,7 @@
 from apitools.base.py import extra_types
 
 
-class ExtraTypesTest(unittest.TestCase):
+class ExtraTypesTest(unittest2.TestCase):
 
     def assertRoundTrip(self, value):
         if isinstance(value, extra_types._JSON_PROTO_TYPES):
diff --git a/apitools/base/py/http_wrapper.py b/apitools/base/py/http_wrapper.py
index c31bea0..a3fe65c 100644
--- a/apitools/base/py/http_wrapper.py
+++ b/apitools/base/py/http_wrapper.py
@@ -339,10 +339,6 @@
     """
     retry = 0
     first_req_time = time.time()
-    # Provide compatibility for breaking change in httplib2 0.16.0+:
-    # https://github.com/googleapis/google-api-python-client/issues/803
-    if hasattr(http, 'redirect_codes'):
-        http.redirect_codes = set(http.redirect_codes) - {308}
     while True:
         try:
             return _MakeRequestNoRetry(
diff --git a/apitools/base/py/http_wrapper_test.py b/apitools/base/py/http_wrapper_test.py
index fdf56f5..ce4c03e 100644
--- a/apitools/base/py/http_wrapper_test.py
+++ b/apitools/base/py/http_wrapper_test.py
@@ -15,10 +15,10 @@
 
 """Tests for http_wrapper."""
 import socket
-import unittest
 
 import httplib2
 from six.moves import http_client
+import unittest2
 
 from mock import patch
 
@@ -57,7 +57,7 @@
         return 1
 
 
-class HttpWrapperTest(unittest.TestCase):
+class HttpWrapperTest(unittest2.TestCase):
 
     def testRequestBodyUsesLengthProperty(self):
         http_wrapper.Request(body=RaisesExceptionOnLen())
@@ -65,8 +65,8 @@
     def testRequestBodyWithLen(self):
         http_wrapper.Request(body='burrito')
 
-    @unittest.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE,
-                     'oauth2client<1.5 lacks HttpAccessTokenRefreshError.')
+    @unittest2.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE,
+                      'oauth2client<1.5 lacks HttpAccessTokenRefreshError.')
     def testExceptionHandlerHttpAccessTokenError(self):
         exception_arg = HttpAccessTokenRefreshError(status=503)
         retry_args = http_wrapper.ExceptionRetryArgs(
@@ -80,8 +80,8 @@
             http_wrapper.HandleExceptionsAndRebuildHttpConnections(
                 retry_args)
 
-    @unittest.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE,
-                     'oauth2client<1.5 lacks HttpAccessTokenRefreshError.')
+    @unittest2.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE,
+                      'oauth2client<1.5 lacks HttpAccessTokenRefreshError.')
     def testExceptionHandlerHttpAccessTokenErrorRaises(self):
         exception_arg = HttpAccessTokenRefreshError(status=200)
         retry_args = http_wrapper.ExceptionRetryArgs(
diff --git a/apitools/base/py/list_pager.py b/apitools/base/py/list_pager.py
index a2c1080..fb14c14 100644
--- a/apitools/base/py/list_pager.py
+++ b/apitools/base/py/list_pager.py
@@ -17,58 +17,18 @@
 """A helper function that executes a series of List queries for many APIs."""
 
 from apitools.base.py import encoding
-import six
 
 __all__ = [
     'YieldFromList',
 ]
 
 
-def _GetattrNested(message, attribute):
-    """Gets a possibly nested attribute.
-
-    Same as getattr() if attribute is a string;
-    if attribute is a tuple, returns the nested attribute referred to by
-    the fields in the tuple as if they were a dotted accessor path.
-
-    (ex _GetattrNested(msg, ('foo', 'bar', 'baz')) gets msg.foo.bar.baz
-    """
-    if isinstance(attribute, six.string_types):
-        return getattr(message, attribute)
-    elif len(attribute) == 0:
-        return message
-    else:
-        return _GetattrNested(getattr(message, attribute[0]), attribute[1:])
-
-
-def _SetattrNested(message, attribute, value):
-    """Sets a possibly nested attribute.
-
-    Same as setattr() if attribute is a string;
-    if attribute is a tuple, sets the nested attribute referred to by
-    the fields in the tuple as if they were a dotted accessor path.
-
-    (ex _SetattrNested(msg, ('foo', 'bar', 'baz'), 'v') sets msg.foo.bar.baz
-    to 'v'
-    """
-    if isinstance(attribute, six.string_types):
-        return setattr(message, attribute, value)
-    elif len(attribute) < 1:
-        raise ValueError("Need an attribute to set")
-    elif len(attribute) == 1:
-        return setattr(message, attribute[0], value)
-    else:
-        return setattr(_GetattrNested(message, attribute[:-1]),
-                       attribute[-1], value)
-
-
 def YieldFromList(
         service, request, global_params=None, limit=None, batch_size=100,
         method='List', field='items', predicate=None,
         current_token_attribute='pageToken',
         next_token_attribute='nextPageToken',
-        batch_size_attribute='maxResults',
-        get_field_func=_GetattrNested):
+        batch_size_attribute='maxResults'):
     """Make a series of List requests, keeping track of page tokens.
 
     Args:
@@ -85,25 +45,21 @@
       method: str, The name of the method used to fetch resources.
       field: str, The field in the response that will be a list of items.
       predicate: lambda, A function that returns true for items to be yielded.
-      current_token_attribute: str or tuple, The name of the attribute in a
+      current_token_attribute: str, The name of the attribute in a
           request message holding the page token for the page being
-          requested. If a tuple, path to attribute.
-      next_token_attribute: str or tuple, The name of the attribute in a
-          response message holding the page token for the next page. If a
-          tuple, path to the attribute.
-      batch_size_attribute: str or tuple, The name of the attribute in a
+          requested.
+      next_token_attribute: str, The name of the attribute in a
+          response message holding the page token for the next page.
+      batch_size_attribute: str, The name of the attribute in a
           response message holding the maximum number of results to be
           returned. None if caller-specified batch size is unsupported.
-          If a tuple, path to the attribute.
-      get_field_func: Function that returns the items to be yielded. Argument
-          is response message, and field.
 
     Yields:
       protorpc.message.Message, The resources listed by the service.
 
     """
     request = encoding.CopyProtoMessage(request)
-    _SetattrNested(request, current_token_attribute, None)
+    setattr(request, current_token_attribute, None)
     while limit is None or limit:
         if batch_size_attribute:
             # On Py3, None is not comparable so min() below will fail.
@@ -116,10 +72,10 @@
                 request_batch_size = None
             else:
                 request_batch_size = min(batch_size, limit or batch_size)
-            _SetattrNested(request, batch_size_attribute, request_batch_size)
+            setattr(request, batch_size_attribute, request_batch_size)
         response = getattr(service, method)(request,
                                             global_params=global_params)
-        items = get_field_func(response, field)
+        items = getattr(response, field)
         if predicate:
             items = list(filter(predicate, items))
         for item in items:
@@ -129,7 +85,7 @@
             limit -= 1
             if not limit:
                 return
-        token = _GetattrNested(response, next_token_attribute)
+        token = getattr(response, next_token_attribute)
         if not token:
             return
-        _SetattrNested(request, current_token_attribute, token)
+        setattr(request, current_token_attribute, token)
diff --git a/apitools/base/py/list_pager_test.py b/apitools/base/py/list_pager_test.py
index 1ea6368..32dfea6 100644
--- a/apitools/base/py/list_pager_test.py
+++ b/apitools/base/py/list_pager_test.py
@@ -15,7 +15,7 @@
 
 """Tests for list_pager."""
 
-import unittest
+import unittest2
 
 from apitools.base.py import list_pager
 from apitools.base.py.testing import mock
@@ -27,33 +27,7 @@
 from samples.iam_sample.iam_v1 import iam_v1_messages as iam_messages
 
 
-class Example(object):
-    def __init__(self):
-        self.a = 'aaa'
-        self.b = 'bbb'
-        self.c = 'ccc'
-
-
-class GetterSetterTest(unittest.TestCase):
-
-    def testGetattrNested(self):
-        o = Example()
-        self.assertEqual(list_pager._GetattrNested(o, 'a'), 'aaa')
-        self.assertEqual(list_pager._GetattrNested(o, ('a',)), 'aaa')
-        o.b = Example()
-        self.assertEqual(list_pager._GetattrNested(o, ('b', 'c')), 'ccc')
-
-    def testSetattrNested(self):
-        o = Example()
-        list_pager._SetattrNested(o, 'b', Example())
-        self.assertEqual(o.b.a, 'aaa')
-        list_pager._SetattrNested(o, ('b', 'a'), 'AAA')
-        self.assertEqual(o.b.a, 'AAA')
-        list_pager._SetattrNested(o, ('c',), 'CCC')
-        self.assertEqual(o.c, 'CCC')
-
-
-class ListPagerTest(unittest.TestCase):
+class ListPagerTest(unittest2.TestCase):
 
     def _AssertInstanceSequence(self, results, n):
         counter = 0
@@ -268,34 +242,8 @@
 
         self._AssertInstanceSequence(results, 3)
 
-    def testYieldFromListWithCustomGetFieldFunction(self):
-        self.mocked_client.column.List.Expect(
-            messages.FusiontablesColumnListRequest(
-                maxResults=100,
-                pageToken=None,
-                tableId='mytable',
-            ),
-            messages.ColumnList(
-                items=[
-                    messages.Column(name='c0')
-                ]
-            ))
-        custom_getter_called = []
 
-        def Custom_Getter(message, attribute):
-            custom_getter_called.append(True)
-            return getattr(message, attribute)
-
-        client = fusiontables.FusiontablesV1(get_credentials=False)
-        request = messages.FusiontablesColumnListRequest(tableId='mytable')
-        results = list_pager.YieldFromList(
-            client.column, request, get_field_func=Custom_Getter)
-
-        self._AssertInstanceSequence(results, 1)
-        self.assertEquals(1, len(custom_getter_called))
-
-
-class ListPagerAttributeTest(unittest.TestCase):
+class ListPagerAttributeTest(unittest2.TestCase):
 
     def setUp(self):
         self.mocked_client = mock.Client(iam_client.IamV1)
diff --git a/apitools/base/py/stream_slice_test.py b/apitools/base/py/stream_slice_test.py
index f29e112..4d5cdfb 100644
--- a/apitools/base/py/stream_slice_test.py
+++ b/apitools/base/py/stream_slice_test.py
@@ -16,15 +16,15 @@
 """Tests for stream_slice."""
 
 import string
-import unittest
 
 import six
+import unittest2
 
 from apitools.base.py import exceptions
 from apitools.base.py import stream_slice
 
 
-class StreamSliceTest(unittest.TestCase):
+class StreamSliceTest(unittest2.TestCase):
 
     def setUp(self):
         self.stream = six.StringIO(string.ascii_letters)
diff --git a/apitools/base/py/testing/mock.py b/apitools/base/py/testing/mock.py
index ae6ad89..3bd38ba 100644
--- a/apitools/base/py/testing/mock.py
+++ b/apitools/base/py/testing/mock.py
@@ -170,8 +170,7 @@
           The response that was specified to be returned.
 
         """
-        if key != self.__key or not (self.__request == request or
-                                     _MessagesEqual(request, self.__request)):
+        if key != self.__key or not _MessagesEqual(request, self.__request):
             raise UnexpectedRequestException((key, request),
                                              (self.__key, self.__request))
 
diff --git a/apitools/base/py/testing/mock_test.py b/apitools/base/py/testing/mock_test.py
index 9bd8f05..4afdf7b 100644
--- a/apitools/base/py/testing/mock_test.py
+++ b/apitools/base/py/testing/mock_test.py
@@ -15,9 +15,8 @@
 
 """Tests for apitools.base.py.testing.mock."""
 
-import unittest
-
 import httplib2
+import unittest2
 import six
 
 from apitools.base.protorpclite import messages
@@ -43,7 +42,7 @@
     pass
 
 
-class MockTest(unittest.TestCase):
+class MockTest(unittest2.TestCase):
 
     def testMockFusionBasic(self):
         with mock.Client(fusiontables.FusiontablesV1) as client_class:
@@ -152,38 +151,6 @@
         client = fusiontables.FusiontablesV1(get_credentials=False)
         self.assertNotEqual(type(client.column), mocked_service_type)
 
-    def testRequestMacher(self):
-        class Matcher(object):
-            def __init__(self, eq):
-                self._eq = eq
-
-            def __eq__(self, other):
-                return self._eq(other)
-
-        with mock.Client(fusiontables.FusiontablesV1) as client_class:
-            def IsEven(x):
-                return x % 2 == 0
-
-            def IsOdd(x):
-                return not IsEven(x)
-
-            client_class.column.List.Expect(
-                request=Matcher(IsEven), response=1,
-                enable_type_checking=False)
-            client_class.column.List.Expect(
-                request=Matcher(IsOdd), response=2, enable_type_checking=False)
-            client_class.column.List.Expect(
-                request=Matcher(IsEven), response=3,
-                enable_type_checking=False)
-            client_class.column.List.Expect(
-                request=Matcher(IsOdd), response=4, enable_type_checking=False)
-
-            client = fusiontables.FusiontablesV1(get_credentials=False)
-            self.assertEqual(client.column.List(2), 1)
-            self.assertEqual(client.column.List(1), 2)
-            self.assertEqual(client.column.List(20), 3)
-            self.assertEqual(client.column.List(23), 4)
-
     def testClientUnmock(self):
         mock_client = mock.Client(fusiontables.FusiontablesV1)
         self.assertFalse(isinstance(mock_client, fusiontables.FusiontablesV1))
@@ -253,7 +220,7 @@
     nested = messages.MessageField(_NestedMessage, 1)
 
 
-class UtilTest(unittest.TestCase):
+class UtilTest(unittest2.TestCase):
 
     def testMessagesEqual(self):
         self.assertFalse(mock._MessagesEqual(
diff --git a/apitools/base/py/transfer_test.py b/apitools/base/py/transfer_test.py
index 4a9e79c..c68e77e 100644
--- a/apitools/base/py/transfer_test.py
+++ b/apitools/base/py/transfer_test.py
@@ -16,12 +16,12 @@
 
 """Tests for transfer.py."""
 import string
-import unittest
 
 import httplib2
 import mock
 import six
 from six.moves import http_client
+import unittest2
 
 from apitools.base.py import base_api
 from apitools.base.py import exceptions
@@ -30,7 +30,7 @@
 from apitools.base.py import transfer
 
 
-class TransferTest(unittest.TestCase):
+class TransferTest(unittest2.TestCase):
 
     def assertRangeAndContentRangeCompatible(self, request, response):
         request_prefix = 'bytes='
@@ -311,7 +311,7 @@
             self.assertTrue(rewritten_upload_contents.endswith(upload_bytes))
 
 
-class UploadTest(unittest.TestCase):
+class UploadTest(unittest2.TestCase):
 
     def setUp(self):
         # Sample highly compressible data.
diff --git a/apitools/base/py/util.py b/apitools/base/py/util.py
index ad086e4..ac1a44c 100644
--- a/apitools/base/py/util.py
+++ b/apitools/base/py/util.py
@@ -16,6 +16,7 @@
 
 """Assorted utilities shared between parts of apitools."""
 
+import collections
 import os
 import random
 
@@ -29,11 +30,6 @@
 from apitools.base.py import encoding_helper as encoding
 from apitools.base.py import exceptions
 
-if six.PY3:
-    from collections.abc import Iterable
-else:
-    from collections import Iterable
-
 __all__ = [
     'DetectGae',
     'DetectGce',
@@ -82,7 +78,7 @@
     if isinstance(scope_spec, six.string_types):
         scope_spec = six.ensure_str(scope_spec)
         return set(scope_spec.split(' '))
-    elif isinstance(scope_spec, Iterable):
+    elif isinstance(scope_spec, collections.Iterable):
         scope_spec = [six.ensure_str(x) for x in scope_spec]
         return set(scope_spec)
     raise exceptions.TypecheckError(
diff --git a/apitools/base/py/util_test.py b/apitools/base/py/util_test.py
index c3a4732..b2ece27 100644
--- a/apitools/base/py/util_test.py
+++ b/apitools/base/py/util_test.py
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 """Tests for util.py."""
-import unittest
+import unittest2
 
 from apitools.base.protorpclite import messages
 from apitools.base.py import encoding
@@ -48,7 +48,7 @@
     MessageWithRemappings.AnEnum, 'value_one', 'ONE')
 
 
-class UtilTest(unittest.TestCase):
+class UtilTest(unittest2.TestCase):
 
     def testExpand(self):
         method_config_xy = MockedMethodConfig(relative_path='{x}/y/{z}',
diff --git a/apitools/gen/client_generation_test.py b/apitools/gen/client_generation_test.py
index 4e382dd..9146501 100644
--- a/apitools/gen/client_generation_test.py
+++ b/apitools/gen/client_generation_test.py
@@ -22,11 +22,15 @@
 import subprocess
 import sys
 import tempfile
-import unittest
 
 from apitools.gen import gen_client
 from apitools.gen import test_utils
 
+if six.PY2:
+    import unittest2 as unittest
+else:
+    import unittest
+
 _API_LIST = [
     'bigquery.v2',
     'compute.v1',
diff --git a/apitools/gen/gen_client_test.py b/apitools/gen/gen_client_test.py
index a0f30d5..6c4e9b1 100644
--- a/apitools/gen/gen_client_test.py
+++ b/apitools/gen/gen_client_test.py
@@ -16,7 +16,8 @@
 """Test for gen_client module."""
 
 import os
-import unittest
+
+import unittest2
 
 from apitools.gen import gen_client
 from apitools.gen import test_utils
@@ -31,7 +32,7 @@
         return f.read()
 
 
-class ClientGenCliTest(unittest.TestCase):
+class ClientGenCliTest(unittest2.TestCase):
 
     def testHelp_NotEnoughArguments(self):
         with self.assertRaisesRegexp(SystemExit, '0'):
diff --git a/apitools/gen/service_registry.py b/apitools/gen/service_registry.py
index b79f0d1..e47b050 100644
--- a/apitools/gen/service_registry.py
+++ b/apitools/gen/service_registry.py
@@ -218,7 +218,6 @@
             printer()
             printer('MESSAGES_MODULE = messages')
             printer('BASE_URL = {0!r}'.format(client_info.base_url))
-            printer('MTLS_BASE_URL = {0!r}'.format(client_info.mtls_base_url))
             printer()
             printer('_PACKAGE = {0!r}'.format(client_info.package))
             printer('_SCOPES = {0!r}'.format(
diff --git a/apitools/gen/test_utils.py b/apitools/gen/test_utils.py
index e6b5373..484dcbc 100644
--- a/apitools/gen/test_utils.py
+++ b/apitools/gen/test_utils.py
@@ -20,12 +20,12 @@
 import shutil
 import sys
 import tempfile
-import unittest
 
 import six
+import unittest2
 
 
-SkipOnWindows = unittest.skipIf(
+SkipOnWindows = unittest2.skipIf(
     os.name == 'nt', 'Does not run on windows')
 
 
diff --git a/apitools/gen/util.py b/apitools/gen/util.py
index c2955a8..680d84a 100644
--- a/apitools/gen/util.py
+++ b/apitools/gen/util.py
@@ -93,7 +93,7 @@
         name = re.sub('[^_A-Za-z0-9]', '_', name)
         if name[0].isdigit():
             name = '_%s' % name
-        while keyword.iskeyword(name) or name == 'exec':
+        while keyword.iskeyword(name):
             name = '%s_' % name
         # If we end up with __ as a prefix, we'll run afoul of python
         # field renaming, so we manually correct for it.
@@ -174,21 +174,9 @@
     return version.replace('.', '_')
 
 
-def _ComputePaths(package, version, root_url, service_path):
-    """Compute the base url and base path.
-
-    Attributes:
-      package: name field of the discovery, i.e. 'storage' for storage service.
-      version: version of the service, i.e. 'v1'.
-      root_url: root url of the service, i.e. 'https://www.googleapis.com/'.
-      service_path: path of the service under the rool url, i.e. 'storage/v1/'.
-
-    Returns:
-      base url: string, base url of the service,
-        'https://www.googleapis.com/storage/v1/' for the storage service.
-      base path: string, common prefix of service endpoints after the base url.
-    """
-    full_path = urllib_parse.urljoin(root_url, service_path)
+def _ComputePaths(package, version, discovery_doc):
+    full_path = urllib_parse.urljoin(
+        discovery_doc['rootUrl'], discovery_doc['servicePath'])
     api_path_component = '/'.join((package, version, ''))
     if api_path_component not in full_path:
         return full_path, ''
@@ -199,7 +187,7 @@
 class ClientInfo(collections.namedtuple('ClientInfo', (
         'package', 'scopes', 'version', 'client_id', 'client_secret',
         'user_agent', 'client_class_name', 'url_version', 'api_key',
-        'base_url', 'base_path', 'mtls_base_url'))):
+        'base_url', 'base_path'))):
 
     """Container for client-related info and names."""
 
@@ -213,15 +201,7 @@
         package = discovery_doc['name']
         url_version = discovery_doc['version']
         base_url, base_path = _ComputePaths(package, url_version,
-                                            discovery_doc['rootUrl'],
-                                            discovery_doc['servicePath'])
-
-        mtls_root_url = discovery_doc.get('mtlsRootUrl', '')
-        mtls_base_url = ''
-        if mtls_root_url:
-            mtls_base_url, _ = _ComputePaths(package, url_version,
-                                             mtls_root_url,
-                                             discovery_doc['servicePath'])
+                                            discovery_doc)
 
         client_info = {
             'package': package,
@@ -234,7 +214,6 @@
             'api_key': api_key,
             'base_url': base_url,
             'base_path': base_path,
-            'mtls_base_url': mtls_base_url,
         }
         client_class_name = '%s%s' % (
             names.ClassName(client_info['package']),
@@ -424,8 +403,7 @@
                 if isinstance(content, bytes):
                     content = content.decode('utf8')
                 discovery_doc = json.loads(content)
-                if discovery_doc:
-                    return discovery_doc
+                break
             except (urllib_error.HTTPError, urllib_error.URLError) as e:
                 logging.info(
                     'Attempting to fetch discovery doc again after "%s"', e)
@@ -434,3 +412,4 @@
         raise CommunicationError(
             'Could not find discovery doc at any of %s: %s' % (
                 discovery_urls, last_exception))
+    return discovery_doc
diff --git a/apitools/gen/util_test.py b/apitools/gen/util_test.py
index 9682bf9..7668b53 100644
--- a/apitools/gen/util_test.py
+++ b/apitools/gen/util_test.py
@@ -21,13 +21,13 @@
 import os
 import six.moves.urllib.request as urllib_request
 import tempfile
-import unittest
+import unittest2
 
 from apitools.gen import util
 from mock import patch
 
 
-class NormalizeVersionTest(unittest.TestCase):
+class NormalizeVersionTest(unittest2.TestCase):
 
     def testVersions(self):
         already_valid = 'v1'
@@ -36,7 +36,7 @@
         self.assertEqual('v0_1', util.NormalizeVersion(to_clean))
 
 
-class NamesTest(unittest.TestCase):
+class NamesTest(unittest2.TestCase):
 
     def testKeywords(self):
         names = util.Names([''])
@@ -81,7 +81,7 @@
         os.unlink(f.name)
 
 
-class GetURLContentTest(unittest.TestCase):
+class GetURLContentTest(unittest2.TestCase):
 
     def testUnspecifiedContentEncoding(self):
         data = 'regular non-gzipped content'
diff --git a/samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py b/samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py
index 90552da..e6cf9c8 100644
--- a/samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py
+++ b/samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py
@@ -9,7 +9,6 @@
 
   MESSAGES_MODULE = messages
   BASE_URL = u'https://www.googleapis.com/bigquery/v2/'
-  MTLS_BASE_URL = u''
 
   _PACKAGE = u'bigquery'
   _SCOPES = [u'https://www.googleapis.com/auth/bigquery', u'https://www.googleapis.com/auth/bigquery.insertdata', u'https://www.googleapis.com/auth/cloud-platform', u'https://www.googleapis.com/auth/cloud-platform.read-only', u'https://www.googleapis.com/auth/devstorage.full_control', u'https://www.googleapis.com/auth/devstorage.read_only', u'https://www.googleapis.com/auth/devstorage.read_write']
diff --git a/samples/dns_sample/dns_v1/dns_v1_client.py b/samples/dns_sample/dns_v1/dns_v1_client.py
index 0666460..ce3aff6 100644
--- a/samples/dns_sample/dns_v1/dns_v1_client.py
+++ b/samples/dns_sample/dns_v1/dns_v1_client.py
@@ -9,7 +9,6 @@
 
   MESSAGES_MODULE = messages
   BASE_URL = u'https://www.googleapis.com/dns/v1/'
-  MTLS_BASE_URL = u''
 
   _PACKAGE = u'dns'
   _SCOPES = [u'https://www.googleapis.com/auth/cloud-platform', u'https://www.googleapis.com/auth/cloud-platform.read-only', u'https://www.googleapis.com/auth/ndev.clouddns.readonly', u'https://www.googleapis.com/auth/ndev.clouddns.readwrite']
diff --git a/samples/dns_sample/gen_dns_client_test.py b/samples/dns_sample/gen_dns_client_test.py
index 862ddba..dff6812 100644
--- a/samples/dns_sample/gen_dns_client_test.py
+++ b/samples/dns_sample/gen_dns_client_test.py
@@ -15,8 +15,7 @@
 
 """Test for generated sample module."""
 
-import unittest
-
+import unittest2
 import six
 
 from apitools.base.py import list_pager
@@ -26,7 +25,7 @@
 from samples.dns_sample.dns_v1 import dns_v1_messages
 
 
-class DnsGenClientSanityTest(unittest.TestCase):
+class DnsGenClientSanityTest(unittest2.TestCase):
 
     def testBaseUrl(self):
         self.assertEquals(u'https://www.googleapis.com/dns/v1/',
@@ -47,7 +46,7 @@
             'ResourceRecordSetsService']), inner_classes)
 
 
-class DnsGenClientTest(unittest.TestCase):
+class DnsGenClientTest(unittest2.TestCase):
 
     def setUp(self):
         self.mocked_dns_v1 = mock.Client(dns_v1_client.DnsV1)
diff --git a/samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py b/samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py
index b7b6c43..f80fb3e 100644
--- a/samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py
+++ b/samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py
@@ -9,7 +9,6 @@
 
   MESSAGES_MODULE = messages
   BASE_URL = u'https://www.googleapis.com/fusiontables/v1/'
-  MTLS_BASE_URL = u''
 
   _PACKAGE = u'fusiontables'
   _SCOPES = [u'https://www.googleapis.com/auth/fusiontables', u'https://www.googleapis.com/auth/fusiontables.readonly']
diff --git a/samples/iam_sample/iam_client_test.py b/samples/iam_sample/iam_client_test.py
index 017a2d0..39d25a4 100644
--- a/samples/iam_sample/iam_client_test.py
+++ b/samples/iam_sample/iam_client_test.py
@@ -15,8 +15,7 @@
 
 """Test for generated sample module."""
 
-import unittest
-
+import unittest2
 import six
 
 from apitools.base.py.testing import mock
@@ -25,7 +24,7 @@
 from samples.iam_sample.iam_v1 import iam_v1_messages  # nopep8
 
 
-class DnsGenClientSanityTest(unittest.TestCase):
+class DnsGenClientSanityTest(unittest2.TestCase):
 
     def testBaseUrl(self):
         self.assertEquals(u'https://iam.googleapis.com/',
@@ -47,7 +46,7 @@
             'RolesService']), inner_classes)
 
 
-class IamGenClientTest(unittest.TestCase):
+class IamGenClientTest(unittest2.TestCase):
 
     def setUp(self):
         self.mocked_iam_v1 = mock.Client(iam_v1_client.IamV1)
diff --git a/samples/iam_sample/iam_v1/iam_v1_client.py b/samples/iam_sample/iam_v1/iam_v1_client.py
index ed9112e..9f333ef 100644
--- a/samples/iam_sample/iam_v1/iam_v1_client.py
+++ b/samples/iam_sample/iam_v1/iam_v1_client.py
@@ -9,7 +9,6 @@
 
   MESSAGES_MODULE = messages
   BASE_URL = u'https://iam.googleapis.com/'
-  MTLS_BASE_URL = u''
 
   _PACKAGE = u'iam'
   _SCOPES = [u'https://www.googleapis.com/auth/cloud-platform']
diff --git a/samples/servicemanagement_sample/messages_test.py b/samples/servicemanagement_sample/messages_test.py
index 5f56322..a62dbd7 100644
--- a/samples/servicemanagement_sample/messages_test.py
+++ b/samples/servicemanagement_sample/messages_test.py
@@ -15,7 +15,7 @@
 
 """Test for generated servicemanagement messages module."""
 
-import unittest
+import unittest2
 
 from apitools.base.py import extra_types
 
@@ -23,7 +23,7 @@
     import servicemanagement_v1_messages as messages  # nopep8
 
 
-class MessagesTest(unittest.TestCase):
+class MessagesTest(unittest2.TestCase):
 
     def testInstantiateMessageWithAdditionalProperties(self):
         PROJECT_NAME = 'test-project'
diff --git a/samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py b/samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py
index 25823db..a72936e 100644
--- a/samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py
+++ b/samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py
@@ -9,7 +9,6 @@
 
   MESSAGES_MODULE = messages
   BASE_URL = u'https://servicemanagement.googleapis.com/'
-  MTLS_BASE_URL = u''
 
   _PACKAGE = u'servicemanagement'
   _SCOPES = [u'https://www.googleapis.com/auth/cloud-platform', u'https://www.googleapis.com/auth/service.management']
diff --git a/samples/storage_sample/storage_v1.json b/samples/storage_sample/storage_v1.json
index cfd2748..2636bda 100644
--- a/samples/storage_sample/storage_v1.json
+++ b/samples/storage_sample/storage_v1.json
@@ -21,7 +21,6 @@
  "baseUrl": "https://www.googleapis.com/storage/v1/",
  "basePath": "/storage/v1/",
  "rootUrl": "https://www.googleapis.com/",
- "mtlsRootUrl": "https://www.mtls.googleapis.com/",
  "servicePath": "storage/v1/",
  "batchPath": "batch/storage/v1",
  "parameters": {
diff --git a/samples/storage_sample/storage_v1/storage_v1_client.py b/samples/storage_sample/storage_v1/storage_v1_client.py
index 4a8414a..38ceab9 100644
--- a/samples/storage_sample/storage_v1/storage_v1_client.py
+++ b/samples/storage_sample/storage_v1/storage_v1_client.py
@@ -9,7 +9,6 @@
 
   MESSAGES_MODULE = messages
   BASE_URL = u'https://www.googleapis.com/storage/v1/'
-  MTLS_BASE_URL = u'https://www.mtls.googleapis.com/storage/v1/'
 
   _PACKAGE = u'storage'
   _SCOPES = [u'https://www.googleapis.com/auth/cloud-platform', u'https://www.googleapis.com/auth/cloud-platform.read-only', u'https://www.googleapis.com/auth/devstorage.full_control', u'https://www.googleapis.com/auth/devstorage.read_only', u'https://www.googleapis.com/auth/devstorage.read_write']
diff --git a/samples/uptodate_check_test.py b/samples/uptodate_check_test.py
index 8ca258e..3871695 100644
--- a/samples/uptodate_check_test.py
+++ b/samples/uptodate_check_test.py
@@ -14,9 +14,9 @@
 
 import os
 import difflib
-import unittest
 
 import six
+import unittest2
 
 from apitools.gen import gen_client
 from apitools.gen import test_utils
@@ -31,7 +31,7 @@
         return f.read()
 
 
-class ClientGenCliTest(unittest.TestCase):
+class ClientGenCliTest(unittest2.TestCase):
 
     def AssertDiffEqual(self, expected, actual):
         """Like unittest.assertEqual with a diff in the exception message."""
diff --git a/setup.py b/setup.py
index f6e26a2..fbf81b1 100644
--- a/setup.py
+++ b/setup.py
@@ -39,6 +39,7 @@
 ]
 
 TESTING_PACKAGES = [
+    'unittest2>=0.5.1',
     'mock>=1.0.1',
 ]
 
@@ -48,7 +49,7 @@
 
 py_version = platform.python_version()
 
-_APITOOLS_VERSION = '0.5.31'
+_APITOOLS_VERSION = '0.5.30'
 
 with open('README.rst') as fileobj:
     README = fileobj.read()
@@ -61,7 +62,6 @@
     url='http://github.com/google/apitools',
     author='Craig Citro',
     author_email='craigcitro@google.com',
-    python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
     # Contained modules and scripts.
     packages=setuptools.find_packages(include=['apitools']),
     entry_points={'console_scripts': CONSOLE_SCRIPTS},
@@ -88,10 +88,6 @@
     # PyPI package information.
     classifiers=[
         'License :: OSI Approved :: Apache Software License',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.5',
         'Topic :: Software Development :: Libraries',
         'Topic :: Software Development :: Libraries :: Python Modules',
         ],
diff --git a/tox.ini b/tox.ini
index 09d2afc..aaa22e0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,9 @@
 [tox]
 envlist =
+    py26-oauth2client4
     py27-oauth2client{1,2,3,4}
+    py33-oauth2client41
+    py34-oauth2client41
     py35-oauth2client{1,2,3,4}
 
 [testenv]
@@ -25,6 +28,7 @@
 deps =
     pycodestyle==2.4.0
     pylint
+    unittest2
 
 [testenv:cover]
 basepython =
@@ -35,6 +39,7 @@
     python-gflags
     mock
     nose
+    unittest2
     coverage
     nosexcover
 
@@ -53,6 +58,7 @@
 deps =
     mock
     nose
+    unittest2
     coverage
 commands =
     coverage run --branch -p samples/storage_sample/downloads_test.py