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}