diff --git a/oauth2client/appengine.py b/oauth2client/appengine.py index b284ad7..555fd3e 100644 --- a/oauth2client/appengine.py +++ b/oauth2client/appengine.py @@ -19,7 +19,6 @@ Utilities for making it easier to use OAuth 2.0 on Google App Engine. __author__ = 'jcgregorio@google.com (Joe Gregorio)' -import base64 import cgi import httplib2 import json @@ -27,7 +26,6 @@ import logging import os import pickle import threading -import time from google.appengine.api import app_identity from google.appengine.api import memcache diff --git a/oauth2client/client.py b/oauth2client/client.py index 648e22f..f3bc4a7 100644 --- a/oauth2client/client.py +++ b/oauth2client/client.py @@ -20,10 +20,9 @@ Tools for interacting with OAuth 2.0 protected resources. __author__ = 'jcgregorio@google.com (Joe Gregorio)' import base64 -import clientsecrets +import collections import copy import datetime -import httplib2 import json import logging import os @@ -32,10 +31,11 @@ import time import urllib import urlparse -from collections import namedtuple +import httplib2 from oauth2client import GOOGLE_AUTH_URI from oauth2client import GOOGLE_REVOKE_URI from oauth2client import GOOGLE_TOKEN_URI +from oauth2client import clientsecrets from oauth2client import util HAS_OPENSSL = False @@ -48,11 +48,6 @@ try: except ImportError: pass -try: - from urlparse import parse_qsl -except ImportError: - from cgi import parse_qsl - logger = logging.getLogger(__name__) # Expiry is stored in RFC3339 UTC format @@ -81,7 +76,8 @@ SERVICE_ACCOUNT = 'service_account' GOOGLE_APPLICATION_CREDENTIALS = 'GOOGLE_APPLICATION_CREDENTIALS' # The access token along with the seconds in which it expires. -AccessTokenInfo = namedtuple('AccessTokenInfo', ['access_token', 'expires_in']) +AccessTokenInfo = collections.namedtuple( + 'AccessTokenInfo', ['access_token', 'expires_in']) class Error(Exception): """Base error for this module.""" @@ -394,11 +390,11 @@ def _update_query_params(uri, params): Returns: The same URI but with the new query parameters added. """ - parts = list(urlparse.urlparse(uri)) - query_params = dict(parse_qsl(parts[4])) # 4 is the index of the query part + parts = urlparse.urlparse(uri) + query_params = dict(urlparse.parse_qsl(parts.query)) query_params.update(params) - parts[4] = urllib.urlencode(query_params) - return urlparse.urlunparse(parts) + new_parts = parts._replace(query=urllib.urlencode(query_params)) + return urlparse.urlunparse(new_parts) class OAuth2Credentials(Credentials): @@ -1457,7 +1453,7 @@ def _parse_exchange_token_response(content): except StandardError: # different JSON libs raise different exceptions, # so we just do a catch-all here - resp = dict(parse_qsl(content)) + resp = dict(urlparse.parse_qsl(content)) # some providers respond with 'expires', others with 'expires_in' if resp and 'expires' in resp: diff --git a/oauth2client/crypt.py b/oauth2client/crypt.py index d0e48ef..02d3b42 100644 --- a/oauth2client/crypt.py +++ b/oauth2client/crypt.py @@ -336,9 +336,8 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): """ segments = jwt.split('.') - if (len(segments) != 3): - raise AppIdentityError( - 'Wrong number of segments in token: %s' % jwt) + if len(segments) != 3: + raise AppIdentityError('Wrong number of segments in token: %s' % jwt) signed = '%s.%s' % (segments[0], segments[1]) signature = _urlsafe_b64decode(segments[2]) @@ -352,9 +351,9 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): # Check signature. verified = False - for (keyname, pem) in certs.items(): + for _, pem in certs.items(): verifier = Verifier.from_string(pem, True) - if (verifier.verify(signed, signature)): + if verifier.verify(signed, signature): verified = True break if not verified: @@ -372,16 +371,15 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): if exp is None: raise AppIdentityError('No exp field in token: %s' % json_body) if exp >= now + MAX_TOKEN_LIFETIME_SECS: - raise AppIdentityError( - 'exp field too far in future: %s' % json_body) + raise AppIdentityError('exp field too far in future: %s' % json_body) latest = exp + CLOCK_SKEW_SECS if now < earliest: raise AppIdentityError('Token used too early, %d < %d: %s' % - (now, earliest, json_body)) + (now, earliest, json_body)) if now > latest: raise AppIdentityError('Token used too late, %d > %d: %s' % - (now, latest, json_body)) + (now, latest, json_body)) # Check audience. if audience is not None: @@ -390,6 +388,6 @@ def verify_signed_jwt_with_certs(jwt, certs, audience): raise AppIdentityError('No aud field in token: %s' % json_body) if aud != audience: raise AppIdentityError('Wrong recipient, %s != %s: %s' % - (aud, audience, json_body)) + (aud, audience, json_body)) return parsed diff --git a/oauth2client/file.py b/oauth2client/file.py index 776c2a6..16bcf32 100644 --- a/oauth2client/file.py +++ b/oauth2client/file.py @@ -21,11 +21,10 @@ credentials. __author__ = 'jcgregorio@google.com (Joe Gregorio)' import os -import stat import threading -from client import Storage as BaseStorage -from client import Credentials +from oauth2client.client import Storage as BaseStorage +from oauth2client.client import Credentials class CredentialsFileSymbolicLinkError(Exception): diff --git a/oauth2client/gce.py b/oauth2client/gce.py index 509990e..024a82d 100644 --- a/oauth2client/gce.py +++ b/oauth2client/gce.py @@ -19,7 +19,6 @@ Utilities for making it easier to use OAuth 2.0 on Google Compute Engine. __author__ = 'jcgregorio@google.com (Joe Gregorio)' -import httplib2 import json import logging import uritemplate @@ -90,7 +89,7 @@ class AppAssertionCredentials(AssertionCredentials): else: if response.status == 404: content = content + (' This can occur if a VM was created' - ' with no service account or scopes.') + ' with no service account or scopes.') raise AccessTokenRefreshError(content) @property diff --git a/oauth2client/keyring_storage.py b/oauth2client/keyring_storage.py index efe2949..9ec9cdd 100644 --- a/oauth2client/keyring_storage.py +++ b/oauth2client/keyring_storage.py @@ -22,8 +22,8 @@ __author__ = 'jcgregorio@google.com (Joe Gregorio)' import keyring import threading -from client import Storage as BaseStorage -from client import Credentials +from oauth2client.client import Storage as BaseStorage +from oauth2client.client import Credentials class Storage(BaseStorage): diff --git a/oauth2client/locked_file.py b/oauth2client/locked_file.py index 5087886..ae9acf4 100644 --- a/oauth2client/locked_file.py +++ b/oauth2client/locked_file.py @@ -70,6 +70,7 @@ class _Opener(object): self._mode = mode self._fallback_mode = fallback_mode self._fh = None + self._lock_fd = None def is_locked(self): """Was the file locked.""" @@ -141,8 +142,8 @@ class _PosixOpener(_Opener): if e.errno != errno.EEXIST: raise if (time.time() - start_time) >= timeout: - logger.warn('Could not acquire lock %s in %s seconds' % ( - lock_filename, timeout)) + logger.warn('Could not acquire lock %s in %s seconds', + lock_filename, timeout) # Close the file and open in fallback_mode. if self._fh: self._fh.close() @@ -194,7 +195,7 @@ try: self._fh = open(self._filename, self._mode) except IOError as e: # If we can't access with _mode, try _fallback_mode and don't lock. - if e.errno in ( errno.EPERM, errno.EACCES ): + if e.errno in (errno.EPERM, errno.EACCES): self._fh = open(self._filename, self._fallback_mode) return @@ -212,8 +213,8 @@ try: raise e # We could not acquire the lock. Try again. if (time.time() - start_time) >= timeout: - logger.warn('Could not lock %s in %s seconds' % ( - self._filename, timeout)) + logger.warn('Could not lock %s in %s seconds', + self._filename, timeout) if self._fh: self._fh.close() self._fh = open(self._filename, self._fallback_mode) diff --git a/oauth2client/multistore_file.py b/oauth2client/multistore_file.py index a5bf6c9..dc88f24 100644 --- a/oauth2client/multistore_file.py +++ b/oauth2client/multistore_file.py @@ -43,8 +43,6 @@ The format of the stored data is like so: __author__ = 'jbeda@google.com (Joe Beda)' -import base64 -import errno import json import logging import os @@ -53,7 +51,7 @@ import threading from oauth2client.client import Storage as BaseStorage from oauth2client.client import Credentials from oauth2client import util -from locked_file import LockedFile +from oauth2client.locked_file import LockedFile logger = logging.getLogger(__name__) @@ -286,7 +284,7 @@ class _MultiStore(object): if self._warn_on_readonly: logger.warn('The credentials file (%s) is not writable. Opening in ' 'read-only mode. Any refreshed credentials will only be ' - 'valid for this run.' % self._file.filename()) + 'valid for this run.', self._file.filename()) if os.path.getsize(self._file.filename()) == 0: logger.debug('Initializing empty multistore file') # The multistore is empty so write out an empty file. diff --git a/oauth2client/service_account.py b/oauth2client/service_account.py index feb5d33..ce08125 100644 --- a/oauth2client/service_account.py +++ b/oauth2client/service_account.py @@ -19,9 +19,7 @@ This credentials class is implemented on top of rsa library. import base64 import json -import rsa import time -import types from oauth2client import GOOGLE_REVOKE_URI from oauth2client import GOOGLE_TOKEN_URI @@ -30,6 +28,7 @@ from oauth2client.client import AssertionCredentials from pyasn1.codec.ber import decoder from pyasn1_modules.rfc5208 import PrivateKeyInfo +import rsa class _ServiceAccountCredentials(AssertionCredentials): @@ -38,8 +37,9 @@ class _ServiceAccountCredentials(AssertionCredentials): MAX_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds def __init__(self, service_account_id, service_account_email, private_key_id, - private_key_pkcs8_text, scopes, user_agent=None, - token_uri=GOOGLE_TOKEN_URI, revoke_uri=GOOGLE_REVOKE_URI, **kwargs): + private_key_pkcs8_text, scopes, user_agent=None, + token_uri=GOOGLE_TOKEN_URI, revoke_uri=GOOGLE_REVOKE_URI, + **kwargs): super(_ServiceAccountCredentials, self).__init__( None, user_agent=user_agent, token_uri=token_uri, revoke_uri=revoke_uri) diff --git a/oauth2client/tools.py b/oauth2client/tools.py index 5d75e6f..1568b24 100644 --- a/oauth2client/tools.py +++ b/oauth2client/tools.py @@ -25,22 +25,15 @@ __all__ = ['argparser', 'run_flow', 'run', 'message_if_missing'] import BaseHTTPServer import argparse -import httplib2 import logging -import os import socket import sys +import urlparse import webbrowser from oauth2client import client -from oauth2client import file from oauth2client import util -try: - from urlparse import parse_qsl -except ImportError: - from cgi import parse_qsl - _CLIENT_SECRETS_MESSAGE = """WARNING: Please configure OAuth 2.0 To make this sample run you will need to populate the client_secrets.json file @@ -57,15 +50,15 @@ with information from the APIs Console . # ArgumentParser. argparser = argparse.ArgumentParser(add_help=False) argparser.add_argument('--auth_host_name', default='localhost', - help='Hostname when running a local web server.') + help='Hostname when running a local web server.') argparser.add_argument('--noauth_local_webserver', action='store_true', - default=False, help='Do not run a local web server.') + default=False, help='Do not run a local web server.') argparser.add_argument('--auth_host_port', default=[8080, 8090], type=int, - nargs='*', help='Port web server should listen on.') + nargs='*', help='Port web server should listen on.') argparser.add_argument('--logging_level', default='ERROR', - choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', - 'CRITICAL'], - help='Set the logging level of detail.') + choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', + 'CRITICAL'], + help='Set the logging level of detail.') class ClientRedirectServer(BaseHTTPServer.HTTPServer): @@ -84,26 +77,25 @@ class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler): into the servers query_params and then stops serving. """ - def do_GET(s): + def do_GET(self): """Handle a GET request. Parses the query parameters and prints a message if the flow has completed. Note that we can't detect if an error occurred. """ - s.send_response(200) - s.send_header("Content-type", "text/html") - s.end_headers() - query = s.path.split('?', 1)[-1] - query = dict(parse_qsl(query)) - s.server.query_params = query - s.wfile.write("Authentication Status") - s.wfile.write("

