summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo <hugovk@users.noreply.github.com>2019-08-14 23:35:36 +0300
committerHugo <hugovk@users.noreply.github.com>2019-08-15 12:24:33 +0300
commit3718a0e048e64994c2ee3819c5e5ed218a05f115 (patch)
tree38b56eba3e23b5c20af0a09a6a860ecc279dc067
parentddc953c11e8d79607f5931a2f80dcd9f7a10c5d9 (diff)
downloadoauthlib-3718a0e048e64994c2ee3819c5e5ed218a05f115.tar.gz
Drop support for legacy Python 2.7
-rw-r--r--.travis.yml2
-rw-r--r--README.rst2
-rw-r--r--bandit.json2
-rw-r--r--docs/contributing.rst4
-rw-r--r--oauthlib/common.py41
-rw-r--r--oauthlib/oauth1/rfc5849/signature.py7
-rw-r--r--oauthlib/oauth1/rfc5849/utils.py6
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/metadata.py3
-rw-r--r--oauthlib/oauth2/rfc6749/parameters.py12
-rw-r--r--oauthlib/oauth2/rfc6749/tokens.py4
-rw-r--r--oauthlib/oauth2/rfc6749/utils.py12
-rw-r--r--oauthlib/openid/connect/core/endpoints/userinfo.py3
-rwxr-xr-xsetup.py5
-rw-r--r--tests/oauth1/rfc5849/test_signatures.py3
-rw-r--r--tests/oauth1/rfc5849/test_utils.py9
-rw-r--r--tests/oauth2/rfc6749/endpoints/test_scope_handling.py6
-rw-r--r--tests/oauth2/rfc6749/test_utils.py9
-rw-r--r--tests/test_common.py50
-rw-r--r--tests/unittest/__init__.py21
-rw-r--r--tox.ini4
20 files changed, 79 insertions, 126 deletions
diff --git a/.travis.yml b/.travis.yml
index 76b0649..c7ec677 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,6 @@ dist: xenial
cache: pip
matrix:
include:
- - python: 2.7
- env: TOXENV=py27
- python: 3.4
env: TOXENV=py34
- python: 3.5
diff --git a/README.rst b/README.rst
index 2900ecc..48b9853 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,7 @@ OAuthLib - Python Framework for OAuth1 & OAuth2
===============================================
*A generic, spec-compliant, thorough implementation of the OAuth request-signing
-logic for Python 2.7 and 3.4+.*
+logic for Python 3.4+.*
.. image:: https://travis-ci.org/oauthlib/oauthlib.svg?branch=master
:target: https://travis-ci.org/oauthlib/oauthlib
diff --git a/bandit.json b/bandit.json
index 4d3bfe1..7161f00 100644
--- a/bandit.json
+++ b/bandit.json
@@ -1133,7 +1133,7 @@
"test_name": "hardcoded_password_funcarg"
},
{
- "code": "164 \n165 def prepare_token_revocation_request(url, token, token_type_hint=\"access_token\",\n166 callback=None, body='', **kwargs):\n167 \"\"\"Prepare a token revocation request.\n168 \n169 The client constructs the request by including the following parameters\n170 using the \"application/x-www-form-urlencoded\" format in the HTTP request\n171 entity-body:\n172 \n173 :param token: REQUIRED. The token that the client wants to get revoked.\n174 \n175 :param token_type_hint: OPTIONAL. A hint about the type of the token\n176 submitted for revocation. Clients MAY pass this\n177 parameter in order to help the authorization server\n178 to optimize the token lookup. If the server is\n179 unable to locate the token using the given hint, it\n180 MUST extend its search across all of its supported\n181 token types. An authorization server MAY ignore\n182 this parameter, particularly if it is able to detect\n183 the token type automatically.\n184 \n185 This specification defines two values for `token_type_hint`:\n186 \n187 * access_token: An access token as defined in [RFC6749],\n188 `Section 1.4`_\n189 \n190 * refresh_token: A refresh token as defined in [RFC6749],\n191 `Section 1.5`_\n192 \n193 Specific implementations, profiles, and extensions of this\n194 specification MAY define other values for this parameter using the\n195 registry defined in `Section 4.1.2`_.\n196 \n197 .. _`Section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4\n198 .. _`Section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5\n199 .. _`Section 4.1.2`: https://tools.ietf.org/html/rfc7009#section-4.1.2\n200 \n201 \"\"\"\n202 if not is_secure_transport(url):\n203 raise InsecureTransportError()\n204 \n205 params = [('token', token)]\n206 \n207 if token_type_hint:\n208 params.append(('token_type_hint', token_type_hint))\n209 \n210 for k in kwargs:\n211 if kwargs[k]:\n212 params.append((unicode_type(k), kwargs[k]))\n213 \n214 headers = {'Content-Type': 'application/x-www-form-urlencoded'}\n215 \n216 if callback:\n217 params.append(('callback', callback))\n218 return add_params_to_uri(url, params), headers, body\n219 else:\n220 return url, headers, add_params_to_qs(body, params)\n221 \n222 \n223 def parse_authorization_code_response(uri, state=None):\n",
+ "code": "164 \n165 def prepare_token_revocation_request(url, token, token_type_hint=\"access_token\",\n166 callback=None, body='', **kwargs):\n167 \"\"\"Prepare a token revocation request.\n168 \n169 The client constructs the request by including the following parameters\n170 using the \"application/x-www-form-urlencoded\" format in the HTTP request\n171 entity-body:\n172 \n173 :param token: REQUIRED. The token that the client wants to get revoked.\n174 \n175 :param token_type_hint: OPTIONAL. A hint about the type of the token\n176 submitted for revocation. Clients MAY pass this\n177 parameter in order to help the authorization server\n178 to optimize the token lookup. If the server is\n179 unable to locate the token using the given hint, it\n180 MUST extend its search across all of its supported\n181 token types. An authorization server MAY ignore\n182 this parameter, particularly if it is able to detect\n183 the token type automatically.\n184 \n185 This specification defines two values for `token_type_hint`:\n186 \n187 * access_token: An access token as defined in [RFC6749],\n188 `Section 1.4`_\n189 \n190 * refresh_token: A refresh token as defined in [RFC6749],\n191 `Section 1.5`_\n192 \n193 Specific implementations, profiles, and extensions of this\n194 specification MAY define other values for this parameter using the\n195 registry defined in `Section 4.1.2`_.\n196 \n197 .. _`Section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4\n198 .. _`Section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5\n199 .. _`Section 4.1.2`: https://tools.ietf.org/html/rfc7009#section-4.1.2\n200 \n201 \"\"\"\n202 if not is_secure_transport(url):\n203 raise InsecureTransportError()\n204 \n205 params = [('token', token)]\n206 \n207 if token_type_hint:\n208 params.append(('token_type_hint', token_type_hint))\n209 \n210 for k in kwargs:\n211 if kwargs[k]:\n212 params.append((str(k), kwargs[k]))\n213 \n214 headers = {'Content-Type': 'application/x-www-form-urlencoded'}\n215 \n216 if callback:\n217 params.append(('callback', callback))\n218 return add_params_to_uri(url, params), headers, body\n219 else:\n220 return url, headers, add_params_to_qs(body, params)\n221 \n222 \n223 def parse_authorization_code_response(uri, state=None):\n",
"filename": "oauthlib/oauth2/rfc6749/parameters.py",
"issue_confidence": "MEDIUM",
"issue_severity": "LOW",
diff --git a/docs/contributing.rst b/docs/contributing.rst
index e101f70..93f6a81 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -152,7 +152,7 @@ request that fails this test suite will be **rejected**.
Testing multiple versions of Python
-----------------------------------
-OAuthLib supports Python 2.7, 3.4, 3.5, 3.6 and PyPy. Testing
+OAuthLib supports Python 3.4, 3.5, 3.6 and PyPy. Testing
all versions conveniently can be done using `Tox`_.
.. sourcecode:: bash
@@ -166,8 +166,6 @@ version. For Ubuntu you can easily install all after adding one ppa.
$ sudo add-apt-repository ppa:fkrull/deadsnakes
$ sudo apt-get update
- $ sudo apt-get install python2.6 python2.6-dev
- $ sudo apt-get install python2.7 python2.7-dev
$ sudo apt-get install python3.2 python3.2-dev
$ sudo apt-get install python3.3 python3.3-dev
$ sudo apt-get install pypy pypy-dev
diff --git a/oauthlib/common.py b/oauthlib/common.py
index 5aeb015..1462e75 100644
--- a/oauthlib/common.py
+++ b/oauthlib/common.py
@@ -51,17 +51,10 @@ always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
log = logging.getLogger('oauthlib')
-PY3 = sys.version_info[0] == 3
-
-if PY3:
- unicode_type = str
-else:
- unicode_type = unicode
-
# 'safe' must be bytes (Python 2.6 requires bytes, other versions allow either)
def quote(s, safe=b'/'):
- s = s.encode('utf-8') if isinstance(s, unicode_type) else s
+ s = s.encode('utf-8') if isinstance(s, str) else s
s = _quote(s, safe)
# PY3 always returns unicode. PY2 may return either, depending on whether
# it had to modify the string.
@@ -83,7 +76,7 @@ def unquote(s):
def urlencode(params):
utf8_params = encode_params_utf8(params)
urlencoded = _urlencode(utf8_params)
- if isinstance(urlencoded, unicode_type): # PY3 returns unicode
+ if isinstance(urlencoded, str):
return urlencoded
else:
return urlencoded.decode("utf-8")
@@ -96,8 +89,8 @@ def encode_params_utf8(params):
encoded = []
for k, v in params:
encoded.append((
- k.encode('utf-8') if isinstance(k, unicode_type) else k,
- v.encode('utf-8') if isinstance(v, unicode_type) else v))
+ k.encode('utf-8') if isinstance(k, str) else k,
+ v.encode('utf-8') if isinstance(v, str) else v))
return encoded
@@ -141,22 +134,6 @@ def urldecode(query):
if INVALID_HEX_PATTERN.search(query):
raise ValueError('Invalid hex encoding in query string.')
- # We encode to utf-8 prior to parsing because parse_qsl behaves
- # differently on unicode input in python 2 and 3.
- # Python 2.7
- # >>> urlparse.parse_qsl(u'%E5%95%A6%E5%95%A6')
- # u'\xe5\x95\xa6\xe5\x95\xa6'
- # Python 2.7, non unicode input gives the same
- # >>> urlparse.parse_qsl('%E5%95%A6%E5%95%A6')
- # '\xe5\x95\xa6\xe5\x95\xa6'
- # but now we can decode it to unicode
- # >>> urlparse.parse_qsl('%E5%95%A6%E5%95%A6').decode('utf-8')
- # u'\u5566\u5566'
- # Python 3.3 however
- # >>> urllib.parse.parse_qsl(u'%E5%95%A6%E5%95%A6')
- # u'\u5566\u5566'
- query = query.encode(
- 'utf-8') if not PY3 and isinstance(query, unicode_type) else query
# We want to allow queries such as "c2" whereas urlparse.parse_qsl
# with the strict_parsing flag will not.
params = urlparse.parse_qsl(query, keep_blank_values=True)
@@ -173,7 +150,7 @@ def extract_params(raw):
empty list of parameters. Any other input will result in a return
value of None.
"""
- if isinstance(raw, (bytes, unicode_type)):
+ if isinstance(raw, (bytes, str)):
try:
params = urldecode(raw)
except ValueError:
@@ -206,7 +183,7 @@ def generate_nonce():
.. _`section 3.2.1`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1
.. _`section 3.3`: https://tools.ietf.org/html/rfc5849#section-3.3
"""
- return unicode_type(unicode_type(randbits(64)) + generate_timestamp())
+ return str(str(randbits(64)) + generate_timestamp())
def generate_timestamp():
@@ -218,7 +195,7 @@ def generate_timestamp():
.. _`section 3.2.1`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1
.. _`section 3.3`: https://tools.ietf.org/html/rfc5849#section-3.3
"""
- return unicode_type(int(time.time()))
+ return str(int(time.time()))
def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET):
@@ -305,11 +282,11 @@ def safe_string_equals(a, b):
def to_unicode(data, encoding='UTF-8'):
"""Convert a number of different types of objects to unicode."""
- if isinstance(data, unicode_type):
+ if isinstance(data, str):
return data
if isinstance(data, bytes):
- return unicode_type(data, encoding=encoding)
+ return str(data, encoding=encoding)
if hasattr(data, '__iter__'):
try:
diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py
index a60bee2..5b080aa 100644
--- a/oauthlib/oauth1/rfc5849/signature.py
+++ b/oauthlib/oauth1/rfc5849/signature.py
@@ -28,8 +28,7 @@ import hashlib
import hmac
import logging
-from oauthlib.common import (extract_params, safe_string_equals,
- unicode_type, urldecode)
+from oauthlib.common import extract_params, safe_string_equals, urldecode
from . import utils
@@ -128,7 +127,7 @@ def base_string_uri(uri, host=None):
The host argument overrides the netloc part of the uri argument.
"""
- if not isinstance(uri, unicode_type):
+ if not isinstance(uri, str):
raise ValueError('uri must be a unicode object.')
# FIXME: urlparse does not support unicode
@@ -577,7 +576,7 @@ def sign_rsa_sha1(base_string, rsa_private_key):
.. _`RFC3447, Section 8.2`: https://tools.ietf.org/html/rfc3447#section-8.2
"""
- if isinstance(base_string, unicode_type):
+ if isinstance(base_string, str):
base_string = base_string.encode('utf-8')
# TODO: finish RSA documentation
alg = _jwt_rs1_signing_algorithm()
diff --git a/oauthlib/oauth1/rfc5849/utils.py b/oauthlib/oauth1/rfc5849/utils.py
index 735f21d..a010aea 100644
--- a/oauthlib/oauth1/rfc5849/utils.py
+++ b/oauthlib/oauth1/rfc5849/utils.py
@@ -8,7 +8,7 @@ spec.
"""
from __future__ import absolute_import, unicode_literals
-from oauthlib.common import quote, unicode_type, unquote
+from oauthlib.common import quote, unquote
try:
import urllib2
@@ -52,7 +52,7 @@ def escape(u):
.. _`section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6
"""
- if not isinstance(u, unicode_type):
+ if not isinstance(u, str):
raise ValueError('Only unicode objects are escapable. ' +
'Got %r of type %s.' % (u, type(u)))
# Letters, digits, and the characters '_.-' are already treated as safe
@@ -61,7 +61,7 @@ def escape(u):
def unescape(u):
- if not isinstance(u, unicode_type):
+ if not isinstance(u, str):
raise ValueError('Only unicode objects are unescapable.')
return unquote(u)
diff --git a/oauthlib/oauth2/rfc6749/endpoints/metadata.py b/oauthlib/oauth2/rfc6749/endpoints/metadata.py
index 936e878..d3ff1d7 100644
--- a/oauthlib/oauth2/rfc6749/endpoints/metadata.py
+++ b/oauthlib/oauth2/rfc6749/endpoints/metadata.py
@@ -13,7 +13,6 @@ import copy
import json
import logging
-from ....common import unicode_type
from .base import BaseEndpoint, catch_errors_and_unavailability
from .authorization import AuthorizationEndpoint
from .introspect import IntrospectEndpoint
@@ -85,7 +84,7 @@ class MetadataEndpoint(BaseEndpoint):
if not isinstance(array[key], list):
raise ValueError("key {}: {} must be an Array".format(key, array[key]))
for elem in array[key]:
- if not isinstance(elem, unicode_type):
+ if not isinstance(elem, str):
raise ValueError("array {}: {} must contains only string (not {})".format(key, array[key], elem))
def validate_metadata_token(self, claims, endpoint):
diff --git a/oauthlib/oauth2/rfc6749/parameters.py b/oauthlib/oauth2/rfc6749/parameters.py
index 14d4c0d..b6249d8 100644
--- a/oauthlib/oauth2/rfc6749/parameters.py
+++ b/oauthlib/oauth2/rfc6749/parameters.py
@@ -13,7 +13,7 @@ import json
import os
import time
-from oauthlib.common import add_params_to_qs, add_params_to_uri, unicode_type
+from oauthlib.common import add_params_to_qs, add_params_to_uri
from oauthlib.signals import scope_changed
from .errors import (InsecureTransportError, MismatchingStateError,
@@ -82,7 +82,7 @@ def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
for k in kwargs:
if kwargs[k]:
- params.append((unicode_type(k), kwargs[k]))
+ params.append((str(k), kwargs[k]))
return add_params_to_uri(uri, params)
@@ -146,18 +146,18 @@ def prepare_token_request(grant_type, body='', include_client_id=True, **kwargs)
client_id = kwargs.pop('client_id', None)
if include_client_id:
if client_id is not None:
- params.append((unicode_type('client_id'), client_id))
+ params.append((str('client_id'), client_id))
# the kwargs iteration below only supports including boolean truth (truthy)
# values, but some servers may require an empty string for `client_secret`
client_secret = kwargs.pop('client_secret', None)
if client_secret is not None:
- params.append((unicode_type('client_secret'), client_secret))
+ params.append((str('client_secret'), client_secret))
# this handles: `code`, `redirect_uri`, and other undocumented params
for k in kwargs:
if kwargs[k]:
- params.append((unicode_type(k), kwargs[k]))
+ params.append((str(k), kwargs[k]))
return add_params_to_qs(body, params)
@@ -209,7 +209,7 @@ def prepare_token_revocation_request(url, token, token_type_hint="access_token",
for k in kwargs:
if kwargs[k]:
- params.append((unicode_type(k), kwargs[k]))
+ params.append((str(k), kwargs[k]))
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
diff --git a/oauthlib/oauth2/rfc6749/tokens.py b/oauthlib/oauth2/rfc6749/tokens.py
index 3587af4..5b99f0c 100644
--- a/oauthlib/oauth2/rfc6749/tokens.py
+++ b/oauthlib/oauth2/rfc6749/tokens.py
@@ -15,7 +15,7 @@ from binascii import b2a_base64
import warnings
from oauthlib import common
-from oauthlib.common import add_params_to_qs, add_params_to_uri, unicode_type
+from oauthlib.common import add_params_to_qs, add_params_to_uri
from . import utils
@@ -158,7 +158,7 @@ def prepare_mac_header(token, uri, key, http_method,
base_string = '\n'.join(base) + '\n'
# hmac struggles with unicode strings - http://bugs.python.org/issue5285
- if isinstance(key, unicode_type):
+ if isinstance(key, str):
key = key.encode('utf-8')
sign = hmac.new(key, base_string.encode('utf-8'), h)
sign = b2a_base64(sign.digest())[:-1].decode('utf-8')
diff --git a/oauthlib/oauth2/rfc6749/utils.py b/oauthlib/oauth2/rfc6749/utils.py
index f67019d..7516c9e 100644
--- a/oauthlib/oauth2/rfc6749/utils.py
+++ b/oauthlib/oauth2/rfc6749/utils.py
@@ -10,7 +10,7 @@ from __future__ import absolute_import, unicode_literals
import datetime
import os
-from oauthlib.common import unicode_type, urldecode
+from oauthlib.common import urldecode
try:
from urllib import quote
@@ -24,10 +24,10 @@ except ImportError:
def list_to_scope(scope):
"""Convert a list of scopes to a space separated string."""
- if isinstance(scope, unicode_type) or scope is None:
+ if isinstance(scope, str) or scope is None:
return scope
elif isinstance(scope, (set, tuple, list)):
- return " ".join([unicode_type(s) for s in scope])
+ return " ".join([str(s) for s in scope])
else:
raise ValueError("Invalid scope (%s), must be string, tuple, set, or list." % scope)
@@ -35,7 +35,7 @@ def list_to_scope(scope):
def scope_to_list(scope):
"""Convert a space separated string to a list of scopes."""
if isinstance(scope, (tuple, list, set)):
- return [unicode_type(s) for s in scope]
+ return [str(s) for s in scope]
elif scope is None:
return None
else:
@@ -74,7 +74,7 @@ def escape(u):
TODO: verify whether this can in fact be used for OAuth 2
"""
- if not isinstance(u, unicode_type):
+ if not isinstance(u, str):
raise ValueError('Only unicode objects are escapable.')
return quote(u.encode('utf-8'), safe=b'~')
@@ -84,7 +84,7 @@ def generate_age(issue_time):
td = datetime.datetime.now() - issue_time
age = (td.microseconds + (td.seconds + td.days * 24 * 3600)
* 10 ** 6) / 10 ** 6
- return unicode_type(age)
+ return str(age)
def is_secure_transport(uri):
diff --git a/oauthlib/openid/connect/core/endpoints/userinfo.py b/oauthlib/openid/connect/core/endpoints/userinfo.py
index 7a39f76..d7387fe 100644
--- a/oauthlib/openid/connect/core/endpoints/userinfo.py
+++ b/oauthlib/openid/connect/core/endpoints/userinfo.py
@@ -10,7 +10,6 @@ import json
import logging
from oauthlib.common import Request
-from oauthlib.common import unicode_type
from oauthlib.oauth2.rfc6749.endpoints.base import BaseEndpoint
from oauthlib.oauth2.rfc6749.endpoints.base import catch_errors_and_unavailability
from oauthlib.oauth2.rfc6749.tokens import BearerToken
@@ -55,7 +54,7 @@ class UserInfoEndpoint(BaseEndpoint):
log.error('Userinfo MUST have "sub" for %r.', request)
raise errors.ServerError(status_code=500)
body = json.dumps(claims)
- elif isinstance(claims, unicode_type):
+ elif isinstance(claims, str):
resp_headers = {
'Content-Type': 'application/jwt'
}
diff --git a/setup.py b/setup.py
index 1de8510..0aebd6c 100755
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@ setup(
platforms='any',
license='BSD',
packages=find_packages(exclude=('docs', 'tests', 'tests.*')),
- python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
+ python_requires='>=3.4',
extras_require={
'rsa': rsa_require,
'signedtoken': signedtoken_require,
@@ -53,13 +53,12 @@ setup(
'Operating System :: POSIX',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: Implementation',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
diff --git a/tests/oauth1/rfc5849/test_signatures.py b/tests/oauth1/rfc5849/test_signatures.py
index bb0dc78..4eb7ff3 100644
--- a/tests/oauth1/rfc5849/test_signatures.py
+++ b/tests/oauth1/rfc5849/test_signatures.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
-from oauthlib.common import unicode_type
from oauthlib.oauth1.rfc5849.signature import (collect_parameters,
signature_base_string,
base_string_uri,
@@ -232,7 +231,7 @@ class SignatureTests(TestCase):
normalized = normalize_parameters(parameters)
# Unicode everywhere and always
- self.assertIsInstance(normalized, unicode_type)
+ self.assertIsInstance(normalized, str)
# Lets see if things are in order
# check to see that querystring keys come in alphanumeric order:
diff --git a/tests/oauth1/rfc5849/test_utils.py b/tests/oauth1/rfc5849/test_utils.py
index 5a889e8..1db2659 100644
--- a/tests/oauth1/rfc5849/test_utils.py
+++ b/tests/oauth1/rfc5849/test_utils.py
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
-from oauthlib.common import unicode_type
from oauthlib.oauth1.rfc5849.utils import *
from ...unittest import TestCase
@@ -102,12 +101,12 @@ class UtilsTests(TestCase):
def test_escape(self):
self.assertRaises(ValueError, escape, b"I am a string type. Not a unicode type.")
self.assertEqual(escape("I am a unicode type."), "I%20am%20a%20unicode%20type.")
- self.assertIsInstance(escape("I am a unicode type."), unicode_type)
+ self.assertIsInstance(escape("I am a unicode type."), str)
def test_unescape(self):
self.assertRaises(ValueError, unescape, b"I am a string type. Not a unicode type.")
self.assertEqual(unescape("I%20am%20a%20unicode%20type."), 'I am a unicode type.')
- self.assertIsInstance(unescape("I%20am%20a%20unicode%20type."), unicode_type)
+ self.assertIsInstance(unescape("I%20am%20a%20unicode%20type."), str)
def test_parse_authorization_header(self):
# make us some headers
@@ -122,8 +121,8 @@ class UtilsTests(TestCase):
# are the internal components of each tuple unicode?
for k, v in authorization_headers:
- self.assertIsInstance(k, unicode_type)
- self.assertIsInstance(v, unicode_type)
+ self.assertIsInstance(k, str)
+ self.assertIsInstance(v, str)
# let's check the parsed headers created
correct_headers = [
diff --git a/tests/oauth2/rfc6749/endpoints/test_scope_handling.py b/tests/oauth2/rfc6749/endpoints/test_scope_handling.py
index 4f27963..b235bd7 100644
--- a/tests/oauth2/rfc6749/endpoints/test_scope_handling.py
+++ b/tests/oauth2/rfc6749/endpoints/test_scope_handling.py
@@ -65,13 +65,13 @@ class TestScopeHandling(TestCase):
for scope, correct_scopes in scopes:
scopes, _ = self.web.validate_authorization_request(
uri % (scope, 'code'))
- self.assertItemsEqual(scopes, correct_scopes)
+ self.assertCountEqual(scopes, correct_scopes)
scopes, _ = self.mobile.validate_authorization_request(
uri % (scope, 'token'))
- self.assertItemsEqual(scopes, correct_scopes)
+ self.assertCountEqual(scopes, correct_scopes)
scopes, _ = self.server.validate_authorization_request(
uri % (scope, 'code'))
- self.assertItemsEqual(scopes, correct_scopes)
+ self.assertCountEqual(scopes, correct_scopes)
def test_scope_preservation(self):
scope = 'pics+http%3A%2f%2fa.b%2fvideos'
diff --git a/tests/oauth2/rfc6749/test_utils.py b/tests/oauth2/rfc6749/test_utils.py
index 609162c..6b85b27 100644
--- a/tests/oauth2/rfc6749/test_utils.py
+++ b/tests/oauth2/rfc6749/test_utils.py
@@ -3,7 +3,6 @@ from __future__ import absolute_import, unicode_literals
import datetime
import os
-from oauthlib.common import PY3
from oauthlib.oauth2.rfc6749.utils import (escape, generate_age, host_from_uri,
is_secure_transport, list_to_scope,
params_from_uri, scope_to_list)
@@ -19,12 +18,8 @@ class ScopeObject:
def __init__(self, scope):
self.scope = scope
- if PY3:
- def __str__(self):
- return self.scope
- else:
- def __unicode__(self):
- return self.scope
+ def __str__(self):
+ return self.scope
class UtilsTests(TestCase):
diff --git a/tests/test_common.py b/tests/test_common.py
index ae2531b..c2c5e41 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -8,7 +8,7 @@ import oauthlib
from oauthlib.common import (CaseInsensitiveDict, Request, add_params_to_uri,
extract_params, generate_client_id,
generate_nonce, generate_timestamp,
- generate_token, unicode_type, urldecode)
+ generate_token, urldecode)
from .unittest import TestCase
@@ -21,23 +21,23 @@ URI = 'http://www.someuri.com'
class EncodingTest(TestCase):
def test_urldecode(self):
- self.assertItemsEqual(urldecode(''), [])
- self.assertItemsEqual(urldecode('='), [('', '')])
- self.assertItemsEqual(urldecode('%20'), [(' ', '')])
- self.assertItemsEqual(urldecode('+'), [(' ', '')])
- self.assertItemsEqual(urldecode('c2'), [('c2', '')])
- self.assertItemsEqual(urldecode('c2='), [('c2', '')])
- self.assertItemsEqual(urldecode('foo=bar'), [('foo', 'bar')])
- self.assertItemsEqual(urldecode('foo_%20~=.bar-'),
+ self.assertCountEqual(urldecode(''), [])
+ self.assertCountEqual(urldecode('='), [('', '')])
+ self.assertCountEqual(urldecode('%20'), [(' ', '')])
+ self.assertCountEqual(urldecode('+'), [(' ', '')])
+ self.assertCountEqual(urldecode('c2'), [('c2', '')])
+ self.assertCountEqual(urldecode('c2='), [('c2', '')])
+ self.assertCountEqual(urldecode('foo=bar'), [('foo', 'bar')])
+ self.assertCountEqual(urldecode('foo_%20~=.bar-'),
[('foo_ ~', '.bar-')])
- self.assertItemsEqual(urldecode('foo=1,2,3'), [('foo', '1,2,3')])
- self.assertItemsEqual(urldecode('foo=(1,2,3)'), [('foo', '(1,2,3)')])
- self.assertItemsEqual(urldecode('foo=bar.*'), [('foo', 'bar.*')])
- self.assertItemsEqual(urldecode('foo=bar@spam'), [('foo', 'bar@spam')])
- self.assertItemsEqual(urldecode('foo=bar/baz'), [('foo', 'bar/baz')])
- self.assertItemsEqual(urldecode('foo=bar?baz'), [('foo', 'bar?baz')])
- self.assertItemsEqual(urldecode('foo=bar\'s'), [('foo', 'bar\'s')])
- self.assertItemsEqual(urldecode('foo=$'), [('foo', '$')])
+ self.assertCountEqual(urldecode('foo=1,2,3'), [('foo', '1,2,3')])
+ self.assertCountEqual(urldecode('foo=(1,2,3)'), [('foo', '(1,2,3)')])
+ self.assertCountEqual(urldecode('foo=bar.*'), [('foo', 'bar.*')])
+ self.assertCountEqual(urldecode('foo=bar@spam'), [('foo', 'bar@spam')])
+ self.assertCountEqual(urldecode('foo=bar/baz'), [('foo', 'bar/baz')])
+ self.assertCountEqual(urldecode('foo=bar?baz'), [('foo', 'bar?baz')])
+ self.assertCountEqual(urldecode('foo=bar\'s'), [('foo', 'bar\'s')])
+ self.assertCountEqual(urldecode('foo=$'), [('foo', '$')])
self.assertRaises(ValueError, urldecode, 'foo bar')
self.assertRaises(ValueError, urldecode, '%R')
self.assertRaises(ValueError, urldecode, '%RA')
@@ -48,20 +48,20 @@ class EncodingTest(TestCase):
class ParameterTest(TestCase):
def test_extract_params_dict(self):
- self.assertItemsEqual(extract_params(PARAMS_DICT), PARAMS_TWOTUPLE)
+ self.assertCountEqual(extract_params(PARAMS_DICT), PARAMS_TWOTUPLE)
def test_extract_params_twotuple(self):
- self.assertItemsEqual(extract_params(PARAMS_TWOTUPLE), PARAMS_TWOTUPLE)
+ self.assertCountEqual(extract_params(PARAMS_TWOTUPLE), PARAMS_TWOTUPLE)
def test_extract_params_formencoded(self):
- self.assertItemsEqual(extract_params(PARAMS_FORMENCODED),
+ self.assertCountEqual(extract_params(PARAMS_FORMENCODED),
PARAMS_TWOTUPLE)
def test_extract_params_blank_string(self):
- self.assertItemsEqual(extract_params(''), [])
+ self.assertCountEqual(extract_params(''), [])
def test_extract_params_empty_list(self):
- self.assertItemsEqual(extract_params([]), [])
+ self.assertCountEqual(extract_params([]), [])
def test_extract_non_formencoded_string(self):
self.assertEqual(extract_params('not a formencoded string'), None)
@@ -80,7 +80,7 @@ class GeneratorTest(TestCase):
def test_generate_timestamp(self):
timestamp = generate_timestamp()
- self.assertIsInstance(timestamp, unicode_type)
+ self.assertIsInstance(timestamp, str)
self.assertTrue(int(timestamp))
self.assertGreater(int(timestamp), 1331672335)
@@ -160,11 +160,11 @@ class RequestTest(TestCase):
def test_list_body(self):
r = Request(URI, body=PARAMS_TWOTUPLE)
- self.assertItemsEqual(r.decoded_body, PARAMS_TWOTUPLE)
+ self.assertCountEqual(r.decoded_body, PARAMS_TWOTUPLE)
def test_dict_body(self):
r = Request(URI, body=PARAMS_DICT)
- self.assertItemsEqual(r.decoded_body, PARAMS_TWOTUPLE)
+ self.assertCountEqual(r.decoded_body, PARAMS_TWOTUPLE)
def test_getattr_existing_attribute(self):
r = Request(URI, body='foo bar')
diff --git a/tests/unittest/__init__.py b/tests/unittest/__init__.py
index 6cb79a6..13ad92f 100644
--- a/tests/unittest/__init__.py
+++ b/tests/unittest/__init__.py
@@ -1,18 +1,8 @@
-import collections
-import sys
from unittest import TestCase
-try:
- import urlparse
-except ImportError:
- import urllib.parse as urlparse
+import urllib.parse as urlparse
-# Somewhat consistent itemsequal between all python versions
-if sys.version_info[0] == 3:
- TestCase.assertItemsEqual = TestCase.assertCountEqual
-
-
-# URL comparison where query param order is insignifcant
+# URL comparison where query param order is insignificant
def url_equals(self, a, b, parse_fragment=False):
parsed_a = urlparse.urlparse(a, allow_fragments=parse_fragment)
parsed_b = urlparse.urlparse(b, allow_fragments=parse_fragment)
@@ -21,7 +11,7 @@ def url_equals(self, a, b, parse_fragment=False):
if parse_fragment:
fragment_a = urlparse.parse_qsl(parsed_a.fragment)
fragment_b = urlparse.parse_qsl(parsed_b.fragment)
- self.assertItemsEqual(fragment_a, fragment_b)
+ self.assertCountEqual(fragment_a, fragment_b)
else:
self.assertEqual(parsed_a.fragment, parsed_b.fragment)
self.assertEqual(parsed_a.scheme, parsed_b.scheme)
@@ -32,10 +22,11 @@ def url_equals(self, a, b, parse_fragment=False):
self.assertEqual(parsed_a.password, parsed_b.password)
self.assertEqual(parsed_a.hostname, parsed_b.hostname)
self.assertEqual(parsed_a.port, parsed_b.port)
- self.assertItemsEqual(query_a, query_b)
+ self.assertCountEqual(query_a, query_b)
+
TestCase.assertURLEqual = url_equals
# Form body comparison where order is insignificant
-TestCase.assertFormBodyEqual = lambda self, a, b: self.assertItemsEqual(
+TestCase.assertFormBodyEqual = lambda self, a, b: self.assertCountEqual(
urlparse.parse_qsl(a), urlparse.parse_qsl(b))
diff --git a/tox.ini b/tox.ini
index 4670c91..e2731f3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py27,py34,py35,py36,py37,pypy,pypy3,docs,readme,bandit
+envlist = py34,py35,py36,py37,pypy,pypy3,docs,readme,bandit
[testenv]
deps=
@@ -29,7 +29,7 @@ commands=
twine check dist/*
[testenv:bandit]
-basepython=python2.7
+basepython=python3.7
skipsdist=True
deps=bandit
commands=bandit -b bandit.json -r oauthlib/