From e5cea397a247c4f379136f23a80d15b47af12a21 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Thu, 28 Jan 2021 11:20:45 -0700 Subject: [PATCH] feat: require python >= 3.6 (#674) We are not ready to require >=3.6 in the main branch, so I am opening this PR against a new `2.0.0dev` branch. For https://github.com/googleapis/gapic-generator/issues/3334#issuecomment-768156415 Use native namespaces (delete `google/__init__.py` and require python>=3.6). There is more cleanup that needs to happen (example: App Engine credentials) in future PRs. --- google/__init__.py | 24 ---- google/auth/jwt.py | 6 +- noxfile.py | 9 -- setup.py | 24 ++-- system_tests/noxfile.py | 45 +----- .../app_engine_test_app/.gitignore | 1 - .../app_engine_test_app/app.yaml | 12 -- .../app_engine_test_app/appengine_config.py | 30 ---- .../app_engine_test_app/main.py | 133 ------------------ .../app_engine_test_app/requirements.txt | 3 - .../system_tests_sync/test_app_engine.py | 22 --- 11 files changed, 14 insertions(+), 295 deletions(-) delete mode 100644 google/__init__.py delete mode 100644 system_tests/system_tests_sync/app_engine_test_app/.gitignore delete mode 100644 system_tests/system_tests_sync/app_engine_test_app/app.yaml delete mode 100644 system_tests/system_tests_sync/app_engine_test_app/appengine_config.py delete mode 100644 system_tests/system_tests_sync/app_engine_test_app/main.py delete mode 100644 system_tests/system_tests_sync/app_engine_test_app/requirements.txt delete mode 100644 system_tests/system_tests_sync/test_app_engine.py diff --git a/google/__init__.py b/google/__init__.py deleted file mode 100644 index 0d0a4c3ab..000000000 --- a/google/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2016 Google LLC -# -# 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. - -"""Google namespace package.""" - -try: - import pkg_resources - - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - - __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/google/auth/jwt.py b/google/auth/jwt.py index a4f04f529..a98964823 100644 --- a/google/auth/jwt.py +++ b/google/auth/jwt.py @@ -40,11 +40,7 @@ """ -try: - from collections.abc import Mapping -# Python 2.7 compatibility -except ImportError: # pragma: NO COVER - from collections import Mapping +from collections.abc import Mapping import copy import datetime import json diff --git a/noxfile.py b/noxfile.py index adce2527c..8a72abf0b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -90,15 +90,6 @@ def unit(session): ) -@nox.session(python=["2.7"]) -def unit_prev_versions(session): - session.install(*TEST_DEPENDENCIES) - session.install(".") - session.run( - "pytest", "--cov=google.auth", "--cov=google.oauth2", "--cov=tests", "tests" - ) - - @nox.session(python="3.7") def cover(session): session.install(*TEST_DEPENDENCIES) diff --git a/setup.py b/setup.py index 3006d9ace..3c4620194 100644 --- a/setup.py +++ b/setup.py @@ -14,27 +14,30 @@ import io -from setuptools import find_packages +from setuptools import PEP420PackageFinder from setuptools import setup DEPENDENCIES = ( "cachetools>=2.0.0,<5.0", "pyasn1-modules>=0.2.1", - # rsa==4.5 is the last version to support 2.7 - # https://github.com/sybrenstuvel/python-rsa/issues/152#issuecomment-643470233 - 'rsa<4.6; python_version < "3.6"', - 'rsa>=3.1.4,<5; python_version >= "3.6"', + "rsa>=3.1.4,<5", "setuptools>=40.3.0", "six>=1.9.0", ) -extras = {"aiohttp": "aiohttp >= 3.6.2, < 4.0.0dev; python_version>='3.6'"} +extras = {"aiohttp": "aiohttp >= 3.6.2, < 4.0.0dev"} with io.open("README.rst", "r") as fh: long_description = fh.read() -version = "1.24.0" +version = "2.0.0dev" + +# Only include packages under the 'google' namespace. Do not include tests, +# benchmarks, etc. +packages = [ + package for package in PEP420PackageFinder.find() if package.startswith("google") +] setup( name="google-auth", @@ -44,16 +47,13 @@ description="Google Authentication Library", long_description=long_description, url="https://github.com/googleapis/google-auth-library-python", - packages=find_packages(exclude=("tests*", "system_tests*")), - namespace_packages=("google",), + packages=packages, 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", license="Apache 2.0", keywords="google auth oauth client", classifiers=[ - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", diff --git a/system_tests/noxfile.py b/system_tests/noxfile.py index 5d0014bc8..228881564 100644 --- a/system_tests/noxfile.py +++ b/system_tests/noxfile.py @@ -171,7 +171,7 @@ def configure_cloud_sdk(session, application_default_credentials, project=False) TEST_DEPENDENCIES_ASYNC = ["aiohttp", "pytest-asyncio", "nest-asyncio"] TEST_DEPENDENCIES_SYNC = ["pytest", "requests", "mock"] PYTHON_VERSIONS_ASYNC = ["3.7"] -PYTHON_VERSIONS_SYNC = ["2.7", "3.7"] +PYTHON_VERSIONS_SYNC = ["3.7"] @nox.session(python=PYTHON_VERSIONS_SYNC) @@ -242,49 +242,6 @@ def compute_engine(session): session.install(LIBRARY_DIR) session.run("pytest", "system_tests_sync/test_compute_engine.py") - -@nox.session(python=["2.7"]) -def app_engine(session): - if SKIP_GAE_TEST_ENV in os.environ: - session.log("Skipping App Engine tests.") - return - - session.install(LIBRARY_DIR) - # Unlike the default tests above, the App Engine system test require a - # 'real' gcloud sdk installation that is configured to deploy to an - # app engine project. - # Grab the project ID from the cloud sdk. - project_id = ( - subprocess.check_output( - ["gcloud", "config", "list", "project", "--format", "value(core.project)"] - ) - .decode("utf-8") - .strip() - ) - - if not project_id: - session.error( - "The Cloud SDK must be installed and configured to deploy to App " "Engine." - ) - - application_url = GAE_APP_URL_TMPL.format(GAE_TEST_APP_SERVICE, project_id) - - # Vendor in the test application's dependencies - session.chdir(os.path.join(HERE, "system_tests_sync/app_engine_test_app")) - session.install(*TEST_DEPENDENCIES_SYNC) - session.run( - "pip", "install", "--target", "lib", "-r", "requirements.txt", silent=True - ) - - # Deploy the application. - session.run("gcloud", "app", "deploy", "-q", "app.yaml") - - # Run the tests - session.env["TEST_APP_URL"] = application_url - session.chdir(HERE) - session.run("pytest", "system_tests_sync/test_app_engine.py") - - @nox.session(python=PYTHON_VERSIONS_SYNC) def grpc(session): session.install(LIBRARY_DIR) diff --git a/system_tests/system_tests_sync/app_engine_test_app/.gitignore b/system_tests/system_tests_sync/app_engine_test_app/.gitignore deleted file mode 100644 index a65b41774..000000000 --- a/system_tests/system_tests_sync/app_engine_test_app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -lib diff --git a/system_tests/system_tests_sync/app_engine_test_app/app.yaml b/system_tests/system_tests_sync/app_engine_test_app/app.yaml deleted file mode 100644 index 872efb37b..000000000 --- a/system_tests/system_tests_sync/app_engine_test_app/app.yaml +++ /dev/null @@ -1,12 +0,0 @@ -api_version: 1 -service: google-auth-system-tests -runtime: python27 -threadsafe: true - -handlers: -- url: .* - script: main.app - -libraries: -- name: ssl - version: 2.7.11 diff --git a/system_tests/system_tests_sync/app_engine_test_app/appengine_config.py b/system_tests/system_tests_sync/app_engine_test_app/appengine_config.py deleted file mode 100644 index 5a832ac6f..000000000 --- a/system_tests/system_tests_sync/app_engine_test_app/appengine_config.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2016 Google LLC -# -# 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. - -from google.appengine.ext import vendor - -# Add any libraries installed in the "lib" folder. -vendor.add("lib") - - -# Patch os.path.expanduser. This should be fixed in GAE -# versions released after Nov 2016. -import os.path - - -def patched_expanduser(path): - return path - - -os.path.expanduser = patched_expanduser diff --git a/system_tests/system_tests_sync/app_engine_test_app/main.py b/system_tests/system_tests_sync/app_engine_test_app/main.py deleted file mode 100644 index 33e61d07b..000000000 --- a/system_tests/system_tests_sync/app_engine_test_app/main.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2016 Google LLC All Rights Reserved. -# -# 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. - -"""App Engine standard application that runs basic system tests for -google.auth.app_engine. - -This application has to run tests manually instead of using pytest because -pytest currently doesn't work on App Engine standard. -""" - -import contextlib -import json -import sys -from StringIO import StringIO -import traceback - -from google.appengine.api import app_identity -import google.auth -from google.auth import _helpers -from google.auth import app_engine -import google.auth.transport.urllib3 -import urllib3.contrib.appengine -import webapp2 - -FAILED_TEST_TMPL = """ -Test {} failed: {} - -Stacktrace: -{} - -Captured output: -{} -""" -TOKEN_INFO_URL = "https://www.googleapis.com/oauth2/v3/tokeninfo" -EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email" -HTTP = urllib3.contrib.appengine.AppEngineManager() -HTTP_REQUEST = google.auth.transport.urllib3.Request(HTTP) - - -def test_credentials(): - credentials = app_engine.Credentials() - scoped_credentials = credentials.with_scopes([EMAIL_SCOPE]) - - scoped_credentials.refresh(None) - - assert scoped_credentials.valid - assert scoped_credentials.token is not None - - # Get token info and verify scope - url = _helpers.update_query( - TOKEN_INFO_URL, {"access_token": scoped_credentials.token} - ) - response = HTTP_REQUEST(url=url, method="GET") - token_info = json.loads(response.data.decode("utf-8")) - - assert token_info["scope"] == EMAIL_SCOPE - - -def test_default(): - credentials, project_id = google.auth.default() - - assert isinstance(credentials, app_engine.Credentials) - assert project_id == app_identity.get_application_id() - - -@contextlib.contextmanager -def capture(): - """Context manager that captures stderr and stdout.""" - oldout, olderr = sys.stdout, sys.stderr - try: - out = StringIO() - sys.stdout, sys.stderr = out, out - yield out - finally: - sys.stdout, sys.stderr = oldout, olderr - - -def run_test_func(func): - with capture() as capsys: - try: - func() - return True, "" - except Exception as exc: - output = FAILED_TEST_TMPL.format( - func.func_name, exc, traceback.format_exc(), capsys.getvalue() - ) - return False, output - - -def run_tests(): - """Runs all tests. - - Returns: - Tuple[bool, str]: A tuple containing True if all tests pass, False - otherwise, and any captured output from the tests. - """ - status = True - output = "" - - tests = (test_credentials, test_default) - - for test in tests: - test_status, test_output = run_test_func(test) - status = status and test_status - output += test_output - - return status, output - - -class MainHandler(webapp2.RequestHandler): - def get(self): - self.response.headers["content-type"] = "text/plain" - - status, output = run_tests() - - if not status: - self.response.status = 500 - - self.response.write(output) - - -app = webapp2.WSGIApplication([("/", MainHandler)], debug=True) diff --git a/system_tests/system_tests_sync/app_engine_test_app/requirements.txt b/system_tests/system_tests_sync/app_engine_test_app/requirements.txt deleted file mode 100644 index bd5c476ab..000000000 --- a/system_tests/system_tests_sync/app_engine_test_app/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -urllib3 -# Relative path to google-auth-python's source. -../../.. diff --git a/system_tests/system_tests_sync/test_app_engine.py b/system_tests/system_tests_sync/test_app_engine.py deleted file mode 100644 index 45a1989a4..000000000 --- a/system_tests/system_tests_sync/test_app_engine.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2016 Google LLC -# -# 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. - -import os - -TEST_APP_URL = os.environ["TEST_APP_URL"] - - -def test_live_application(http_request): - response = http_request(method="GET", url=TEST_APP_URL) - assert response.status == 200, response.data.decode("utf-8")