Projet

Général

Profil

0001-apply-isort-and-pyupgrade-55990.patch

Benjamin Dauvergne, 05 août 2021 11:14

Télécharger (29,7 ko)

Voir les différences:

Subject: [PATCH 1/2] apply isort and pyupgrade (#55990)

 .pre-commit-config.yaml                | 10 +++++
 README                                 | 14 +++++-
 mellon/adapters.py                     | 22 ++++------
 mellon/app_settings.py                 |  2 +-
 mellon/backends.py                     |  2 +-
 mellon/middleware.py                   |  5 +--
 mellon/migrations/0001_initial.py      |  7 +--
 mellon/migrations/0002_sessionindex.py |  2 +-
 mellon/models.py                       |  3 +-
 mellon/sessions_backends/db.py         |  4 +-
 mellon/urls.py                         |  5 +--
 mellon/utils.py                        | 14 +++---
 mellon/views.py                        | 61 +++++++++++---------------
 setup.py                               | 10 +++--
 tests/conftest.py                      |  4 +-
 tests/test_default_adapter.py          |  9 ++--
 tests/test_sso_slo.py                  | 46 ++++++++-----------
 tests/test_utils.py                    | 19 ++++----
 tests/test_views.py                    | 19 ++++----
 tests/urls_tests.py                    |  2 +-
 tests/urls_tests_template_base.py      |  2 +-
 tests/urls_tests_template_hook.py      |  2 +-
 testsettings.py                        |  1 +
 tox.ini                                |  6 +--
 24 files changed, 127 insertions(+), 144 deletions(-)
.pre-commit-config.yaml
6 6
    hooks:
7 7
    - id: black
8 8
      args: ['--target-version', 'py37', '--skip-string-normalization', '--line-length', '110']
9
-   repo: https://github.com/PyCQA/isort
10
    rev: 5.7.0
11
    hooks:
12
    - id: isort
13
      args: ['--profile', 'black', '--line-length', '110']
14
-   repo: https://github.com/asottile/pyupgrade
15
    rev: v2.20.0
16
    hooks:
17
    - id: pyupgrade
18
      args: ['--keep-percent-format', '--py37-plus']
README
319 319
   tox
320 320

  
321 321
Code Style
322
----------
322
==========
323 323

  
324 324
black is used to format the code, using thoses parameters:
325 325

  
......
328 328
There is .pre-commit-config.yaml to use pre-commit to automatically run black
329 329
before commits. (execute `pre-commit install` to install the git hook.)
330 330

  
331
isort is used to format the imports, using those parameter:
332

  
333
    isort --profile black --line-length 110
334

  
335
pyupgrade is used to automatically upgrade syntax, using those parameters:
336

  
337
    pyupgrade --keep-percent-format --py37-plus
338

  
339
There is .pre-commit-config.yaml to use pre-commit to automatically run black,
340
isort and pyupgrade before commits. (execute `pre-commit install` to install
341
the git hook.)
342

  
331 343
Remarks
332 344
=======
333 345

  
mellon/adapters.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18
from xml.etree import ElementTree as ET
19 17
import hashlib
20

  
21 18
import logging
22 19
import os
23 20
import threading
24 21
import time
25 22
import uuid
23
from xml.etree import ElementTree as ET
26 24

  
27 25
import lasso
28 26
import requests
29 27
import requests.exceptions
30 28
from atomicwrites import atomic_write
31

  
32
from django.core.exceptions import PermissionDenied, FieldDoesNotExist
33
from django.core.files.storage import default_storage
34
from django.contrib import auth
29
from django.contrib import auth, messages
35 30
from django.contrib.auth.models import Group
36
from django.contrib import messages
31
from django.core.exceptions import FieldDoesNotExist, PermissionDenied
32
from django.core.files.storage import default_storage
37 33
from django.utils import six
38 34
from django.utils.encoding import force_text
39 35
from django.utils.six.moves.urllib.parse import urlparse
40 36
from django.utils.translation import ugettext as _
41 37

  
42
from . import utils, app_settings, models
38
from . import app_settings, models, utils
43 39

  
44 40
User = auth.get_user_model()
45 41

  
......
51 47

  
52 48

  
53 49
def display_truncated_list(l, max_length=10):
54
    s = '[' + ', '.join(map(six.text_type, l))
50
    s = '[' + ', '.join(map(str, l))
55 51
    if len(l) > max_length:
56 52
        s += '..truncated more than %d items (%d)]' % (max_length, len(l))
57 53
    else:
......
59 55
    return s
60 56

  
61 57

  
62
class DefaultAdapter(object):
58
class DefaultAdapter:
63 59
    def __init__(self, request=None):
64 60
        self.request = request
65 61

  
......
153 149
                        idp['METADATA'] = fd.read()
154 150
                    # use file cache mtime as last_update time, prevent too many loading from different workers
155 151
                    last_update = max(last_update, os.stat(file_cache_path).st_mtime)
156
                except (IOError, OSError):
152
                except OSError:
157 153
                    warning('metadata url %s : error when loading the file cache %s', url, file_cache_path)
158 154

  
159 155
        # fresh cache, skip loading
......
305 301
        if saml_attributes['name_id_format'] == lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT:
306 302
            if transient_federation_attribute and saml_attributes.get(transient_federation_attribute):
307 303
                name_id = saml_attributes[transient_federation_attribute]
308
                if not isinstance(name_id, six.string_types):
304
                if not isinstance(name_id, str):
309 305
                    if len(name_id) == 1:
310 306
                        name_id = name_id[0]
311 307
                    else:
mellon/app_settings.py
1 1
import sys
2 2

  
3 3

  
4
class AppSettings(object):
4
class AppSettings:
5 5
    __PREFIX = 'MELLON_'
6 6
    __DEFAULTS = {
7 7
        'IDENTITY_PROVIDERS': [],
mellon/backends.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
16

  
17 17
import logging
18 18

  
19 19
from django.contrib.auth.backends import ModelBackend
mellon/middleware.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18
from django.utils.http import urlencode
19 17
from django.http import HttpResponseRedirect
20
from django.utils.deprecation import MiddlewareMixin
21 18
from django.urls import reverse
19
from django.utils.deprecation import MiddlewareMixin
20
from django.utils.http import urlencode
22 21

  
23 22
from . import app_settings, utils
24 23

  
mellon/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import models, migrations
5 1
from django.conf import settings
2
from django.db import migrations, models
6 3

  
7 4

  
8 5
class Migration(migrations.Migration):
......
40 37
        ),
41 38
        migrations.AlterUniqueTogether(
42 39
            name='usersamlidentifier',
43
            unique_together=set([('issuer', 'name_id')]),
40
            unique_together={('issuer', 'name_id')},
44 41
        ),
45 42
    ]
