aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-05-15 21:03:09 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-05-15 21:03:09 +0000
commitf7c3bec4e79ea14b5841f88b0ded43ced596b78e (patch)
treee9aff1d08c13ef099a1691d778416a233a712f38
parent8a8d7f89f1762f40fd02df9af9d547a99c3aa6b8 (diff)
parent70045997c545daa465f9a08afb8602276179b092 (diff)
downloadapitools-f7c3bec4e79ea14b5841f88b0ded43ced596b78e.tar.gz
Upgrade python/apitools to v0.5.31 am: f864ef688b am: 9b6a69032d am: 89ea80b037 am: 4044c97a7e am: 70045997c5
Change-Id: Ib88eb589d1ef3ff2847525d19fc88c4157ef55c4
-rw-r--r--.travis.yml3
-rw-r--r--METADATA8
-rw-r--r--apitools/base/protorpclite/descriptor.py2
-rw-r--r--apitools/base/protorpclite/descriptor_test.py8
-rw-r--r--apitools/base/protorpclite/test_util.py2
-rw-r--r--apitools/base/py/base_api_test.py6
-rw-r--r--apitools/base/py/batch_test.py4
-rw-r--r--apitools/base/py/buffered_stream_test.py4
-rw-r--r--apitools/base/py/compression_test.py7
-rw-r--r--apitools/base/py/credentials_lib.py13
-rw-r--r--apitools/base/py/credentials_lib_test.py6
-rw-r--r--apitools/base/py/encoding_test.py5
-rw-r--r--apitools/base/py/exceptions_test.py4
-rw-r--r--apitools/base/py/extra_types.py10
-rw-r--r--apitools/base/py/extra_types_test.py5
-rw-r--r--apitools/base/py/http_wrapper.py4
-rw-r--r--apitools/base/py/http_wrapper_test.py12
-rw-r--r--apitools/base/py/list_pager.py66
-rw-r--r--apitools/base/py/list_pager_test.py58
-rw-r--r--apitools/base/py/stream_slice_test.py4
-rw-r--r--apitools/base/py/testing/mock.py3
-rw-r--r--apitools/base/py/testing/mock_test.py39
-rw-r--r--apitools/base/py/transfer_test.py6
-rw-r--r--apitools/base/py/util.py8
-rw-r--r--apitools/base/py/util_test.py4
-rw-r--r--apitools/gen/client_generation_test.py6
-rw-r--r--apitools/gen/gen_client_test.py5
-rw-r--r--apitools/gen/service_registry.py1
-rw-r--r--apitools/gen/test_utils.py4
-rw-r--r--apitools/gen/util.py37
-rw-r--r--apitools/gen/util_test.py8
-rw-r--r--samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py1
-rw-r--r--samples/dns_sample/dns_v1/dns_v1_client.py1
-rw-r--r--samples/dns_sample/gen_dns_client_test.py7
-rw-r--r--samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py1
-rw-r--r--samples/iam_sample/iam_client_test.py7
-rw-r--r--samples/iam_sample/iam_v1/iam_v1_client.py1
-rw-r--r--samples/servicemanagement_sample/messages_test.py4
-rw-r--r--samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py1
-rw-r--r--samples/storage_sample/storage_v1.json1
-rw-r--r--samples/storage_sample/storage_v1/storage_v1_client.py1
-rw-r--r--samples/uptodate_check_test.py4
-rw-r--r--setup.py8
-rw-r--r--tox.ini6
44 files changed, 277 insertions, 118 deletions
diff --git a/.travis.yml b/.travis.yml
index 627bf3d..453e56d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,4 @@
language: python
-sudo: false
matrix:
include:
- python: "2.7"
@@ -12,8 +11,6 @@ matrix:
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/METADATA b/METADATA
index 536369d..e5ecb93 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@ third_party {
type: GIT
value: "https://github.com/google/apitools"
}
- version: "v0.5.30"
+ version: "v0.5.31"
license_type: NOTICE
last_upgrade_date {
- year: 2019
- month: 6
- day: 26
+ year: 2020
+ month: 5
+ day: 14
}
}
diff --git a/apitools/base/protorpclite/descriptor.py b/apitools/base/protorpclite/descriptor.py
index add0e4c..70b7ed1 100644
--- a/apitools/base/protorpclite/descriptor.py
+++ b/apitools/base/protorpclite/descriptor.py
@@ -292,7 +292,7 @@ def describe_enum(enum_definition):
enum_descriptor.name = enum_definition.definition_name().split('.')[-1]
values = []
- for number in enum_definition.numbers():
+ for number in sorted(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 fc27ec4..5fbed35 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 @@ class DescribeEnumTest(test_util.TestCase):
described.check_initialized()
self.assertEquals(expected, described)
- @unittest2.skipIf('PyPy' in platform.python_implementation(),
- 'todo: reenable this')
+ @unittest.skipIf('PyPy' in platform.python_implementation(),
+ 'todo: reenable this')
def testEnumWithItems(self):
class EnumWithItems(messages.Enum):
A = 3
@@ -512,4 +512,4 @@ class DescriptorLibraryTest(test_util.TestCase):
if __name__ == '__main__':
- unittest2.main()
+ unittest.main()
diff --git a/apitools/base/protorpclite/test_util.py b/apitools/base/protorpclite/test_util.py
index 43345fc..89e3a68 100644
--- a/apitools/base/protorpclite/test_util.py
+++ b/apitools/base/protorpclite/test_util.py
@@ -33,10 +33,10 @@ import os
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 b00085c..27b1727 100644
--- a/apitools/base/py/base_api_test.py
+++ b/apitools/base/py/base_api_test.py
@@ -17,11 +17,11 @@ import base64
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 @@ class FakeService(base_api.BaseApiService):
super(FakeService, self).__init__(client)
-class BaseApiTest(unittest2.TestCase):
+class BaseApiTest(unittest.TestCase):
def __GetFakeClient(self):
return FakeClient('', credentials=FakeCredentials())
@@ -331,4 +331,4 @@ class BaseApiTest(unittest2.TestCase):
if __name__ == '__main__':
- unittest2.main()
+ unittest.main()
diff --git a/apitools/base/py/batch_test.py b/apitools/base/py/batch_test.py
index 0574dc6..90cf4fb 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 @@ class FakeService(object):
return http_response
-class BatchTest(unittest2.TestCase):
+class BatchTest(unittest.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 2098fb1..4de231d 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(unittest2.TestCase):
+class BufferedStreamTest(unittest.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 c8ecdac..9832b31 100644
--- a/apitools/base/py/compression_test.py
+++ b/apitools/base/py/compression_test.py
@@ -16,14 +16,15 @@
"""Tests for compression."""
+import unittest
+
from apitools.base.py import compression
from apitools.base.py import gzip
import six
-import unittest2
-class CompressionTest(unittest2.TestCase):
+class CompressionTest(unittest.TestCase):
def setUp(self):
# Sample highly compressible data (~50MB).
@@ -98,7 +99,7 @@ class CompressionTest(unittest2.TestCase):
self.assertTrue(exhausted)
-class StreamingBufferTest(unittest2.TestCase):
+class StreamingBufferTest(unittest.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 bf39285..0823f93 100644
--- a/apitools/base/py/credentials_lib.py
+++ b/apitools/base/py/credentials_lib.py
@@ -17,6 +17,7 @@
"""Common credentials classes and constructors."""
from __future__ import print_function
+import argparse
import contextlib
import datetime
import json
@@ -515,10 +516,6 @@ def _GetRunFlowFlags(args=None):
# 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)
@@ -721,10 +718,6 @@ def _GetServiceAccountCredentials(
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.
@@ -732,6 +725,10 @@ def _GetServiceAccountCredentials(
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 80b970c..64f056d 100644
--- a/apitools/base/py/credentials_lib_test.py
+++ b/apitools/base/py/credentials_lib_test.py
@@ -17,10 +17,10 @@ import json
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 @@ class MetadataMock(object):
self.fail('Unexpected HTTP request to %s' % request_url)
-class CredentialsLibTest(unittest2.TestCase):
+class CredentialsLibTest(unittest.TestCase):
def _RunGceAssertionCredentials(
self, service_account_name=None, scopes=None, cache_filename=None):
@@ -153,7 +153,7 @@ class CredentialsLibTest(unittest2.TestCase):
self.assertIsNone(creds)
-class TestGetRunFlowFlags(unittest2.TestCase):
+class TestGetRunFlowFlags(unittest.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 d130cc5..54058a2 100644
--- a/apitools/base/py/encoding_test.py
+++ b/apitools/base/py/encoding_test.py
@@ -17,8 +17,7 @@ import base64
import datetime
import json
import sys
-
-import unittest2
+import unittest
from apitools.base.protorpclite import message_types
from apitools.base.protorpclite import messages
@@ -238,7 +237,7 @@ encoding.AddCustomJsonFieldMapping(MessageWithRemappings,
'repeated_field', 'repeatedField')
-class EncodingTest(unittest2.TestCase):
+class EncodingTest(unittest.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 4937f73..6e3a182 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 unittest2
+import unittest
from apitools.base.py import exceptions
from apitools.base.py import http_wrapper
@@ -24,7 +24,7 @@ def _MakeResponse(status_code):
request_url='http://www.google.com')
-class HttpErrorFromResponseTest(unittest2.TestCase):
+class HttpErrorFromResponseTest(unittest.TestCase):
"""Tests for exceptions.HttpError.FromResponse."""
diff --git a/apitools/base/py/extra_types.py b/apitools/base/py/extra_types.py
index 847dc91..e40a785 100644
--- a/apitools/base/py/extra_types.py
+++ b/apitools/base/py/extra_types.py
@@ -16,7 +16,6 @@
"""Extra types understood by apitools."""
-import collections
import datetime
import json
import numbers
@@ -30,6 +29,11 @@ from apitools.base.py import encoding_helper as encoding
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',
@@ -129,7 +133,7 @@ def _PythonValueToJsonValue(py_value):
return JsonValue(double_value=float(py_value))
if isinstance(py_value, dict):
return JsonValue(object_value=_PythonValueToJsonObject(py_value))
- if isinstance(py_value, collections.Iterable):
+ if isinstance(py_value, Iterable):
return JsonValue(array_value=_PythonValueToJsonArray(py_value))
raise exceptions.InvalidDataError(
'Cannot convert "%s" to JsonValue' % py_value)
@@ -212,7 +216,7 @@ def _JsonProtoToPythonValue(json_proto):
def _PythonValueToJsonProto(py_value):
if isinstance(py_value, dict):
return _PythonValueToJsonObject(py_value)
- if (isinstance(py_value, collections.Iterable) and
+ if (isinstance(py_value, 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 7e37f7c..6a4092b 100644
--- a/apitools/base/py/extra_types_test.py
+++ b/apitools/base/py/extra_types_test.py
@@ -16,8 +16,7 @@
import datetime
import json
import math
-
-import unittest2
+import unittest
from apitools.base.protorpclite import messages
from apitools.base.py import encoding
@@ -25,7 +24,7 @@ from apitools.base.py import exceptions
from apitools.base.py import extra_types
-class ExtraTypesTest(unittest2.TestCase):
+class ExtraTypesTest(unittest.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 a3fe65c..c31bea0 100644
--- a/apitools/base/py/http_wrapper.py
+++ b/apitools/base/py/http_wrapper.py
@@ -339,6 +339,10 @@ def MakeRequest(http, http_request, retries=7, max_retry_wait=60,
"""
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 ce4c03e..fdf56f5 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 @@ class RaisesExceptionOnLen(object):
return 1
-class HttpWrapperTest(unittest2.TestCase):
+class HttpWrapperTest(unittest.TestCase):
def testRequestBodyUsesLengthProperty(self):
http_wrapper.Request(body=RaisesExceptionOnLen())
@@ -65,8 +65,8 @@ class HttpWrapperTest(unittest2.TestCase):
def testRequestBodyWithLen(self):
http_wrapper.Request(body='burrito')
- @unittest2.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE,
- 'oauth2client<1.5 lacks HttpAccessTokenRefreshError.')
+ @unittest.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 @@ class HttpWrapperTest(unittest2.TestCase):
http_wrapper.HandleExceptionsAndRebuildHttpConnections(
retry_args)
- @unittest2.skipIf(not _TOKEN_REFRESH_STATUS_AVAILABLE,
- 'oauth2client<1.5 lacks HttpAccessTokenRefreshError.')
+ @unittest.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 fb14c14..a2c1080 100644
--- a/apitools/base/py/list_pager.py
+++ b/apitools/base/py/list_pager.py
@@ -17,18 +17,58 @@
"""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'):
+ batch_size_attribute='maxResults',
+ get_field_func=_GetattrNested):
"""Make a series of List requests, keeping track of page tokens.
Args:
@@ -45,21 +85,25 @@ def YieldFromList(
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, The name of the attribute in a
+ current_token_attribute: str or tuple, The name of the attribute in a
request message holding the page token for the page being
- 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
+ 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
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)
- setattr(request, current_token_attribute, None)
+ _SetattrNested(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.
@@ -72,10 +116,10 @@ def YieldFromList(
request_batch_size = None
else:
request_batch_size = min(batch_size, limit or batch_size)
- setattr(request, batch_size_attribute, request_batch_size)
+ _SetattrNested(request, batch_size_attribute, request_batch_size)
response = getattr(service, method)(request,
global_params=global_params)
- items = getattr(response, field)
+ items = get_field_func(response, field)
if predicate:
items = list(filter(predicate, items))
for item in items:
@@ -85,7 +129,7 @@ def YieldFromList(
limit -= 1
if not limit:
return
- token = getattr(response, next_token_attribute)
+ token = _GetattrNested(response, next_token_attribute)
if not token:
return
- setattr(request, current_token_attribute, token)
+ _SetattrNested(request, current_token_attribute, token)
diff --git a/apitools/base/py/list_pager_test.py b/apitools/base/py/list_pager_test.py
index 32dfea6..1ea6368 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 unittest2
+import unittest
from apitools.base.py import list_pager
from apitools.base.py.testing import mock
@@ -27,7 +27,33 @@ from samples.iam_sample.iam_v1 import iam_v1_client as iam_client
from samples.iam_sample.iam_v1 import iam_v1_messages as iam_messages
-class ListPagerTest(unittest2.TestCase):
+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):
def _AssertInstanceSequence(self, results, n):
counter = 0
@@ -242,8 +268,34 @@ class ListPagerTest(unittest2.TestCase):
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(unittest2.TestCase):
+class ListPagerAttributeTest(unittest.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 4d5cdfb..f29e112 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(unittest2.TestCase):
+class StreamSliceTest(unittest.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 3bd38ba..ae6ad89 100644
--- a/apitools/base/py/testing/mock.py
+++ b/apitools/base/py/testing/mock.py
@@ -170,7 +170,8 @@ class _ExpectedRequestResponse(object):
The response that was specified to be returned.
"""
- if key != self.__key or not _MessagesEqual(request, self.__request):
+ if key != self.__key or not (self.__request == request or
+ _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 4afdf7b..9bd8f05 100644
--- a/apitools/base/py/testing/mock_test.py
+++ b/apitools/base/py/testing/mock_test.py
@@ -15,8 +15,9 @@
"""Tests for apitools.base.py.testing.mock."""
+import unittest
+
import httplib2
-import unittest2
import six
from apitools.base.protorpclite import messages
@@ -42,7 +43,7 @@ class CustomException(Exception):
pass
-class MockTest(unittest2.TestCase):
+class MockTest(unittest.TestCase):
def testMockFusionBasic(self):
with mock.Client(fusiontables.FusiontablesV1) as client_class:
@@ -151,6 +152,38 @@ class MockTest(unittest2.TestCase):
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))
@@ -220,7 +253,7 @@ class _NestedNestedMessage(messages.Message):
nested = messages.MessageField(_NestedMessage, 1)
-class UtilTest(unittest2.TestCase):
+class UtilTest(unittest.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 c68e77e..4a9e79c 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 http_wrapper
from apitools.base.py import transfer
-class TransferTest(unittest2.TestCase):
+class TransferTest(unittest.TestCase):
def assertRangeAndContentRangeCompatible(self, request, response):
request_prefix = 'bytes='
@@ -311,7 +311,7 @@ class TransferTest(unittest2.TestCase):
self.assertTrue(rewritten_upload_contents.endswith(upload_bytes))
-class UploadTest(unittest2.TestCase):
+class UploadTest(unittest.TestCase):
def setUp(self):
# Sample highly compressible data.
diff --git a/apitools/base/py/util.py b/apitools/base/py/util.py
index ac1a44c..ad086e4 100644
--- a/apitools/base/py/util.py
+++ b/apitools/base/py/util.py
@@ -16,7 +16,6 @@
"""Assorted utilities shared between parts of apitools."""
-import collections
import os
import random
@@ -30,6 +29,11 @@ from apitools.base.protorpclite import messages
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',
@@ -78,7 +82,7 @@ def NormalizeScopes(scope_spec):
if isinstance(scope_spec, six.string_types):
scope_spec = six.ensure_str(scope_spec)
return set(scope_spec.split(' '))
- elif isinstance(scope_spec, collections.Iterable):
+ elif isinstance(scope_spec, 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 b2ece27..c3a4732 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 unittest2
+import unittest
from apitools.base.protorpclite import messages
from apitools.base.py import encoding
@@ -48,7 +48,7 @@ encoding.AddCustomJsonEnumMapping(
MessageWithRemappings.AnEnum, 'value_one', 'ONE')
-class UtilTest(unittest2.TestCase):
+class UtilTest(unittest.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 9146501..4e382dd 100644
--- a/apitools/gen/client_generation_test.py
+++ b/apitools/gen/client_generation_test.py
@@ -22,15 +22,11 @@ import six
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 6c4e9b1..a0f30d5 100644
--- a/apitools/gen/gen_client_test.py
+++ b/apitools/gen/gen_client_test.py
@@ -16,8 +16,7 @@
"""Test for gen_client module."""
import os
-
-import unittest2
+import unittest
from apitools.gen import gen_client
from apitools.gen import test_utils
@@ -32,7 +31,7 @@ def _GetContent(file_path):
return f.read()
-class ClientGenCliTest(unittest2.TestCase):
+class ClientGenCliTest(unittest.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 e47b050..b79f0d1 100644
--- a/apitools/gen/service_registry.py
+++ b/apitools/gen/service_registry.py
@@ -218,6 +218,7 @@ class ServiceRegistry(object):
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 484dcbc..e6b5373 100644
--- a/apitools/gen/test_utils.py
+++ b/apitools/gen/test_utils.py
@@ -20,12 +20,12 @@ import os
import shutil
import sys
import tempfile
+import unittest
import six
-import unittest2
-SkipOnWindows = unittest2.skipIf(
+SkipOnWindows = unittest.skipIf(
os.name == 'nt', 'Does not run on windows')
diff --git a/apitools/gen/util.py b/apitools/gen/util.py
index 680d84a..c2955a8 100644
--- a/apitools/gen/util.py
+++ b/apitools/gen/util.py
@@ -93,7 +93,7 @@ class Names(object):
name = re.sub('[^_A-Za-z0-9]', '_', name)
if name[0].isdigit():
name = '_%s' % name
- while keyword.iskeyword(name):
+ while keyword.iskeyword(name) or name == 'exec':
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,9 +174,21 @@ def NormalizeVersion(version):
return version.replace('.', '_')
-def _ComputePaths(package, version, discovery_doc):
- full_path = urllib_parse.urljoin(
- discovery_doc['rootUrl'], discovery_doc['servicePath'])
+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)
api_path_component = '/'.join((package, version, ''))
if api_path_component not in full_path:
return full_path, ''
@@ -187,7 +199,7 @@ def _ComputePaths(package, version, discovery_doc):
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'))):
+ 'base_url', 'base_path', 'mtls_base_url'))):
"""Container for client-related info and names."""
@@ -201,7 +213,15 @@ class ClientInfo(collections.namedtuple('ClientInfo', (
package = discovery_doc['name']
url_version = discovery_doc['version']
base_url, base_path = _ComputePaths(package, url_version,
- discovery_doc)
+ 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'])
client_info = {
'package': package,
@@ -214,6 +234,7 @@ class ClientInfo(collections.namedtuple('ClientInfo', (
'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']),
@@ -403,7 +424,8 @@ def FetchDiscoveryDoc(discovery_url, retries=5):
if isinstance(content, bytes):
content = content.decode('utf8')
discovery_doc = json.loads(content)
- break
+ if discovery_doc:
+ return discovery_doc
except (urllib_error.HTTPError, urllib_error.URLError) as e:
logging.info(
'Attempting to fetch discovery doc again after "%s"', e)
@@ -412,4 +434,3 @@ def FetchDiscoveryDoc(discovery_url, retries=5):
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 7668b53..9682bf9 100644
--- a/apitools/gen/util_test.py
+++ b/apitools/gen/util_test.py
@@ -21,13 +21,13 @@ import gzip
import os
import six.moves.urllib.request as urllib_request
import tempfile
-import unittest2
+import unittest
from apitools.gen import util
from mock import patch
-class NormalizeVersionTest(unittest2.TestCase):
+class NormalizeVersionTest(unittest.TestCase):
def testVersions(self):
already_valid = 'v1'
@@ -36,7 +36,7 @@ class NormalizeVersionTest(unittest2.TestCase):
self.assertEqual('v0_1', util.NormalizeVersion(to_clean))
-class NamesTest(unittest2.TestCase):
+class NamesTest(unittest.TestCase):
def testKeywords(self):
names = util.Names([''])
@@ -81,7 +81,7 @@ def _Gzip(raw_content):
os.unlink(f.name)
-class GetURLContentTest(unittest2.TestCase):
+class GetURLContentTest(unittest.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 e6cf9c8..90552da 100644
--- a/samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py
+++ b/samples/bigquery_sample/bigquery_v2/bigquery_v2_client.py
@@ -9,6 +9,7 @@ class BigqueryV2(base_api.BaseApiClient):
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 ce3aff6..0666460 100644
--- a/samples/dns_sample/dns_v1/dns_v1_client.py
+++ b/samples/dns_sample/dns_v1/dns_v1_client.py
@@ -9,6 +9,7 @@ class DnsV1(base_api.BaseApiClient):
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 dff6812..862ddba 100644
--- a/samples/dns_sample/gen_dns_client_test.py
+++ b/samples/dns_sample/gen_dns_client_test.py
@@ -15,7 +15,8 @@
"""Test for generated sample module."""
-import unittest2
+import unittest
+
import six
from apitools.base.py import list_pager
@@ -25,7 +26,7 @@ from samples.dns_sample.dns_v1 import dns_v1_client
from samples.dns_sample.dns_v1 import dns_v1_messages
-class DnsGenClientSanityTest(unittest2.TestCase):
+class DnsGenClientSanityTest(unittest.TestCase):
def testBaseUrl(self):
self.assertEquals(u'https://www.googleapis.com/dns/v1/',
@@ -46,7 +47,7 @@ class DnsGenClientSanityTest(unittest2.TestCase):
'ResourceRecordSetsService']), inner_classes)
-class DnsGenClientTest(unittest2.TestCase):
+class DnsGenClientTest(unittest.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 f80fb3e..b7b6c43 100644
--- a/samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py
+++ b/samples/fusiontables_sample/fusiontables_v1/fusiontables_v1_client.py
@@ -9,6 +9,7 @@ class FusiontablesV1(base_api.BaseApiClient):
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 39d25a4..017a2d0 100644
--- a/samples/iam_sample/iam_client_test.py
+++ b/samples/iam_sample/iam_client_test.py
@@ -15,7 +15,8 @@
"""Test for generated sample module."""
-import unittest2
+import unittest
+
import six
from apitools.base.py.testing import mock
@@ -24,7 +25,7 @@ from samples.iam_sample.iam_v1 import iam_v1_client # nopep8
from samples.iam_sample.iam_v1 import iam_v1_messages # nopep8
-class DnsGenClientSanityTest(unittest2.TestCase):
+class DnsGenClientSanityTest(unittest.TestCase):
def testBaseUrl(self):
self.assertEquals(u'https://iam.googleapis.com/',
@@ -46,7 +47,7 @@ class DnsGenClientSanityTest(unittest2.TestCase):
'RolesService']), inner_classes)
-class IamGenClientTest(unittest2.TestCase):
+class IamGenClientTest(unittest.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 9f333ef..ed9112e 100644
--- a/samples/iam_sample/iam_v1/iam_v1_client.py
+++ b/samples/iam_sample/iam_v1/iam_v1_client.py
@@ -9,6 +9,7 @@ class IamV1(base_api.BaseApiClient):
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 a62dbd7..5f56322 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 unittest2
+import unittest
from apitools.base.py import extra_types
@@ -23,7 +23,7 @@ from samples.servicemanagement_sample.servicemanagement_v1 \
import servicemanagement_v1_messages as messages # nopep8
-class MessagesTest(unittest2.TestCase):
+class MessagesTest(unittest.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 a72936e..25823db 100644
--- a/samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py
+++ b/samples/servicemanagement_sample/servicemanagement_v1/servicemanagement_v1_client.py
@@ -9,6 +9,7 @@ class ServicemanagementV1(base_api.BaseApiClient):
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 2636bda..cfd2748 100644
--- a/samples/storage_sample/storage_v1.json
+++ b/samples/storage_sample/storage_v1.json
@@ -21,6 +21,7 @@
"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 38ceab9..4a8414a 100644
--- a/samples/storage_sample/storage_v1/storage_v1_client.py
+++ b/samples/storage_sample/storage_v1/storage_v1_client.py
@@ -9,6 +9,7 @@ class StorageV1(base_api.BaseApiClient):
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 3871695..8ca258e 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 @@ def _GetContent(file_path):
return f.read()
-class ClientGenCliTest(unittest2.TestCase):
+class ClientGenCliTest(unittest.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 fbf81b1..f6e26a2 100644
--- a/setup.py
+++ b/setup.py
@@ -39,7 +39,6 @@ CLI_PACKAGES = [
]
TESTING_PACKAGES = [
- 'unittest2>=0.5.1',
'mock>=1.0.1',
]
@@ -49,7 +48,7 @@ CONSOLE_SCRIPTS = [
py_version = platform.python_version()
-_APITOOLS_VERSION = '0.5.30'
+_APITOOLS_VERSION = '0.5.31'
with open('README.rst') as fileobj:
README = fileobj.read()
@@ -62,6 +61,7 @@ setuptools.setup(
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,6 +88,10 @@ setuptools.setup(
# 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 aaa22e0..09d2afc 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,9 +1,6 @@
[tox]
envlist =
- py26-oauth2client4
py27-oauth2client{1,2,3,4}
- py33-oauth2client41
- py34-oauth2client41
py35-oauth2client{1,2,3,4}
[testenv]
@@ -28,7 +25,6 @@ commands =
deps =
pycodestyle==2.4.0
pylint
- unittest2
[testenv:cover]
basepython =
@@ -39,7 +35,6 @@ deps =
python-gflags
mock
nose
- unittest2
coverage
nosexcover
@@ -58,7 +53,6 @@ basepython =
deps =
mock
nose
- unittest2
coverage
commands =
coverage run --branch -p samples/storage_sample/downloads_test.py