Projet

Général

Profil

0001-misc-apply-pyupgrade-55519.patch

Valentin Deniaud, 12 juillet 2021 12:04

Télécharger (391 ko)

Voir les différences:

Subject: [PATCH 1/2] misc: apply pyupgrade (#55519)

 merge-coverage.py                             |  11 +-
 setup.py                                      |   2 +-
 src/authentic2/a2_rbac/admin.py               |   4 +-
 src/authentic2/a2_rbac/app_settings.py        |   2 +-
 src/authentic2/a2_rbac/fields.py              |   4 +-
 src/authentic2/a2_rbac/management.py          |   2 +-
 .../a2_rbac/migrations/0001_initial.py        |   9 +-
 .../migrations/0002_role_external_id.py       |   3 -
 ...3_partial_unique_index_on_name_and_slug.py |   3 -
 .../migrations/0004_auto_20150523_0028.py     |   5 +-
 .../migrations/0005_auto_20150526_1406.py     |   3 -
 .../migrations/0006_auto_20150619_1056.py     |   3 -
 .../migrations/0007_auto_20150708_1337.py     |   3 -
 .../migrations/0008_auto_20150810_1953.py     |   3 -
 ...0009_partial_unique_index_on_permission.py |   3 -
 .../migrations/0010_auto_20160209_1417.py     |   7 +-
 .../migrations/0011_auto_20160209_1511.py     |   5 +-
 .../migrations/0013_auto_20170629_0007.py     |   7 +-
 .../migrations/0014_auto_20170711_1024.py     |   3 -
 ...0015_organizationalunit_validate_emails.py |   3 -
 .../migrations/0016_auto_20171208_1429.py     |   3 -
 ...anizationalunit_user_can_reset_password.py |   3 -
 ...nizationalunit_user_add_password_policy.py |   3 -
 .../0019_organizationalunit_show_username.py  |   2 -
 .../0020_partial_unique_index_on_name.py      |   3 -
 .../migrations/0021_auto_20200317_1514.py     |   2 -
 .../migrations/0022_auto_20200402_1101.py     |   2 -
 .../0023_role_can_manage_members.py           |   2 -
 .../migrations/0024_fix_self_admin_perm.py    |   2 -
 src/authentic2/a2_rbac/models.py              |  12 +-
 src/authentic2/admin.py                       |  16 +-
 src/authentic2/api_mixins.py                  |   6 +-
 src/authentic2/api_views.py                   |  64 ++---
 src/authentic2/app_settings.py                |   4 +-
 .../migrations/0001_initial.py                |   5 +-
 .../migrations/0002_auto_20150409_1840.py     |   3 -
 .../migrations/0003_auto_20150526_2239.py     |   3 -
 .../migrations/0004_auto_20150915_2041.py     |   3 -
 src/authentic2/attribute_kinds.py             |  16 +-
 src/authentic2/attributes_ng/engine.py        |   5 +-
 .../attributes_ng/sources/__init__.py         |   2 +-
 .../attributes_ng/sources/format.py           |   2 +-
 .../attributes_ng/sources/function.py         |   4 +-
 .../auth2_auth/auth2_ssl/__init__.py          |   2 +-
 .../auth2_ssl/migrations/0001_initial.py      |   3 -
 .../migrations/0002_auto_20150409_1840.py     |   3 -
 .../migrations/0003_auto_20190614_1438.py     |   2 -
 .../auth_migrations_18/0001_initial.py        |   3 -
 .../0002_auto_20150323_1720.py                |   3 -
 .../0003_auto_20150410_1657.py                |   3 -
 .../auth_migrations_18/0004_user.py           |   3 -
 .../0005_auto_20150526_2303.py                |   3 -
 src/authentic2/authentication.py              |  13 +-
 src/authentic2/authenticators.py              |   2 +-
 src/authentic2/backends/ldap_backend.py       |  37 ++-
 src/authentic2/backends/models_backend.py     |   3 +-
 src/authentic2/cbv.py                         |  18 +-
 src/authentic2/compat_lasso.py                |   2 +-
 src/authentic2/context_processors.py          |   4 +-
 src/authentic2/csv_import.py                  |  23 +-
 .../management/commands/changepassword.py     |   1 -
 .../management/commands/fix-attributes.py     |   1 -
 .../custom_user/migrations/0001_initial.py    |   3 -
 .../migrations/0002_auto_20150410_1823.py     |  11 +-
 .../migrations/0003_auto_20150504_1410.py     |   3 -
 .../custom_user/migrations/0004_user_ou.py    |   3 -
 .../migrations/0005_auto_20150522_1527.py     |   3 -
 .../migrations/0006_auto_20150527_1212.py     |   3 -
 .../migrations/0007_auto_20150610_1527.py     |   3 -
 .../migrations/0008_auto_20150617_1606.py     |   3 -
 .../migrations/0009_auto_20150810_1953.py     |   3 -
 .../migrations/0010_auto_20160307_1418.py     |   3 -
 ...manual_attribute_values_for_name_fields.py |   3 -
 .../migrations/0012_user_modified.py          |   3 -
 .../migrations/0013_user_email_verified.py    |   3 -
 .../migrations/0014_set_email_verified.py     |   3 -
 .../migrations/0015_auto_20170707_1653.py     |   3 -
 .../migrations/0016_auto_20180925_1107.py     |   2 -
 .../migrations/0017_auto_20200305_1645.py     |   2 -
 .../0018_user_last_account_deletion_alert.py  |   2 -
 .../migrations/0019_add_user_deleted.py       |   2 -
 .../migrations/0021_set_unusable_password.py  |   2 -
 .../migrations/0025_user_deactivation.py      |   2 -
 src/authentic2/custom_user/models.py          |  18 +-
 src/authentic2/data_transfer.py               |   9 +-
 src/authentic2/decorators.py                  |  20 +-
 src/authentic2/exponential_retry_timeout.py   |   6 +-
 src/authentic2/forms/authentication.py        |   4 +-
 src/authentic2/forms/fields.py                |  10 +-
 src/authentic2/forms/mixins.py                |   4 +-
 src/authentic2/forms/passwords.py             |   8 +-
 src/authentic2/forms/profile.py               |   8 +-
 src/authentic2/forms/registration.py          |   4 +-
 src/authentic2/forms/utils.py                 |   2 +-
 src/authentic2/forms/widgets.py               |  28 +-
 src/authentic2/hooks.py                       |   4 +-
 src/authentic2/idp/__init__.py                |   1 -
 src/authentic2/idp/migrations/0001_initial.py |   3 -
 .../idp/migrations/0002_auto_20150526_2239.py |   3 -
 .../idp/migrations/0003_auto_20150915_2041.py |   3 -
 src/authentic2/idp/saml/__init__.py           |   2 +-
 src/authentic2/idp/saml/app_settings.py       |   2 +-
 src/authentic2/idp/saml/backend.py            |  14 +-
 src/authentic2/idp/saml/saml2_endpoints.py    |  31 +-
 src/authentic2/idp/saml/views.py              |   2 +-
 src/authentic2/ldap_utils.py                  |  16 +-
 src/authentic2/logger.py                      |   6 +-
 .../management/commands/check-and-repair.py   |   5 +-
 .../commands/clean-unused-accounts.py         |   1 -
 .../management/commands/import_site.py        |   2 +-
 .../management/commands/slapd-shell.py        |   3 +-
 .../management/commands/sync-ldap-users.py    |   1 -
 src/authentic2/manager/app_settings.py        |   2 +-
 src/authentic2/manager/fields.py              |   6 +-
 src/authentic2/manager/forms.py               |  56 ++--
 src/authentic2/manager/ou_views.py            |   4 +-
 src/authentic2/manager/role_views.py          |  58 ++--
 src/authentic2/manager/service_views.py       |   6 +-
 src/authentic2/manager/tables.py              |   4 +-
 src/authentic2/manager/user_export.py         |   8 +-
 src/authentic2/manager/user_import.py         |   7 +-
 src/authentic2/manager/user_views.py          |  63 ++---
 src/authentic2/manager/utils.py               |   6 +-
 src/authentic2/manager/views.py               |  84 +++---
 src/authentic2/manager/widgets.py             |  10 +-
 src/authentic2/migrations/0001_initial.py     |   3 -
 .../migrations/0002_auto_20150320_1418.py     |   3 -
 .../migrations/0003_auto_20150409_1840.py     |   3 -
 src/authentic2/migrations/0004_service.py     |   3 -
 src/authentic2/migrations/0005_service_ou.py  |   5 +-
 .../migrations/0006_conditional_slug_index.py |   3 -
 .../migrations/0007_auto_20150523_0028.py     |   3 -
 .../migrations/0008_auto_20160204_1415.py     |   3 -
 .../migrations/0009_auto_20160211_2247.py     |   3 -
 .../0010_attributevalue_multiple.py           |   3 -
 .../migrations/0011_auto_20160211_2253.py     |   3 -
 .../migrations/0012_auto_20160211_2255.py     |   3 -
 .../migrations/0013_auto_20160211_2258.py     |   5 +-
 .../0014_attributevalue_verified.py           |   3 -
 .../migrations/0015_auto_20160621_1711.py     |   3 -
 .../migrations/0016_attribute_disabled.py     |   3 -
 .../0017_modify_attribute_serialization.py    |   1 -
 .../migrations/0018_auto_20170524_0842.py     |   3 -
 .../migrations/0019_auto_20170309_1529.py     |   3 -
 .../migrations/0020_delete_federatedid.py     |   3 -
 .../migrations/0021_attribute_order.py        |   3 -
 .../migrations/0022_attribute_scopes.py       |   3 -
 .../migrations/0023_auto_20181031_0900.py     |   2 -
 .../migrations/0024_auto_20190617_1113.py     |   4 +-
 .../migrations/0025_auto_20191009_1047.py     |   2 -
 src/authentic2/migrations/0026_token.py       |   2 -
 .../migrations/0027_remove_deleteduser.py     |   2 -
 .../migrations/0028_trigram_unaccent_index.py |   1 -
 .../migrations/0029_auto_20201013_1614.py     |   2 -
 src/authentic2/models.py                      |  11 +-
 .../nonce/migrations/0001_initial.py          |   3 -
 src/authentic2/passwords.py                   |   6 +-
 src/authentic2/saml/admin.py                  |  14 +-
 src/authentic2/saml/admin_views.py            |   8 +-
 src/authentic2/saml/app_settings.py           |   2 +-
 src/authentic2/saml/fields.py                 |   6 +-
 src/authentic2/saml/forms.py                  |   2 +-
 src/authentic2/saml/lasso_helper.py           |   4 +-
 .../saml/management/commands/sync-metadata.py |   3 +-
 .../saml/migrations/0001_initial.py           |   9 +-
 .../migrations/0002_auto_20150320_1245.py     |   3 -
 .../0002_ease_federation_migration.py         |   3 -
 src/authentic2/saml/migrations/0003_merge.py  |   3 -
 .../migrations/0004_auto_20150410_1438.py     |   3 -
 ...e_liberty_provider_inherit_from_service.py |   3 -
 .../migrations/0006_restore_foreign_keys.py   |   3 -
 .../0007_copy_service_ptr_id_to_old_id.py     |   3 -
 .../migrations/0008_alter_foreign_keys.py     |   3 -
 src/authentic2/saml/migrations/0009_auto.py   |   3 -
 src/authentic2/saml/migrations/0010_auto.py   |   3 -
 src/authentic2/saml/migrations/0011_auto.py   |   3 -
 .../migrations/0012_auto_20150526_2239.py     |   3 -
 .../migrations/0013_auto_20150617_1004.py     |   3 -
 .../migrations/0014_auto_20150617_1216.py     |   5 +-
 .../migrations/0015_auto_20150915_2032.py     |   3 -
 .../migrations/0016_auto_20150915_2041.py     |   3 -
 .../migrations/0017_auto_20170710_1738.py     |   3 -
 src/authentic2/saml/models.py                 |   8 +-
 src/authentic2/saml/saml2utils.py             |   3 +-
 src/authentic2/saml/shibboleth/afp_parser.py  |   3 +-
 src/authentic2/saml/shibboleth/utils.py       |   6 +-
 src/authentic2/serializers.py                 |   5 +-
 src/authentic2/user_login_failure.py          |   4 +-
 src/authentic2/utils/__init__.py              |  23 +-
 src/authentic2/utils/evaluate.py              |   8 +-
 src/authentic2/utils/lazy.py                  |   1 -
 src/authentic2/utils/lookups.py               |   4 +-
 src/authentic2/utils/template.py              |   2 +-
 src/authentic2/validators.py                  |   5 +-
 src/authentic2/views.py                       | 100 ++++---
 src/authentic2_auth_fc/app_settings.py        |   2 +-
 src/authentic2_auth_fc/apps.py                |   2 +-
 .../migrations/0001_initial.py                |   3 -
 .../migrations/0002_auto_20200416_1439.py     |   2 -
 .../migrations/0003_fcaccount_order1.py       |   2 -
 .../migrations/0004_fcaccount_order2.py       |   4 +-
 src/authentic2_auth_fc/utils.py               |   4 +-
 src/authentic2_auth_fc/views.py               |   2 +-
 src/authentic2_auth_oidc/admin.py             |   2 +-
 src/authentic2_auth_oidc/app_settings.py      |   2 +-
 src/authentic2_auth_oidc/apps.py              |   2 +-
 .../commands/oidc-register-issuer.py          |   1 -
 .../migrations/0001_initial.py                |   3 -
 ..._oidcprovider_token_revocation_endpoint.py |   3 -
 .../migrations/0003_oidcprovider_show.py      |   3 -
 .../migrations/0004_auto_20171017_1522.py     |   3 -
 .../migrations/0005_oidcprovider_slug.py      |   2 -
 ...oidcprovider_claims_parameter_supported.py |   3 -
 .../migrations/0007_auto_20200317_1732.py     |   2 -
 src/authentic2_auth_oidc/models.py            |   4 +-
 src/authentic2_auth_oidc/utils.py             |  36 +--
 src/authentic2_auth_oidc/views.py             |   2 +-
 src/authentic2_auth_saml/adapters.py          |   7 +-
 src/authentic2_auth_saml/app_settings.py      |   2 +-
 src/authentic2_auth_saml/backends.py          |   2 +-
 src/authentic2_idp_cas/admin.py               |   8 +-
 src/authentic2_idp_cas/app_settings.py        |   2 +-
 src/authentic2_idp_cas/apps.py                |   2 +-
 .../migrations/0001_initial.py                |   5 +-
 .../migrations/0002_auto_20150410_1438.py     |   3 -
 .../migrations/0003_auto_20150415_2223.py     |   3 -
 .../migrations/0004_create_services.py        |   3 -
 .../0005_alter_field_service_ptr.py           |   3 -
 .../migrations/0006_copy_proxy_m2m.py         |   3 -
 .../migrations/0007_alter_service.py          |   3 -
 .../migrations/0008_alter_foreign_keys.py     |   3 -
 .../migrations/0009_alter_related_models.py   |   3 -
 .../0010_copy_service_ptr_id_to_old_id.py     |   3 -
 .../0011_remove_old_id_restore_proxy.py       |   3 -
 .../0012_copy_service_proxy_to_m2m.py         |   3 -
 .../0013_delete_model_service_proxy2.py       |   3 -
 .../migrations/0014_auto_20151204_1606.py     |   3 -
 .../migrations/0015_auto_20170406_1825.py     |   3 -
 src/authentic2_idp_cas/models.py              |   4 +-
 src/authentic2_idp_cas/views.py               |   2 +-
 src/authentic2_idp_oidc/admin.py              |  10 +-
 src/authentic2_idp_oidc/app_settings.py       |   2 +-
 src/authentic2_idp_oidc/apps.py               |   2 +-
 .../migrations/0001_initial.py                |   3 -
 .../migrations/0002_auto_20170121_2346.py     |   3 -
 .../migrations/0003_auto_20170329_1259.py     |   3 -
 .../migrations/0004_auto_20170324_1426.py     |   3 -
 .../migrations/0005_authorization_mode.py     |   3 -
 .../migrations/0006_auto_20170720_1054.py     |   3 -
 .../0007_oidcclient_has_api_access.py         |   3 -
 .../0008_oidcclient_idtoken_duration.py       |   3 -
 .../migrations/0009_auto_20180313_1156.py     |   3 -
 .../migrations/0010_oidcclaim.py              |   3 -
 .../migrations/0011_auto_20180808_1546.py     |   3 -
 .../migrations/0012_auto_20200122_2258.py     |   2 -
 src/authentic2_idp_oidc/models.py             |   2 +-
 src/authentic2_idp_oidc/utils.py              |   2 +-
 src/authentic2_idp_oidc/views.py              |   4 +-
 src/django_rbac/backends.py                   |   4 +-
 src/django_rbac/context_processors.py         |   6 +-
 .../management/commands/cleanup_rbac.py       |   2 -
 src/django_rbac/migrations/0001_initial.py    |   3 -
 ...ionalunit_permission_role_roleparenting.py |   3 -
 .../0003_add_max_aggregate_for_postgres.py    |   3 -
 .../migrations/0004_auto_20150708_1337.py     |   3 -
 .../migrations/0005_auto_20171209_1106.py     |   3 -
 src/django_rbac/models.py                     |  10 +-
 tests/auth_fc/test_auth_fc.py                 |   3 +-
 tests/auth_fc/test_auth_fc_api.py             |   1 -
 tests/conftest.py                             |  23 +-
 tests/idp_oidc/test_api.py                    |   2 +-
 tests/idp_oidc/test_misc.py                   |  14 +-
 tests/test_a2_rbac.py                         |  20 +-
 tests/test_admin.py                           |  34 +--
 tests/test_all.py                             |  15 +-
 tests/test_api.py                             | 267 ++++++++----------
 tests/test_attribute_kinds.py                 |   1 -
 tests/test_auth_oidc.py                       |  15 +-
 tests/test_commands.py                        |   4 +-
 tests/test_crypto.py                          |   1 -
 tests/test_csv_import.py                      |   6 +-
 tests/test_custom_user.py                     |   4 +-
 tests/test_data_transfer.py                   |   2 +-
 tests/test_fields.py                          |   1 -
 tests/test_idp_cas.py                         |  10 +-
 tests/test_idp_saml2.py                       | 102 ++++---
 tests/test_journal.py                         |   4 +-
 tests/test_large_userbase.py                  |   1 -
 tests/test_ldap.py                            |  67 +++--
 tests/test_login.py                           |  18 +-
 tests/test_manager.py                         |  60 ++--
 tests/test_manager_journal.py                 |   2 +-
 tests/test_manager_user_import.py             |   2 -
 tests/test_models.py                          |   2 -
 tests/test_ou_manager.py                      |   2 +-
 tests/test_passwords.py                       |   3 +-
 tests/test_profile.py                         |  21 +-
 tests/test_registration.py                    |   7 +-
 tests/test_role_manager.py                    |   6 +-
 tests/test_token.py                           |   1 -
 tests/test_user_manager.py                    |  18 +-
 tests/test_validators.py                      |   4 +-
 tests_rbac/test_rbac.py                       |  86 +++---
 303 files changed, 944 insertions(+), 1500 deletions(-)
merge-coverage.py
1 1
#!/usr/bin/python
2
from __future__ import print_function
3 2

  
4 3
import logging
5 4
import os
......
145 144
    for pckg in packages:
146 145
        name = pckg.get('name')
147 146
        if not include_package(name):
148
            logging.debug('excluding package "{0}"'.format(name))
147
            logging.debug(f'excluding package "{name}"')
149 148
            packageroot.remove(pckg)
150 149
        else:
151 150
            included.append(pckg)
......
158 157

  
159 158
    # create simple regexp from given filter
160 159
    for i in range(len(packagefilters)):
161
        packagefilters[i] = '^' + packagefilters[i].replace('.', '\.').replace('*', '.*') + '$'
160
        packagefilters[i] = '^' + packagefilters[i].replace('.', r'\.').replace('*', '.*') + '$'
162 161

  
163 162

  
164 163
def include_package(name):
......
265 264
    for xmlfile in xmlfiles:
266 265
        xml = ET.parse(xmlfile)
267 266
        filter_xml(xml)
268
        logging.debug('{1}/{2} filtering: {0}'.format(xmlfile, currfile, totalfiles))
267
        logging.debug(f'{currfile}/{totalfiles} filtering: {xmlfile}')
269 268
        xml.write(xmlfile + filtersuffix, encoding="UTF-8", xml_declaration=True)
270 269
        currfile += 1
271 270
else:
......
283 282
        sys.exit(0)
284 283

  
285 284
    currfile = 1
286
    logging.debug('{2}/{3} merging: {0} & {1}'.format(xmlfiles[0], xmlfiles[1], currfile, totalfiles - 1))
285
    logging.debug(f'{currfile}/{totalfiles - 1} merging: {xmlfiles[0]} & {xmlfiles[1]}')
287 286
    merge_xml(xmlfiles[0], xmlfiles[1], finalxml)
288 287

  
289 288
    currfile = 2
290 289
    for i in range(totalfiles - 2):
291 290
        xmlfile = xmlfiles[i + 2]
292
        logging.debug('{2}/{3} merging: {0} & {1}'.format(finalxml, xmlfile, currfile, totalfiles - 1))
291
        logging.debug(f'{currfile}/{totalfiles - 1} merging: {finalxml} & {xmlfile}')
293 292
        merge_xml(finalxml, xmlfile, finalxml)
294 293
        currfile += 1
setup.py
79 79
    tag exists, take 0.0- and add the length of the commit log.
80 80
    """
81 81
    if os.path.exists('VERSION'):
82
        with open('VERSION', 'r') as v:
82
        with open('VERSION') as v:
83 83
            return v.read()
84 84
    if os.path.exists('.git'):
85 85
        p = subprocess.Popen(
src/authentic2/a2_rbac/admin.py
26 26
    fields = ['parent']
27 27

  
28 28
    def get_queryset(self, request):
29
        return super(RoleParentInline, self).get_queryset(request).filter(direct=True)
29
        return super().get_queryset(request).filter(direct=True)
30 30

  
31 31

  
32 32
class RoleChildInline(admin.TabularInline):
......
35 35
    fields = ['child']
36 36

  
37 37
    def get_queryset(self, request):
38
        return super(RoleChildInline, self).get_queryset(request).filter(direct=True)
38
        return super().get_queryset(request).filter(direct=True)
39 39

  
40 40

  
41 41
class RoleAttributeInline(admin.TabularInline):
src/authentic2/a2_rbac/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    __DEFAULTS = dict(
22 22
        MANAGED_CONTENT_TYPES=None,
23 23
        ROLE_ADMIN_RESTRICT_TO_OU_USERS=False,
src/authentic2/a2_rbac/fields.py
39 39
        return name, path, args, kwargs
40 40

  
41 41
    def to_python(self, value):
42
        value = super(UniqueBooleanField, self).to_python(value)
42
        value = super().to_python(value)
43 43
        if value is None:
44 44
            return False
45 45
        return value
46 46

  
47 47
    def get_db_prep_value(self, value, connection, prepared=False):
48
        value = super(UniqueBooleanField, self).get_db_prep_value(value, connection, prepared=prepared)
48
        value = super().get_db_prep_value(value, connection, prepared=prepared)
49 49
        if value is False:
50 50
            return None
51 51
        return value
src/authentic2/a2_rbac/management.py
29 29
    Role = get_role_model()
30 30

  
31 31
    if app_settings.MANAGED_CONTENT_TYPES == ():
32
        Role.objects.filter(slug='a2-managers-of-{ou.slug}'.format(ou=ou)).delete()
32
        Role.objects.filter(slug=f'a2-managers-of-{ou.slug}').delete()
33 33
    else:
34 34
        ou_admin_role = ou.get_admin_role()
35 35

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

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

  
......
210 207
        ),
211 208
        migrations.AlterUniqueTogether(
212 209
            name='organizationalunit',
213
            unique_together=set([('name',), ('slug',)]),
210
            unique_together={('name',), ('slug',)},
214 211
        ),
215 212
        migrations.AlterUniqueTogether(
216 213
            name='roleattribute',
217
            unique_together=set([('role', 'name', 'kind', 'value')]),
214
            unique_together={('role', 'name', 'kind', 'value')},
218 215
        ),
219 216
        migrations.AlterUniqueTogether(
220 217
            name='role',
221
            unique_together=set([('slug', 'service'), ('slug', 'admin_scope_ct', 'admin_scope_id', 'ou')]),
218
            unique_together={('slug', 'service'), ('slug', 'admin_scope_ct', 'admin_scope_id', 'ou')},
222 219
        ),
223 220
    ]
src/authentic2/a2_rbac/migrations/0002_role_external_id.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0003_partial_unique_index_on_name_and_slug.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
from authentic2.migrations import CreatePartialIndexes
src/authentic2/a2_rbac/migrations/0004_auto_20150523_0028.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
......
21 18
        ),
22 19
        migrations.AlterUniqueTogether(
23 20
            name='role',
24
            unique_together=set([]),
21
            unique_together=set(),
25 22
        ),
26 23
    ]
src/authentic2/a2_rbac/migrations/0005_auto_20150526_1406.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0006_auto_20150619_1056.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0007_auto_20150708_1337.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/a2_rbac/migrations/0008_auto_20150810_1953.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0009_partial_unique_index_on_permission.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
from authentic2.migrations import CreatePartialIndexes
src/authentic2/a2_rbac/migrations/0010_auto_20160209_1417.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from collections import defaultdict
5 2

  
6 3
from django.db import migrations
......
26 23
        children = set()
27 24
        for role in duplicates:
28 25
            members |= set(role.members.all())
29
            parents |= set(rp.parent for rp in RoleParenting.objects.filter(child=role, direct=True))
30
            children |= set(rp.child for rp in RoleParenting.objects.filter(parent=role, direct=True))
26
            parents |= {rp.parent for rp in RoleParenting.objects.filter(child=role, direct=True)}
27
            children |= {rp.child for rp in RoleParenting.objects.filter(parent=role, direct=True)}
31 28
        duplicates[0].members = members
32 29
        for parent in parents:
33 30
            RoleParenting.objects.get_or_crate(parent=parent, child=duplicates[0], direct=True)
src/authentic2/a2_rbac/migrations/0011_auto_20160209_1511.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
......
13 10
    operations = [
14 11
        migrations.AlterUniqueTogether(
15 12
            name='role',
16
            unique_together=set([('admin_scope_ct', 'admin_scope_id')]),
13
            unique_together={('admin_scope_ct', 'admin_scope_id')},
17 14
        ),
18 15
    ]
src/authentic2/a2_rbac/migrations/0013_auto_20170629_0007.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
......
13 10
    operations = [
14 11
        migrations.AlterUniqueTogether(
15 12
            name='roleparenting',
16
            unique_together=set([('parent', 'child', 'direct')]),
13
            unique_together={('parent', 'child', 'direct')},
17 14
        ),
18 15
        migrations.AlterIndexTogether(
19 16
            name='roleparenting',
20
            index_together=set([('child', 'parent', 'direct')]),
17
            index_together={('child', 'parent', 'direct')},
21 18
        ),
22 19
    ]
src/authentic2/a2_rbac/migrations/0014_auto_20170711_1024.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0015_organizationalunit_validate_emails.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0016_auto_20171208_1429.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0017_organizationalunit_user_can_reset_password.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/a2_rbac/migrations/0019_organizationalunit_show_username.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2019-03-08 10:22
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/a2_rbac/migrations/0020_partial_unique_index_on_name.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
from authentic2.migrations import CreatePartialIndexes
src/authentic2/a2_rbac/migrations/0021_auto_20200317_1514.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-03-17 14:14
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/a2_rbac/migrations/0022_auto_20200402_1101.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-04-02 09:01
3
from __future__ import unicode_literals
4 2

  
5 3
import django.core.validators
6 4
from django.db import migrations, models
src/authentic2/a2_rbac/migrations/0023_role_can_manage_members.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-05-27 13:22
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-05-12 08:58
3
from __future__ import unicode_literals
4 2

  
5 3
from django.db import migrations
6 4

  
src/authentic2/a2_rbac/models.py
148 148
            and self.clean_unused_accounts_alert >= self.clean_unused_accounts_deletion
149 149
        ):
150 150
            raise ValidationError(_('Deletion alert delay must be less than actual deletion delay.'))
151
        super(OrganizationalUnit, self).clean()
151
        super().clean()
152 152

  
153 153
    def get_admin_role(self):
154 154
        """Get or create the generic admin role for this organizational
155 155
        unit.
156 156
        """
157 157
        name = _('Managers of "{ou}"').format(ou=self)
158
        slug = '_a2-managers-of-{ou.slug}'.format(ou=self)
158
        slug = f'_a2-managers-of-{self.slug}'
159 159
        return Role.objects.get_admin_role(
160 160
            instance=self,
161 161
            name=name,
......
256 256
        admin_role = self.__class__.objects.get_admin_role(
257 257
            self,
258 258
            name=_('Managers of role "{role}"').format(role=str(self)),
259
            slug='_a2-managers-of-role-{role}'.format(role=slugify(str(self))),
259
            slug=f'_a2-managers-of-role-{slugify(str(self))}',
260 260
            permissions=(view_user_perm,),
261 261
            self_administered=True,
262 262
            update_name=True,
......
270 270
        errors = {}
271 271

  
272 272
        with errorcollector(errors):
273
            super(Role, self).validate_unique(exclude=exclude)
273
            super().validate_unique(exclude=exclude)
274 274

  
275 275
        exclude = exclude or []
276 276

  
......
295 295
        # Service roles can only be part of the same ou as the service
296 296
        if self.service:
297 297
            self.ou = self.service.ou
298
        result = super(Role, self).save(*args, **kwargs)
298
        result = super().save(*args, **kwargs)
299 299
        self.get_admin_role(create=False)
300 300
        return result
301 301

  
......
402 402
        verbose_name_plural = _('role parenting relations')
403 403

  
404 404
    def __str__(self):
405
        return '{0} {1}> {2}'.format(self.parent.name, '-' if self.direct else '~', self.child.name)
405
        return '{} {}> {}'.format(self.parent.name, '-' if self.direct else '~', self.child.name)
406 406

  
407 407

  
408 408
class RoleAttribute(models.Model):
src/authentic2/admin.py
44 44

  
45 45
class CleanupAdminMixin(admin.ModelAdmin):
46 46
    def get_actions(self, request):
47
        actions = super(CleanupAdminMixin, self).get_actions(request)
47
        actions = super().get_actions(request)
48 48
        if hasattr(self.model.objects.none(), 'cleanup'):
49 49
            actions['cleanup_action'] = cleanup_action, 'cleanup_action', cleanup_action.short_description
50 50
        return actions
......
192 192
        `self.value()`.
193 193
        """
194 194
        if self.value():
195
            return queryset.filter(username__endswith=u'@' + self.value())
195
            return queryset.filter(username__endswith='@' + self.value())
196 196
        return queryset
197 197

  
198 198

  
......
215 215
        fields = '__all__'
216 216

  
217 217
    def __init__(self, *args, **kwargs):
218
        super(UserChangeForm, self).__init__(*args, **kwargs)
218
        super().__init__(*args, **kwargs)
219 219
        f = self.fields.get('user_permissions', None)
220 220
        if f is not None:
221 221
            f.queryset = f.queryset.select_related('content_type')
......
276 276
            )
277 277

  
278 278
    def save(self, commit=True):
279
        user = super(UserCreationForm, self).save(commit=False)
279
        user = super().save(commit=False)
280 280
        user.set_password(self.cleaned_data["password1"])
281 281
        if commit:
282 282
            user.save()
......
305 305
    actions = UserAdmin.actions + ['mark_as_inactive']
306 306

  
307 307
    def get_fieldsets(self, request, obj=None):
308
        fieldsets = deepcopy(super(AuthenticUserAdmin, self).get_fieldsets(request, obj))
308
        fieldsets = deepcopy(super().get_fieldsets(request, obj))
309 309
        if obj:
310 310
            if not request.user.is_superuser:
311 311
                fieldsets[2][1]['fields'] = filter(lambda x: x != 'is_superuser', fieldsets[2][1]['fields'])
......
342 342
            qs = models.Attribute.objects.all()
343 343
        else:
344 344
            qs = models.Attribute.objects.filter(required=True)
345
        non_model_fields = set([a.name for a in qs]) - set(['first_name', 'last_name'])
345
        non_model_fields = {a.name for a in qs} - {'first_name', 'last_name'}
346 346
        fields = list(set(fields) - set(non_model_fields))
347 347
        kwargs['fields'] = fields
348
        return super(AuthenticUserAdmin, self).get_form(request, obj=obj, **kwargs)
348
        return super().get_form(request, obj=obj, **kwargs)
349 349

  
350 350
    @transaction.atomic
351 351
    def mark_as_inactive(self, request, queryset):
......
361 361

  
362 362
class AttributeForm(forms.ModelForm):
363 363
    def __init__(self, *args, **kwargs):
364
        super(AttributeForm, self).__init__(*args, **kwargs)
364
        super().__init__(*args, **kwargs)
365 365
        choices = self.kind_choices()
366 366
        self.fields['kind'].choices = choices
367 367
        self.fields['kind'].widget = forms.Select(choices=choices)
src/authentic2/api_mixins.py
28 28
    default_code = 'conflict'
29 29

  
30 30

  
31
class GetOrCreateMixinView(object):
31
class GetOrCreateMixinView:
32 32
    _lookup_object = None
33 33

  
34 34
    def get_object(self):
35 35
        if self._lookup_object is not None:
36 36
            return self._lookup_object
37
        return super(GetOrCreateMixinView, self).get_object()
37
        return super().get_object()
38 38

  
39 39
    def _get_lookup_keys(self, name):
40 40
        return self.request.GET.getlist(name)
......
85 85
            self._lookup_object = self._lookup_instance(update_or_create_keys)
86 86
            if self._lookup_object is not None:
87 87
                return self.partial_update(request, *args, **kwargs)
88
        return super(GetOrCreateMixinView, self).create(request, *args, **kwargs)
88
        return super().create(request, *args, **kwargs)
src/authentic2/api_views.py
77 77
User = get_user_model()
78 78

  
79 79

  
80
class HookMixin(object):
80
class HookMixin:
81 81
    def get_serializer(self, *args, **kwargs):
82
        serializer = super(HookMixin, self).get_serializer(*args, **kwargs)
82
        serializer = super().get_serializer(*args, **kwargs)
83 83
        # if the serializer is a ListSerializer, we modify the child
84 84
        if hasattr(serializer, 'child'):
85 85
            hooks.call_hooks('api_modify_serializer', self, serializer.child)
......
89 89

  
90 90
    def get_object(self):
91 91
        hooks.call_hooks('api_modify_view_before_get_object', self)
92
        return super(HookMixin, self).get_object()
92
        return super().get_object()
93 93

  
94 94

  
95 95
class DjangoPermission(permissions.BasePermission):
......
106 106
        return self
107 107

  
108 108

  
109
class ExceptionHandlerMixin(object):
109
class ExceptionHandlerMixin:
110 110
    def handle_exception(self, exc):
111 111
        if hasattr(exc, 'detail'):
112 112
            exc.detail = {
113 113
                'result': 0,
114 114
                'errors': exc.detail,
115 115
            }
116
            return super(ExceptionHandlerMixin, self).handle_exception(exc)
116
            return super().handle_exception(exc)
117 117
        else:
118
            response = super(ExceptionHandlerMixin, self).handle_exception(exc)
118
            response = super().handle_exception(exc)