mellon/migrations/0002_sessionindex.py
1 1
# Generated by Django 2.2.12 on 2020-04-24 05:14
2 2

  
3
from django.db import migrations, models
4 3
import django.db.models.deletion
4
from django.db import migrations, models
5 5

  
6 6

  
7 7
class Migration(migrations.Migration):
mellon/models.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18 17
from importlib import import_module
19 18

  
19
from django.conf import settings
20 20
from django.db import models
21 21
from django.utils.translation import ugettext_lazy as _
22
from django.conf import settings
23 22

  
24 23

  
25 24
class UserSAMLIdentifier(models.Model):
mellon/sessions_backends/db.py
29 29
        session_not_on_or_after = self.get_session_not_on_or_after()
30 30
        if session_not_on_or_after and 'expiry' not in kwargs:
31 31
            kwargs['expiry'] = session_not_on_or_after
32
        return super(SessionStore, self).get_expiry_age(**kwargs)
32
        return super().get_expiry_age(**kwargs)
33 33

  
34 34
    def get_expiry_date(self, **kwargs):
35 35
        session_not_on_or_after = self.get_session_not_on_or_after()
36 36
        if session_not_on_or_after and 'expiry' not in kwargs:
37 37
            kwargs['expiry'] = session_not_on_or_after
38
        return super(SessionStore, self).get_expiry_date(**kwargs)
38
        return super().get_expiry_date(**kwargs)
