diff --git a/debian/control b/debian/control
index 37f59d688..c19cc8281 100644
--- a/debian/control
+++ b/debian/control
@@ -29,7 +29,6 @@ Depends: ${misc:Depends}, ${python3:Depends},
python3-djangorestframework (<< 3.10),
python3-markdown (>= 2.1),
python3-ldap (>= 2.4),
- python3-six (>= 1.0),
python3-jwcrypto (>= 0.3.1),
python3-cryptography (>= 1.3.4),
python3-django-filters (>= 1),
diff --git a/debian/py3dist-overrides b/debian/py3dist-overrides
index 06a9625b7..15b31a735 100644
--- a/debian/py3dist-overrides
+++ b/debian/py3dist-overrides
@@ -9,7 +9,6 @@ XStatic_jQuery python3-xstatic-jquery
XStatic_jquery_ui python3-xstatic-jquery-ui
django-import-export python3-django-import-export
django-sekizai python3-django-sekizai
-six python3-six
pycryptodome python3-pycryptodome
ldaptools python3-ldaptools
django-mellon python3-django-mellon
diff --git a/doc/installation_modes.rst b/doc/installation_modes.rst
index 9912a5ddd..0a5ddcb7b 100644
--- a/doc/installation_modes.rst
+++ b/doc/installation_modes.rst
@@ -23,7 +23,6 @@ The other Authentic 2 dependencies are:
- gadjo>=0.6
- django-import-export>=0.2.7,<=0.4.5
- djangorestframework>=3.3
-- six>=1.9
- Markdown>=2.5
- python-ldap
diff --git a/setup.py b/setup.py
index f313eb6ee..c748d7e06 100755
--- a/setup.py
+++ b/setup.py
@@ -129,7 +129,6 @@ setup(
'gadjo>=0.53',
'django-import-export>=1,<2',
'djangorestframework>=3.3,<3.10',
- 'six>=1',
'Markdown>=2.1',
'python-ldap',
'django-filter>1,<2.3',
diff --git a/src/authentic2/a2_rbac/admin.py b/src/authentic2/a2_rbac/admin.py
index d7dedaecc..2e844acfa 100644
--- a/src/authentic2/a2_rbac/admin.py
+++ b/src/authentic2/a2_rbac/admin.py
@@ -15,7 +15,6 @@
# along with this program. If not, see .
from django.contrib import admin
-from django.utils import six
from django.utils.translation import ugettext_lazy as _
from . import models
@@ -90,7 +89,7 @@ class PermissionAdmin(admin.ModelAdmin):
list_select_related = True
def name(self, obj):
- return six.text_type(obj)
+ return str(obj)
name.short_description = _('name')
diff --git a/src/authentic2/a2_rbac/management.py b/src/authentic2/a2_rbac/management.py
index 7e5410b74..a1c94ff88 100644
--- a/src/authentic2/a2_rbac/management.py
+++ b/src/authentic2/a2_rbac/management.py
@@ -15,7 +15,6 @@
# along with this program. If not, see .
from django.contrib.contenttypes.models import ContentType
-from django.utils import six
from django.utils.text import slugify
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
@@ -41,9 +40,9 @@ def update_ou_admin_roles(ou):
# do not create scoped admin roles if the model is not scopable
if not ou_model:
continue
- name = six.text_type(MANAGED_CT[key]['name'])
+ name = str(MANAGED_CT[key]['name'])
slug = '_a2-' + slugify(name)
- scoped_name = six.text_type(MANAGED_CT[key]['scoped_name'])
+ scoped_name = str(MANAGED_CT[key]['scoped_name'])
name = scoped_name.format(ou=ou)
ou_slug = slug + '-' + ou.slug
if app_settings.MANAGED_CONTENT_TYPES == ():
@@ -123,7 +122,7 @@ def update_content_types_roles():
if ct_tuple not in MANAGED_CT:
continue
# General admin role
- name = six.text_type(MANAGED_CT[ct_tuple]['name'])
+ name = str(MANAGED_CT[ct_tuple]['name'])
slug = '_a2-' + slugify(name)
if (
app_settings.MANAGED_CONTENT_TYPES is not None
diff --git a/src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py b/src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py
index 05ff20c75..accdb0b17 100644
--- a/src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py
+++ b/src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
from django.db import migrations
-from django.utils.six import text_type
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
from django_rbac.models import CHANGE_OP
@@ -14,8 +13,8 @@ def update_self_administration_perm(apps, schema_editor):
Permission = apps.get_model('a2_rbac', 'Permission')
Operation = apps.get_model('django_rbac', 'Operation')
ContentType = apps.get_model('contenttypes', 'ContentType')
- change_op, _ = Operation.objects.get_or_create(slug=text_type(CHANGE_OP.slug))
- manage_members_op, _ = Operation.objects.get_or_create(slug=text_type(MANAGE_MEMBERS_OP.slug))
+ change_op, _ = Operation.objects.get_or_create(slug=str(CHANGE_OP.slug))
+ manage_members_op, _ = Operation.objects.get_or_create(slug=str(MANAGE_MEMBERS_OP.slug))
ct = ContentType.objects.get_for_model(Role)
perms_to_delete = []
for role in Role.objects.all():
diff --git a/src/authentic2/a2_rbac/models.py b/src/authentic2/a2_rbac/models.py
index b17e8df9b..f8dcd74da 100644
--- a/src/authentic2/a2_rbac/models.py
+++ b/src/authentic2/a2_rbac/models.py
@@ -20,7 +20,6 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
from django.db import models
-from django.utils import six
from django.utils.text import slugify
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
@@ -248,8 +247,8 @@ class Role(RoleAbstractBase):
admin_role = self.__class__.objects.get_admin_role(
self,
- name=_('Managers of role "{role}"').format(role=six.text_type(self)),
- slug='_a2-managers-of-role-{role}'.format(role=slugify(six.text_type(self))),
+ name=_('Managers of role "{role}"').format(role=str(self)),
+ slug='_a2-managers-of-role-{role}'.format(role=slugify(str(self))),
permissions=(view_user_perm,),
self_administered=True,
update_name=True,
diff --git a/src/authentic2/app_settings.py b/src/authentic2/app_settings.py
index 24be4e6c8..2cfb15389 100644
--- a/src/authentic2/app_settings.py
+++ b/src/authentic2/app_settings.py
@@ -16,7 +16,6 @@
import sys
-import six
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _
@@ -26,7 +25,7 @@ class Setting(object):
def __init__(self, default=SENTINEL, definition='', names=None):
self.names = names or []
- if isinstance(self.names, six.string_types):
+ if isinstance(self.names, str):
self.names = [self.names]
self.names = set(self.names)
self.default = default
diff --git a/src/authentic2/attribute_kinds.py b/src/authentic2/attribute_kinds.py
index 60fd15be9..e30e5a027 100644
--- a/src/authentic2/attribute_kinds.py
+++ b/src/authentic2/attribute_kinds.py
@@ -28,7 +28,7 @@ from django.core.files.storage import default_storage
from django.core.validators import RegexValidator
from django.db.models import query
from django.urls import reverse
-from django.utils import formats, html, six
+from django.utils import formats, html
from django.utils.functional import keep_lazy
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
@@ -42,7 +42,7 @@ from .forms import fields, widgets
from .plugins import collect_from_plugins
-@keep_lazy(six.text_type)
+@keep_lazy(str)
def capfirst(value):
return value and value[0].upper() + value[1:]
@@ -75,7 +75,7 @@ class DateRestField(serializers.DateField):
# Test for the empty string here so that it does not get validated,
# and so that subclasses do not need to handle it explicitly
# inside the `to_internal_value()` method.
- if data == '' or (self.trim_whitespace and six.text_type(data).strip() == ''):
+ if data == '' or (self.trim_whitespace and str(data).strip() == ''):
if not self.allow_blank:
self.fail('blank')
return ''
diff --git a/src/authentic2/attributes_ng/sources/__init__.py b/src/authentic2/attributes_ng/sources/__init__.py
index 1895f09ea..ca4a9bdb0 100644
--- a/src/authentic2/attributes_ng/sources/__init__.py
+++ b/src/authentic2/attributes_ng/sources/__init__.py
@@ -16,11 +16,8 @@
import abc
-from django.utils import six
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseAttributeSource(object):
+class BaseAttributeSource(object, metaclass=abc.ABCMeta):
"""
Base class for attribute sources
"""
diff --git a/src/authentic2/attributes_ng/sources/django_user.py b/src/authentic2/attributes_ng/sources/django_user.py
index 13ab0c0b2..af9f190a9 100644
--- a/src/authentic2/attributes_ng/sources/django_user.py
+++ b/src/authentic2/attributes_ng/sources/django_user.py
@@ -15,7 +15,6 @@
# along with this program. If not, see .
from django.contrib.auth import get_user_model
-from django.utils import six
from django.utils.translation import ugettext_lazy as _
from django_rbac.utils import get_role_model
@@ -91,7 +90,7 @@ def get_attributes(instance, ctx):
ctx['django_user_' + str(av.attribute.name)] = serialized
ctx['django_user_' + str(av.attribute.name) + ':verified'] = av.verified
ctx['django_user_groups'] = [group for group in user.groups.all()]
- ctx['django_user_group_names'] = [six.text_type(group) for group in user.groups.all()]
+ ctx['django_user_group_names'] = [str(group) for group in user.groups.all()]
if user.username:
splitted = user.username.rsplit('@', 1)
ctx['django_user_domain'] = splitted[1] if '@' in user.username else ''
diff --git a/src/authentic2/attributes_ng/sources/format.py b/src/authentic2/attributes_ng/sources/format.py
index 93ed095ed..f72e9e266 100644
--- a/src/authentic2/attributes_ng/sources/format.py
+++ b/src/authentic2/attributes_ng/sources/format.py
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import six
from django.core.exceptions import ImproperlyConfigured
from ...decorators import to_list
@@ -62,7 +61,7 @@ def get_instances(ctx):
config_error(UNEXPECTED_KEYS_ERROR, unexpected)
if 'name' not in keys or 'template' not in keys:
config_error(BAD_CONFIG_ERROR)
- if not isinstance(d['template'], six.string_types):
+ if not isinstance(d['template'], str):
config_error(TYPE_ERROR)
yield d
diff --git a/src/authentic2/authentication.py b/src/authentic2/authentication.py
index b1b76a4a9..d31c94ab1 100644
--- a/src/authentic2/authentication.py
+++ b/src/authentic2/authentication.py
@@ -16,8 +16,6 @@
import inspect
-from django.utils import six
-
try:
from django.utils.deprecation import CallableTrue
except ImportError:
@@ -71,8 +69,7 @@ class Authentic2Authentication(BasicAuthentication):
pass
# try BasicAuthentication
if (
- six.PY3
- and 'request'
+ 'request'
in inspect.signature(super(Authentic2Authentication, self).authenticate_credentials).parameters
):
# compatibility with DRF 3.4
diff --git a/src/authentic2/backends/ldap_backend.py b/src/authentic2/backends/ldap_backend.py
index a4a53aa42..676f082e9 100644
--- a/src/authentic2/backends/ldap_backend.py
+++ b/src/authentic2/backends/ldap_backend.py
@@ -15,6 +15,7 @@
# along with this program. If not, see .
import hashlib
+import urllib.parse
try:
import ldap
@@ -36,6 +37,7 @@ import logging
import os
import random
import time
+import urllib.parse
from django.conf import settings
from django.contrib import messages
@@ -43,9 +45,7 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.core.cache import cache
from django.core.exceptions import ImproperlyConfigured
-from django.utils import six
from django.utils.encoding import force_bytes, force_text
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ngettext
from django.utils.translation import ugettext as _
@@ -290,7 +290,7 @@ elif PYTHON_LDAP3 is False:
def map_text(d):
if d is None:
return d
- elif isinstance(d, six.string_types):
+ elif isinstance(d, str):
return force_text(d)
elif isinstance(d, (list, tuple)):
return d.__class__(map_text(x) for x in d)
@@ -1031,7 +1031,7 @@ class LDAPBackend(object):
'''Obtain a Django role'''
kwargs = {}
slug = None
- if isinstance(role_id, six.string_types):
+ if isinstance(role_id, str):
slug = role_id
elif isinstance(role_id, (tuple, list)):
try:
@@ -1302,7 +1302,7 @@ class LDAPBackend(object):
attribute, param = attribute.split(':')
quote = 'noquote' not in param.split(',')
if quote:
- decoded.append((attribute, urlparse.unquote(value)))
+ decoded.append((attribute, urllib.parse.unquote(value)))
else:
decoded.append((attribute, force_text(value)))
filters = [filter_format(u'(%s=%s)', (a, b)) for a, b in decoded]
@@ -1322,7 +1322,7 @@ class LDAPBackend(object):
if isinstance(part, list):
part = part[0]
if quote:
- part = urlparse.quote(part.encode('utf-8'))
+ part = urllib.parse.quote(part.encode('utf-8'))
parts.append(part)
return ' '.join(part for part in parts)
@@ -1676,7 +1676,7 @@ class LDAPBackend(object):
# convert string to list of strings for settings accepting it
for i in cls._TO_ITERABLE:
- if i in block and isinstance(block[i], six.string_types):
+ if i in block and isinstance(block[i], str):
block[i] = (block[i],)
for d in cls._DEFAULTS:
@@ -1685,8 +1685,8 @@ class LDAPBackend(object):
if d == 'user_filter' and app_settings.A2_ACCEPT_EMAIL_AUTHENTICATION:
block[d] = '(|(mail=%s)(uid=%s))'
else:
- if isinstance(cls._DEFAULTS[d], six.string_types):
- if not isinstance(block[d], six.string_types):
+ if isinstance(cls._DEFAULTS[d], str):
+ if not isinstance(block[d], str):
raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: attribute %r must be a string' % d)
try:
block[d] = force_text(block[d])
@@ -1710,7 +1710,7 @@ class LDAPBackend(object):
for key in cls._TO_LOWERCASE:
# we handle strings, list of strings and list of list or tuple whose first element is a
# string
- if isinstance(block[key], six.string_types):
+ if isinstance(block[key], str):
block[key] = force_text(block[key]).lower()
elif isinstance(block[key], (list, tuple)):
new_seq = []
diff --git a/src/authentic2/backends/models_backend.py b/src/authentic2/backends/models_backend.py
index 0fffa85e3..eeb54138c 100644
--- a/src/authentic2/backends/models_backend.py
+++ b/src/authentic2/backends/models_backend.py
@@ -16,10 +16,11 @@
from __future__ import unicode_literals
+import functools
+
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.db import models
-from django.utils import six
from authentic2.backends import get_user_queryset
from authentic2.user_login_failure import user_login_failure, user_login_success
@@ -58,7 +59,7 @@ class ModelBackend(ModelBackend):
queries.append(models.Q(**{username_field: upn(username, realm)}))
else:
queries.append(models.Q(**{username_field: upn(username, realm)}))
- queries = six.moves.reduce(models.Q.__or__, queries)
+ queries = functools.reduce(models.Q.__or__, queries)
if ou:
queries &= models.Q(ou=ou)
return queries
diff --git a/src/authentic2/cors.py b/src/authentic2/cors.py
index 1064118dd..9ccf97c82 100644
--- a/src/authentic2/cors.py
+++ b/src/authentic2/cors.py
@@ -15,8 +15,9 @@
# along with this program. If not, see .
+import urllib.parse
+
from django.conf import settings
-from django.utils.six.moves.urllib import parse as urlparse
from . import app_settings, plugins
from .decorators import SessionCache
@@ -24,7 +25,7 @@ from .decorators import SessionCache
def make_origin(url):
'''Build origin of an URL'''
- parsed = urlparse.urlparse(url)
+ parsed = urllib.parse.urlparse(url)
if ':' in parsed.netloc:
host, port = parsed.netloc.split(':', 1)
if parsed.scheme == 'http' and port == 80:
diff --git a/src/authentic2/crypto.py b/src/authentic2/crypto.py
index 8b9f04bf2..3abf9eb81 100644
--- a/src/authentic2/crypto.py
+++ b/src/authentic2/crypto.py
@@ -26,7 +26,6 @@ from Cryptodome.Hash import HMAC, SHA256
from Cryptodome.Protocol.KDF import PBKDF2
from django.utils.crypto import constant_time_compare
from django.utils.encoding import force_bytes
-from django.utils.six import text_type
class DecryptionError(Exception):
@@ -123,7 +122,7 @@ def aes_base64url_deterministic_encrypt(key, data, salt, hash_name='sha256', cou
key_size = 16
hmac_size = key_size
- if isinstance(salt, text_type):
+ if isinstance(salt, str):
salt = force_bytes(salt)
iv = hashmod.new(salt).digest()
@@ -174,7 +173,7 @@ def aes_base64url_deterministic_decrypt(key, urlencoded, salt, raise_on_error=Tr
if not crypted or not hmac or prf(key, crypted)[:hmac_size] != hmac:
raise DecryptionError('invalid HMAC')
- if isinstance(salt, text_type):
+ if isinstance(salt, str):
salt = force_bytes(salt)
iv = hashmod.new(salt).digest()
diff --git a/src/authentic2/csv_import.py b/src/authentic2/csv_import.py
index dbc029e48..04c621472 100644
--- a/src/authentic2/csv_import.py
+++ b/src/authentic2/csv_import.py
@@ -27,7 +27,6 @@ from django.core.exceptions import FieldDoesNotExist, ValidationError
from django.core.validators import RegexValidator
from django.db import IntegrityError, models
from django.db.transaction import atomic
-from django.utils import six
from django.utils.encoding import force_bytes, force_text
from django.utils.translation import ugettext as _
@@ -109,9 +108,9 @@ class CsvImporter(object):
encoding = None
def run(self, fd_or_str, encoding):
- if isinstance(fd_or_str, six.binary_type):
+ if isinstance(fd_or_str, bytes):
input_fd = io.BytesIO(fd_or_str)
- elif isinstance(fd_or_str, six.text_type):
+ elif isinstance(fd_or_str, str):
input_fd = io.StringIO(fd_or_str)
elif not hasattr(fd_or_str, 'read1'):
try:
@@ -122,7 +121,7 @@ class CsvImporter(object):
except Exception:
pass
content = fd_or_str.read()
- if isinstance(content, six.text_type):
+ if isinstance(content, str):
input_fd = io.StringIO(content)
else:
input_fd = io.BytesIO(content)
@@ -539,7 +538,7 @@ class UserCsvImporter(object):
form.is_valid()
def get_form_errors(form, name):
- return [Error('data-error', six.text_type(value)) for value in form.errors.get(name, [])]
+ return [Error('data-error', str(value)) for value in form.errors.get(name, [])]
cells = [
CsvCell(
diff --git a/src/authentic2/custom_user/models.py b/src/authentic2/custom_user/models.py
index bc67f99b4..caef5ded4 100644
--- a/src/authentic2/custom_user/models.py
+++ b/src/authentic2/custom_user/models.py
@@ -24,7 +24,7 @@ import os
from django.core.exceptions import MultipleObjectsReturned, ValidationError
from django.core.mail import send_mail
from django.db import models, transaction
-from django.utils import six, timezone
+from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
try:
@@ -233,7 +233,7 @@ class User(AbstractBaseUser, PermissionMixin):
return '%s (%s)' % (human_name, short_id)
def __repr__(self):
- return '' % six.text_type(self)
+ return '' % str(self)
def clean(self):
if not (self.username or self.email or (self.first_name and self.last_name)):
diff --git a/src/authentic2/decorators.py b/src/authentic2/decorators.py
index 62641a4a3..acfc4ce67 100644
--- a/src/authentic2/decorators.py
+++ b/src/authentic2/decorators.py
@@ -25,7 +25,6 @@ from json import dumps as json_dumps
from django.core.cache import cache as django_cache
from django.core.exceptions import ValidationError
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
-from django.utils import six
from django.views.debug import technical_404_response
from . import app_settings, middleware
@@ -195,12 +194,12 @@ class CacheDecoratorBase(object):
for i, arg in enumerate(args):
if self.args and i not in self.args:
continue
- parts.append(six.text_type(arg))
+ parts.append(str(arg))
for kw, arg in sorted(kwargs.items(), key=lambda x: x[0]):
if kw not in self.kwargs:
continue
- parts.append(u'%s-%s' % (six.text_type(kw), six.text_type(arg)))
+ parts.append(u'%s-%s' % (str(kw), str(arg)))
return u'|'.join(parts)
diff --git a/src/authentic2/disco_service/disco_responder.py b/src/authentic2/disco_service/disco_responder.py
index 7ac230afa..6100ec2ba 100644
--- a/src/authentic2/disco_service/disco_responder.py
+++ b/src/authentic2/disco_service/disco_responder.py
@@ -23,13 +23,13 @@
import logging
+import urllib.parse
from xml.dom.minidom import parseString
from django.conf.urls import url
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.http import urlquote
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext as _
from authentic2 import settings
@@ -117,21 +117,21 @@ def get_disco_return_url_from_metadata(entity_id):
def is_param_id_in_return_url(return_url, returnIDParam):
- url = urlparse.urlparse(return_url)
- if url.query and returnIDParam in urlparse.parse_qs(url.query):
+ url = urllib.parse.urlparse(return_url)
+ if url.query and returnIDParam in urllib.parse.parse_qs(url.query):
return True
return False
def add_param_to_url(url, param_name, value):
- scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
+ scheme, netloc, path, params, query, fragment = urllib.parse.urlparse(url)
if query:
- qs = urlparse.parse_qs(query)
+ qs = urllib.parse.parse_qs(query)
qs[param_name] = [value]
query = urlparse.urlencode(qs)
else:
query = '%s=%s' % (param_name, value)
- return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
+ return urllib.parse.urlunparse((scheme, netloc, path, params, query, fragment))
def disco(request):
diff --git a/src/authentic2/exponential_retry_timeout.py b/src/authentic2/exponential_retry_timeout.py
index 42f9d7ecf..52597f6dd 100644
--- a/src/authentic2/exponential_retry_timeout.py
+++ b/src/authentic2/exponential_retry_timeout.py
@@ -19,7 +19,6 @@ import logging
import time
from django.core.cache import cache
-from django.utils import six
class ExponentialRetryTimeout(object):
@@ -45,7 +44,7 @@ class ExponentialRetryTimeout(object):
self.key_prefix = key_prefix
def key(self, keys):
- key = u'-'.join(six.text_type(key) for key in keys)
+ key = u'-'.join(str(key) for key in keys)
key = key.encode('utf-8')
return '%s%s' % (self.key_prefix or self.KEY_PREFIX, hashlib.md5(key).hexdigest())
diff --git a/src/authentic2/idp/saml/backend.py b/src/authentic2/idp/saml/backend.py
index 38b73be98..32427a0c3 100644
--- a/src/authentic2/idp/saml/backend.py
+++ b/src/authentic2/idp/saml/backend.py
@@ -14,15 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import functools
import logging
import operator
import random
+from urllib.parse import quote
from django.db.models import Q
from django.template.loader import render_to_string
from django.urls import reverse
-from django.utils import six
-from django.utils.six.moves.urllib.parse import quote
from django.utils.translation import ugettext as _
import authentic2.idp.saml.saml2_endpoints as saml2_endpoints
@@ -68,7 +68,7 @@ class SamlBackend(object):
queries.append(
q.filter(sp_options_policy__isnull=True, liberty_provider__entity_id__in=sessions_eids)
)
- qs = six.moves.reduce(operator.__or__, queries)
+ qs = functools.reduce(operator.__or__, queries)
# do some prefetching
qs = qs.prefetch_related('liberty_provider')
qs = qs.select_related('sp_options_policy')
diff --git a/src/authentic2/idp/saml/saml2_endpoints.py b/src/authentic2/idp/saml/saml2_endpoints.py
index 96f468fe8..e347e6fe3 100644
--- a/src/authentic2/idp/saml/saml2_endpoints.py
+++ b/src/authentic2/idp/saml/saml2_endpoints.py
@@ -41,6 +41,7 @@ import random
import string
import xml.etree.cElementTree as ctree
from functools import wraps
+from urllib.parse import quote, urlencode
from django.conf import settings
from django.contrib import messages
@@ -50,9 +51,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse
-from django.utils import six
from django.utils.encoding import force_bytes, force_str, force_text
-from django.utils.six.moves.urllib.parse import quote, urlencode
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_noop as N_
from django.views.decorators.cache import never_cache
@@ -821,7 +820,7 @@ def sso_after_process_request(
if not access_granted:
logger.debug('access denied, return answer to the requester')
set_saml2_response_responder_status_code(
- login.response, lasso.SAML2_STATUS_CODE_REQUEST_DENIED, msg=six.text_type(dic['message'])
+ login.response, lasso.SAML2_STATUS_CODE_REQUEST_DENIED, msg=str(dic['message'])
)
return finish_sso(request, login)
diff --git a/src/authentic2/log_filters.py b/src/authentic2/log_filters.py
index 9e38966ae..4915459eb 100644
--- a/src/authentic2/log_filters.py
+++ b/src/authentic2/log_filters.py
@@ -16,8 +16,6 @@
import logging
-from django.utils import six
-
class RequestContextFilter(logging.Filter):
DEFAULT_USERNAME = '-'
@@ -45,7 +43,7 @@ class RequestContextFilter(logging.Filter):
if not hasattr(record, 'user'):
if hasattr(request, 'user') and request.user.is_authenticated:
- record.user = six.text_type(request.user)
+ record.user = str(request.user)
else:
record.user = self.DEFAULT_USERNAME
diff --git a/src/authentic2/management/commands/check-and-repair.py b/src/authentic2/management/commands/check-and-repair.py
index 2e17b7caf..ebe2c1e69 100644
--- a/src/authentic2/management/commands/check-and-repair.py
+++ b/src/authentic2/management/commands/check-and-repair.py
@@ -27,7 +27,6 @@ from django.db import connection
from django.db.models import Count, Q
from django.db.models.functions import Lower
from django.db.transaction import atomic
-from django.utils.six.moves import input
from django.utils.timezone import localtime
from authentic2 import app_settings
diff --git a/src/authentic2/management/commands/clean-unused-accounts.py b/src/authentic2/management/commands/clean-unused-accounts.py
index 46a4f00e0..324f1d2ea 100644
--- a/src/authentic2/management/commands/clean-unused-accounts.py
+++ b/src/authentic2/management/commands/clean-unused-accounts.py
@@ -17,6 +17,7 @@
from __future__ import print_function
import logging
+import urllib.parse
from datetime import timedelta
from django.conf import settings
@@ -25,7 +26,6 @@ from django.core.management.base import BaseCommand
from django.db import transaction
from django.db.models import F
from django.utils import timezone, translation
-from django.utils.six.moves.urllib import parse as urlparse
from authentic2.backends.ldap_backend import LDAPBackend
from authentic2.utils import send_templated_mail
@@ -110,7 +110,7 @@ class Command(BaseCommand):
ctx = {
'user': user,
'days_to_deletion': days_to_deletion,
- 'login_url': urlparse.urljoin(settings.SITE_BASE_URL, settings.LOGIN_URL),
+ 'login_url': urllib.parse.urljoin(settings.SITE_BASE_URL, settings.LOGIN_URL),
}
with transaction.atomic():
if not self.fake:
diff --git a/src/authentic2/management/commands/slapd-shell.py b/src/authentic2/management/commands/slapd-shell.py
index 7beaffa9a..a35870f26 100644
--- a/src/authentic2/management/commands/slapd-shell.py
+++ b/src/authentic2/management/commands/slapd-shell.py
@@ -16,13 +16,13 @@
from __future__ import print_function
+import io
import logging
import re
import sys
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
-from django.utils import six
from ldap.dn import escape_dn_chars
from ldif import LDIFWriter
@@ -48,7 +48,7 @@ class Command(BaseCommand):
def ldap(self, command, attrs):
self.logger.debug('received command %s %s', command, attrs)
if command == 'SEARCH':
- out = six.BytesIO()
+ out = io.BytesIO()
ldif_writer = LDIFWriter(out)
qs = get_user_model().objects.all()
if attrs['filter'] != '(objectClass=*)':
@@ -85,7 +85,7 @@ class Command(BaseCommand):
for user in qs:
o = {}
for user_attribute, ldap_attribute in MAPPING.items():
- o[ldap_attribute] = [six.text_type(getattr(user, user_attribute)).encode('utf-8')]
+ o[ldap_attribute] = [str(getattr(user, user_attribute)).encode('utf-8')]
o['objectClass'] = ['inetOrgPerson']
dn = 'uid=%s,%s' % (escape_dn_chars(o['uid'][0]), attrs['suffix'])
self.logger.debug(u'sending entry %s %s', dn, o)
diff --git a/src/authentic2/manager/forms.py b/src/authentic2/manager/forms.py
index 0f3220a20..e1a87c4c7 100644
--- a/src/authentic2/manager/forms.py
+++ b/src/authentic2/manager/forms.py
@@ -23,7 +23,6 @@ from django import forms
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
-from django.utils import six
from django.utils.text import slugify
from django.utils.translation import pgettext, ugettext
from django.utils.translation import ugettext_lazy as _
@@ -67,7 +66,7 @@ class SlugMixin(forms.ModelForm):
def save(self, commit=True):
instance = self.instance
if not instance.slug:
- instance.slug = slugify(six.text_type(instance.name)).lstrip('_')
+ instance.slug = slugify(str(instance.name)).lstrip('_')
qs = instance.__class__.objects.all()
if instance.pk:
qs = qs.exclude(pk=instance.pk)
@@ -441,7 +440,7 @@ class OUSearchForm(FormWithRequest):
if self.show_all_ou and (len(self.ou_qs) > 1 or self.search_all_ous):
choices.append(('all', all_ou_label))
for ou in self.ou_qs:
- choices.append((str(ou.pk), six.text_type(ou)))
+ choices.append((str(ou.pk), str(ou)))
if self.show_none_ou and self.search_all_ous:
choices.append(('none', pgettext('organizational unit', 'None')))
@@ -703,7 +702,7 @@ class UserImportForm(forms.Form):
@staticmethod
def raise_validation_error(error_message):
message_prefix = ugettext('Invalid import file')
- raise forms.ValidationError('%s : %s' % (message_prefix, six.text_type(error_message)))
+ raise forms.ValidationError('%s : %s' % (message_prefix, str(error_message)))
class UserNewImportForm(UserImportForm):
diff --git a/src/authentic2/manager/ou_views.py b/src/authentic2/manager/ou_views.py
index 4886349a7..8c0ac3b34 100644
--- a/src/authentic2/manager/ou_views.py
+++ b/src/authentic2/manager/ou_views.py
@@ -21,7 +21,6 @@ from django.core.exceptions import PermissionDenied, ValidationError
from django.db import transaction
from django.http import HttpResponseRedirect
from django.urls import reverse
-from django.utils import six
from django.utils.translation import ugettext as _
from django.views.generic import FormView
@@ -68,7 +67,7 @@ class OrganizationalUnitDetailView(views.BaseDetailView):
@property
def title(self):
- return six.text_type(self.object)
+ return str(self.object)
def authorize(self, request, *args, **kwargs):
super(OrganizationalUnitDetailView, self).authorize(request, *args, **kwargs)
diff --git a/src/authentic2/manager/resources.py b/src/authentic2/manager/resources.py
index 2cb01adc8..ac69fbbeb 100644
--- a/src/authentic2/manager/resources.py
+++ b/src/authentic2/manager/resources.py
@@ -15,7 +15,6 @@
# along with this program. If not, see .
from django.contrib.auth import get_user_model
-from django.utils import six
from import_export.fields import Field
from import_export.resources import ModelResource
from import_export.widgets import Widget
@@ -30,7 +29,7 @@ class ListWidget(Widget):
raise NotImplementedError
def render(self, value, object):
- return u', '.join(six.text_type(v) for v in value.all())
+ return u', '.join(str(v) for v in value.all())
class UserResource(ModelResource):
@@ -42,7 +41,7 @@ class UserResource(ModelResource):
result.add(role)
for pr in role.parent_relation.all():
result.add(pr.parent)
- return ', '.join(six.text_type(x) for x in result)
+ return ', '.join(str(x) for x in result)
class Meta:
model = User
diff --git a/src/authentic2/manager/service_views.py b/src/authentic2/manager/service_views.py
index 1556d5bb5..ff0e3f47f 100644
--- a/src/authentic2/manager/service_views.py
+++ b/src/authentic2/manager/service_views.py
@@ -15,7 +15,6 @@
# along with this program. If not, see .
from django.contrib import messages
-from django.utils import six
from django.utils.translation import ugettext as _
from authentic2.models import Service
@@ -53,7 +52,7 @@ class ServiceView(
@property
def title(self):
- return six.text_type(self.object)
+ return str(self.object)
def get_table_queryset(self):
return self.object.authorized_roles.all()
diff --git a/src/authentic2/manager/user_import.py b/src/authentic2/manager/user_import.py
index 21ea4e6a5..a8d53636d 100644
--- a/src/authentic2/manager/user_import.py
+++ b/src/authentic2/manager/user_import.py
@@ -30,7 +30,6 @@ from atomicwrites import AtomicWriter
from django.conf import settings
from django.core.files.storage import default_storage
from django.db import connection
-from django.utils import six
from django.utils.functional import cached_property
from django.utils.timezone import utc
from django.utils.translation import ugettext_lazy as _
@@ -225,7 +224,7 @@ class Report(object):
logger.exception('error during report %s:%s run', self.user_import.uuid, self.uuid)
state = self.STATE_ERROR
try:
- exception = six.text_type(e)
+ exception = str(e)
except Exception:
exception = repr(repr(e))
else:
diff --git a/src/authentic2/manager/views.py b/src/authentic2/manager/views.py
index ccfb5d559..e1cb61ed5 100644
--- a/src/authentic2/manager/views.py
+++ b/src/authentic2/manager/views.py
@@ -26,7 +26,6 @@ from django.db import transaction
from django.forms import MediaDefiningClass
from django.http import Http404, HttpResponse
from django.urls import reverse, reverse_lazy
-from django.utils import six
from django.utils.encoding import force_text
from django.utils.functional import cached_property
from django.utils.timezone import now
@@ -62,8 +61,7 @@ class MultipleOUMixin(object):
return super(MultipleOUMixin, self).get_context_data(**kwargs)
-@six.add_metaclass(MediaMixinBase)
-class MediaMixin(object):
+class MediaMixin(object, metaclass=MediaMixinBase):
'''Expose needed CSS and JS files as a media object'''
class Media:
@@ -401,7 +399,7 @@ class ModelNameMixin(MediaMixin):
def get_instance_name(self):
if hasattr(self, 'get_object'):
- return six.text_type(self.get_object())
+ return str(self.get_object())
return u''
def get_context_data(self, **kwargs):
@@ -674,9 +672,9 @@ class MenuJson(HomepageView):
continue
menu_entries.append(
{
- 'label': six.text_type(entry['label']),
+ 'label': str(entry['label']),
'slug': entry.get('slug', ''),
- 'url': request.build_absolute_uri(six.text_type(entry['href'])),
+ 'url': request.build_absolute_uri(str(entry['href'])),
}
)
return menu_entries
diff --git a/src/authentic2/manager/widgets.py b/src/authentic2/manager/widgets.py
index e58d37b6e..1b29e3f49 100644
--- a/src/authentic2/manager/widgets.py
+++ b/src/authentic2/manager/widgets.py
@@ -15,12 +15,12 @@
# along with this program. If not, see .
import base64
+import functools
import operator
import pickle
from django.contrib.auth import get_user_model
from django.core import signing
-from django.utils import six
from django.utils.encoding import force_text
from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
@@ -43,7 +43,7 @@ class SplitTermMixin(object):
queries = []
for term in term.split():
queries.append(super(SplitTermMixin, self).filter_queryset(term, queryset=qs))
- qs = six.moves.reduce(self.split_term_operator, queries)
+ qs = functools.reduce(self.split_term_operator, queries)
return qs
@@ -101,7 +101,7 @@ class SearchRoleWidgetMixin(SplitTermMixin):
]
def label_from_instance(self, obj):
- label = six.text_type(obj)
+ label = str(obj)
if obj.ou and utils.get_ou_count() > 1:
label = u'{ou} - {obj}'.format(ou=obj.ou, obj=obj)
return label
diff --git a/src/authentic2/middleware.py b/src/authentic2/middleware.py
index 8912b5d1c..b03d8a2a6 100644
--- a/src/authentic2/middleware.py
+++ b/src/authentic2/middleware.py
@@ -21,12 +21,13 @@ try:
except ImportError:
threading = None
+import urllib.parse
+
from django import http
from django.conf import settings
from django.contrib import messages
from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext as _
from . import app_settings, plugins, utils
@@ -162,10 +163,10 @@ class DisplayMessageBeforeRedirectMiddleware(MiddlewareMixin):
return response
if not getattr(response, 'display_message', True):
return response
- parsed_url = urlparse.urlparse(url)
+ parsed_url = urllib.parse.urlparse(url)
if not parsed_url.scheme and not parsed_url.netloc:
return response
- parsed_request_url = urlparse.urlparse(request.build_absolute_uri())
+ parsed_request_url = urllib.parse.urlparse(request.build_absolute_uri())
if (parsed_request_url.scheme == parsed_url.scheme or not parsed_url.scheme) and (
parsed_request_url.netloc == parsed_url.netloc
):
diff --git a/src/authentic2/migrations/__init__.py b/src/authentic2/migrations/__init__.py
index 3bc8d854f..cada7b5e3 100644
--- a/src/authentic2/migrations/__init__.py
+++ b/src/authentic2/migrations/__init__.py
@@ -1,7 +1,6 @@
import itertools
from django.db.migrations.operations.base import Operation
-from django.utils import six
class CreatePartialIndexes(Operation):
@@ -64,10 +63,10 @@ class CreatePartialIndexes(Operation):
for clause in where:
if isinstance(clause, tuple):
clause, params = clause
- assert isinstance(clause, six.string_types)
+ assert isinstance(clause, str)
assert isinstance(params, tuple)
clause = clause % tuple(schema_editor.quote_value(param) for param in params)
- assert isinstance(clause, six.string_types)
+ assert isinstance(clause, str)
clauses.append(clause)
where_clause = ' AND '.join(clauses)
# SQLite does not accept parameters in partial index creations, don't ask why :/
diff --git a/src/authentic2/models.py b/src/authentic2/models.py
index dd0340fe9..21a41040c 100644
--- a/src/authentic2/models.py
+++ b/src/authentic2/models.py
@@ -16,6 +16,7 @@
import datetime
import time
+import urllib.parse
import uuid
import django
@@ -27,9 +28,8 @@ from django.contrib.postgres.search import SearchVectorField
from django.core.exceptions import ValidationError
from django.db import models, transaction
from django.db.models.query import Q
-from django.utils import six, timezone
+from django.utils import timezone
from django.utils.http import urlquote
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext_lazy as _
from model_utils.managers import QueryManager
@@ -117,7 +117,7 @@ class LogoutUrlAbstract(models.Model):
def get_logout_url(self, request):
ok_icon_url = (
- request.build_absolute_uri(urlparse.urljoin(settings.STATIC_URL, 'authentic2/images/ok.png'))
+ request.build_absolute_uri(urllib.parse.urljoin(settings.STATIC_URL, 'authentic2/images/ok.png'))
+ '?nonce=%s' % time.time()
)
return self.logout_url.format(urlquote(ok_icon_url))
@@ -363,7 +363,7 @@ class PasswordReset(models.Model):
verbose_name_plural = _('password reset')
def __str__(self):
- return six.text_type(self.user)
+ return str(self.user)
class Service(models.Model):
@@ -418,7 +418,7 @@ class Service(models.Model):
return self.name
def __repr__(self):
- return '<%s %r>' % (self.__class__.__name__, six.text_type(self))
+ return '<%s %r>' % (self.__class__.__name__, str(self))
def authorize(self, user):
if not self.authorized_roles.exists():
@@ -492,7 +492,7 @@ class Token(models.Model):
else:
return _uuid
- if isinstance(_uuid, six.text_type):
+ if isinstance(_uuid, str):
_uuid = _uuid.encode('ascii')
_uuid = base64url_decode(_uuid)
return uuid.UUID(bytes=_uuid)
diff --git a/src/authentic2/passwords.py b/src/authentic2/passwords.py
index 804131b6b..2857ace09 100644
--- a/src/authentic2/passwords.py
+++ b/src/authentic2/passwords.py
@@ -20,7 +20,6 @@ import re
import string
from django.core.exceptions import ValidationError
-from django.utils import six
from django.utils.functional import lazy
from django.utils.module_loading import import_string
from django.utils.translation import ugettext as _
@@ -50,8 +49,7 @@ def generate_password():
return ''.join(new_password)
-@six.add_metaclass(abc.ABCMeta)
-class PasswordChecker(object):
+class PasswordChecker(object, metaclass=abc.ABCMeta):
class Check(object):
def __init__(self, label, result):
self.label = label
@@ -134,4 +132,4 @@ def password_help_text(password='', only_errors=False):
return ''
-password_help_text = lazy(password_help_text, six.text_type)
+password_help_text = lazy(password_help_text, str)
diff --git a/src/authentic2/saml/admin.py b/src/authentic2/saml/admin.py
index fcbabc678..77fdba44e 100644
--- a/src/authentic2/saml/admin.py
+++ b/src/authentic2/saml/admin.py
@@ -22,7 +22,6 @@ from django.conf.urls import url
from django.contrib import admin, messages
from django.core.exceptions import ValidationError
from django.forms import ModelForm
-from django.utils import six
from django.utils.translation import ugettext as _
try:
@@ -72,7 +71,7 @@ class TextAndFileWidget(forms.widgets.MultiWidget):
def render(self, name, value, attrs=None, **kwargs):
if attrs is None:
attrs = {}
- if isinstance(value, (str, six.text_type)):
+ if isinstance(value, (str, str)):
attrs['rows'] = value.count('\n') + 5
attrs['cols'] = min(max((len(x) for x in value.split('\n'))), 150)
return super(TextAndFileWidget, self).render(name, value, attrs, **kwargs)
diff --git a/src/authentic2/saml/common.py b/src/authentic2/saml/common.py
index 133b1f48e..d8d33aef4 100644
--- a/src/authentic2/saml/common.py
+++ b/src/authentic2/saml/common.py
@@ -15,6 +15,7 @@
# along with this program. If not, see .
import datetime
+import functools
import logging
import os.path
import re
@@ -25,7 +26,6 @@ from django.core.exceptions import ValidationError
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
-from django.utils import six
from django.utils.encoding import force_text
from authentic2.compat_lasso import lasso
@@ -337,7 +337,7 @@ def retrieve_metadata_and_create(request, provider_id, sp_or_idp):
return None
logger.debug('loaded %d bytes', len(metadata))
try:
- metadata = six.text_type(metadata, 'utf-8')
+ metadata = str(metadata, 'utf-8')
except UnicodeDecodeError:
logging.error('SAML metadata autoload: retrieved metadata for entity id %s is not UTF-8', provider_id)
return None
@@ -586,5 +586,5 @@ def get_session_not_on_or_after(assertion):
value,
)
if session_not_on_or_afters:
- return six.moves.reduce(min, session_not_on_or_afters)
+ return functools.reduce(min, session_not_on_or_afters)
return None
diff --git a/src/authentic2/saml/fields.py b/src/authentic2/saml/fields.py
index 5897a8732..562438304 100644
--- a/src/authentic2/saml/fields.py
+++ b/src/authentic2/saml/fields.py
@@ -27,7 +27,6 @@ from django.contrib.humanize.templatetags.humanize import apnumber
from django.core.exceptions import ValidationError
from django.db import models
from django.template.defaultfilters import pluralize
-from django.utils import six
from django.utils.encoding import force_bytes, force_text
from django.utils.text import capfirst
@@ -56,7 +55,7 @@ def dumps(value):
# Initial author: Oliver Beattie
-class PickledObject(six.text_type):
+class PickledObject(str):
"""A subclass of string so it can be told whether a string is
a pickled object or not (if the object is an instance of this class
then it must [well, should] be a pickled one)."""
@@ -161,7 +160,7 @@ class MultiSelectField(models.Field):
return MultiSelectFormField(**defaults)
def get_db_prep_value(self, value, connection, prepared=False):
- if isinstance(value, six.string_types):
+ if isinstance(value, str):
return value
elif isinstance(value, list):
return ",".join(value)
diff --git a/src/authentic2/saml/management/commands/sync-metadata.py b/src/authentic2/saml/management/commands/sync-metadata.py
index 000c821e2..5b969ae63 100644
--- a/src/authentic2/saml/management/commands/sync-metadata.py
+++ b/src/authentic2/saml/management/commands/sync-metadata.py
@@ -16,6 +16,7 @@
from __future__ import print_function
+import io
import os
import sys
import warnings
@@ -26,7 +27,6 @@ from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand, CommandError
from django.db.transaction import atomic
from django.template.defaultfilters import slugify
-from django.utils import six
from django.utils.translation import gettext as _
from authentic2.compat_lasso import lasso
@@ -340,11 +340,11 @@ Any other kind of attribute filter policy is unsupported.
response = requests.get(metadata_file_path)
if not response.ok:
raise CommandError('Unable to open url %s' % metadata_file_path)
- metadata_file = six.BytesIO(response.content)
+ metadata_file = io.BytesIO(response.content)
else:
try:
with open(metadata_file_path, 'rb') as fd:
- metadata_file = six.BytesIO(fd.read())
+ metadata_file = io.BytesIO(fd.read())
except IOError:
raise CommandError('Unable to open file %s' % metadata_file_path)
diff --git a/src/authentic2/saml/models.py b/src/authentic2/saml/models.py
index 1b9931c51..49bf41564 100644
--- a/src/authentic2/saml/models.py
+++ b/src/authentic2/saml/models.py
@@ -25,7 +25,6 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.db.models import Q
from django.db.models.query import QuerySet
-from django.utils import six
from django.utils.encoding import force_str, force_text
from django.utils.translation import ugettext_lazy as _
@@ -484,7 +483,7 @@ class LibertyServiceProvider(models.Model):
return (self.liberty_provider.slug,)
def __str__(self):
- return six.text_type(self.liberty_provider)
+ return str(self.liberty_provider)
class Meta:
verbose_name = _('SAML service provider')
diff --git a/src/authentic2/saml/saml2utils.py b/src/authentic2/saml/saml2utils.py
index 580832304..e147627fa 100644
--- a/src/authentic2/saml/saml2utils.py
+++ b/src/authentic2/saml/saml2utils.py
@@ -22,7 +22,6 @@ import re
import time
import xml.etree.ElementTree as etree
-from django.utils import six
from django.utils.encoding import force_text
from authentic2.compat_lasso import lasso
@@ -30,14 +29,14 @@ from authentic2.saml import x509utils
def filter_attribute_private_key(message):
- if isinstance(message, six.string_types):
+ if isinstance(message, str):
return re.sub(r' (\w+:)?(PrivateKey=")([\w/ +-=])+(")', '', message)
else:
return message
def filter_element_private_key(message):
- if isinstance(message, six.string_types):
+ if isinstance(message, str):
return re.sub(
r'(-----BEGIN RSA PRIVATE KEY-----)'
r'([\w/+=\s])+'
diff --git a/src/authentic2/saml/x509utils.py b/src/authentic2/saml/x509utils.py
index a1caddaed..8243c89f2 100644
--- a/src/authentic2/saml/x509utils.py
+++ b/src/authentic2/saml/x509utils.py
@@ -19,14 +19,12 @@ import os
import subprocess
import tempfile
-import six
-
_openssl = 'openssl'
def decapsulate_pem_file(file_or_string):
'''Remove PEM header lines'''
- if not isinstance(file_or_string, six.string_types):
+ if not isinstance(file_or_string, str):
content = file_or_string.read()
else:
content = file_or_string
diff --git a/src/authentic2/serializers.py b/src/authentic2/serializers.py
index dd376242c..2804bd4a4 100644
--- a/src/authentic2/serializers.py
+++ b/src/authentic2/serializers.py
@@ -23,7 +23,6 @@ from django.core.serializers.base import DeserializationError
from django.core.serializers.json import Serializer as JSONSerializer
from django.core.serializers.python import _get_model
from django.db import DEFAULT_DB_ALIAS
-from django.utils import six
class Serializer(JSONSerializer):
@@ -73,7 +72,7 @@ def Deserializer(stream_or_string, **options):
"""
from django.core.serializers.python import Deserializer as PythonDeserializer
- if not isinstance(stream_or_string, (bytes, six.string_types)):
+ if not isinstance(stream_or_string, (bytes, str)):
stream_or_string = stream_or_string.read()
if isinstance(stream_or_string, bytes):
stream_or_string = stream_or_string.decode('utf-8')
@@ -85,5 +84,4 @@ def Deserializer(stream_or_string, **options):
except GeneratorExit:
raise
except Exception as e:
- # Map to deserializer error
- six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
+ raise DeserializationError(e)
diff --git a/src/authentic2/utils/__init__.py b/src/authentic2/utils/__init__.py
index e92d7bdbc..660bf7d49 100644
--- a/src/authentic2/utils/__init__.py
+++ b/src/authentic2/utils/__init__.py
@@ -19,6 +19,7 @@ import ctypes
import logging
import random
import time
+import urllib.parse
import uuid
from functools import wraps
from importlib import import_module
@@ -40,10 +41,9 @@ from django.shortcuts import render, resolve_url
from django.template.context import make_context
from django.template.loader import TemplateDoesNotExist, render_to_string, select_template
from django.urls import reverse
-from django.utils import html, six, timezone
+from django.utils import html, timezone
from django.utils.encoding import iri_to_uri, uri_to_iri
from django.utils.formats import localize
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ungettext
try:
@@ -171,7 +171,7 @@ def get_backends(setting_name='IDP_BACKENDS'):
backends = []
for backend_path in getattr(app_settings, setting_name):
kwargs = {}
- if not isinstance(backend_path, six.string_types):
+ if not isinstance(backend_path, str):
backend_path, kwargs = backend_path
kwargs_settings = getattr(app_settings, setting_name + '_KWARGS', {})
backend = load_backend(backend_path, kwargs_settings)
@@ -232,9 +232,9 @@ def get_authenticator_method(authenticator, method, parameters):
def add_arg(url, key, value=None):
'''Add a parameter to an URL'''
- key = urlparse.quote(key)
+ key = urllib.parse.quote(key)
if value is not None:
- add = '%s=%s' % (key, urlparse.quote(value))
+ add = '%s=%s' % (key, urllib.parse.quote(value))
else:
add = key
if '?' in url:
@@ -262,7 +262,7 @@ class Service(object):
def field_names(list_of_field_name_and_titles):
for t in list_of_field_name_and_titles:
- if isinstance(t, six.string_types):
+ if isinstance(t, str):
yield t
else:
yield t[0]
@@ -270,7 +270,7 @@ def field_names(list_of_field_name_and_titles):
def is_valid_url(url):
try:
- parsed = urlparse.urlparse(url)
+ parsed = urllib.parse.urlparse(url)
if parsed.scheme in ('http', 'https', ''):
return True
except Exception:
@@ -307,8 +307,8 @@ def make_url(
else:
url = to
url = iri_to_uri(url)
- scheme, netloc, path, query_string, o_fragment = urlparse.urlsplit(url)
- url = uri_to_iri(urlparse.urlunsplit((scheme, netloc, path, '', '')))
+ scheme, netloc, path, query_string, o_fragment = urllib.parse.urlsplit(url)
+ url = uri_to_iri(urllib.parse.urlunsplit((scheme, netloc, path, '', '')))
fragment = fragment or o_fragment
# Django < 1.6 compat, query_string is not optional
url_params = QueryDict(query_string=query_string, mutable=True)
@@ -348,7 +348,7 @@ def make_url(
if request:
url = request.build_absolute_uri(url)
elif hasattr(settings, 'SITE_BASE_URL'):
- url = urlparse.urljoin(settings.SITE_BASE_URL, url)
+ url = urllib.parse.urljoin(settings.SITE_BASE_URL, url)
else:
raise TypeError('make_url() absolute cannot be used without request')
# keep using unicode
@@ -426,13 +426,13 @@ def record_authentication_event(request, how, nonce=None):
# explicitly state that the session has been modified
request.session.modified = True
event = {
- 'who': six.text_type(request.user),
+ 'who': str(request.user),
'who_id': getattr(request.user, 'pk', None),
'how': how,
'when': int(time.time()),
}
kwargs = {
- 'who': six.text_type(request.user)[:80],
+ 'who': str(request.user)[:80],
'how': how,
}
nonce = nonce or get_nonce(request)
@@ -621,12 +621,12 @@ def to_iter(func):
def normalize_attribute_values(values):
'''Take a list of values or a single one and normalize it'''
values_set = set()
- if isinstance(values, six.string_types) or not hasattr(values, '__iter__'):
+ if isinstance(values, str) or not hasattr(values, '__iter__'):
values = [values]
for value in values:
if isinstance(value, bool):
value = str(value).lower()
- values_set.add(six.text_type(value))
+ values_set.add(str(value))
return values_set
@@ -682,7 +682,7 @@ def send_templated_mail(
"""
from .. import middleware
- if isinstance(template_names, six.string_types):
+ if isinstance(template_names, str):
template_names = [template_names]
if per_ou_templates and getattr(user_or_email, 'ou', None):
new_template_names = []
@@ -1055,7 +1055,7 @@ def select_next_url(request, default, field_name=None, include_post=False, repla
if good_next_url(request, next_url):
if replace:
for key, value in replace.items():
- next_url = next_url.replace(key, urlparse.quote(value))
+ next_url = next_url.replace(key, urllib.parse.quote(value))
return next_url
return default
@@ -1127,7 +1127,7 @@ def same_origin(url1, url2):
If not scheme and not port are given, port compare is skipped.
The last two rules allow authorizing complete domains easily.
"""
- p1, p2 = urlparse.urlparse(url1), urlparse.urlparse(url2)
+ p1, p2 = urllib.parse.urlparse(url1), urllib.parse.urlparse(url2)
p1_host, p1_port = netloc_to_host_port(p1.netloc)
p2_host, p2_port = netloc_to_host_port(p2.netloc)
diff --git a/src/authentic2/utils/evaluate.py b/src/authentic2/utils/evaluate.py
index 7abe7a4ef..19957529e 100644
--- a/src/authentic2/utils/evaluate.py
+++ b/src/authentic2/utils/evaluate.py
@@ -25,7 +25,6 @@ except ImportError:
import ast
-from django.utils import six
from django.utils.translation import ugettext as _
@@ -110,7 +109,7 @@ class BaseExpressionValidator(ast.NodeVisitor):
# set the nearer expr node as the node of the error
if e.node is None and hasattr(node, 'col_offset'):
e.set_node(node)
- six.reraise(*sys.exc_info())
+ raise e
@lru_cache(maxsize=1024)
def __call__(self, expression):
@@ -126,7 +125,7 @@ class BaseExpressionValidator(ast.NodeVisitor):
if e.text is None:
e.text = expression
e.params = {'expression': expression}
- six.reraise(*sys.exc_info())
+ raise e
return compile(tree, expression, mode='eval')
@@ -179,8 +178,7 @@ class ConditionValidator(BaseExpressionValidator):
super(ConditionValidator, self).__init__(
authorized_nodes=authorized_nodes, forbidden_nodes=forbidden_nodes
)
- if six.PY3:
- self.authorized_nodes.append(ast.NameConstant)
+ self.authorized_nodes.append(ast.NameConstant)
def check_Name(self, node):
if node.id.startswith('_'):
@@ -225,7 +223,7 @@ def evaluate_condition(expression, ctx=None, validator=None, on_raise=None):
raise ExpressionError(
_('variable is not defined: %s') % e, code='undefined-variable', text=expression, column=0
)
- except Exception:
+ except Exception as e:
if on_raise is not None:
return on_raise
- six.reraise(*sys.exc_info())
+ raise e
diff --git a/src/authentic2/utils/lazy.py b/src/authentic2/utils/lazy.py
index f57819c98..637280c83 100644
--- a/src/authentic2/utils/lazy.py
+++ b/src/authentic2/utils/lazy.py
@@ -16,7 +16,6 @@
from __future__ import unicode_literals
-from django.utils import six
from django.utils.encoding import force_text
from django.utils.functional import keep_lazy
from django.utils.text import format_lazy
@@ -30,7 +29,7 @@ def lazy_join(join, args):
return format_lazy(fstring, *args)
-@keep_lazy(six.text_type)
+@keep_lazy(str)
def lazy_label(default, func):
"""Allow using a getter for a label, with late binding.
diff --git a/src/authentic2/views.py b/src/authentic2/views.py
index 43cebd19c..34df2d5ec 100644
--- a/src/authentic2/views.py
+++ b/src/authentic2/views.py
@@ -42,7 +42,7 @@ from django.shortcuts import get_object_or_404, render
from django.template import loader
from django.template.loader import render_to_string
from django.urls import reverse
-from django.utils import six, timezone
+from django.utils import timezone
from django.utils.translation import ugettext as _
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
@@ -452,7 +452,7 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
value = filter(None, value)
value = [html_value(attribute, at_value) for at_value in value]
if not title:
- title = six.text_type(attribute)
+ title = str(attribute)
else:
# fallback to model attributes
try:
@@ -471,7 +471,7 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
if not isinstance(value, (list, tuple)):
value = (value,)
raw_value = value
- value = [six.text_type(v) for v in value]
+ value = [str(v) for v in value]
if value or app_settings.A2_PROFILE_DISPLAY_EMPTY_FIELDS:
profile.append((title, value))
attributes.append({'attribute': attribute, 'values': raw_value})
diff --git a/src/authentic2_auth_fc/models.py b/src/authentic2_auth_fc/models.py
index 9aecded45..3516ee10c 100644
--- a/src/authentic2_auth_fc/models.py
+++ b/src/authentic2_auth_fc/models.py
@@ -18,11 +18,11 @@ import base64
import hashlib
import hmac
import json
+import urllib.parse
from django.conf import settings
from django.db import models
from django.utils.encoding import force_bytes, force_text
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
@@ -66,11 +66,11 @@ def parse_id_token(id_token, client_id=None, client_secret=None):
return None, 'id_token is expired'
def check_issuer():
- parsed = urlparse.urlparse(app_settings.authorize_url)
+ parsed = urllib.parse.urlparse(app_settings.authorize_url)
if 'iss' not in payload:
return False
try:
- parsed_issuer = urlparse.urlparse(payload['iss'])
+ parsed_issuer = urllib.parse.urlparse(payload['iss'])
except Exception:
return False
return parsed_issuer.scheme == parsed.scheme and parsed_issuer.netloc == parsed.netloc
diff --git a/src/authentic2_auth_fc/views.py b/src/authentic2_auth_fc/views.py
index 217501a8c..7b5b1182e 100644
--- a/src/authentic2_auth_fc/views.py
+++ b/src/authentic2_auth_fc/views.py
@@ -16,6 +16,7 @@
import json
import logging
+import urllib.parse
import uuid
import requests
@@ -31,7 +32,6 @@ from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render, resolve_url
from django.urls import reverse
from django.utils.http import is_safe_url, urlencode
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext as _
from django.views.generic import FormView, View
from requests_oauthlib import OAuth2Session
@@ -509,9 +509,9 @@ class RegistrationView(PopupViewMixin, LoggerMixin, View):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Prevent errors when redirect_to does not contain fc-login-or-link view
- parsed_redirect_to = urlparse.urlparse(redirect_to)
+ parsed_redirect_to = urllib.parse.urlparse(redirect_to)
if parsed_redirect_to.path == reverse('fc-login-or-link'):
- redirect_to = urlparse.parse_qs(parsed_redirect_to.query).get(
+ redirect_to = urllib.parse.parse_qs(parsed_redirect_to.query).get(
REDIRECT_FIELD_NAME, [a2_utils.make_url('auth_homepage')]
)[0]
params = {
diff --git a/src/authentic2_auth_oidc/backends.py b/src/authentic2_auth_oidc/backends.py
index b346b6fec..d6ca20900 100644
--- a/src/authentic2_auth_oidc/backends.py
+++ b/src/authentic2_auth_oidc/backends.py
@@ -20,7 +20,6 @@ import logging
import requests
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
-from django.utils import six
from django.utils.timezone import now
from jwcrypto.jwk import JWK
from jwcrypto.jwt import JWT
@@ -88,7 +87,7 @@ class OIDCBackend(ModelBackend):
jwt = JWT(jwt=original_id_token, key=key_or_keyset, check_claims={}, algs=algs)
jwt.claims
- if isinstance(id_token.aud, six.text_type) and provider.client_id != id_token.aud:
+ if isinstance(id_token.aud, str) and provider.client_id != id_token.aud:
logger.warning(
'auth_oidc: invalid id_token audience %s != provider client_id %s',
id_token.aud,
diff --git a/src/authentic2_auth_oidc/utils.py b/src/authentic2_auth_oidc/utils.py
index 1feb8c76f..61dbd909b 100644
--- a/src/authentic2_auth_oidc/utils.py
+++ b/src/authentic2_auth_oidc/utils.py
@@ -15,11 +15,10 @@
# along with this program. If not, see .
import datetime
+import urllib.parse
import requests
from django.shortcuts import get_object_or_404
-from django.utils import six
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import utc
from django.utils.translation import ugettext as _
from jwcrypto.common import JWException, base64url_encode, json_decode
@@ -93,14 +92,14 @@ def parse_id_token(encoded, provider):
REQUIRED_ID_TOKEN_KEYS = set(['iss', 'sub', 'aud', 'exp', 'iat'])
KEY_TYPES = {
- 'iss': six.text_type,
- 'sub': six.text_type,
+ 'iss': str,
+ 'sub': str,
'exp': int,
'iat': int,
'auth_time': int,
- 'nonce': six.text_type,
- 'acr': six.text_type,
- 'azp': six.text_type,
+ 'nonce': str,
+ 'acr': str,
+ 'azp': str,
# aud and amr havec specific checks
}
@@ -120,7 +119,7 @@ class IDToken(object):
nonce = None
def __init__(self, encoded):
- if not isinstance(encoded, (six.binary_type, six.string_types)):
+ if not isinstance(encoded, (bytes, str)):
raise IDTokenError(_('Encoded ID Token must be either binary or string data'))
self._encoded = encoded
@@ -139,7 +138,7 @@ class IDToken(object):
if key == 'amr':
if not isinstance(decoded['amr'], list):
raise IDTokenError(_('invalid amr value: %s') % decoded['amr'])
- if not all(isinstance(v, six.text_type) for v in decoded['amr']):
+ if not all(isinstance(v, str) for v in decoded['amr']):
raise IDTokenError(_('invalid amr value: %s') % decoded['amr'])
elif key in KEY_TYPES:
if not isinstance(decoded[key], KEY_TYPES[key]):
@@ -197,7 +196,7 @@ OPENID_CONFIGURATION_REQUIRED = set(
def check_https(url):
- return urlparse.urlparse(url).scheme == 'https'
+ return urllib.parse.urlparse(url).scheme == 'https'
def register_issuer(name, issuer=None, openid_configuration=None, verify=True, timeout=None, ou=None):
@@ -293,10 +292,12 @@ def register_issuer(name, issuer=None, openid_configuration=None, verify=True, t
def get_openid_configuration_url(issuer):
- parsed = urlparse.urlparse(issuer)
+ parsed = urllib.parse.urlparse(issuer)
if parsed.query or parsed.fragment or parsed.scheme != 'https':
raise ValueError(
_('invalid issuer URL, it must use the https:// scheme and not have a ' 'query or fragment')
)
- issuer = urlparse.urlunparse((parsed.scheme, parsed.netloc, parsed.path.rstrip('/'), None, None, None))
+ issuer = urllib.parse.urlunparse(
+ (parsed.scheme, parsed.netloc, parsed.path.rstrip('/'), None, None, None)
+ )
return issuer + '/.well-known/openid-configuration'
diff --git a/src/authentic2_auth_saml/adapters.py b/src/authentic2_auth_saml/adapters.py
index ebf934f34..86c815167 100644
--- a/src/authentic2_auth_saml/adapters.py
+++ b/src/authentic2_auth_saml/adapters.py
@@ -21,7 +21,6 @@ import logging
from django.contrib import messages
from django.core.exceptions import MultipleObjectsReturned
from django.db.transaction import atomic
-from django.utils import six
from django.utils.translation import ugettext as _
from mellon.adapters import DefaultAdapter, UserCreationError
from mellon.utils import get_setting
@@ -44,7 +43,7 @@ class MappingError(Exception):
super(MappingError, self).__init__(message)
def __str__(self):
- s = six.text_type(self.args[0])
+ s = str(self.args[0])
if self.details:
s += ' ' + repr(self.details)
return s
@@ -127,7 +126,7 @@ class AuthenticAdapter(DefaultAdapter):
action = mapping.get('action', 'set-attribute')
mandatory = mapping.get('mandatory', False) is True
method = None
- if isinstance(action, six.string_types):
+ if isinstance(action, str):
try:
method = getattr(self, 'action_' + action.replace('-', '_'))
except AttributeError:
@@ -149,21 +148,21 @@ class AuthenticAdapter(DefaultAdapter):
def action_rename(self, user, idp, saml_attributes, mapping):
from_name = mapping.get('from')
- if not from_name or not isinstance(from_name, six.string_types):
+ if not from_name or not isinstance(from_name, str):
raise MappingError('missing from in rename')
to_name = mapping.get('to')
- if not to_name or not isinstance(to_name, six.string_types):
+ if not to_name or not isinstance(to_name, str):
raise MappingError('missing to in rename')
if from_name in saml_attributes:
saml_attributes[to_name] = saml_attributes[from_name]
def action_set_attribute(self, user, idp, saml_attributes, mapping):
attribute = mapping.get('attribute')
- if not attribute or not isinstance(attribute, six.string_types):
+ if not attribute or not isinstance(attribute, str):
raise MappingError('missing attribute key')
saml_attribute = mapping.get('saml_attribute')
- if not saml_attribute or not isinstance(saml_attribute, six.string_types):
+ if not saml_attribute or not isinstance(saml_attribute, str):
raise MappingError('missing saml_attribute key')
if saml_attribute not in saml_attributes:
@@ -199,14 +198,14 @@ class AuthenticAdapter(DefaultAdapter):
slug = ou_desc.get('slug')
name = ou_desc.get('name')
if slug:
- if not isinstance(slug, six.string_types):
+ if not isinstance(slug, str):
raise MappingError('invalid ou.slug in ou description')
try:
return OU.objects.get(slug=slug)
except OU.DoesNotExist:
raise MappingError('unknown ou', details={'slug': slug})
elif name:
- if not isinstance(name, six.string_types):
+ if not isinstance(name, str):
raise MappingError('invalid ou.slug in ou description')
try:
return OU.objects.get(name=name)
@@ -228,11 +227,11 @@ class AuthenticAdapter(DefaultAdapter):
kwargs['ou'] = ou
if slug:
- if not isinstance(slug, six.string_types):
+ if not isinstance(slug, str):
raise MappingError('invalid role slug', details={'slug': slug})
kwargs['slug'] = slug
elif name:
- if not isinstance(name, six.string_types):
+ if not isinstance(name, str):
raise MappingError('invalid role name', details={'name': name})
kwargs['name'] = name
else:
@@ -249,7 +248,7 @@ class AuthenticAdapter(DefaultAdapter):
condition = mapping.get('condition')
if condition is None:
return True
- if not isinstance(condition, six.string_types):
+ if not isinstance(condition, str):
raise MappingError('invalid condition')
try:
# use a proxy to simplify condition expressions as subscript is forbidden
@@ -258,7 +257,7 @@ class AuthenticAdapter(DefaultAdapter):
logger.debug('auth_saml: condition %r is %s', condition, value, extra={'user': user})
return value
except Exception as e:
- raise MappingError('condition evaluation failed', details={'error': six.text_type(e)})
+ raise MappingError('condition evaluation failed', details={'error': str(e)})
def action_add_role(self, user, idp, saml_attributes, mapping):
role = self.get_role(mapping)
diff --git a/src/authentic2_idp_cas/managers.py b/src/authentic2_idp_cas/managers.py
index f40bf1d2b..587b2419d 100644
--- a/src/authentic2_idp_cas/managers.py
+++ b/src/authentic2_idp_cas/managers.py
@@ -14,11 +14,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import urllib.parse
from datetime import timedelta
from django.db import models
from django.db.models import query
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import now
@@ -37,7 +37,7 @@ class TicketQuerySet(query.QuerySet):
class ServiceQuerySet(query.QuerySet):
def for_service(self, service):
'''Find service with the longest match'''
- parsed = urlparse.urlparse(service)
+ parsed = urllib.parse.urlparse(service)
matches = []
for match in self.filter(urls__contains=parsed.netloc):
urls = match.get_urls()
diff --git a/src/authentic2_idp_cas/views.py b/src/authentic2_idp_cas/views.py
index 0c6216423..bd0f74836 100644
--- a/src/authentic2_idp_cas/views.py
+++ b/src/authentic2_idp_cas/views.py
@@ -21,7 +21,6 @@ from xml.etree import ElementTree as ET
import requests
from django.http import HttpResponse, HttpResponseBadRequest
-from django.utils import six
from django.utils.timezone import now
from django.views.generic.base import View
@@ -262,7 +261,7 @@ class ValidateBaseView(CasMixin, View):
if st.service.identifier_attribute not in attributes:
self.logger.error(
'unable to compute an identifier for user %r and service %s',
- six.text_type(st.user),
+ str(st.user),
st.service_url,
)
return self.validation_failure(request, service, INTERNAL_ERROR)
@@ -299,7 +298,7 @@ class ValidateBaseView(CasMixin, View):
'validation success service: %r ticket: %s user: %r identifier: %r',
st.service_url,
st.ticket_id,
- six.text_type(st.user),
+ str(st.user),
identifier,
)
return self.real_validation_success(request, st, identifier)
@@ -327,7 +326,7 @@ class ServiceValidateView(ValidateBaseView):
root = ET.Element(SERVICE_RESPONSE_ELT)
success = ET.SubElement(root, AUTHENTICATION_SUCCESS_ELT)
user = ET.SubElement(success, USER_ELT)
- user.text = six.text_type(identifier)
+ user.text = str(identifier)
self.provision_pgt(request, st, success)
self.provision_attributes(request, st, success)
return HttpResponse(ET.tostring(root, encoding='utf-8'), content_type='text/xml')
@@ -349,7 +348,7 @@ class ServiceValidateView(ValidateBaseView):
for key, values in values.items():
for value in values:
attribute_elt = ET.SubElement(attributes_elt, '{%s}%s' % (CAS_NAMESPACE, key))
- attribute_elt.text = six.text_type(value)
+ attribute_elt.text = str(value)
def provision_pgt(self, request, st, success):
"""Provision a PGT ticket if requested"""
diff --git a/src/authentic2_idp_oidc/models.py b/src/authentic2_idp_oidc/models.py
index aeb5a409d..60181ce9c 100644
--- a/src/authentic2_idp_oidc/models.py
+++ b/src/authentic2_idp_oidc/models.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import urllib.parse
import uuid
from importlib import import_module
@@ -22,8 +23,6 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.validators import URLValidator
from django.db import models
-from django.utils import six
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
@@ -34,7 +33,7 @@ from . import app_settings, managers, utils
def generate_uuid():
- return six.text_type(uuid.uuid4())
+ return str(uuid.uuid4())
def validate_https_url(data):
@@ -173,9 +172,9 @@ class OIDCClient(Service):
if len(redirect_uri) > app_settings.REDIRECT_URI_MAX_LENGTH:
raise ValueError('redirect_uri length > %s' % app_settings.REDIRECT_URI_MAX_LENGTH)
- parsed_uri = urlparse.urlparse(redirect_uri)
+ parsed_uri = urllib.parse.urlparse(redirect_uri)
for valid_redirect_uri in self.redirect_uris.split():
- parsed_valid_uri = urlparse.urlparse(valid_redirect_uri)
+ parsed_valid_uri = urllib.parse.urlparse(valid_redirect_uri)
if parsed_uri.scheme != parsed_valid_uri.scheme:
continue
if parsed_valid_uri.netloc.startswith('*'):
@@ -257,8 +256,8 @@ class OIDCAuthorization(models.Model):
def __repr__(self):
return '' % (
- self.client_id and six.text_type(self.client),
- self.user_id and six.text_type(self.user),
+ self.client_id and str(self.client),
+ self.user_id and str(self.user),
self.scopes,
)
@@ -324,8 +323,8 @@ class OIDCCode(SessionMixin, models.Model):
def __repr__(self):
return '' % (
self.uuid,
- self.client_id and six.text_type(self.client),
- self.user_id and six.text_type(self.user),
+ self.client_id and str(self.client),
+ self.user_id and str(self.user),
self.expired,
self.scopes,
)
@@ -362,8 +361,8 @@ class OIDCAccessToken(SessionMixin, models.Model):
def __repr__(self):
return '' % (
self.uuid,
- self.client_id and six.text_type(self.client),
- self.user_id and six.text_type(self.user),
+ self.client_id and str(self.client),
+ self.user_id and str(self.user),
self.expired,
self.scopes,
)
diff --git a/src/authentic2_idp_oidc/utils.py b/src/authentic2_idp_oidc/utils.py
index 1a00a4f87..6af8e530e 100644
--- a/src/authentic2_idp_oidc/utils.py
+++ b/src/authentic2_idp_oidc/utils.py
@@ -17,13 +17,12 @@
import base64
import hashlib
import json
+import urllib.parse
import uuid
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
-from django.utils import six
from django.utils.encoding import force_bytes, force_text
-from django.utils.six.moves.urllib import parse as urlparse
from jwcrypto.jwk import JWK, InvalidJWKValue, JWKSet
from jwcrypto.jwt import JWT
@@ -107,7 +106,7 @@ def clean_words(data):
def url_domain(url):
- return urlparse.urlparse(url).netloc.split(':')[0]
+ return urllib.parse.urlparse(url).netloc.split(':')[0]
def make_sub(client, user):
@@ -165,7 +164,7 @@ def reverse_pairwise_sub(client, sub):
def normalize_claim_values(values):
values_list = []
- if isinstance(values, six.string_types) or not hasattr(values, '__iter__'):
+ if isinstance(values, str) or not hasattr(values, '__iter__'):
return values
for value in values:
if isinstance(value, bool):
diff --git a/src/authentic2_idp_oidc/views.py b/src/authentic2_idp_oidc/views.py
index b4931c85f..2518daca3 100644
--- a/src/authentic2_idp_oidc/views.py
+++ b/src/authentic2_idp_oidc/views.py
@@ -36,7 +36,6 @@ from django.contrib.auth import authenticate
from django.http import HttpResponse, HttpResponseNotAllowed, JsonResponse
from django.shortcuts import render
from django.urls import reverse
-from django.utils import six
from django.utils.encoding import force_text
from django.utils.http import urlencode
from django.utils.timezone import now, utc
@@ -423,7 +422,7 @@ def authorize_for_client(request, client, redirect_uri):
'idp_oidc: sending code %s for scopes %s for service %s', code.uuid, ' '.join(scopes), client
)
params = {
- 'code': six.text_type(code.uuid),
+ 'code': str(code.uuid),
}
if state is not None:
params['state'] = state
@@ -664,7 +663,7 @@ def idtoken_from_user_credential(request):
)
return JsonResponse(
{
- 'access_token': six.text_type(access_token.uuid),
+ 'access_token': str(access_token.uuid),
'token_type': 'Bearer',
'expires_in': int(expires_in.total_seconds()),
'id_token': utils.make_idtoken(client, id_token),
@@ -726,7 +725,7 @@ def tokens_from_authz_code(request):
id_token['nonce'] = oidc_code.nonce
return JsonResponse(
{
- 'access_token': six.text_type(access_token.uuid),
+ 'access_token': str(access_token.uuid),
'token_type': 'Bearer',
'expires_in': int(expires_in.total_seconds()),
'id_token': utils.make_idtoken(client, id_token),
diff --git a/src/django_rbac/backends.py b/src/django_rbac/backends.py
index 703b6cc2c..297e0eb3a 100644
--- a/src/django_rbac/backends.py
+++ b/src/django_rbac/backends.py
@@ -1,9 +1,9 @@
import copy
+import functools
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models.query import Q
-from django.utils import six
try:
from django.core.exceptions import FieldDoesNotExist
@@ -145,7 +145,7 @@ class DjangoRBACBackend(object):
return False
if user_obj.is_superuser:
return True
- if isinstance(perm_or_perms, six.string_types):
+ if isinstance(perm_or_perms, str):
perm_or_perms = [perm_or_perms]
perm_or_perms = set(perm_or_perms)
cache = self.get_permission_cache(user_obj)
@@ -174,7 +174,7 @@ class DjangoRBACBackend(object):
return False
if user_obj.is_superuser:
return True
- if isinstance(perm_or_perms, six.string_types):
+ if isinstance(perm_or_perms, str):
perm_or_perms = [perm_or_perms]
perm_or_perms = set(perm_or_perms)
cache = self.get_permission_cache(user_obj)
@@ -197,7 +197,7 @@ class DjangoRBACBackend(object):
ct_id, fk = key.split('.')
q.append(Q(pk=int(fk)))
if q:
- return six.moves.reduce(Q.__or__, q)
+ return functools.reduce(Q.__or__, q)
return False
def filter_by_perm(self, user_obj, perm_or_perms, qs):
diff --git a/src/django_rbac/managers.py b/src/django_rbac/managers.py
index ce1fdc8de..8c232e2df 100644
--- a/src/django_rbac/managers.py
+++ b/src/django_rbac/managers.py
@@ -1,4 +1,5 @@
import contextlib
+import functools
import threading
from django.contrib.auth import get_user_model
@@ -6,7 +7,6 @@ from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.db.models import query
from django.db.models.query import Prefetch, Q
-from django.utils import six
from . import utils
@@ -210,7 +210,7 @@ class RoleParentingManager(models.Manager):
obsolete = old - add
if obsolete:
queries = (query.Q(parent_id=a, child_id=b, direct=False) for a, b in obsolete)
- self.model.objects.filter(six.moves.reduce(query.Q.__or__, queries)).delete()
+ self.model.objects.filter(functools.reduce(query.Q.__or__, queries)).delete()
@contextlib.contextmanager
diff --git a/src/django_rbac/models.py b/src/django_rbac/models.py
index fb1e86e90..68bb38afd 100644
--- a/src/django_rbac/models.py
+++ b/src/django_rbac/models.py
@@ -1,10 +1,10 @@
+import functools
import hashlib
import operator
from django.conf import settings
from django.db import models
from django.db.models.query import Prefetch, Q
-from django.utils import six
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
@@ -45,7 +45,7 @@ class AbstractBase(models.Model):
def save(self, *args, **kwargs):
# truncate slug and add a hash if it's too long
if not self.slug:
- self.slug = slugify(six.text_type(self.name)).lstrip('_')
+ self.slug = slugify(str(self.name)).lstrip('_')
if len(self.slug) > 256:
self.slug = self.slug[:252] + hashlib.md5(self.slug).hexdigest()[:4]
if not self.uuid:
@@ -373,7 +373,7 @@ class PermissionMixin(models.Model):
if hasattr(backend, "filter_by_perm"):
results.append(backend.filter_by_perm(self, perm_or_perms, qs))
if results:
- return six.moves.reduce(operator.__or__, results)
+ return functools.reduce(operator.__or__, results)
else:
return qs
diff --git a/tests/auth_fc/conftest.py b/tests/auth_fc/conftest.py
index 511d6e007..3676bdba4 100644
--- a/tests/auth_fc/conftest.py
+++ b/tests/auth_fc/conftest.py
@@ -18,7 +18,7 @@ import base64
import contextlib
import datetime
import json
-import urllib.parse as urlparse
+import urllib.parse
import uuid
import httmock
@@ -60,7 +60,7 @@ class FranceConnectMock:
def handle_authorization(self, app, url, **kwargs):
assert url.startswith('https://fcp.integ01')
- parsed_url = urlparse.urlparse(url)
+ parsed_url = urllib.parse.urlparse(url)
query = QueryDict(parsed_url.query)
assert_equals_url(query['redirect_uri'], self.callback_url)
assert query['client_id'] == self.client_id
@@ -90,7 +90,7 @@ class FranceConnectMock:
app.session.flush()
response = app.get(path)
self.callback_params = {
- k: v for k, v in QueryDict(urlparse.urlparse(response.location).query).items()
+ k: v for k, v in QueryDict(urllib.parse.urlparse(response.location).query).items()
}
response = response.follow()
response = response.click(href='callback')
@@ -142,7 +142,7 @@ class FranceConnectMock:
def handle_logout(self, app, url):
assert url.startswith('https://fcp.integ01.dev-franceconnect.fr/api/v1/logout')
- parsed_url = urlparse.urlparse(url)
+ parsed_url = urllib.parse.urlparse(url)
query = QueryDict(parsed_url.query)
assert_equals_url(query['post_logout_redirect_uri'], 'http://testserver' + reverse('fc-logout'))
assert query['state']
diff --git a/tests/auth_fc/test_auth_fc.py b/tests/auth_fc/test_auth_fc.py
index b3334a1e8..1b97e08aa 100644
--- a/tests/auth_fc/test_auth_fc.py
+++ b/tests/auth_fc/test_auth_fc.py
@@ -16,12 +16,12 @@
# along with this program. If not, see .
import datetime
+import urllib.parse
import mock
import requests
from django.contrib.auth import get_user_model
from django.urls import reverse
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import now
from authentic2.custom_user.models import DeletedUser
@@ -34,7 +34,7 @@ User = get_user_model()
def path(url):
- return urlparse.urlparse(url).path
+ return urllib.parse.urlparse(url).path
def test_login_redirect(app, franceconnect):
diff --git a/tests/conftest.py b/tests/conftest.py
index ca3cf1c04..114ce271f 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -16,6 +16,8 @@
# along with this program. If not, see .
+import urllib.parse
+
import django
import django_webtest
import mock
@@ -25,7 +27,6 @@ from django.core.cache import cache
from django.core.management import call_command
from django.db import connection
from django.db.migrations.executor import MigrationExecutor
-from django.utils.six.moves.urllib import parse as urlparse
from pytest_django.migrations import DisableMigrations
from authentic2 import hooks as a2_hooks
@@ -458,7 +459,7 @@ def assert_external_redirect(external_redirect):
else:
def check_location(response, default_return):
- assert urlparse.urljoin('http://testserver/', default_return).endswith(response['Location'])
+ assert urllib.parse.urljoin('http://testserver/', default_return).endswith(response['Location'])
return check_location
diff --git a/tests/test_admin.py b/tests/test_admin.py
index 8a5dd0410..da0c2170c 100644
--- a/tests/test_admin.py
+++ b/tests/test_admin.py
@@ -17,7 +17,7 @@
from __future__ import unicode_literals
-from django.utils.six.moves.urllib.parse import urlparse
+from urllib.parse import urlparse
from authentic2.custom_user.models import User
from authentic2.models import Attribute
diff --git a/tests/test_all.py b/tests/test_all.py
index 29d257db7..d387e5eb9 100644
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -17,6 +17,7 @@
import base64
import json
+import urllib.parse
import pytest
from django.contrib.auth import get_user_model
@@ -29,8 +30,6 @@ from django.test.client import Client
from django.test.utils import override_settings
from django.urls import reverse
from django.utils.encoding import force_text
-from django.utils.six import text_type
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext as _
from rest_framework import status, test
@@ -203,7 +202,8 @@ class UtilsTests(Authentic2TestCase):
response = login_require(request, login_hint=['backoffice'])
self.assertEqualsURL(response['Location'].split('?', 1)[0], '/login/')
self.assertEqualsURL(
- urlparse.parse_qs(response['Location'].split('?', 1)[1])['next'][0], '/coin?nonce=xxx&next=/zob/'
+ urllib.parse.parse_qs(response['Location'].split('?', 1)[1])['next'][0],
+ '/coin?nonce=xxx&next=/zob/',
)
self.assertEqual(request.session['login-hint'], ['backoffice'])
@@ -385,7 +385,7 @@ class AttributeKindsTest(TestCase):
for i, name in enumerate(attribute_kinds.get_attribute_kinds()):
fields['field_%d' % i] = attribute_kinds.get_form_field(name)
AttributeKindForm = type('AttributeKindForm', (forms.Form,), fields)
- text_type(AttributeKindForm().as_p())
+ str(AttributeKindForm().as_p())
class APITest(TestCase):
diff --git a/tests/test_auth_oidc.py b/tests/test_auth_oidc.py
index b27fb36db..a6c4ef02f 100644
--- a/tests/test_auth_oidc.py
+++ b/tests/test_auth_oidc.py
@@ -21,6 +21,7 @@ import os
import random
import re
import time
+import urllib.parse
import pytest
from django.contrib.auth import get_user_model
@@ -28,7 +29,6 @@ from django.db import IntegrityError, transaction
from django.http import QueryDict
from django.urls import reverse
from django.utils.encoding import force_str, force_text
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import now, utc
from httmock import HTTMock, urlmatch
from jwcrypto.common import base64url_decode, base64url_encode, json_encode
@@ -248,13 +248,13 @@ def oidc_provider_mock(
provides_kid_header=False,
kid=None,
):
- token_endpoint = urlparse.urlparse(oidc_provider.token_endpoint)
- userinfo_endpoint = urlparse.urlparse(oidc_provider.userinfo_endpoint)
- token_revocation_endpoint = urlparse.urlparse(oidc_provider.token_revocation_endpoint)
+ token_endpoint = urllib.parse.urlparse(oidc_provider.token_endpoint)
+ userinfo_endpoint = urllib.parse.urlparse(oidc_provider.userinfo_endpoint)
+ token_revocation_endpoint = urllib.parse.urlparse(oidc_provider.token_revocation_endpoint)
@urlmatch(netloc=token_endpoint.netloc, path=token_endpoint.path)
def token_endpoint_mock(url, request):
- if urlparse.parse_qs(request.body).get('code') == [code]:
+ if urllib.parse.parse_qs(request.body).get('code') == [code]:
exp = now() + datetime.timedelta(seconds=10)
id_token = {
'iss': oidc_provider.issuer,
@@ -341,7 +341,7 @@ def oidc_provider_mock(
@urlmatch(netloc=token_revocation_endpoint.netloc, path=token_revocation_endpoint.path)
def token_revocation_endpoint_mock(url, request):
- query = urlparse.parse_qs(request.body)
+ query = urllib.parse.parse_qs(request.body)
assert 'token' in query
return {
'status_code': 200,
@@ -458,8 +458,8 @@ def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, hooks):
response = app.get('/admin/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
- location = urlparse.urlparse(response.location)
- endpoint = urlparse.urlparse(oidc_provider.authorization_endpoint)
+ location = urllib.parse.urlparse(response.location)
+ endpoint = urllib.parse.urlparse(oidc_provider.authorization_endpoint)
assert location.scheme == endpoint.scheme
assert location.netloc == endpoint.netloc
assert location.path == endpoint.path
@@ -510,7 +510,7 @@ def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, hooks):
assert set(hooks.auth_oidc_backend_modify_user[0]['kwargs']) >= set(
['user', 'provider', 'user_info', 'id_token', 'access_token']
)
- assert urlparse.urlparse(response['Location']).path == '/admin/'
+ assert urllib.parse.urlparse(response['Location']).path == '/admin/'
assert User.objects.count() == 1
user = User.objects.get()
assert user.ou == get_default_ou()
@@ -588,7 +588,7 @@ def test_strategy_find_uuid(app, caplog, code, oidc_provider, oidc_provider_jwks
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
@@ -603,7 +603,7 @@ def test_strategy_find_uuid(app, caplog, code, oidc_provider, oidc_provider_jwks
with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, sub=simple_user.uuid, nonce=nonce):
response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state})
- assert urlparse.urlparse(response['Location']).path == '/'
+ assert urllib.parse.urlparse(response['Location']).path == '/'
assert User.objects.count() == 1
user = User.objects.get()
# verify user was not modified
@@ -630,7 +630,7 @@ def test_strategy_create(app, caplog, code, oidc_provider, oidc_provider_jwkset)
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
@@ -658,7 +658,7 @@ def test_register_issuer(db, app, caplog, oidc_provider_jwkset):
config_file = os.path.join(config_dir, 'openid_configuration.json')
with open(config_file) as f:
oidc_conf = json.load(f)
- jwks_uri = urlparse.urlparse(oidc_conf['jwks_uri'])
+ jwks_uri = urllib.parse.urlparse(oidc_conf['jwks_uri'])
@urlmatch(netloc=jwks_uri.netloc, path=jwks_uri.path)
def jwks_mock(url, request):
@@ -705,7 +705,7 @@ def test_invalid_kid(app, caplog, code, oidc_provider_rsa, oidc_provider_jwkset,
response = app.get('/').maybe_follow()
assert oidc_provider_rsa.name in response.text
response = response.click(oidc_provider_rsa.name)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
@@ -771,7 +771,7 @@ def test_templated_claim_mapping(app, caplog, code, oidc_provider, oidc_provider
response = app.get('/').maybe_follow()
response = response.click(oidc_provider.name)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
@@ -799,7 +799,7 @@ def test_lost_state(app, caplog, code, oidc_provider, oidc_provider_jwkset, hook
# As the oidc-state is used during a redirect from a third-party, we need
# it to be lax.
assert re.search('Set-Cookie.* oidc-state=.*SameSite=Lax', str(response))
- qs = urlparse.parse_qs(urlparse.urlparse(response.location).query)
+ qs = urllib.parse.parse_qs(urllib.parse.urlparse(response.location).query)
state = qs['state']
# reset the session to forget the state
@@ -858,7 +858,7 @@ def test_multiple_users_with_same_email(app, caplog, code, oidc_provider_jwkset,
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
@@ -877,7 +877,7 @@ def test_multiple_users_with_same_email(app, caplog, code, oidc_provider_jwkset,
response = app.get('/').maybe_follow()
assert oidc_provider.name in response.text
response = response.click(oidc_provider.name)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
query = QueryDict(location.query)
state = query['state']
nonce = query['nonce']
diff --git a/tests/test_idp_cas.py b/tests/test_idp_cas.py
index 7dad7f4c2..e38cc817b 100644
--- a/tests/test_idp_cas.py
+++ b/tests/test_idp_cas.py
@@ -14,11 +14,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import urllib.parse
+
from django.contrib.auth import get_user_model
from django.test.client import Client, RequestFactory
from django.test.utils import override_settings
from django.utils.encoding import force_text
-from django.utils.six.moves.urllib import parse as urlparse
from authentic2.a2_rbac.utils import get_default_ou
from authentic2.constants import AUTHENTICATION_EVENTS_SESSION_KEY, NONCE_FIELD_NAME
@@ -132,9 +133,9 @@ class CasTests(Authentic2TestCase):
assert service.authorized_roles.exists() is True
response = client.get('/idp/cas/login', {constants.SERVICE_PARAM: self.URL})
location = response['Location']
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
response = client.get(location)
response = client.post(
location,
@@ -152,9 +153,9 @@ class CasTests(Authentic2TestCase):
assert service.authorized_roles.exists() is True
response = client.get('/idp/cas/login', {constants.SERVICE_PARAM: self.URL})
location = response['Location']
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
response = client.get(location)
response = client.post(
location,
@@ -163,7 +164,7 @@ class CasTests(Authentic2TestCase):
)
response = client.get(response.url)
client = Client()
- ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
+ ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
response = client.get(
'/idp/cas/validate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
)
@@ -174,13 +175,13 @@ class CasTests(Authentic2TestCase):
ticket = Ticket.objects.get()
location = response['Location']
url = location.split('?')[0]
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
self.assertTrue(url.endswith('/login/'))
self.assertIn('nonce', query)
self.assertIn('next', query)
self.assertEqual(query['nonce'], [ticket.ticket_id])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
self.assertEqual(next_url, '/idp/cas/continue/')
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
@@ -214,7 +215,7 @@ class CasTests(Authentic2TestCase):
# Do not the same client for direct calls from the CAS service provider
# to prevent use of the user session
client = Client()
- ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
+ ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
response = client.get(
'/idp/cas/validate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
)
@@ -231,13 +232,13 @@ class CasTests(Authentic2TestCase):
ticket = Ticket.objects.get()
location = response['Location']
url = location.split('?')[0]
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
self.assertTrue(url.endswith('/login/'))
self.assertIn('nonce', query)
self.assertIn('next', query)
self.assertEqual(query['nonce'], [ticket.ticket_id])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
self.assertEqual(next_url, '/idp/cas/continue/')
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
@@ -271,7 +272,7 @@ class CasTests(Authentic2TestCase):
# Do not the same client for direct calls from the CAS service provider
# to prevent use of the user session
client = Client()
- ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
+ ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
response = client.get(
'/idp/cas/serviceValidate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
)
@@ -292,13 +293,13 @@ class CasTests(Authentic2TestCase):
ticket = Ticket.objects.get()
location = response['Location']
url = location.split('?')[0]
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
self.assertTrue(url.endswith('/login/'))
self.assertIn('nonce', query)
self.assertIn('next', query)
self.assertEqual(query['nonce'], [ticket.ticket_id])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
self.assertEqual(next_url, '/idp/cas/continue/')
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
@@ -332,7 +333,7 @@ class CasTests(Authentic2TestCase):
# Do not the same client for direct calls from the CAS service provider
# to prevent use of the user session
client = Client()
- ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
+ ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
response = client.get(
'/idp/cas/serviceValidate',
{constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL, constants.RENEW_PARAM: ''},
@@ -351,13 +352,13 @@ class CasTests(Authentic2TestCase):
ticket = Ticket.objects.get()
location = response['Location']
url = location.split('?')[0]
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
self.assertTrue(url.endswith('/login/'))
self.assertIn('nonce', query)
self.assertIn('next', query)
self.assertEqual(query['nonce'], [ticket.ticket_id])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
self.assertEqual(next_url, '/idp/cas/continue/')
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
@@ -391,7 +392,7 @@ class CasTests(Authentic2TestCase):
# Do not the same client for direct calls from the CAS service provider
# to prevent use of the user session
client = Client()
- ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
+ ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
response = client.get(
'/idp/cas/proxyValidate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
)
@@ -413,13 +414,13 @@ class CasTests(Authentic2TestCase):
ticket = Ticket.objects.get()
location = response['Location']
url = location.split('?')[0]
- query = urlparse.parse_qs(location.split('?')[1])
+ query = urllib.parse.parse_qs(location.split('?')[1])
self.assertTrue(url.endswith('/login/'))
self.assertIn('nonce', query)
self.assertIn('next', query)
self.assertEqual(query['nonce'], [ticket.ticket_id])
next_url, next_url_query = query['next'][0].split('?')
- next_url_query = urlparse.parse_qs(next_url_query)
+ next_url_query = urllib.parse.parse_qs(next_url_query)
self.assertEqual(next_url, '/idp/cas/continue/')
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
@@ -453,7 +454,7 @@ class CasTests(Authentic2TestCase):
# Do not the same client for direct calls from the CAS service provider
# to prevent use of the user session
client = Client()
- ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
+ ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
response = client.get(
'/idp/cas/serviceValidate',
{
diff --git a/tests/test_idp_oidc.py b/tests/test_idp_oidc.py
index 7e2dd057a..11c61e967 100644
--- a/tests/test_idp_oidc.py
+++ b/tests/test_idp_oidc.py
@@ -18,6 +18,7 @@ import base64
import datetime
import functools
import json
+import urllib.parse
from importlib import import_module
import pytest
@@ -28,7 +29,6 @@ from django.http import QueryDict
from django.test.utils import override_settings
from django.urls import reverse
from django.utils.encoding import force_text
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.timezone import now
from jwcrypto.jwk import JWK, JWKSet
from jwcrypto.jwt import JWT
@@ -301,9 +301,9 @@ def test_authorization_code_sso(
assert code.auth_time <= now()
assert code.expired >= now()
assert response['Location'].startswith(redirect_uri)
- location = urlparse.urlparse(response['Location'])
+ location = urllib.parse.urlparse(response['Location'])
if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
- query = urlparse.parse_qs(location.query)
+ query = urllib.parse.parse_qs(location.query)
assert set(query.keys()) == set(['code', 'state'])
assert query['code'] == [code.uuid]
code = query['code'][0]
@@ -328,7 +328,7 @@ def test_authorization_code_sso(
id_token = response.json['id_token']
elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
assert location.fragment
- query = urlparse.parse_qs(location.fragment)
+ query = urllib.parse.parse_qs(location.fragment)
assert OIDCAccessToken.objects.count() == 1
access_token = OIDCAccessToken.objects.get()
assert set(query.keys()) == set(['access_token', 'token_type', 'expires_in', 'id_token', 'state'])
@@ -434,13 +434,13 @@ def check_authorize_error(
):
# check next_url qs
if message:
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
assert location.path == '/continue/'
if check_next:
location_qs = QueryDict(location.query or '')
assert 'next' in location_qs
assert location_qs['next'].startswith(redirect_uri)
- next_url = urlparse.urlparse(location_qs['next'])
+ next_url = urllib.parse.urlparse(location_qs['next'])
next_url_qs = QueryDict(next_url.fragment if fragment else next_url.query)
assert next_url_qs['error'] == error
assert next_url_qs['error_description'] == error_description
@@ -449,7 +449,7 @@ def check_authorize_error(
assert error_description in continue_response.pyquery('.error').text()
elif check_next:
assert response.location.startswith(redirect_uri)
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
location_qs = QueryDict(location.fragment if fragment else location.query)
assert location_qs['error'] == error
assert location_qs['error_description'] == error_description
@@ -466,7 +466,7 @@ def check_authorize_error(
def assert_authorization_response(response, fragment=False, **kwargs):
- location = urlparse.urlparse(response.location)
+ location = urllib.parse.urlparse(response.location)
location_qs = QueryDict(location.fragment if fragment else location.query)
assert set(location_qs) == set(kwargs)
for key, value in kwargs.items():
@@ -769,7 +769,7 @@ def test_invalid_request(oidc_client, caplog, oidc_settings, simple_user, app):
},
)
response = app.get(authorize_url)
- assert urlparse.urlparse(response['Location']).path == reverse('auth_login')
+ assert urllib.parse.urlparse(response['Location']).path == reverse('auth_login')
if oidc_client.authorization_mode != oidc_client.AUTHORIZATION_MODE_NONE:
# prompt is none, but consent is required
@@ -873,8 +873,8 @@ def test_invalid_request(oidc_client, caplog, oidc_settings, simple_user, app):
code.expired = now() - datetime.timedelta(seconds=120)
assert not code.is_valid()
code.save()
- location = urlparse.urlparse(response['Location'])
- query = urlparse.parse_qs(location.query)
+ location = urllib.parse.urlparse(response['Location'])
+ query = urllib.parse.parse_qs(location.query)
assert set(query.keys()) == set(['code'])
assert query['code'] == [code.uuid]
code = query['code'][0]
@@ -1000,8 +1000,8 @@ def test_client_secret_post_authentication(oidc_settings, app, simple_oidc_clien
authorize_url = make_url('oidc-authorize', params=params)
response = app.get(authorize_url)
response = response.form.submit('accept')
- location = urlparse.urlparse(response['Location'])
- query = urlparse.parse_qs(location.query)
+ location = urllib.parse.urlparse(response['Location'])
+ query = urllib.parse.parse_qs(location.query)
code = query['code'][0]
token_url = make_url('oidc-token')
response = app.post(
@@ -1067,9 +1067,9 @@ def test_role_control_access(login_first, oidc_settings, oidc_client, simple_use
assert OIDCAuthorization.objects.get()
if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
code = OIDCCode.objects.get()
- location = urlparse.urlparse(response['Location'])
+ location = urllib.parse.urlparse(response['Location'])
if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
- query = urlparse.parse_qs(location.query)
+ query = urllib.parse.parse_qs(location.query)
code = query['code'][0]
token_url = make_url('oidc-token')
response = app.post(
@@ -1083,7 +1083,7 @@ def test_role_control_access(login_first, oidc_settings, oidc_client, simple_use
)
id_token = response.json['id_token']
elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
- query = urlparse.parse_qs(location.fragment)
+ query = urllib.parse.parse_qs(location.fragment)
id_token = query['id_token'][0]
if oidc_client.idtoken_algo in (oidc_client.ALGO_RSA, oidc_client.ALGO_EC):
@@ -1118,12 +1118,12 @@ def test_registration_service_slug(oidc_settings, app, simple_oidc_client, simpl
authorize_url = make_url('oidc-authorize', params=params)
response = app.get(authorize_url)
- location = urlparse.urlparse(response['Location'])
- query = urlparse.parse_qs(location.query)
+ location = urllib.parse.urlparse(response['Location'])
+ query = urllib.parse.parse_qs(location.query)
assert query['service'] == ['default client']
response = response.follow().click('Register')
- location = urlparse.urlparse(response.request.url)
- query = urlparse.parse_qs(location.query)
+ location = urllib.parse.urlparse(response.request.url)
+ query = urllib.parse.parse_qs(location.query)
assert query['service'] == ['default client']
response.form.set('email', 'john.doe@example.com')
@@ -1317,8 +1317,8 @@ def test_claim_default_value(oidc_settings, normal_oidc_client, simple_user, app
authorize_url = make_url('oidc-authorize', params=params)
response = app.get(authorize_url)
- location = urlparse.urlparse(response['Location'])
- query = urlparse.parse_qs(location.query)
+ location = urllib.parse.urlparse(response['Location'])
+ query = urllib.parse.parse_qs(location.query)
code = query['code'][0]
token_url = make_url('oidc-token')
@@ -1420,8 +1420,8 @@ def test_claim_templated(oidc_settings, normal_oidc_client, simple_user, app):
authorize_url = make_url('oidc-authorize', params=params)
response = app.get(authorize_url)
- location = urlparse.urlparse(response['Location'])
- query = urlparse.parse_qs(location.query)
+ location = urllib.parse.urlparse(response['Location'])
+ query = urllib.parse.parse_qs(location.query)
code = query['code'][0]
token_url = make_url('oidc-token')
diff --git a/tests/test_idp_saml2.py b/tests/test_idp_saml2.py
index 962eee4ff..b3c80878d 100644
--- a/tests/test_idp_saml2.py
+++ b/tests/test_idp_saml2.py
@@ -21,6 +21,7 @@ import base64
import datetime
import hashlib
import re
+import urllib.parse
import xml.etree.ElementTree as ET
import lasso
@@ -31,7 +32,6 @@ from django.core.files import File
from django.template import Context, Template
from django.urls import reverse
from django.utils.encoding import force_bytes, force_str, force_text
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import gettext as _
from authentic2.a2_rbac.models import OrganizationalUnit, Role
@@ -272,7 +272,7 @@ class SamlSP(object):
),
)
login.buildAuthnRequestMsg()
- url_parsed = urlparse.urlparse(login.msgUrl)
+ url_parsed = urllib.parse.urlparse(login.msgUrl)
assert url_parsed.path == reverse('a2-idp-saml-sso'), 'msgUrl should target the sso endpoint'
if self.keys:
assert 'rsa-sha256' in login.msgUrl
@@ -288,7 +288,7 @@ class SamlSP(object):
if response.location:
method = lasso.HTTP_METHOD_ARTIFACT_GET
query_string = response.location.split('?', 1)[1]
- parsed_query_string = urlparse.parse_qs(query_string)
+ parsed_query_string = urllib.parse.parse_qs(query_string)
self.relay_state = parsed_query_string.get('RelayState')
login.msgRelayState = force_str(self.relay_state)
else: # lasso.HTTP_METHOD_ARTIFACT_POST, never happens
@@ -334,7 +334,7 @@ class Scenario(object):
REDIRECT_FIELD_NAME: make_url('a2-idp-saml-continue', params={NONCE_FIELD_NAME: request_id}),
},
)
- self.nonce = urlparse.parse_qs(urlparse.urlparse(response['Location']).query)['nonce'][0]
+ self.nonce = urllib.parse.parse_qs(urllib.parse.urlparse(response['Location']).query)['nonce'][0]
url = response['Location']
response = self.app.get(url)
assert response.status_code == 200
diff --git a/tests/test_import_export_site_cmd.py b/tests/test_import_export_site_cmd.py
index c9bd93fdb..c3ad3126f 100644
--- a/tests/test_import_export_site_cmd.py
+++ b/tests/test_import_export_site_cmd.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import builtins as __builtin__
import json
import random
@@ -21,7 +22,6 @@ import pytest
from django import VERSION
from django.core import management
from django.core.exceptions import ValidationError
-from django.utils.six.moves import builtins as __builtin__
from django_rbac.utils import get_role_model
diff --git a/tests/test_ldap.py b/tests/test_ldap.py
index a4c1d75cc..edc4b9a6e 100644
--- a/tests/test_ldap.py
+++ b/tests/test_ldap.py
@@ -18,6 +18,7 @@
import json
import os
import time
+import urllib.parse
import ldap
import mock
@@ -27,7 +28,6 @@ from django.core import mail, management
from django.core.exceptions import ImproperlyConfigured
from django.utils import timezone
from django.utils.encoding import force_bytes, force_text
-from django.utils.six.moves.urllib import parse as urlparse
from ldap.dn import escape_dn_chars
from ldaptools.slapd import Slapd, has_slapd
@@ -1479,7 +1479,7 @@ def test_sync_ldap_users(slapd, settings, app, db, capsys):
assert all(
[
user.userexternalid_set.first().external_id
- == urlparse.quote(user.username.split('@')[0].encode('utf-8'))
+ == urllib.parse.quote(user.username.split('@')[0].encode('utf-8'))
for user in User.objects.all()
]
)
diff --git a/tests/test_login.py b/tests/test_login.py
index b4b8326c7..40874653b 100644
--- a/tests/test_login.py
+++ b/tests/test_login.py
@@ -14,9 +14,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+from urllib.parse import quote
+
import pytest
from django.contrib.auth import get_user_model
-from django.utils.six.moves.urllib.parse import quote
from authentic2 import models
diff --git a/tests/test_manager.py b/tests/test_manager.py
index ff67fb0b0..89ed532ea 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -18,6 +18,7 @@
from __future__ import unicode_literals
import json
+from urllib.parse import urlparse
import pytest
from django.contrib.auth import get_user_model
@@ -25,7 +26,6 @@ from django.contrib.contenttypes.models import ContentType
from django.core import mail
from django.urls import reverse
from django.utils.encoding import force_bytes, force_str
-from django.utils.six.moves.urllib.parse import urlparse
from webtest import Upload
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
diff --git a/tests/test_registration.py b/tests/test_registration.py
index 7107e3c60..2673ae8bb 100644
--- a/tests/test_registration.py
+++ b/tests/test_registration.py
@@ -16,11 +16,11 @@
# along with this program. If not, see .
from datetime import date
+from urllib.parse import urlparse
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.urls import reverse
from django.utils.http import urlquote
-from django.utils.six.moves.urllib.parse import urlparse
from authentic2 import models, utils
from authentic2.apps.journal.models import Event
diff --git a/tests/test_user_manager.py b/tests/test_user_manager.py
index 069aea8fc..0e1d506d1 100644
--- a/tests/test_user_manager.py
+++ b/tests/test_user_manager.py
@@ -27,7 +27,6 @@ import pytest
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
-from django.utils.six import text_type
from webtest import Upload
from authentic2.a2_rbac.utils import get_default_ou, get_view_user_perm
@@ -230,12 +229,12 @@ def test_manager_user_change_email(app, superuser_or_admin, simple_user, mailout
response = login(
app,
superuser_or_admin,
- reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': text_type(simple_user.uuid)}),
+ reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': str(simple_user.uuid)}),
)
assert 'Change user email' in response.text
# cannot click it's a submit button :/
response = app.get(
- reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': text_type(simple_user.uuid)})
+ reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': str(simple_user.uuid)})
)
assert response.form['new_email'].value == simple_user.email
response.form.set('new_email', NEW_EMAIL)
@@ -270,12 +269,12 @@ def test_manager_user_change_email_no_change(app, superuser_or_admin, simple_use
response = login(
app,
superuser_or_admin,
- reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': text_type(simple_user.uuid)}),
+ reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': str(simple_user.uuid)}),
)
assert 'Change user email' in response.text
# cannot click it's a submit button :/
response = app.get(
- reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': text_type(simple_user.uuid)})
+ reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': str(simple_user.uuid)})
)
assert response.form['new_email'].value == simple_user.email
assert len(mailoutbox) == 0
diff --git a/tests/test_views.py b/tests/test_views.py
index 2bb31e963..2e4dcad69 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -16,11 +16,11 @@
# authentic2
import datetime
+from urllib.parse import urlparse
import pytest
from django.urls import reverse
from django.utils.html import escape
-from django.utils.six.moves.urllib.parse import urlparse
from authentic2.custom_user.models import DeletedUser, User
diff --git a/tests/utils.py b/tests/utils.py
index a4a73b9bc..9b415b278 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -18,6 +18,7 @@
import base64
import re
import socket
+import urllib.parse
from contextlib import closing, contextmanager
import httmock
@@ -25,9 +26,7 @@ from django.core.management import call_command as django_call_command
from django.shortcuts import resolve_url
from django.test import TestCase
from django.urls import reverse
-from django.utils import six
from django.utils.encoding import force_text, iri_to_uri
-from django.utils.six.moves.urllib import parse as urlparse
from lxml import etree
from authentic2 import models, utils
@@ -98,13 +97,13 @@ def assert_equals_url(url1, url2, **kwargs):
value.
"""
url1 = iri_to_uri(utils.make_url(url1, params=None))
- splitted1 = urlparse.urlsplit(url1)
+ splitted1 = urllib.parse.urlsplit(url1)
url2 = iri_to_uri(utils.make_url(url2, params=kwargs))
- splitted2 = urlparse.urlsplit(url2)
+ splitted2 = urllib.parse.urlsplit(url2)
for i, (elt1, elt2) in enumerate(zip(splitted1, splitted2)):
if i == 3:
- elt1 = urlparse.parse_qs(elt1, True)
- elt2 = urlparse.parse_qs(elt2, True)
+ elt1 = urllib.parse.parse_qs(elt1, True)
+ elt2 = urllib.parse.parse_qs(elt2, True)
for k, v in elt1.items():
elt1[k] = set(v)
for k, v in elt2.items():
@@ -117,11 +116,11 @@ def assert_equals_url(url1, url2, **kwargs):
def assert_redirects_complex(response, expected_url, **kwargs):
assert response.status_code == 302, 'code should be 302'
- scheme, netloc, path, query, fragment = urlparse.urlsplit(response.url)
- e_scheme, e_netloc, e_path, e_query, e_fragment = urlparse.urlsplit(expected_url)
+ scheme, netloc, path, query, fragment = urllib.parse.urlsplit(response.url)
+ e_scheme, e_netloc, e_path, e_query, e_fragment = urllib.parse.urlsplit(expected_url)
e_scheme = e_scheme if e_scheme else scheme
e_netloc = e_netloc if e_netloc else netloc
- expected_url = urlparse.urlunsplit((e_scheme, e_netloc, e_path, e_query, e_fragment))
+ expected_url = urllib.parse.urlunsplit((e_scheme, e_netloc, e_path, e_query, e_fragment))
assert_equals_url(response['Location'], expected_url, **kwargs)
@@ -132,7 +131,7 @@ def assert_xpath_constraints(xml, constraints, namespaces):
for xpath, content in constraints:
nodes = doc.xpath(xpath, namespaces=namespaces)
assert len(nodes) > 0, 'xpath %s not found' % xpath
- if isinstance(content, six.string_types):
+ if isinstance(content, str):
for node in nodes:
if hasattr(node, 'text'):
assert node.text == content, 'xpath %s does not contain %s but %s' % (