119 119
            response.data = {
120 120
                'result': 0,
121 121
                'errors': response.data,
......
182 182
        return data
183 183

  
184 184

  
185
class RpcMixin(object):
185
class RpcMixin:
186 186
    def post(self, request, format=None):
187 187
        serializer = self.get_serializer(data=request.data)
188 188
        if serializer.is_valid():
......
373 373
    hashed_password = serializers.CharField(max_length=128, required=False)
374 374

  
375 375
    def __init__(self, *args, **kwargs):
376
        super(BaseUserSerializer, self).__init__(*args, **kwargs)
376
        super().__init__(*args, **kwargs)
377 377

  
378 378
        for at in Attribute.objects.all():
379 379
            if at.name in self.fields:
......
408 408
        password = validated_data.pop('password', None)
409 409
        hashed_password = validated_data.pop('hashed_password', None)
410 410
        self.check_perm('custom_user.add_user', validated_data.get('ou'))
411
        instance = super(BaseUserSerializer, self).create(validated_data)
411
        instance = super().create(validated_data)
412 412
        # prevent update on a get_or_create
413 413
        if not getattr(instance, '_a2_created', True):
414 414
            return instance
......
466 466
            self.check_perm('custom_user.change_user', validated_data.get('ou'))
467 467
        if validated_data.get('email') != instance.email and not validated_data.get('email_verified'):
468 468
            instance.email_verified = False
469
        super(BaseUserSerializer, self).update(instance, validated_data)
469
        super().update(instance, validated_data)
470 470
        for key, value in attributes.items():
471 471
            if is_verified.get(key):
472 472
                setattr(instance.verified_attributes, key, value)
......
582 582
        return self.context['request'].user
583 583

  
584 584
    def __init__(self, instance=None, **kwargs):
585
        super(RoleSerializer, self).__init__(instance, **kwargs)
585
        super().__init__(instance, **kwargs)
586 586
        if self.instance:
587 587
            self.fields['ou'].read_only = True
588 588

  
......
590 590
        ou = validated_data.get('ou')
591 591
        # Creating roles also means being allowed to within the OU:
592 592
        if not self.user.has_ou_perm('a2_rbac.add_role', ou):
593
            raise PermissionDenied(u'User %s can\'t create role in OU %s' % (self.user, ou))
594
        return super(RoleSerializer, self).create(validated_data)
593
            raise PermissionDenied('User %s can\'t create role in OU %s' % (self.user, ou))
594
        return super().create(validated_data)
595 595

  
596 596
    def update(self, instance, validated_data):
597 597
        # Check role-updating permissions:
598 598
        if not self.user.has_perm('a2_rbac.change_role', obj=instance):
599
            raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
600
        super(RoleSerializer, self).update(instance, validated_data)
599
            raise PermissionDenied('User %s can\'t change role %s' % (self.user, instance))
600
        super().update(instance, validated_data)
601 601
        return instance
602 602

  
603 603
    def partial_update(self, instance, validated_data):
604 604
        # Check role-updating permissions:
605 605
        if not self.user.has_perm('a2_rbac.change_role', obj=instance):
606
            raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
607
        super(RoleSerializer, self).partial_update(instance, validated_data)
606
            raise PermissionDenied('User %s can\'t change role %s' % (self.user, instance))
607
        super().partial_update(instance, validated_data)
608 608
        return instance
609 609

  
610 610
    class Meta:
......
627 627
    def __init__(self, *args, **kwargs):
628 628
        self.bound = kwargs.pop('bound')
629 629
        assert self.bound in ['upper', 'lesser']
630
        super(IsoDateTimeField, self).__init__(*args, **kwargs)
630
        super().__init__(*args, **kwargs)
631 631

  
632 632
    def strptime(self, value, format):
633 633
        try:
634
            return super(IsoDateTimeField, self).strptime(value, format)
634
            return super().strptime(value, format)
635 635
        except (NonExistentTimeError, AmbiguousTimeError):
636 636
            parsed = parse_datetime(value)
637 637
            possible = sorted(
......
657 657
            raise NotImplementedError
658 658

  
659 659
    def filter(self, qs, value):
660
        return super(IsoDateTimeFilter, self).filter(qs, value)
660
        return super().filter(qs, value)
661 661

  
662 662

  
663 663
class UsersFilter(FilterSet):
......
779 779
    def check_perm(self, perm, ou):
780 780
        if ou:
781 781
            if not self.request.user.has_ou_perm(perm, ou):
782
                raise PermissionDenied(u'You do not have permission %s in %s' % (perm, ou))
782
                raise PermissionDenied('You do not have permission %s in %s' % (perm, ou))
783 783
        else:
784 784
            if not self.request.user.has_perm(perm):
785
                raise PermissionDenied(u'You do not have permission %s' % perm)
785
                raise PermissionDenied('You do not have permission %s' % perm)
786 786

  
787 787
    def perform_create(self, serializer):
788 788
        super().perform_create(serializer)
......
797 797
    def perform_destroy(self, instance):
798 798
        self.check_perm('custom_user.delete_user', instance.ou)
799 799
        self.request.journal.record('manager.user.deletion', target_user=instance, api=True)
800
        super(UsersAPI, self).perform_destroy(instance)
800
        super().perform_destroy(instance)
801 801

  
802 802
    class SynchronizationSerializer(serializers.Serializer):
803 803
        known_uuids = serializers.ListField(child=serializers.CharField())
......
896 896

  
897 897
    def perform_destroy(self, instance):
898 898
        if not self.request.user.has_perm(perm='a2_rbac.delete_role', obj=instance):
899
            raise PermissionDenied(u'User %s can\'t create role %s' % (self.request.user, instance))
899
            raise PermissionDenied('User %s can\'t create role %s' % (self.request.user, instance))
900 900
        self.request.journal.record('manager.role.deletion', role=instance, api=True)
901
        super(RolesAPI, self).perform_destroy(instance)
901
        super().perform_destroy(instance)
902 902

  
903 903
    def perform_create(self, serializer):
904 904
        super().perform_create(serializer)
......
911 911

  
912 912
class RolesMembersAPI(UsersAPI):
913 913
    def initial(self, request, *args, **kwargs):
914
        super(RolesMembersAPI, self).initial(request, *args, **kwargs)
914
        super().initial(request, *args, **kwargs)
915 915
        Role = get_role_model()
916 916
        self.role = get_object_or_404(Role, uuid=kwargs['role_uuid'])
917 917

  
......
930 930
    permission_classes = (permissions.IsAuthenticated,)
931 931

  
932 932
    def initial(self, request, *args, **kwargs):
933
        super(RoleMembershipAPI, self).initial(request, *args, **kwargs)
933
        super().initial(request, *args, **kwargs)
934 934
        Role = get_role_model()
935 935
        User = get_user_model()
936 936
        self.role = get_object_or_404(Role, uuid=kwargs['role_uuid'])
......
938 938

  
939 939
    def get(self, request, *args, **kwargs):
940 940
        if not request.user.has_perm('a2_rbac.view_role', obj=self.role):
941
            raise PermissionDenied(u'User not allowed to view role')
941
            raise PermissionDenied('User not allowed to view role')
942 942
        if self.request.GET.get('nested', 'false').lower() in ('true', '1'):
943 943
            qs = self.role.all_members()
944 944
        else:
......
948 948

  
949 949
    def post(self, request, *args, **kwargs):
950 950
        if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role):
951
            raise PermissionDenied(u'User not allowed to manage role members')
951
            raise PermissionDenied('User not allowed to manage role members')
952 952
        self.role.members.add(self.member)
953 953
        request.journal.record('manager.role.membership.grant', role=self.role, member=self.member, api=True)
954 954
        return Response(
......
957 957

  
958 958
    def delete(self, request, *args, **kwargs):
959 959
        if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role):
960
            raise PermissionDenied(u'User not allowed to manage role members')
960
            raise PermissionDenied('User not allowed to manage role members')
961 961
        self.role.members.remove(self.member)
962 962
        request.journal.record(
963 963
            'manager.role.membership.removal', role=self.role, member=self.member, api=True
......
975 975
    http_method_names = ['post', 'put', 'patch', 'delete']
976 976

  
977 977
    def initial(self, request, *args, **kwargs):
978
        super(RoleMembershipsAPI, self).initial(request, *args, **kwargs)
978
        super().initial(request, *args, **kwargs)
979 979
        Role = get_role_model()
980 980
        User = get_user_model()
981 981
        self.role = get_object_or_404(Role, uuid=kwargs['role_uuid'])
......
984 984
        perm = 'a2_rbac.manage_members_role'
985 985
        authorized = request.user.has_perm(perm, obj=self.role)
986 986
        if not authorized:
987
            raise PermissionDenied(u'User not allowed to manage role members')
987
            raise PermissionDenied('User not allowed to manage role members')
988 988

  
989 989
        if not isinstance(request.data, dict):
990 990
            raise ValidationError(_('Payload must be a dictionary'))
src/authentic2/app_settings.py
20 20
from django.utils.translation import ugettext_lazy as _
21 21

  
22 22

  
23
class Setting(object):
23
class Setting:
24 24
    SENTINEL = object()
25 25

  
26 26
    def __init__(self, default=SENTINEL, definition='', names=None):
......
35 35
        return self.default != self.SENTINEL
36 36

  
37 37

  
38
class AppSettings(object):
38
class AppSettings:
39 39
    def __init__(self, defaults):
40 40
        self.defaults = defaults
41 41

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

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

  
......
472 469
        ),
473 470
        migrations.AlterUniqueTogether(
474 471
            name='useraliasinsource',
475
            unique_together=set([('name', 'source')]),
472
            unique_together={('name', 'source')},
476 473
        ),
477 474
        migrations.AddField(
478 475
            model_name='attributeitem',
src/authentic2/attribute_aggregator/migrations/0002_auto_20150409_1840.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/attribute_aggregator/migrations/0003_auto_20150526_2239.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/attribute_aggregator/migrations/0004_auto_20150915_2041.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/attribute_kinds.py
69 69
    def __init__(self, **kwargs):
70 70
        self.allow_blank = kwargs.pop('allow_blank', False)
71 71
        self.trim_whitespace = kwargs.pop('trim_whitespace', True)
72
        super(DateRestField, self).__init__(**kwargs)
72
        super().__init__(**kwargs)
73 73

  
74 74
    def run_validation(self, data=empty):
75 75
        # Test for the empty string here so that it does not get validated,
......
79 79
            if not self.allow_blank:
80 80
                self.fail('blank')
81 81
            return ''
82
        return super(DateRestField, self).run_validation(data)
82
        return super().run_validation(data)
83 83

  
84 84

  
85 85
class BirthdateWidget(DateWidget):
......
90 90
        options['startDate'] = '1900-01-01'
91 91
        attrs['min'] = '1900-01-01'
92 92
        attrs['max'] = (datetime.date.today() - datetime.timedelta(days=1)).isoformat()
93
        super(BirthdateWidget, self).__init__(*args, **kwargs)
93
        super().__init__(*args, **kwargs)
94 94

  
95 95

  
96 96
def validate_birthdate(value):
......
158 158
    def __init__(self, *args, **kwargs):
159 159
        kwargs['max_length'] = 30
160 160
        kwargs.setdefault('help_text', _('ex.: 0699999999, +33 6 99 99 99 99'))
161
        super(PhoneNumberField, self).__init__(*args, **kwargs)
161
        super().__init__(*args, **kwargs)
162 162

  
163 163
    def clean(self, value):
164 164
        if value not in self.empty_values:
......
179 179
class FrPostcodeField(forms.CharField):
180 180
    def __init__(self, *args, **kwargs):
181 181
        kwargs.setdefault('help_text', _('ex.: 13260'))
182
        super(FrPostcodeField, self).__init__(*args, **kwargs)
182
        super().__init__(*args, **kwargs)
183 183

  
184 184
    def clean(self, value):
185
        value = super(FrPostcodeField, self).clean(value)
185
        value = super().clean(value)
186 186
        if value not in self.empty_values:
187 187
            value = value.strip()
188 188
            validate_fr_postcode(value)
......
196 196
    default_validators = [validate_fr_postcode]
197 197

  
198 198

  
199
class ProfileImageFile(object):
199
class ProfileImageFile:
200 200
    def __init__(self, name):
201 201
        self.name = name
202 202

  
......
370 370
    default_validators = [validate_siret]
371 371

  
372 372
    def to_python(self, value):
373
        value = super(SIRETField, self).to_python(value)
373
        value = super().to_python(value)
374 374
        value = only_digits(value)
375 375
        return value
376 376

  
src/authentic2/attributes_ng/engine.py
97 97
    """
98 98
    for source in get_sources():
99 99
        for instance in source.get_instances(ctx):
100
            for attribute_name, attribute_description in source.get_attribute_names(instance, ctx):
101
                yield attribute_name, attribute_description
100
            yield from source.get_attribute_names(instance, ctx)
102 101

  
103 102

  
104 103
def get_attributes(ctx):
......
110 109
    """
111 110
    source_and_instances = []
112 111
    for source in get_sources():
113
        source_and_instances.extend(((source, instance) for instance in source.get_instances(ctx)))
112
        source_and_instances.extend((source, instance) for instance in source.get_instances(ctx))
114 113
    source_and_instances = topological_sort(source_and_instances, ctx)
115 114
    ctx = ctx.copy()
116 115
    for source, instance in source_and_instances:
src/authentic2/attributes_ng/sources/__init__.py
17 17
import abc
18 18

  
19 19

  
20
class BaseAttributeSource(object, metaclass=abc.ABCMeta):
20
class BaseAttributeSource(metaclass=abc.ABCMeta):
21 21
    """
22 22
    Base class for attribute sources
23 23
    """
src/authentic2/attributes_ng/sources/format.py
18 18

  
19 19
from ...decorators import to_list
20 20

  
21
AUTHORIZED_KEYS = set(('name', 'label', 'template'))
21
AUTHORIZED_KEYS = {'name', 'label', 'template'}
22 22

  
23 23

  
24 24
@to_list
src/authentic2/attributes_ng/sources/function.py
18 18

  
19 19
from ...decorators import to_list
20 20

  
21
AUTHORIZED_KEYS = set(('name', 'label', 'dependencies', 'function'))
21
AUTHORIZED_KEYS = {'name', 'label', 'dependencies', 'function'}
22 22

  
23
REQUIRED_KEYS = set(('name', 'dependencies', 'function'))
23
REQUIRED_KEYS = {'name', 'dependencies', 'function'}
24 24

  
25 25
UNEXPECTED_KEYS_ERROR = '{0}: unexpected key(s) {1} in configuration'
26 26
MISSING_KEYS_ERROR = '{0}: missing key(s) {1} in configuration'
src/authentic2/auth2_auth/auth2_ssl/__init__.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17

  
18
class Plugin(object):
18
class Plugin:
19 19
    def get_apps(self):
20 20
        return [__name__]
src/authentic2/auth2_auth/auth2_ssl/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/auth2_auth/auth2_ssl/migrations/0002_auto_20150409_1840.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/auth2_auth/auth2_ssl/migrations/0003_auto_20190614_1438.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2019-06-14 12:38
3
from __future__ import unicode_literals
4 2

  
5 3
from django.db import migrations
6 4

  
src/authentic2/auth_migrations_18/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.core import validators
5 2
from django.db import migrations, models
6 3
from django.utils import timezone
src/authentic2/auth_migrations_18/0002_auto_20150323_1720.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import django.core.validators
5 2
from django.db import migrations, models
6 3

  
src/authentic2/auth_migrations_18/0003_auto_20150410_1657.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/auth_migrations_18/0004_user.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import django.core.validators
5 2
import django.utils.timezone
6 3
from django.db import migrations, models
src/authentic2/auth_migrations_18/0005_auto_20150526_2303.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import django.contrib.auth.models
5 2
import django.core.validators
6 3
from django.db import migrations, models
src/authentic2/authentication.py
27 27
from authentic2_idp_oidc.models import OIDCClient
28 28

  
29 29

  
30
class OIDCUser(object):
30
class OIDCUser:
31 31
    """Fake user class to return in case OIDC authentication"""
32 32

  
33 33
    def __init__(self, oidc_client):
......
68 68
        except OIDCClient.DoesNotExist:
69 69
            pass
70 70
        # try BasicAuthentication
71
        if (
72
            'request'
73
            in inspect.signature(super(Authentic2Authentication, self).authenticate_credentials).parameters
74
        ):
71
        if 'request' in inspect.signature(super().authenticate_credentials).parameters:
75 72
            # compatibility with DRF 3.4
76
            return super(Authentic2Authentication, self).authenticate_credentials(
77
                userid, password, request=request
78
            )
79
        return super(Authentic2Authentication, self).authenticate_credentials(userid, password)
73
            return super().authenticate_credentials(userid, password, request=request)
74
        return super().authenticate_credentials(userid, password)
src/authentic2/authenticators.py
34 34
logger = logging.getLogger(__name__)
35 35

  
36 36

  
37
class BaseAuthenticator(object):
37
class BaseAuthenticator:
38 38
    def __init__(self, show_condition=None, **kwargs):
39 39
        self.show_condition = show_condition
40 40

  
src/authentic2/backends/ldap_backend.py
412 412
        if self.block.get('keep_password_in_session', False):
413 413
            self.keep_password_in_session(password)
414 414
        if self.block['keep_password']:
415
            if not super(LDAPUser, self).check_password(password):
416
                super(LDAPUser, self).set_password(password)
415
            if not super().check_password(password):
416
                super().set_password(password)
417 417
                self._changed = True
418 418
        else:
419
            if super(LDAPUser, self).has_usable_password():
419
            if super().has_usable_password():
420 420
                self.set_unusable_password()
421 421
                self._changed = True
422 422

  
......
478 478
            self._current_password = new_password
479 479
        self.keep_password_in_session(new_password)
480 480
        if self.block['keep_password']:
481
            super(LDAPUser, self).set_password(new_password)
481
            super().set_password(new_password)
482 482
        else:
483 483
            self.set_unusable_password()
484 484

  
......
515 515
        if hasattr(self, 'keep_pk'):
516 516
            pk = self.pk
517 517
            self.pk = self.keep_pk
518
        super(LDAPUser, self).save(*args, **kwargs)
518
        super().save(*args, **kwargs)
519 519
        if hasattr(self, 'keep_pk'):
520 520
            self.pk = pk
521 521

  
......
527 527
        return self.block.get('user_can_change_password', False)
528 528

  
529 529

  
530
class LDAPBackend(object):
530
class LDAPBackend:
531 531
    _DEFAULTS = {
532 532
        'basedn': '',
533 533
        'binddn': '',
......
699 699
        # 1.1 is special attribute meaning, "no attribute requested"
700 700
        results = conn.search_s(group_base_dn, ldap.SCOPE_SUBTREE, block['group_filter'], ['1.1'])
701 701
        results = cls.normalize_ldap_results(results)
702
        return set([group_dn for group_dn, attrs in results])
702
        return {group_dn for group_dn, attrs in results}
703 703

  
704 704
    def authenticate(self, request=None, username=None, password=None, realm=None, ou=None):
705 705
        if username is None or password is None:
......
762 762
                            log.debug(
763 763
                                '[%s] looking up dn for username %r using query %r', ldap_uri, username, query
764 764
                            )
765
                            results = conn.search_s(user_basedn, ldap.SCOPE_SUBTREE, query, [u'1.1'])
765
                            results = conn.search_s(user_basedn, ldap.SCOPE_SUBTREE, query, ['1.1'])
766 766
                            results = self.normalize_ldap_results(results)
767 767
                            # remove search references
768 768
                            results = [result for result in results if result[0] is not None]
......
808 808
                                try:
809 809
                                    self.bind(block, conn)
810 810
                                except Exception:
811
                                    log.exception(u'rebind failure after login bind')
811
                                    log.exception('rebind failure after login bind')
812 812
                                    raise ldap.SERVER_DOWN
813 813
                            break
814 814
                        except ldap.INVALID_CREDENTIALS as e:
......
1180 1180
            for key in at_mapping:
1181 1181
                if at_mapping[key] != 'dn':
1182 1182
                    attributes.add(at_mapping[key])
1183
        return list(set(attribute.lower() for attribute in attributes))
1183
        return list({attribute.lower() for attribute in attributes})
1184 1184

  
1185 1185
    @classmethod
1186 1186
    def get_ppolicy_attributes(cls, block, conn, dn):
......
1188 1188

  
1189 1189
        def get_attributes(dn, attributes):
1190 1190
            try:
1191
                results = conn.search_s(dn, ldap.SCOPE_BASE, u'(objectclass=*)', attributes)
1191
                results = conn.search_s(dn, ldap.SCOPE_BASE, '(objectclass=*)', attributes)
1192 1192
            except ldap.LDAPError as e:
1193 1193
                log.error('[%s] unable to retrieve attributes of dn %r: %r', ldap_uri, dn, e)
1194 1194
                return {}
......
1369 1369
                decoded.append((attribute, urllib.parse.unquote(value)))
1370 1370
            else:
1371 1371
                decoded.append((attribute, force_text(value)))
1372
        filters = [filter_format(u'(%s=%s)', (a, b)) for a, b in decoded]
1373
        return '(&{0})'.format(''.join(filters))
1372
        filters = [filter_format('(%s=%s)', (a, b)) for a, b in decoded]
1373
        return '(&{})'.format(''.join(filters))
1374 1374

  
1375 1375
    def build_external_id(self, external_id_tuple, attributes):
1376 1376
        """Build the exernal id for the user, use attribute that eventually
......
1529 1529
            msgid = conn.search_ext(*args, serverctrls=[pg_ctrl], **kwargs)
1530 1530
            result_type, data, msgid, serverctrls = conn.result3(msgid)
1531 1531
            pg_ctrl.cookie = serverctrls[0].cookie
1532
            for dn, attrs in cls.normalize_ldap_results(data):
1533
                yield dn, attrs
1532
            yield from cls.normalize_ldap_results(data)
1534 1533

  
1535 1534
    @classmethod
1536 1535
    def get_users(cls):
1537 1536
        for block in cls.get_config():
1538 1537
            conn = cls.get_connection(block)
1539 1538
            if conn is None:
1540
                log.warning(u'unable to synchronize with LDAP servers %s', force_text(block['url']))
1539
                log.warning('unable to synchronize with LDAP servers %s', force_text(block['url']))
1541 1540
                continue
1542 1541
            cls.check_group_to_role_mappings(block)
1543 1542
            user_basedn = force_text(block.get('user_basedn') or block['basedn'])
......
1601 1600
    @classmethod
1602 1601
    def ad_encoding(cls, s):
1603 1602
        '''Encode a string for AD consumption as a password'''
1604
        return (u'"{0}"'.format(s)).encode('utf-16-le')
1603
        return (f'"{s}"').encode('utf-16-le')
1605 1604

  
1606 1605
    @classmethod
1607 1606
    def modify_password(cls, conn, block, dn, old_password, new_password):
......
1705 1704
                yield conn
1706 1705
            else:
1707 1706
                if block['replicas']:
1708
                    log.warning(u'admin bind failed on %s: %s', url, error)
1707
                    log.warning('admin bind failed on %s: %s', url, error)
1709 1708
                else:
1710
                    log.error(u'admin bind failed on %s: %s', url, error)
1709
                    log.error('admin bind failed on %s: %s', url, error)
1711 1710

  
1712 1711
    @classmethod
1713 1712
    def bind(cls, block, conn, credentials=()):
src/authentic2/backends/models_backend.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import functools
20 19

  
......
30 29

  
31 30
def upn(username, realm):
32 31
    '''Build an UPN from a username and a realm'''
33
    return '{0}@{1}'.format(username, realm)
32
    return f'{username}@{realm}'
34 33

  
35 34

  
36 35
PROXY_USER_MODEL = None
src/authentic2/cbv.py
24 24
from .utils.views import csrf_token_check
25 25

  
26 26

  
27
class ValidateCSRFMixin(object):
27
class ValidateCSRFMixin:
28 28
    """Move CSRF token validation inside the form validation.
29 29

  
30 30
    This mixin must always be the leftest one and if your class override
......
35 35
    @method_decorator(csrf_exempt)
36 36
    @method_decorator(ensure_csrf_cookie)
37 37
    def dispatch(self, *args, **kwargs):
38
        return super(ValidateCSRFMixin, self).dispatch(*args, **kwargs)
38
        return super().dispatch(*args, **kwargs)
39 39

  
40 40
    def form_valid(self, *args, **kwargs):
41 41
        for form in args:
......
43 43
                csrf_token_check(self.request, form)
44 44
        if not form.is_valid():
45 45
            return self.form_invalid(form)
46
        return super(ValidateCSRFMixin, self).form_valid(*args, **kwargs)
46
        return super().form_valid(*args, **kwargs)
47 47

  
48 48

  
49
class RedirectToNextURLViewMixin(object):
49
class RedirectToNextURLViewMixin:
50 50
    def get_success_url(self):
51 51
        if REDIRECT_FIELD_NAME in self.request.GET:
52 52
            return self.request.GET[REDIRECT_FIELD_NAME]
......
78 78
                },
79 79
                status=303,
80 80
            )
81
        return super(NextURLViewMixin, self).dispatch(request, *args, **kwargs)
81
        return super().dispatch(request, *args, **kwargs)
82 82

  
83 83

  
84
class TemplateNamesMixin(object):
84
class TemplateNamesMixin:
85 85
    def get_template_names(self):
86 86
        if hasattr(self, 'template_names'):
87 87
            return self.template_names
88
        return super(TemplateNamesMixin, self).get_template_names()
88
        return super().get_template_names()
89 89

  
90 90

  
91
class HookMixin(object):
91
class HookMixin:
92 92
    def get_form(self):
93
        form = super(HookMixin, self).get_form()
93
        form = super().get_form()
94 94
        hooks.call_hooks('front_modify_form', self, form)
95 95
        return form
src/authentic2/compat_lasso.py
18 18
    import lasso
19 19
except ImportError:
20 20

  
21
    class MockLasso(object):
21
    class MockLasso:
22 22
        def __getattr__(self, key):
23 23
            if key[0].isupper():
24 24
                return ''
src/authentic2/context_processors.py
21 21
from .models import Service
22 22

  
23 23

  
24
class UserFederations(object):
24
class UserFederations:
25 25
    '''Provide access to all federations of the current user'''
26 26

  
27 27
    def __init__(self, request):
......
42 42
                    d['provider'] = provider
43 43
                    d['links'].append(link)
44 44
            return d
45
        return super(UserFederations, self).__getattr__(name)
45
        return super().__getattr__(name)
46 46

  
47 47

  
48 48
__AUTHENTIC2_DISTRIBUTION = None
src/authentic2/csv_import.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import csv
20 19
import io
......
74 73
        return attr.s(func, **kwargs)
75 74

  
76 75

  
77
class UTF8Recoder(object):
76
class UTF8Recoder:
78 77
    def __init__(self, fd):
79 78
        self.fd = fd
80 79

  
......
87 86
    next = __next__
88 87

  
89 88

  
90
class UnicodeReader(object):
89
class UnicodeReader:
91 90
    def __init__(self, fd, dialect='excel', **kwargs):
92 91
        self.reader = csv.reader(UTF8Recoder(fd), dialect=dialect, **kwargs)
93 92

  
......
101 100
    next = __next__
102 101

  
103 102

  
104
class CsvImporter(object):
103
class CsvImporter:
105 104
    rows = None
106 105
    error = None
107 106
    error_description = None
......
114 113
            input_fd = io.StringIO(fd_or_str)
115 114
        elif not hasattr(fd_or_str, 'read1'):
116 115
            try:
117
                input_fd = io.open(fd_or_str.fileno(), closefd=False, mode='rb')
116
                input_fd = open(fd_or_str.fileno(), closefd=False, mode='rb')
118 117
            except Exception:
119 118
                try:
120 119
                    fd_or_str.seek(0)
......
152 151
                    input_fd.seek(0)
153 152

  
154 153
            if not hasattr(input_fd, 'readable'):
155
                input_fd = io.open(input_fd.fileno(), 'rb', closefd=False)
154
                input_fd = open(input_fd.fileno(), 'rb', closefd=False)
156 155
            return io.TextIOWrapper(input_fd, encoding=encoding)
157 156

  
158 157
        def parse_csv(input_fd):
......
188 187

  
189 188

  
190 189
@attrs
191
class CsvHeader(object):
190
class CsvHeader:
192 191
    column = attrib()
193 192
    name = attrib(default='')
194 193
    field = attrib(default=False, converter=bool)
......
215 214

  
216 215

  
217 216
@attrs
218
class Error(object):
217
class Error:
219 218
    code = attrib()
220 219
    description = attrib(default='', cmp=False)
221 220

  
......
240 239

  
241 240
SOURCE_NAME = '_source_name'
242 241
SOURCE_ID = '_source_id'
243
SOURCE_COLUMNS = set([SOURCE_NAME, SOURCE_ID])
242
SOURCE_COLUMNS = {SOURCE_NAME, SOURCE_ID}
244 243
ROLE_NAME = '_role_name'
245 244
ROLE_SLUG = '_role_slug'
246 245
PASSWORD_HASH = 'password_hash'
......
289 288

  
290 289

  
291 290
@attrs
292
class CsvRow(object):
291
class CsvRow:
293 292
    line = attrib()
294 293
    cells = attrib(default=[])
295 294
    errors = attrib(default=[])
......
328 327

  
329 328

  
330 329
@attrs
331
class CsvCell(object):
330
class CsvCell:
332 331
    line = attrib()
333 332
    header = attrib()
334 333
    value = attrib(default=None)
......
349 348
    pass
350 349

  
351 350

  
352
class UserCsvImporter(object):
351
class UserCsvImporter:
353 352
    csv_importer = None
354 353
    errors = None
355 354
    headers = None
src/authentic2/custom_user/management/commands/changepassword.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function, unicode_literals
18 17

  
19 18
import getpass
20 19

  
src/authentic2/custom_user/management/commands/fix-attributes.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function, unicode_literals
18 17

  
19 18
from django.core.management.base import BaseCommand
20 19

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

  
4 1
import django.utils.timezone
5 2
from django.db import migrations, models
6 3

  
src/authentic2/custom_user/migrations/0002_auto_20150410_1823.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
......
8 5
class ThirdPartyAlterField(migrations.AlterField):
9 6
    def __init__(self, *args, **kwargs):
10 7
        self.app_label = kwargs.pop('app_label')
11
        super(ThirdPartyAlterField, self).__init__(*args, **kwargs)
8
        super().__init__(*args, **kwargs)
12 9

  
13 10
    def state_forwards(self, app_label, state):
14
        super(ThirdPartyAlterField, self).state_forwards(self.app_label, state)
11
        super().state_forwards(self.app_label, state)
15 12

  
16 13
    def database_forwards(self, app_label, schema_editor, from_state, to_state):
17 14
        if hasattr(from_state, 'clear_delayed_apps_cache'):
18 15
            from_state.clear_delayed_apps_cache()
19
        super(ThirdPartyAlterField, self).database_forwards(
20
            self.app_label, schema_editor, from_state, to_state
21
        )
16
        super().database_forwards(self.app_label, schema_editor, from_state, to_state)
22 17

  
23 18
    def database_backwards(self, app_label, schema_editor, from_state, to_state):
24 19
        self.database_forwards(app_label, schema_editor, from_state, to_state)
src/authentic2/custom_user/migrations/0003_auto_20150504_1410.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0004_user_ou.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/custom_user/migrations/0005_auto_20150522_1527.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/custom_user/migrations/0006_auto_20150527_1212.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0007_auto_20150610_1527.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0008_auto_20150617_1606.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import django.utils.timezone
5 2
from django.db import migrations, models
6 3

  
src/authentic2/custom_user/migrations/0009_auto_20150810_1953.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0010_auto_20160307_1418.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0011_manual_attribute_values_for_name_fields.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0012_user_modified.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import datetime
5 2

  
6 3
from django.db import migrations, models
src/authentic2/custom_user/migrations/0013_user_email_verified.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0014_set_email_verified.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0015_auto_20170707_1653.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/custom_user/migrations/0016_auto_20180925_1107.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.12 on 2018-09-25 09:07
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/custom_user/migrations/0017_auto_20200305_1645.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-03-05 15:45
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/custom_user/migrations/0018_user_last_account_deletion_alert.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-03-17 14:16
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/custom_user/migrations/0019_add_user_deleted.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.29 on 2020-04-21 13:38
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/custom_user/migrations/0021_set_unusable_password.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.29 on 2020-11-02 21:52
3
from __future__ import unicode_literals
4 2

  
5 3
from django.contrib.auth.models import AbstractUser
6 4
from django.db import migrations
src/authentic2/custom_user/migrations/0025_user_deactivation.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.29 on 2021-02-09 09:37
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/custom_user/models.py
1
# coding: utf-8
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import base64
21 19
import datetime
......
60 58
            yield value
61 59

  
62 60

  
63
class Attributes(object):
61
class Attributes:
64 62
    def __init__(self, owner, verified=None):
65 63
        self.__dict__['owner'] = owner
66 64
        self.__dict__['verified'] = verified
......
112 110
        return None
113 111

  
114 112

  
115
class AttributesDescriptor(object):
113
class AttributesDescriptor:
116 114
    def __init__(self, verified=None):
117 115
        self.verified = verified
118 116

  
......
120 118
        return Attributes(obj, verified=self.verified)
121 119

  
122 120

  
123
class IsVerified(object):
121
class IsVerified:
124 122
    def __init__(self, user):
125 123
        self.user = user
126 124

  
......
129 127
        return v is not None and v == getattr(self.user.verified_attributes, name, None)
130 128

  
131 129

  
132
class IsVerifiedDescriptor(object):
130
class IsVerifiedDescriptor:
133 131
    def __get__(self, obj, objtype):
134 132
        return IsVerified(obj)
135 133

  
......
249 247
        errors = {}
250 248

  
251 249
        with errorcollector(errors):
252
            super(User, self).validate_unique(exclude=exclude)
250
            super().validate_unique(exclude=exclude)
253 251

  
254 252
        exclude = exclude or []
255 253

  
......
335 333

  
336 334
    def save(self, *args, **kwargs):
337 335
        update_fields = kwargs.get('update_fields')
338
        rc = super(User, self).save(*args, **kwargs)
339
        if not update_fields or not set(update_fields).isdisjoint(set(['first_name', 'last_name'])):
336
        rc = super().save(*args, **kwargs)
337
        if not update_fields or not set(update_fields).isdisjoint({'first_name', 'last_name'}):
340 338
            try:
341 339
                self.attributes.first_name
342 340
            except AttributeError:
......
359 357
    def refresh_from_db(self, *args, **kwargs):
360 358
        if hasattr(self, '_a2_attributes_cache'):
361 359
            del self._a2_attributes_cache
362
        return super(User, self).refresh_from_db(*args, **kwargs)
360
        return super().refresh_from_db(*args, **kwargs)
363 361

  
364 362
    def mark_as_active(self):
365 363
        self.is_active = True
src/authentic2/data_transfer.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import uuid
20 19
from functools import wraps
......
68 67
    obj.save()
69 68

  
70 69

  
71
class ExportContext(object):
70
class ExportContext:
72 71
    _role_qs = None
73 72
    _ou_qs = None
74 73
    export_roles = None
......
130 129
        return role
131 130

  
132 131

  
133
class ImportContext(object):
132
class ImportContext:
134 133
    """Holds information on how to perform the import.
135 134

  
136 135
    ou_delete_orphans: if True any existing ou that is not found in the export will
......
172 171
        self.set_ou = set_ou
173 172

  
174 173

  
175
class RoleDeserializer(object):
174
class RoleDeserializer:
176 175
    def __init__(self, d, import_context):
177 176
        self._import_context = import_context
178 177
        self._obj = None
......
316 315
        return created, deleted
317 316

  
318 317

  
319
class ImportResult(object):
318
class ImportResult:
320 319
    def __init__(self):
321 320
        self.roles = {'created': [], 'updated': []}
322 321
        self.ous = {'created': [], 'updated': []}
src/authentic2/decorators.py
125 125
    return instance
126 126

  
127 127

  
128
class CacheDecoratorBase(object):
128
class CacheDecoratorBase:
129 129
    """Base class to build cache decorators.
130 130

  
131 131
    It helps for building keys from function arguments.
......
140 140
        if args:
141 141
            # Case of a decorator used directly
142 142
            return cls(**kwargs)(args[0])
143
        return super(CacheDecoratorBase, cls).__new__(cls)
143
        return super().__new__(cls)
144 144

  
145 145
    def __init__(self, timeout=None, hostname_vary=True, args=None, kwargs=None):
146 146
        self.timeout = timeout
......
199 199
        for kw, arg in sorted(kwargs.items(), key=lambda x: x[0]):
200 200
            if kw not in self.kwargs:
201 201
                continue
202
            parts.append(u'%s-%s' % (str(kw), str(arg)))
202
            parts.append('%s-%s' % (str(kw), str(arg)))
203 203
        return '|'.join(parts)
204 204

  
205 205

  
206
class SimpleDictionnaryCacheMixin(object):
206
class SimpleDictionnaryCacheMixin:
207 207
    """Default implementations of set, get and delete for a cache implemented
208 208
    using a dictionary. The dictionnary must be returned by a property named
209 209
    'cache'.
......
226 226
class GlobalCache(SimpleDictionnaryCacheMixin, CacheDecoratorBase):
227 227
    def __init__(self, *args, **kwargs):
228 228
        self.cache = {}
229
        super(GlobalCache, self).__init__(*args, **kwargs)
229
        super().__init__(*args, **kwargs)
230 230

  
231 231

  
232 232
class RequestCache(SimpleDictionnaryCacheMixin, CacheDecoratorBase):
......
252 252
            self.delete(key)
253 253

  
254 254

  
255
class PickleCacheMixin(object):
255
class PickleCacheMixin:
256 256
    def set(self, key, value):
257 257
        value, tstamp = value
258 258
        value = base64.b64encode(pickle.dumps(value)).decode('ascii')
259
        super(PickleCacheMixin, self).set(key, (value, tstamp))
259
        super().set(key, (value, tstamp))
260 260

  
261 261
    def get(self, key):
262
        value = super(PickleCacheMixin, self).get(key)
262
        value = super().get(key)
263 263
        if value[0] is not None:
264 264
            value, tstamp = value
265 265
            try:
......
283 283
        request = middleware.StoreRequestMiddleware.get_request()
284 284
        if request:
285 285
            request.session.modified = True
286
        return super(SessionCache, self).set(key, value)
286
        return super().set(key, value)
287 287

  
288 288
    def clear(self):
289 289
        request = middleware.StoreRequestMiddleware.get_request()
290 290
        if request:
291 291
            request.session.modified = True
292
        return super(SessionCache, self).clear()
292
        return super().clear()
293 293

  
294 294

  
295 295
@contextmanager
src/authentic2/exponential_retry_timeout.py
21 21
from django.core.cache import cache
22 22

  
23 23

  
24
class ExponentialRetryTimeout(object):
24
class ExponentialRetryTimeout:
25 25
    FACTOR = 1.8
26 26
    DURATION = 0.8
27 27
    MAX_DURATION = 3600  # max 1 hour
......
66 66
        if not self.duration:
67 67
            return
68 68
        cache.delete(key)
69
        self.logger.debug(u'success for %s', keys)
69
        self.logger.debug('success for %s', keys)
70 70

  
71 71
    def failure(self, *keys):
72 72
        """Signal an action failure, augment the exponential backoff one level."""
......
83 83
            duration = min(self.duration * self.factor ** level, self.max_duration)
84 84
            next_time += duration
85 85
        cache.set(key, (level, next_time), self.cache_duration)
86
        self.logger.debug(u'failure for %s, level: %s, next_time: %s', keys, level, next_time)
86
        self.logger.debug('failure for %s, level: %s, next_time: %s', keys, level, next_time)
src/authentic2/forms/authentication.py
51 51
    def __init__(self, *args, **kwargs):
52 52
        preferred_ous = kwargs.pop('preferred_ous', [])
53 53

  
54
        super(AuthenticationForm, self).__init__(*args, **kwargs)
54
        super().__init__(*args, **kwargs)
55 55

  
56 56
        self.exponential_backoff = ExponentialRetryTimeout(
57 57
            key_prefix='login-exp-backoff-',
......
132 132

  
133 133
    @property
134 134
    def media(self):
135
        media = super(AuthenticationForm, self).media
135
        media = super().media
136 136
        media = media + Media(js=['authentic2/js/js_seconds_until.js'])
137 137
        if app_settings.A2_LOGIN_FORM_OU_SELECTOR:
138 138
            media = media + Media(js=['authentic2/js/ou_selector.js'])
src/authentic2/forms/fields.py
45 45

  
46 46
    def __init__(self, *args, **kwargs):
47 47
        kwargs['help_text'] = password_help_text()
48
        super(NewPasswordField, self).__init__(*args, **kwargs)
48
        super().__init__(*args, **kwargs)
49 49

  
50 50

  
51 51
class CheckPasswordField(CharField):
......
63 63
            'match': _('Passwords match.'),
64 64
            'nomatch': _('Passwords do not match.'),
65 65
        }
66
        super(CheckPasswordField, self).__init__(*args, **kwargs)
66
        super().__init__(*args, **kwargs)
67 67

  
68 68

  
69 69
class ProfileImageField(FileField):
......
75 75

  
76 76
    def clean(self, data, initial=None):
77 77
        if data is FILE_INPUT_CONTRADICTION or data is False or data is None:
78
            return super(ProfileImageField, self).clean(data, initial=initial)
78
            return super().clean(data, initial=initial)
79 79
        # we have a file
80 80
        try:
81 81
            with warnings.catch_warnings():
82 82
                image = PIL.Image.open(io.BytesIO(data.read()))
83
        except (IOError, PIL.Image.DecompressionBombWarning):
83
        except (OSError, PIL.Image.DecompressionBombWarning):
84 84
            raise ValidationError(_('The image is not valid'))
85 85
        image = self.normalize_image(image)
86 86
        new_data = self.file_from_image(image, data.name)
87
        return super(ProfileImageField, self).clean(new_data, initial=initial)
87
        return super().clean(new_data, initial=initial)
88 88

  
89 89
    def file_from_image(self, image, name=None):
90 90
        output = io.BytesIO()
src/authentic2/forms/mixins.py
20 20
from django.utils.translation import ugettext as _
21 21

  
22 22

  
23
class LockedFieldFormMixin(object):
23
class LockedFieldFormMixin:
24 24
    def __init__(self, *args, **kwargs):
25
        super(LockedFieldFormMixin, self).__init__(*args, **kwargs)
25
        super().__init__(*args, **kwargs)
26 26
        self.__lock_fields()
27 27

  
28 28
    def __lock_fields(self):
src/authentic2/forms/passwords.py
87 87
            logger.info('password reset failed for user "%r": account is disabled', user)
88 88
            utils.send_templated_mail(user, ['authentic2/password_reset_refused'])
89 89
        if not self.users.exists() and email:
90
            logger.info(u'password reset request for "%s", no user found', email)
90
            logger.info('password reset request for "%s", no user found', email)
91 91
            if getattr(settings, 'REGISTRATION_OPEN', True):
92 92
                ctx = {
93 93
                    'registration_url': utils.make_url('registration_register', absolute=True),
......
103 103
    successfully changed."""
104 104

  
105 105
    def save(self, commit=True):
106
        ret = super(PasswordResetMixin, self).save(commit=commit)
106
        ret = super().save(commit=commit)
107 107
        if commit:
108 108
            models.PasswordReset.objects.filter(user=self.user).delete()
109 109
        else:
......
118 118
        return ret
119 119

  
120 120

  
121
class NotifyOfPasswordChange(object):
121
class NotifyOfPasswordChange:
122 122
    def save(self, commit=True):
123
        user = super(NotifyOfPasswordChange, self).save(commit=commit)
123
        user = super().save(commit=commit)
124 124
        if user.email:
125 125
            ctx = {
126 126
                'user': user,
src/authentic2/forms/profile.py
33 33

  
34 34
    def __init__(self, *args, **kwargs):
35 35
        self.user = kwargs.pop('user')
36
        super(DeleteAccountForm, self).__init__(*args, **kwargs)
36
        super().__init__(*args, **kwargs)
37 37

  
38 38
    def clean_password(self):
39 39
        password = self.cleaned_data.get('password')
......
47 47

  
48 48
    def __init__(self, user, *args, **kwargs):
49 49
        self.user = user
50
        super(EmailChangeFormNoPassword, self).__init__(*args, **kwargs)
50
        super().__init__(*args, **kwargs)
51 51

  
52 52

  
53 53
class EmailChangeForm(EmailChangeFormNoPassword):
......
93 93
                # helper data for LockedFieldFormMixin
94 94
                if atv.verified:
95 95
                    self.locked_fields.add(name)
96
        super(BaseUserForm, self).__init__(*args, **kwargs)
96
        super().__init__(*args, **kwargs)
97 97

  
98 98
    def is_field_locked(self, name):
99 99
        # helper method for LockedFieldFormMixin
......
111 111
                setattr(self.instance.attributes, name, value)
112 112

  
113 113
    def save(self, commit=True):
114
        result = super(BaseUserForm, self).save(commit=commit)
114
        result = super().save(commit=commit)
115 115
        if commit:
116 116
            self.save_attributes()
117 117
        else:
src/authentic2/forms/registration.py
41 41
    email = ValidatedEmailField(label=_('Email'))
42 42

  
43 43
    def __init__(self, *args, **kwargs):
44
        super(RegistrationForm, self).__init__(*args, **kwargs)
44
        super().__init__(*args, **kwargs)
45 45
        attributes = {a.name: a for a in models.Attribute.objects.all()}
46 46
        for field in app_settings.A2_PRE_REGISTRATION_FIELDS:
47 47
            if field in ('first_name', 'last_name'):
......
127 127
    def save(self, commit=True):
128 128
        self.instance.email_verified = True
129 129
        self.instance.is_active = True
130
        user = super(RegistrationCompletionFormNoPassword, self).save(commit=commit)
130
        user = super().save(commit=commit)
131 131
        if commit and app_settings.A2_REGISTRATION_GROUPS:
132 132
            groups = []
133 133
            for name in app_settings.A2_REGISTRATION_GROUPS:
src/authentic2/forms/utils.py
28 28
        request = StoreRequestMiddleware.get_request()
29 29
        if not next_url and request:
30 30
            next_url = request.GET.get(REDIRECT_FIELD_NAME)
31
        super(NextUrlFormMixin, self).__init__(*args, **kwargs)
31
        super().__init__(*args, **kwargs)
32 32
        if next_url:
33 33
            self.fields['next_url'].initial = next_url
src/authentic2/forms/widgets.py
101 101
CLEAR_BTN_TEMPLATE = """<span class="add-on"><i class="icon-remove"></i></span>"""
102 102

  
103 103

  
104
class PickerWidgetMixin(object):
104
class PickerWidgetMixin:
105 105
    class Media:
106 106
        css = {
107 107
            'all': ('css/datetimepicker.css',),
......
134 134
            lambda x: DATE_FORMAT_JS_PY_MAPPING[x.group()], date_format
135 135
        )
136 136

  
137
        super(PickerWidgetMixin, self).__init__(attrs, format=self.format)
137
        super().__init__(attrs, format=self.format)
138 138

  
139 139
    def get_format(self):
140 140
        format = get_format(self.format_name)[0]
......
146 146
        attrs = attrs or {}
147 147
        final_attrs = self.build_attrs(attrs)
148 148
        final_attrs['class'] = "controls input-append date"
149
        rendered_widget = super(PickerWidgetMixin, self).render(
150
            name, value, attrs=final_attrs, renderer=renderer
151
        )
149
        rendered_widget = super().render(name, value, attrs=final_attrs, renderer=renderer)
152 150

  
153 151
        # if not set, autoclose have to be true.
154 152
        self.options.setdefault('autoclose', True)
......
198 196
        # Set the default options to show only the datepicker object
199 197
        options['format'] = options.get('format', self.get_format())
200 198

  
201
        super(DateTimeWidget, self).__init__(attrs, options, usel10n)
199
        super().__init__(attrs, options, usel10n)
202 200

  
203 201

  
204 202
class DateWidget(PickerWidgetMixin, DateInput):
......
222 220
        options['minView'] = options.get('minView', 2)
223 221
        options['format'] = options.get('format', self.get_format())
224 222

  
225
        super(DateWidget, self).__init__(attrs, options, usel10n)
223
        super().__init__(attrs, options, usel10n)
226 224

  
227 225
    def format_value(self, value):
228 226
        if value is not None:
......
251 249
        options['maxView'] = options.get('maxView', 1)
252 250
        options['format'] = options.get('format', self.get_format())
253 251

  
254
        super(TimeWidget, self).__init__(attrs, options, usel10n)
252
        super().__init__(attrs, options, usel10n)
255 253

  
256 254

  
257 255
class PasswordInput(BasePasswordInput):
......
263 261
        css = {'all': ('authentic2/css/password.css',)}
264 262

  
265 263
    def render(self, name, value, attrs=None, renderer=None):
266
        output = super(PasswordInput, self).render(name, value, attrs=attrs, renderer=renderer)
264
        output = super().render(name, value, attrs=attrs, renderer=renderer)
267 265
        if attrs and app_settings.A2_PASSWORD_POLICY_SHOW_LAST_CHAR:
268 266
            _id = attrs.get('id')
269 267
            if _id:
......
276 274
        if attrs is None:
277 275
            attrs = {}
278 276
        attrs['autocomplete'] = 'new-password'
279
        output = super(NewPasswordInput, self).render(name, value, attrs=attrs, renderer=renderer)
277
        output = super().render(name, value, attrs=attrs, renderer=renderer)
280 278
        if attrs:
281 279
            _id = attrs.get('id')
282 280
            if _id:
......
291 289
        if attrs is None:
292 290
            attrs = {}
293 291
        attrs['autocomplete'] = 'new-password'
294
        output = super(CheckPasswordInput, self).render(name, value, attrs=attrs, renderer=renderer)
292
        output = super().render(name, value, attrs=attrs, renderer=renderer)
295 293
        if attrs:
296 294
            _id = attrs.get('id')
297 295
            if _id and _id.endswith('2'):
......
315 313
    def __init__(self, *args, **kwargs):
316 314
        attrs = kwargs.pop('attrs', {})
317 315
        attrs['accept'] = 'image/*'
318
        super(ProfileImageInput, self).__init__(*args, attrs=attrs, **kwargs)
316
        super().__init__(*args, attrs=attrs, **kwargs)
319 317

  
320 318

  
321 319
class DatalistTextInput(TextInput):
322 320
    def __init__(self, name='', data=(), attrs=None):
323
        super(DatalistTextInput, self).__init__(attrs)
321
        super().__init__(attrs)
324 322
        self.data = data
325 323
        self.name = 'list__%s' % name
326 324
        self.attrs.update({'list': self.name})
327 325

  
328 326
    def render(self, name, value, attrs=None, renderer=None):
329
        output = super(DatalistTextInput, self).render(name, value, attrs=attrs, renderer=renderer)
327
        output = super().render(name, value, attrs=attrs, renderer=renderer)
330 328
        datalist = '<datalist id="%s">' % self.name
331 329
        for element in self.data:
332 330
            datalist += '<option value="%s">' % element
......
354 352
            )
355 353

  
356 354
    def get_context(self, *args, **kwargs):
357
        context = super(EmailInput, self).get_context(*args, **kwargs)
355
        context = super().get_context(*args, **kwargs)
358 356
        if app_settings.A2_SUGGESTED_EMAIL_DOMAINS:
359 357
            context['widget']['attrs']['data-suggested-domains'] = ':'.join(
360 358
                app_settings.A2_SUGGESTED_EMAIL_DOMAINS
src/authentic2/hooks.py
56 56
        except Exception:
57 57
            if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False):
58 58
                raise
59
            logger.exception(u'exception while calling hook %s', hook)
59
            logger.exception('exception while calling hook %s', hook)
60 60

  
61 61

  
62 62
def call_hooks_first_result(hook_name, *args, **kwargs):
......
71 71
        except Exception:
72 72
            if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False):