The authentication flow has completed.

") - s.wfile.write("") + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + query = self.path.split('?', 1)[-1] + query = dict(urlparse.parse_qsl(query)) + self.server.query_params = query + self.wfile.write("Authentication Status") + self.wfile.write("

The authentication flow has completed.

") + self.wfile.write("") def log_message(self, format, *args): """Do not log messages to stdout while running as command line program.""" - pass @util.positional(3) @@ -233,8 +225,8 @@ def message_if_missing(filename): return _CLIENT_SECRETS_MESSAGE % filename try: - from old_run import run - from old_run import FLAGS + from oauth2client.old_run import run + from oauth2client.old_run import FLAGS except ImportError: def run(*args, **kwargs): raise NotImplementedError( diff --git a/oauth2client/util.py b/oauth2client/util.py index 90dff15..fd64524 100644 --- a/oauth2client/util.py +++ b/oauth2client/util.py @@ -17,14 +17,16 @@ """Common utility library.""" -__author__ = ['rafek@google.com (Rafe Kaplan)', - 'guido@google.com (Guido van Rossum)', +__author__ = [ + 'rafek@google.com (Rafe Kaplan)', + 'guido@google.com (Guido van Rossum)', ] + __all__ = [ - 'positional', - 'POSITIONAL_WARNING', - 'POSITIONAL_EXCEPTION', - 'POSITIONAL_IGNORE', + 'positional', + 'POSITIONAL_WARNING', + 'POSITIONAL_EXCEPTION', + 'POSITIONAL_IGNORE', ] import inspect @@ -33,11 +35,6 @@ import types import urllib import urlparse -try: - from urlparse import parse_qsl -except ImportError: - from cgi import parse_qsl - logger = logging.getLogger(__name__) POSITIONAL_WARNING = 'WARNING' @@ -190,7 +187,7 @@ def _add_query_parameter(url, name, value): return url else: parsed = list(urlparse.urlparse(url)) - q = dict(parse_qsl(parsed[4])) + q = dict(urlparse.parse_qsl(parsed[4])) q[name] = value parsed[4] = urllib.urlencode(q) return urlparse.urlunparse(parsed) diff --git a/oauth2client/xsrfutil.py b/oauth2client/xsrfutil.py index 7e1fe5c..0663bbb 100644 --- a/oauth2client/xsrfutil.py +++ b/oauth2client/xsrfutil.py @@ -17,14 +17,13 @@ """Helper methods for creating & verifying XSRF tokens.""" __authors__ = [ - '"Doug Coker" ', - '"Joe Gregorio" ', + '"Doug Coker" ', + '"Joe Gregorio" ', ] import base64 import hmac -import os # for urandom import time from oauth2client import util diff --git a/tests/test_appengine.py b/tests/test_appengine.py index 40fde6f..5514d84 100644 --- a/tests/test_appengine.py +++ b/tests/test_appengine.py @@ -22,23 +22,18 @@ Unit tests for objects created from discovery documents. __author__ = 'jcgregorio@google.com (Joe Gregorio)' -import base64 import datetime import httplib2 import json -import mox import os import time import unittest import urllib - -try: - from urlparse import parse_qs -except ImportError: - from cgi import parse_qs +import urlparse import dev_appserver dev_appserver.fix_sys_path() +import mox import webapp2 from google.appengine.api import apiproxy_stub @@ -559,7 +554,7 @@ class DecoratorTests(unittest.TestCase): self.assertEqual(self.decorator.credentials, None) response = self.app.get('http://localhost/foo_path') self.assertTrue(response.status.startswith('302')) - q = parse_qs(response.headers['Location'].split('?', 1)[1]) + q = urlparse.parse_qs(response.headers['Location'].split('?', 1)[1]) self.assertEqual('http://localhost/oauth2callback', q['redirect_uri'][0]) self.assertEqual('foo_client_id', q['client_id'][0]) self.assertEqual('foo_scope bar_scope', q['scope'][0]) @@ -583,7 +578,8 @@ class DecoratorTests(unittest.TestCase): self.assertEqual('http://localhost/foo_path', parts[0]) self.assertEqual(None, self.decorator.credentials) if self.decorator._token_response_param: - response = parse_qs(parts[1])[self.decorator._token_response_param][0] + response = urlparse.parse_qs( + parts[1])[self.decorator._token_response_param][0] self.assertEqual(Http2Mock.content, json.loads(urllib.unquote(response))) self.assertEqual(self.decorator.flow, self.decorator._tls.flow) self.assertEqual(self.decorator.credentials, @@ -619,7 +615,7 @@ class DecoratorTests(unittest.TestCase): # Invalid Credentials should start the OAuth dance again. response = self.app.get('/foo_path') self.assertTrue(response.status.startswith('302')) - q = parse_qs(response.headers['Location'].split('?', 1)[1]) + q = urlparse.parse_qs(response.headers['Location'].split('?', 1)[1]) self.assertEqual('http://localhost/oauth2callback', q['redirect_uri'][0]) def test_storage_delete(self): @@ -667,7 +663,7 @@ class DecoratorTests(unittest.TestCase): self.assertEqual('200 OK', response.status) self.assertEqual(False, self.decorator.has_credentials()) url = self.decorator.authorize_url() - q = parse_qs(url.split('?', 1)[1]) + q = urlparse.parse_qs(url.split('?', 1)[1]) self.assertEqual('http://localhost/oauth2callback', q['redirect_uri'][0]) self.assertEqual('foo_client_id', q['client_id'][0]) self.assertEqual('foo_scope bar_scope', q['scope'][0]) diff --git a/tests/test_jwt.py b/tests/test_jwt.py index 8b94d40..51351e2 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -22,20 +22,12 @@ Unit tests for oauth2client. __author__ = 'jcgregorio@google.com (Joe Gregorio)' -import httplib2 import os -import sys import tempfile import time import unittest -import urlparse -try: - from urlparse import parse_qs -except ImportError: - from cgi import parse_qs - -from http_mock import HttpMockSequence +from tests.http_mock import HttpMockSequence from oauth2client import crypt from oauth2client.client import Credentials from oauth2client.client import SignedJwtAssertionCredentials @@ -79,20 +71,18 @@ class CryptTests(unittest.TestCase): self.assertTrue(verifier.verify('foo', signature)) self.assertFalse(verifier.verify('bar', signature)) - self.assertFalse(verifier.verify('foo', 'bad signagure')) + self.assertFalse(verifier.verify('foo', 'bad signature')) def _check_jwt_failure(self, jwt, expected_error): - try: - public_key = datafile('publickey.pem') - certs = {'foo': public_key} - audience = 'https://www.googleapis.com/auth/id?client_id=' + \ - 'external_public_key@testing.gserviceaccount.com' - contents = crypt.verify_signed_jwt_with_certs(jwt, certs, audience) - self.fail('Should have thrown for %s' % jwt) - except: - e = sys.exc_info()[1] - msg = e.args[0] - self.assertTrue(expected_error in msg) + public_key = datafile('publickey.pem') + certs = {'foo': public_key} + audience = ('https://www.googleapis.com/auth/id?client_id=' + 'external_public_key@testing.gserviceaccount.com') + try: + crypt.verify_signed_jwt_with_certs(jwt, certs, audience) + self.fail() + except crypt.AppIdentityError as e: + self.assertTrue(expected_error in str(e)) def _create_signed_jwt(self): private_key = datafile('privatekey.%s' % self.format) @@ -100,20 +90,18 @@ class CryptTests(unittest.TestCase): audience = 'some_audience_address@testing.gserviceaccount.com' now = long(time.time()) - return crypt.make_signed_jwt( - signer, - { + return crypt.make_signed_jwt(signer, { 'aud': audience, 'iat': now, 'exp': now + 300, 'user': 'billy bob', 'metadata': {'meta': 'data'}, - }) + }) def test_verify_id_token(self): jwt = self._create_signed_jwt() public_key = datafile('publickey.pem') - certs = {'foo': public_key } + certs = {'foo': public_key} audience = 'some_audience_address@testing.gserviceaccount.com' contents = crypt.verify_signed_jwt_with_certs(jwt, certs, audience) self.assertEqual('billy bob', contents['user']) @@ -123,11 +111,11 @@ class CryptTests(unittest.TestCase): jwt = self._create_signed_jwt() http = HttpMockSequence([ - ({'status': '200'}, datafile('certs.json')), - ]) + ({'status': '200'}, datafile('certs.json')), + ]) - contents = verify_id_token(jwt, - 'some_audience_address@testing.gserviceaccount.com', http=http) + contents = verify_id_token( + jwt, 'some_audience_address@testing.gserviceaccount.com', http=http) self.assertEqual('billy bob', contents['user']) self.assertEqual('data', contents['metadata']['meta']) @@ -135,11 +123,12 @@ class CryptTests(unittest.TestCase): jwt = self._create_signed_jwt() http = HttpMockSequence([ - ({'status': '404'}, datafile('certs.json')), - ]) + ({'status': '404'}, datafile('certs.json')), + ]) self.assertRaises(VerifyJwtTokenError, verify_id_token, jwt, - 'some_audience_address@testing.gserviceaccount.com', http=http) + 'some_audience_address@testing.gserviceaccount.com', + http=http) def test_verify_id_token_bad_tokens(self): private_key = datafile('privatekey.%s' % self.format) @@ -148,8 +137,7 @@ class CryptTests(unittest.TestCase): self._check_jwt_failure('foo', 'Wrong number of segments') # Not json - self._check_jwt_failure('foo.bar.baz', - 'Can\'t parse token') + self._check_jwt_failure('foo.bar.baz', 'Can\'t parse token') # Bad signature jwt = 'foo.%s.baz' % crypt._urlsafe_b64encode('{"a":"b"}') @@ -157,21 +145,19 @@ class CryptTests(unittest.TestCase): # No expiration signer = self.signer.from_string(private_key) - audience = 'https:#www.googleapis.com/auth/id?client_id=' + \ - 'external_public_key@testing.gserviceaccount.com' + audience = ('https:#www.googleapis.com/auth/id?client_id=' + 'external_public_key@testing.gserviceaccount.com') jwt = crypt.make_signed_jwt(signer, { - 'aud': 'audience', - 'iat': time.time(), - } - ) + 'aud': audience, + 'iat': time.time(), + }) self._check_jwt_failure(jwt, 'No exp field in token') # No issued at jwt = crypt.make_signed_jwt(signer, { - 'aud': 'audience', - 'exp': time.time() + 400, - } - ) + 'aud': 'audience', + 'exp': time.time() + 400, + }) self._check_jwt_failure(jwt, 'No iat field in token') # Too early @@ -226,11 +212,11 @@ class SignedJwtAssertionCredentialsTests(unittest.TestCase): scope='read+write', sub='joe@example.org') http = HttpMockSequence([ - ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'), - ({'status': '200'}, 'echo_request_headers'), - ]) + ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'), + ({'status': '200'}, 'echo_request_headers'), + ]) http = credentials.authorize(http) - resp, content = http.request('http://example.org') + _, content = http.request('http://example.org') self.assertEqual('Bearer 1/3w', content['Authorization']) def test_credentials_to_from_json(self): @@ -249,13 +235,13 @@ class SignedJwtAssertionCredentialsTests(unittest.TestCase): def _credentials_refresh(self, credentials): http = HttpMockSequence([ - ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'), - ({'status': '401'}, ''), - ({'status': '200'}, '{"access_token":"3/3w","expires_in":3600}'), - ({'status': '200'}, 'echo_request_headers'), - ]) + ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'), + ({'status': '401'}, ''), + ({'status': '200'}, '{"access_token":"3/3w","expires_in":3600}'), + ({'status': '200'}, 'echo_request_headers'), + ]) http = credentials.authorize(http) - resp, content = http.request('http://example.org') + _, content = http.request('http://example.org') return content def test_credentials_refresh_without_storage(self): @@ -319,6 +305,7 @@ class PKCSSignedJwtAssertionCredentialsPyCryptoTests(unittest.TestCase): except NotImplementedError: pass + class TestHasOpenSSLFlag(unittest.TestCase): def test_true(self): self.assertEqual(True, HAS_OPENSSL)