mellon/urls.py
1
from __future__ import unicode_literals
2

  
3
from django.conf.urls import url
4 1
import django
2
from django.conf.urls import url
5 3

  
6 4
from . import views
7 5

  
8

  
9 6
urlpatterns = [
10 7
    url('login/$', views.login, name='mellon_login'),
11 8
    url('login/debug/$', views.debug_login, name='mellon_debug_login'),
mellon/utils.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18
import logging
19 17
import datetime
20 18
import importlib
19
import logging
21 20
from functools import wraps
22
import isodate
23 21
from xml.parsers import expat
24 22

  
23
import isodate
24
import lasso
25
from django.conf import settings
25 26
from django.contrib import auth
26 27
from django.template.loader import render_to_string
27 28
from django.urls import reverse
28 29
from django.utils.encoding import force_text
29
from django.utils.timezone import make_aware, now, make_naive, is_aware, get_default_timezone
30
from django.conf import settings
31 30
from django.utils.six.moves.urllib.parse import urlparse
32
import lasso
31
from django.utils.timezone import get_default_timezone, is_aware, make_aware, make_naive, now
33 32

  
34 33
from . import app_settings
35 34

  
......
133 132
def get_idps():
134 133
    for adapter in get_adapters():
135 134
        if hasattr(adapter, 'get_idps'):
136
            for idp in adapter.get_idps():
137
                yield idp
135
            yield from adapter.get_idps()
138 136

  
139 137

  
140 138
def flatten_datetime(d):
mellon/views.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
17
import logging
18
import uuid
19
import xml.etree.ElementTree as ET
18 20
from contextlib import contextmanager, nullcontext
19 21
from importlib import import_module
20 22
from io import StringIO
21
import logging
22
import requests
23
import lasso
24
import uuid
25
from requests.exceptions import RequestException
26 23
from xml.sax.saxutils import escape
27
import xml.etree.ElementTree as ET
28 24

  
29 25
import django.http
30
from django.views.generic import View
31
from django.views.generic.base import RedirectView
32
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden
33
from django.contrib import auth
34
from django.contrib.auth import get_user_model
26
import lasso
27
import requests
35 28
from django.conf import settings
36
from django.views.decorators.csrf import csrf_exempt
29
from django.contrib import auth
30
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
31
from django.db import transaction
32
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
37 33
from django.shortcuts import render, resolve_url
38 34
from django.urls import reverse
39
from django.utils.http import urlencode
40 35
from django.utils import six
41
from django.utils.encoding import force_text, force_str
42
from django.contrib.auth import REDIRECT_FIELD_NAME
43
from django.db import transaction
36
from django.utils.encoding import force_str, force_text
37
from django.utils.http import urlencode
44 38
from django.utils.translation import ugettext as _
39
from django.views.decorators.csrf import csrf_exempt
40
from django.views.generic import View
41
from django.views.generic.base import RedirectView
42
from requests.exceptions import RequestException
45 43

  
46
from . import app_settings, utils, models
47

  
44
from . import app_settings, models, utils
48 45

  
49 46
RETRY_LOGIN_COOKIE = 'MELLON_RETRY_LOGIN'
50 47

  
51 48
lasso.setFlag('thin-sessions')
52 49

  
53
if six.PY3:
54

  
55
    def lasso_decode(x):
56
        return x
57

  
58

  
59
else:
60 50

  
61
    def lasso_decode(x):
62
        return x.decode('utf-8')
51
def lasso_decode(x):
52
    return x
63 53

  
64 54

  
65 55
EO_NS = 'https://www.entrouvert.com/'
......
71 61
class HttpResponseBadRequest(django.http.HttpResponseBadRequest):
72 62
    def __init__(self, *args, **kwargs):
73 63
        kwargs['content_type'] = kwargs.get('content_type', 'text/plain')
74
        super(HttpResponseBadRequest, self).__init__(*args, **kwargs)
64
        super().__init__(*args, **kwargs)
75 65
        self['X-Content-Type-Options'] = 'nosniff'
76 66

  
77 67

  
78
class LogMixin(object):
68
class LogMixin:
79 69
    """Initialize a module logger in new objects"""
80 70

  
81 71
    def __init__(self, *args, **kwargs):
82 72
        self.log = logging.getLogger(__name__)
83
        super(LogMixin, self).__init__(*args, **kwargs)
73
        super().__init__(*args, **kwargs)
84 74

  
85 75

  
86 76
def check_next_url(request, next_url):
......
101 91
    return next_url
102 92

  
103 93

  
104
class ProfileMixin(object):
94
class ProfileMixin:
105 95
    profile = None
106 96

  
107 97
    def set_next_url(self, next_url):
......
507 497
            # configure requested AuthnClassRef
508 498
            authn_classref = utils.get_setting(idp, 'AUTHN_CLASSREF')
509 499
            if authn_classref:
510
                authn_classref = tuple([str(x) for x in authn_classref])
500
                authn_classref = tuple(str(x) for x in authn_classref)
511 501
                req_authncontext = lasso.Samlp2RequestedAuthnContext()
512 502
                authn_request.requestedAuthnContext = req_authncontext
513 503
                req_authncontext.authnContextClassRef = authn_classref
......
550 540
        assert hasattr(authn_request.extensions, 'any'), 'extension nodes need lasso > 2.5.1'
551 541
        serialized = ET.tostring(node, 'utf-8')
552 542
        # tostring return bytes in PY3, but lasso needs str
553
        if six.PY3:
554
            serialized = serialized.decode('utf-8')
543
        serialized = serialized.decode('utf-8')
555 544
        extension_content = authn_request.extensions.any or ()
556 545
        extension_content += (serialized,)
557 546
        authn_request.extensions.any = extension_content
......
653 642
            return HttpResponseBadRequest('error processing logout request: %r' % e)
654 643

  
655 644
        issuer = force_text(logout.remoteProviderId)
656
        session_indexes = set(force_text(sessionIndex) for sessionIndex in logout.request.sessionIndexes)
645
        session_indexes = {force_text(sessionIndex) for sessionIndex in logout.request.sessionIndexes}
657 646

  
658 647
        saml_identifier = (
659 648
            models.UserSAMLIdentifier.objects.filter(
setup.py
5 5

  
6 6
import os
7 7
import subprocess
8
from setuptools import setup, find_packages
9
from setuptools.command.install_lib import install_lib as _install_lib
8
from distutils.cmd import Command
10 9
from distutils.command.build import build as _build
10

  
11
from setuptools import find_packages, setup
12
from setuptools.command.install_lib import install_lib as _install_lib
11 13
from setuptools.command.sdist import sdist as _sdist
12
from distutils.cmd import Command
13 14

  
14 15

  
15 16
class compile_translations(Command):
......
24 25

  
25 26
    def run(self):
26 27
        import os
28

  
27 29
        from django.core.management import call_command
28 30

  
29 31
        os.environ.pop('DJANGO_SETTINGS_MODULE', None)
......
68 70
    tag exists, take 0.0.0- and add the length of the commit log.
69 71
    """
70 72
    if os.path.exists('VERSION'):
71
        with open('VERSION', 'r') as v:
73
        with open('VERSION') as v:
72 74
            return v.read()
73 75
    if os.path.exists('.git'):
74 76
        p = subprocess.Popen(
tests/conftest.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
import os
17 16
import logging
17
import os
18 18

  
19
import pytest
20 19
import django_webtest
20
import pytest
21 21

  
22 22

  
23 23
@pytest.fixture(autouse=True)
tests/test_default_adapter.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18 17
import datetime
19 18
import re
20
import lasso
21 19
import time
22 20
from multiprocessing.pool import ThreadPool
21
from unittest import mock
23 22

  
24
import mock
23
import lasso
25 24
import pytest
26

  
27 25
from django.contrib import auth
28 26
from django.db import connection
29 27

  
30 28
from mellon.adapters import DefaultAdapter
31 29
from mellon.backends import SAMLBackend
32 30

  
33

  
34 31
pytestmark = pytest.mark.django_db
35 32

  
36 33
User = auth.get_user_model()
......
119 116
    users = p.map(f, range(concurrency))
120 117

  
121 118
    assert len(users) == concurrency
122
    assert len(set(user.pk for user in users)) == 1
119
    assert len({user.pk for user in users}) == 1
123 120

  
124 121

  
125 122
def test_provision_user_attributes(settings, django_user_model, idp, saml_attributes, caplog):
tests/test_sso_slo.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
17
import base64
18 18
import datetime
19
from html import unescape
20 19
import re
21
import base64
22
import zlib
23 20
import xml.etree.ElementTree as ET
21
import zlib
22
from html import unescape
24 23

  
25 24
import lasso
26

  
27 25
import pytest
28
from pytest import fixture
29

  
30
from django.contrib.sessions.models import Session
31 26
from django.contrib.auth.models import User
27
from django.contrib.sessions.models import Session
32 28
from django.urls import reverse
33 29
from django.utils import six
34
from django.utils.six.moves.urllib import parse as urlparse
35 30
from django.utils.encoding import force_str
31
from django.utils.six.moves.urllib import parse as urlparse
32
from httmock import HTTMock, all_requests
33
from httmock import response as mock_response
34
from pytest import fixture
36 35

  
37 36
from mellon.utils import create_metadata
38 37
from mellon.views import lasso_decode
39 38

  
40
from httmock import all_requests, HTTMock, response as mock_response
41

  
42 39

  
43 40
@fixture
44 41
def idp_metadata():
......
81 78
    return create_metadata(request)
82 79

  
83 80

  
84
class MockIdp(object):
81
class MockIdp:
85 82
    session_dump = None
86 83
    identity_dump = None
87 84

  
......
240 237
    assert 'created new user' in caplog.text
241 238
    assert 'logged in using SAML' in caplog.text
242 239
    assert urlparse.urlparse(response['Location']).path == '/whatever/'
243
    response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': str('/some/path')})
240
    response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'})
244 241
    assert urlparse.urlparse(response['Location']).path == '/singleLogout'
245 242
    # again, user is already logged out
246
    response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': str('/some/path')})
243
    response = app.get(reverse('mellon_logout'), extra_environ={'HTTP_REFERER': '/some/path'})
247 244
    assert urlparse.urlparse(response['Location']).path == '/some/path'
248 245

  
249 246

  
......
433 430
    assert not relay_state
434 431
    assert url.endswith(reverse('mellon_login'))
435 432
    response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state})
436
    if six.PY3:
437
        assert (
438
            "status is not success codes: ['urn:oasis:names:tc:SAML:2.0:status:Responder',\
433
    assert (
434
        "status is not success codes: ['urn:oasis:names:tc:SAML:2.0:status:Responder',\
439 435
 'urn:oasis:names:tc:SAML:2.0:status:RequestDenied']"
440
            in caplog.text
441
        )
442
    else:
443
        assert (
444
            "status is not success codes: [u'urn:oasis:names:tc:SAML:2.0:status:Responder',\
445
 u'urn:oasis:names:tc:SAML:2.0:status:RequestDenied']"
446
            in caplog.text
447
        )
436
        in caplog.text
437
    )
448 438

  
449 439

  
450 440
@pytest.mark.urls('urls_tests_template_base')
......
663 653
    settings.MELLON_OPENED_SESSION_COOKIE_NAME = 'IDP_SESSION'
664 654
    assert 'MELLON_PASSIVE_TRIED' not in app.cookies
665 655
    # webtest-lint is against unicode
666
    app.set_cookie(str('IDP_SESSION'), str('1'))
656
    app.set_cookie('IDP_SESSION', '1')
667 657
    response = app.get('/', headers={'Accept': force_str('text/html')}, status=302)
668 658
    assert urlparse.urlparse(response.location).path == '/login/'
669 659
    assert urlparse.parse_qs(urlparse.urlparse(response.location).query, keep_blank_values=True) == {
......
681 671
    assert 'MELLON_PASSIVE_TRIED' not in app.cookies
682 672

  
683 673
    # check passive authentication is tried again
684
    app.set_cookie(str('IDP_SESSION'), str('1'))
674
    app.set_cookie('IDP_SESSION', '1')
685 675
    response = app.get('/', headers={'Accept': force_str('text/html')}, status=302)
686 676
    assert urlparse.urlparse(response.location).path == '/login/'
687 677
    assert urlparse.parse_qs(urlparse.urlparse(response.location).query, keep_blank_values=True) == {
......
695 685
    settings.MELLON_OPENED_SESSION_COOKIE_NAME = 'IDP_SESSION'
696 686
    assert 'MELLON_PASSIVE_TRIED' not in app.cookies
697 687
    # webtest-lint is against unicode
698
    app.set_cookie(str('IDP_SESSION'), str('1'))
688
    app.set_cookie('IDP_SESSION', '1')
699 689
    app.get('/?no-passive-auth', headers={'Accept': force_str('text/html')}, status=200)
700 690

  
701 691

  
tests/test_utils.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18 17
import datetime
18
from unittest import mock
19 19

  
20
import mock
21 20
import lasso
21
from xml_utils import assert_xml_constraints
22 22

  
23
from mellon.utils import create_metadata, iso8601_to_datetime, flatten_datetime
23
from mellon.utils import create_metadata, flatten_datetime, iso8601_to_datetime
24 24
from mellon.views import check_next_url
25
from xml_utils import assert_xml_constraints
26 25

  
27 26

  
28 27
def test_create_metadata(rf, private_settings, caplog):
......
144 143
        'y': 1,
145 144
        'z': 'u',
146 145
    }
147
    assert set(flatten_datetime(d).keys()) == set(['x', 'y', 'z'])
146
    assert set(flatten_datetime(d).keys()) == {'x', 'y', 'z'}
148 147
    assert flatten_datetime(d)['x'] == '2010-10-10T10:10:34'
149 148
    assert flatten_datetime(d)['y'] == 1
150 149
    assert flatten_datetime(d)['z'] == 'u'
151 150

  
152 151

  
153 152
def test_check_next_url(rf):
154
    assert not check_next_url(rf.get('/'), u'')
153
    assert not check_next_url(rf.get('/'), '')
155 154
    assert not check_next_url(rf.get('/'), None)
156
    assert not check_next_url(rf.get('/'), u'\x00')
157
    assert not check_next_url(rf.get('/'), u'\u010e')
158
    assert not check_next_url(rf.get('/'), u'https://example.invalid/')
155
    assert not check_next_url(rf.get('/'), '\x00')
156
    assert not check_next_url(rf.get('/'), '\u010e')
157
    assert not check_next_url(rf.get('/'), 'https://example.invalid/')
159 158
    # default hostname is testserver
160
    assert check_next_url(rf.get('/'), u'http://testserver/ok/')
159
    assert check_next_url(rf.get('/'), 'http://testserver/ok/')
tests/test_views.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17 16

  
18
import pytest
19
import mock
20
import lasso
21
from django.utils.six.moves.urllib.parse import parse_qs, urlparse
22 17
import base64
23 18
import hashlib
24
from httmock import HTTMock
19
from unittest import mock
25 20

  
21
import lasso
22
import pytest
26 23
from django.urls import reverse
27 24
from django.utils.encoding import force_text
28 25
from django.utils.http import urlencode
29

  
30
from xml_utils import assert_xml_constraints
31

  
26
from django.utils.six.moves.urllib.parse import parse_qs, urlparse
27
from httmock import HTTMock
32 28
from utils import error_500, html_response
29
from xml_utils import assert_xml_constraints
33 30

  
34 31
pytestmark = pytest.mark.django_db
35 32

  
......
207 204
    assert response.status_code == 302
208 205
    params = parse_qs(urlparse(response['Location']).query)
209 206
    assert response['Location'].startswith('http://idp5/singleSignOn?')
210
    assert set(params.keys()) == set(['SAMLRequest', 'RelayState'])
207
    assert set(params.keys()) == {'SAMLRequest', 'RelayState'}
211 208
    assert len(params['SAMLRequest']) == 1
212 209
    assert base64.b64decode(params['SAMLRequest'][0])
213 210
    assert client.session['mellon_next_url_%s' % params['RelayState'][0]] == '/whatever'
......
229 226
    assert response.status_code == 302
230 227
    params = parse_qs(urlparse(response['Location']).query)
231 228
    assert response['Location'].startswith('http://idp5/singleSignOn?')
232
    assert set(params.keys()) == set(['SAMLRequest', 'RelayState'])
229
    assert set(params.keys()) == {'SAMLRequest', 'RelayState'}
233 230
    assert len(params['SAMLRequest']) == 1
234 231
    assert base64.b64decode(params['SAMLRequest'][0])
235 232
    assert client.session['mellon_next_url_%s' % params['RelayState'][0]] == '/whatever'
tests/urls_tests.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from django.conf.urls import url, include
16
from django.conf.urls import include, url
17 17
from django.http import HttpResponse
18 18

  
19 19

  
tests/urls_tests_template_base.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from django.conf.urls import url, include
16
from django.conf.urls import include, url
17 17
from django.http import HttpResponse
18 18

  
19 19

  
tests/urls_tests_template_hook.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from django.conf.urls import url, include
16
from django.conf.urls import include, url
17 17
from django.http import HttpResponse
18 18

  
19 19

  
testsettings.py
1 1
import os
2

  
2 3
import django
3 4
from django.conf import global_settings
4 5

  
tox.ini
1 1
[tox]
2
envlist = black,py3-django22-coverage
2
envlist = code-style,py3-django22-coverage
3 3
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/django-mellon/
4 4

  
5 5
[testenv]
......
55 55
  ./getlasso3.sh
56 56
  django-admin {posargs:--help}
57 57

  
58
[testenv:black]
58
[testenv:code-style]
59 59
skip_install = true
60 60
deps =
61 61
  pre-commit
62 62
commands =
63
  pre-commit run black --all-files --show-diff-on-failure
63
  pre-commit run --all-files --show-diff-on-failure
64 64

  
65 65
[pytest]
66 66
junit_family=legacy
67
-