diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a14705c..ce247d6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -6,3 +6,13 @@ repos:
hooks:
- id: black
args: ['--target-version', 'py37', '--skip-string-normalization', '--line-length', '110']
+- repo: https://github.com/PyCQA/isort
+ rev: 5.7.0
+ hooks:
+ - id: isort
+ args: ['--profile', 'black', '--line-length', '110']
+- repo: https://github.com/asottile/pyupgrade
+ rev: v2.20.0
+ hooks:
+ - id: pyupgrade
+ args: ['--keep-percent-format', '--py37-plus']
diff --git a/README b/README
index fba31ef..16180a8 100644
--- a/README
+++ b/README
@@ -319,7 +319,7 @@ Unit tests are written using pytest and launched using tox, and can be run with:
tox
Code Style
-----------
+==========
black is used to format the code, using thoses parameters:
@@ -328,6 +328,18 @@ black is used to format the code, using thoses parameters:
There is .pre-commit-config.yaml to use pre-commit to automatically run black
before commits. (execute `pre-commit install` to install the git hook.)
+isort is used to format the imports, using those parameter:
+
+ isort --profile black --line-length 110
+
+pyupgrade is used to automatically upgrade syntax, using those parameters:
+
+ pyupgrade --keep-percent-format --py37-plus
+
+There is .pre-commit-config.yaml to use pre-commit to automatically run black,
+isort and pyupgrade before commits. (execute `pre-commit install` to install
+the git hook.)
+
Remarks
=======
diff --git a/mellon/adapters.py b/mellon/adapters.py
index 6ec5f80..ee95a2f 100644
--- a/mellon/adapters.py
+++ b/mellon/adapters.py
@@ -13,33 +13,29 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
-from xml.etree import ElementTree as ET
import hashlib
-
import logging
import os
import threading
import time
import uuid
+from xml.etree import ElementTree as ET
import lasso
import requests
import requests.exceptions
from atomicwrites import atomic_write
-
-from django.core.exceptions import PermissionDenied, FieldDoesNotExist
-from django.core.files.storage import default_storage
-from django.contrib import auth
+from django.contrib import auth, messages
from django.contrib.auth.models import Group
-from django.contrib import messages
+from django.core.exceptions import FieldDoesNotExist, PermissionDenied
+from django.core.files.storage import default_storage
from django.utils import six
from django.utils.encoding import force_text
from django.utils.six.moves.urllib.parse import urlparse
from django.utils.translation import ugettext as _
-from . import utils, app_settings, models
+from . import app_settings, models, utils
User = auth.get_user_model()
@@ -51,7 +47,7 @@ class UserCreationError(Exception):
def display_truncated_list(l, max_length=10):
- s = '[' + ', '.join(map(six.text_type, l))
+ s = '[' + ', '.join(map(str, l))
if len(l) > max_length:
s += '..truncated more than %d items (%d)]' % (max_length, len(l))
else:
@@ -59,7 +55,7 @@ def display_truncated_list(l, max_length=10):
return s
-class DefaultAdapter(object):
+class DefaultAdapter:
def __init__(self, request=None):
self.request = request
@@ -153,7 +149,7 @@ class DefaultAdapter(object):
idp['METADATA'] = fd.read()
# use file cache mtime as last_update time, prevent too many loading from different workers
last_update = max(last_update, os.stat(file_cache_path).st_mtime)
- except (IOError, OSError):
+ except OSError:
warning('metadata url %s : error when loading the file cache %s', url, file_cache_path)
# fresh cache, skip loading
@@ -305,7 +301,7 @@ class DefaultAdapter(object):
if saml_attributes['name_id_format'] == lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT:
if transient_federation_attribute and saml_attributes.get(transient_federation_attribute):
name_id = saml_attributes[transient_federation_attribute]
- if not isinstance(name_id, six.string_types):
+ if not isinstance(name_id, str):
if len(name_id) == 1:
name_id = name_id[0]
else:
diff --git a/mellon/app_settings.py b/mellon/app_settings.py
index 82361ad..a177abf 100644
--- a/mellon/app_settings.py
+++ b/mellon/app_settings.py
@@ -1,7 +1,7 @@
import sys
-class AppSettings(object):
+class AppSettings:
__PREFIX = 'MELLON_'
__DEFAULTS = {
'IDENTITY_PROVIDERS': [],
diff --git a/mellon/backends.py b/mellon/backends.py
index 025a2f3..668f8c5 100644
--- a/mellon/backends.py
+++ b/mellon/backends.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
+
import logging
from django.contrib.auth.backends import ModelBackend
diff --git a/mellon/middleware.py b/mellon/middleware.py
index 5db67ac..0bcd59f 100644
--- a/mellon/middleware.py
+++ b/mellon/middleware.py
@@ -13,12 +13,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
-from django.utils.http import urlencode
from django.http import HttpResponseRedirect
-from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse
+from django.utils.deprecation import MiddlewareMixin
+from django.utils.http import urlencode
from . import app_settings, utils
diff --git a/mellon/migrations/0001_initial.py b/mellon/migrations/0001_initial.py
index ed281b4..2e04812 100644
--- a/mellon/migrations/0001_initial.py
+++ b/mellon/migrations/0001_initial.py
@@ -1,8 +1,5 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -40,6 +37,6 @@ class Migration(migrations.Migration):
),
migrations.AlterUniqueTogether(
name='usersamlidentifier',
- unique_together=set([('issuer', 'name_id')]),
+ unique_together={('issuer', 'name_id')},
),
]
diff --git a/mellon/migrations/0002_sessionindex.py b/mellon/migrations/0002_sessionindex.py
index 41d0309..5e5ebc4 100644
--- a/mellon/migrations/0002_sessionindex.py
+++ b/mellon/migrations/0002_sessionindex.py
@@ -1,7 +1,7 @@
# Generated by Django 2.2.12 on 2020-04-24 05:14
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
diff --git a/mellon/models.py b/mellon/models.py
index 755756b..740487c 100644
--- a/mellon/models.py
+++ b/mellon/models.py
@@ -13,13 +13,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
from importlib import import_module
+from django.conf import settings
from django.db import models
from django.utils.translation import ugettext_lazy as _
-from django.conf import settings
class UserSAMLIdentifier(models.Model):
diff --git a/mellon/sessions_backends/db.py b/mellon/sessions_backends/db.py
index a45eadf..dbec306 100644
--- a/mellon/sessions_backends/db.py
+++ b/mellon/sessions_backends/db.py
@@ -29,10 +29,10 @@ class SessionStore(SessionStore):
session_not_on_or_after = self.get_session_not_on_or_after()
if session_not_on_or_after and 'expiry' not in kwargs:
kwargs['expiry'] = session_not_on_or_after
- return super(SessionStore, self).get_expiry_age(**kwargs)
+ return super().get_expiry_age(**kwargs)
def get_expiry_date(self, **kwargs):
session_not_on_or_after = self.get_session_not_on_or_after()
if session_not_on_or_after and 'expiry' not in kwargs:
kwargs['expiry'] = session_not_on_or_after
- return super(SessionStore, self).get_expiry_date(**kwargs)
+ return super().get_expiry_date(**kwargs)
diff --git a/mellon/urls.py b/mellon/urls.py
index dca25b5..0e44152 100644
--- a/mellon/urls.py
+++ b/mellon/urls.py
@@ -1,11 +1,8 @@
-from __future__ import unicode_literals
-
-from django.conf.urls import url
import django
+from django.conf.urls import url
from . import views
-
urlpatterns = [
url('login/$', views.login, name='mellon_login'),
url('login/debug/$', views.debug_login, name='mellon_debug_login'),
diff --git a/mellon/utils.py b/mellon/utils.py
index 77bb899..a05fcae 100644
--- a/mellon/utils.py
+++ b/mellon/utils.py
@@ -13,23 +13,22 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
-import logging
import datetime
import importlib
+import logging
from functools import wraps
-import isodate
from xml.parsers import expat
+import isodate
+import lasso
+from django.conf import settings
from django.contrib import auth
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.encoding import force_text
-from django.utils.timezone import make_aware, now, make_naive, is_aware, get_default_timezone
-from django.conf import settings
from django.utils.six.moves.urllib.parse import urlparse
-import lasso
+from django.utils.timezone import get_default_timezone, is_aware, make_aware, make_naive, now
from . import app_settings
@@ -133,8 +132,7 @@ def get_idp(entity_id):
def get_idps():
for adapter in get_adapters():
if hasattr(adapter, 'get_idps'):
- for idp in adapter.get_idps():
- yield idp
+ yield from adapter.get_idps()
def flatten_datetime(d):
diff --git a/mellon/views.py b/mellon/views.py
index c78c517..aac7a75 100644
--- a/mellon/views.py
+++ b/mellon/views.py
@@ -13,53 +13,43 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
+import logging
+import uuid
+import xml.etree.ElementTree as ET
from contextlib import contextmanager, nullcontext
from importlib import import_module
from io import StringIO
-import logging
-import requests
-import lasso
-import uuid
-from requests.exceptions import RequestException
from xml.sax.saxutils import escape
-import xml.etree.ElementTree as ET
import django.http
-from django.views.generic import View
-from django.views.generic.base import RedirectView
-from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden
-from django.contrib import auth
-from django.contrib.auth import get_user_model
+import lasso
+import requests
from django.conf import settings
-from django.views.decorators.csrf import csrf_exempt
+from django.contrib import auth
+from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
+from django.db import transaction
+from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import render, resolve_url
from django.urls import reverse
-from django.utils.http import urlencode
from django.utils import six
-from django.utils.encoding import force_text, force_str
-from django.contrib.auth import REDIRECT_FIELD_NAME
-from django.db import transaction
+from django.utils.encoding import force_str, force_text
+from django.utils.http import urlencode
from django.utils.translation import ugettext as _
+from django.views.decorators.csrf import csrf_exempt
+from django.views.generic import View
+from django.views.generic.base import RedirectView
+from requests.exceptions import RequestException
-from . import app_settings, utils, models
-
+from . import app_settings, models, utils
RETRY_LOGIN_COOKIE = 'MELLON_RETRY_LOGIN'
lasso.setFlag('thin-sessions')
-if six.PY3:
- def lasso_decode(x):
- return x
-
-
-else:
-
- def lasso_decode(x):
- return x.decode('utf-8')
+def lasso_decode(x):
+ return x
EO_NS = 'https://www.entrouvert.com/'
@@ -71,16 +61,16 @@ User = get_user_model()
class HttpResponseBadRequest(django.http.HttpResponseBadRequest):
def __init__(self, *args, **kwargs):
kwargs['content_type'] = kwargs.get('content_type', 'text/plain')
- super(HttpResponseBadRequest, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self['X-Content-Type-Options'] = 'nosniff'
-class LogMixin(object):
+class LogMixin:
"""Initialize a module logger in new objects"""
def __init__(self, *args, **kwargs):
self.log = logging.getLogger(__name__)
- super(LogMixin, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
def check_next_url(request, next_url):
@@ -101,7 +91,7 @@ def check_next_url(request, next_url):
return next_url
-class ProfileMixin(object):
+class ProfileMixin:
profile = None
def set_next_url(self, next_url):
@@ -507,7 +497,7 @@ class LoginView(ProfileMixin, LogMixin, View):
# configure requested AuthnClassRef
authn_classref = utils.get_setting(idp, 'AUTHN_CLASSREF')
if authn_classref:
- authn_classref = tuple([str(x) for x in authn_classref])
+ authn_classref = tuple(str(x) for x in authn_classref)
req_authncontext = lasso.Samlp2RequestedAuthnContext()
authn_request.requestedAuthnContext = req_authncontext
req_authncontext.authnContextClassRef = authn_classref
@@ -550,8 +540,7 @@ class LoginView(ProfileMixin, LogMixin, View):
assert hasattr(authn_request.extensions, 'any'), 'extension nodes need lasso > 2.5.1'
serialized = ET.tostring(node, 'utf-8')
# tostring return bytes in PY3, but lasso needs str
- if six.PY3:
- serialized = serialized.decode('utf-8')
+ serialized = serialized.decode('utf-8')
extension_content = authn_request.extensions.any or ()
extension_content += (serialized,)
authn_request.extensions.any = extension_content
@@ -653,7 +642,7 @@ class LogoutView(ProfileMixin, LogMixin, View):
return HttpResponseBadRequest('error processing logout request: %r' % e)
issuer = force_text(logout.remoteProviderId)
- session_indexes = set(force_text(sessionIndex) for sessionIndex in logout.request.sessionIndexes)
+ session_indexes = {force_text(sessionIndex) for sessionIndex in logout.request.sessionIndexes}
saml_identifier = (
models.UserSAMLIdentifier.objects.filter(
diff --git a/setup.py b/setup.py
index 6fa8b1e..5a130b4 100755
--- a/setup.py
+++ b/setup.py
@@ -5,11 +5,12 @@
import os
import subprocess
-from setuptools import setup, find_packages
-from setuptools.command.install_lib import install_lib as _install_lib
-from distutils.command.build import build as _build
-from setuptools.command.sdist import sdist as _sdist
from distutils.cmd import Command
+from distutils.command.build import build as _build
+
+from setuptools import find_packages, setup
+from setuptools.command.install_lib import install_lib as _install_lib
+from setuptools.command.sdist import sdist as _sdist
class compile_translations(Command):
@@ -24,6 +25,7 @@ class compile_translations(Command):
def run(self):
import os
+
from django.core.management import call_command
os.environ.pop('DJANGO_SETTINGS_MODULE', None)
@@ -68,7 +70,7 @@ def get_version():
tag exists, take 0.0.0- and add the length of the commit log.
"""
if os.path.exists('VERSION'):
- with open('VERSION', 'r') as v:
+ with open('VERSION') as v:
return v.read()
if os.path.exists('.git'):
p = subprocess.Popen(
diff --git a/tests/conftest.py b/tests/conftest.py
index 882e300..2e668be 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import os
import logging
+import os
-import pytest
import django_webtest
+import pytest
@pytest.fixture(autouse=True)
diff --git a/tests/test_default_adapter.py b/tests/test_default_adapter.py
index a8e3b4d..771c885 100644
--- a/tests/test_default_adapter.py
+++ b/tests/test_default_adapter.py
@@ -13,24 +13,21 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
import datetime
import re
-import lasso
import time
from multiprocessing.pool import ThreadPool
+from unittest import mock
-import mock
+import lasso
import pytest
-
from django.contrib import auth
from django.db import connection
from mellon.adapters import DefaultAdapter
from mellon.backends import SAMLBackend
-
pytestmark = pytest.mark.django_db
User = auth.get_user_model()
@@ -119,7 +116,7 @@ def test_lookup_user_transaction(transactional_db, concurrency, idp, saml_attrib
users = p.map(f, range(concurrency))
assert len(users) == concurrency
- assert len(set(user.pk for user in users)) == 1
+ assert len({user.pk for user in users}) == 1
def test_provision_user_attributes(settings, django_user_model, idp, saml_attributes, caplog):
diff --git a/tests/test_sso_slo.py b/tests/test_sso_slo.py
index 61eae22..970d50c 100644
--- a/tests/test_sso_slo.py
+++ b/tests/test_sso_slo.py
@@ -13,32 +13,29 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
-import datetime
-from html import unescape
-import re
import base64
-import zlib
+import datetime
+import re
import xml.etree.ElementTree as ET
+import zlib
+from html import unescape
import lasso
-
import pytest
-from pytest import fixture
-
-from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
+from django.contrib.sessions.models import Session
from django.urls import reverse
from django.utils import six
-from django.utils.six.moves.urllib import parse as urlparse
from django.utils.encoding import force_str
+from django.utils.six.moves.urllib import parse as urlparse
+from httmock import HTTMock, all_requests
+from httmock import response as mock_response
+from pytest import fixture
from mellon.utils import create_metadata
from mellon.views import lasso_decode
-from httmock import all_requests, HTTMock, response as mock_response
-
@fixture
def idp_metadata():
@@ -81,7 +78,7 @@ def sp_metadata(sp_settings, rf):
return create_metadata(request)
-class MockIdp(object):
+class MockIdp:
session_dump = None
identity_dump = None
@@ -240,10 +237,10 @@ def test_sso_slo(db, app, idp, caplog, sp_settings):
assert 'created new user' in caplog.text
assert 'logged in using SAML' in caplog.text
assert urlparse.urlparse(response['Location']).path == '/whatever/'
- response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': str('/some/path')})
+ response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'})
assert urlparse.urlparse(response['Location']).path == '/singleLogout'
# again, user is already logged out
- response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': str('/some/path')})
+ response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'})
assert urlparse.urlparse(response['Location']).path == '/some/path'
@@ -433,18 +430,11 @@ def test_sso_request_denied(db, app, idp, caplog, sp_settings):
assert not relay_state
assert url.endswith(reverse('mellon_login'))
response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state})
- if six.PY3:
- assert (
- "status is not success codes: ['urn:oasis:names:tc:SAML:2.0:status:Responder',\
+ assert (
+ "status is not success codes: ['urn:oasis:names:tc:SAML:2.0:status:Responder',\
'urn:oasis:names:tc:SAML:2.0:status:RequestDenied']"
- in caplog.text
- )
- else:
- assert (
- "status is not success codes: [u'urn:oasis:names:tc:SAML:2.0:status:Responder',\
- u'urn:oasis:names:tc:SAML:2.0:status:RequestDenied']"
- in caplog.text
- )
+ in caplog.text
+ )
@pytest.mark.urls('urls_tests_template_base')
@@ -663,7 +653,7 @@ def test_passive_auth_middleware_ok(db, app, idp, caplog, settings):
settings.MELLON_OPENED_SESSION_COOKIE_NAME = 'IDP_SESSION'
assert 'MELLON_PASSIVE_TRIED' not in app.cookies
# webtest-lint is against unicode
- app.set_cookie(str('IDP_SESSION'), str('1'))
+ app.set_cookie('IDP_SESSION', '1')
response = app.get('/', headers={'Accept': force_str('text/html')}, status=302)
assert urlparse.urlparse(response.location).path == '/login/'
assert urlparse.parse_qs(urlparse.urlparse(response.location).query, keep_blank_values=True) == {
@@ -681,7 +671,7 @@ def test_passive_auth_middleware_ok(db, app, idp, caplog, settings):
assert 'MELLON_PASSIVE_TRIED' not in app.cookies
# check passive authentication is tried again
- app.set_cookie(str('IDP_SESSION'), str('1'))
+ app.set_cookie('IDP_SESSION', '1')
response = app.get('/', headers={'Accept': force_str('text/html')}, status=302)
assert urlparse.urlparse(response.location).path == '/login/'
assert urlparse.parse_qs(urlparse.urlparse(response.location).query, keep_blank_values=True) == {
@@ -695,7 +685,7 @@ def test_passive_auth_middleware_no_passive_auth_parameter(db, app, idp, caplog,
settings.MELLON_OPENED_SESSION_COOKIE_NAME = 'IDP_SESSION'
assert 'MELLON_PASSIVE_TRIED' not in app.cookies
# webtest-lint is against unicode
- app.set_cookie(str('IDP_SESSION'), str('1'))
+ app.set_cookie('IDP_SESSION', '1')
app.get('/?no-passive-auth', headers={'Accept': force_str('text/html')}, status=200)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index fb5fa21..d4f38cb 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -13,17 +13,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
import datetime
+from unittest import mock
-import mock
import lasso
-
-from mellon.utils import create_metadata, iso8601_to_datetime, flatten_datetime
-from mellon.views import check_next_url
from xml_utils import assert_xml_constraints
+from mellon.utils import create_metadata, flatten_datetime, iso8601_to_datetime
+from mellon.views import check_next_url
+
def test_create_metadata(rf, private_settings, caplog):
ns = {
@@ -144,17 +143,17 @@ def test_flatten_datetime():
'y': 1,
'z': 'u',
}
- assert set(flatten_datetime(d).keys()) == set(['x', 'y', 'z'])
+ assert set(flatten_datetime(d).keys()) == {'x', 'y', 'z'}
assert flatten_datetime(d)['x'] == '2010-10-10T10:10:34'
assert flatten_datetime(d)['y'] == 1
assert flatten_datetime(d)['z'] == 'u'
def test_check_next_url(rf):
- assert not check_next_url(rf.get('/'), u'')
+ assert not check_next_url(rf.get('/'), '')
assert not check_next_url(rf.get('/'), None)
- assert not check_next_url(rf.get('/'), u'\x00')
- assert not check_next_url(rf.get('/'), u'\u010e')
- assert not check_next_url(rf.get('/'), u'https://example.invalid/')
+ assert not check_next_url(rf.get('/'), '\x00')
+ assert not check_next_url(rf.get('/'), '\u010e')
+ assert not check_next_url(rf.get('/'), 'https://example.invalid/')
# default hostname is testserver
- assert check_next_url(rf.get('/'), u'http://testserver/ok/')
+ assert check_next_url(rf.get('/'), 'http://testserver/ok/')
diff --git a/tests/test_views.py b/tests/test_views.py
index 451709e..3783ce4 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -13,23 +13,20 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from __future__ import unicode_literals
-import pytest
-import mock
-import lasso
-from django.utils.six.moves.urllib.parse import parse_qs, urlparse
import base64
import hashlib
-from httmock import HTTMock
+from unittest import mock
+import lasso
+import pytest
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.http import urlencode
-
-from xml_utils import assert_xml_constraints
-
+from django.utils.six.moves.urllib.parse import parse_qs, urlparse
+from httmock import HTTMock
from utils import error_500, html_response
+from xml_utils import assert_xml_constraints
pytestmark = pytest.mark.django_db
@@ -207,7 +204,7 @@ def test_sp_initiated_login(private_settings, client):
assert response.status_code == 302
params = parse_qs(urlparse(response['Location']).query)
assert response['Location'].startswith('http://idp5/singleSignOn?')
- assert set(params.keys()) == set(['SAMLRequest', 'RelayState'])
+ assert set(params.keys()) == {'SAMLRequest', 'RelayState'}
assert len(params['SAMLRequest']) == 1
assert base64.b64decode(params['SAMLRequest'][0])
assert client.session['mellon_next_url_%s' % params['RelayState'][0]] == '/whatever'
@@ -229,7 +226,7 @@ def test_sp_initiated_login_chosen(private_settings, client):
assert response.status_code == 302
params = parse_qs(urlparse(response['Location']).query)
assert response['Location'].startswith('http://idp5/singleSignOn?')
- assert set(params.keys()) == set(['SAMLRequest', 'RelayState'])
+ assert set(params.keys()) == {'SAMLRequest', 'RelayState'}
assert len(params['SAMLRequest']) == 1
assert base64.b64decode(params['SAMLRequest'][0])
assert client.session['mellon_next_url_%s' % params['RelayState'][0]] == '/whatever'
diff --git a/tests/urls_tests.py b/tests/urls_tests.py
index 16e7602..233848c 100644
--- a/tests/urls_tests.py
+++ b/tests/urls_tests.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from django.conf.urls import url, include
+from django.conf.urls import include, url
from django.http import HttpResponse
diff --git a/tests/urls_tests_template_base.py b/tests/urls_tests_template_base.py
index 8279af0..d800036 100644
--- a/tests/urls_tests_template_base.py
+++ b/tests/urls_tests_template_base.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from django.conf.urls import url, include
+from django.conf.urls import include, url
from django.http import HttpResponse
diff --git a/tests/urls_tests_template_hook.py b/tests/urls_tests_template_hook.py
index 0301d63..716c4d9 100644
--- a/tests/urls_tests_template_hook.py
+++ b/tests/urls_tests_template_hook.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from django.conf.urls import url, include
+from django.conf.urls import include, url
from django.http import HttpResponse
diff --git a/testsettings.py b/testsettings.py
index 99e1726..104e585 100644
--- a/testsettings.py
+++ b/testsettings.py
@@ -1,4 +1,5 @@
import os
+
import django
from django.conf import global_settings
diff --git a/tox.ini b/tox.ini
index 1c71d1c..4b137b8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = black,py3-django22-coverage
+envlist = code-style,py3-django22-coverage
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/django-mellon/
[testenv]
@@ -55,12 +55,12 @@ commands =
./getlasso3.sh
django-admin {posargs:--help}
-[testenv:black]
+[testenv:code-style]
skip_install = true
deps =
pre-commit
commands =
- pre-commit run black --all-files --show-diff-on-failure
+ pre-commit run --all-files --show-diff-on-failure
[pytest]
junit_family=legacy