From 181d706e5b44d9d4189c21782551ce85c720d733 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 2 Aug 2021 14:54:16 -0400 Subject: [PATCH] fix!: drop python 2.7 support (#103) Drop 'mock' shim Drop 'six' Drop explicit 'u"' prefix Drop 'pytz' Expand ranges to allow 2.x versions of 'google-auth' / `google-api-core`. Release-As: 2.0.0b1 Closes #102 --- CONTRIBUTING.rst | 8 +-- README.rst | 7 ++- google/cloud/_helpers.py | 66 ++++----------------- google/cloud/_http.py | 11 +--- google/cloud/_testing.py | 8 +-- google/cloud/client.py | 6 +- google/cloud/version.py | 2 +- noxfile.py | 6 +- owlbot.py | 4 +- setup.py | 11 +--- testing/constraints-2.7.txt | 3 - testing/constraints-3.5.txt | 2 - testing/constraints-3.6.txt | 3 +- tests/unit/test__helpers.py | 105 +++++----------------------------- tests/unit/test__http.py | 100 ++++++++++++++++---------------- tests/unit/test_client.py | 11 ++-- tests/unit/test_exceptions.py | 20 +++---- tests/unit/test_obsolete.py | 3 +- tests/unit/test_operation.py | 2 +- 19 files changed, 114 insertions(+), 264 deletions(-) delete mode 100644 testing/constraints-2.7.txt delete mode 100644 testing/constraints-3.5.txt diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b6ae668..e4542d4 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -22,7 +22,7 @@ In order to add a feature: documentation. - The feature must work fully on the following CPython versions: - 2.7, 3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows. + 3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should @@ -148,7 +148,7 @@ Running System Tests .. note:: - System tests are only configured to run under Python 2.7 and 3.8. + System tests are only configured to run under Python 3.8. For expediency, we do not run them in older versions of Python 3. This alone will not run the tests. You'll need to change some local @@ -221,13 +221,11 @@ Supported Python Versions We support: -- `Python 2.7`_ - `Python 3.6`_ - `Python 3.7`_ - `Python 3.8`_ - `Python 3.9`_ -.. _Python 2.7: https://docs.python.org/2.7/ .. _Python 3.6: https://docs.python.org/3.6/ .. _Python 3.7: https://docs.python.org/3.7/ .. _Python 3.8: https://docs.python.org/3.8/ @@ -239,7 +237,7 @@ Supported versions can be found in our ``noxfile.py`` `config`_. .. _config: https://github.com/googleapis/python-cloud-core/blob/master/noxfile.py -We also explicitly decided to support Python 3 beginning with version 2.7. +We also explicitly decided to support Python 3 beginning with version 3.6. Reasons for this include: - Encouraging use of newest versions of Python 3 diff --git a/README.rst b/README.rst index 1d760ae..f64c3f6 100644 --- a/README.rst +++ b/README.rst @@ -34,6 +34,7 @@ Supported Python Versions ------------------------- Python >= 3.6 -Deprecated Python Versions --------------------------- -Python == 2.7. Python 2.7 support will be removed on January 1, 2020. +Unsupported Python Versions +--------------------------- +Python == 2.7: the last version of this library which supported Python 2.7 +is ``google.cloud.core 1.7.2``. diff --git a/google/cloud/_helpers.py b/google/cloud/_helpers.py index 52a96b8..d8f2851 100644 --- a/google/cloud/_helpers.py +++ b/google/cloud/_helpers.py @@ -21,13 +21,11 @@ import calendar import datetime +import http.client import os import re from threading import local as Local -import six -from six.moves import http_client - import google.auth import google.auth.transport.requests from google.protobuf import duration_pb2 @@ -41,6 +39,9 @@ _NOW = datetime.datetime.utcnow # To be replaced by tests. +UTC = datetime.timezone.utc # Singleton instance to be used throughout. +_EPOCH = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc) + _RFC3339_MICROS = "%Y-%m-%dT%H:%M:%S.%fZ" _RFC3339_NO_FRACTION = "%Y-%m-%dT%H:%M:%S" _TIMEONLY_W_MICROS = "%H:%M:%S.%f" @@ -111,41 +112,6 @@ def top(self): return self._stack[-1] -class _UTC(datetime.tzinfo): - """Basic UTC implementation. - - Implementing a small surface area to avoid depending on ``pytz``. - """ - - _dst = datetime.timedelta(0) - _tzname = "UTC" - _utcoffset = _dst - - def dst(self, dt): # pylint: disable=unused-argument - """Daylight savings time offset.""" - return self._dst - - def fromutc(self, dt): - """Convert a timestamp from (naive) UTC to this timezone.""" - if dt.tzinfo is None: - return dt.replace(tzinfo=self) - return super(_UTC, self).fromutc(dt) - - def tzname(self, dt): # pylint: disable=unused-argument - """Get the name of this timezone.""" - return self._tzname - - def utcoffset(self, dt): # pylint: disable=unused-argument - """UTC offset of this timezone.""" - return self._utcoffset - - def __repr__(self): - return "<%s>" % (self._tzname,) - - def __str__(self): - return self._tzname - - def _ensure_tuple_or_list(arg_name, tuple_or_list): """Ensures an input is a tuple or list. @@ -344,9 +310,6 @@ def _datetime_to_rfc3339(value, ignore_zone=True): def _to_bytes(value, encoding="ascii"): """Converts a string value to bytes, if necessary. - Unfortunately, ``six.b`` is insufficient for this task since in - Python2 it does not modify ``unicode`` objects. - :type value: str / bytes or unicode :param value: The string/bytes value to be converted. @@ -363,8 +326,8 @@ def _to_bytes(value, encoding="ascii"): in if it started out as bytes. :raises TypeError: if the value could not be converted to bytes. """ - result = value.encode(encoding) if isinstance(value, six.text_type) else value - if isinstance(result, six.binary_type): + result = value.encode(encoding) if isinstance(value, str) else value + if isinstance(result, bytes): return result else: raise TypeError("%r could not be converted to bytes" % (value,)) @@ -382,8 +345,8 @@ def _bytes_to_unicode(value): :raises ValueError: if the value could not be converted to unicode. """ - result = value.decode("utf-8") if isinstance(value, six.binary_type) else value - if isinstance(result, six.text_type): + result = value.decode("utf-8") if isinstance(value, bytes) else value + if isinstance(result, str): return result else: raise ValueError("%r could not be converted to unicode" % (value,)) @@ -559,7 +522,7 @@ def make_secure_channel(credentials, user_agent, host, extra_options=()): :rtype: :class:`grpc._channel.Channel` :returns: gRPC secure channel with credentials attached. """ - target = "%s:%d" % (host, http_client.HTTPS_PORT) + target = "%s:%d" % (host, http.client.HTTPS_PORT) http_request = google.auth.transport.requests.Request() user_agent_option = ("grpc.primary_user_agent", user_agent) @@ -621,16 +584,7 @@ def make_insecure_stub(stub_class, host, port=None): if port is None: target = host else: - # NOTE: This assumes port != http_client.HTTPS_PORT: + # NOTE: This assumes port != http.client.HTTPS_PORT: target = "%s:%d" % (host, port) channel = grpc.insecure_channel(target) return stub_class(channel) - - -try: - from pytz import UTC # pylint: disable=unused-import,wrong-import-order -except ImportError: # pragma: NO COVER - UTC = _UTC() # Singleton instance to be used throughout. - -# Need to define _EPOCH at the end of module since it relies on UTC. -_EPOCH = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=UTC) diff --git a/google/cloud/_http.py b/google/cloud/_http.py index 6627a9b..7c9cbc9 100644 --- a/google/cloud/_http.py +++ b/google/cloud/_http.py @@ -15,18 +15,13 @@ """Shared implementation of connections to API servers.""" import collections - -try: - import collections.abc as collections_abc -except ImportError: # Python2 - import collections as collections_abc +import collections.abc import json import os import platform +from urllib.parse import urlencode import warnings -from six.moves.urllib.parse import urlencode - from google.api_core.client_info import ClientInfo from google.cloud import exceptions from google.cloud import version @@ -263,7 +258,7 @@ def build_api_url( query_params = query_params or {} - if isinstance(query_params, collections_abc.Mapping): + if isinstance(query_params, collections.abc.Mapping): query_params = query_params.copy() else: query_params_dict = collections.defaultdict(list) diff --git a/google/cloud/_testing.py b/google/cloud/_testing.py index 04f0dba..8bbd082 100644 --- a/google/cloud/_testing.py +++ b/google/cloud/_testing.py @@ -117,10 +117,6 @@ def __init__(self, *pages, **kwargs): self._pages = iter(pages) self.page_token = kwargs.get("page_token") - def next(self): + def __next__(self): """Iterate to the next page.""" - import six - - return six.next(self._pages) - - __next__ = next + return next(self._pages) diff --git a/google/cloud/client.py b/google/cloud/client.py index c2e7cff..e058c2d 100644 --- a/google/cloud/client.py +++ b/google/cloud/client.py @@ -19,8 +19,6 @@ import os from pickle import PicklingError -import six - import google.api_core.client_options import google.api_core.exceptions import google.auth @@ -271,10 +269,10 @@ def __init__(self, project=None, credentials=None): "determined from the environment." ) - if isinstance(project, six.binary_type): + if isinstance(project, bytes): project = project.decode("utf-8") - if not isinstance(project, six.string_types): + if not isinstance(project, str): raise ValueError("Project must be a string.") self.project = project diff --git a/google/cloud/version.py b/google/cloud/version.py index ce786ff..5fa7744 100644 --- a/google/cloud/version.py +++ b/google/cloud/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.7.2" +__version__ = "2.0.0b1" diff --git a/noxfile.py b/noxfile.py index cf7ba7c..fbe1359 100644 --- a/noxfile.py +++ b/noxfile.py @@ -60,9 +60,7 @@ def default(session): ) # Install all test dependencies, then install local packages in-place. - session.install( - "mock", "pytest", "pytest-cov", "grpcio >= 1.0.2", "-c", constraints_path - ) + session.install("pytest", "pytest-cov", "grpcio >= 1.0.2", "-c", constraints_path) session.install("-e", ".", "-c", constraints_path) # Run py.test against the unit tests. @@ -80,7 +78,7 @@ def default(session): ) -@nox.session(python=["2.7", "3.6", "3.7", "3.8", "3.9"]) +@nox.session(python=["3.6", "3.7", "3.8", "3.9"]) def unit(session): """Default unit test session.""" default(session) diff --git a/owlbot.py b/owlbot.py index 80f0c15..5b0f6c3 100644 --- a/owlbot.py +++ b/owlbot.py @@ -14,8 +14,6 @@ """This script is used to synthesize generated parts of this library.""" -import re - import synthtool as s from synthtool import gcp @@ -24,7 +22,7 @@ # ---------------------------------------------------------------------------- # Add templated files # ---------------------------------------------------------------------------- -templated_files = common.py_library(cov_level=100) +templated_files = common.py_library(microgenerator=True, cov_level=100) s.move( templated_files, excludes=[ diff --git a/setup.py b/setup.py index 66e115c..78457ca 100644 --- a/setup.py +++ b/setup.py @@ -28,11 +28,8 @@ # 'Development Status :: 5 - Production/Stable' release_status = "Development Status :: 5 - Production/Stable" dependencies = [ - "google-api-core >= 1.21.0, < 2.0.0dev", - "google-auth >= 1.24.0, < 2.0dev", - # Support six==1.12.0 due to App Engine standard runtime. - # https://github.com/googleapis/python-cloud-core/issues/45 - "six >=1.12.0", + "google-api-core >= 1.21.0, < 3.0.0dev", + "google-auth >= 1.24.0, < 3.0dev", ] extras = {"grpc": "grpcio >= 1.8.2, < 2.0dev"} @@ -76,8 +73,6 @@ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", @@ -91,7 +86,7 @@ namespace_packages=namespaces, install_requires=dependencies, extras_require=extras, - python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*", + python_requires=">=3.6", include_package_data=True, zip_safe=False, ) diff --git a/testing/constraints-2.7.txt b/testing/constraints-2.7.txt deleted file mode 100644 index 3b6cd2c..0000000 --- a/testing/constraints-2.7.txt +++ /dev/null @@ -1,3 +0,0 @@ -google-api-core==1.21.0 -googleapis-common-protos<1.53.0 -six==1.12.0 diff --git a/testing/constraints-3.5.txt b/testing/constraints-3.5.txt deleted file mode 100644 index 8679811..0000000 --- a/testing/constraints-3.5.txt +++ /dev/null @@ -1,2 +0,0 @@ -google-api-core==1.21.0 -six==1.12.0 diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt index 83fc2eb..9bd2a7c 100644 --- a/testing/constraints-3.6.txt +++ b/testing/constraints-3.6.txt @@ -6,5 +6,4 @@ # e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", # Then this file should have foo==1.14.0 google-api-core==1.21.0 -six==1.12.0 -grpcio==1.8.2 \ No newline at end of file +grpcio==1.8.2 diff --git a/tests/unit/test__helpers.py b/tests/unit/test__helpers.py index 03e2ff2..db0fa5b 100644 --- a/tests/unit/test__helpers.py +++ b/tests/unit/test__helpers.py @@ -13,8 +13,7 @@ # limitations under the License. import unittest - -import mock +from unittest import mock class Test__LocalStack(unittest.TestCase): @@ -45,69 +44,6 @@ def test_it(self): self.assertEqual(list(batches), []) -class Test__UTC(unittest.TestCase): - @staticmethod - def _get_target_class(): - from google.cloud._helpers import _UTC - - return _UTC - - def _make_one(self): - return self._get_target_class()() - - def test_module_property(self): - from google.cloud import _helpers as MUT - - klass = self._get_target_class() - try: - import pytz - except ImportError: # pragma: NO COVER - self.assertIsInstance(MUT.UTC, klass) - else: - self.assertIs(MUT.UTC, pytz.UTC) - - def test_dst(self): - import datetime - - tz = self._make_one() - self.assertEqual(tz.dst(None), datetime.timedelta(0)) - - def test_fromutc(self): - import datetime - - naive_epoch = datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=None) - self.assertIsNone(naive_epoch.tzinfo) - tz = self._make_one() - epoch = tz.fromutc(naive_epoch) - self.assertEqual(epoch.tzinfo, tz) - - def test_fromutc_with_tz(self): - import datetime - - tz = self._make_one() - epoch_with_tz = datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=tz) - epoch = tz.fromutc(epoch_with_tz) - self.assertEqual(epoch.tzinfo, tz) - - def test_tzname(self): - tz = self._make_one() - self.assertEqual(tz.tzname(None), "UTC") - - def test_utcoffset(self): - import datetime - - tz = self._make_one() - self.assertEqual(tz.utcoffset(None), datetime.timedelta(0)) - - def test___repr__(self): - tz = self._make_one() - self.assertEqual(repr(tz), "") - - def test___str__(self): - tz = self._make_one() - self.assertEqual(str(tz), "UTC") - - class Test__ensure_tuple_or_list(unittest.TestCase): def _call_fut(self, arg_name, tuple_or_list): from google.cloud._helpers import _ensure_tuple_or_list @@ -199,7 +135,6 @@ def test_w_none(self): def test_w_utc_datetime(self): import datetime - import six from google.cloud._helpers import UTC from google.cloud._helpers import _microseconds_from_datetime @@ -207,30 +142,24 @@ def test_w_utc_datetime(self): NOW_MICROS = _microseconds_from_datetime(NOW) MILLIS = NOW_MICROS // 1000 result = self._call_fut(NOW) - self.assertIsInstance(result, six.integer_types) + self.assertIsInstance(result, int) self.assertEqual(result, MILLIS) def test_w_non_utc_datetime(self): import datetime - import six - from google.cloud._helpers import _UTC from google.cloud._helpers import _microseconds_from_datetime - class CET(_UTC): - _tzname = "CET" - _utcoffset = datetime.timedelta(hours=-1) - - zone = CET() + offset = datetime.timedelta(hours=-1) + zone = datetime.timezone(offset=offset, name="CET") NOW = datetime.datetime(2015, 7, 28, 16, 34, 47, tzinfo=zone) NOW_MICROS = _microseconds_from_datetime(NOW) MILLIS = NOW_MICROS // 1000 result = self._call_fut(NOW) - self.assertIsInstance(result, six.integer_types) + self.assertIsInstance(result, int) self.assertEqual(result, MILLIS) def test_w_naive_datetime(self): import datetime - import six from google.cloud._helpers import UTC from google.cloud._helpers import _microseconds_from_datetime @@ -239,7 +168,7 @@ def test_w_naive_datetime(self): UTC_NOW_MICROS = _microseconds_from_datetime(UTC_NOW) MILLIS = UTC_NOW_MICROS // 1000 result = self._call_fut(NOW) - self.assertIsInstance(result, six.integer_types) + self.assertIsInstance(result, int) self.assertEqual(result, MILLIS) @@ -497,13 +426,9 @@ def _call_fut(self, *args, **kwargs): @staticmethod def _make_timezone(offset): - from google.cloud._helpers import _UTC - - class CET(_UTC): - _tzname = "CET" - _utcoffset = offset + import datetime - return CET() + return datetime.timezone(offset=offset, name="CET") def test_w_utc_datetime(self): import datetime @@ -548,12 +473,12 @@ def test_with_bytes(self): self.assertEqual(self._call_fut(value), value) def test_with_unicode(self): - value = u"string-val" + value = "string-val" encoded_value = b"string-val" self.assertEqual(self._call_fut(value), encoded_value) def test_unicode_non_ascii(self): - value = u"\u2013" # Long hyphen + value = "\u2013" # Long hyphen encoded_value = b"\xe2\x80\x93" self.assertRaises(UnicodeEncodeError, self._call_fut, value) self.assertEqual(self._call_fut(value, encoding="utf-8"), encoded_value) @@ -575,7 +500,7 @@ def test_with_bytes(self): self.assertEqual(self._call_fut(value), encoded_value) def test_with_unicode(self): - value = u"string-val" + value = "string-val" encoded_value = "string-val" self.assertEqual(self._call_fut(value), encoded_value) @@ -795,7 +720,7 @@ def _call_fut(self, *args, **kwargs): return make_secure_channel(*args, **kwargs) def test_it(self): - from six.moves import http_client + import http.client credentials = object() host = "HOST" @@ -810,7 +735,7 @@ def test_it(self): self.assertIs(result, secure_authorized_channel.return_value) - expected_target = "%s:%d" % (host, http_client.HTTPS_PORT) + expected_target = "%s:%d" % (host, http.client.HTTPS_PORT) expected_options = (("grpc.primary_user_agent", user_agent),) secure_authorized_channel.assert_called_once_with( @@ -818,7 +743,7 @@ def test_it(self): ) def test_extra_options(self): - from six.moves import http_client + import http.client credentials = object() host = "HOST" @@ -834,7 +759,7 @@ def test_extra_options(self): self.assertIs(result, secure_authorized_channel.return_value) - expected_target = "%s:%d" % (host, http_client.HTTPS_PORT) + expected_target = "%s:%d" % (host, http.client.HTTPS_PORT) expected_options = (("grpc.primary_user_agent", user_agent), extra_options[0]) secure_authorized_channel.assert_called_once_with( diff --git a/tests/unit/test__http.py b/tests/unit/test__http.py index f96d291..ab03fac 100644 --- a/tests/unit/test__http.py +++ b/tests/unit/test__http.py @@ -12,14 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +import http.client import json import os import unittest +from unittest import mock import warnings -import mock import requests -from six.moves import http_client class TestConnection(unittest.TestCase): @@ -128,7 +128,7 @@ def test_http_property(self): self.assertIs(conn.http, client._http) -def make_response(status=http_client.OK, content=b"", headers={}): +def make_response(status=http.client.OK, content=b"", headers={}): response = requests.Response() response.status_code = status response._content = content @@ -206,8 +206,8 @@ def test_build_api_url_w_pretty_print_query_params(self): self.assertEqual(uri, URI) def test_build_api_url_w_extra_query_params(self): - from six.moves.urllib.parse import parse_qs - from six.moves.urllib.parse import urlsplit + from urllib.parse import parse_qs + from urllib.parse import urlsplit client = object() conn = self._make_mock_one(client) @@ -224,8 +224,8 @@ def test_build_api_url_w_extra_query_params(self): self.assertEqual(parms["prettyPrint"], ["false"]) def test_build_api_url_w_extra_query_params_tuples(self): - from six.moves.urllib.parse import parse_qs - from six.moves.urllib.parse import urlsplit + from urllib.parse import parse_qs + from urllib.parse import urlsplit client = object() conn = self._make_mock_one(client) @@ -290,14 +290,14 @@ def test_get_api_base_url_for_mtls_env_auto(self): def test__make_request_no_data_no_content_type_no_headers(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([make_response()]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response()]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_one(client) url = "http://example.com/test" response = conn._make_request("GET", url) - self.assertEqual(response.status_code, http_client.OK) + self.assertEqual(response.status_code, http.client.OK) self.assertEqual(response.content, b"") expected_headers = { @@ -305,7 +305,7 @@ def test__make_request_no_data_no_content_type_no_headers(self): "User-Agent": conn.user_agent, CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=url, headers=expected_headers, @@ -316,8 +316,8 @@ def test__make_request_no_data_no_content_type_no_headers(self): def test__make_request_w_data_no_extra_headers(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([make_response()]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response()]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_one(client) url = "http://example.com/test" data = b"data" @@ -330,7 +330,7 @@ def test__make_request_w_data_no_extra_headers(self): "User-Agent": conn.user_agent, CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=url, headers=expected_headers, @@ -341,8 +341,8 @@ def test__make_request_w_data_no_extra_headers(self): def test__make_request_w_extra_headers(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([make_response()]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response()]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_one(client) url = "http://example.com/test" @@ -354,7 +354,7 @@ def test__make_request_w_extra_headers(self): "User-Agent": conn.user_agent, CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=url, headers=expected_headers, @@ -365,8 +365,8 @@ def test__make_request_w_extra_headers(self): def test__make_request_w_timeout(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([make_response()]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response()]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_one(client) url = "http://example.com/test" @@ -377,7 +377,7 @@ def test__make_request_w_timeout(self): "User-Agent": conn.user_agent, CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=url, headers=expected_headers, @@ -388,10 +388,10 @@ def test__make_request_w_timeout(self): def test_api_request_defaults(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session( + session = make_requests_session( [make_response(content=b"{}", headers=self.JSON_HEADERS)] ) - client = mock.Mock(_http=http, spec=["_http"]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) path = "/path/required" @@ -405,7 +405,7 @@ def test_api_request_defaults(self): expected_url = "{base}/mock/{version}{path}?prettyPrint=false".format( base=conn.API_BASE_URL, version=conn.API_VERSION, path=path ) - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=expected_url, headers=expected_headers, @@ -414,16 +414,16 @@ def test_api_request_defaults(self): ) def test_api_request_w_non_json_response(self): - http = make_requests_session([make_response(content=b"content")]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response(content=b"content")]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) with self.assertRaises(ValueError): conn.api_request("GET", "/") def test_api_request_wo_json_expected(self): - http = make_requests_session([make_response(content=b"content")]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response(content=b"content")]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) result = conn.api_request("GET", "/", expect_json=False) @@ -431,12 +431,12 @@ def test_api_request_wo_json_expected(self): self.assertEqual(result, b"content") def test_api_request_w_query_params(self): - from six.moves.urllib.parse import parse_qs - from six.moves.urllib.parse import urlsplit + from urllib.parse import parse_qs + from urllib.parse import urlsplit from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([self.EMPTY_JSON_RESPONSE]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([self.EMPTY_JSON_RESPONSE]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) result = conn.api_request("GET", "/", {"foo": "bar", "baz": ["qux", "quux"]}) @@ -448,7 +448,7 @@ def test_api_request_w_query_params(self): "User-Agent": conn.user_agent, CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=mock.ANY, headers=expected_headers, @@ -456,7 +456,7 @@ def test_api_request_w_query_params(self): timeout=self._get_default_timeout(), ) - url = http.request.call_args[1]["url"] + url = session.request.call_args[1]["url"] scheme, netloc, path, qs, _ = urlsplit(url) self.assertEqual("%s://%s" % (scheme, netloc), conn.API_BASE_URL) # Intended to emulate self.mock_template @@ -469,8 +469,8 @@ def test_api_request_w_query_params(self): def test_api_request_w_headers(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([self.EMPTY_JSON_RESPONSE]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([self.EMPTY_JSON_RESPONSE]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) result = conn.api_request("GET", "/", headers={"X-Foo": "bar"}) @@ -482,7 +482,7 @@ def test_api_request_w_headers(self): "X-Foo": "bar", CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=mock.ANY, headers=expected_headers, @@ -493,8 +493,8 @@ def test_api_request_w_headers(self): def test_api_request_w_extra_headers(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([self.EMPTY_JSON_RESPONSE]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([self.EMPTY_JSON_RESPONSE]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) conn.extra_headers = { "X-Baz": "dax-quux", @@ -512,7 +512,7 @@ def test_api_request_w_extra_headers(self): "X-Baz": "dax-quux", CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=mock.ANY, headers=expected_headers, @@ -523,8 +523,8 @@ def test_api_request_w_extra_headers(self): def test_api_request_w_data(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session([self.EMPTY_JSON_RESPONSE]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([self.EMPTY_JSON_RESPONSE]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) data = {"foo": "bar"} @@ -539,7 +539,7 @@ def test_api_request_w_data(self): CLIENT_INFO_HEADER: conn.user_agent, } - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="POST", url=mock.ANY, headers=expected_headers, @@ -550,10 +550,10 @@ def test_api_request_w_data(self): def test_api_request_w_timeout(self): from google.cloud._http import CLIENT_INFO_HEADER - http = make_requests_session( + session = make_requests_session( [make_response(content=b"{}", headers=self.JSON_HEADERS)] ) - client = mock.Mock(_http=http, spec=["_http"]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) path = "/path/required" @@ -567,7 +567,7 @@ def test_api_request_w_timeout(self): expected_url = "{base}/mock/{version}{path}?prettyPrint=false".format( base=conn.API_BASE_URL, version=conn.API_VERSION, path=path ) - http.request.assert_called_once_with( + session.request.assert_called_once_with( method="GET", url=expected_url, headers=expected_headers, @@ -578,8 +578,8 @@ def test_api_request_w_timeout(self): def test_api_request_w_404(self): from google.cloud import exceptions - http = make_requests_session([make_response(http_client.NOT_FOUND)]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session([make_response(http.client.NOT_FOUND)]) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) with self.assertRaises(exceptions.NotFound): @@ -588,8 +588,10 @@ def test_api_request_w_404(self): def test_api_request_w_500(self): from google.cloud import exceptions - http = make_requests_session([make_response(http_client.INTERNAL_SERVER_ERROR)]) - client = mock.Mock(_http=http, spec=["_http"]) + session = make_requests_session( + [make_response(http.client.INTERNAL_SERVER_ERROR)] + ) + client = mock.Mock(_http=session, spec=["_http"]) conn = self._make_mock_one(client) with self.assertRaises(exceptions.InternalServerError): diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index c7753a8..febfcfe 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -15,8 +15,7 @@ import io import json import unittest - -import mock +from unittest import mock def _make_credentials(): @@ -393,8 +392,6 @@ def test_constructor_w_invalid_project(self): self._make_one(project=object(), credentials=CREDENTIALS, _http=HTTP) def _explicit_ctor_helper(self, project): - import six - CREDENTIALS = _make_credentials() HTTP = object() @@ -402,7 +399,7 @@ def _explicit_ctor_helper(self, project): project=project, credentials=CREDENTIALS, _http=HTTP ) - if isinstance(project, six.binary_type): + if isinstance(project, bytes): self.assertEqual(client_obj.project, project.decode("utf-8")) else: self.assertEqual(client_obj.project, project) @@ -413,8 +410,8 @@ def test_constructor_explicit_bytes(self): PROJECT = b"PROJECT" self._explicit_ctor_helper(PROJECT) - def test_constructor_explicit_unicode(self): - PROJECT = u"PROJECT" + def test_constructor_explicit_text(self): + PROJECT = "PROJECT" self._explicit_ctor_helper(PROJECT) def _from_service_account_info_helper(self, project=None): diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py index 8c9a04d..86795c2 100644 --- a/tests/unit/test_exceptions.py +++ b/tests/unit/test_exceptions.py @@ -12,10 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +import http.client import json import requests -from six.moves import http_client from google.cloud import exceptions @@ -45,8 +45,8 @@ def test_create_google_cloud_error_with_args(): def test_from_http_status(): message = "message" - exception = exceptions.from_http_status(http_client.NOT_FOUND, message) - assert exception.code == http_client.NOT_FOUND + exception = exceptions.from_http_status(http.client.NOT_FOUND, message) + assert exception.code == http.client.NOT_FOUND assert exception.message == message assert exception.errors == [] @@ -55,11 +55,11 @@ def test_from_http_status_with_errors(): message = "message" errors = ["1", "2"] exception = exceptions.from_http_status( - http_client.NOT_FOUND, message, errors=errors + http.client.NOT_FOUND, message, errors=errors ) assert isinstance(exception, exceptions.NotFound) - assert exception.code == http_client.NOT_FOUND + assert exception.code == http.client.NOT_FOUND assert exception.message == message assert exception.errors == errors @@ -75,7 +75,7 @@ def test_from_http_status_unknown_code(): def make_response(content): response = requests.Response() response._content = content - response.status_code = http_client.NOT_FOUND + response.status_code = http.client.NOT_FOUND response.request = requests.Request( method="POST", url="https://example.com" ).prepare() @@ -88,7 +88,7 @@ def test_from_http_response_no_content(): exception = exceptions.from_http_response(response) assert isinstance(exception, exceptions.NotFound) - assert exception.code == http_client.NOT_FOUND + assert exception.code == http.client.NOT_FOUND assert exception.message == "POST https://example.com/: unknown error" assert exception.response == response @@ -99,7 +99,7 @@ def test_from_http_response_text_content(): exception = exceptions.from_http_response(response) assert isinstance(exception, exceptions.NotFound) - assert exception.code == http_client.NOT_FOUND + assert exception.code == http.client.NOT_FOUND assert exception.message == "POST https://example.com/: message" @@ -113,7 +113,7 @@ def test_from_http_response_json_content(): exception = exceptions.from_http_response(response) assert isinstance(exception, exceptions.NotFound) - assert exception.code == http_client.NOT_FOUND + assert exception.code == http.client.NOT_FOUND assert exception.message == "POST https://example.com/: json message" assert exception.errors == ["1", "2"] @@ -124,5 +124,5 @@ def test_from_http_response_bad_json_content(): exception = exceptions.from_http_response(response) assert isinstance(exception, exceptions.NotFound) - assert exception.code == http_client.NOT_FOUND + assert exception.code == http.client.NOT_FOUND assert exception.message == "POST https://example.com/: unknown error" diff --git a/tests/unit/test_obsolete.py b/tests/unit/test_obsolete.py index 3c38005..d4c8020 100644 --- a/tests/unit/test_obsolete.py +++ b/tests/unit/test_obsolete.py @@ -12,10 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from unittest import mock import warnings -import mock - from google.cloud import obsolete diff --git a/tests/unit/test_operation.py b/tests/unit/test_operation.py index 5a86dbe..3d90048 100644 --- a/tests/unit/test_operation.py +++ b/tests/unit/test_operation.py @@ -191,7 +191,7 @@ def test_from_pb_w_metadata_and_kwargs(self): type_url_map = {type_url: Struct} client = _Client() - meta = Struct(fields={"foo": Value(string_value=u"Bar")}) + meta = Struct(fields={"foo": Value(string_value="Bar")}) metadata_pb = Any(type_url=type_url, value=meta.SerializeToString()) operation_pb = operations_pb2.Operation( name=self.OPERATION_NAME, metadata=metadata_pb