73 73
                raise
74
            logger.exception(u'exception while calling hook %s', hook)
74
            logger.exception('exception while calling hook %s', hook)
src/authentic2/idp/__init__.py
1

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

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/idp/migrations/0002_auto_20150526_2239.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/idp/migrations/0003_auto_20150915_2041.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/idp/saml/__init__.py
19 19
from django.core.checks import Tags, Warning, register
20 20

  
21 21

  
22
class Plugin(object):
22
class Plugin:
23 23
    def check_origin(self, request, origin):
24 24
        from authentic2.cors import make_origin
25 25
        from authentic2.saml.models import LibertySession
src/authentic2/idp/saml/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    __DEFAULTS = dict(
22 22
        ENABLE=False,
23 23
        METADATA_OPTIONS={},
src/authentic2/idp/saml/backend.py
32 32
from authentic2.utils import Service
33 33

  
34 34

  
35
class SamlBackend(object):
35
class SamlBackend:
36 36
    def __init__(self):
37 37
        self.logger = logging.getLogger(__name__)
38 38

  
......
44 44
        )
45 45
        ls = []
46 46
        sessions = models.LibertySession.objects.filter(django_session_key=request.session.session_key)
47
        sessions_eids = set(session.provider_id for session in sessions)
47
        sessions_eids = {session.provider_id for session in sessions}
48 48
        all_policy = common.get_sp_options_policy_all()
49 49
        default_policy = common.get_sp_options_policy_default()
50 50
        queries = []
......
99 99
    def logout_list(self, request):
100 100
        all_sessions = models.LibertySession.objects.filter(django_session_key=request.session.session_key)
101 101
        self.logger.debug("all_sessions %r" % all_sessions)
102
        provider_ids = set([s.provider_id for s in all_sessions])
102
        provider_ids = {s.provider_id for s in all_sessions}
103 103
        self.logger.debug("provider_ids %r" % provider_ids)
104 104
        result = []
105 105
        for provider_id in provider_ids:
......
109 109
                provider = models.LibertyProvider.objects.get(entity_id=provider_id)
110 110
                name = provider.name
111 111
            except models.LibertyProvider.DoesNotExist:
112
                self.logger.error(u'session found for unknown provider %s', provider_id)
112
                self.logger.error('session found for unknown provider %s', provider_id)
113 113
            else:
114 114
                policy = common.get_sp_options_policy(provider)
115 115
                if not policy:
116
                    self.logger.error(u'No policy found for %s', provider_id)
116
                    self.logger.error('No policy found for %s', provider_id)
117 117
                elif not policy.forward_slo:
118
                    self.logger.info(u'%s configured to not reveive slo', provider_id)
118
                    self.logger.info('%s configured to not reveive slo', provider_id)
119 119
                else:
120 120
                    url = reverse(saml2_endpoints.idp_slo, args=[provider_id])
121 121
                    # add a nonce so this link is never cached
122 122
                    nonce = hex(random.getrandbits(128))
123
                    url = '{0}?provider_id={1}&nonce={2}'.format(url, quote(provider_id), nonce)
123
                    url = f'{url}?provider_id={quote(provider_id)}&nonce={nonce}'
124 124
                    name = name or provider_id
125 125
                    code = render_to_string(
126 126
                        'idp/saml/logout_fragment.html',
src/authentic2/idp/saml/saml2_endpoints.py
32 32
     - assertionIDRequest
33 33
"""
34 34

  
35
from __future__ import unicode_literals
36 35

  
37 36
import datetime
38 37
import hashlib
39 38
import logging
40 39
import random
41 40
import string
42
import xml.etree.cElementTree as ctree
41
import xml.etree.ElementTree as ctree
43 42
from functools import wraps
44 43
from urllib.parse import quote, urlencode
45 44

  
......
367 366
    if attributes:
368 367
        logger.debug('adding attributes')
369 368
        logger.debug('assertion before processing %s', force_text(assertion.dump()))
370
        logger.debug(u'adding attributes %s', attributes)
369
        logger.debug('adding attributes %s', attributes)
371 370
        if not assertion.attributeStatement:
372 371
            assertion.attributeStatement = [lasso.Saml2AttributeStatement()]
373 372
        attribute_statement = assertion.attributeStatement[0]
......
429 428
    else:
430 429
        try:
431 430
            event = find_authentication_event(request, login.request.id)
432
            logger.debug(u'authentication from stored event %s', event)
431
            logger.debug('authentication from stored event %s', event)
433 432
            how = event['how']
434 433
            if how == 'password':
435 434
                authn_context = lasso.SAML2_AUTHN_CONTEXT_PASSWORD
......
506 505
        logger.debug('called by GET')
507 506
        consent_answer = request.GET.get('consent_answer', '')
508 507
        if consent_answer:
509
            logger.debug(u'back from the consent page for federation with answer %s', consent_answer)
508
            logger.debug('back from the consent page for federation with answer %s', consent_answer)
510 509
    server = create_server(request)
511 510
    login = lasso.Login(server)
512 511
    message = get_saml2_request_message(request, login)
......
673 672
            logger.debug('back from the consent page for federation with answer %s', consent_answer)
674 673
        consent_attribute_answer = request.GET.get('consent_attribute_answer', '')
675 674
        if consent_attribute_answer:
676
            logger.debug(u'back from the consent page for attributes %s', consent_attribute_answer)
675
            logger.debug('back from the consent page for attributes %s', consent_attribute_answer)
677 676
    nonce = request.GET.get(NONCE_FIELD_NAME, '')
678 677
    if not nonce:
679 678
        logger.warning('nonce not found')
......
806 805
        if dic and 'authz' in dic:
807 806
            logger.debug('decision is %s', dic['authz'])
808 807
            if 'message' in dic:
809
                logger.debug(u'with message %s', dic['message'])
808
                logger.debug('with message %s', dic['message'])
810 809
            if not dic['authz']:
811 810
                logger.debug('access denied by an external function')
812 811
                access_granted = False
......
932 931

  
933 932
    name_id = build_assertion(request, login, provider, nid_format=nid_format)
934 933
    hooks.call_hooks('event', name='sso-success', idp='saml2', service=service, user=request.user)
935
    logger.info(u'sso success sending AuthenticationResponse to %s with NameID %s', service, name_id)
934
    logger.info('sso success sending AuthenticationResponse to %s with NameID %s', service, name_id)
936 935
    return finish_sso(request, login, user=user, return_profile=return_profile)
937 936

  
938 937

  
......
1211 1210
    )
1212 1211
    django_session_keys = [s.django_session_key for s in lib_session1]
1213 1212
    lib_session = LibertySession.objects.filter(django_session_key__in=django_session_keys)
1214
    providers = set([s.provider_id for s in lib_session])
1213
    providers = {s.provider_id for s in lib_session}
1215 1214
    result = []
1216 1215
    for provider in providers:
1217 1216
        if provider != provider_id:
......
1236 1235
            'AssertionID="xxx" '
1237 1236
            'SessionIndex="{0.session_index}">'.format(liberty_session)
1238 1237
        )
1239
        session.append(u'<saml:NameID Format="{0.name_id_format}" '.format(liberty_session))
1238
        session.append(f'<saml:NameID Format="{liberty_session.name_id_format}" ')
1240 1239
        if liberty_session.name_id_qualifier:
1241
            session.append(u'NameQualifier="{0.name_id_qualifier}" '.format(liberty_session))
1240
            session.append(f'NameQualifier="{liberty_session.name_id_qualifier}" ')
1242 1241
        if liberty_session.name_id_sp_name_qualifier:
1243
            session.append(u'SPNameQualifier="{0.name_id_sp_name_qualifier}" '.format(liberty_session))
1244
        session.append(u'>{0.name_id_content}</saml:NameID>'.format(liberty_session))
1245
        session.append(u'</NidAndSessionIndex>')
1246
    session.append(u'</Session>')
1242
            session.append(f'SPNameQualifier="{liberty_session.name_id_sp_name_qualifier}" ')
1243
        session.append(f'>{liberty_session.name_id_content}</saml:NameID>')
1244
        session.append('</NidAndSessionIndex>')
1245
    session.append('</Session>')
1247 1246
    s = ''.join(session)
1248 1247
    logger.debug('session built %s', s)
1249 1248
    return s
......
1302 1301
                logger.debug('slo cannot logout provider %s, it is no more known.', lib_session.provider_id)
1303 1302
                continue
1304 1303
            else:
1305
                logger.debug(u'provider %s loaded', p)
1304
                logger.debug('provider %s loaded', p)
1306 1305
                policy = get_sp_options_policy(p)
1307 1306
                if not policy:
1308 1307
                    logger.warning('No policy found for %s', lib_session.provider_id)
src/authentic2/idp/saml/views.py
33 33

  
34 34
    def get_queryset(self):
35 35
        # check current user owns this federation
36
        qs = super(FederationDeleteView, self).get_queryset()
36
        qs = super().get_queryset()
37 37
        return qs.filter(user=self.request.user)
38 38

  
39 39
    def delete(self, request, *args, **kwargs):
src/authentic2/ldap_utils.py
24 24

  
25 25
class DnFormatter(string.Formatter):
26 26
    def get_value(self, key, args, kwargs):
27
        value = super(DnFormatter, self).get_value(key, args, kwargs)
27
        value = super().get_value(key, args, kwargs)
28 28
        return value
29 29

  
30 30
    def get_field(self, field_name, args, kwargs):
31
        value, used_arg = super(DnFormatter, self).get_field(field_name, args, kwargs)
31
        value, used_arg = super().get_field(field_name, args, kwargs)
32 32
        if isinstance(value, (list, tuple)) and len(value) == 1:
33 33
            value = value[0]
34 34
        return value, used_arg
35 35

  
36 36
    def format_field(self, value, format_spec):
37
        value = super(DnFormatter, self).format_field(value, format_spec)
37
        value = super().format_field(value, format_spec)
38 38
        return ldap.dn.escape_dn_chars(value)
39 39

  
40 40
    def convert_field(self, value, conversion):
41 41
        if conversion == 's':
42 42
            return force_text(value)
43
        return super(DnFormatter, self).convert_field(value, conversion)
43
        return super().convert_field(value, conversion)
44 44

  
45 45

  
46 46
class FilterFormatter(string.Formatter):
47 47
    def get_value(self, key, args, kwargs):
48
        value = super(FilterFormatter, self).get_value(key, args, kwargs)
48
        value = super().get_value(key, args, kwargs)
49 49
        return value
50 50

  
51 51
    def get_field(self, field_name, args, kwargs):
52
        value, used_arg = super(FilterFormatter, self).get_field(field_name, args, kwargs)
52
        value, used_arg = super().get_field(field_name, args, kwargs)
53 53
        if isinstance(value, (list, tuple)) and len(value) == 1:
54 54
            value = value[0]
55 55
        return value, used_arg
56 56

  
57 57
    def format_field(self, value, format_spec):
58
        value = super(FilterFormatter, self).format_field(value, format_spec)
58
        value = super().format_field(value, format_spec)
59 59
        return ldap.filter.escape_filter_chars(value)
60 60

  
61 61
    def convert_field(self, value, conversion):
62 62
        if conversion == 's':
63 63
            return force_text(value)
64
        return super(FilterFormatter, self).convert_field(value, conversion)
64
        return super().convert_field(value, conversion)
src/authentic2/logger.py
19 19

  
20 20
class SettingsLogLevel(int):
21 21
    def __new__(cls, default_log_level, debug_setting='DEBUG'):
22
        return super(SettingsLogLevel, cls).__new__(cls, getattr(logging, default_log_level))
22
        return super().__new__(cls, getattr(logging, default_log_level))
23 23

  
24 24
    def __init__(self, default_log_level, debug_setting='DEBUG'):
25 25
        self.debug_setting = debug_setting
26
        super(SettingsLogLevel, self).__init__()
26
        super().__init__()
27 27

  
28 28

  
29 29
class DjangoLogger(logging.getLoggerClass()):
30 30
    def getEffectiveLevel(self):
31
        level = super(DjangoLogger, self).getEffectiveLevel()
31
        level = super().getEffectiveLevel()
32 32
        if isinstance(level, SettingsLogLevel):
33 33
            from django.conf import settings
34 34

  
src/authentic2/management/commands/check-and-repair.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import contextlib
20 19
import traceback
......
47 46
    from tenant_schemas.utils import tenant_context
48 47

  
49 48

  
50
class FakeState(object):
49
class FakeState:
51 50
    class FakeException(Exception):
52 51
        pass
53 52

  
......
369 368
            to_change_ou = []
370 369
            with fake_atomic() as fake_state:
371 370
                admin_role = role.get_admin_role()
372
                ok = set(manager_roles) <= set([admin_role])
371
                ok = set(manager_roles) <= {admin_role}
373 372
                if ok and manager_roles:
374 373
                    if list(manager_roles)[0].ou != role.ou:
375 374
                        self.warning(
src/authentic2/management/commands/clean-unused-accounts.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
import logging
20 19
import urllib.parse
src/authentic2/management/commands/import_site.py
69 69
        msg = "Dry run\n" if dry_run else "Real run\n"
70 70
        c_kwargs = create_context_args(options)
71 71
        try:
72
            with open(filename, 'r') as f:
72
            with open(filename) as f:
73 73
                with transaction.atomic():
74 74
                    sys.stdout.write(msg)
75 75
                    result = import_site(json.load(f), ImportContext(**c_kwargs))
src/authentic2/management/commands/slapd-shell.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
import io
20 19
import logging
......
88 87
                    o[ldap_attribute] = [str(getattr(user, user_attribute)).encode('utf-8')]
89 88
                o['objectClass'] = ['inetOrgPerson']
90 89
                dn = 'uid=%s,%s' % (escape_dn_chars(o['uid'][0]), attrs['suffix'])
91
                self.logger.debug(u'sending entry %s %s', dn, o)
90
                self.logger.debug('sending entry %s %s', dn, o)
92 91
                ldif_writer.unparse(dn, o)
93 92
            print(out.getvalue())
94 93
            out.close()
src/authentic2/management/commands/sync-ldap-users.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
try:
20 19
    import ldap
src/authentic2/manager/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    __PREFIX = 'A2_MANAGER_'
22 22
    __DEFAULTS = {
23 23
        'HOMEPAGE_URL': None,
src/authentic2/manager/fields.py
19 19
from . import widgets
20 20

  
21 21

  
22
class Select2Mixin(object):
22
class Select2Mixin:
23 23
    def __init__(self, **kwargs):
24 24
        kwargs['queryset'] = self.widget.get_initial_queryset()
25
        super(Select2Mixin, self).__init__(**kwargs)
25
        super().__init__(**kwargs)
26 26

  
27 27
    def __setattr__(self, key, value):
28 28
        if key == 'queryset':
29 29
            self.widget.queryset = value
30
        super(Select2Mixin, self).__setattr__(key, value)
30
        super().__setattr__(key, value)
31 31

  
32 32

  
33 33
class Select2ModelChoiceField(Select2Mixin, forms.ModelChoiceField):
src/authentic2/manager/forms.py
54 54
logger = logging.getLogger(__name__)
55 55

  
56 56

  
57
class CssClass(object):
57
class CssClass:
58 58
    pass
59 59

  
60 60

  
......
63 63

  
64 64
    def __init__(self, *args, **kwargs):
65 65
        self.request = kwargs.pop('request')
66
        super(FormWithRequest, self).__init__(*args, **kwargs)
66
        super().__init__(*args, **kwargs)
67 67

  
68 68

  
69 69
class SlugMixin(forms.ModelForm):
......
80 80
                i += 1
81 81
        if len(instance.slug) > 256:
82 82
            instance.slug = instance.slug[:252] + hashlib.md5(instance.slug).hexdigest()[:4]
83
        return super(SlugMixin, self).save(commit=commit)
83
        return super().save(commit=commit)
84 84

  
85 85

  
86
class PrefixFormMixin(object):
86
class PrefixFormMixin:
87 87
    def __init__(self, *args, **kwargs):
88 88
        kwargs['prefix'] = self.__class__.prefix
89
        super(PrefixFormMixin, self).__init__(*args, **kwargs)
89
        super().__init__(*args, **kwargs)
90 90

  
91 91

  
92 92
class LimitQuerysetFormMixin(FormWithRequest):
......
95 95
    """
96 96

  
97 97
    def __init__(self, *args, **kwargs):
98
        super(LimitQuerysetFormMixin, self).__init__(*args, **kwargs)
98
        super().__init__(*args, **kwargs)
99 99
        if self.request and not self.request.user.is_anonymous:
100 100
            for name, field in self.fields.items():
101 101
                qs = getattr(field, 'queryset', None)
......
115 115

  
116 116
    def __init__(self, *args, **kwargs):
117 117
        ou = kwargs.pop('ou', None)
118
        super(ChooseUserForm, self).__init__(*args, **kwargs)
118
        super().__init__(*args, **kwargs)
119 119
        # Filter user by ou if asked
120 120
        if ou:
121 121
            self.fields['user'].queryset = self.fields['user'].queryset.filter(ou=ou)
......
147 147

  
148 148
    def __init__(self, *args, **kwargs):
149 149
        ou = kwargs.pop('ou', None)
150
        super(ChooseUserRoleForm, self).__init__(*args, **kwargs)
150
        super().__init__(*args, **kwargs)
151 151
        # Filter roles by ou if asked
152 152
        if ou:
153 153
            self.fields['role'].queryset = self.fields['role'].queryset.filter(ou=ou)
......
176 176
    def __init__(self, *args, **kwargs):
177 177
        request = kwargs.get('request')
178 178

  
179
        super(UserEditForm, self).__init__(*args, **kwargs)
179
        super().__init__(*args, **kwargs)
180 180
        if 'ou' in self.fields and not request.user.is_superuser:
181 181
            field = self.fields['ou']
182 182
            field.required = True
......
220 220
        return password2
221 221

  
222 222
    def clean(self):
223
        super(UserChangePasswordForm, self).clean()
223
        super().clean()
224 224
        if (
225 225
            self.require_password
226 226
            and not self.cleaned_data.get('generate_password')
......
243 243
        return bool(self.instance and self.instance.email)
244 244

  
245 245
    def save(self, commit=True):
246
        user = super(UserChangePasswordForm, self).save(commit=False)
246
        user = super().save(commit=False)
247 247
        new_password = None
248 248
        if self.cleaned_data.get('generate_password'):
249 249
            new_password = generate_password()
......
294 294

  
295 295
    def __init__(self, *args, **kwargs):
296 296
        self.ou = kwargs.pop('ou', None)
297
        super(UserAddForm, self).__init__(*args, **kwargs)
297
        super().__init__(*args, **kwargs)
298 298

  
299 299
    def clean(self):
300 300
        self.instance.ou = self.ou
301
        super(UserAddForm, self).clean()
301
        super().clean()
302 302
        # check if this account is going to be real online account, i.e. with a
303 303
        # password, it it's the case complain that there is no identifiers.
304 304
        has_password = (
......
319 319
        return bool(self.cleaned_data.get('email'))
320 320

  
321 321
    def save(self, commit=True):
322
        user = super(UserAddForm, self).save(commit=commit)
322
        user = super().save(commit=commit)
323 323
        if self.cleaned_data.get('reset_password_at_next_login'):
324 324
            if commit:
325 325
                PasswordReset.objects.get_or_create(user=user)
......
364 364
    internals = forms.BooleanField(initial=False, label=_('Show internal roles'), required=False)
365 365

  
366 366
    def __init__(self, *args, **kwargs):
367
        super(ServiceRoleSearchForm, self).__init__(*args, **kwargs)
367
        super().__init__(*args, **kwargs)
368 368
        if app_settings.SHOW_INTERNAL_ROLES:
369 369
            del self.fields['internals']
370 370

  
371 371
    def filter(self, qs):
372
        if hasattr(super(ServiceRoleSearchForm, self), 'filter'):
373
            qs = super(ServiceRoleSearchForm, self).filter(qs)
372
        if hasattr(super(), 'filter'):
373
            qs = super().filter(qs)
374 374
        if self.cleaned_data.get('text'):
375 375
            qs = qs.filter(name__icontains=self.cleaned_data['text'])
376 376
        if not app_settings.SHOW_INTERNAL_ROLES and not self.cleaned_data.get('internals'):
......
378 378
        return qs
379 379

  
380 380

  
381
class HideOUFieldMixin(object):
381
class HideOUFieldMixin:
382 382
    def __init__(self, *args, **kwargs):
383
        super(HideOUFieldMixin, self).__init__(*args, **kwargs)
383
        super().__init__(*args, **kwargs)
384 384
        if utils.get_ou_count() < 2:
385 385
            del self.fields['ou']
386 386

  
387 387
    def clean(self):
388 388
        if 'ou' not in self.fields:
389 389
            self.instance.ou = get_default_ou()
390
        return super(HideOUFieldMixin, self).clean()
390
        return super().clean()
391 391

  
392 392

  
393 393
class OUSearchForm(FormWithRequest):
......
464 464
                else:
465 465
                    data[ou_key] = str(self.ou_qs[0].pk)
466 466

  
467
        super(OUSearchForm, self).__init__(*args, **kwargs)
467
        super().__init__(*args, **kwargs)
468 468

  
469 469
        # modify choices after initialization
470 470
        if self.ou_count > 1:
......
519 519
        return qs
520 520

  
521 521
    def filter(self, qs):
522
        if hasattr(super(OUSearchForm, self), 'filter'):
523
            qs = super(OUSearchForm, self).filter(qs)
522
        if hasattr(super(), 'filter'):
523
            qs = super().filter(qs)
524 524
        qs = self.filter_by_ou(qs)
525 525
        return qs
526 526

  
......
546 546
            else:
547 547
                ou_qs = ou_qs.none()
548 548
            kwargs['ou_queryset'] = ou_qs
549
        super(UserRoleSearchForm, self).__init__(*args, **kwargs)
549
        super().__init__(*args, **kwargs)
550 550

  
551 551
    def filter_no_ou(self, qs):
552 552
        return qs
......
560 560

  
561 561
    def __init__(self, *args, **kwargs):
562 562
        self.minimum_chars = kwargs.pop('minimum_chars', 0)
563
        super(UserSearchForm, self).__init__(*args, **kwargs)
563
        super().__init__(*args, **kwargs)
564 564

  
565 565
    def not_enough_chars(self):
566 566
        text = self.cleaned_data.get('text')
......
571 571
        return text and len(text) >= self.minimum_chars
572 572

  
573 573
    def filter(self, qs):
574
        qs = super(UserSearchForm, self).filter(qs)
574
        qs = super().filter(qs)
575 575
        if self.enough_chars():
576 576
            qs = qs.free_text_search(self.cleaned_data['text'])
577 577
        elif self.not_enough_chars():
......
610 610

  
611 611
class OUEditForm(SlugMixin, CssClass, forms.ModelForm):
612 612
    def __init__(self, *args, **kwargs):
613
        super(OUEditForm, self).__init__(*args, **kwargs)
613
        super().__init__(*args, **kwargs)
614 614
        self.fields['name'].label = _('label').title()
615 615

  
616 616
    class Meta:
......
646 646
        instance = kwargs.get('instance')
647 647
        if instance:
648 648
            initial['new_email'] = instance.email
649
        super(UserChangeEmailForm, self).__init__(*args, **kwargs)
649
        super().__init__(*args, **kwargs)
650 650

  
651 651
    def save(self, *args, **kwargs):
652 652
        new_email = self.cleaned_data['new_email']
src/authentic2/manager/ou_views.py
70 70
        return str(self.object)
71 71

  
72 72
    def authorize(self, request, *args, **kwargs):
73
        super(OrganizationalUnitDetailView, self).authorize(request, *args, **kwargs)
73
        super().authorize(request, *args, **kwargs)
74 74
        self.can_delete = self.can_delete and not self.object.default
75 75

  
76 76

  
......
106 106
                ),
107 107
            )
108 108
            return self.return_ajax_response(request, HttpResponseRedirect(self.get_success_url()))
109
        return super(OrganizationalUnitDeleteView, self).dispatch(request, *args, **kwargs)
109
        return super().dispatch(request, *args, **kwargs)
110 110

  
111 111

  
112 112
delete = OrganizationalUnitDeleteView.as_view()
src/authentic2/manager/role_views.py
43 43
OU = get_ou_model()
44 44

  
45 45

  
46
class RolesMixin(object):
46
class RolesMixin:
47 47
    service_roles = True
48 48
    admin_roles = False
49 49

  
50 50
    def get_queryset(self):
51
        qs = super(RolesMixin, self).get_queryset()
51
        qs = super().get_queryset()
52 52
        qs = qs.select_related('ou')
53 53
        Permission = get_permission_model()
54 54
        permission_ct = ContentType.objects.get_for_model(Permission)
......
78 78
    title = _('Roles')
79 79

  
80 80
    def get_queryset(self):
81
        qs = super(RolesView, self).get_queryset()
81
        qs = super().get_queryset()
82 82
        qs = qs.annotate(member_count=Count('members'))
83 83
        return qs
84 84

  
85 85
    def get_search_form_kwargs(self):
86
        kwargs = super(RolesView, self).get_search_form_kwargs()
86
        kwargs = super().get_search_form_kwargs()
87 87
        kwargs['queryset'] = self.get_queryset()
88 88
        return kwargs
89 89

  
......
111 111
        return modelform_factory(self.model, form=form, fields=fields)
112 112

  
113 113
    def form_valid(self, form):
114
        response = super(RoleAddView, self).form_valid(form)
114
        response = super().form_valid(form)
115 115
        hooks.call_hooks(
116 116
            'event', name='manager-add-role', user=self.request.user, instance=form.instance, form=form
117 117
        )
......
135 135
                )
136 136
            )
137 137
            return self.export_response(json.dumps(export, indent=4), 'application/json', 'json')
138
        return super(RolesExportView, self).get(request, *args, **kwargs)
138
        return super().get(request, *args, **kwargs)
139 139

  
140 140

  
141 141
export = RolesExportView.as_view()
......
158 158
        return forms.get_role_form_class()
159 159

  
160 160
    def form_valid(self, form):
161
        response = super(RoleEditView, self).form_valid(form)
161
        response = super().form_valid(form)
162 162
        hooks.call_hooks(
163 163
            'event', name='manager-edit-role', user=self.request.user, instance=form.instance, form=form
164 164
        )
......
230 230
                    )
231 231
        else:
232 232
            messages.warning(self.request, _('You are not authorized'))
233
        return super(RoleMembersView, self).form_valid(form)
233
        return super().form_valid(form)
234 234

  
235 235
    def get_form_kwargs(self):
236
        kwargs = super(RoleMembersView, self).get_form_kwargs()
236
        kwargs = super().get_form_kwargs()
237 237
        # if role's members can only be from the same OU we filter user based on the role's OU
238 238
        if app_settings.ROLE_MEMBERS_FROM_OU:
239 239
            kwargs['ou'] = self.object.ou
