From c42930bf9715d40d0433563a9188f975ce5ee5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Fernanda=20Magallanes?= <35668326+MaferMazu@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:48:33 -0500 Subject: [PATCH] perf: add Quince support DS-776 (#196) BREAKING CHANGE: add compatibility with quince * chore: update github workflows and tests * chore: update requirements and remove constraints * fix: add get_reponse to the test middlewares * fix: some pylint errors * fix: remove too-few-public-methods alert and fix f-strings * fix: restore old format in the get_configurations * fix: restore the logs to %s format * fix: pylint tests * fix: remove the test in python 310 and 11 for backports-zoneinfo * docs: update doc --- .github/workflows/bump_version.yml | 12 +- .github/workflows/commitlint.yml | 2 +- .github/workflows/python-publish.yml | 6 +- .github/workflows/tests.yml | 6 +- Makefile | 2 +- README.rst | 2 + eox_tenant/admin.py | 12 +- eox_tenant/api/v1/tests/test_microsites.py | 2 +- eox_tenant/api/v1/tests/test_routes.py | 2 +- eox_tenant/api/v1/tests/test_tenant_config.py | 2 +- eox_tenant/async_utils.py | 2 +- .../backends/branding_api_l_v1.py | 2 +- .../management/commands/change_domain.py | 2 +- .../commands/change_signup_sources.py | 2 +- .../create_or_update_tenant_config.py | 45 +-- .../commands/edit_microsite_values.py | 6 +- .../commands/synchronize_organizations.py | 8 +- eox_tenant/middleware.py | 2 + eox_tenant/models.py | 2 +- eox_tenant/pipeline.py | 19 +- eox_tenant/settings/production.py | 2 +- eox_tenant/settings/test.py | 7 +- eox_tenant/signals.py | 2 +- eox_tenant/templatetags/ednx.py | 16 +- eox_tenant/tenant_wise/proxies.py | 8 +- eox_tenant/test/test_async_utils.py | 4 +- eox_tenant/test/test_middleware.py | 7 +- eox_tenant/test/test_pipeline.py | 1 + eox_tenant/test/test_signals.py | 8 +- eox_tenant/test_utils.py | 2 +- eox_tenant/utils.py | 6 +- requirements/base.txt | 56 ++-- requirements/constraints.txt | 18 +- requirements/{django.txt => django32.txt} | 0 requirements/django42.txt | 1 + requirements/pip-tools.txt | 4 +- requirements/test.txt | 106 +++---- requirements/tox.txt | 10 +- setup.cfg | 276 +----------------- setup.py | 2 +- tox.ini | 7 +- 41 files changed, 179 insertions(+), 502 deletions(-) rename requirements/{django.txt => django32.txt} (100%) create mode 100644 requirements/django42.txt diff --git a/.github/workflows/bump_version.yml b/.github/workflows/bump_version.yml index 3392c867..88c304d9 100644 --- a/.github/workflows/bump_version.yml +++ b/.github/workflows/bump_version.yml @@ -11,7 +11,7 @@ jobs: previous_tag: ${{ steps.tag_version.outputs.previous_tag }} bump_commit_sha: ${{ steps.bumpversion.outputs.commit_hash }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: token: ${{ secrets.DEDALO_PAT }} - name: Get next version @@ -23,7 +23,7 @@ jobs: default_prerelease_bump: false dry_run: true - name: Set up Python 3.8 - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v5 with: python-version: "3.8" - name: Create bumpversion @@ -33,14 +33,14 @@ jobs: bumpversion --new-version ${{ steps.tag_version.outputs.new_version }} setup.cfg - name: Update Changelog if: steps.tag_version.outputs.new_version - uses: stefanzweifel/changelog-updater-action@v1.6.2 + uses: stefanzweifel/changelog-updater-action@v1.10.0 with: latest-version: ${{ steps.tag_version.outputs.new_tag }} release-notes: ${{ steps.tag_version.outputs.changelog }} - name: Commit bumpversion id: bumpversion if: steps.tag_version.outputs.new_version - uses: stefanzweifel/git-auto-commit-action@v4.16.0 + uses: stefanzweifel/git-auto-commit-action@v5 with: branch: ${{ github.ref }} commit_message: "docs(bumpversion): ${{ steps.tag_version.outputs.previous_tag }} → ${{ steps.tag_version.outputs.new_version }}" @@ -53,7 +53,7 @@ jobs: tag: ${{ steps.tag_version.outputs.new_tag }} changelog: ${{ steps.tag_version.outputs.changelog }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: token: ${{ secrets.DEDALO_PAT }} - name: Create tag @@ -66,7 +66,7 @@ jobs: default_prerelease_bump: false - name: Create a GitHub release if: steps.tag_version.outputs.new_tag - uses: ncipollo/release-action@v1.12.0 + uses: ncipollo/release-action@v1.14.0 with: tag: ${{ steps.tag_version.outputs.new_tag }} name: Release ${{ steps.tag_version.outputs.new_tag }} diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index 5fcfeaea..85484a4b 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -5,7 +5,7 @@ jobs: commitlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: wagoid/commitlint-github-action@v4 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 7105f680..c1763ec6 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v5 with: python-version: '3.10' - name: Install dependencies @@ -34,7 +34,7 @@ jobs: run: | python -m build --sdist --wheel --outdir dist/ . - name: Publish package - uses: pypa/gh-action-pypi-publish@v1.6.4 + uses: pypa/gh-action-pypi-publish@v1.8.11 with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 40dec21b..8073790a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,11 +12,11 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: ["3.8", "3.10", "3.11"] - django: ["32"] + python-version: ["3.8"] + django: ["32", "42"] steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache dependency uses: actions/cache@v3.2.3 diff --git a/Makefile b/Makefile index 41c4e3c4..4e4b65eb 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ upgrade: ## update the requirements/*.txt files with the latest packages satisfy $(PIP_COMPILE) -o requirements/test.txt requirements/test.in $(PIP_COMPILE) -o requirements/tox.txt requirements/tox.in - grep -e "^django==" requirements/test.txt > requirements/django.txt + grep -e "^django==" requirements/test.txt > requirements/django42.txt sed '/^[dD]jango==/d;' requirements/test.txt > requirements/test.tmp mv requirements/test.tmp requirements/test.txt diff --git a/README.rst b/README.rst index 338ab832..a11ef856 100644 --- a/README.rst +++ b/README.rst @@ -33,6 +33,8 @@ Compatibility Notes +-------------------+-----------------------+ | Palm | >=v10.0.0 | +-------------------+-----------------------+ +| Quince | >=v11.0.0 | ++-------------------+-----------------------+ **NOTE**: Since 6.2 version, eox-tenant does not support Django 2.2 diff --git a/eox_tenant/admin.py b/eox_tenant/admin.py index 88c6fa7a..bc77b18a 100644 --- a/eox_tenant/admin.py +++ b/eox_tenant/admin.py @@ -180,8 +180,8 @@ def config_link(self, route): Helper method to display a link to the related config model. """ # pylint: disable=protected-access - url = reverse('admin:%s_%s_change' % (route._meta.app_label, "tenantconfig"), args=[route.config.id]) - return mark_safe('%s' % (url, route.config.__unicode__())) + url = reverse(f'admin:{route._meta.app_label}_tenantconfig_change', args=[route.config.id]) + return mark_safe(f'{route.config.__unicode__()}') config_link.allow_tags = True config_link.short_description = "Configuration" @@ -224,10 +224,10 @@ def microsites(self, org): for microsite in microsites: url = reverse( - 'admin:%s_%s_change' % (microsite._meta.app_label, "microsite"), # pylint: disable=protected-access + f'admin:{microsite._meta.app_label}_microsite_change', # pylint: disable=protected-access args=[microsite.id], ) - domains.append('%s' % (url, microsite.subdomain)) + domains.append(f'{microsite.subdomain}') return mark_safe('\n'.join(domains)) @@ -245,10 +245,10 @@ def tenants(self, org): for tenant in tenants: url = reverse( - 'admin:%s_%s_change' % (tenant._meta.app_label, "tenantconfig"), # pylint: disable=protected-access + f'admin:{tenant._meta.app_label}_tenantconfig_change', # pylint: disable=protected-access args=[tenant.id], ) - domains += ['%s' % (url, route.domain) for route in tenant.route_set.all()] + domains += [f'{route.domain}' for route in tenant.route_set.all()] return mark_safe('\n'.join(domains)) diff --git a/eox_tenant/api/v1/tests/test_microsites.py b/eox_tenant/api/v1/tests/test_microsites.py index 7f3f969d..086a5b1f 100644 --- a/eox_tenant/api/v1/tests/test_microsites.py +++ b/eox_tenant/api/v1/tests/test_microsites.py @@ -27,7 +27,7 @@ def setUp(self): subdomain='test.host', values={'key': 'value'}, ) - self.url_detail = '{url}{id}/'.format(url=self.url, id=self.microsite_example.pk) + self.url_detail = f'{self.url}{self.microsite_example.pk}/' @patch_permissions def test_get_microsites(self, _): diff --git a/eox_tenant/api/v1/tests/test_routes.py b/eox_tenant/api/v1/tests/test_routes.py index 77d7606e..06474caf 100644 --- a/eox_tenant/api/v1/tests/test_routes.py +++ b/eox_tenant/api/v1/tests/test_routes.py @@ -33,7 +33,7 @@ def setUp(self): domain='domain.host', config=self.tenant_config, ) - self.url_detail = '{url}{id}/'.format(url=self.url, id=self.route_example.pk) + self.url_detail = f'{self.url}{self.route_example.pk}/' @patch_permissions def test_get_routes(self, _): diff --git a/eox_tenant/api/v1/tests/test_tenant_config.py b/eox_tenant/api/v1/tests/test_tenant_config.py index 90b173de..914e9e32 100644 --- a/eox_tenant/api/v1/tests/test_tenant_config.py +++ b/eox_tenant/api/v1/tests/test_tenant_config.py @@ -31,7 +31,7 @@ def setUp(self): theming_configs={'key': 'value'}, meta={'key': 'value'}, ) - self.url_detail = '{url}{id}/'.format(url=self.url, id=self.tenant_config_example.pk) + self.url_detail = f'{self.url}{self.tenant_config_example.pk}/' @patch_permissions def test_get_tenant_configs(self, _): diff --git a/eox_tenant/async_utils.py b/eox_tenant/async_utils.py index 8be1c880..55fcf702 100644 --- a/eox_tenant/async_utils.py +++ b/eox_tenant/async_utils.py @@ -56,7 +56,7 @@ def tenant_from_sync_process(self): if not host: LOG.warning( "Could not find the host information for eox_tenant.signals " - "for the task {sender}".format(sender=self.sender) + "for the task %s", self.sender ) def get_host(_body): diff --git a/eox_tenant/edxapp_wrapper/backends/branding_api_l_v1.py b/eox_tenant/edxapp_wrapper/backends/branding_api_l_v1.py index 9e9333f6..75a3a54d 100644 --- a/eox_tenant/edxapp_wrapper/backends/branding_api_l_v1.py +++ b/eox_tenant/edxapp_wrapper/backends/branding_api_l_v1.py @@ -2,7 +2,7 @@ try: from lms.djangoapps.branding import api as branding_api except ImportError: - branding_api = object + branding_api = object # pylint: disable=invalid-name def get_branding_api(): diff --git a/eox_tenant/management/commands/change_domain.py b/eox_tenant/management/commands/change_domain.py index 703d39cd..4fb15640 100644 --- a/eox_tenant/management/commands/change_domain.py +++ b/eox_tenant/management/commands/change_domain.py @@ -32,7 +32,7 @@ class Command(BaseCommand): This function will iterate over all microsites objects to change microsite prod domains to a stage versions. Usage Example: - python manage.py lms change_domain ".i.stage.ednx.co" ".i.ecom.ednx.co" --signupsources --settings=production + python manage.py lms change_domain ".i.stage.ednx.co" ".i.ecom.ednx.co" --signupsources """ suffix_stage_domain = "" suffix_stage_ecommerce_domain = "" diff --git a/eox_tenant/management/commands/change_signup_sources.py b/eox_tenant/management/commands/change_signup_sources.py index f7406904..70475380 100644 --- a/eox_tenant/management/commands/change_signup_sources.py +++ b/eox_tenant/management/commands/change_signup_sources.py @@ -17,7 +17,7 @@ class Command(BaseCommand): signupsources of a given domain with another domain. Usage Example: - python manage.py lms change_signup_sources --from old.edunext.io --to new.edunext.io --settings=production + python manage.py lms change_signup_sources --from old.edunext.io --to new.edunext.io """ def add_arguments(self, parser): diff --git a/eox_tenant/management/commands/create_or_update_tenant_config.py b/eox_tenant/management/commands/create_or_update_tenant_config.py index 47490247..bd000010 100644 --- a/eox_tenant/management/commands/create_or_update_tenant_config.py +++ b/eox_tenant/management/commands/create_or_update_tenant_config.py @@ -88,30 +88,30 @@ def merge_dict(self, base_dict, override): return override - def handle(self, *args, **options): + def handle(self, *args, **options): # pylint: disable=too-many-branches """ Create or update TenantConfig and link related routes. """ - external_key = options['external_key'] - routes = options['routes'] - configuration = options.get('config') - config_file_data = options.get('config_file_data') - tenant_configuration_values = configuration or config_file_data - override = options.get('override') + data = { + "external_key": options['external_key'], + "routes": options['routes'], + "tenant_configuration_values": options.get('config') or options.get('config_file_data'), + "override": options.get('override'), + } # pylint: disable=no-member,protected-access external_key_length = TenantConfig._meta.get_field("external_key").max_length - if external_key: - if len(str(external_key)) > external_key_length: + if data["external_key"]: + if len(str(data["external_key"])) > external_key_length: LOG.warning( "The external_key %s is too long, truncating to %s" " characters. Please update external_key in admin.", - external_key, + data["external_key"], external_key_length ) # trim name as the column has a limit of 63 characters - external_key = external_key[:external_key_length] + data["external_key"] = data["external_key"][:external_key_length] tenant, created = TenantConfig.objects.get_or_create( - external_key=external_key, + external_key=data["external_key"], ) if created: LOG.info("Tenant does not exist. Created new tenant: '%s'", tenant.external_key) @@ -119,22 +119,23 @@ def handle(self, *args, **options): LOG.info("Found existing tenant for: '%s'", tenant.external_key) # split out lms, studio, theme, meta from configuration json - if tenant_configuration_values: + if data["tenant_configuration_values"]: for field in TenantConfig._meta.get_fields(): if isinstance(field, JSONField): name = field.name - value = tenant_configuration_values.get(name) - if value is not None: - if override: - setattr(tenant, name, value) - else: - base_value = getattr(tenant, name, {}) - merged = self.merge_dict(base_value, value) - setattr(tenant, name, merged) + value = data["tenant_configuration_values"].get(name) + if not value: + continue + if data["override"]: + setattr(tenant, name, value) + else: + base_value = getattr(tenant, name, {}) + merged = self.merge_dict(base_value, value) + setattr(tenant, name, merged) tenant.save() # next add routes and link them - for route in routes: + for route in data["routes"]: route, created = Route.objects.update_or_create( domain=route, defaults={"config": tenant} diff --git a/eox_tenant/management/commands/edit_microsite_values.py b/eox_tenant/management/commands/edit_microsite_values.py index f9da4131..76637ca9 100644 --- a/eox_tenant/management/commands/edit_microsite_values.py +++ b/eox_tenant/management/commands/edit_microsite_values.py @@ -101,7 +101,7 @@ def handle(self, *args, **options): LOGGER.info("This command will affect the following sites:") for tenant in query: - LOGGER.info("{} on: {}".format(tenant, tenant.subdomain)) + LOGGER.info("%s on: %s", tenant, tenant.subdomain) if not options['force']: user_response = input("Continue? y/n: ") @@ -134,7 +134,7 @@ def action_delete(self, tenant, keys): tenant.save() except KeyError: - LOGGER.info("Could not find key: {} on site {}".format(key, tenant)) + LOGGER.info("Could not find key: %s on site %s", key, tenant) def action_add(self, tenant, key, value): """ @@ -158,4 +158,4 @@ def action_add(self, tenant, key, value): tenant.save() except Exception: # pylint: disable=broad-except - LOGGER.info("Could not add key {} to site {}".format(key, tenant)) + LOGGER.info("Could not add key %s to site %s", key, tenant) diff --git a/eox_tenant/management/commands/synchronize_organizations.py b/eox_tenant/management/commands/synchronize_organizations.py index a553a107..cdd1710e 100644 --- a/eox_tenant/management/commands/synchronize_organizations.py +++ b/eox_tenant/management/commands/synchronize_organizations.py @@ -52,10 +52,10 @@ def handle(self, *args, **options): model = getattr(models, valid_model) queryset = model.objects.all() - LOGGER.info("Synchronize {} {} registers.".format( - len(queryset), - valid_model, - )) + LOGGER.info("Synchronize %s %s registers.", + len(queryset), + valid_model, + ) for instance in queryset: synchronize_tenant_organizations(instance) diff --git a/eox_tenant/middleware.py b/eox_tenant/middleware.py index 8bb8a00a..db6492b5 100644 --- a/eox_tenant/middleware.py +++ b/eox_tenant/middleware.py @@ -95,6 +95,8 @@ def process_request(self, request): ) ) + return None + class CurrentSiteMiddleware(MiddlewareMixin): """ diff --git a/eox_tenant/models.py b/eox_tenant/models.py index 551baeb6..fc663a0f 100644 --- a/eox_tenant/models.py +++ b/eox_tenant/models.py @@ -30,7 +30,7 @@ class Meta: app_label = "eox_tenant" def __str__(self): - return "".format(self.name) + return f"" class Microsite(models.Model): diff --git a/eox_tenant/pipeline.py b/eox_tenant/pipeline.py index 6b9ec6db..5efc3214 100644 --- a/eox_tenant/pipeline.py +++ b/eox_tenant/pipeline.py @@ -32,16 +32,17 @@ def safer_associate_by_email(backend, details, user=None, *args, **kwargs): users = list(backend.strategy.storage.user.get_users_by_email(email)) if not users: return None - elif len(users) > 1: + if len(users) > 1: raise EoxTenantAuthException( backend, 'The given email address is associated with another account' ) - else: - if users[0].is_staff or users[0].is_superuser: - raise EoxTenantAuthException( - backend, - 'It is not allowed to auto associate staff or admin users' - ) - return {'user': users[0], - 'is_new': False} + if users[0].is_staff or users[0].is_superuser: + raise EoxTenantAuthException( + backend, + 'It is not allowed to auto associate staff or admin users' + ) + return {'user': users[0], + 'is_new': False} + + return None diff --git a/eox_tenant/settings/production.py b/eox_tenant/settings/production.py index 924ffb12..2a8ba181 100644 --- a/eox_tenant/settings/production.py +++ b/eox_tenant/settings/production.py @@ -2,7 +2,7 @@ Settings for eox_tenant project meant to be called on the edx-platform/*/envs/production.py module """ -from .common import * # pylint: disable=wildcard-import +from .common import * # pylint: disable=wildcard-import,unused-wildcard-import EDX_AUTH_BACKEND = \ 'openedx.core.djangoapps.oauth_dispatch.dot_overrides.backends.EdxRateLimitedAllowAllUsersModelBackend' diff --git a/eox_tenant/settings/test.py b/eox_tenant/settings/test.py index 61771c7b..b4a9f1f5 100644 --- a/eox_tenant/settings/test.py +++ b/eox_tenant/settings/test.py @@ -3,7 +3,7 @@ """ from __future__ import absolute_import, unicode_literals -from .common import * # pylint: disable=wildcard-import +from .common import * # pylint: disable=wildcard-import,unused-wildcard-import class SettingsClass: @@ -87,7 +87,6 @@ def plugin_settings(settings): # pylint: disable=function-redefined settings.EOX_TENANT_SKIP_FILTER_FOR_TESTS = True settings.EOX_TENANT_LOAD_PERMISSIONS = False if hasattr(settings, 'OAUTH2_PROVIDER'): - settings.OAUTH2_PROVIDER['OAUTH2_VALIDATOR_CLASS'] = '{oauth_path}.{validator_path}'.format( - oauth_path='openedx.core.djangoapps', - validator_path='oauth_dispatch.dot_overrides.validators.EdxOAuth2Validator' + settings.OAUTH2_PROVIDER['OAUTH2_VALIDATOR_CLASS'] = ( + 'openedx.core.djangoapps.oauth_dispatch.dot_overrides.validators.EdxOAuth2Validator' ) diff --git a/eox_tenant/signals.py b/eox_tenant/signals.py index 40db51fd..c53bb670 100644 --- a/eox_tenant/signals.py +++ b/eox_tenant/signals.py @@ -22,7 +22,7 @@ import logging from datetime import datetime -from os import getpid # pylint: disable=no-name-in-module +from os import getpid import six from django.apps.config import AppConfig diff --git a/eox_tenant/templatetags/ednx.py b/eox_tenant/templatetags/ednx.py index be966878..2ddbd98f 100644 --- a/eox_tenant/templatetags/ednx.py +++ b/eox_tenant/templatetags/ednx.py @@ -52,9 +52,9 @@ def microsite_css_overrides_file(): file_path = configuration_helpers.get_value('css_overrides_file') if file_path is not None: - return "".format(static(file_path)) - else: - return "" + return f"" + + return "" @register.simple_tag(name="microsite_rtl") @@ -178,8 +178,8 @@ def get_login_link(): """ if settings.FEATURES.get('ednx_custom_login_link'): return settings.FEATURES.get('ednx_custom_login_link') - else: - return get_lms_root_url() + "/login" + + return get_lms_root_url() + "/login" @register.simple_tag(name="tenant_css_overrides_file") @@ -197,9 +197,9 @@ def tenant_css_overrides_file(): file_path = configuration_helpers.get_value('css_overrides_file') if file_path is not None: - return "".format(static(file_path)) - else: - return "" + return f"" + + return "" @register.simple_tag(name="tenant_rtl") diff --git a/eox_tenant/tenant_wise/proxies.py b/eox_tenant/tenant_wise/proxies.py index 9ee036ce..4195d440 100644 --- a/eox_tenant/tenant_wise/proxies.py +++ b/eox_tenant/tenant_wise/proxies.py @@ -40,7 +40,7 @@ class Meta: def __str__(self): key = getattr(settings, "EDNX_TENANT_KEY", "No tenant is active at the moment") - return "".format(key) + return f"" @property def enabled(self): @@ -147,7 +147,7 @@ def __get_value_for_org(cls, org, val_name, default=None): Optimized method, that returns a value for the given org and val_name, from the TenantConfig or Microsite model. """ - cache_key = "org-value-{}-{}".format(org, val_name) + cache_key = f"org-value-{org}-{val_name}" cached_value = cache.get(cache_key) if cached_value: @@ -170,7 +170,7 @@ def pre_load_values_by_org(cls, val_name): """ Save in cache the values for all the organizations in TenantConfig and Microsite models. """ - pre_load_value_key = "eox-tenant-pre-load-{}-key".format(val_name) + pre_load_value_key = f"eox-tenant-pre-load-{val_name}-key" if cache.get(pre_load_value_key): return @@ -192,7 +192,7 @@ def pre_load_values_by_org(cls, val_name): org_filter = [org_filter] for org in org_filter: - key = "org-value-{}-{}".format(org, val_name) + key = f"org-value-{org}-{val_name}" cls.set_key_to_cache(key, result) cls.set_key_to_cache(pre_load_value_key, True) diff --git a/eox_tenant/test/test_async_utils.py b/eox_tenant/test/test_async_utils.py index 29603f5f..b770934d 100644 --- a/eox_tenant/test/test_async_utils.py +++ b/eox_tenant/test/test_async_utils.py @@ -18,8 +18,8 @@ def setUp(self): """ setup """ for number in range(3): Site.objects.create( - domain="tenant{number}.com".format(number=number), - name="tenant{number}.com".format(number=number) + domain=f"tenant{number}.com", + name=f"tenant{number}.com" ) def test_get_host_from_siteid(self): diff --git a/eox_tenant/test/test_middleware.py b/eox_tenant/test/test_middleware.py index 1eba06f7..9f71d9b3 100644 --- a/eox_tenant/test/test_middleware.py +++ b/eox_tenant/test/test_middleware.py @@ -35,7 +35,7 @@ class MicrositeCrossBrandingFilterMiddlewareTest(TestCase): def setUp(self): """ setup """ self.request_factory = RequestFactory() - self.middleware_instance = MicrositeCrossBrandingFilterMiddleware() + self.middleware_instance = MicrositeCrossBrandingFilterMiddleware(get_response=lambda req: None) def test_no_url_courses_match(self): """ @@ -110,10 +110,11 @@ class AvailableScreenMiddlewareTest(TestCase): """ Testing the middleware AvailableScreenMiddleware """ + def setUp(self): """ setup """ self.request_factory = RequestFactory() - self.middleware_instance = AvailableScreenMiddleware() + self.middleware_instance = AvailableScreenMiddleware(get_response=lambda req: None) @mock.patch('eox_tenant.middleware.theming_helper') @mock.patch('eox_tenant.middleware.HttpResponseNotFound') @@ -160,7 +161,7 @@ class CurrentSiteMiddlewareTest(TestCase): def setUp(self): """ Setup. """ self.request_factory = RequestFactory(SERVER_NAME='test-domain.com') - self.middleware_instance = CurrentSiteMiddleware() + self.middleware_instance = CurrentSiteMiddleware(get_response=lambda req: None) Site.objects.create( domain='test-domain.com', diff --git a/eox_tenant/test/test_pipeline.py b/eox_tenant/test/test_pipeline.py index 673c2787..0535a273 100644 --- a/eox_tenant/test/test_pipeline.py +++ b/eox_tenant/test/test_pipeline.py @@ -12,6 +12,7 @@ class AssociationByEmailTest(TestCase): """ Test the custom association backend. """ + def setUp(self): self.backend_mock = MagicMock() self.user_mock = MagicMock() diff --git a/eox_tenant/test/test_signals.py b/eox_tenant/test/test_signals.py index 8c4dd3ff..820bd792 100644 --- a/eox_tenant/test/test_signals.py +++ b/eox_tenant/test/test_signals.py @@ -290,8 +290,8 @@ def setUp(self): } for number in range(3): Site.objects.create( - domain="tenant{number}.com".format(number=number), - name="tenant{number}.com".format(number=number) + domain=f"tenant{number}.com", + name=f"tenant{number}.com" ) def test_unknown_task(self): @@ -330,8 +330,8 @@ def setUp(self): """ setup """ for number in range(3): Site.objects.create( - domain="tenant{number}.com".format(number=number), - name="tenant{number}.com".format(number=number) + domain=f"tenant{number}.com", + name=f"tenant{number}.com" ) def test_sync_process_with_tenant(self): diff --git a/eox_tenant/test_utils.py b/eox_tenant/test_utils.py index 95516fde..dc11334d 100644 --- a/eox_tenant/test_utils.py +++ b/eox_tenant/test_utils.py @@ -3,7 +3,7 @@ """ -class test_theming_helpers: +class test_theming_helpers: # pylint: disable=invalid-name """ Test class for theming helpers """ diff --git a/eox_tenant/utils.py b/eox_tenant/utils.py index 4259cf73..bff85b3c 100644 --- a/eox_tenant/utils.py +++ b/eox_tenant/utils.py @@ -63,7 +63,7 @@ def is_valid_domain(domain): try: return domain_pattern.match(domain) except (UnicodeError, AttributeError): - log.error("{} is not a valid domain.".format(domain)) + log.error("%s is not a valid domain.", domain) return False @@ -74,10 +74,10 @@ def move_signupsource(old_domain, new_domain): if is_valid_domain(old_domain) and is_valid_domain(new_domain): - log.info("Changing SignupSources from {} to {}.".format(old_domain, new_domain)) + log.info("Changing SignupSources from %s to %s.", old_domain, new_domain) count = UserSignupSource.objects.filter(site=old_domain).update(site=new_domain) - log.info("Updated {} SignupSources from {} to {}.".format(count, old_domain, new_domain)) + log.info("Updated %s SignupSources from %s to %s.", count, old_domain, new_domain) def synchronize_tenant_organizations(instance): diff --git a/requirements/base.txt b/requirements/base.txt index f3e88ef7..458b9bf4 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -6,7 +6,9 @@ # asgiref==3.7.2 # via django -django==3.2.23 +backports-zoneinfo==0.2.1 + # via django +django==4.2.10 # via # -c requirements/constraints.txt # -r requirements/base.in @@ -16,46 +18,30 @@ django==3.2.23 # jsonfield # openedx-filters django-crum==0.7.9 - # via - # -c requirements/constraints.txt - # -r requirements/base.in -django-mysql==4.7.1 - # via - # -c requirements/constraints.txt - # -r requirements/base.in -djangorestframework==3.13.1 - # via - # -c requirements/constraints.txt - # -r requirements/base.in -edx-opaque-keys[django]==2.3.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.in + # via -r requirements/base.in +django-mysql==4.12.0 + # via -r requirements/base.in +djangorestframework==3.14.0 + # via -r requirements/base.in +edx-opaque-keys[django]==2.5.1 + # via -r requirements/base.in jsonfield==3.1.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.in -openedx-filters==1.2.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.in + # via -r requirements/base.in +openedx-filters==1.6.0 + # via -r requirements/base.in pbr==6.0.0 # via stevedore pymongo==3.13.0 - # via - # -c requirements/constraints.txt - # edx-opaque-keys -pytz==2023.3.post1 - # via - # django - # djangorestframework + # via edx-opaque-keys +pytz==2024.1 + # via djangorestframework six==1.16.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.in + # via -r requirements/base.in sqlparse==0.4.4 # via django stevedore==5.1.0 # via edx-opaque-keys -typing-extensions==4.8.0 - # via asgiref +typing-extensions==4.9.0 + # via + # asgiref + # edx-opaque-keys diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 887ec335..0f023b86 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -8,20 +8,4 @@ # pin when possible. Writing an issue against the offending project and # linking to it here is good. -Django<4.0 -pymongo<4.0.0 -coverage[toml]==6.5.0 -ddt==1.6.0 -six==1.16.0 -edx-opaque-keys==2.3.0 -django-crum==0.7.9 -django-fake-model==0.1.4 -django-mysql==4.9.0 -djangorestframework==3.13.1 -jsonfield==3.1.0 -mock<5.0.3 -path-py==12.5.0 -pycodestyle<2.9.0 -pylint<3.0.0 -testfixtures==7.0.0 -openedx_filters==1.2.0 +Django<5 diff --git a/requirements/django.txt b/requirements/django32.txt similarity index 100% rename from requirements/django.txt rename to requirements/django32.txt diff --git a/requirements/django42.txt b/requirements/django42.txt new file mode 100644 index 00000000..1facfe28 --- /dev/null +++ b/requirements/django42.txt @@ -0,0 +1 @@ +django==4.2.10 diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index ea347319..0e882265 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -8,7 +8,7 @@ build==1.0.3 # via pip-tools click==8.1.7 # via pip-tools -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via build packaging==23.2 # via build @@ -21,7 +21,7 @@ tomli==2.0.1 # build # pip-tools # pyproject-hooks -wheel==0.41.3 +wheel==0.42.0 # via pip-tools zipp==3.17.0 # via importlib-metadata diff --git a/requirements/test.txt b/requirements/test.txt index 40abf287..794de185 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -8,17 +8,17 @@ asgiref==3.7.2 # via # -r requirements/base.txt # django -astroid==2.11.7 +astroid==3.0.3 # via pylint -coverage==6.5.0 +backports-zoneinfo==0.2.1 # via - # -c requirements/constraints.txt - # -r requirements/test.in -ddt==1.6.0 - # via - # -c requirements/constraints.txt - # -r requirements/test.in -dill==0.3.7 + # -r requirements/base.txt + # django +coverage==7.4.1 + # via -r requirements/test.in +ddt==1.7.1 + # via -r requirements/test.in +dill==0.3.8 # via pylint # via # -c requirements/constraints.txt @@ -29,77 +29,51 @@ dill==0.3.7 # jsonfield # openedx-filters django-crum==0.7.9 - # via - # -c requirements/constraints.txt - # -r requirements/base.txt + # via -r requirements/base.txt django-fake-model==0.1.4 + # via -r requirements/test.in +django-mysql==4.12.0 + # via -r requirements/base.txt +djangorestframework==3.14.0 + # via -r requirements/base.txt +edx-opaque-keys[django]==2.5.1 # via - # -c requirements/constraints.txt - # -r requirements/test.in -django-mysql==4.7.1 - # via - # -c requirements/constraints.txt # -r requirements/base.txt -djangorestframework==3.13.1 - # via - # -c requirements/constraints.txt - # -r requirements/base.txt -edx-opaque-keys[django]==2.3.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.txt -isort==5.12.0 + # edx-opaque-keys +isort==5.13.2 # via pylint jsonfield==3.1.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.txt -lazy-object-proxy==1.9.0 - # via astroid + # via -r requirements/base.txt mccabe==0.7.0 # via pylint -mock==4.0.3 - # via - # -c requirements/constraints.txt - # -r requirements/test.in -openedx-filters==1.2.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.txt -path==16.7.1 +mock==5.1.0 + # via -r requirements/test.in +openedx-filters==1.6.0 + # via -r requirements/base.txt +path==16.10.0 # via path-py path-py==12.5.0 - # via - # -c requirements/constraints.txt - # -r requirements/test.in + # via -r requirements/test.in pbr==6.0.0 # via # -r requirements/base.txt # stevedore -platformdirs==4.0.0 +platformdirs==4.2.0 # via pylint -pycodestyle==2.8.0 - # via - # -c requirements/constraints.txt - # -r requirements/test.in -pylint==2.13.9 - # via - # -c requirements/constraints.txt - # -r requirements/test.in +pycodestyle==2.11.1 + # via -r requirements/test.in +pylint==3.0.3 + # via -r requirements/test.in pymongo==3.13.0 # via - # -c requirements/constraints.txt # -r requirements/base.txt # edx-opaque-keys -pytz==2023.3.post1 +pytz==2024.1 # via # -r requirements/base.txt - # django # djangorestframework six==1.16.0 - # via - # -c requirements/constraints.txt - # -r requirements/base.txt + # via -r requirements/base.txt sqlparse==0.4.4 # via # -r requirements/base.txt @@ -108,20 +82,16 @@ stevedore==5.1.0 # via # -r requirements/base.txt # edx-opaque-keys -testfixtures==7.0.0 - # via - # -c requirements/constraints.txt - # -r requirements/test.in +testfixtures==7.2.2 + # via -r requirements/test.in tomli==2.0.1 # via pylint -typing-extensions==4.8.0 +tomlkit==0.12.3 + # via pylint +typing-extensions==4.9.0 # via # -r requirements/base.txt # asgiref # astroid + # edx-opaque-keys # pylint -wrapt==1.16.0 - # via astroid - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/requirements/tox.txt b/requirements/tox.txt index 46856718..28261f31 100644 --- a/requirements/tox.txt +++ b/requirements/tox.txt @@ -10,7 +10,7 @@ chardet==5.2.0 # via tox colorama==0.4.6 # via tox -distlib==0.3.7 +distlib==0.3.8 # via virtualenv filelock==3.13.1 # via @@ -20,11 +20,11 @@ packaging==23.2 # via # pyproject-api # tox -platformdirs==3.11.0 +platformdirs==4.2.0 # via # tox # virtualenv -pluggy==1.3.0 +pluggy==1.4.0 # via tox pyproject-api==1.6.1 # via tox @@ -32,7 +32,7 @@ tomli==2.0.1 # via # pyproject-api # tox -tox==4.11.3 +tox==4.12.1 # via -r requirements/tox.in -virtualenv==20.24.6 +virtualenv==20.25.0 # via tox diff --git a/setup.cfg b/setup.cfg index 8672af07..6b5c1000 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,281 +20,11 @@ statistics = True [pylint] ignore = migrations,CVS generated-members = objects - -[MESSAGES CONTROL] -enable = - line-too-long, - syntax-error, - init-is-generator, - return-in-init, - function-redefined, - not-in-loop, - return-outside-function, - yield-outside-function, - return-arg-in-generator, - nonexistent-operator, - duplicate-argument-name, - abstract-class-instantiated, - bad-reversed-sequence, - continue-in-finally, - method-hidden, - access-member-before-definition, - no-method-argument, - no-self-argument, - invalid-slots-object, - assigning-non-slot, - invalid-slots, - inherit-non-class, - inconsistent-mro, - duplicate-bases, - non-iterator-returned, - unexpected-special-method-signature, - invalid-length-returned, - import-error, - used-before-assignment, - undefined-variable, - undefined-all-variable, - invalid-all-object, - no-name-in-module, - unbalance-tuple-unpacking, - unpacking-non-sequence, - bad-except-order, - raising-bad-type, - misplaced-bare-raise, - raising-non-exception, - nonimplemented-raised, - catching-non-exception, - slots-on-old-class, - super-on-old-class, - bad-super-call, - missing-super-argument, - no-member, - not-callable, - assignment-from-no-return, - no-value-for-parameter, - too-many-function-args, - unexpected-keyword-arg, - redundant-keyword-arg, - invalid-sequence-index, - invalid-slice-index, - assignment-from-none, - not-context-manager, - invalid-unary-operand-type, - unsupported-binary-operation, - repeated-keyword, - not-an-iterable, - not-a-mapping, - unsupported-membership-test, - unsubscriptable-object, - logging-unsupported-format, - logging-too-many-args, - logging-too-few-args, - bad-format-character, - truncated-format-string, - mixed-fomat-string, - format-needs-mapping, - missing-format-string-key, - too-many-format-args, - too-few-format-args, - bad-str-strip-call, - model-unicode-not-callable, - super-method-not-called, - non-parent-method-called, - test-inherits-tests, - translation-of-non-string, - redefined-variable-type, - cyclical-import, - unreachable, - dangerous-default-value, - pointless-statement, - pointless-string-statement, - expression-not-assigned, - duplicate-key, - confusing-with-statement, - using-constant-test, - lost-exception, - assert-on-tuple, - attribute-defined-outside-init, - bad-staticmethod-argument, - arguments-differ, - signature-differs, - abstract-method, - super-init-not-called, - relative-import, - import-self, - misplaced-future, - invalid-encoded-data, - global-variable-undefined, - redefined-outer-name, - redefined-builtin, - redefined-in-handler, - undefined-loop-variable, - cell-var-from-loop, - duplicate-except, - nonstandard-exception, - binary-op-exception, - property-on-old-class, - bad-format-string-key, - unused-format-string-key, - bad-format-string, - missing-format-argument-key, - unused-format-string-argument, - format-combined-specification, - missing-format-attribute, - invalid-format-index, - anomalous-backslash-in-string, - anomalous-unicode-escape-in-string, - bad-open-mode, - boolean-datetime, - fatal, - astroid-error, - parse-error, - method-check-failed, - django-not-available, - raw-checker-failed, - django-not-available-placeholder, - empty-docstring, - invalid-characters-in-docstring, - missing-docstring, - wrong-spelling-in-comment, - wrong-spelling-in-docstring, - unused-import, - unused-variable, - unused-argument, - exec-used, - eval-used, - bad-classmethod-argument, - bad-mcs-classmethod-argument, - bad-mcs-method-argument, - bad-whitespace, - consider-iterating-dictionary, - consider-using-enumerate, - literal-used-as-attribute, - multiple-imports, - multiple-statements, - old-style-class, - simplifiable-range, - singleton-comparison, - superfluous-parens, - unidiomatic-typecheck, - unneeded-not, - wrong-assert-type, - simplifiable-if-statement, - no-classmethod-decorator, - no-staticmethod-decorator, - unnecessary-pass, - unnecessary-lambda, - useless-else-on-loop, - unnecessary-semicolon, - reimported, - global-variable-not-assigned, - global-at-module-level, - bare-except, - broad-except, - logging-not-lazy, - redundant-unittest-assert, - model-missing-unicode, - model-has-unicode, - model-no-explicit-unicode, - protected-access, - deprecated-module, - deprecated-method, - too-many-nested-blocks, - too-many-statements, - too-many-boolean-expressions, - ungrouped-imports, - wrong-import-order, - wrong-import-position, - wildcard-import, - missing-final-newline, - mixed-line-endings, - trailing-newlines, - trailing-whitespace, - unexpected-line-ending-format, - mixed-indentation, - bad-option-value, - unrecognized-inline-option, - useless-suppression, - bad-inline-option, - deprecated-pragma, -disable = - bad-continuation, - invalid-name, - misplaced-comparison-constant, - file-ignored, - bad-indentation, - lowercase-l-suffix, - unused-wildcard-import, - global-statement, - no-else-return, - apply-builtin, - backtick, - basestring-builtin, - buffer-builtin, - cmp-builtin, - cmp-method, - coerce-builtin, - coerce-method, - delslice-method, - dict-iter-method, - dict-view-method, - duplicate-code, - execfile-builtin, - file-builtin, - filter-builtin-not-iterating, - fixme, - getslice-method, - hex-method, - import-star-module-level, - indexing-exception, - input-builtin, - intern-builtin, - locally-disabled, - locally-enabled, - logging-format-interpolation, - long-builtin, - long-suffix, - map-builtin-not-iterating, - metaclass-assignment, - next-method-called, - no-absolute-import, - no-init, - no-self-use, - nonzero-method, - oct-method, - old-division, - old-ne-operator, - old-octal-literal, - old-raise-syntax, - parameter-unpacking, - print-statement, - raising-string, - range-builtin-not-iterating, - raw_input-builtin, - reduce-builtin, - reload-builtin, - round-builtin, - setslice-method, - standarderror-builtin, - suppressed-message, +max-line-length = 120 +disable = too-few-public-methods, too-many-ancestors, - too-many-arguments, - too-many-branches, - too-many-instance-attributes, - too-many-lines, - too-many-locals, - too-many-public-methods, - too-many-return-statements, - unichr-builtin, - unicode-builtin, - unpacking-in-except, - using-cmp-argument, - xrange-builtin, - zip-builtin-not-iterating, - old-style-class, - inconsistent-return-statements, - consider-using-f-string + duplicate-code, [isort] default_section = THIRDPARTY diff --git a/setup.py b/setup.py index b5a9d23d..7c009de2 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def get_version(): match_string = re.search(version_regex, line, re.M) if match_string: return match_string.group(1) - raise RuntimeError('Unable to find version string in %s.' % (file_path,)) + raise RuntimeError(f'Unable to find version string in {file_path}.') setup( diff --git a/tox.ini b/tox.ini index 96e9700f..69893ecf 100644 --- a/tox.ini +++ b/tox.ini @@ -1,16 +1,15 @@ [tox] -envlist = py{38,310,311}-django{32} +envlist = py{38}-django{32,42} [testenv] envdir= # Use the same environment for all commands running under a specific python version py38: {toxworkdir}/py38 - py310: {toxworkdir}/py310 - py311: {toxworkdir}/py311 deps = - django32: -r requirements/django.txt + django32: -r requirements/django32.txt + django42: -r requirements/django42.txt -r requirements/test.txt commands = {posargs}