240 240
        return kwargs
241 241

  
242 242
    def get_context_data(self, **kwargs):
243
        ctx = super(RoleMembersView, self).get_context_data(**kwargs)
243
        ctx = super().get_context_data(**kwargs)
244 244
        ctx['children'] = views.filter_view(
245 245
            self.request, self.object.children(include_self=False, annotate=True)
246 246
        )
......
281 281
    def post(self, request, *args, **kwargs):
282 282
        if not self.can_delete:
283 283
            raise PermissionDenied
284
        return super(RoleDeleteView, self).post(request, *args, **kwargs)
284
        return super().post(request, *args, **kwargs)
285 285

  
286 286
    def get_success_url(self):
287 287
        return reverse('a2-manager-roles')
......
291 291

  
292 292
        hooks.call_hooks('event', name='manager-delete-role', user=request.user, role=role)
293 293
        self.request.journal.record('manager.role.deletion', role=role)
294
        return super(RoleDeleteView, self).delete(request, *args, **kwargs)
294
        return super().delete(request, *args, **kwargs)
295 295

  
296 296

  
297 297
delete = RoleDeleteView.as_view()
......
348 348
                        )
349 349
        else:
350 350
            messages.warning(self.request, _('You are not authorized'))
351
        return super(RolePermissionsView, self).form_valid(form)
351
        return super().form_valid(form)
352 352

  
353 353

  
354 354
permissions = RolePermissionsView.as_view()
......
382 382

  
383 383
    def dispatch(self, request, *args, **kwargs):
384 384
        self.object = self.get_object()
385
        return super(RoleAddChildView, self).dispatch(request, *args, **kwargs)
385
        return super().dispatch(request, *args, **kwargs)
386 386

  
387 387
    def form_valid(self, form):
388 388
        parent = self.get_object()
......
392 392
                'event', name='manager-add-child-role', user=self.request.user, parent=parent, child=role
393 393
            )
394 394
            self.request.journal.record('manager.role.inheritance.addition', parent=parent, child=role)
395
        return super(RoleAddChildView, self).form_valid(form)
395
        return super().form_valid(form)
396 396

  
397 397

  
398 398
add_child = RoleAddChildView.as_view()
......
411 411
        self.object = self.get_object()
412 412
        if self.object.is_internal():
413 413
            raise PermissionDenied
414
        return super(RoleAddParentView, self).dispatch(request, *args, **kwargs)
414
        return super().dispatch(request, *args, **kwargs)
415 415

  
416 416
    def form_valid(self, form):
417 417
        child = self.get_object()
......
421 421
                'event', name='manager-add-child-role', user=self.request.user, parent=role, child=child
422 422
            )
423 423
            self.request.journal.record('manager.role.inheritance.addition', parent=role, child=child)
424
        return super(RoleAddParentView, self).form_valid(form)
424
        return super().form_valid(form)
425 425

  
426 426

  
427 427
add_parent = RoleAddParentView.as_view()
......
437 437
    def dispatch(self, request, *args, **kwargs):
438 438
        self.object = self.get_object()
439 439
        self.child = self.get_queryset().get(pk=kwargs['child_pk'])
440
        return super(RoleRemoveChildView, self).dispatch(request, *args, **kwargs)
440
        return super().dispatch(request, *args, **kwargs)
441 441

  
442 442
    def get_context_data(self, **kwargs):
443
        ctx = super(RoleRemoveChildView, self).get_context_data(**kwargs)
443
        ctx = super().get_context_data(**kwargs)
444 444
        ctx['child'] = self.child
445 445
        return ctx
446 446

  
......
471 471
        if self.object.is_internal():
472 472
            raise PermissionDenied
473 473
        self.parent = self.get_queryset().get(pk=kwargs['parent_pk'])
474
        return super(RoleRemoveParentView, self).dispatch(request, *args, **kwargs)
474
        return super().dispatch(request, *args, **kwargs)
475 475

  
476 476
    def get_context_data(self, **kwargs):
477
        ctx = super(RoleRemoveParentView, self).get_context_data(**kwargs)
477
        ctx = super().get_context_data(**kwargs)
478 478
        ctx['parent'] = self.parent
479 479
        return ctx
480 480

  
......
513 513

  
514 514
    def dispatch(self, request, *args, **kwargs):
515 515
        self.object = self.get_object()
516
        return super(RoleAddAdminRoleView, self).dispatch(request, *args, **kwargs)
516
        return super().dispatch(request, *args, **kwargs)
517 517

  
518 518
    def form_valid(self, form):
519 519
        administered_role = self.get_object()
......
529 529
            self.request.journal.record(
530 530
                'manager.role.administrator.role.addition', role=administered_role, admin_role=role
531 531
            )
532
        return super(RoleAddAdminRoleView, self).form_valid(form)
532
        return super().form_valid(form)
533 533

  
534 534

  
535 535
add_admin_role = RoleAddAdminRoleView.as_view()
......
547 547
    def dispatch(self, request, *args, **kwargs):
548 548
        self.object = self.get_object()
549 549
        self.child = self.get_queryset().get(pk=kwargs['role_pk'])
550
        return super(RoleRemoveAdminRoleView, self).dispatch(request, *args, **kwargs)
550
        return super().dispatch(request, *args, **kwargs)
551 551

  
552 552
    def get_context_data(self, **kwargs):
553
        ctx = super(RoleRemoveAdminRoleView, self).get_context_data(**kwargs)
553
        ctx = super().get_context_data(**kwargs)
554 554
        ctx['child'] = self.child
555 555
        return ctx
556 556

  
......
589 589

  
590 590
    def dispatch(self, request, *args, **kwargs):
591 591
        self.object = self.get_object()
592
        return super(RoleAddAdminUserView, self).dispatch(request, *args, **kwargs)
592
        return super().dispatch(request, *args, **kwargs)
593 593

  
594 594
    def form_valid(self, form):
595 595
        administered_role = self.get_object()
......
605 605
            self.request.journal.record(
606 606
                'manager.role.administrator.user.addition', role=administered_role, admin_user=user
607 607
            )
608
        return super(RoleAddAdminUserView, self).form_valid(form)
608
        return super().form_valid(form)
609 609

  
610 610

  
611 611
add_admin_user = RoleAddAdminUserView.as_view()
......
623 623
    def dispatch(self, request, *args, **kwargs):
624 624
        self.object = self.get_object()
625 625
        self.user = get_user_model().objects.get(pk=kwargs['user_pk'])
626
        return super(RoleRemoveAdminUserView, self).dispatch(request, *args, **kwargs)
626
        return super().dispatch(request, *args, **kwargs)
627 627

  
628 628
    def get_context_data(self, **kwargs):
629
        ctx = super(RoleRemoveAdminUserView, self).get_context_data(**kwargs)
629
        ctx = super().get_context_data(**kwargs)
630 630
        ctx['user'] = self.user
631 631
        return ctx
632 632

  
src/authentic2/manager/service_views.py
63 63
        return self.object.authorized_roles.all()
64 64

  
65 65
    def get(self, request, *args, **kwargs):
66
        result = super(ServiceView, self).get(request, *args, **kwargs)
66
        result = super().get(request, *args, **kwargs)
67 67
        self.service = self.object
68 68
        return result
69 69

  
......
80 80
                self.object.remove_authorized_role(role)
81 81
        else:
82 82
            messages.warning(self.request, _('You are not authorized'))
83
        return super(ServiceView, self).form_valid(form)
83
        return super().form_valid(form)
84 84

  
85 85
    def get_context_data(self, **kwargs):
86 86
        kwargs['form'] = self.get_form()
87
        ctx = super(ServiceView, self).get_context_data(**kwargs)
87
        ctx = super().get_context_data(**kwargs)
88 88
        ctx['roles_table'] = tables.RoleTable(self.object.roles.all())
89 89
        return ctx
90 90

  
src/authentic2/manager/tables.py
33 33
class PermissionLinkColumn(tables.LinkColumn):
34 34
    def __init__(self, viewname, **kwargs):
35 35
        self.permission = kwargs.pop('permission', None)
36
        super(PermissionLinkColumn, self).__init__(viewname, **kwargs)
36
        super().__init__(viewname, **kwargs)
37 37

  
38 38
    def render(self, value, record, bound_column, **kwargs):
39 39
        if self.permission:
40 40
            request = StoreRequestMiddleware.get_request()
41 41
            if request and not request.user.has_perm(self.permission, record):
42 42
                return value
43
        return super(PermissionLinkColumn, self).render(value, record, bound_column)
43
        return super().render(value, record, bound_column)
44 44

  
45 45

  
46 46
class VerifiableEmailColumn(tables.Column):
src/authentic2/manager/user_export.py
34 34
    user_resource = UserResource()
35 35
    fields = user_resource._meta.export_order + ('email_verified', 'is_active', 'modified')
36 36
    attributes = [attr.name for attr in Attribute.objects.all()]
37
    headers = fields + tuple(['attribute_%s' % attr for attr in attributes])
37
    headers = fields + tuple('attribute_%s' % attr for attr in attributes)
38 38

  
39 39
    at_mapping = {a.id: a for a in Attribute.objects.all()}
40 40
    avs = (
......
79 79
    return dataset
80 80

  
81 81

  
82
class UserExport(object):
82
class UserExport:
83 83
    def __init__(self, uuid):
84 84
        self.uuid = uuid
85 85
        self.path = os.path.join(self.base_path(), self.uuid)
......
105 105

  
106 106
    @property
107 107
    def csv(self):
108
        return open(self.export_path, 'r')
108
        return open(self.export_path)
109 109

  
110 110
    def set_export_content(self, content):
111 111
        with open(self.export_path, 'w') as f:
......
115 115
    def progress(self):
116 116
        progress = 0
117 117
        if os.path.exists(self.progress_path):
118
            with open(self.progress_path, 'r') as f:
118
            with open(self.progress_path) as f:
119 119
                progress = f.read()
120 120
        return int(progress) if progress else 0
121 121

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

  
17
from __future__ import unicode_literals
18 17

  
19 18
import base64
20 19
import contextlib
......
43 42
    return base64.b32encode(uuid.uuid4().bytes).strip(b'=').lower().decode('ascii')
44 43

  
45 44

  
46
class UserImport(object):
45
class UserImport:
47 46
    def __init__(self, uuid):
48 47
        self.uuid = uuid
49 48
        self.path = os.path.join(self.base_path(), self.uuid)
......
118 117
            shutil.rmtree(self.path)
119 118

  
120 119

  
121
class Report(object):
120
class Report:
122 121
    STATE_WAITING = 'waiting'
123 122
    STATE_RUNNING = 'running'
124 123
    STATE_FINISHED = 'finished'
......
276 275
            os.unlink(self.path)
277 276

  
278 277

  
279
class Reports(object):
278
class Reports:
280 279
    PREFIX = 'report-'
281 280

  
282 281
    def __init__(self, user_import):
src/authentic2/manager/user_views.py
106 106
        return self.search_form.is_valid() and self.search_form.cleaned_data.get('ou')
107 107

  
108 108
    def get_queryset(self):
109
        qs = super(UsersView, self).get_queryset()
109
        qs = super().get_queryset()
110 110
        qs = qs.select_related('ou')
111 111
        qs = qs.prefetch_related('roles', 'roles__parent_relation__parent')
112 112
        return qs
113 113

  
114 114
    def get_search_form_kwargs(self):
115
        kwargs = super(UsersView, self).get_search_form_kwargs()
115
        kwargs = super().get_search_form_kwargs()
116 116
        kwargs['minimum_chars'] = app_settings.USER_SEARCH_MINIMUM_CHARS
117 117
        kwargs['show_all_ou'] = app_settings.SHOW_ALL_OU
118 118
        return kwargs
119 119

  
120 120
    def filter_by_search(self, qs):
121
        qs = super(UsersView, self).filter_by_search(qs)
121
        qs = super().filter_by_search(qs)
122 122
        if not self.search_form.is_valid():
123 123
            qs = qs.filter(ou=self.request.user.ou)
124 124
        return qs
......
131 131
            exclude = kwargs.setdefault('exclude', [])
132 132
            if 'username' not in exclude:
133 133
                exclude.append('username')
134
        table = super(UsersView, self).get_table(**kwargs)
134
        table = super().get_table(**kwargs)
135 135
        if self.search_form.not_enough_chars():
136 136
            user_qs = self.search_form.filter_by_ou(self.get_queryset())
137 137
            table.empty_text = _('Enter at least %(limit)d characters ' '(%(user_count)d users)') % {
......
142 142
        return table
143 143

  
144 144
    def get_context_data(self, **kwargs):
145
        ctx = super(UsersView, self).get_context_data()
145
        ctx = super().get_context_data()
146 146
        if get_ou_count() < 2:
147 147
            ou = get_default_ou()
148 148
        else:
......
195 195
        return super().dispatch(request, *args, **kwargs)
196 196

  
197 197
    def get_form_kwargs(self):
198
        kwargs = super(UserAddView, self).get_form_kwargs()
198
        kwargs = super().get_form_kwargs()
199 199
        kwargs['ou'] = self.ou
200 200
        return kwargs
201 201

  
......
223 223
        )
224 224

  
225 225
    def get_context_data(self, **kwargs):
226
        context = super(UserAddView, self).get_context_data(**kwargs)
226
        context = super().get_context_data(**kwargs)
227 227
        context['cancel_url'] = select_next_url(self.request, default='../..', field_name='cancel')
228 228
        context['next'] = select_next_url(self.request, default=None, include_post=True)
229 229
        context['ou'] = self.ou
......
245 245
                self.duplicate_users = duplicate_users
246 246
                return self.form_invalid(form)
247 247

  
248
        response = super(UserAddView, self).form_valid(form)
248
        response = super().form_valid(form)
249 249
        hooks.call_hooks(
250 250
            'event', name='manager-add-user', user=self.request.user, instance=form.instance, form=form
251 251
        )
......
253 253
        return response
254 254

  
255 255
    def get_initial(self, *args, **kwargs):
256
        initial = super(UserAddView, self).get_initial(*args, **kwargs)
256
        initial = super().get_initial(*args, **kwargs)
257 257
        initial.update(self.get_user_add_policies())
258 258
        return initial
259 259

  
......
314 314
        return OIDCClient.objects.exists()
315 315

  
316 316
    def get_other_actions(self):
317
        for action in super(UserDetailView, self).get_other_actions():
318
            yield action
317
        yield from super().get_other_actions()
319 318
        yield Action('password_reset', _('Reset password'), permission='custom_user.reset_password_user')
320 319
        if self.object.is_active:
321 320
            yield Action('deactivate', _('Suspend'), permission='custom_user.activate_user')
......
412 411
        return fields
413 412

  
414 413
    def get_form(self, *args, **kwargs):
415
        form = super(UserDetailView, self).get_form(*args, **kwargs)
414
        form = super().get_form(*args, **kwargs)
416 415
        if 'email' in form.fields:
417 416
            if self.object.email_verified:
418 417
                comment = _('Email verified')
......
449 448
            data for datas in hooks.call_hooks('manager_user_data', self, self.object) for data in datas
450 449
        ]
451 450
        kwargs['user_data'] = user_data
452
        ctx = super(UserDetailView, self).get_context_data(**kwargs)
451
        ctx = super().get_context_data(**kwargs)
453 452
        return ctx
454 453

  
455 454

  
......
486 485
        )
487 486

  
488 487
    def get_context_data(self, **kwargs):
489
        context = super(UserEditView, self).get_context_data(**kwargs)
488
        context = super().get_context_data(**kwargs)
490 489
        next_url = self._get_next_url()
491 490
        context['next'] = next_url
492 491
        context['cancel_url'] = next_url
......
499 498
        if 'email' in form.changed_data:
500 499
            self.object.email_verified = False
501 500
            self.object.save()
502
        response = super(UserEditView, self).form_valid(form)
501
        response = super().form_valid(form)
503 502
        if form.has_changed():
504 503
            hooks.call_hooks(
505 504
                'event', name='manager-edit-user', user=self.request.user, instance=form.instance, form=form
......
581 580
            return ugettext('New password set')
582 581

  
583 582
    def form_valid(self, form):
584
        response = super(UserChangePasswordView, self).form_valid(form)
583
        response = super().form_valid(form)
585 584
        hooks.call_hooks(
586 585
            'event', name='manager-change-password', user=self.request.user, instance=form.instance, form=form
587 586
        )
......
607 606
        return None
608 607

  
609 608
    def form_valid(self, form):
610
        response = super(UserChangeEmailView, self).form_valid(form)
609
        response = super().form_valid(form)
611 610
        new_email = form.cleaned_data['new_email']
612 611
        hooks.call_hooks(
613 612
            'event',
......
669 668
            return self.object.roles_and_parents()
670 669

  
671 670
    def get_table_data(self):
672
        qs = super(UserRolesView, self).get_table_data()
671
        qs = super().get_table_data()
673 672
        if self.is_ou_specified():
674 673
            qs = list(qs)
675 674
        return qs
676 675

  
677 676
    def authorize(self, request, *args, **kwargs):
678
        response = super(UserRolesView, self).authorize(request, *args, **kwargs)
677
        response = super().authorize(request, *args, **kwargs)
679 678
        if response is not None:
680 679
            return response
681 680
        if not UserDetailView.has_perm_on_roles(request.user, self.object):
......
703 702
                    'event', name='manager-remove-role-member', user=self.request.user, role=role, member=user
704 703
                )
705 704
                self.request.journal.record('manager.role.membership.removal', member=user, role=role)
706
        return super(UserRolesView, self).form_valid(form)
705
        return super().form_valid(form)
707 706

  
708 707
    def get_search_form_kwargs(self):
709
        kwargs = super(UserRolesView, self).get_search_form_kwargs()
708
        kwargs = super().get_search_form_kwargs()
710 709
        kwargs['all_ou_label'] = ''
711 710
        kwargs['user'] = self.object
712 711
        kwargs['role_members_from_ou'] = app_settings.ROLE_MEMBERS_FROM_OU
......
720 719
        return kwargs
721 720

  
722 721
    def get_form_kwargs(self):
723
        kwargs = super(UserRolesView, self).get_form_kwargs()
722
        kwargs = super().get_form_kwargs()
724 723
        # if role members can only be from the same OU, we filter roles based on the user's ou
725 724
        if app_settings.ROLE_MEMBERS_FROM_OU and self.object.ou_id:
726 725
            kwargs['ou'] = self.object.ou
......
760 759
            uuid = request.POST['delete']
761 760
            user_import.UserImport(uuid).delete()
762 761
            return redirect(self.request, 'a2-manager-users-imports')
763
        return super(UserImportsView, self).post(request, *args, **kwargs)
762
        return super().post(request, *args, **kwargs)
764 763

  
765 764
    def form_valid(self, form):
766 765
        user_import = form.save()
......
772 771
    def get_context_data(self, **kwargs):
773 772
        from authentic2.manager import user_import
774 773

  
775
        ctx = super(UserImportsView, self).get_context_data(**kwargs)
774
        ctx = super().get_context_data(**kwargs)
776 775
        ctx['imports'] = sorted(
777 776
            user_import.UserImport.all(), key=operator.attrgetter('created'), reverse=True
778 777
        )
......
845 844
        if self.user_import.encoding == 'utf-8':
846 845
            with self.user_import.meta_update as meta:
847 846
                meta['encoding'] = 'utf-8-sig'
848
        return super(UserImportView, self).dispatch(request, uuid, **kwargs)
847
        return super().dispatch(request, uuid, **kwargs)
849 848

  
850 849
    def get(self, request, uuid, filename=None):
851 850
        if filename:
852 851
            return FileResponse(self.user_import.import_file, content_type='text/csv')
853
        return super(UserImportView, self).get(request, uuid=uuid, filename=filename)
852
        return super().get(request, uuid=uuid, filename=filename)
854 853

  
855 854
    def post(self, request, *args, **kwargs):
856 855
        from authentic2.manager import user_import
......
870 869
        return redirect(request, 'a2-manager-users-import', kwargs={'uuid': self.user_import.uuid})
871 870

  
872 871
    def get_context_data(self, **kwargs):
873
        ctx = super(UserImportView, self).get_context_data(**kwargs)
872
        ctx = super().get_context_data(**kwargs)
874 873
        ctx['encoding'] = [encoding for id, encoding in ENCODINGS if id == self.user_import.encoding][0]
875 874
        ctx['user_import'] = self.user_import
876 875
        ctx['reports'] = sorted(self.user_import.reports, key=operator.attrgetter('created'), reverse=True)
......
894 893
            self.report = self.user_import.reports[report_uuid]
895 894
        except KeyError:
896 895
            raise Http404
897
        return super(UserImportReportView, self).dispatch(request, import_uuid, report_uuid)
896
        return super().dispatch(request, import_uuid, report_uuid)
898 897

  
899 898
    def get_context_data(self, **kwargs):
900
        ctx = super(UserImportReportView, self).get_context_data(**kwargs)
899
        ctx = super().get_context_data(**kwargs)
901 900
        ctx['user_import'] = self.user_import
902 901
        ctx['report'] = self.report
903 902
        if self.report.simulate:
......
934 933
    def dispatch(self, request, *args, **kwargs):
935 934
        if not request.user.is_superuser:
936 935
            raise PermissionDenied
937
        return super(UserSuView, self).dispatch(request, *args, **kwargs)
936
        return super().dispatch(request, *args, **kwargs)
938 937

  
939 938
    def get_context_data(self, **kwargs):
940
        ctx = super(UserSuView, self).get_context_data(**kwargs)
939
        ctx = super().get_context_data(**kwargs)
941 940
        ctx['su_url'] = make_url(
942 941
            'auth_logout',
943 942
            params={REDIRECT_FIELD_NAME: switch_user.build_url(self.object, self.duration)},
......
972 971
        return qs
973 972

  
974 973
    def form_valid(self, form):
975
        response = super(UserAuthorizationsView, self).form_valid(form)
974
        response = super().form_valid(form)
976 975
        auth_id = form.cleaned_data['authorization']
977 976
        if self.can_manage_authorizations:
978 977
            qs = OIDCAuthorization.objects.filter(user=self.get_object())
src/authentic2/manager/utils.py
25 25
    if user.first_name or user.last_name:
26 26
        labels.append(user.first_name)
27 27
        if user.first_name and user.last_name:
28
            labels.append(u' ')
28
            labels.append(' ')
29 29
        labels.append(user.last_name)
30 30
    if user.email and user.email not in labels:
31 31
        if labels:
32
            labels.append(u' - ')
32
            labels.append(' - ')
33 33
        labels.append(user.email)
34 34
    if user.username and user.username not in labels:
35 35
        if labels:
36
            labels.append(u' - ')
36
            labels.append(' - ')
37 37
        labels.append(user.username)
38 38
    return ''.join(labels)
39 39

  
src/authentic2/manager/views.py
53 53
    pass
54 54

  
55 55

  
56
class MultipleOUMixin(object):
56
class MultipleOUMixin:
57 57
    '''Tell templates if there are multiple OU for adaptation in breadcrumbs for example'''
58 58

  
59 59
    def get_context_data(self, **kwargs):
60 60
        kwargs['multiple_ou'] = utils.get_ou_count() > 1
61
        return super(MultipleOUMixin, self).get_context_data(**kwargs)
61
        return super().get_context_data(**kwargs)
62 62

  
63 63

  
64
class MediaMixin(object, metaclass=MediaMixinBase):
64
class MediaMixin(metaclass=MediaMixinBase):
65 65
    '''Expose needed CSS and JS files as a media object'''
66 66

  
67 67
    class Media:
......
79 79

  
80 80
    def get_context_data(self, **kwargs):
81 81
        kwargs['media'] = self.media
82
        ctx = super(MediaMixin, self).get_context_data(**kwargs)
82
        ctx = super().get_context_data(**kwargs)
83 83
        if 'form' in ctx:
84 84
            ctx['media'] += ctx['form'].media
85 85
        return ctx
86 86

  
87 87

  
88
class PermissionMixin(object):
88
class PermissionMixin:
89 89
    '''Control access to views based on permissions'''
90 90

  
91 91
    permissions = None
......
121 121
        response = self.authorize(request, *args, **kwargs)
122 122
        if response is not None:
123 123
            return response
124
        return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
124
        return super().dispatch(request, *args, **kwargs)
125 125

  
126 126

  
127 127
def filter_view(request, qs):
......
130 130
    return request.user.filter_by_perm(perm, qs)
131 131

  
132 132

  
133
class FilterQuerysetByPermMixin(object):
133
class FilterQuerysetByPermMixin:
134 134
    def get_queryset(self):
135
        qs = super(FilterQuerysetByPermMixin, self).get_queryset()
135
        qs = super().get_queryset()
136 136
        return filter_view(self.request, qs)
137 137

  
138 138

  
139
class FilterTableQuerysetByPermMixin(object):
139
class FilterTableQuerysetByPermMixin:
140 140
    def get_table_data(self):
141
        qs = super(FilterTableQuerysetByPermMixin, self).get_table_data()
141
        qs = super().get_table_data()
142 142
        if getattr(self, 'filter_table_by_perm', True):
143 143
            qs = filter_view(self.request, qs)
144 144
        return qs
145 145

  
146 146

  
147
class TableQuerysetMixin(object):
147
class TableQuerysetMixin:
148 148
    def get_table_queryset(self):
149 149
        return self.get_queryset()
150 150

  
......
152 152
        return self.get_table_queryset()
153 153

  
154 154

  
155
class SearchFormMixin(object):
155
class SearchFormMixin:
156 156
    """Handle a search form on the current table view.
157 157

  
158 158
    The search form class must implement a .filter(qs) method returning a new queryset."""
......
173 173

  
174 174
    def dispatch(self, request, *args, **kwargs):
175 175
        self.search_form = self.get_search_form()
176
        return super(SearchFormMixin, self).dispatch(request, *args, **kwargs)
176
        return super().dispatch(request, *args, **kwargs)
177 177

  
178 178
    def get_context_data(self, **kwargs):
179
        ctx = super(SearchFormMixin, self).get_context_data(**kwargs)
179
        ctx = super().get_context_data(**kwargs)
180 180
        if self.search_form:
181 181
            ctx['search_form'] = self.search_form
182 182
        return ctx
......
187 187
        return qs
188 188

  
189 189
    def get_table_data(self):
190
        qs = super(SearchFormMixin, self).get_table_data()
190
        qs = super().get_table_data()
191 191
        qs = self.filter_by_search(qs)
192 192
        return qs
193 193

  
194 194

  
195
class FormatsContextData(object):
195
class FormatsContextData:
196 196
    '''Export list of supported formats in context'''
197 197

  
198 198
    formats = ['csv']
199 199

  
200 200
    def get_context_data(self, **kwargs):
201
        ctx = super(FormatsContextData, self).get_context_data(**kwargs)
201
        ctx = super().get_context_data(**kwargs)
202 202
        ctx['formats'] = self.formats
203 203
        return ctx
204 204

  
205 205

  
206
class Action(object):
206
class Action:
207 207
    '''Describe an action for view supporting multiples actions.'''
208 208

  
209 209
    name = None
......
238 238
        return True
239 239

  
240 240

  
241
class AjaxFormViewMixin(object):
241
class AjaxFormViewMixin:
242 242
    '''Implement a JSON response for view which can be included in an AJAX popup'''
243 243

  
244 244
    success_url = '.'
245 245

  
246 246
    def dispatch(self, request, *args, **kwargs):
247
        response = super(AjaxFormViewMixin, self).dispatch(request, *args, **kwargs)
247
        response = super().dispatch(request, *args, **kwargs)
248 248
        return self.return_ajax_response(request, response)
249 249

  
250 250
    def return_ajax_response(self, request, response):
......
269 269
        return HttpResponse(json.dumps(data), content_type='application/json')
270 270

  
271 271

  
272
class TitleMixin(object):
272
class TitleMixin:
273 273
    '''Mixin to provide a title to the view's template'''
274 274

  
275 275
    title = ''
276 276

  
277 277
    def get_context_data(self, **kwargs):
278
        ctx = super(TitleMixin, self).get_context_data(**kwargs)
278
        ctx = super().get_context_data(**kwargs)
279 279
        ctx['title'] = self.title
280 280
        ctx['manager_site_title'] = app_settings.SITE_TITLE
281 281
        return ctx
282 282

  
283 283

  
284
class ActionMixin(object):
284
class ActionMixin:
285 285
    '''Describe the main action implementd by a view'''
286 286

  
287 287
    action = None
288 288

  
289 289
    def get_context_data(self, **kwargs):
290
        ctx = super(ActionMixin, self).get_context_data(**kwargs)
290
        ctx = super().get_context_data(**kwargs)
291 291
        if self.action:
292 292
            ctx['action'] = self.action
293 293
        return ctx
294 294

  
295 295

  
296
class OtherActionsMixin(object):
296
class OtherActionsMixin:
297 297
    '''Describe secondary actions possible on a view'''
298 298

  
299 299
    other_actions = None
300 300

  
301 301
    def get_context_data(self, **kwargs):
302
        ctx = super(OtherActionsMixin, self).get_context_data(**kwargs)
302
        ctx = super().get_context_data(**kwargs)
303 303
        ctx['other_actions'] = tuple(self.get_displayed_other_actions())
304 304
        return ctx
305 305

  
......
340 340
                    return response
341 341
                self.request.method = 'GET'
342 342
                return self.get(request, *args, **kwargs)
343
        parent = super(OtherActionsMixin, self)
343
        parent = super()
344 344
        if hasattr(parent, 'post'):
345 345
            return parent.post(request, *args, **kwargs)
346 346
        return self.get(request, *args, **kwargs)
347 347

  
348 348

  
349
class ExportMixin(object):
349
class ExportMixin:
350 350
    '''Help in implementd export views'''
351 351

  
352 352
    http_method_names = ['get', 'head', 'options']
......
383 383
        return response
384 384

  
385 385

  
386
class FormNeedsRequest(object):
386
class FormNeedsRequest:
387 387
    def get_form_kwargs(self):
388
        kwargs = super(FormNeedsRequest, self).get_form_kwargs()
388
        kwargs = super().get_form_kwargs()
389 389
        if getattr(self.get_form_class(), 'need_request', False):
390 390
            kwargs['request'] = self.request
391 391
        return kwargs
......
403 403
        return ''
404 404

  
405 405
    def get_context_data(self, **kwargs):
406
        ctx = super(ModelNameMixin, self).get_context_data(**kwargs)
406
        ctx = super().get_context_data(**kwargs)
407 407
        ctx['model_name'] = self.get_model_name()
408 408
        return ctx
409 409

  
410 410

  
411
class TableHookMixin(object):
411
class TableHookMixin:
412 412
    '''Helper class for table views, hiding the OU column from tables if an OU filter exists'''
413 413

  
414 414
    def get_table(self, **kwargs):
415
        table = super(TableHookMixin, self).get_table(**kwargs)
415
        table = super().get_table(**kwargs)
416 416
        import copy
417 417

  
418 418
        table = copy.deepcopy(table)
......
500 500
        return modelform_factory(self.model, form=self.form_class, fields=self.get_fields())
501 501

  
502 502
    def get_form(self, form_class=None):
503
        form = super(ModelFormView, self).get_form(form_class=form_class)
503
        form = super().get_form(form_class=form_class)
504 504
        hooks.call_hooks('manager_modify_form', self, form)
505 505
        return form
506 506

  
......
532 532
        form = self.get_form()
533 533
        hooks.call_hooks('manager_modify_form', self, form)
534 534
        kwargs['form'] = form
535
        ctx = super(BaseDetailView, self).get_context_data(**kwargs)
535
        ctx = super().get_context_data(**kwargs)
536 536
        return ctx
537 537

  
538 538

  
......
553 553

  
554 554
    @property
555 555
    def title(self):
556
        return ('Add %s') % super(BaseAddView, self).get_model_name()
556
        return ('Add %s') % super().get_model_name()
557 557

  
558 558
    def get_success_url(self):
559 559
        return reverse(self.success_view_name, kwargs={'pk': self.object.pk})
......
634 634
    def dispatch(self, request, *args, **kwargs):
635 635
        if app_settings.HOMEPAGE_URL:
636 636
            return redirect(request, app_settings.HOMEPAGE_URL)
637
        return super(HomepageView, self).dispatch(request, *args, **kwargs)
637
        return super().dispatch(request, *args, **kwargs)
638 638

  
639 639
    def get_homepage_entries(self):
640 640
        entries = []
......
661 661
        kwargs['can_view_journal'] = self.request.user.has_perms(
662 662
            ['custom_user.view_user', 'a2_rbac.view_role']
663 663
        )
664
        return super(HomepageView, self).get_context_data(**kwargs)
664
        return super().get_context_data(**kwargs)
665 665

  
666 666

  
667 667
homepage = HomepageView.as_view()
......
686 686
menu_json = json_view(MenuJson.as_view())
687 687

  
688 688

  
689
class HideOUColumnMixin(object):
689
class HideOUColumnMixin:
690 690
    '''Helper class for table views, hiding the OU column from tables if an OU filter exists'''
691 691

  
692 692
    def get_table(self, **kwargs):
......
704 704
            exclude = kwargs.setdefault('exclude', [])
705 705
            if 'ou' not in exclude:
706 706
                exclude.append('ou')
707
        return super(HideOUColumnMixin, self).get_table(**kwargs)
707
        return super().get_table(**kwargs)
708 708

  
709 709

  
710 710
class Select2View(AutoResponseView):
......
763 763
            form.add_error('site_json', e)
764 764
            return self.form_invalid(form)
765 765

  
766
        return super(SiteImportView, self).form_valid(form)
766
        return super().form_valid(form)
767 767

  
768 768
    def dispatch(self, request, *args, **kwargs):
769 769
        if not request.user.is_superuser:
770 770
            raise PermissionDenied
771
        return super(SiteImportView, self).dispatch(request, *args, **kwargs)
771
        return super().dispatch(request, *args, **kwargs)
772 772

  
773 773

  
774 774
site_import = SiteImportView.as_view()
src/authentic2/manager/widgets.py
30 30
from . import utils
31 31

  
32 32

  
33
class SplitTermMixin(object):
33
class SplitTermMixin:
34 34
    split_term_operator = operator.__or__
35 35

  
36 36
    def filter_queryset(self, term, queryset=None):
......
42 42
            return qs.all()
43 43
        queries = []
44 44
        for term in term.split():
45
            queries.append(super(SplitTermMixin, self).filter_queryset(term, queryset=qs))
45
            queries.append(super().filter_queryset(term, queryset=qs))
46 46
        qs = functools.reduce(self.split_term_operator, queries)
47 47
        return qs
48 48

  
49 49

  
50
class Select2Mixin(object):
50
class Select2Mixin:
51 51
    class Media:
52 52
        js = ('authentic2/manager/js/select2_locale.js',)
53 53

  
54 54
    def build_attrs(self, *args, **kwargs):
55
        attrs = super(Select2Mixin, self).build_attrs(*args, **kwargs)
55
        attrs = super().build_attrs(*args, **kwargs)
56 56
        field_data = {
57 57
            'class': self.__class__.__name__,
58 58
            'where_clause': force_text(base64.b64encode(pickle.dumps(self.queryset.query.where))),
......
106 106
    def label_from_instance(self, obj):
107 107
        label = str(obj)
108 108
        if obj.ou and utils.get_ou_count() > 1:
109
            label = '{ou} - {obj}'.format(ou=obj.ou, obj=obj)
109
            label = f'{obj.ou} - {obj}'
110 110
        return label
111 111

  
112 112

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

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0002_auto_20150320_1418.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0003_auto_20150409_1840.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0004_service.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0005_service_ou.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
......
23 20
        ),
24 21
        migrations.AlterUniqueTogether(
25 22
            name='service',
26
            unique_together=set([('slug', 'ou')]),
23
            unique_together={('slug', 'ou')},
27 24
        ),
28 25
    ]
src/authentic2/migrations/0006_conditional_slug_index.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations
5 2

  
6 3
from authentic2.migrations import CreatePartialIndexes
src/authentic2/migrations/0007_auto_20150523_0028.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0008_auto_20160204_1415.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0009_auto_20160211_2247.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0010_attributevalue_multiple.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0011_auto_20160211_2253.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0012_auto_20160211_2255.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0013_auto_20160211_2258.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
from authentic2.migrations import CreatePartialIndexes
......
15 12
    operations = [
16 13
        migrations.AlterUniqueTogether(
17 14
            name='attributevalue',
18
            unique_together=set([('content_type', 'object_id', 'attribute', 'multiple', 'content')]),
15
            unique_together={('content_type', 'object_id', 'attribute', 'multiple', 'content')},
19 16
        ),
20 17
        CreatePartialIndexes(
21 18
            'AttributeValue',
src/authentic2/migrations/0014_attributevalue_verified.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0015_auto_20160621_1711.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0016_attribute_disabled.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0017_modify_attribute_serialization.py
1
# -*- coding: utf-8 -*-
2 1
import json
3 2

  
4 3
from django.db import migrations
src/authentic2/migrations/0018_auto_20170524_0842.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0019_auto_20170309_1529.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0020_delete_federatedid.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0021_attribute_order.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2/migrations/0022_attribute_scopes.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/migrations/0023_auto_20181031_0900.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.12 on 2018-10-31 08:00
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/migrations/0024_auto_20190617_1113.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2019-06-17 09:13
3
from __future__ import unicode_literals
4 2

  
5 3
from django.db import migrations
6 4

  
......
23 21
        ),
24 22
        migrations.AlterUniqueTogether(
25 23
            name='userexternalid',
26
            unique_together=set([('source', 'external_id')]),
24
            unique_together={('source', 'external_id')},
27 25
        ),
28 26
    ]
src/authentic2/migrations/0025_auto_20191009_1047.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2019-10-09 08:47
3
from __future__ import unicode_literals
4 2

  
5 3
import django.db.models.deletion
6 4
from django.conf import settings
src/authentic2/migrations/0026_token.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2020-02-11 10:27
3
from __future__ import unicode_literals
4 2

  
5 3
import uuid
6 4

  
src/authentic2/migrations/0027_remove_deleteduser.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.29 on 2020-04-21 14:09
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2/migrations/0028_trigram_unaccent_index.py
1 1
# Generated by Django 1.11.18 on 2020-09-17 15:38
2
from __future__ import unicode_literals
3 2

  
4 3
from django.db import migrations
5 4

  
src/authentic2/migrations/0029_auto_20201013_1614.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-10-13 14:14
3
from __future__ import unicode_literals
4 2

  
5 3
from django.db import migrations
6 4

  
src/authentic2/models.py
56 56
    updated = models.DateTimeField(auto_now=True, verbose_name=_('last update date'))
57 57

  
58 58
    def __str__(self):
59
        return '{0} is {1} on {2}'.format(self.user, self.external_id, self.source)
59
        return f'{self.user} is {self.external_id} on {self.source}'
60 60

  
61 61
    def __repr__(self):
62
        return (
63
            '<UserExternalId user: {0!r} source: {1!r} '
64
            'external_id: {2!r} created: {3} updated: {4}'.format(
65
                self.user_id, self.source, self.external_id, self.created, self.updated
66
            )
62
        return '<UserExternalId user: {!r} source: {!r} ' 'external_id: {!r} created: {} updated: {}'.format(
63
            self.user_id, self.source, self.external_id, self.created, self.updated
67 64
        )
68 65

  
69 66
    class Meta:
......
356 353
        if self.user_id and not self.user.has_usable_password():
357 354
            self.user.set_password(uuid.uuid4().hex)
358 355
            self.user.save()
359
        return super(PasswordReset, self).save(*args, **kwargs)
356
        return super().save(*args, **kwargs)
360 357

  
361 358
    class Meta:
362 359
        verbose_name = _('password reset')
src/authentic2/nonce/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/passwords.py
49 49
    return ''.join(new_password)
50 50

  
51 51

  
52
class PasswordChecker(object, metaclass=abc.ABCMeta):
53
    class Check(object):
52
class PasswordChecker(metaclass=abc.ABCMeta):
53
    class Check:
54 54
        def __init__(self, label, result):
55 55
            self.label = label
56 56
            self.result = result
......
123 123
    password_checker = get_password_checker()
124 124
    criteria = [check.label for check in password_checker(password) if not (only_errors and check.result)]
125 125
    if criteria:
126
        html_criteria = [u'<span class="a2-password-policy-rule">%s</span>' % criter for criter in criteria]
126
        html_criteria = ['<span class="a2-password-policy-rule">%s</span>' % criter for criter in criteria]
127 127
        return _(
128 128
            'In order to create a secure password, please use at least: '
129 129
            '<span class="a2-password-policy-container">%s</span>'
src/authentic2/saml/admin.py
52 52
class TextAndFileWidget(forms.widgets.MultiWidget):
53 53
    def __init__(self, attrs=None):
54 54
        widgets = (forms.widgets.Textarea(), forms.widgets.FileInput())
55
        super(TextAndFileWidget, self).__init__(widgets, attrs)
55
        super().__init__(widgets, attrs)
56 56

  
57 57
    def decompress(self, value):
58 58
        return (value, None)
......
73 73
            attrs = {}
74 74
        if isinstance(value, (str, str)):
75 75
            attrs['rows'] = value.count('\n') + 5
76
            attrs['cols'] = min(max((len(x) for x in value.split('\n'))), 150)
77
        return super(TextAndFileWidget, self).render(name, value, attrs, **kwargs)
76
            attrs['cols'] = min(max(len(x) for x in value.split('\n')), 150)
77
        return super().render(name, value, attrs, **kwargs)
78 78

  
79 79

  
80 80
class LibertyProviderForm(ModelForm):
......
114 114
class SAMLAttributeInlineForm(forms.ModelForm):
115 115
    def __init__(self, *args, **kwargs):
116 116
        service = kwargs.pop('service', None)
117
        super(SAMLAttributeInlineForm, self).__init__(*args, **kwargs)
117
        super().__init__(*args, **kwargs)
118 118
        choices = list(get_service_attributes(service))
119 119
        choices += [('edupersontargetedid', 'eduPersonTargetedId')]
120 120
        self.fields['attribute_name'].choices = choices
......
140 140
        class NewForm(self.form):
141 141
            def __init__(self, *args, **kwargs):
142 142
                kwargs['service'] = obj
143
                super(NewForm, self).__init__(*args, **kwargs)
143
                super().__init__(*args, **kwargs)
144 144

  
145 145
        kwargs['form'] = NewForm
146
        return super(SAMLAttributeInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
146
        return super().get_formset(request, obj=obj, **kwargs)
147 147

  
148 148

  
149 149
class LibertyProviderAdmin(admin.ModelAdmin):
......
167 167
    )
168 168

  
169 169
    def get_urls(self):
170
        urls = super(LibertyProviderAdmin, self).get_urls()
170
        urls = super().get_urls()
171 171
        urls = [
172 172
            url(
173 173
                r'^add-from-url/$',
src/authentic2/saml/admin_views.py
20 20
from .forms import AddLibertyProviderFromUrlForm
21 21

  
22 22

  
23
class AdminAddFormViewMixin(object):
23
class AdminAddFormViewMixin:
24 24
    model_admin = None
25 25

  
26 26
    def get_context_data(self, **kwargs):
27
        ctx = super(AdminAddFormViewMixin, self).get_context_data(**kwargs)
27
        ctx = super().get_context_data(**kwargs)
28 28
        ctx.update(
29 29
            {
30 30
                'app_label': self.model_admin.model._meta.app_label,
......
40 40
    template_name = 'admin/saml/libertyprovider/add_from_url.html'
41 41

  
42 42
    def get_form_kwargs(self, **kwargs):
43
        kwargs = super(AddLibertyProviderFromUrlView, self).get_form_kwargs(**kwargs)
43
        kwargs = super().get_form_kwargs(**kwargs)
44 44
        if 'entity_id' in self.request.GET:
45 45
            initial = kwargs.setdefault('initial', {})
46 46
            initial['url'] = self.request.GET['entity_id']
......
49 49
    def form_valid(self, form):
50 50
        form.save()
51 51
        self.success_url = reverse('admin:saml_libertyprovider_change', args=(form.instance.id,))
52
        return super(AddLibertyProviderFromUrlView, self).form_valid(form)
52
        return super().form_valid(form)
src/authentic2/saml/app_settings.py
21 21
from django.utils.translation import ugettext_lazy as _
22 22

  
23 23

  
24
class AppSettings(object):
24
class AppSettings:
25 25
    __PREFIX = 'SAML_'
26 26
    __NAMES = ('ALLOWED_FEDERATION_MODE', 'DEFAULT_FEDERATION_MODE')
27 27

  
src/authentic2/saml/fields.py
123 123

  
124 124
    def __init__(self, *args, **kwargs):
125 125
        self.max_choices = kwargs.pop('max_choices', 0)
126
        super(MultiSelectFormField, self).__init__(*args, **kwargs)
126
        super().__init__(*args, **kwargs)
127 127

  
128 128
    def clean(self, value):
129 129
        if not value and self.required:
......
168 168
    def validate(self, value, model_instance):
169 169
        out = set()
170 170
        if self.choices:
171
            out |= set([option_key for option_key, _ in self.choices])
171
            out |= {option_key for option_key, _ in self.choices}
172 172
        out = set(value) - out
173 173
        if out:
174 174
            raise ValidationError(self.error_messages['invalid_choice'] % ','.join(list(out)))
......
193 193
            return self.to_python(value)
194 194

  
195 195
    def contribute_to_class(self, cls, name):
196
        super(MultiSelectField, self).contribute_to_class(cls, name)
196
        super().contribute_to_class(cls, name)
197 197
        if self.choices:
198 198

  
199 199
            def func(self, fieldname=name, choicedict=dict(self.choices)):
src/authentic2/saml/forms.py
39 39
    )
40 40

  
41 41
    def clean(self):
42
        cleaned_data = super(AddLibertyProviderFromUrlForm, self).clean()
42
        cleaned_data = super().clean()
43 43
        name = cleaned_data.get('name')
44 44
        slug = cleaned_data.get('slug')
45 45
        url = cleaned_data.get('url')
src/authentic2/saml/lasso_helper.py
21 21

  
22 22

  
23 23
def lasso_elt(name):
24
    return '{{{0}}}{1}'.format(LASSO_NS, name)
24
    return f'{{{LASSO_NS}}}{name}'
25 25

  
26 26

  
27 27
def samla_elt(name):
28
    return '{{{0}}}{1}'.format(SAML_ASSERTION_NS, name)
28
    return f'{{{SAML_ASSERTION_NS}}}{name}'
29 29

  
30 30

  
31 31
SESSION_ELT = lasso_elt('Session')
src/authentic2/saml/management/commands/sync-metadata.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
import io
20 19
import os
......
345 344
            try:
346 345
                with open(metadata_file_path, 'rb') as fd:
347 346
                    metadata_file = io.BytesIO(fd.read())
348
            except IOError:
347
            except OSError:
349 348
                raise CommandError('Unable to open file %s' % metadata_file_path)
350 349

  
351 350
        try:
src/authentic2/saml/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
......
696 693
        ),
697 694
        migrations.AlterUniqueTogether(
698 695
            name='samlattribute',
699
            unique_together=set(
700
                [('content_type', 'object_id', 'name_format', 'name', 'friendly_name', 'attribute_name')]
701
            ),
696
            unique_together={
697
                ('content_type', 'object_id', 'name_format', 'name', 'friendly_name', 'attribute_name')
698
            },
702 699
        ),
703 700
        migrations.AddField(
704 701
            model_name='libertyserviceprovider',
src/authentic2/saml/migrations/0002_auto_20150320_1245.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0002_ease_federation_migration.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
from authentic2.saml.common import AUTHENTIC_SAME_ID_SENTINEL
src/authentic2/saml/migrations/0003_merge.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0004_auto_20150410_1438.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import django.db.models.deletion
5 2
from django.conf import settings
6 3
from django.db import migrations, models
src/authentic2/saml/migrations/0005_make_liberty_provider_inherit_from_service.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0006_restore_foreign_keys.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0007_copy_service_ptr_id_to_old_id.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0008_alter_foreign_keys.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0009_auto.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0010_auto.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0011_auto.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0012_auto_20150526_2239.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0013_auto_20150617_1004.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0014_auto_20150617_1216.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
......
13 10
    operations = [
14 11
        migrations.AlterUniqueTogether(
15 12
            name='libertysessiondump',
16
            unique_together=set([('django_session_key', 'kind')]),
13
            unique_together={('django_session_key', 'kind')},
17 14
        ),
18 15
    ]
src/authentic2/saml/migrations/0015_auto_20150915_2032.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
import authentic2.saml.fields
src/authentic2/saml/migrations/0016_auto_20150915_2041.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/migrations/0017_auto_20170710_1738.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2/saml/models.py
172 172

  
173 173
NAME_ID_FORMATS_CHOICES = [(force_text(x), y['caption']) for x, y in NAME_ID_FORMATS.items()]
174 174

  
175
ACCEPTED_NAME_ID_FORMAT_LENGTH = sum([len(x) for x, y in NAME_ID_FORMATS.items()]) + len(NAME_ID_FORMATS) - 1
175
ACCEPTED_NAME_ID_FORMAT_LENGTH = sum(len(x) for x, y in NAME_ID_FORMATS.items()) + len(NAME_ID_FORMATS) - 1
176 176

  
177 177

  
178 178
def saml2_urn_to_nidformat(urn, accepted=()):
......
328 328
    enabled = models.BooleanField(verbose_name=_('enabled'), default=True, blank=True)
329 329

  
330 330
    def clean(self):
331
        super(SAMLAttribute, self).clean()
331
        super().clean()
332 332
        if self.attribute_name and not self.name:
333 333
            self.name = self.attribute_name
334 334

  
......
401 401
        '''Update the SHA1 hash of the entity_id when saving'''
402 402
        if self.protocol_conformance == 3:
403 403
            self.entity_id_sha1 = hashlib.sha1(self.entity_id.encode('ascii')).hexdigest()
404
        super(LibertyProvider, self).save(*args, **kwargs)
404
        super().save(*args, **kwargs)
405 405

  
406 406
    def clean(self):
407
        super(LibertyProvider, self).clean()
407
        super().clean()
408 408
        p = lasso.Provider.newFromBuffer(lasso.PROVIDER_ROLE_ANY, force_text(self.metadata.encode('utf8')))
409 409
        if p is None:
410 410
            raise ValidationError(_('Invalid metadata file'))
src/authentic2/saml/saml2utils.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
import collections
20 19
import datetime
......
115 114
        return etree.TreeBuilder.end(self, tag)
116 115

  
117 116

  
118
class Saml2Metadata(object):
117
class Saml2Metadata:
119 118
    ENTITY_DESCRIPTOR = 'EntityDescriptor'
120 119
    SP_SSO_DESCRIPTOR = 'SPSSODescriptor'
121 120
    IDP_SSO_DESCRIPTOR = 'IDPSSODescriptor'
src/authentic2/saml/shibboleth/afp_parser.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
import xml.etree.ElementTree as ET
20 19

  
21 20
from authentic2.saml.shibboleth.utils import FancyTreeBuilder
22 21

  
23 22

  
24
class NS(object):
23
class NS:
25 24
    AFP = 'urn:mace:shibboleth:2.0:afp'
26 25
    BASIC = 'urn:mace:shibboleth:2.0:afp:mf:basic'
27 26
    SAML = 'urn:mace:shibboleth:2.0:afp:mf:saml'
src/authentic2/saml/shibboleth/utils.py
21 21
    """Attach defined namespaces to elements during parsing"""
22 22

  
23 23
    def __init__(self, *args, **kwargs):
24
        super(FancyTreeBuilder, self).__init__(*args, **kwargs)
24
        super().__init__(*args, **kwargs)
25 25
        self._namespaces = {}
26 26
        self._parser.StartNamespaceDeclHandler = self._start_ns
27 27

  
28 28
    def _start(self, *args):
29
        elem = super(FancyTreeBuilder, self)._start(*args)
29
        elem = super()._start(*args)
30 30
        elem.namespaces = self._namespaces.copy()
31 31
        return elem
32 32

  
33 33
    def _start_list(self, *args):
34
        elem = super(FancyTreeBuilder, self)._start_list(*args)
34
        elem = super()._start_list(*args)
35 35
        elem.namespaces = self._namespaces.copy()
36 36
        return elem
37 37

  
src/authentic2/serializers.py
44 44
            del self._current[pfield.ct_field]
45 45
            del self._current[pfield.fk_field]
46 46
            self._current[pfield.name] = (ct.natural_key(), sub_obj.natural_key())
47
        super(Serializer, self).end_object(obj)
47
        super().end_object(obj)
48 48

  
49 49

  
50 50
def PreDeserializer(objects, **options):
......
79 79
    try:
80 80
        objects = json.loads(stream_or_string)
81 81
        objects = PreDeserializer(objects, **options)
82
        for obj in PythonDeserializer(objects, **options):
83
            yield obj
82
        yield from PythonDeserializer(objects, **options)
84 83
    except GeneratorExit:
85 84
        raise
86 85
    except Exception as e:
src/authentic2/user_login_failure.py
35 35
    cache.add(key(identifier), 0)
36 36
    count = cache.incr(key(identifier))
37 37
    logger = logging.getLogger('authentic2.user_login_failure')
38
    logger.info(u'user %s failed to login', identifier)
38
    logger.info('user %s failed to login', identifier)
39 39
    if (
40 40
        app_settings.A2_LOGIN_FAILURE_COUNT_BEFORE_WARNING
41 41
        and count >= app_settings.A2_LOGIN_FAILURE_COUNT_BEFORE_WARNING
42 42
    ):
43
        logger.warning(u'user %s failed to login more than %d times in a row', identifier, count)
43
        logger.warning('user %s failed to login more than %d times in a row', identifier, count)
src/authentic2/utils/__init__.py
65 65
        return True
66 66

  
67 67

  
68
class MWT(object):
68
class MWT:
69 69
    """Memoize With Timeout"""
70 70

  
71 71
    _caches = {}
......
117 117
    get_session_store()(session_key=django_session_key).flush()
118 118

  
119 119

  
120
class IterableFactory(object):
120
class IterableFactory:
121 121
    """Return an new iterable using a generator function each time this object
122 122
    is iterated."""
123 123

  
......
251 251
        return user.username
252 252

  
253 253

  
254
class Service(object):
254
class Service:
255 255
    url = None
256 256
    name = None
257 257
    actions = []
......
833 833
        legacy_body_templates=['registration/activation_email.txt'],
834 834
        legacy_html_body_templates=['registration/activation_email.html'],
835 835
    )
836
    logger.info(u'registration mail sent to  %s with registration URL %s...', email, registration_url)
836
    logger.info('registration mail sent to  %s with registration URL %s...', email, registration_url)
837 837
    request.journal.record('user.registration.request', email=email)
838 838

  
839 839

  
......
852 852
    }
853 853
    template_names = ['authentic2/account_deletion_code']
854 854
    send_templated_mail(user, template_names, context, request=request, per_ou_templates=True)
855
    logger.info(u'account deletion code sent to %s', user.email)
855
    logger.info('account deletion code sent to %s', user.email)
856 856

  
857 857

  
858 858
def send_account_deletion_mail(request, user):
......
864 864
    context = {'full_name': user.get_full_name(), 'user': user, 'site': request.get_host()}
865 865
    template_names = ['authentic2/account_delete_notification']
866 866
    send_templated_mail(user, template_names, context, request=request, per_ou_templates=True)
867
    logger.info(u'account deletion mail sent to %s', user.email)
867
    logger.info('account deletion mail sent to %s', user.email)
868 868

  
869 869

  
870 870
def build_reset_password_url(user, request=None, next_url=None, set_random_password=True, sign_next_url=True):
......
971 971
            break
972 972
        if progress_callback:
973 973
            progress_callback(i * size)
974
        for row in chunk:
975
            yield row
974
        yield from chunk
976 975

  
977 976

  
978 977
def lower_keys(d):
979 978
    '''Convert all keys in dictionary d to lowercase'''
980
    return dict((key.lower(), value) for key, value in d.items())
979
    return {key.lower(): value for key, value in d.items()}
981 980

  
982 981

  
983 982
def to_dict_of_set(d):
984 983
    '''Convert a dictionary of sequence into a dictionary of sets'''
985
    return dict((k, set(v)) for k, v in d.items())
984
    return {k: set(v) for k, v in d.items()}
986 985

  
987 986

  
988 987
def datetime_to_utc(dt):
......
1186 1185
            'user_pk': user.pk,
1187 1186
        }
1188 1187
    )
1189
    link = '{0}?token={1}'.format(reverse('email-change-verify'), token)
1188
    link = '{}?token={}'.format(reverse('email-change-verify'), token)
1190 1189
    link = request.build_absolute_uri(link)
1191 1190

  
1192 1191
    # check if email should be unique and is not
......
1210 1209
            'email_is_not_unique': email_is_not_unique,
1211 1210
        }
1212 1211
    )
1213
    logger.info(u'sent email verify email to %s for %s', email, user)
1212
    logger.info('sent email verify email to %s for %s', email, user)
1214 1213
    send_templated_mail(
1215 1214
        email,
1216 1215
        template_names,
src/authentic2/utils/evaluate.py
52 52
    text = None
53 53

  
54 54
    def __init__(self, message, code=None, params=None, node=None, column=None, text=None):
55
        super(ExpressionError, self).__init__(message, code=code, params=params)
55
        super().__init__(message, code=code, params=params)
56 56
        if hasattr(node, 'col_offset'):
57 57
            self.set_node(node)
58 58
        if column is not None:
......
103 103

  
104 104
        # now recurse on subnodes
105 105
        try:
106
            return super(BaseExpressionValidator, self).generic_visit(node)
106
            return super().generic_visit(node)
107 107
        except ExpressionError as e:
108 108
            # for errors in non expr nodes (so without a col_offset attribute,
109 109
            # set the nearer expr node as the node of the error
......
175 175
    ]
176 176

  
177 177
    def __init__(self, authorized_nodes=None, forbidden_nodes=None):
178
        super(ConditionValidator, self).__init__(
179
            authorized_nodes=authorized_nodes, forbidden_nodes=forbidden_nodes
180
        )
178
        super().__init__(authorized_nodes=authorized_nodes, forbidden_nodes=forbidden_nodes)
181 179
        self.authorized_nodes.append(ast.NameConstant)
182 180

  
183 181
    def check_Name(self, node):
src/authentic2/utils/lazy.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
from django.utils.encoding import force_text
20 19
from django.utils.functional import keep_lazy
src/authentic2/utils/lookups.py
14 14
    """
15 15

  
16 16
    def as_postgresql(self, compiler, connection):
17
        return super(ConcatPair, self).as_sql(
18
            compiler, connection, template='%(expressions)s', arg_joiner=' || '
19
        )
17
        return super().as_sql(compiler, connection, template='%(expressions)s', arg_joiner=' || ')
20 18

  
21 19

  
22 20
class ImmutableConcat(Concat):
src/authentic2/utils/template.py
23 23
    pass
24 24

  
25 25

  
26
class Template(object):
26
class Template:
27 27
    def __init__(self, value, raises=False):
28 28
        self.value = value
29 29
        self.raises = raises
src/authentic2/validators.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import re
20 19
import smtplib
......
34 33

  
35 34

  
36 35
# copied from http://www.djangotips.com/real-email-validation
37
class EmailValidator(object):
36
class EmailValidator:
38 37
    def __init__(self, rcpt_check=False):
39 38
        self.rcpt_check = rcpt_check
40 39

  
......
103 102
class UsernameValidator(RegexValidator):
104 103
    def __init__(self, *args, **kwargs):
105 104
        self.regex = app_settings.A2_REGISTRATION_FORM_USERNAME_REGEX
106
        super(UsernameValidator, self).__init__(*args, **kwargs)
105
        super().__init__(*args, **kwargs)
107 106

  
108 107

  
109 108
@deconstructible
src/authentic2/views.py
130 130
        return self.request.user
131 131

  
132 132
    def get_form_kwargs(self, **kwargs):
133
        kwargs = super(EditProfile, self).get_form_kwargs(**kwargs)
133
        kwargs = super().get_form_kwargs(**kwargs)
134 134
        kwargs['next_url'] = utils.select_next_url(self.request, reverse('account_management'))
135 135
        return kwargs
136 136

  
......
142 142
    def post(self, request, *args, **kwargs):
143 143
        if 'cancel' in request.POST:
144 144
            return utils.redirect(request, self.get_success_url())
145
        return super(EditProfile, self).post(request, *args, **kwargs)
145
        return super().post(request, *args, **kwargs)
146 146

  
147 147
    def form_valid(self, form):
148
        response = super(EditProfile, self).form_valid(form)
148
        response = super().form_valid(form)
149 149
        hooks.call_hooks('event', name='edit-profile', user=self.request.user, form=form)
150 150
        self.request.journal.record('user.profile.edit', form=form)
151 151
        return response
......
167 167
        return profile_forms.EmailChangeFormNoPassword
168 168

  
169 169
    def get_form_kwargs(self):
170
        kwargs = super(EmailChangeView, self).get_form_kwargs()
170
        kwargs = super().get_form_kwargs()
171 171
        kwargs['user'] = self.request.user
172 172
        return kwargs
173 173

  
174 174
    def post(self, request, *args, **kwargs):
175 175
        if 'cancel' in request.POST:
176 176
            return utils.redirect(request, 'account_management')
177
        return super(EmailChangeView, self).post(request, *args, **kwargs)
177
        return super().post(request, *args, **kwargs)
178 178

  
179 179
    def form_valid(self, form):
180 180
        email = form.cleaned_data['email']
......
193 193
        self.request.journal.record(
194 194
            'user.email.change.request', user=self.request.user, session=self.request.session, new_email=email
195 195
        )
196
        return super(EmailChangeView, self).form_valid(form)
196
        return super().form_valid(form)
197 197

  
198 198

  
199 199
email_change = decorators.setting_enabled('A2_PROFILE_CAN_CHANGE_EMAIL')(
......
392 392
    def dispatch(self, request, *args, **kwargs):
393 393
        if app_settings.A2_HOMEPAGE_URL:
394 394
            return utils.redirect(request, app_settings.A2_HOMEPAGE_URL)
395
        return login_required(super(Homepage, self).dispatch)(request, *args, **kwargs)
395
        return login_required(super().dispatch)(request, *args, **kwargs)
396 396

  
397 397
    def get_context_data(self, **kwargs):
398
        ctx = super(Homepage, self).get_context_data(**kwargs)
398
        ctx = super().get_context_data(**kwargs)
399 399
        ctx['account_management'] = 'account_management'
400 400
        ctx['authorized_services'] = service_list(self.request)
401 401
        return ctx
......
411 411
    def dispatch(self, request, *args, **kwargs):
412 412
        if app_settings.A2_ACCOUNTS_URL:
413 413
            return utils.redirect(request, app_settings.A2_ACCOUNTS_URL)
414
        return super(ProfileView, self).dispatch(request, *args, **kwargs)
414
        return super().dispatch(request, *args, **kwargs)
415 415

  
416 416
    def get_context_data(self, **kwargs):
417
        context = super(ProfileView, self).get_context_data(**kwargs)
417
        context = super().get_context_data(**kwargs)
418 418
        frontends = utils.get_backends('AUTH_FRONTENDS')
419 419

  
420 420
        request = self.request
......
577 577
        # Get redirection targets for full logout with redirections
578 578
        # (needed before local logout)
579 579
        targets = redirect_logout_list(request)
580
        logger.debug('Accumulated redirections : {}'.format(targets))
580
        logger.debug(f'Accumulated redirections : {targets}')
581 581
        # Local logout
582 582
        request.journal.record('user.logout')
583 583
        auth_logout(request)
......
587 587
        targets.append(next_url)
588 588
        # Put redirection targets in session (after local logout)
589 589
        request.session['logout_redirections'] = targets
590
        logger.debug('All planned redirections : {}'.format(targets))
590
        logger.debug(f'All planned redirections : {targets}')
591 591
    # Full logout by redirections if any
592 592
    targets = request.session.pop('logout_redirections', None)
593 593
    if targets:
594 594
        # Full logout with redirections
595
        logger.debug('Redirections queue: {}'.format(targets))
595
        logger.debug(f'Redirections queue: {targets}')
596 596
        next_url = targets.pop(0)
597 597
        request.session['logout_redirections'] = targets
598
    logger.debug('Next redirection : {}'.format(next_url))
598
    logger.debug(f'Next redirection : {next_url}')
599 599
    response = shortcuts.redirect(next_url)
600 600
    if local_logout_done:
601 601
        response.set_cookie('a2_just_logged_out', 1, max_age=60)
......
622 622
class LoggedInView(View):
623 623
    '''JSONP web service to detect if an user is logged'''
624 624

  
625
    http_method_names = [u'get']
625
    http_method_names = ['get']
626 626

  
627 627
    def check_referrer(self):
628 628
        '''Check if the given referer is authorized'''
......
636 636
        if not self.check_referrer():
637 637
            return HttpResponseForbidden()
638 638
        callback = request.GET.get('callback')
639
        content = '{0}({1})'.format(callback, int(request.user.is_authenticated))
639
        content = f'{callback}({int(request.user.is_authenticated)})'
640 640
        return HttpResponse(content, content_type='application/json')
641 641

  
642 642

  
......
664 664
        ]
665 665

  
666 666
    def get_form_kwargs(self, **kwargs):
667
        kwargs = super(PasswordResetView, self).get_form_kwargs(**kwargs)
667
        kwargs = super().get_form_kwargs(**kwargs)
668 668
        initial = kwargs.setdefault('initial', {})
669 669
        initial['next_url'] = utils.select_next_url(self.request, '')
670 670
        return kwargs
671 671

  
672 672
    def get_context_data(self, **kwargs):
673
        ctx = super(PasswordResetView, self).get_context_data(**kwargs)
673
        ctx = super().get_context_data(**kwargs)
674 674
        if app_settings.A2_USER_CAN_RESET_PASSWORD is False:
675 675
            raise Http404('Password reset is not allowed.')
676 676
        ctx['title'] = _('Password reset')
......
740 740

  
741 741
        form.save()
742 742
        self.request.session['reset_email'] = email
743
        return super(PasswordResetView, self).form_valid(form)
743
        return super().form_valid(form)
744 744

  
745 745

  
746 746
password_reset = PasswordResetView.as_view()
......
750 750
    template_name = 'registration/password_reset_instructions.html'
751 751

  
752 752
    def get_context_data(self, **kwargs):
753
        ctx = super(PasswordResetInstructionsView, self).get_context_data(**kwargs)
753
        ctx = super().get_context_data(**kwargs)
754 754
        ctx['from_email_address'] = parseaddr(settings.DEFAULT_FROM_EMAIL)[1]
755 755
        return ctx
756 756

  
......
803 803
                request, _('It\'s not possible to reset your password. Please contact an administrator.')
804 804
            )
805 805
            return utils.redirect(request, self.get_success_url())
806
        return super(PasswordResetConfirmView, self).dispatch(request, *args, **kwargs)
806
        return super().dispatch(request, *args, **kwargs)
807 807

  
808 808
    def get_context_data(self, **kwargs):
809
        ctx = super(PasswordResetConfirmView, self).get_context_data(**kwargs)
809
        ctx = super().get_context_data(**kwargs)
810 810
        # compatibility with existing templates !
811 811
        ctx['title'] = _('Enter new password')
812 812
        ctx['validlink'] = True
813 813
        return ctx
814 814

  
815 815
    def get_form_kwargs(self):
816
        kwargs = super(PasswordResetConfirmView, self).get_form_kwargs()
816
        kwargs = super().get_form_kwargs()
817 817
        kwargs['user'] = self.user
818 818
        return kwargs
819 819

  
......
822 822
        form.user.email_verified = True
823 823
        form.save()
824 824
        hooks.call_hooks('event', name='password-reset-confirm', user=form.user, token=self.token, form=form)
825
        logger.info(u'password reset for user %s with token %r', self.user, self.token.uuid)
825
        logger.info('password reset for user %s with token %r', self.user, self.token.uuid)
826 826
        self.token.delete()
827 827
        return self.finish()
828 828

  
......
853 853
                    request.GET.get('token'), max_age=settings.ACCOUNT_ACTIVATION_DAYS * 3600 * 24
854 854
                )
855 855
            except (TypeError, ValueError, signing.BadSignature) as e:
856
                logger.warning(u'registration_view: invalid token: %s', e)
856
                logger.warning('registration_view: invalid token: %s', e)
857 857
                return HttpResponseBadRequest('invalid token', content_type='text/plain')
858 858
            if 'ou' in self.token:
859 859
                self.ou = OU.objects.get(pk=self.token['ou'])
860 860
        self.next_url = self.token.pop(REDIRECT_FIELD_NAME, utils.select_next_url(request, None))
861
        return super(BaseRegistrationView, self).dispatch(request, *args, **kwargs)
861
        return super().dispatch(request, *args, **kwargs)
862 862

  
863 863
    def form_valid(self, form):
864 864
        if form.is_robot():
......
939 939
        )
940 940

  
941 941
    def get_context_data(self, **kwargs):
942
        context = super(BaseRegistrationView, self).get_context_data(**kwargs)
942
        context = super().get_context_data(**kwargs)
943 943
        parameters = {'request': self.request, 'context': context}
944 944
        blocks = [
945 945
            utils.get_authenticator_method(authenticator, 'registration', parameters)
......
1012 1012
        self.init_fields_labels_and_help_texts()
1013 1013
        # if registration is done during an SSO add the service to the registration event
1014 1014
        self.service = get_service_from_token(self.token)
1015
        return super(RegistrationCompletionView, self).dispatch(request, *args, **kwargs)
1015
        return super().dispatch(request, *args, **kwargs)
1016 1016

  
1017 1017
    def init_fields_labels_and_help_texts(self):
1018 1018
        attributes = models.Attribute.objects.filter(asked_on_registration=True)
......
1070 1070

  
1071 1071
    def get_form_kwargs(self, **kwargs):
1072 1072
        '''Initialize mail from token'''
1073
        kwargs = super(RegistrationCompletionView, self).get_form_kwargs(**kwargs)
1073
        kwargs = super().get_form_kwargs(**kwargs)
1074 1074
        if 'ou' in self.token:
1075 1075
            ou = get_object_or_404(OU, id=self.token['ou'])
1076 1076
        else:
......
1080 1080
        for key in self.token:
1081 1081
            if key in app_settings.A2_PRE_REGISTRATION_FIELDS:
1082 1082
                attributes[key] = self.token[key]
1083
        logger.debug(u'attributes %s', attributes)
1083
        logger.debug('attributes %s', attributes)
1084 1084

  
1085 1085
        prefilling_list = utils.accumulate_from_backends(self.request, 'registration_form_prefill')
1086
        logger.debug(u'prefilling_list %s', prefilling_list)
1086
        logger.debug('prefilling_list %s', prefilling_list)
1087 1087
        # Build a single meaningful prefilling with sets of values
1088 1088
        prefilling = {}
1089 1089
        for p in prefilling_list:
1090 1090
            for name, values in p.items():
1091 1091
                if name in self.fields:
1092 1092
                    prefilling.setdefault(name, set()).update(values)
1093
        logger.debug(u'prefilling %s', prefilling)
1093
        logger.debug('prefilling %s', prefilling)
1094 1094

  
1095 1095
        for name, values in prefilling.items():
1096 1096
            attributes[name] = ' '.join(values)
1097
        logger.debug(u'attributes with prefilling %s', attributes)
1097
        logger.debug('attributes with prefilling %s', attributes)
1098 1098

  
1099 1099
        if self.token.get('user_id'):
1100 1100
            kwargs['instance'] = User.objects.get(id=self.token.get('user_id'))
......
1108 1108
        return kwargs
1109 1109

  
1110 1110
    def get_form(self, form_class=None):
1111
        form = super(RegistrationCompletionView, self).get_form(form_class=form_class)
1111
        form = super().get_form(form_class=form_class)
1112 1112
        hooks.call_hooks('front_modify_form', self, form)
1113 1113
        return form
1114 1114

  
1115 1115
    def get_context_data(self, **kwargs):
1116
        ctx = super(RegistrationCompletionView, self).get_context_data(**kwargs)
1116
        ctx = super().get_context_data(**kwargs)
1117 1117
        ctx['token'] = self.token
1118 1118
        ctx['users'] = self.users
1119 1119
        ctx['email'] = self.email
......
1151 1151
                user = form.save()
1152 1152
                return self.registration_success(request, user, form)
1153 1153
            self.get_form = lambda *args, **kwargs: form
1154
        return super(RegistrationCompletionView, self).get(request, *args, **kwargs)
1154
        return super().get(request, *args, **kwargs)
1155 1155

  
1156 1156
    def post(self, request, *args, **kwargs):
1157 1157
        if self.users and self.email_is_unique:
......
1167 1167
                        request, user, method=self.authentication_method, service=self.service
1168 1168
                    )
1169 1169
                    return utils.redirect(request, self.get_success_url())
1170
        return super(RegistrationCompletionView, self).post(request, *args, **kwargs)
1170
        return super().post(request, *args, **kwargs)
1171 1171

  
1172 1172
    def form_valid(self, form):
1173 1173

  
......
1199 1199
            self.token_obj.delete()
1200 1200
            self.request.session['registered_email'] = form.cleaned_data['email']
1201 1201
            return utils.redirect(self.request, 'registration_complete')
1202
        super(RegistrationCompletionView, self).form_valid(form)
1202
        super().form_valid(form)
1203 1203
        return self.registration_success(self.request, form.instance, form)
1204 1204

  
1205 1205
    def registration_success(self, request, user, form):
......
1251 1251
    def dispatch(self, request, *args, **kwargs):
1252 1252
        if not app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT:
1253 1253
            return utils.redirect(request, '..')
1254
        return super(DeleteView, self).dispatch(request, *args, **kwargs)
1254
        return super().dispatch(request, *args, **kwargs)
1255 1255

  
1256 1256
    def post(self, request, *args, **kwargs):
1257 1257
        if 'cancel' in request.POST:
......
1261 1261
        return utils.redirect(request, 'account_management')
1262 1262

  
1263 1263
    def get_context_data(self, **kwargs):
1264
        ctx = super(DeleteView, self).get_context_data(**kwargs)
1264
        ctx = super().get_context_data(**kwargs)
1265 1265
        ctx['email'] = self.request.user.email
1266 1266
        return ctx
1267 1267

  
......
1293 1293
        except get_user_model().DoesNotExist:
1294 1294
            error = _('This account has previously been deleted.')
1295 1295
        else:
1296
            return super(ValidateDeletionView, self).dispatch(request, *args, **kwargs)
1296
            return super().dispatch(request, *args, **kwargs)
1297 1297
        messages.error(request, error)
1298 1298
        return utils.redirect(request, 'auth_homepage')
1299 1299

  
1300 1300
    def post(self, request, *args, **kwargs):
1301 1301
        if 'cancel' not in request.POST:
1302 1302
            utils.send_account_deletion_mail(self.request, self.user)
1303
            logger.info(u'deletion of account %s performed', self.user)
1303
            logger.info('deletion of account %s performed', self.user)
1304 1304
            hooks.call_hooks('event', name='delete-account', user=self.user)
1305 1305
            request.journal.record('user.deletion', user=self.user)
1306 1306
            is_deleted_user_logged = self.user == request.user
......
1314 1314
        return utils.redirect(request, 'auth_homepage')
1315 1315

  
1316 1316
    def get_context_data(self, **kwargs):
1317
        ctx = super(ValidateDeletionView, self).get_context_data(**kwargs)
1317
        ctx = super().get_context_data(**kwargs)
1318 1318
        ctx['user'] = self.user  # Not necessarily the user in request
1319 1319
        return ctx
1320 1320

  
......
1326 1326
        kwargs['next_url'] = utils.select_next_url(self.request, settings.LOGIN_REDIRECT_URL)
1327 1327
        kwargs['from_email'] = settings.DEFAULT_FROM_EMAIL
1328 1328
        kwargs['from_email_address'] = parseaddr(settings.DEFAULT_FROM_EMAIL)[1]
1329
        return super(RegistrationCompleteView, self).get_context_data(
1330
            account_activation_days=settings.ACCOUNT_ACTIVATION_DAYS, **kwargs
1331
        )
1329
        return super().get_context_data(account_activation_days=settings.ACCOUNT_ACTIVATION_DAYS, **kwargs)
1332 1330

  
1333 1331

  
1334 1332
registration_complete = RegistrationCompleteView.as_view()
......
1348 1346
        if not utils.user_can_change_password(request=request):
1349 1347
            messages.warning(request, _('Password change is forbidden'))
1350 1348
            return utils.redirect(request, self.post_change_redirect)
1351
        return super(PasswordChangeView, self).dispatch(request, *args, **kwargs)
1349
        return super().dispatch(request, *args, **kwargs)
1352 1350

  
1353 1351
    def post(self, request, *args, **kwargs):
1354 1352
        if 'cancel' in request.POST:
1355 1353
            return utils.redirect(request, self.post_change_redirect)
1356
        return super(PasswordChangeView, self).post(request, *args, **kwargs)
1354
        return super().post(request, *args, **kwargs)
1357 1355

  
1358 1356
    def form_valid(self, form):
1359 1357
        hooks.call_hooks('event', name='change-password', user=self.request.user, request=self.request)
1360 1358
        messages.info(self.request, _('Password changed'))
1361 1359
        models.PasswordReset.objects.filter(user=self.request.user).delete()
1362
        response = super(PasswordChangeView, self).form_valid(form)
1360
        response = super().form_valid(form)
1363 1361
        self.request.journal.record('user.password.change', session=self.request.session)
1364 1362
        return response
1365 1363

  
......
1370 1368
            return passwords_forms.SetPasswordForm
1371 1369

  
1372 1370
    def get_context_data(self, **kwargs):
1373
        ctx = super(PasswordChangeView, self).get_context_data(**kwargs)
1371
        ctx = super().get_context_data(**kwargs)
1374 1372
        ctx[REDIRECT_FIELD_NAME] = self.post_change_redirect
1375 1373
        return ctx
1376 1374

  
......
1401 1399
    def get_context_data(self, **kwargs):
1402 1400
        from authentic2_idp_oidc.models import OIDCAuthorization
1403 1401

  
1404
        context = super(AuthorizedOauthServicesView, self).get_context_data(**kwargs)
1402
        context = super().get_context_data(**kwargs)
1405 1403
        context['authorized_oauth_services'] = OIDCAuthorization.objects.filter(user=self.request.user)
1406 1404
        return context
1407 1405

  
src/authentic2_auth_fc/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    __SENTINEL = object()
22 22

  
23 23
    def __init__(self, prefix):
src/authentic2_auth_fc/apps.py
20 20
from . import app_settings
21 21

  
22 22

  
23
class Plugin(object):
23
class Plugin:
24 24
    def redirect_logout_list(self, request, **kwargs):
25 25
        from django.urls import reverse
26 26

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

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

  
src/authentic2_auth_fc/migrations/0002_auto_20200416_1439.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.29 on 2020-04-16 12:39
3
from __future__ import unicode_literals
4 2

  
5 3
import django.utils.timezone
6 4
from django.db import migrations, models
src/authentic2_auth_fc/migrations/0003_fcaccount_order1.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2019-06-12 21:27
3
from __future__ import unicode_literals
4 2

  
5 3
from collections import Counter
6 4

  
src/authentic2_auth_fc/migrations/0004_fcaccount_order2.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2019-06-12 21:27
3
from __future__ import unicode_literals
4 2

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

  
......
18 16
        ),
19 17
        migrations.AlterUniqueTogether(
20 18
            name='fcaccount',
21
            unique_together=set([('sub', 'order'), ('user', 'order')]),
19
            unique_together={('sub', 'order'), ('user', 'order')},
22 20
        ),
23 21
    ]
src/authentic2_auth_fc/utils.py
132 132
        try:
133 133
            value = mapping_to_value(mapping, user_info)
134 134
        except (ValueError, KeyError, NotImplementedError) as e:
135
            logger.warning(u'auth_fc: cannot apply mapping %s <- %r: %s', attribute, mapping, e)
135
            logger.warning('auth_fc: cannot apply mapping %s <- %r: %s', attribute, mapping, e)
136 136
            continue
137 137
        if mapping.get('if-tag') and mapping['if-tag'] not in tags:
138 138
            continue
......
155 155
                continue
156 156
            setattr(user, attribute, value)
157 157
        else:
158
            logger.warning(u'auth_fc: unknown attribute in user_info mapping: %s', attribute)
158
            logger.warning('auth_fc: unknown attribute in user_info mapping: %s', attribute)
159 159
            continue
160 160
        if mapping.get('tag'):
161 161
            tags.add(mapping['tag'])
src/authentic2_auth_fc/views.py
227 227
            'nonce': nonce,
228 228
            'acr_values': 'eidas1',
229 229
        }
230
        url = '{0}?{1}'.format(app_settings.authorize_url, urlencode(params))
230
        url = f'{app_settings.authorize_url}?{urlencode(params)}'
231 231
        logger.debug('auth_fc: authorization_request redirect to %s', url)
232 232

  
233 233
        response = HttpResponseRedirect(url)
src/authentic2_auth_oidc/admin.py
29 29

  
30 30
class OIDCClaimMappingForm(forms.ModelForm):
31 31
    def __init__(self, *args, **kwargs):
32
        super(OIDCClaimMappingForm, self).__init__(*args, **kwargs)
32
        super().__init__(*args, **kwargs)
33 33
        claim_widget = self.fields['claim'].widget
34 34
        # fill datalist with standard claims from
35 35
        # https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
src/authentic2_auth_oidc/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    '''Thanks django-allauth'''
22 22

  
23 23
    __SENTINEL = object()
src/authentic2_auth_oidc/apps.py
18 18
from django import template
19 19

  
20 20

  
21
class Plugin(object):
21
class Plugin:
22 22
    def revoke_token(self, provider, access_token):
23 23
        import logging
24 24

  
src/authentic2_auth_oidc/management/commands/oidc-register-issuer.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import print_function
18 17

  
19 18
import json
20 19
import pprint
src/authentic2_auth_oidc/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
import uuid
5 2

  
6 3
import django.contrib.postgres.fields.jsonb
src/authentic2_auth_oidc/migrations/0002_oidcprovider_token_revocation_endpoint.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_auth_oidc/migrations/0003_oidcprovider_show.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_auth_oidc/migrations/0004_auto_20171017_1522.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_auth_oidc/migrations/0005_oidcprovider_slug.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.12 on 2018-09-28 08:58
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2_auth_oidc/migrations/0006_oidcprovider_claims_parameter_supported.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_auth_oidc/migrations/0007_auto_20200317_1732.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.18 on 2020-03-17 16:32
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2_auth_oidc/models.py
162 162
        return (self.claim, self.attribute, self.verified, self.required)
163 163

  
164 164
    def __str__(self):
165
        s = '{0} -> {1}'.format(self.claim, self.attribute)
165
        s = f'{self.claim} -> {self.attribute}'
166 166
        if self.verified:
167 167
            s += ', verified'
168 168
        if self.required:
......
196 196
    sub = models.CharField(verbose_name=_('sub'), max_length=256)
197 197

  
198 198
    def __str__(self):
199
        return '{0} on {1} linked to {2}'.format(self.sub, self.provider and self.provider.issuer, self.user)
199
        return f'{self.sub} on {self.provider and self.provider.issuer} linked to {self.user}'
200 200

  
201 201
    def __repr__(self):
202 202
        return '<OIDCAccount %r on %r>' % (self.sub, self.provider and self.provider.issuer)
src/authentic2_auth_oidc/utils.py
90 90
    return json_decode(jwt.claims)
91 91

  
92 92

  
93
REQUIRED_ID_TOKEN_KEYS = set(['iss', 'sub', 'aud', 'exp', 'iat'])
93
REQUIRED_ID_TOKEN_KEYS = {'iss', 'sub', 'aud', 'exp', 'iat'}
94 94
KEY_TYPES = {
95 95
    'iss': str,
96 96
    'sub': str,
......
114 114
    pass
115 115

  
116 116

  
117
class IDToken(object):
117
class IDToken:
118 118
    auth_time = None
119 119
    nonce = None
120 120

  
......
181 181
            return default
182 182

  
183 183

  
184
OPENID_CONFIGURATION_REQUIRED = set(
185
    [
186
        'issuer',
187
        'authorization_endpoint',
188
        'token_endpoint',
189
        'jwks_uri',
190
        'response_types_supported',
191
        'subject_types_supported',
192
        'id_token_signing_alg_values_supported',
193
        'userinfo_endpoint',
194
    ]
195
)
184
OPENID_CONFIGURATION_REQUIRED = {
185
    'issuer',
186
    'authorization_endpoint',
187
    'token_endpoint',
188
    'jwks_uri',
189
    'response_types_supported',
190
    'subject_types_supported',
191
    'id_token_signing_alg_values_supported',
192
    'userinfo_endpoint',
193
}
196 194

  
197 195

  
198 196
def check_https(url):
......
256 254
        old_pk = models.OIDCProvider.objects.get(issuer=openid_configuration['issuer']).pk
257 255
    except models.OIDCProvider.DoesNotExist:
258 256
        old_pk = None
259
    if set(['RS256', 'RS384', 'RS512']) & set(openid_configuration['id_token_signing_alg_values_supported']):
257
    if {'RS256', 'RS384', 'RS512'} & set(openid_configuration['id_token_signing_alg_values_supported']):
260 258
        idtoken_algo = models.OIDCProvider.ALGO_RSA
261
    elif set(['HS256', 'HS384', 'HS512']) & set(
262
        openid_configuration['id_token_signing_alg_values_supported']
263
    ):
259
    elif {'HS256', 'HS384', 'HS512'} & set(openid_configuration['id_token_signing_alg_values_supported']):
264 260
        idtoken_algo = models.OIDCProvider.ALGO_HMAC
265
    elif set(['ES256', 'ES384', 'ES512']) & set(
266
        openid_configuration['id_token_signing_alg_values_supported']
267
    ):
261
    elif {'ES256', 'ES384', 'ES512'} & set(openid_configuration['id_token_signing_alg_values_supported']):
268 262
        idtoken_algo = models.OIDCProvider.ALGO_EC
269 263
    else:
270 264
        raise ValueError(
src/authentic2_auth_oidc/views.py
47 47
@setting_enabled('ENABLE', settings=app_settings)
48 48
def oidc_login(request, pk, next_url=None, *args, **kwargs):
49 49
    provider = get_provider(pk)
50
    scopes = set(provider.scopes.split()) | set(['openid'])
50
    scopes = set(provider.scopes.split()) | {'openid'}
51 51
    state_id = str(uuid.uuid4())
52 52
    next_url = next_url or request.GET.get(REDIRECT_FIELD_NAME, '')
53 53
    if next_url and not good_next_url(request, next_url):
src/authentic2_auth_saml/adapters.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import logging
20 19

  
......
40 39

  
41 40
    def __init__(self, message, details=None):
42 41
        self.details = details or {}
43
        super(MappingError, self).__init__(message)
42
        super().__init__(message)
44 43

  
45 44
    def __str__(self):
46 45
        s = str(self.args[0])
......
49 48
        return s
50 49

  
51 50

  
52
class SamlConditionContextProxy(object):
51
class SamlConditionContextProxy:
53 52
    def __init__(self, saml_attributes):
54 53
        self.saml_attributes = saml_attributes
55 54

  
......
84 83
            user.save()
85 84

  
86 85
    def provision(self, user, idp, saml_attributes):
87
        super(AuthenticAdapter, self).provision(user, idp, saml_attributes)
86
        super().provision(user, idp, saml_attributes)
88 87
        try:
89 88
            self.provision_a2_attributes(user, idp, saml_attributes)
90 89
        except MappingError as e:
src/authentic2_auth_saml/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    '''Thanks django-allauth'''
22 22

  
23 23
    __SENTINEL = object()
src/authentic2_auth_saml/backends.py
25 25
    def authenticate(self, request=None, **kwargs):
26 26
        if not app_settings.enable:
27 27
            return None
28
        return super(SAMLBackend, self).authenticate(request=request, **kwargs)
28
        return super().authenticate(request=request, **kwargs)
29 29

  
30 30
    def get_saml2_authn_context(self):
31 31
        # Pass AuthnContextClassRef from the previous IdP
src/authentic2_idp_cas/admin.py
29 29

  
30 30
class ServiceForm(forms.ModelForm):
31 31
    def __init__(self, *args, **kwargs):
32
        super(ServiceForm, self).__init__(*args, **kwargs)
32
        super().__init__(*args, **kwargs)
33 33
        choices = self.choices({'user': None, 'request': None, 'service': self.instance})
34 34
        self.fields['identifier_attribute'].choices = choices
35 35
        self.fields['identifier_attribute'].widget = forms.Select(choices=choices)
......
46 46
class AttributeInlineForm(forms.ModelForm):
47 47
    def __init__(self, *args, **kwargs):
48 48
        service = kwargs.pop('service', None)
49
        super(AttributeInlineForm, self).__init__(*args, **kwargs)
49
        super().__init__(*args, **kwargs)
50 50
        choices = self.choices({'user': None, 'request': None, 'service': service})
51 51
        self.fields['attribute_name'].choices = choices
52 52
        self.fields['attribute_name'].widget = forms.Select(choices=choices)
......
73 73
        class NewForm(self.form):
74 74
            def __init__(self, *args, **kwargs):
75 75
                kwargs['service'] = obj
76
                super(NewForm, self).__init__(*args, **kwargs)
76
                super().__init__(*args, **kwargs)
77 77

  
78 78
        kwargs['form'] = NewForm
79
        return super(AttributeInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
79
        return super().get_formset(request, obj=obj, **kwargs)
80 80

  
81 81

  
82 82
class ServiceAdmin(admin.ModelAdmin):
src/authentic2_idp_cas/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    __DEFAULTS = {
22 22
        'ENABLE': False,
23 23
        # allow do tisable check of pgt url for testing purpose
src/authentic2_idp_cas/apps.py
20 20
from .constants import SESSION_CAS_LOGOUTS
21 21

  
22 22

  
23
class Plugin(object):
23
class Plugin:
24 24
    def logout_list(self, request):
25 25
        fragments = []
26 26
        cas_logouts = request.session.get(SESSION_CAS_LOGOUTS, [])
src/authentic2_idp_cas/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
import authentic2_idp_cas.models
......
147 144
        ),
148 145
        migrations.AlterUniqueTogether(
149 146
            name='attribute',
150
            unique_together=set([('service', 'slug', 'attribute_name')]),
147
            unique_together={('service', 'slug', 'attribute_name')},
151 148
        ),
152 149
    ]
src/authentic2_idp_cas/migrations/0002_auto_20150410_1438.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2_idp_cas/migrations/0003_auto_20150415_2223.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0004_create_services.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0005_alter_field_service_ptr.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0006_copy_proxy_m2m.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0007_alter_service.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0008_alter_foreign_keys.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0009_alter_related_models.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0010_copy_service_ptr_id_to_old_id.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0011_remove_old_id_restore_proxy.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0012_copy_service_proxy_to_m2m.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0013_delete_model_service_proxy2.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0014_auto_20151204_1606.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/migrations/0015_auto_20170406_1825.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_cas/models.py
44 44

  
45 45
    def clean(self):
46 46
        '''Check urls is a space separated list of urls and normalize it'''
47
        super(Service, self).clean()
47
        super().clean()
48 48
        urls = self.urls.split(' ')
49 49
        for url in urls:
50 50
            try:
......
66 66

  
67 67
    def get_wanted_attributes(self):
68 68
        '''Compute wanted attributes for this service'''
69
        wanted = set([self.identifier_attribute])
69
        wanted = {self.identifier_attribute}
70 70
        for attribute in self.attribute_set.all():
71 71
            wanted.add(attribute.attribute_name)
72 72
        return list(wanted)
src/authentic2_idp_cas/views.py
87 87
    ET._namespace_map['http://www.yale.edu/tp/cas'] = 'cas'
88 88

  
89 89

  
90
class CasMixin(object):
90
class CasMixin:
91 91
    '''Common methods'''
92 92

  
93 93
    def __init__(self, *args, **kwargs):
src/authentic2_idp_oidc/admin.py
26 26

  
27 27
class OIDCClaimInlineForm(forms.ModelForm):
28 28
    def __init__(self, *args, **kwargs):
29
        super(OIDCClaimInlineForm, self).__init__(*args, **kwargs)
29
        super().__init__(*args, **kwargs)
30 30
        data = dict(get_service_attributes(getattr(self.instance, 'client', None))).keys()
31 31
        widget = self.fields['value'].widget
32 32
        widget.data = data
......
54 54
        if request.method == 'GET' and not obj:
55 55
            initial.extend(app_settings.DEFAULT_MAPPINGS)
56 56
            self.extra = 5
57
        formset = super(OIDCClaimInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
57
        formset = super().get_formset(request, obj=obj, **kwargs)
58 58
        formset.__init__ = curry(formset.__init__, initial=initial)
59 59
        return formset
60 60

  
......
74 74
    readonly_fields = ['created', 'expired']
75 75

  
76 76
    def get_queryset(self, request):
77
        qs = super(OIDCAuthorizationAdmin, self).get_queryset(request)
77
        qs = super().get_queryset(request)
78 78
        qs = qs.prefetch_related('client')
79 79
        return qs
80 80

  
......
83 83

  
84 84
        from authentic2.a2_rbac.models import OrganizationalUnit as OU
85 85

  
86
        queryset, use_distinct = super(OIDCAuthorizationAdmin, self).get_search_results(
87
            request, queryset, search_term
88
        )
86
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)
89 87
        clients = models.OIDCClient.objects.filter(name__contains=search_term).values_list('pk')
90 88
        ous = OU.objects.filter(name__contains=search_term).values_list('pk')
91 89
        queryset |= self.model.objects.filter(
src/authentic2_idp_oidc/app_settings.py
17 17
import sys
18 18

  
19 19

  
20
class AppSettings(object):
20
class AppSettings:
21 21
    '''Thanks django-allauth'''
22 22

  
23 23
    __SENTINEL = object()
src/authentic2_idp_oidc/apps.py
19 19
from django.utils.encoding import smart_bytes
20 20

  
21 21

  
22
class Plugin(object):
22
class Plugin:
23 23
    def logout_list(self, request):
24 24
        from . import app_settings
25 25
        from .utils import get_oidc_sessions
src/authentic2_idp_oidc/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/authentic2_idp_oidc/migrations/0002_auto_20170121_2346.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
import authentic2_idp_oidc.models
src/authentic2_idp_oidc/migrations/0003_auto_20170329_1259.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3
import authentic2_idp_oidc.models
src/authentic2_idp_oidc/migrations/0004_auto_20170324_1426.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0005_authorization_mode.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0006_auto_20170720_1054.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0007_oidcclient_has_api_access.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0008_oidcclient_idtoken_duration.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0009_auto_20180313_1156.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0010_oidcclaim.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/authentic2_idp_oidc/migrations/0011_auto_20180808_1546.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations
5 2

  
6 3
OLD_DEFAULT_CLAIMS_MAPPING = {
src/authentic2_idp_oidc/migrations/0012_auto_20200122_2258.py
1
# -*- coding: utf-8 -*-
2 1
# Generated by Django 1.11.20 on 2020-01-22 21:58
3
from __future__ import unicode_literals
4 2

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

  
src/authentic2_idp_oidc/models.py
271 271
    return None
272 272

  
273 273

  
274
class SessionMixin(object):
274
class SessionMixin:
275 275
    @property
276 276
    def session(self):
277 277
        if not hasattr(self, '_session'):
src/authentic2_idp_oidc/utils.py
105 105

  
106 106
def scope_set(data):
107 107
    '''Convert a scope string into a set of scopes'''
108
    return set([scope.strip() for scope in data.split()])
108
    return {scope.strip() for scope in data.split()}
109 109

  
110 110

  
111 111
def clean_words(data):
src/authentic2_idp_oidc/views.py
289 289
        if response_type != 'code':
290 290
            raise UnsupportedResponseType(_('Response type must be "code"'))
291 291
    elif client.authorization_flow == client.FLOW_IMPLICIT:
292
        if not set(filter(None, response_type.split())) in (set(['id_token', 'token']), set(['id_token'])):
292
        if not set(filter(None, response_type.split())) in ({'id_token', 'token'}, {'id_token'}):
293 293
            raise UnsupportedResponseType(_('Response type must be "id_token token" or "id_token"'))
294 294
    else:
295 295
        raise NotImplementedError
......
403 403
                    'authentic2_idp_oidc/authorization.html',
404 404
                    {
405 405
                        'client': client,
406
                        'scopes': scopes - set(['openid']),
406
                        'scopes': scopes - {'openid'},
407 407
                    },
408 408
                )
409 409
    if response_type == 'code':
src/django_rbac/backends.py
25 25
        return field.related_model
26 26

  
27 27

  
28
class DjangoRBACBackend(object):
28
class DjangoRBACBackend:
29 29
    _DEFAULT_DJANGO_RBAC_PERMISSIONS_HIERARCHY = {
30 30
        'view': ['search'],
31 31
        'admin': ['change', 'delete', 'add', 'view', 'search'],
......
99 99
            key = '%s.%s' % (ct.id, obj.pk)
100 100
            if key in perms_cache:
101 101
                permissions.update(perms_cache[key])
102
            for permission in perms_cache.get('__all__', set([])):
102
            for permission in perms_cache.get('__all__', set()):
103 103
                if permission.startswith('%s.' % ct.app_label) and permission.endswith('_%s' % ct.model):
104 104
                    permissions.add(permission)
105 105
            if hasattr(obj, 'ou_id') and obj.ou_id:
src/django_rbac/context_processors.py
4 4
from django.contrib.auth.context_processors import PermWrapper as AuthPermWrapper
5 5

  
6 6

  
7
class PermAnyLookupDict(object):
7
class PermAnyLookupDict:
8 8
    def __init__(self, user, app_label):
9 9
        self.user = user
10 10
        self.app_label = app_label
......
20 20
        raise TypeError('PermAnyLookupDict has not boolean value')
21 21

  
22 22

  
23
class PermAnyWrapper(object):
23
class PermAnyWrapper:
24 24
    def __init__(self, user):
25 25
        self.user = user
26 26

  
......
42 42
    def __getitem__(self, app_label):
43 43
        if app_label == 'any':
44 44
            return PermAnyWrapper(self.user)
45
        return super(PermWrapper, self).__getitem__(app_label)
45
        return super().__getitem__(app_label)
46 46

  
47 47

  
48 48
def auth(request):
src/django_rbac/management/commands/cleanup_rbac.py
1
from __future__ import print_function
2

  
3 1
from django.core.management.base import BaseCommand
4 2

  
5 3

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

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

  
src/django_rbac/migrations/0002_organizationalunit_permission_role_roleparenting.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/django_rbac/migrations/0003_add_max_aggregate_for_postgres.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations
5 2

  
6 3

  
src/django_rbac/migrations/0004_auto_20150708_1337.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

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

  
src/django_rbac/migrations/0005_auto_20171209_1106.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4 1
from django.db import migrations, models
5 2

  
6 3

  
src/django_rbac/models.py
39 39
        return self.name
40 40

  
41 41
    def __repr__(self):
42
        return '<{0} {1} {2}>'.format(self.__class__.__name__, repr(self.slug), repr(self.name))
42
        return f'<{self.__class__.__name__} {repr(self.slug)} {repr(self.name)}>'
43 43

  
44 44
    def save(self, *args, **kwargs):
45 45
        # truncate slug and add a hash if it's too long
......
49 49
            self.slug = self.slug[:252] + hashlib.md5(self.slug).hexdigest()[:4]
50 50
        if not self.uuid:
51 51
            self.uuid = utils.get_hex_uuid()
52
        return super(AbstractBase, self).save(*args, **kwargs)
52
        return super().save(*args, **kwargs)
53 53

  
54 54
    def natural_key(self):
55 55
        return [self.uuid]
......
159 159
        ct_ct = ContentType.objects.get_for_model(ContentType)
160 160
        if ct == ct_ct:
161 161
            target = ContentType.objects.get_for_id(self.target_id)
162
            s = '{0} / {1}'.format(self.operation, target)
162
            s = f'{self.operation} / {target}'
163 163
        else:
164
            s = '{0} / {1} / {2}'.format(self.operation, ct, self.target)
164
            s = f'{self.operation} / {ct} / {self.target}'
165 165
        if self.ou:
166
            s += _(u' (scope "{0}")').format(self.ou)
166
            s += _(' (scope "{0}")').format(self.ou)
167 167
        return s
168 168

  
169 169
    class Meta:
tests/auth_fc/test_auth_fc.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - authentic2 authentication for FranceConnect
3 2
# Copyright (C) 2020 Entr'ouvert
4 3
#
......
19 18
import json
20 19
import re
21 20
import urllib.parse
21
from unittest import mock
22 22

  
23
import mock
24 23
import pytest
25 24
import requests
26 25
from django.contrib.auth import get_user_model
tests/auth_fc/test_auth_fc_api.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2-auth-fc - authentic2 authentication for FranceConnect
3 2
# Copyright (C) 2019 Entr'ouvert
4 3
#
tests/conftest.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
17 16

  
18 17

  
19 18
import urllib.parse
19
from unittest import mock
20 20

  
21 21
import django
22 22
import django_webtest
23
import mock
24 23
import pytest
25 24
from django.contrib.auth import get_user_model
26 25
from django.core.cache import cache
......
130 129
@pytest.fixture
131 130
def simple_user(db, ou1):
132 131
    return create_user(
133
        username='user', first_name=u'Jôhn', last_name=u'Dôe', email='user@example.net', ou=get_default_ou()
132
        username='user', first_name='Jôhn', last_name='Dôe', email='user@example.net', ou=get_default_ou()
134 133
    )
135 134

  
136 135

  
......
165 164
@pytest.fixture
166 165
def user_ou1(db, ou1):
167 166
    return create_user(
168
        username='john.doe', first_name=u'Jôhn', last_name=u'Dôe', email='john.doe@example.net', ou=ou1
167
        username='john.doe', first_name='Jôhn', last_name='Dôe', email='john.doe@example.net', ou=ou1
169 168
    )
170 169

  
171 170

  
172 171
@pytest.fixture
173 172
def user_ou2(db, ou2):
174 173
    return create_user(
175
        username='john.doe.ou2', first_name=u'Jôhn', last_name=u'Dôe', email='john.doe@example.net', ou=ou2
174
        username='john.doe.ou2', first_name='Jôhn', last_name='Dôe', email='john.doe@example.net', ou=ou2
176 175
    )
177 176

  
178 177

  
179 178
@pytest.fixture
180 179
def admin_ou1(db, ou1):
181 180
    user = create_user(
182
        username='admin.ou1', first_name=u'Admin', last_name=u'OU1', email='admin.ou1@example.net', ou=ou1
181
        username='admin.ou1', first_name='Admin', last_name='OU1', email='admin.ou1@example.net', ou=ou1
183 182
    )
184 183
    user.roles.add(ou1.get_admin_role())
185 184
    return user
......
188 187
@pytest.fixture
189 188
def admin_ou2(db, ou2):
190 189
    user = create_user(
191
        username='admin.ou2', first_name=u'Admin', last_name=u'OU2', email='admin.ou2@example.net', ou=ou2
190
        username='admin.ou2', first_name='Admin', last_name='OU2', email='admin.ou2@example.net', ou=ou2
192 191
    )
193 192
    user.roles.add(ou2.get_admin_role())
194 193
    return user
......
297 296

  
298 297
    class TestOIDCUser(OIDCUser):
299 298
        def __init__(self, oidc_client):
300
            super(TestOIDCUser, self).__init__(oidc_client)
299
            super().__init__(oidc_client)
301 300

  
302 301
        @property
303 302
        def username(self):
......
353 352
        cached_el.cache.clear()
354 353

  
355 354

  
356
class AllHook(object):
355
class AllHook:
357 356
    def __init__(self):
358 357
        self.calls = {}
359 358

  
......
391 390
def user_with_auto_admin_role(auto_admin_role, ou1):
392 391
    user = create_user(
393 392
        username='user.with.auto.admin.role',
394
        first_name=u'User',
395
        last_name=u'With Auto Admin Role',
393
        first_name='User',
394
        last_name='With Auto Admin Role',
396 395
        email='user.with.auto.admin.role@example.net',
397 396
        ou=ou1,
398 397
    )
......
502 501
    Based on: https://gist.github.com/blueyed/4fb0a807104551f103e6
503 502
    """
504 503

  
505
    class Migrator(object):
504
    class Migrator:
506 505
        def before(self, targets, at_end=True):
507 506
            """Specify app and starting migration names as in:
508 507
            before([('app', '0001_before')]) => app/migrations/0001_before.py
tests/idp_oidc/test_api.py
25 25
    users = [User.objects.create(username='user-%s' % i) for i in range(10)]
26 26
    for user in users[5:]:
27 27
        user.delete()
28
    deleted_subs = set(make_sub(oidc_client, user) for user in users[5:])
28
    deleted_subs = {make_sub(oidc_client, user) for user in users[5:]}
29 29

  
30 30
    app.authorization = ('Basic', (oidc_client.client_id, oidc_client.client_secret))
31 31
    status = 200
tests/idp_oidc/test_misc.py
150 150
        utils.login(app, simple_user)
151 151
    response = app.get(authorize_url)
152 152
    if not login_first:
153
        assert set(app.session['login-hint']) == set(['backoffice', 'john@example.com'])
153
        assert set(app.session['login-hint']) == {'backoffice', 'john@example.com'}
154 154
        response = response.follow()
155 155
        assert response.request.path == reverse('auth_login')
156 156
        response.form.set('username', simple_user.username)
......
205 205
    location = urllib.parse.urlparse(response['Location'])
206 206
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
207 207
        query = urllib.parse.parse_qs(location.query)
208
        assert set(query.keys()) == set(['code', 'state'])
208
        assert set(query.keys()) == {'code', 'state'}
209 209
        assert query['code'] == [code.uuid]
210 210
        code = query['code'][0]
211 211
        assert query['state'] == ['xxx']
......
232 232
        query = urllib.parse.parse_qs(location.fragment)
233 233
        assert OIDCAccessToken.objects.count() == 1
234 234
        access_token = OIDCAccessToken.objects.get()
235
        assert set(query.keys()) == set(['access_token', 'token_type', 'expires_in', 'id_token', 'state'])
235
        assert set(query.keys()) == {'access_token', 'token_type', 'expires_in', 'id_token', 'state'}
236 236
        assert query['access_token'] == [access_token.uuid]
237 237
        assert query['token_type'] == ['Bearer']
238 238
        assert query['state'] == ['xxx']
......
250 250
        raise NotImplementedError
251 251
    jwt = JWT(jwt=id_token, key=key, algs=algs)
252 252
    claims = json.loads(jwt.claims)
253
    assert set(claims) >= set(['iss', 'sub', 'aud', 'exp', 'iat', 'nonce', 'auth_time', 'acr'])
253
    assert set(claims) >= {'iss', 'sub', 'aud', 'exp', 'iat', 'nonce', 'auth_time', 'acr'}
254 254
    assert claims['nonce'] == 'yyy'
255 255
    assert response.request.url.startswith(claims['iss'])
256 256
    assert claims['aud'] == oidc_client.client_id
......
776 776
        code.save()
777 777
        location = urllib.parse.urlparse(response['Location'])
778 778
        query = urllib.parse.parse_qs(location.query)
779
        assert set(query.keys()) == set(['code'])
779
        assert set(query.keys()) == {'code'}
780 780
        assert query['code'] == [code.uuid]
781 781
        code = query['code'][0]
782 782
        token_url = make_url('oidc-token')
......
1288 1288
    # jwt deserialization implicitly checks the token signature:
1289 1289
    jwt.deserialize(token, key=jwk)
1290 1290
    claims = json.loads(jwt.claims)
1291
    assert set(claims) == set(['acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'])
1291
    assert set(claims) == {'acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'}
1292 1292
    assert all(claims.values())
1293 1293

  
1294 1294
    # 2. test basic authz
......
1303 1303
    # jwt deserialization implicitly checks the token signature:
1304 1304
    jwt.deserialize(token, key=jwk)
1305 1305
    claims = json.loads(jwt.claims)
1306
    assert set(claims) == set(['acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'])
1306
    assert set(claims) == {'acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'}
1307 1307
    assert all(claims.values())
1308 1308

  
1309 1309

  
tests/test_a2_rbac.py
113 113

  
114 114

  
115 115
def test_role_clean(db):
116
    coin = Role(name=u'Coin')
116
    coin = Role(name='Coin')
117 117
    coin.clean()
118 118
    coin.save()
119 119
    assert coin.slug == 'coin'
......
190 190
    attributes = role_dict['attributes']
191 191
    assert len(attributes) == 2
192 192

  
193
    expected_attr_names = set([attr1.name, attr2.name])
193
    expected_attr_names = {attr1.name, attr2.name}
194 194
    for attr_dict in attributes:
195 195
        assert attr_dict['name'] in expected_attr_names
196 196
        expected_attr_names.remove(attr_dict['name'])
......
213 213
    assert child_role_dict['slug'] == child_role.slug
214 214
    parents = child_role_dict['parents']
215 215
    assert len(parents) == 2
216
    expected_slugs = set([parent_1_role.slug, parent_2_role.slug])
216
    expected_slugs = {parent_1_role.slug, parent_2_role.slug}
217 217
    for parent in parents:
218 218
        assert parent['slug'] in expected_slugs
219 219
        expected_slugs.remove(parent['slug'])
......
404 404
    response = response.click('role_ou1')
405 405
    select2_json = request_select2(app, response)
406 406
    assert select2_json['more'] is False
407
    assert set(result['id'] for result in select2_json['results']) == set(
408
        [simple_user.id, user_ou1.id, admin.id]
409
    )
407
    assert {result['id'] for result in select2_json['results']} == {simple_user.id, user_ou1.id, admin.id}
410 408

  
411 409
    # with A2_RBAC_ROLE_ADMIN_RESTRICT_TO_OU_USERS after a reload of the admin
412 410
    # page, we should only see user from the same OU as the role
......
416 414
    response = response.click('role_ou1')
417 415
    select2_json = request_select2(app, response)
418 416
    assert select2_json['more'] is False
419
    assert set(result['id'] for result in select2_json['results']) == set([user_ou1.id])
417
    assert {result['id'] for result in select2_json['results']} == {user_ou1.id}
420 418

  
421 419

  
422 420
def test_no_managed_ct(transactional_db, settings):
......
464 462
    assert manager.parents(include_self=False).count() == 4
465 463

  
466 464
    for ou in [get_default_ou(), ou1]:
467
        manager = Role.objects.get(ou__isnull=True, slug='_a2-managers-of-{ou.slug}'.format(ou=ou))
468
        user_manager = Role.objects.get(ou=ou, slug='_a2-manager-of-users-{ou.slug}'.format(ou=ou))
469
        role_manager = Role.objects.get(ou=ou, slug='_a2-manager-of-roles-{ou.slug}'.format(ou=ou))
470
        service_manager = Role.objects.get(ou=ou, slug='_a2-manager-of-services-{ou.slug}'.format(ou=ou))
465
        manager = Role.objects.get(ou__isnull=True, slug=f'_a2-managers-of-{ou.slug}')
466
        user_manager = Role.objects.get(ou=ou, slug=f'_a2-manager-of-users-{ou.slug}')
467
        role_manager = Role.objects.get(ou=ou, slug=f'_a2-manager-of-roles-{ou.slug}')
468
        service_manager = Role.objects.get(ou=ou, slug=f'_a2-manager-of-services-{ou.slug}')
471 469

  
472 470
        assert user_manager in manager.parents()
473 471
        assert role_manager in manager.parents()
tests/test_admin.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
from urllib.parse import urlparse
21 19

  
......
52 50
    superuser.verified_attributes.last_name = 'Doe'
53 51

  
54 52
    resp = app.get('/admin/custom_user/user/%s/' % superuser.pk).maybe_follow()
55
    assert set(resp.form.fields.keys()) >= set(
56
        [
57
            'username',
58
            'first_name',
59
            'last_name',
60
            'civilite',
61
            'siret',
62
            'is_staff',
63
            'is_superuser',
64
            'ou',
65
            'groups',
66
            'date_joined_0',
67
            'date_joined_1',
68
            'last_login_0',
69
            'last_login_1',
70
        ]
71
    )
53
    assert set(resp.form.fields.keys()) >= {
54
        'username',
55
        'first_name',
56
        'last_name',
57
        'civilite',
58
        'siret',
59
        'is_staff',
60
        'is_superuser',
61
        'ou',
62
        'groups',
63
        'date_joined_0',
64
        'date_joined_1',
65
        'last_login_0',
66
        'last_login_1',
67
    }
72 68
    resp.form.set('first_name', 'John')
73 69
    resp.form.set('last_name', 'Doe')
74 70
    resp.form.set('civilite', 'Mr')
tests/test_all.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
223 222
        models.Attribute.objects.update(disabled=True)
224 223

  
225 224
        models.Attribute.objects.create(
226
            label=u'custom',
225
            label='custom',
227 226
            name='custom',
228 227
            required=True,
229 228
            user_visible=True,
......
231 230
            kind='string',
232 231
        )
233 232
        models.Attribute.objects.create(
234
            label=u'ID', name='national_number', user_editable=True, user_visible=True, kind='string'
233
            label='ID', name='national_number', user_editable=True, user_visible=True, kind='string'
235 234
        )
236 235
        self.assertTrue(self.client.login(request=None, username='testbot', password='secret'))
237 236

  
......
241 240

  
242 241
        kwargs = {'custom': 'random data', 'national_number': 'xx20153566342yy'}
243 242
        if form.prefix:
244
            kwargs = dict(('%s-%s' % (form.prefix, k), v) for k, v in kwargs.items())
243
            kwargs = {'%s-%s' % (form.prefix, k): v for k, v in kwargs.items()}
245 244

  
246 245
        response = self.client.post(reverse('profile_edit'), kwargs)
247 246
        new = {'custom': 'random data', 'next_url': '', 'national_number': 'xx20153566342yy'}
......
265 264
        models.Attribute.objects.update(disabled=True)
266 265

  
267 266
        models.Attribute.objects.create(
268
            label=u'custom', name='custom', required=False, user_editable=False, kind='string'
267
            label='custom', name='custom', required=False, user_editable=False, kind='string'
269 268
        )
270 269
        models.Attribute.objects.create(
271
            label=u'ID', name='national_number', user_editable=False, user_visible=False, kind='string'
270
            label='ID', name='national_number', user_editable=False, user_visible=False, kind='string'
272 271
        )
273 272

  
274 273
        self.assertTrue(self.client.login(request=None, username='testbot', password='secret'))
275 274
        response = self.client.get(reverse('profile_edit'))
276 275
        form = get_response_form(response)
277
        self.assertEqual(set(form.fields), set(['next_url']))
276
        self.assertEqual(set(form.fields), {'next_url'})
278 277

  
279 278

  
280 279
class CacheTests(TestCase):
......
291 290
        class GlobalCache(CacheDecoratorBase):
292 291
            def __init__(self, *args, **kwargs):
293 292
                self.cache = {}
294
                super(GlobalCache, self).__init__(*args, **kwargs)
293
                super().__init__(*args, **kwargs)
295 294

  
296 295
            def set(self, key, value):
297 296
                self.cache[key] = value
tests/test_api.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
20 19
import json
21 20
import random
22 21
import uuid
22
from unittest import mock
23 23

  
24 24
import django
25
import mock
26 25
import pytest
27 26
from django.contrib.auth import get_user_model
28 27
from django.contrib.auth.hashers import check_password
......
48 47

  
49 48
User = get_user_model()
50 49

  
51
USER_ATTRIBUTES_SET = set(
52
    [
53
        'ou',
54
        'id',
55
        'uuid',
56
        'is_staff',
57
        'is_superuser',
58
        'first_name',
59
        'first_name_verified',
60
        'last_name',
61
        'last_name_verified',
62
        'date_joined',
63
        'last_login',
64
        'username',
65
        'password',
66
        'email',
67
        'is_active',
68
        'modified',
69
        'email_verified',
70
        'last_account_deletion_alert',
71
        'deactivation',
72
        'deactivation_reason',
73
    ]
74
)
50
USER_ATTRIBUTES_SET = {
51
    'ou',
52
    'id',
53
    'uuid',
54
    'is_staff',
55
    'is_superuser',
56
    'first_name',
57
    'first_name_verified',
58
    'last_name',
59
    'last_name_verified',
60
    'date_joined',
61
    'last_login',
62
    'username',
63
    'password',
64
    'email',
65
    'is_active',
66
    'modified',
67
    'email_verified',
68
    'last_account_deletion_alert',
69
    'deactivation',
70
    'deactivation_reason',
71
}
75 72

  
76 73

  
77 74
def test_api_user_simple(logged_app):
......
86 83

  
87 84
    Attribute.objects.create(kind='birthdate', name='birthdate', label='birthdate', required=True)
88 85
    user = User.objects.create(
89
        ou=ou, username='john.doe', first_name=u'Jôhn', last_name=u'Doe', email='john.doe@example.net'
86
        ou=ou, username='john.doe', first_name='Jôhn', last_name='Doe', email='john.doe@example.net'
90 87
    )
91 88
    user.attributes.birthdate = datetime.date(2019, 2, 2)
92 89
    user.set_password('password')
......
111 108
    response = client.get('/api/user/', HTTP_ORIGIN='http://testserver')
112 109
    data = json.loads(force_text(response.content))
113 110
    assert isinstance(data, dict)
114
    assert set(data.keys()) == set(
115
        [
116
            'uuid',
117
            'username',
118
            'first_name',
119
            'ou__slug',
120
            'ou__uuid',
121
            'ou__name',
122
            'last_name',
123
            'email',
124
            'roles',
125
            'services',
126
            'is_superuser',
127
            'ou',
128
            'birthdate',
129
        ]
130
    )
111
    assert set(data.keys()) == {
112
        'uuid',
113
        'username',
114
        'first_name',
115
        'ou__slug',
116
        'ou__uuid',
117
        'ou__name',
118
        'last_name',
119
        'email',
120
        'roles',
121
        'services',
122
        'is_superuser',
123
        'ou',
124
        'birthdate',
125
    }
131 126
    assert data['uuid'] == user.uuid
132 127
    assert data['username'] == user.username
133 128
    assert data['first_name'] == user.first_name
......
142 137
    assert isinstance(data['roles'], list)
143 138
    assert len(data['roles']) == 2
144 139
    for role in data['roles']:
145
        assert set(role.keys()) == set(
146
            ['uuid', 'name', 'slug', 'is_admin', 'is_service', 'ou__uuid', 'ou__name', 'ou__slug']
147
        )
140
        assert set(role.keys()) == {
141
            'uuid',
142
            'name',
143
            'slug',
144
            'is_admin',
145
            'is_service',
146
            'ou__uuid',
147
            'ou__name',
148
            'ou__slug',
149
        }
148 150
        assert (
149 151
            role['uuid'] == role1.uuid
150 152
            and role['name'] == role1.name
......
168 170
    assert isinstance(data['services'], list)
169 171
    assert len(data['services']) == 1
170 172
    s = data['services'][0]
171
    assert set(s.keys()) == set(['name', 'slug', 'ou', 'ou__name', 'ou__slug', 'ou__uuid', 'roles'])
173
    assert set(s.keys()) == {'name', 'slug', 'ou', 'ou__name', 'ou__slug', 'ou__uuid', 'roles'}
172 174
    assert s['name'] == service.name
173 175
    assert s['slug'] == service.slug
174 176
    assert s['ou'] == ou.name
......
178 180
    assert isinstance(s['roles'], list)
179 181
    assert len(s['roles']) == 2
180 182
    for role in s['roles']:
181
        assert set(role.keys()) == set(
182
            ['uuid', 'name', 'slug', 'is_admin', 'is_service', 'ou__uuid', 'ou__name', 'ou__slug']
183
        )
183
        assert set(role.keys()) == {
184
            'uuid',
185
            'name',
186
            'slug',
187
            'is_admin',
188
            'is_service',
189
            'ou__uuid',
190
            'ou__name',
191
            'ou__slug',
192
        }
184 193
        assert (
185 194
            role['uuid'] == role1.uuid
186 195
            and role['name'] == role1.name
......
206 215
    app.authorization = ('Basic', (user.username, user.username))
207 216
    resp = app.get('/api/users/')
208 217
    assert isinstance(resp.json, dict)
209
    assert set(['previous', 'next', 'results']) == set(resp.json.keys())
218
    assert {'previous', 'next', 'results'} == set(resp.json.keys())
210 219
    assert resp.json['previous'] is None
211 220
    assert resp.json['next'] is None
212 221

  
......
217 226
    simple_role.members.add(user)
218 227
    resp = app.get(url)
219 228
    assert isinstance(resp.json, dict)
220
    assert set(['previous', 'next', 'results']) == set(resp.json.keys())
229
    assert {'previous', 'next', 'results'} == set(resp.json.keys())
221 230
    assert resp.json['previous'] is None
222 231
    assert resp.json['next'] is None
223 232

  
......
237 246
        'email_verified': True,
238 247
    }
239 248
    headers = basic_authorization_header(admin)
240
    resp = app.put_json(
241
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
242
    )
249
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
243 250
    user = User.objects.get(id=simple_user.id)
244 251
    assert user.email_verified
245 252
    assert resp.json['email_verified']
......
249 256
    user.email = 'johnny.doeny@foo.bar'
250 257
    user.save()
251 258

  
252
    resp = app.patch_json(
253
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
254
    )
259
    resp = app.patch_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
255 260
    user = User.objects.get(id=simple_user.id)
256 261
    assert user.email_verified
257 262
    assert resp.json['email_verified']
......
271 276
        'last_name': 'Doeny',
272 277
    }
273 278
    headers = basic_authorization_header(admin)
274
    resp = app.put_json(
275
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
276
    )
279
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
277 280
    user = User.objects.get(id=simple_user.id)
278 281
    assert not user.email_verified
279 282
    assert not resp.json['email_verified']
......
282 285
    user.email = 'johnny.doeny@foo.bar'
283 286
    user.save()
284 287

  
285
    resp = app.patch_json(
286
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
287
    )
288
    resp = app.patch_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
288 289
    user = User.objects.get(id=simple_user.id)
289 290
    assert not user.email_verified
290 291
    assert not resp.json['email_verified']
......
305 306
        'last_name': 'Doeny',
306 307
    }
307 308
    headers = basic_authorization_header(admin)
308
    resp = app.put_json(
309
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
310
    )
309
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
311 310
    user = User.objects.get(id=simple_user.id)
312 311

  
313
    resp = app.patch_json(
314
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
315
    )
312
    resp = app.patch_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
316 313

  
317 314

  
318 315
def test_api_users_create_with_email_verified(settings, app, admin):
......
359 356
        'email': 'john.doe@nowhere.null',
360 357
    }
361 358
    headers = basic_authorization_header(admin)
362
    resp = app.post_json(
363
        '/api/users/{}/email/'.format(simple_user.uuid), params=payload, headers=headers, status=200
364
    )
359
    resp = app.post_json(f'/api/users/{simple_user.uuid}/email/', params=payload, headers=headers, status=200)
365 360
    user = User.objects.get(id=simple_user.id)
366 361
    assert not user.email_verified
367 362

  
......
407 402

  
408 403
    resp = app.get('/api/users/?service-ou=default&service-slug=service1')
409 404
    assert len(resp.json['results']) == 2
410
    assert set(user['username'] for user in resp.json['results']) == set(['user1', 'user2'])
405
    assert {user['username'] for user in resp.json['results']} == {'user1', 'user2'}
411 406

  
412 407
    resp = app.get('/api/users/?service-ou=default&service-slug=service2')
413 408
    assert len(resp.json['results']) == 4
......
442 437

  
443 438
    resp = app.get(url + '?service-ou=default&service-slug=service1')
444 439
    assert len(resp.json['results']) == 2
445
    assert set(user['username'] for user in resp.json['results']) == set(['user1', 'user2'])
440
    assert {user['username'] for user in resp.json['results']} == {'user1', 'user2'}
446 441

  
447 442
    resp = app.get(url + '?service-ou=default&service-slug=service2')
448 443
    assert len(resp.json['results']) == 4
......
495 490
        payload['ou'] = api_user.ou.slug
496 491
    resp = app.post_json('/api/users/', params=payload, status=400)
497 492
    assert resp.json['result'] == 0
498
    assert set(['first_name', 'last_name']) == set(resp.json['errors'])
493
    assert {'first_name', 'last_name'} == set(resp.json['errors'])
499 494
    settings.A2_API_USERS_REQUIRED_FIELDS = ['email']
500 495
    if api_user.is_superuser or hasattr(api_user, 'oidc_client') or api_user.roles.exists():
501 496
        status = 201
......
524 519

  
525 520
    resp = app.post_json('/api/users/', params=payload, status=status)
526 521
    if api_user.is_superuser or api_user.roles.exists():
527
        assert (USER_ATTRIBUTES_SET | set(['title', 'title_verified'])) == set(resp.json)
522
        assert (USER_ATTRIBUTES_SET | {'title', 'title_verified'}) == set(resp.json)
528 523
        assert resp.json['first_name'] == payload['first_name']
529 524
        assert resp.json['last_name'] == payload['last_name']
530 525
        assert resp.json['email'] == payload['email']
......
584 579

  
585 580
    resp = app.post_json('/api/users/', params=payload, status=status)
586 581
    if api_user.is_superuser or api_user.roles.exists():
587
        assert (USER_ATTRIBUTES_SET | set(['title', 'title_verified'])) == set(resp.json)
582
        assert (USER_ATTRIBUTES_SET | {'title', 'title_verified'}) == set(resp.json)
588 583
        user = get_user_model().objects.get(pk=resp.json['id'])
589 584
        assert AttributeValue.objects.with_owner(user).filter(verified=True).count() == 3
590 585
        assert AttributeValue.objects.with_owner(user).filter(verified=False).count() == 0
......
725 720
    else:
726 721
        status = 403
727 722

  
728
    resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=status)
723
    resp = app.get(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=status)
729 724

  
730 725
    if member.username == 'fake' or role.name == 'fake':
731 726
        assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}}
732 727
    elif status == 404:
733 728
        assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}}
734 729
        member.roles.add(role)
735
        resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid))
730
        resp = app.get(f'/api/roles/{role.uuid}/members/{member.uuid}/')
736 731
        assert resp.json['uuid'] == member.uuid
737 732
        assert USER_ATTRIBUTES_SET == set(resp.json)
738 733
    else:
......
767 762
    # api call with nested users
768 763
    resp = app.get(url, params={'nested': 'true'})
769 764
    assert resp.json['username'] == 'admin.ou1'
770
    assert USER_ATTRIBUTES_SET | set(['birthdate', 'birthdate_verified']) == set(resp.json)
765
    assert USER_ATTRIBUTES_SET | {'birthdate', 'birthdate_verified'} == set(resp.json)
771 766

  
772 767

  
773 768
def test_api_role_add_member(app, api_user, role, member):
......
782 777
    else:
783 778
        status = 403
784 779

  
785
    resp = app.post_json('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=status)
780
    resp = app.post_json(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=status)
786 781
    if status == 404:
787 782
        pass
788 783
    elif authorized:
......
812 807
    else:
813 808
        status = 403
814 809

  
815
    resp = app.delete_json('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=status)
810
    resp = app.delete_json(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=status)
816 811

  
817 812
    if status == 404:
818 813
        pass
819 814
    elif authorized:
820 815
        assert resp.json['result'] == 1
821 816
        assert resp.json['detail'] == 'User successfully removed from role'
822
        resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=404)
817
        resp = app.get(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=404)
823 818
        assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}}
824 819
        assert_event(
825 820
            'manager.role.membership.removal',
......
852 847
    for m in [member, member_rando2, member_rando2]:  # test no duplicate
853 848
        payload['data'].append({"uuid": m.uuid})
854 849

  
855
    resp = app.post_json(
856
        '/api/roles/{}/relationships/members/'.format(role.uuid), params=payload, status=status
857
    )
850
    resp = app.post_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status)
858 851

  
859 852
    if status in (400, 404):
860 853
        pass
......
894 887
    for m in [member, member_rando2, member_rando2]:  # test no duplicate
895 888
        payload['data'].append({"uuid": m.uuid})
896 889

  
897
    resp = app.delete_json(
898
        '/api/roles/{}/relationships/members/'.format(role.uuid), params=payload, status=status
899
    )
890
    resp = app.delete_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status)
900 891

  
901 892
    if status in (400, 404):
902 893
        pass
......
940 931
    for m in [member, member_rando2, member_rando2]:  # test no duplicate
941 932
        payload['data'].append({"uuid": m.uuid})
942 933

  
943
    resp = app.put_json(
944
        '/api/roles/{}/relationships/members/'.format(role.uuid), params=payload, status=status
945
    )
934
    resp = app.put_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status)
946 935

  
947 936
    if status in (400, 404):
948 937
        pass
......
976 965
    ou = get_default_ou()
977 966

  
978 967
    user = User.objects.create(
979
        ou=ou, username='john.doe', first_name=u'Jôhn', last_name=u'Doe', email='john.doe@example.net'
968
        ou=ou, username='john.doe', first_name='Jôhn', last_name='Doe', email='john.doe@example.net'
980 969
    )
981 970
    user.save()
982 971

  
......
987 976
    if not api_user.has_perm('a2_rbac.manage_members_role', role):
988 977
        status = 403
989 978

  
990
    resp = app.put_json(
991
        '/api/roles/{}/relationships/members/'.format(role.uuid), params={'data': []}, status=status
992
    )
979
    resp = app.put_json(f'/api/roles/{role.uuid}/relationships/members/', params={'data': []}, status=status)
993 980
    if api_user.has_perm('a2_rbac.manage_members_role', role):
994 981
        assert len(role.members.all()) == 0
995 982
    else:
......
1001 988
    authorized = api_user.has_perm('a2_rbac.manage_members_role', role)
1002 989
    status = 405 if authorized else 403
1003 990

  
1004
    app.get('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
991
    app.get(f'/api/roles/{role.uuid}/relationships/members/', status=status)
1005 992

  
1006 993

  
1007 994
def test_api_role_members_payload_missing(app, api_user, role):
......
1009 996
    authorized = api_user.has_perm('a2_rbac.manage_members_role', role)
1010 997
    status = 400 if authorized else 403
1011 998

  
1012
    app.post_json('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
999
    app.post_json(f'/api/roles/{role.uuid}/relationships/members/', status=status)
1013 1000

  
1014
    app.delete_json('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
1001
    app.delete_json(f'/api/roles/{role.uuid}/relationships/members/', status=status)
1015 1002

  
1016
    app.put_json('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
1003
    app.put_json(f'/api/roles/{role.uuid}/relationships/members/', status=status)
1017 1004

  
1018 1005

  
1019 1006
def test_api_role_members_wrong_payload_types(app, superuser, role_random, member_rando2):
......
1021 1008

  
1022 1009
    payload = [{"data": [{'uuid': member_rando2.uuid}]}]
1023 1010

  
1024
    resp = app.post_json(
1025
        '/api/roles/{}/relationships/members/'.format(role_random.uuid), params=payload, status=400
1026
    )
1011
    resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400)
1027 1012

  
1028 1013
    assert resp.json['result'] == 0
1029 1014
    assert resp.json['errors'] == ['Payload must be a dictionary']
1030 1015

  
1031 1016
    payload = {"data": [[member_rando2.uuid]]}
1032 1017

  
1033
    resp = app.post_json(
1034
        '/api/roles/{}/relationships/members/'.format(role_random.uuid), params=payload, status=400
1035
    )
1018
    resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400)
1036 1019

  
1037 1020
    assert resp.json['result'] == 0
1038 1021
    assert resp.json['errors'] == ["List elements of the 'data' dict entry must be dictionaries"]
1039 1022

  
1040 1023
    payload = {"data": [member_rando2.uuid]}
1041 1024

  
1042
    resp = app.post_json(
1043
        '/api/roles/{}/relationships/members/'.format(role_random.uuid), params=payload, status=400
1044
    )
1025
    resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400)
1045 1026

  
1046 1027
    assert resp.json['result'] == 0
1047 1028
    assert resp.json['errors'] == ["List elements of the 'data' dict entry must be dictionaries"]
......
1219 1200
    payload = {'username': 'whatever'}
1220 1201
    resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=400)
1221 1202
    assert resp.json['result'] == 0
1222
    assert resp.json['errors'] == {u'password': [u'This field is required.']}
1203
    assert resp.json['errors'] == {'password': ['This field is required.']}
1223 1204
    # test with invalid credentials
1224 1205
    payload = {'username': 'whatever', 'password': 'password'}
1225 1206
    resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=200)
......
1322 1303

  
1323 1304
def test_api_delete_role(app, admin_ou1, role_ou1):
1324 1305
    app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username))
1325
    app.delete('/api/roles/{}/'.format(role_ou1.uuid))
1306
    app.delete(f'/api/roles/{role_ou1.uuid}/')
1326 1307
    assert not len(Role.objects.filter(slug='role_ou1'))
1327 1308
    assert_event('manager.role.deletion', user=admin_ou1, api=True, role_name=role_ou1.name)
1328 1309

  
1329 1310

  
1330 1311
def test_api_delete_role_unauthorized(app, simple_user, role_ou1):
1331 1312
    app.authorization = ('Basic', (simple_user.username, simple_user.username))
1332
    app.delete('/api/roles/{}/'.format(role_ou1.uuid), status=404)
1313
    app.delete(f'/api/roles/{role_ou1.uuid}/', status=404)
1333 1314
    assert len(Role.objects.filter(slug='role_ou1'))
1334 1315

  
1335 1316

  
......
1339 1320
    role_data = {
1340 1321
        'slug': 'updated-role',
1341 1322
    }
1342
    app.patch_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data)
1323
    app.patch_json(f'/api/roles/{role_ou1.uuid}/', params=role_data)
1343 1324
    assert_event('manager.role.edit', user=admin_ou1, api=True, role_name=role_ou1.name)
1344 1325

  
1345 1326
    # The role API won't change the organizational unit attribute:
......
1354 1335
    role_data = {
1355 1336
        'slug': 'updated-role',
1356 1337
    }
1357
    app.patch_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data, status=404)
1338
    app.patch_json(f'/api/roles/{role_ou1.uuid}/', params=role_data, status=404)
1358 1339
    role_ou1.refresh_from_db()
1359 1340
    assert role_ou1.slug == 'role_ou1'
1360 1341
    assert not len(Role.objects.filter(slug='updated-role'))
......
1364 1345
    app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username))
1365 1346

  
1366 1347
    role_data = {'name': 'updated-role', 'slug': 'updated-role', 'ou': 'ou2'}
1367
    app.put_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data)
1348
    app.put_json(f'/api/roles/{role_ou1.uuid}/', params=role_data)
1368 1349
    role_ou1.refresh_from_db()
1369 1350
    assert role_ou1.name == 'updated-role'
1370 1351
    assert role_ou1.slug == 'updated-role'
......
1375 1356
def test_api_put_role_unauthorized(app, simple_user, role_ou1, ou1):
1376 1357
    app.authorization = ('Basic', (simple_user.username, simple_user.username))
1377 1358
    role_data = {'name': 'updated-role', 'slug': 'updated-role', 'ou': 'ou2'}
1378
    app.put_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data, status=404)
1359
    app.put_json(f'/api/roles/{role_ou1.uuid}/', params=role_data, status=404)
1379 1360
    role_ou1.refresh_from_db()
1380 1361
    assert role_ou1.name == 'role_ou1'
1381 1362
    assert role_ou1.slug == 'role_ou1'
......
1508 1489

  
1509 1490
def test_api_get_role_description(app, admin_rando_role, role_random):
1510 1491
    app.authorization = ('Basic', (admin_rando_role.username, admin_rando_role.username))
1511
    resp = app.get('/api/roles/{}/'.format(role_random.uuid))
1492
    resp = app.get(f'/api/roles/{role_random.uuid}/')
1512 1493

  
1513 1494
    assert resp.json['slug'] == 'rando'
1514 1495
    assert resp.json['ou'] == 'ou_rando'
......
1554 1535
    resp = app.get(url)
1555 1536
    assert len(resp.json['results']) > 0
1556 1537
    for user_dict in resp.json['results']:
1557
        assert USER_ATTRIBUTES_SET | set(['birthdate', 'birthdate_verified']) == set(user_dict)
1538
        assert USER_ATTRIBUTES_SET | {'birthdate', 'birthdate_verified'} == set(user_dict)
1558 1539
    assert [x['username'] for x in resp.json['results']] == ['john.doe']
1559 1540

  
1560 1541
    # api call with nested users
......
1853 1834

  
1854 1835
    # update from missing value to blank field fails
1855 1836
    payload['last_name'] = ''
1856
    resp = app.put_json(
1857
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400
1858
    )
1837
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400)
1859 1838
    assert resp.json['result'] == 0
1860 1839
    assert resp.json['errors']['last_name'] == ['This field may not be blank.']
1861 1840

  
1862 1841
    # update with value pass
1863 1842
    payload['last_name'] = 'Foobar'
1864
    resp = app.put_json(
1865
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
1866
    )
1843
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
1867 1844
    user = User.objects.get(id=simple_user.id)
1868 1845
    assert user.last_name == 'Foobar'
1869 1846

  
1870 1847
    # update from non-empty value to blank fails
1871 1848
    payload['last_name'] = ''
1872
    resp = app.put_json(
1873
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400
1874
    )
1849
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400)
1875 1850
    assert resp.json['result'] == 0
1876 1851
    assert resp.json['errors']['last_name'] == ['This field may not be blank.']
1877 1852

  
......
1901 1876
    payload['prefered_color'] = ''
1902 1877
    payload['date'] = ''
1903 1878
    payload['birthdate'] = ''
1904
    resp = app.put_json(
1905
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400
1906
    )
1879
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400)
1907 1880
    assert resp.json['result'] == 0
1908 1881
    assert resp.json['errors']['prefered_color'] == ['This field may not be blank.']
1909 1882
    assert resp.json['errors']['date'] == ['This field may not be blank.']
......
1913 1886
    payload['prefered_color'] = '?' * 257
1914 1887
    payload['date'] = '0000-00-00'
1915 1888
    payload['birthdate'] = '1899-12-31'
1916
    resp = app.put_json(
1917
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400
1918
    )
1889
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400)
1919 1890
    assert resp.json['result'] == 0
1920 1891
    assert resp.json['errors']['prefered_color'] == ['Ensure this field has no more than 256 characters.']
1921 1892
    assert any(error.startswith('Date has wrong format.') for error in resp.json['errors']['date'])
......
1928 1899
    payload['prefered_color'] = 'blue'
1929 1900
    payload['date'] = '1515-01-15'
1930 1901
    payload['birthdate'] = '1900-02-22'
1931
    resp = app.put_json(
1932
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
1933
    )
1902
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
1934 1903
    assert_event('manager.user.profile.edit', user=admin, api=True, new=payload)
1935 1904

  
1936 1905
    # value are properly returned on a get
1937
    resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200)
1906
    resp = app.get(f'/api/users/{simple_user.uuid}/', headers=headers, status=200)
1938 1907
    assert resp.json['prefered_color'] == 'blue'
1939 1908
    assert resp.json['date'] == '1515-01-15'
1940 1909
    assert resp.json['birthdate'] == '1900-02-22'
......
1953 1922
        'last_name': 'Doe',
1954 1923
    }
1955 1924
    headers = basic_authorization_header(admin)
1956
    resp = app.put_json(
1957
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
1958
    )
1959
    resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200)
1925
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
1926
    resp = app.get(f'/api/users/{simple_user.uuid}/', headers=headers, status=200)
1960 1927
    payload['prefered_color'] = None
1961 1928
    payload['date'] = None
1962 1929
    payload['birthdate'] = None
......
1964 1931
    payload['prefered_color'] = ''
1965 1932
    payload['date'] = ''
1966 1933
    payload['birthdate'] = ''
1967
    resp = app.put_json(
1968
        '/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200
1969
    )
1970
    resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200)
1934
    resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200)
1935
    resp = app.get(f'/api/users/{simple_user.uuid}/', headers=headers, status=200)
1971 1936
    payload['prefered_color'] = None
1972 1937
    payload['date'] = None
1973 1938
    payload['birthdate'] = None
......
2253 2218
    user2 = User.objects.create(username='foo2', email=email)
2254 2219

  
2255 2220
    app.authorization = ('Basic', (admin.username, admin.username))
2256
    resp = app.get('/api/users/?email={}'.format(email))
2221
    resp = app.get(f'/api/users/?email={email}')
2257 2222
    assert len(resp.json['results']) == 1
2258 2223

  
2259 2224
    payload = {
......
2265 2230
    headers = basic_authorization_header(admin)
2266 2231
    app.post_json('/api/users/', headers=headers, params=payload, status=201)
2267 2232

  
2268
    resp = app.get('/api/users/?email={}'.format(email))
2233
    resp = app.get(f'/api/users/?email={email}')
2269 2234
    assert len(resp.json['results']) == 2
2270 2235

  
2271 2236
    user2.delete()
2272
    resp = app.get('/api/users/?email={}'.format(email))
2237
    resp = app.get(f'/api/users/?email={email}')
2273 2238
    assert len(resp.json['results']) == 1
2274 2239

  
2275 2240
    settings.A2_EMAIL_IS_UNIQUE = True
......
2325 2290

  
2326 2291
def test_api_users_delete(settings, app, admin, simple_user):
2327 2292
    headers = basic_authorization_header(admin)
2328
    resp = app.delete_json('/api/users/{}/'.format(simple_user.uuid), headers=headers)
2293
    resp = app.delete_json(f'/api/users/{simple_user.uuid}/', headers=headers)
2329 2294
    assert not User.objects.filter(pk=simple_user.pk).exists()
2330 2295
    assert_event('manager.user.deletion', user=admin, api=True)
2331 2296

  
tests/test_attribute_kinds.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
tests/test_auth_oidc.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2020 Entr'ouvert
4 3
#
......
515 514
        with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, nonce=nonce):
516 515
            response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state})
517 516
    assert len(hooks.auth_oidc_backend_modify_user) == 1
518
    assert set(hooks.auth_oidc_backend_modify_user[0]['kwargs']) >= set(
519
        ['user', 'provider', 'user_info', 'id_token', 'access_token']
520
    )
517
    assert set(hooks.auth_oidc_backend_modify_user[0]['kwargs']) >= {
518
        'user',
519
        'provider',
520
        'user_info',
521
        'id_token',
522
        'access_token',
523
    }
521 524
    assert urllib.parse.urlparse(response['Location']).path == '/admin/'
522 525
    assert User.objects.count() == 1
523 526
    user = User.objects.get()
......
697 700

  
698 701
    with pytest.raises(IDTokenError):
699 702
        with utils.check_log(caplog, 'missing field'):
700
            token = IDToken(
701
                '{}.{}.{}'.format(_header(oidc_provider), erroneous_payload, _signature(oidc_provider))
702
            )
703
            token = IDToken(f'{_header(oidc_provider)}.{erroneous_payload}.{_signature(oidc_provider)}')
703 704
            token.deserialize(oidc_provider)
704 705

  
705 706

  
tests/test_commands.py
203 203
    ldif = tmpdir.join('some.ldif')
204 204
    ldif.ensure()
205 205

  
206
    class MockPArser(object):
206
    class MockPArser:
207 207
        def __init__(self, *args, **kwargs):
208 208
            self.users = []
209 209
            assert len(args) == 1
......
219 219
    call_command('load-ldif', ldif.strpath, result='result', extra_attribute={'ldap_attr': 'first_name'})
220 220

  
221 221
    # test ExtraAttributeAction
222
    class MockPArser(object):
222
    class MockPArser:
223 223
        def __init__(self, *args, **kwargs):
224 224
            self.users = []
225 225
            assert len(args) == 1
tests/test_crypto.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
tests/test_csv_import.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import codecs
21 19
import io
......
89 87

  
90 88
def test_bad_csv_encoding(profile):
91 89
    importer = CsvImporter()
92
    assert not importer.run(u'é'.encode('utf-8'), 'ascii')
90
    assert not importer.run('é'.encode(), 'ascii')
93 91
    assert importer.error == Error('bad-encoding')
94 92

  
95 93

  
......
173 171

  
174 172

  
175 173
def test_bom_character(profile, user_csv_importer_factory):
176
    content = codecs.BOM_UTF8 + 'email key,first_name\ntest@entrouvert.org,hop'.encode('utf-8')
174
    content = codecs.BOM_UTF8 + b'email key,first_name\ntest@entrouvert.org,hop'
177 175
    file_content = io.BytesIO(content)
178 176
    importer = UserCsvImporter()
179 177
    assert importer.run(file_content, 'utf-8-sig')
tests/test_custom_user.py
38 38

  
39 39
    user1 = User.objects.create(username='user')
40 40
    user1.roles.add(rchild1)
41
    assert set([r.id for r in user1.roles_and_parents()]) == set([rchild1.id, rparent1.id, rparent2.id])
41
    assert {r.id for r in user1.roles_and_parents()} == {rchild1.id, rparent1.id, rparent2.id}
42 42
    for r in user1.roles_and_parents():
43 43
        if r.id == rchild1.id:
44 44
            assert r.member == [user1]
......
47 47
            assert r.member == []
48 48
    user1.roles.remove(rchild1)
49 49
    user1.roles.add(rchild2)
50
    assert set([r.id for r in user1.roles_and_parents()]) == set([rchild2.id, rparent1.id, rparent2.id])
50
    assert {r.id for r in user1.roles_and_parents()} == {rchild2.id, rparent1.id, rparent2.id}
51 51
    for r in user1.roles_and_parents():
52 52
        if r.id == rchild2.id:
53 53
            assert r.member == [user1]
tests/test_data_transfer.py
70 70
    assert child_role_dict['slug'] == child_role.slug
71 71
    parents = child_role_dict['parents']
72 72
    assert len(parents) == 2
73
    expected_slugs = set([parent_1_role.slug, parent_2_role.slug])
73
    expected_slugs = {parent_1_role.slug, parent_2_role.slug}
74 74
    for parent in parents:
75 75
        assert parent['slug'] in expected_slugs
76 76
        expected_slugs.remove(parent['slug'])
tests/test_fields.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import pytest
20 19
from django.core.exceptions import ValidationError
tests/test_idp_cas.py
183 183
        next_url, next_url_query = query['next'][0].split('?')
184 184
        next_url_query = urllib.parse.parse_qs(next_url_query)
185 185
        self.assertEqual(next_url, '/idp/cas/continue/')
186
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
186
        self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
187 187
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
188 188
        self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id])
189 189
        response = self.client.get(location)
......
240 240
        next_url, next_url_query = query['next'][0].split('?')
241 241
        next_url_query = urllib.parse.parse_qs(next_url_query)
242 242
        self.assertEqual(next_url, '/idp/cas/continue/')
243
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
243
        self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
244 244
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
245 245
        self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id])
246 246
        response = self.client.get(location)
......
301 301
        next_url, next_url_query = query['next'][0].split('?')
302 302
        next_url_query = urllib.parse.parse_qs(next_url_query)
303 303
        self.assertEqual(next_url, '/idp/cas/continue/')
304
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
304
        self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
305 305
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
306 306
        self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id])
307 307
        response = self.client.get(location)
......
360 360
        next_url, next_url_query = query['next'][0].split('?')
361 361
        next_url_query = urllib.parse.parse_qs(next_url_query)
362 362
        self.assertEqual(next_url, '/idp/cas/continue/')
363
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
363
        self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
364 364
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
365 365
        self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id])
366 366
        response = self.client.get(location)
......
422 422
        next_url, next_url_query = query['next'][0].split('?')
423 423
        next_url_query = urllib.parse.parse_qs(next_url_query)
424 424
        self.assertEqual(next_url, '/idp/cas/continue/')
425
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
425
        self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
426 426
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
427 427
        self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id])
428 428
        response = self.client.get(location)
tests/test_idp_saml2.py
1
# coding: utf-8
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2020 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import base64
21 19
import datetime
......
23 21
import re
24 22
import urllib.parse
25 23
import xml.etree.ElementTree as ET
24
from unittest import mock
26 25

  
27 26
import lasso
28
import mock
29 27
import pytest
30 28
from django.contrib.auth import REDIRECT_FIELD_NAME
31 29
from django.core.files import File
......
63 61
    return response.text
64 62

  
65 63

  
66
class Raw(object):
64
class Raw:
67 65
    def __init__(self, d):
68 66
        self.__dict__.update(d)
69 67

  
......
102 100
    return user
103 101

  
104 102

  
105
class SamlSP(object):
103
class SamlSP:
106 104
    METADATA_TPL = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
107 105
<EntityDescriptor
108 106
 entityID="{{ base_url }}/"
......
298 296
        login.initRequest(force_str(query_string), method)
299 297
        login.buildRequestMsg()
300 298
        response = self.app.post(
301
            login.msgUrl, params=force_bytes(login.msgBody), headers={'content-type': str('text/xml')}
299
            login.msgUrl, params=force_bytes(login.msgBody), headers={'content-type': 'text/xml'}
302 300
        )
303 301
        login.processResponseMsg(force_str(response.text))
304 302
        login.acceptSso()
305 303

  
306 304

  
307
class Scenario(object):
305
class Scenario:
308 306
    check_federation = False
309 307

  
310 308
    def __init__(self, app, sp_kwargs=None, make_authn_request_kwargs=None, **kwargs):
......
507 505
            (
508 506
                "/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/"
509 507
                "saml:AttributeValue",
510
                set(['code_code', 'mobile']),
508
                {'code_code', 'mobile'},
511 509
            ),
512 510
        )
513 511
        if user is not None and self.sp.admin_role in user.roles.all():
......
651 649
                    func.nid_format,
652 650
                )
653 651
                return {
654
                    at.name: set(
655
                        [''.join(force_text(mtn.dump()) for mtn in atv.any) for atv in at.attributeValue]
656
                    )
652
                    at.name: {''.join(force_text(mtn.dump()) for mtn in atv.any) for atv in at.attributeValue}
657 653
                    for at in assertion.attributeStatement[0].attribute
658 654
                }
659 655

  
......
684 680

  
685 681
    # check
686 682
    assert attributes == {
687
        'nom': set(['Rigby']),
688
        'prenom': set(['Éléonore']),
683
        'nom': {'Rigby'},
684
        'prenom': {'Éléonore'},
689 685
    }
690 686

  
691 687

  
......
720 716

  
721 717
    # check
722 718
    assert attributes == {
723
        'nom': set(['Rigby']),
724
        'prenom': set(['Éléonore', 'coucou']),
719
        'nom': {'Rigby'},
720
        'prenom': {'Éléonore', 'coucou'},
725 721
    }
726 722

  
727 723

  
......
758 754
    profile.request.extensions.any = tuple(force_str(ext) for ext in extensions)
759 755

  
760 756
    login_hints = get_login_hints_extension(profile)
761
    assert login_hints == set(['backoffice', 'saint-machin-truc', 'toto@example.com'])
757
    assert login_hints == {'backoffice', 'saint-machin-truc', 'toto@example.com'}
762 758

  
763 759

  
764 760
def test_make_edu_person_targeted_id(db, settings, rf):
......
809 805

  
810 806
    # check
811 807
    assert len(attributes) == 3
812
    assert attributes['nom'] == set(['Rambo'])
813
    assert attributes['prenom'] == set(['John'])
808
    assert attributes['nom'] == {'Rambo'}
809
    assert attributes['prenom'] == {'John'}
814 810
    edu_name = 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10'
815 811

  
816 812
    assert len(attributes[edu_name]) == 1
......
842 838

  
843 839
    # check
844 840
    assert len(attributes) == 3
845
    assert attributes['nom'] == set(['Rambo'])
846
    assert attributes['prenom'] == set(['John'])
841
    assert attributes['nom'] == {'Rambo'}
842
    assert attributes['prenom'] == {'John'}
847 843

  
848 844
    assert len(attributes['edupersontargetedid']) == 1
849 845
    node = lasso.Node.newFromXmlNode(force_str(list(attributes['edupersontargetedid'])[0]))
......
930 926

  
931 927
    attributes = add_attributes_all(user_ou1)
932 928
    assert attributes == {
933
        'a2_role_names': set(['Role of service', 'role_ou2']),
934
        'a2_role_slugs': set(['role-of-service', 'role_ou2']),
935
        'a2_role_uuids': set([service_role.uuid, role_ou2.uuid]),
936
        'a2_service_ou_role_names': set(['Role of service']),
937
        'a2_service_ou_role_slugs': set(['role-of-service']),
938
        'a2_service_ou_role_uuids': set([service_role.uuid]),
939
        'django_user_birthdate': set(['1970-01-01']),
940
        'django_user_date_joined': set([str(user_ou1.date_joined)]),
941
        'django_user_deleted': set([]),
942
        'django_user_domain': set(['']),
943
        'django_user_email': set(['john.doe@example.net']),
944
        'django_user_email_verified': set(['false']),
945
        'django_user_first_name': set(['J\xf4hn']),
946
        'django_user_full_name': set(['J\xf4hn D\xf4e']),
947
        'django_user_group_names': set([]),
948
        'django_user_groups': set([]),
949
        'django_user_id': set([str(user_ou1.id)]),
950
        'django_user_identifier': set(['john.doe']),
951
        'django_user_is_active': set(['true']),
952
        'django_user_is_staff': set(['false']),
953
        'django_user_is_superuser': set(['false']),
954
        'django_user_last_account_deletion_alert': set([]),
955
        'django_user_last_login': set([]),
956
        'django_user_last_name': set(['D\xf4e']),
957
        'django_user_modified': set([str(user_ou1.modified)]),
958
        'django_user_ou': set([]),
959
        'django_user_ou_name': set(['OU1']),
960
        'django_user_ou_slug': set(['ou1']),
961
        'django_user_ou_uuid': set([ou1.uuid]),
962
        'django_user_password': set(['abba0b6ff456806bab66baed93e6d9c4']),
963
        'django_user_username': set(['john.doe']),
964
        'django_user_uuid': set([user_ou1.uuid]),
965
        'is_admin': set(['true']),
929
        'a2_role_names': {'Role of service', 'role_ou2'},
930
        'a2_role_slugs': {'role-of-service', 'role_ou2'},
931
        'a2_role_uuids': {service_role.uuid, role_ou2.uuid},
932
        'a2_service_ou_role_names': {'Role of service'},
933
        'a2_service_ou_role_slugs': {'role-of-service'},
934
        'a2_service_ou_role_uuids': {service_role.uuid},
935
        'django_user_birthdate': {'1970-01-01'},
936
        'django_user_date_joined': {str(user_ou1.date_joined)},
937
        'django_user_deleted': set(),
938
        'django_user_domain': {''},
939
        'django_user_email': {'john.doe@example.net'},
940
        'django_user_email_verified': {'false'},
941
        'django_user_first_name': {'J\xf4hn'},
942
        'django_user_full_name': {'J\xf4hn D\xf4e'},
943
        'django_user_group_names': set(),
944
        'django_user_groups': set(),
945
        'django_user_id': {str(user_ou1.id)},
946
        'django_user_identifier': {'john.doe'},
947
        'django_user_is_active': {'true'},
948
        'django_user_is_staff': {'false'},
949
        'django_user_is_superuser': {'false'},
950
        'django_user_last_account_deletion_alert': set(),
951
        'django_user_last_login': set(),
952
        'django_user_last_name': {'D\xf4e'},
953
        'django_user_modified': {str(user_ou1.modified)},
954
        'django_user_ou': set(),
955
        'django_user_ou_name': {'OU1'},
956
        'django_user_ou_slug': {'ou1'},
957
        'django_user_ou_uuid': {ou1.uuid},
958
        'django_user_password': {'abba0b6ff456806bab66baed93e6d9c4'},
959
        'django_user_username': {'john.doe'},
960
        'django_user_uuid': {user_ou1.uuid},
961
        'is_admin': {'true'},
966 962
    }
967 963

  
968 964

  
tests/test_journal.py
16 16

  
17 17
import random
18 18
from datetime import datetime, timedelta
19
from unittest import mock
19 20

  
20
import mock
21 21
import pytest
22 22
import pytz
23 23
from django.contrib.auth import get_user_model
......
107 107
    assert Event.objects.from_cursor(ev1.cursor).count() == 12
108 108
    assert list(Event.objects.all()[ev2.cursor : 2]) == events[6:8]
109 109
    assert list(Event.objects.all()[-4 : ev2.cursor]) == events[3:7]
110
    assert set(Event.objects.which_references(service)[0].references) == set([service])
110
    assert set(Event.objects.which_references(service)[0].references) == {service}
111 111

  
112 112
    # verify type, user and service are prefetched
113 113
    with django_assert_num_queries(3):
tests/test_large_userbase.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
tests/test_ldap.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
19 18
import os
20 19
import time
21 20
import urllib.parse
21
from unittest import mock
22 22

  
23 23
import ldap
24
import mock
25 24
import pytest
26 25
from django.contrib.auth import get_user_model
27 26
from django.core import mail, management
......
510 509
            'use_tls': False,
511 510
            'create_group': True,
512 511
            'group_mapping': [
513
                [u'cn=group1,o=ôrga', ['Group1']],
512
                ['cn=group1,o=ôrga', ['Group1']],
514 513
            ],
515 514
        }
516 515
    ]
......
533 532
            'use_tls': False,
534 533
            'create_group': True,
535 534
            'group_mapping': [
536
                [u'cn=group2,o=ôrga', ['Group2']],
535
                ['cn=group2,o=ôrga', ['Group2']],
537 536
            ],
538 537
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
539 538
        }
......
569 568
        '/login/', {'login-password-submit': '1', 'username': USERNAME, 'password': PASS}, follow=True
570 569
    )
571 570
    assert response.context['user'].username == '%s@ldap' % USERNAME
572
    assert set(response.context['user'].roles.values_list('name', flat=True)) == set(['Role1', 'Role2'])
571
    assert set(response.context['user'].roles.values_list('name', flat=True)) == {'Role1', 'Role2'}
573 572

  
574 573

  
575 574
def test_posix_group_to_role_mapping(slapd, settings, client, db):
......
642 641
            'url': [slapd.ldap_url],
643 642
            'basedn': 'o=ôrga',
644 643
            'use_tls': False,
645
            'groupsu': [u'cn=group1,o=ôrga'],
644
            'groupsu': ['cn=group1,o=ôrga'],
646 645
        }
647 646
    ]
648 647
    response = client.post(
......
662 661
            'url': [slapd.ldap_url],
663 662
            'basedn': 'o=ôrga',
664 663
            'use_tls': False,
665
            'groupstaff': [u'cn=group1,o=ôrga'],
664
            'groupstaff': ['cn=group1,o=ôrga'],
666 665
        }
667 666
    ]
668 667
    response = client.post(
......
687 686
            'use_tls': False,
688 687
            'create_group': True,
689 688
            'group_mapping': [
690
                [u'cn=group2,o=ôrga', ['Group2']],
689
                ['cn=group2,o=ôrga', ['Group2']],
691 690
            ],
692 691
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
693 692
            'group_to_role_mapping': [
......
772 771
            'use_tls': False,
773 772
            'create_group': True,
774 773
            'group_mapping': [
775
                [u'cn=group2,o=ôrga', ['Group2']],
774
                ['cn=group2,o=ôrga', ['Group2']],
776 775
            ],
777 776
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
778 777
            'set_mandatory_roles': ['tech', 'admin'],
......
791 790
            'use_tls': False,
792 791
            'create_group': True,
793 792
            'group_mapping': [
794
                [u'cn=group2,o=ôrga', ['Group2']],
793
                ['cn=group2,o=ôrga', ['Group2']],
795 794
            ],
796 795
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
797 796
            'set_mandatory_roles': ['tech', 'admin'],
......
814 813
            'use_tls': False,
815 814
            'create_group': True,
816 815
            'group_mapping': [
817
                [u'cn=group2,o=ôrga', ['Group2']],
816
                ['cn=group2,o=ôrga', ['Group2']],
818 817
            ],
819 818
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
820 819
            'set_mandatory_roles': ['tech', 'admin'],
......
839 838
            'use_tls': False,
840 839
            'create_group': True,
841 840
            'group_mapping': [
842
                [u'cn=group2,o=ôrga', ['Group2']],
841
                ['cn=group2,o=ôrga', ['Group2']],
843 842
            ],
844 843
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
845 844
            'set_mandatory_roles': ['tech'],
......
865 864
            'use_tls': False,
866 865
            'create_group': True,
867 866
            'group_mapping': [
868
                [u'cn=group2,o=ôrga', ['Group2']],
867
                ['cn=group2,o=ôrga', ['Group2']],
869 868
            ],
870 869
            'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))',
871 870
            'set_mandatory_roles': ['tech'],
......
1115 1114
            'use_tls': False,
1116 1115
        }
1117 1116
    ]
1118
    user = authenticate(username=u'etienne.michu', password=u'passé')
1117
    user = authenticate(username='etienne.michu', password='passé')
1119 1118
    assert user
1120
    assert user.check_password(u'passé')
1121
    user.set_password(u'àbon')
1122
    assert user.check_password(u'àbon')
1123
    user2 = authenticate(username=u'etienne.michu', password=u'àbon')
1119
    assert user.check_password('passé')
1120
    user.set_password('àbon')
1121
    assert user.check_password('àbon')
1122
    user2 = authenticate(username='etienne.michu', password='àbon')
1124 1123
    assert user.pk == user2.pk
1125 1124

  
1126 1125

  
......
1255 1254
    settings.LDAP_AUTH_SETTINGS = [
1256 1255
        {
1257 1256
            'url': [slapd_ppolicy.ldap_url],
1258
            'basedn': u'o=ôrga',
1259
            'ppolicy_dn': u'cn=default,ou=ppolicies,o=ôrga',
1257
            'basedn': 'o=ôrga',
1258
            'ppolicy_dn': 'cn=default,ou=ppolicies,o=ôrga',
1260 1259
            'use_tls': False,
1261 1260
        }
1262 1261
    ]
......
1293 1292

  
1294 1293
    user = authenticate(username=USERNAME, password=UPASS)
1295 1294
    assert user.check_password(UPASS)
1296
    password = u'ogutOmyetew4'
1295
    password = 'ogutOmyetew4'
1297 1296
    user.set_password(password)
1298 1297

  
1299 1298
    time.sleep(pwdMaxAge * 3)
......
1504 1503
    )
1505 1504

  
1506 1505
    user = authenticate(username=USERNAME, password=UPASS)
1507
    assert user.set_password(u'ogutOmyetew4') is None
1506
    assert user.set_password('ogutOmyetew4') is None
1508 1507
    assert 'STRONG_AUTH_REQUIRED' in caplog.text
1509 1508

  
1510 1509

  
......
1649 1648
    assert user
1650 1649
    assert user.get_attributes(object(), {}) == {
1651 1650
        'dn': 'cn=étienne michu,o=\xf4rga',
1652
        'givenname': [u'Étienne'],
1653
        'mail': [u'etienne.michu@example.net'],
1654
        'sn': [u'Michu'],
1655
        'uid': [u'etienne.michu'],
1651
        'givenname': ['Étienne'],
1652
        'mail': ['etienne.michu@example.net'],
1653
        'sn': ['Michu'],
1654
        'uid': ['etienne.michu'],
1656 1655
        'carlicense': ['123445ABC'],
1657 1656
    }
1658 1657
    # simulate LDAP down
1659 1658
    slapd.stop()
1660 1659
    assert user.get_attributes(object(), {}) == {
1661 1660
        'dn': 'cn=étienne michu,o=\xf4rga',
1662
        'givenname': [u'\xc9tienne'],
1663
        'mail': [u'etienne.michu@example.net'],
1664
        'sn': [u'Michu'],
1665
        'uid': [u'etienne.michu'],
1661
        'givenname': ['\xc9tienne'],
1662
        'mail': ['etienne.michu@example.net'],
1663
        'sn': ['Michu'],
1664
        'uid': ['etienne.michu'],
1666 1665
        'carlicense': ['123445ABC'],
1667 1666
    }
1668 1667
    assert not user.check_password(UPASS)
......
1675 1674
    conn.modify_s(DN, ldif)
1676 1675
    assert user.get_attributes(object(), {}) == {
1677 1676
        'dn': 'cn=étienne michu,o=\xf4rga',
1678
        'givenname': [u'\xc9tienne'],
1679
        'mail': [u'etienne.michu@example.net'],
1680
        'sn': [u'Micho'],
1681
        'uid': [u'etienne.michu'],
1677
        'givenname': ['\xc9tienne'],
1678
        'mail': ['etienne.michu@example.net'],
1679
        'sn': ['Micho'],
1680
        'uid': ['etienne.michu'],
1682 1681
        'carlicense': ['123445ABC'],
1683 1682
    }
1684 1683

  
tests/test_login.py
203 203
    assert not response.pyquery('.errorlist')
204 204
    assert response.pyquery.find('select#id_ou')
205 205
    assert len(response.pyquery.find('select#id_ou optgroup')) == 0
206
    assert set([elt.text for elt in response.pyquery.find('select#id_ou option')]) == set(
207
        [u'Default organizational unit', 'OU1', 'OU2', '---------']
208
    )
206
    assert {elt.text for elt in response.pyquery.find('select#id_ou option')} == {
207
        'Default organizational unit',
208
        'OU1',
209
        'OU2',
210
        '---------',
211
    }
209 212
    # Check selector is required
210 213
    response.form.set('username', simple_user.username)
211 214
    response.form.set('password', simple_user.username)
......
230 233
    response = app.get('/login/')
231 234
    assert response.pyquery.find('select#id_ou')
232 235
    assert len(response.pyquery.find('select#id_ou optgroup')) == 2
233
    assert set([elt.text for elt in response.pyquery.find('select#id_ou option')]) == set(
234
        [u'Default organizational unit', 'OU1', 'OU2', '---------']
235
    )
236
    assert {elt.text for elt in response.pyquery.find('select#id_ou option')} == {
237
        'Default organizational unit',
238
        'OU1',
239
        'OU2',
240
        '---------',
241
    }
236 242
    assert response.pyquery.find('select#id_ou option[selected]')[0].text == 'Default organizational unit'
237 243

  
238 244
    # Create a service
tests/test_manager.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import json
21 19
from urllib.parse import urlparse
......
370 368
        # verify table shown
371 369
        q = response.pyquery.remove_namespaces()
372 370
        assert len(q('table tbody tr')) == 2
373
        assert set([e.text for e in q('table tbody td.username')]) == {'admin', 'superuser'}
371
        assert {e.text for e in q('table tbody td.username')} == {'admin', 'superuser'}
374 372

  
375 373
        # test user's role page
376 374
        response = app.get('/manage/users/%d/roles/' % admin.pk)
......
429 427
        # verify table shown
430 428
        q = response.pyquery.remove_namespaces()
431 429
        assert len(q('table tbody tr')) == 3
432
        assert set([e.text for e in q('table tbody td.username')]) == {'admin', 'superuser', 'admin.ou1'}
430
        assert {e.text for e in q('table tbody td.username')} == {'admin', 'superuser', 'admin.ou1'}
433 431

  
434 432
        # test user's role page
435 433
        response = app.get('/manage/users/%d/roles/' % admin.pk)
......
483 481
        q = response.pyquery.remove_namespaces()
484 482
        assert len(q('table tbody tr')) == 2
485 483
        names = [elt.text for elt in q('table tbody td.name a')]
486
        assert set(names) == {u'simple role', 'role_ou1'}
484
        assert set(names) == {'simple role', 'role_ou1'}
487 485

  
488 486
        response.form.set('search-ou', 'all')
489 487
        response.form.set('search-internals', True)
......
531 529
        q = response.pyquery.remove_namespaces()
532 530
        # only admin.ou1 is visible
533 531
        assert len(q('table tbody tr')) == 1
534
        assert set([e.text for e in q('table tbody td.username')]) == {'admin.ou1'}
532
        assert {e.text for e in q('table tbody td.username')} == {'admin.ou1'}
535 533

  
536 534
        # test user's role page
537 535
        response = app.get('/manage/users/%d/roles/' % admin.pk)
......
566 564
        q = response.pyquery.remove_namespaces()
567 565
        assert len(q('table tbody tr')) == 1
568 566
        names = [elt.text for elt in q('table tbody td.name a')]
569
        assert set(names) == {u'role_ou1'}
567
        assert set(names) == {'role_ou1'}
570 568

  
571 569
        response.form.set('search-internals', True)
572 570
        response = response.form.submit()
......
619 617
        q = response.pyquery.remove_namespaces()
620 618
        assert len(q('table tbody tr')) == 1
621 619
        names = [elt.text for elt in q('table tbody td.name a')]
622
        assert set(names) == {u'Auto Admin Role'}
620
        assert set(names) == {'Auto Admin Role'}
623 621

  
624 622
        response.form.set('search-internals', True)
625 623
        response = response.form.submit()
626 624
        q = response.pyquery.remove_namespaces()
627 625
        assert len(q('table tbody tr')) == 1
628 626
        names = {elt.text for elt in q('table tbody td.name a')}
629
        assert set(names) == {u'Auto Admin Role'}
627
        assert set(names) == {'Auto Admin Role'}
630 628

  
631 629
    test_user_listing_auto_admin_role(user_with_auto_admin_role)
632 630

  
......
775 773
def test_manager_ou(app, superuser_or_admin, ou1):
776 774
    manager_home_page = login(app, superuser_or_admin, reverse('a2-manager-homepage'))
777 775
    ou_homepage = manager_home_page.click(href='organizational-units')
778
    assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set(
779
        ['OU1', 'Default organizational unit']
780
    )
776
    assert {e.text for e in ou_homepage.pyquery('td.name')} == {'OU1', 'Default organizational unit'}
781 777
    assert [x.text for x in ou_homepage.pyquery('td.slug')] == ['default', 'ou1']
782 778

  
783 779
    # add a new ou
......
786 782
    add_ou_page.form.set('default', True)
787 783
    ou_homepage = add_ou_page.form.submit().follow()
788 784
    ou2 = OU.objects.get(name='ou2')
789
    assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set(
790
        ['OU1', 'Default organizational unit', 'ou2']
791
    )
785
    assert {e.text for e in ou_homepage.pyquery('td.name')} == {'OU1', 'Default organizational unit', 'ou2'}
792 786
    assert len(ou_homepage.pyquery('tr[data-pk="%s"] td.default span.true' % ou2.pk)) == 1
793 787
    assert len(ou_homepage.pyquery('tr[data-url="%s/"] td.default span.true' % ou2.pk)) == 1
794 788

  
......
801 795
    ou1_detail_page = app.get(reverse('a2-manager-ou-detail', kwargs={'pk': ou1.pk}))
802 796
    ou1_delete_page = ou1_detail_page.click('Delete')
803 797
    ou_homepage = ou1_delete_page.form.submit().follow()
804
    assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set(
805
        ['Default organizational unit', 'ou2']
806
    )
798
    assert {e.text for e in ou_homepage.pyquery('td.name')} == {'Default organizational unit', 'ou2'}
807 799

  
808 800
    # remake old default ou the default one
809 801
    old_default = OU.objects.get(name__contains='Default')
......
816 808
    assert old_default_detail_page.pyquery('input[name="default"][checked="checked"]')
817 809
    # check ou homepage has changed too
818 810
    ou_homepage = old_default_detail_page.click('Organizational unit')
819
    assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set(
820
        ['Default organizational unit', 'ou2']
821
    )
811
    assert {e.text for e in ou_homepage.pyquery('td.name')} == {'Default organizational unit', 'ou2'}
822 812
    assert len(ou_homepage.pyquery('span.true')) == 1
823 813
    assert len(ou_homepage.pyquery('tr[data-pk="%s"] td.default span.true' % ou2.pk)) == 0
824 814
    assert len(ou_homepage.pyquery('tr[data-pk="%s"] td.default span.true' % old_default.pk)) == 1
......
844 834
    from authentic2.manager.forms import ChooseRoleForm
845 835

  
846 836
    login(app, admin, '/manage/')
847
    cassis = OU.objects.create(name=u'Cassis')
848
    la_bedoule = OU.objects.create(name=u'La Bédoule')
849
    cuges = OU.objects.create(name=u'Cuges')
850
    Role.objects.create(ou=cassis, name=u'Administrateur')
851
    Role.objects.create(ou=la_bedoule, name=u'Administrateur')
852
    Role.objects.create(ou=cuges, name=u'Administrateur')
837
    cassis = OU.objects.create(name='Cassis')
838
    la_bedoule = OU.objects.create(name='La Bédoule')
839
    cuges = OU.objects.create(name='Cuges')
840
    Role.objects.create(ou=cassis, name='Administrateur')
841
    Role.objects.create(ou=la_bedoule, name='Administrateur')
842
    Role.objects.create(ou=cuges, name='Administrateur')
853 843

  
854 844
    form = ChooseRoleForm(request=None)
855 845
    assert form.as_p()
......
869 859
    from authentic2.manager.forms import RoleParentsForm
870 860

  
871 861
    login(app, admin, '/manage/')
872
    Role.objects.create(name=u'admin 1')
873
    Role.objects.create(name=u'user 1')
862
    Role.objects.create(name='admin 1')
863
    Role.objects.create(name='user 1')
874 864

  
875 865
    form = RoleParentsForm(request=None)
876 866
    assert form.as_p()
......
914 904
    response = app.get('/manage/users/')
915 905
    q = response.pyquery.remove_namespaces()
916 906
    assert len(q('table tbody tr')) == 2
917
    assert set([e.text for e in q('table tbody td.username')]) == {'admin', 'user'}
907
    assert {e.text for e in q('table tbody td.username')} == {'admin', 'user'}
918 908

  
919 909
    # user can view administered roles
920 910
    response = app.get('/manage/roles/')
......
1086 1076
    def get_choices(response):
1087 1077
        select2_json = request_select2(app, response)
1088 1078
        assert select2_json['more'] is False
1089
        return set(result['id'] for result in select2_json['results'])
1079
        return {result['id'] for result in select2_json['results']}
1090 1080

  
1091 1081
    visible_role = Role.objects.create(name='visible_role', ou=simple_user.ou)
1092 1082
    Role.objects.create(name='invisible_role', ou=simple_user.ou)
......
1105 1095

  
1106 1096
    # all visible roles are shown
1107 1097
    response = app.get('/manage/roles/%s/add-child/' % simple_role.pk)
1108
    assert set([visible_role.pk, simple_role.pk]) == get_choices(response)
1098
    assert {visible_role.pk, simple_role.pk} == get_choices(response)
1109 1099

  
1110 1100
    # all roles with manage_members permissions are shown
1111 1101
    response = app.get('/manage/roles/%s/add-parent/' % simple_role.pk)
1112
    assert set([simple_role.pk, admin_of_simple_role.pk]) == get_choices(response)
1102
    assert {simple_role.pk, admin_of_simple_role.pk} == get_choices(response)
1113 1103

  
1114 1104
    response = app.get('/manage/roles/%s/add-parent/' % visible_role.pk)
1115
    assert set([simple_role.pk, admin_of_simple_role.pk]) == get_choices(response)
1105
    assert {simple_role.pk, admin_of_simple_role.pk} == get_choices(response)
1116 1106

  
1117 1107

  
1118 1108
def test_manager_widgets_field_id_other_user(app, admin, simple_user, simple_role):
......
1124 1114
    assert select2_json['more'] is False
1125 1115

  
1126 1116
    # admin can see every roles
1127
    assert set([simple_role.pk, other_role.pk]) == set(result['id'] for result in select2_json['results'])
1117
    assert {simple_role.pk, other_role.pk} == {result['id'] for result in select2_json['results']}
1128 1118

  
1129 1119
    login(app, simple_user)
1130 1120
    # same request from the page served for admin
tests/test_manager_journal.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import datetime
18
from unittest import mock
18 19

  
19
import mock
20 20
import pytest
21 21
from django.contrib.sessions.models import Session
22 22
from django.utils.timezone import make_aware
tests/test_manager_user_import.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import io
21 19
import operator
tests/test_models.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import pytest
21 19

  
tests/test_ou_manager.py
34 34

  
35 35
    assert list(export.keys()) == ['ous']
36 36
    assert len(export['ous']) == 3
37
    assert set([ou['slug'] for ou in export['ous']]) == set(['default', 'ou1', 'ou2'])
37
    assert {ou['slug'] for ou in export['ous']} == {'default', 'ou1', 'ou2'}
38 38

  
39 39
    response.form.set('search-text', 'ou1')
40 40
    search_response = response.form.submit()
tests/test_passwords.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import string
20 19

  
......
23 22

  
24 23

  
25 24
def test_generate_password():
26
    passwords = set(generate_password() for i in range(10))
25
    passwords = {generate_password() for i in range(10)}
27 26

  
28 27
    char_classes = [string.digits, string.ascii_lowercase, string.ascii_uppercase, string.punctuation]
29 28
    assert len(passwords) == 10
tests/test_profile.py
1
# -*- coding: utf-8 -*-
2

  
3 1
# authentic2 - versatile identity manager
4 2
# Copyright (C) 2010-2019 Entr'ouvert
5 3
#
......
16 14
# You should have received a copy of the GNU Affero General Public License
17 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 16

  
19
from __future__ import unicode_literals
20 17

  
21 18
import pytest
22 19
from django.urls import reverse
......
163 160
    )
164 161

  
165 162
    def get_fields(resp):
166
        return set(
163
        return {
167 164
            key for key in resp.form.fields.keys() if key and key not in ['csrfmiddlewaretoken', 'cancel']
168
        )
165
        }
169 166

  
170 167
    resp = app.get(url, status=200)
171
    assert get_fields(resp) == set(
172
        ['first_name', 'last_name', 'phone', 'mobile', 'city', 'zipcode', 'next_url']
173
    )
168
    assert get_fields(resp) == {'first_name', 'last_name', 'phone', 'mobile', 'city', 'zipcode', 'next_url'}
174 169

  
175 170
    resp = app.get(url + '?scope=contact', status=200)
176
    assert get_fields(resp) == set(['phone', 'mobile', 'next_url'])
171
    assert get_fields(resp) == {'phone', 'mobile', 'next_url'}
177 172

  
178 173
    resp = app.get(url + '?scope=address', status=200)
179
    assert get_fields(resp) == set(['city', 'zipcode', 'next_url'])
174
    assert get_fields(resp) == {'city', 'zipcode', 'next_url'}
180 175

  
181 176
    resp = app.get(url + '?scope=contact address', status=200)
182
    assert get_fields(resp) == set(['phone', 'mobile', 'city', 'zipcode', 'next_url'])
177
    assert get_fields(resp) == {'phone', 'mobile', 'city', 'zipcode', 'next_url'}
183 178

  
184 179
    resp = app.get(reverse('profile_edit_with_scope', kwargs={'scope': 'contact'}), status=200)
185
    assert get_fields(resp) == set(['phone', 'mobile', 'next_url'])
180
    assert get_fields(resp) == {'phone', 'mobile', 'next_url'}
186 181

  
187 182
    resp = app.get(reverse('profile_edit_with_scope', kwargs={'scope': 'address'}), status=200)
188
    assert get_fields(resp) == set(['city', 'zipcode', 'next_url'])
183
    assert get_fields(resp) == {'city', 'zipcode', 'next_url'}
189 184

  
190 185

  
191 186
def test_account_edit_locked_title(app, simple_user):
tests/test_registration.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
330 329
    # disable existing attributes
331 330
    models.Attribute.objects.update(disabled=True)
332 331

  
333
    models.Attribute.objects.create(label=u'Prénom', name='prenom', required=True, kind='string')
332
    models.Attribute.objects.create(label='Prénom', name='prenom', required=True, kind='string')
334 333
    models.Attribute.objects.create(
335
        label=u'Nom', name='nom', asked_on_registration=True, user_visible=True, kind='string'
334
        label='Nom', name='nom', asked_on_registration=True, user_visible=True, kind='string'
336 335
    )
337 336
    models.Attribute.objects.create(label='Profession', name='profession', user_editable=True, kind='string')
338 337

  
......
448 447

  
449 448
    response = app.get(activation_url, status=200)
450 449
    assert 'form' in response.context
451
    assert set(response.context['form'].fields.keys()) == set(['first_name', 'last_name'])
450
    assert set(response.context['form'].fields.keys()) == {'first_name', 'last_name'}
452 451

  
453 452
    activation_url = utils.build_activation_url(
454 453
        rf.post('/accounts/register/'),
tests/test_role_manager.py
36 36

  
37 37
    assert list(export.keys()) == ['roles']
38 38
    assert len(export['roles']) == 2
39
    assert set([role['slug'] for role in export['roles']]) == set(['role_ou1', 'role_ou2'])
39
    assert {role['slug'] for role in export['roles']} == {'role_ou1', 'role_ou2'}
40 40

  
41 41
    export_response = response.click('CSV', href='/export/')
42 42
    reader = csv.reader(
......
46 46

  
47 47
    assert rows[0] == ['name', 'slug', 'members', 'ou']
48 48
    assert len(rows) - 2 == 2  # csv header and last EOL
49
    assert set([row[1] for row in rows[1:3]]) == set(['role_ou1', 'role_ou2'])
50
    assert set([row[3] for row in rows[1:3]]) == set(['OU1', 'OU2'])
49
    assert {row[1] for row in rows[1:3]} == {'role_ou1', 'role_ou2'}
50
    assert {row[3] for row in rows[1:3]} == {'OU1', 'OU2'}
51 51

  
52 52
    response.form.set('search-text', 'role_ou1')
53 53
    search_response = response.form.submit()
tests/test_token.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from __future__ import unicode_literals
18 17

  
19 18
import pytest
20 19

  
tests/test_user_manager.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import csv
21 19
import datetime
......
44 42

  
45 43

  
46 44
def visible_users(response):
47
    return set(elt.text for elt in response.pyquery('td.username'))
45
    return {elt.text for elt in response.pyquery('td.username')}
48 46

  
49 47

  
50 48
def test_create_user(app, superuser):
......
690 688
    login(app, admin, '/manage/users/')
691 689

  
692 690
    csv_lines = [
693
        u"email key verified,first_name,last_name,more,title,bike,saintsday,birthdate,zip,phone",
694
        u"elliot@universalpictures.com,Elliott,Thomas,petit,Mr,True,2019-7-20,1972-05-26,75014,1234",
695
        u"et@universalpictures.com,ET,the Extra-Terrestrial,long,??,False,1/2/3/4,0002-2-22,42,home",
691
        "email key verified,first_name,last_name,more,title,bike,saintsday,birthdate,zip,phone",
692
        "elliot@universalpictures.com,Elliott,Thomas,petit,Mr,True,2019-7-20,1972-05-26,75014,1234",
693
        "et@universalpictures.com,ET,the Extra-Terrestrial,long,??,False,1/2/3/4,0002-2-22,42,home",
696 694
    ]
697 695
    response = import_csv('\n'.join(csv_lines), app)
698 696
    urls = re.findall('<a href="(/manage/users/import/[^/]+/[^/]+/)">', response.text)
......
713 711
    assert elliot.attributes.values['zip'].content == '75014'
714 712
    assert elliot.attributes.values['phone'].content == '1234'
715 713

  
716
    csv_lines[2] = u"et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+888 5678"
714
    csv_lines[2] = "et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+888 5678"
717 715
    response = import_csv('\n'.join(csv_lines), app)
718 716
    assert '0 rows have errors' in response.text
719 717

  
......
729 727

  
730 728

  
731 729
def test_detail_view(app, admin, simple_user):
732
    url = '/manage/users/{user.pk}/'.format(user=simple_user)
730
    url = f'/manage/users/{simple_user.pk}/'
733 731
    login(app, admin, url)
734 732

  
735 733

  
736 734
def test_detail_view_user_deleted(app, admin, simple_user):
737
    url = '/manage/users/{user.pk}/'.format(user=simple_user)
735
    url = f'/manage/users/{simple_user.pk}/'
738 736
    login(app, admin, url)
739 737
    simple_user.delete()
740 738
    app.get(url, status=404)
......
902 900

  
903 901

  
904 902
def test_ou_hide_username(admin, app, db):
905
    some_ou = OU.objects.create(name=u'Some Ou', show_username=False)
903
    some_ou = OU.objects.create(name='Some Ou', show_username=False)
906 904

  
907 905
    login(app, admin, '/manage/')
908 906
    url = '/manage/users/%s/add/' % some_ou.pk
tests/test_validators.py
1
# -*- coding: utf-8 -*-
2 1
# authentic2 - versatile identity manager
3 2
# Copyright (C) 2010-2019 Entr'ouvert
4 3
#
......
15 14
# You should have received a copy of the GNU Affero General Public License
16 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 16

  
18
from __future__ import unicode_literals
19 17

  
20 18
import smtplib
19
from unittest import mock
21 20

  
22
import mock
23 21
import pytest
24 22
from django.core.exceptions import ValidationError
25 23

  
tests_rbac/test_rbac.py
127 127
    Permission = utils.get_permission_model()
128 128
    User = get_user_model()
129 129
    OU = utils.get_ou_model()
130
    ou1 = OU.objects.create(name=u'ou1', slug=u'ou1')
131
    ou2 = OU.objects.create(name=u'ou2', slug=u'ou2')
130
    ou1 = OU.objects.create(name='ou1', slug='ou1')
131
    ou2 = OU.objects.create(name='ou2', slug='ou2')
132 132
    user1 = User.objects.create(username='john.doe')
133 133
    Role = utils.get_role_model()
134 134
    ct_ct = ContentType.objects.get_for_model(ContentType)
......
154 154
    rbac_backend = backends.DjangoRBACBackend()
155 155
    ctx = CaptureQueriesContext(connection)
156 156
    with ctx:
157
        assert rbac_backend.get_all_permissions(user1) == set(
158
            ['django_rbac.change_role', 'django_rbac.search_role', 'django_rbac.view_role']
159
        )
160
        assert rbac_backend.get_all_permissions(user1, obj=role1) == set(
161
            [
162
                'django_rbac.delete_role',
163
                'django_rbac.change_role',
164
                'django_rbac.search_role',
165
                'django_rbac.view_role',
166
            ]
167
        )
168
        assert rbac_backend.get_all_permissions(user1, obj=role2) == set(
169
            [
170
                'django_rbac.change_role',
171
                'django_rbac.view_role',
172
                'django_rbac.search_role',
173
                'django_rbac.add_role',
174
            ]
175
        )
157
        assert rbac_backend.get_all_permissions(user1) == {
158
            'django_rbac.change_role',
159
            'django_rbac.search_role',
160
            'django_rbac.view_role',
161
        }
162
        assert rbac_backend.get_all_permissions(user1, obj=role1) == {
163
            'django_rbac.delete_role',
164
            'django_rbac.change_role',
165
            'django_rbac.search_role',
166
            'django_rbac.view_role',
167
        }
168
        assert rbac_backend.get_all_permissions(user1, obj=role2) == {
169
            'django_rbac.change_role',
170
            'django_rbac.view_role',
171
            'django_rbac.search_role',
172
            'django_rbac.add_role',
173
        }
176 174
        assert not rbac_backend.has_perm(user1, 'django_rbac.delete_role', obj=role2)
177 175
        assert rbac_backend.has_perm(user1, 'django_rbac.delete_role', obj=role1)
178 176
        assert rbac_backend.has_perms(
......
181 179
        assert rbac_backend.has_module_perms(user1, 'django_rbac')
182 180
        assert not rbac_backend.has_module_perms(user1, 'contenttypes')
183 181
    assert len(ctx.captured_queries) == 1
184
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.add_role', Role.objects.all())) == set([role2])
185
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.delete_role', Role.objects.all())) == set(
186
        [role1]
187
    )
182
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.add_role', Role.objects.all())) == {role2}
183
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.delete_role', Role.objects.all())) == {role1}
188 184
    assert set(
189 185
        rbac_backend.filter_by_perm(
190 186
            user1, ['django_rbac.delete_role', 'django_rbac.add_role'], Role.objects.all()
191 187
        )
192
    ) == set([role1, role2])
193
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.view_role', Role.objects.all())) == set(
194
        [role1, role2]
195
    )
196
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.change_role', Role.objects.all())) == set(
197
        [role1, role2]
198
    )
188
    ) == {role1, role2}
189
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.view_role', Role.objects.all())) == {
190
        role1,
191
        role2,
192
    }
193
    assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.change_role', Role.objects.all())) == {
194
        role1,
195
        role2,
196
    }
199 197

  
200 198
    # Test admin op as a generalization of other ops
201 199
    user2 = User.objects.create(username='donald.knuth')
......
203 201
    role3.members.add(user2)
204 202
    perm5 = Permission.objects.create(operation=admin_op, target_ct=ct_ct, target_id=role_ct.pk)
205 203
    role3.permissions.add(perm5)
206
    assert rbac_backend.get_all_permissions(user2) == set(
207
        [
208
            'django_rbac.add_role',
209
            'django_rbac.change_role',
210
            'django_rbac.search_role',
211
            'django_rbac.admin_role',
212
            'django_rbac.view_role',
213
            'django_rbac.delete_role',
214
        ]
215
    )
204
    assert rbac_backend.get_all_permissions(user2) == {
205
        'django_rbac.add_role',
206
        'django_rbac.change_role',
207
        'django_rbac.search_role',
208
        'django_rbac.admin_role',
209
        'django_rbac.view_role',
210
        'django_rbac.delete_role',
211
    }
216 212

  
217 213
    # test ous_with_perm
218
    assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.add_role')) == set([ou1])
219
    assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.view_role')) == set([ou1, ou2])
220
    assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.delete_role')) == set([])
214
    assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.add_role')) == {ou1}
215
    assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.view_role')) == {ou1, ou2}
216
    assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.delete_role')) == set()
221 217

  
222 218

  
223 219
def test_all_members(db):
224
-