New fixes

This commit is contained in:
Antoine Nguyen
2025-02-18 16:15:44 +01:00
parent db0b7eb79d
commit 4458e82c25
92 changed files with 298 additions and 309 deletions
+11 -7
View File
@@ -178,7 +178,7 @@ class DomainAliasSerializer(serializers.ModelSerializer):
object_type="domain_aliases",
)
except lib_exceptions.ModoboaException as inst:
raise serializers.ValidationError({"domain": force_str(inst)})
raise serializers.ValidationError({"domain": force_str(inst)}) from None
domain_alias.save(creator=creator)
return domain_alias
@@ -311,7 +311,7 @@ class AccountPasswordSerializer(serializers.ModelSerializer):
try:
password_validation.validate_password(value, self.instance)
except ValidationError as exc:
raise serializers.ValidationError(exc.messages[0])
raise serializers.ValidationError(exc.messages[0]) from None
return value
def update(self, instance, validated_data):
@@ -363,7 +363,7 @@ class WritableAccountSerializer(AccountSerializer):
try:
validators.UTF8EmailValidator()(username)
except ValidationError as err:
raise ValidationError({"username": err.message})
raise ValidationError({"username": err.message}) from None
mailbox = data.get("mailbox")
if mailbox is None:
if not self.instance:
@@ -396,7 +396,9 @@ class WritableAccountSerializer(AccountSerializer):
object_type="mailboxes",
)
except lib_exceptions.ModoboaException as inst:
raise serializers.ValidationError({"mailbox": force_str(inst)})
raise serializers.ValidationError(
{"mailbox": force_str(inst)}
) from None
condition = not data.get("random_password") and (
data.get("password") or not self.partial
)
@@ -408,7 +410,9 @@ class WritableAccountSerializer(AccountSerializer):
data["password"], self.instance
)
except ValidationError as exc:
raise serializers.ValidationError({"password": exc.messages[0]})
raise serializers.ValidationError(
{"password": exc.messages[0]}
) from None
elif not self.instance:
raise serializers.ValidationError(
{"password": _("This field is required.")}
@@ -523,9 +527,9 @@ class AliasSerializer(serializers.ModelSerializer):
value, self.context["request"].user, instance=self.instance
)
except ValidationError as err:
raise serializers.ValidationError(err)
raise serializers.ValidationError(err) from None
except AliasExists:
raise serializers.ValidationError(_("This alias already exists"))
raise serializers.ValidationError(_("This alias already exists")) from None
return value.lower()
def create(self, validated_data):
+1 -1
View File
@@ -135,7 +135,7 @@ class AccountViewSet(
try:
user = core_models.User.objects.get(pk=pk)
except core_models.User.DoesNotExist:
raise http.Http404
raise http.Http404 from None
serializer = self.get_serializer(user, data=request.data)
if serializer.is_valid():
serializer.save()
+7 -5
View File
@@ -94,7 +94,7 @@ class DomainSerializer(v1_serializers.DomainSerializer):
return domain
# 1. Create a domain administrator
username = "%s@%s" % (domain_admin["username"], domain.name)
username = "{}@{}".format(domain_admin["username"], domain.name)
try:
da = core_models.User.objects.get(username=username)
except core_models.User.DoesNotExist:
@@ -244,7 +244,7 @@ class AdminGlobalParametersSerializer(serializers.Serializer):
except ValueError:
raise serializers.ValidationError(
_("This field only allows valid IP addresses (or networks)")
)
) from None
return value
def validate_auto_create_domain_and_mailbox(self, value):
@@ -479,7 +479,7 @@ class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
try:
validators.UTF8EmailValidator()(username)
except ValidationError as err:
raise ValidationError({"username": err.message})
raise ValidationError({"username": err.message}) from None
mailbox = data.get("mailbox")
if mailbox is None:
if not self.instance:
@@ -501,7 +501,7 @@ class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
object_type="mailboxes",
)
except lib_exceptions.ModoboaException as inst:
raise serializers.ValidationError({"mailbox": str(inst)})
raise serializers.ValidationError({"mailbox": str(inst)}) from None
if len(self.address) > 64:
raise serializers.ValidationError(
{
@@ -518,7 +518,9 @@ class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
data["password"], self.instance
)
except ValidationError as exc:
raise serializers.ValidationError({"password": exc.messages[0]})
raise serializers.ValidationError(
{"password": exc.messages[0]}
) from None
elif not self.instance:
raise serializers.ValidationError(
{"password": _("This field is required.")}
+3 -3
View File
@@ -212,7 +212,7 @@ class AdminParametersForm(param_forms.AdminParametersForm):
dpath = fpath
if dpath:
try:
code, version = exec_cmd("%s --version" % dpath)
code, version = exec_cmd(f"{dpath} --version")
except OSError:
hide_fields = True
else:
@@ -259,12 +259,12 @@ class AdminParametersForm(param_forms.AdminParametersForm):
except ValueError:
raise forms.ValidationError(
gettext_lazy("This field only allows valid IP addresses (or networks)")
)
) from None
return value
def clean(self):
"""Check MX options."""
cleaned_data = super(AdminParametersForm, self).clean()
cleaned_data = super().clean()
condition = (
cleaned_data.get("enable_mx_checks")
and cleaned_data.get("domains_must_have_authorized_mx")
+12 -12
View File
@@ -71,7 +71,7 @@ class AccountFormGeneral(forms.ModelForm):
labels = {"is_active": gettext_lazy("Enabled")}
def __init__(self, user, *args, **kwargs):
super(AccountFormGeneral, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields = OrderedDict(
(key, self.fields[key])
for key in [
@@ -163,7 +163,7 @@ class AccountFormGeneral(forms.ModelForm):
def clean(self):
"""Check master user mode."""
super(AccountFormGeneral, self).clean()
super().clean()
if self.errors:
return self.cleaned_data
condition = (
@@ -200,7 +200,7 @@ class AccountFormGeneral(forms.ModelForm):
return self.cleaned_data
def save(self, commit=True):
account = super(AccountFormGeneral, self).save(commit=False)
account = super().save(commit=False)
if self.user == account and not self.cleaned_data["is_active"]:
raise lib_exceptions.PermDeniedException(
_("You can't disable your own account")
@@ -355,7 +355,7 @@ class AccountFormMail(forms.Form, DynamicForm):
Check if quota is >= 0 only when the domain value is not used.
"""
cleaned_data = super(AccountFormMail, self).clean()
cleaned_data = super().clean()
use_default_domain_quota = cleaned_data["quota_act"]
condition = (
not use_default_domain_quota
@@ -510,13 +510,13 @@ class AccountPermissionsForm(forms.Form, DynamicForm):
self.account = kwargs["instance"]
del kwargs["instance"]
super(AccountPermissionsForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if not hasattr(self, "account") or self.account is None:
return
qset = models.Domain.objects.get_for_admin(self.account)
for pos, dom in enumerate(qset):
name = "domains_%d" % (pos + 1)
name = f"domains_{pos + 1}"
self._create_field(lib_fields.DomainNameField, name, dom.name)
if len(args) and isinstance(args[0], QueryDict):
self._load_from_qdict(args[0], "domains", lib_fields.DomainNameField)
@@ -580,7 +580,7 @@ class AccountForm(TabForms):
cbargs["account"] = kwargs["instances"]["general"]
results = signals.extra_account_forms.send(sender=self.__class__, **cbargs)
self.forms += reduce(lambda a, b: a + b, [result[1] for result in results])
super(AccountForm, self).__init__(request, *args, **kwargs)
super().__init__(request, *args, **kwargs)
def extra_context(self, context):
account = self.instances["general"]
@@ -604,8 +604,8 @@ class AccountForm(TabForms):
if form["id"] == "general":
return True
if hasattr(self, "check_%s" % form["id"]):
if not getattr(self, "check_%s" % form["id"])(self.account):
if hasattr(self, "check_{}".format(form["id"])):
if not getattr(self, "check_{}".format(form["id"]))(self.account):
return False
return True
@@ -620,9 +620,9 @@ class AccountForm(TabForms):
def is_valid(self):
"""Two steps validation."""
self.instances["general"].oldgroup = self.instances["general"].role
if super(AccountForm, self).is_valid(mandatory_only=True):
if super().is_valid(mandatory_only=True):
self.account = self.forms[0]["instance"].save()
return super(AccountForm, self).is_valid(optional_only=True)
return super().is_valid(optional_only=True)
return False
def save(self):
@@ -646,7 +646,7 @@ class AccountWizard(WizardForm):
"""Account creation wizard."""
def __init__(self, request):
super(AccountWizard, self).__init__(request)
super().__init__(request)
self.add_step(
WizardStep(
"general", AccountFormGeneral, _("General"), new_args=[request.user]
+6 -6
View File
@@ -49,7 +49,7 @@ class AliasForm(forms.ModelForm, DynamicForm):
def __init__(self, user, *args, **kwargs):
self.user = user
super(AliasForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields = OrderedDict(
(key, self.fields[key])
for key in [
@@ -80,7 +80,7 @@ class AliasForm(forms.ModelForm, DynamicForm):
self.fields["enabled"].widget.attrs["disabled"] = "disabled"
cpt = 1
for rcpt in alias.aliasrecipient_set.filter(alias__internal=False):
name = "recipients_%d" % cpt
name = f"recipients_{cpt}"
self._create_field(forms.EmailField, name, rcpt.address, 2)
cpt += 1
@@ -92,7 +92,7 @@ class AliasForm(forms.ModelForm, DynamicForm):
try:
domain = Domain.objects.get(name=domname)
except Domain.DoesNotExist:
raise forms.ValidationError(_("Domain does not exist"))
raise forms.ValidationError(_("Domain does not exist")) from None
if not self.user.can_access(domain):
raise forms.ValidationError(_("You don't have access to this domain"))
if not self.instance.pk:
@@ -101,12 +101,12 @@ class AliasForm(forms.ModelForm, DynamicForm):
sender=self.__class__, context=domain, object_type="mailbox_aliases"
)
except lib_exceptions.ModoboaException as inst:
raise forms.ValidationError(inst)
raise forms.ValidationError(inst) from None
return self.cleaned_data["address"].lower()
def clean(self):
"""Check it there is at least one recipient."""
super(AliasForm, self).clean()
super().clean()
random_address = self.cleaned_data.get("random_address")
if not random_address:
if not self.cleaned_data.get("address"):
@@ -121,7 +121,7 @@ class AliasForm(forms.ModelForm, DynamicForm):
def save(self, commit=True):
"""Custom save method."""
alias = super(AliasForm, self).save(commit=False)
alias = super().save(commit=False)
if self.cleaned_data.get("random_address"):
alias.address = f"{Alias.generate_random_address()}@{alias.domain}"
else:
+1 -1
View File
@@ -13,7 +13,7 @@ class ExportDataForm(forms.Form):
)
def __init__(self, *args, **kwargs):
super(ExportDataForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields["sepchar"].widget.attrs = {"class": "col-md-1 form-control"}
def clean_sepchar(self):
+1 -1
View File
@@ -21,7 +21,7 @@ class ImportDataForm(forms.Form):
)
def __init__(self, *args, **kwargs):
super(ImportDataForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields["sepchar"].widget.attrs = {"class": "col-md-1 form-control"}
def clean_sepchar(self):
+2 -2
View File
@@ -253,7 +253,7 @@ def get_dns_records(name, typ, resolver=None):
exc_info=e,
)
except dns.name.NameTooLong as e:
logger.error(_("DNS name is too long: %s" % name), exc_info=e)
logger.error(_("DNS name is too long: {}".format(name)), exc_info=e)
else:
return dns_answers
return None
@@ -359,7 +359,7 @@ def import_data(user, file_object, options: dict):
raise Conflict(
_("Object already exists: %s")
% options["sepchar"].join(row[:2])
)
) from None
cpt += 1
msg = _("%d objects imported successfully") % cpt
return True, msg
+5 -5
View File
@@ -54,7 +54,7 @@ def validate_alias_address(
object_type="mailbox_aliases",
)
except ModoboaException as inst:
raise ValidationError(str(inst))
raise ValidationError(str(inst)) from None
return local_part, domain
@@ -132,7 +132,7 @@ class Alias(AdminObject):
return "---"
rcpts = self.recipients
if rcpts_count > 1:
return "%s, ..." % rcpts[0]
return f"{rcpts[0]}, ..."
return rcpts[0]
@property
@@ -150,7 +150,7 @@ class Alias(AdminObject):
def post_create(self, creator):
from modoboa.lib.permissions import grant_access_to_object
super(Alias, self).post_create(creator)
super().post_create(creator)
if creator.is_superuser:
for admin in self.domain.admins:
grant_access_to_object(admin, self)
@@ -174,7 +174,7 @@ class Alias(AdminObject):
address, return_extension=True
)
if domname is None:
raise BadRequest("%s %s" % (_("Invalid address"), address))
raise BadRequest("{} {}".format(_("Invalid address"), address))
domain = Domain.objects.filter(name=domname).first()
kwargs = {"address": address, "alias": self}
if (domain is not None) and (
@@ -189,7 +189,7 @@ class Alias(AdminObject):
rcpt = Mailbox.objects.filter(domain=domain, address=local_part).first()
if rcpt is None:
rcpt = Alias.objects.filter(
address="%s@%s" % (local_part, domname)
address=f"{local_part}@{domname}"
).first()
if rcpt is None:
raise NotFound(
+2 -2
View File
@@ -62,10 +62,10 @@ class AdminObject(models.Model):
def save(self, *args, **kwargs):
creator = kwargs.pop("creator", None)
super(AdminObject, self).save(*args, **kwargs)
super().save(*args, **kwargs)
if creator is not None:
self.post_create(creator)
def delete(self):
ungrant_access_to_object(self)
super(AdminObject, self).delete()
super().delete()
+8 -6
View File
@@ -271,17 +271,17 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
@property
def bind_format_dkim_public_key(self):
"""Return DKIM public key using Bind format."""
record = "v=DKIM1;k=rsa;p=%s" % self.dkim_public_key
record = f"v=DKIM1;k=rsa;p={self.dkim_public_key}"
# TXT records longer than 255 characters need split into chunks
# split record into 74 character chunks (+2 for indent, +2 for quotes(")
# == 78 characters) to make more readable in text editors.
split_record = []
while record:
if len(record) > 74:
split_record.append(' "%s"' % record[:74])
split_record.append(f' "{record[:74]}"')
record = record[74:]
else:
split_record.append(' "%s"' % record)
split_record.append(f' "{record}"')
break
record = "\n".join(split_record)
return f"{self.dkim_key_selector}._domainkey.{self.name}. IN TXT (\n{record})"
@@ -343,7 +343,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
if param_tools.get_global_parameter("auto_account_removal"):
User.objects.filter(mailbox__domain=self).delete()
elif self.mailbox_set.count():
Quota.objects.filter(username__contains="@%s" % self.name).delete()
Quota.objects.filter(username__contains=f"@{self.name}").delete()
ungrant_access_to_objects(self.mailbox_set.all())
super().delete()
@@ -378,7 +378,9 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
try:
self.quota = int(row[2].strip())
except ValueError:
raise BadRequest(_("{}: invalid quota value for domain").format(self.name))
raise BadRequest(
_("{}: invalid quota value for domain").format(self.name)
) from None
try:
self.default_mailbox_quota = int(row[3].strip())
except ValueError:
@@ -386,7 +388,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
_("{}: invalid default mailbox quota value for domain").format(
self.name
)
)
) from None
if self.quota != 0 and self.default_mailbox_quota > self.quota:
raise BadRequest(
_(
+1 -1
View File
@@ -76,7 +76,7 @@ class DomainAlias(AdminObject):
try:
self.target = Domain.objects.get(name=domname)
except Domain.DoesNotExist:
raise BadRequest(_("Unknown domain %s") % domname)
raise BadRequest(_("Unknown domain %s") % domname) from None
core_signals.can_create_object.send(
sender="import", context=self.target, object_type="domain_aliases"
)
+4 -4
View File
@@ -114,7 +114,7 @@ class Mailbox(mixins.MessageLimitMixin, AdminObject):
return smart_str(self.full_address)
def __full_address(self, localpart):
return "%s@%s" % (localpart, self.domain.name)
return f"{localpart}@{self.domain.name}"
@property
def full_address(self):
@@ -147,7 +147,7 @@ class Mailbox(mixins.MessageLimitMixin, AdminObject):
if not admin_params.get("handle_mailboxes"):
return None
if self.__mail_home is None:
code, output = doveadm_cmd("user -f home %s" % self.full_address)
code, output = doveadm_cmd(f"user -f home {self.full_address}")
if code:
raise lib_exceptions.InternalError(
_("Failed to retrieve mailbox location (%s)") % output
@@ -384,5 +384,5 @@ class MailboxOperation(models.Model):
def __str__(self):
if self.type == "rename":
return "Rename %s -> %s" % (self.argument, self.mailbox.mail_home)
return "Delete %s" % self.argument
return f"Rename {self.argument} -> {self.mailbox.mail_home}"
return f"Delete {self.argument}"
+4 -4
View File
@@ -151,7 +151,7 @@ def domain_actions(user, domain):
actions = [
{
"name": "listidentities",
"url": "{0}#list/?searchquery=@{1}".format(
"url": "{}#list/?searchquery=@{}".format(
reverse("admin:identity_list"), domain.name
),
"title": _("View the domain's identities"),
@@ -268,7 +268,7 @@ def domain_aliases(domain):
return "---"
res = ""
for alias in domain.aliases.all():
res += "%s<br/>" % alias.name
res += f"{alias.name}<br/>"
return mark_safe(res)
@@ -286,7 +286,7 @@ def identity_modify_link(identity, active_tab="default"):
linkdef = {"label": identity.identity, "modal": True}
if identity.__class__.__name__ == "User":
linkdef["url"] = reverse("admin:account_change", args=[identity.id])
linkdef["url"] += "?active_tab=%s" % active_tab
linkdef["url"] += f"?active_tab={active_tab}"
linkdef["modalcb"] = "admin.editaccount_cb"
else:
linkdef["url"] = reverse("admin:alias_change", args=[identity.id])
@@ -299,7 +299,7 @@ def domadmin_actions(daid, domid):
actions = [
{
"name": "removeperm",
"url": "{0}?domid={1}&daid={2}".format(
"url": "{}?domid={}&daid={}".format(
reverse("admin:permission_remove"), domid, daid
),
"img": "fa fa-trash",
+4 -4
View File
@@ -17,7 +17,7 @@ class AuthenticationTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(AuthenticationTestCase, cls).setUpTestData()
super().setUpTestData()
cls.mb = factories.MailboxFactory(
domain__name="test.com",
address="user",
@@ -42,7 +42,7 @@ class AccountTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(AccountTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def test_crud(self):
@@ -612,7 +612,7 @@ class PermissionsTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(PermissionsTestCase, cls).setUpTestData()
super().setUpTestData()
parameters = {}
for name, _definition in limits_utils.get_user_limit_templates():
parameters[f"deflt_user_{name}_limit"] = 2
@@ -625,7 +625,7 @@ class PermissionsTestCase(ModoTestCase):
def setUp(self):
"""Initiate test context."""
super(PermissionsTestCase, self).setUp()
super().setUp()
self.values = {
"username": self.user.username,
"role": "DomainAdmins",
+2 -2
View File
@@ -13,7 +13,7 @@ class AliasTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(AliasTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def test_alias(self):
@@ -173,7 +173,7 @@ class AliasTestCase(ModoTestCase):
self.ajax_post(reverse("admin:alias_change", args=[fwd.id]), values)
self.assertEqual(fwd.recipients_count, 1)
self.ajax_delete(reverse("admin:alias_delete") + "?selection=%d" % fwd.id, {})
self.ajax_delete(reverse("admin:alias_delete") + f"?selection={fwd.id}", {})
self.assertRaises(
Alias.DoesNotExist, Alias.objects.get, address="forward2@test.com"
)
+2 -2
View File
@@ -32,7 +32,7 @@ class DomainTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(DomainTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def test_create(self):
@@ -431,7 +431,7 @@ class DKIMTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(DKIMTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def setUp(self):
+1 -1
View File
@@ -10,7 +10,7 @@ class DomainAliasTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(DomainAliasTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
cls.dom = Domain.objects.get(name="test.com")
+2 -2
View File
@@ -17,7 +17,7 @@ class ExportTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(ExportTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def __export_domains(self, domfilter=""):
@@ -31,7 +31,7 @@ class ExportTestCase(ModoTestCase):
def __export_identities(self, idtfilter="", grpfilter=""):
self.client.get(
reverse("admin:_identity_list")
+ "?grpfilter=%s&idtfilter=%s" % (grpfilter, idtfilter)
+ f"?grpfilter={grpfilter}&idtfilter={idtfilter}"
)
return self.client.post(
reverse("admin:identity_export"), {"filename": "test.csv"}
@@ -20,12 +20,12 @@ class MailboxOperationTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(MailboxOperationTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def setUp(self):
"""Initiate test env."""
super(MailboxOperationTestCase, self).setUp()
super().setUp()
self.workdir = tempfile.mkdtemp()
path = f"{self.workdir}/test.com/admin"
os.makedirs(path)
+2 -2
View File
@@ -23,7 +23,7 @@ class MXTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create some data."""
super(MXTestCase, cls).setUpTestData()
super().setUpTestData()
cls.domain = factories.DomainFactory(name="modoboa.org")
# should not exist
cls.bad_domain = factories.DomainFactory(name="does-not-exist.example.com")
@@ -297,7 +297,7 @@ class DNSChecksTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create some data."""
super(DNSChecksTestCase, cls).setUpTestData()
super().setUpTestData()
cls.domain = factories.DomainFactory(name="dns-checks.com")
@mock.patch("gevent.socket.gethostbyname")
+1 -1
View File
@@ -10,7 +10,7 @@ class PasswordSchemesTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(PasswordSchemesTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def _create_account(self):
+1 -1
View File
@@ -13,7 +13,7 @@ class RepairTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create some data."""
super(RepairTestCase, cls).setUpTestData()
super().setUpTestData()
factories.populate_database()
def test_management_command(self):
+1 -1
View File
@@ -12,7 +12,7 @@ class ForwardTestCase(ModoTestCase):
"""User forward test cases."""
def setUp(self):
super(ForwardTestCase, self).setUp()
super().setUp()
populate_database()
def test_set_forward(self):
+3 -3
View File
@@ -27,7 +27,7 @@ def _validate_alias(request, form, successmsg, callback=None):
try:
alias = form.save()
except IntegrityError:
raise Conflict(_("Alias with this name already exists"))
raise Conflict(_("Alias with this name already exists")) from None
if callback:
callback(request.user, alias)
return render_to_json_response(successmsg)
@@ -110,13 +110,13 @@ class AliasDetailView(auth_mixins.PermissionRequiredMixin, generic.DetailView):
def has_permission(self):
"""Check object-level access."""
result = super(AliasDetailView, self).has_permission()
result = super().has_permission()
if not result:
return result
return self.request.user.can_access(self.get_object())
def get_context_data(self, **kwargs):
"""Add information to context."""
context = super(AliasDetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context["selection"] = "identities"
return context
+4 -12
View File
@@ -16,15 +16,11 @@ class MXDomainDetailView(auth_mixins.PermissionRequiredMixin, generic.DetailView
def get_queryset(self):
"""Add some prefetching."""
return (
super(MXDomainDetailView, self)
.get_queryset()
.prefetch_related("mxrecord_set")
)
return super().get_queryset().prefetch_related("mxrecord_set")
def get_context_data(self, **kwargs):
"""Add extra variables."""
context = super(MXDomainDetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context.update({"title": _("MX records of {}").format(self.object.name)})
return context
@@ -38,14 +34,10 @@ class DNSBLDomainDetailView(auth_mixins.PermissionRequiredMixin, generic.DetailV
def get_queryset(self):
"""Add some prefetching."""
return (
super(DNSBLDomainDetailView, self)
.get_queryset()
.prefetch_related("dnsblresult_set")
)
return super().get_queryset().prefetch_related("dnsblresult_set")
def get_context_data(self, **kwargs):
"""Add extra variables."""
context = super(DNSBLDomainDetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context.update({"title": _("DNSBL summary for {}").format(self.object.name)})
return context
+8 -8
View File
@@ -75,7 +75,7 @@ def list_quotas(request):
)
mboxes = mboxes.exclude(quota=0)
if sort_order in ["address", "quota"]:
mboxes = mboxes.order_by("%s%s" % (sort_dir, sort_order))
mboxes = mboxes.order_by(f"{sort_dir}{sort_order}")
elif sort_order in ("quota_value__bytes", "quota_usage"):
db_type = db_type()
if db_type == "mysql":
@@ -85,9 +85,9 @@ def list_quotas(request):
if sort_order == "quota_value__bytes":
mboxes = mboxes.extra(
select={"quota_value__bytes": "admin_quota.bytes"},
where=["admin_quota.username=%s" % where],
where=[f"admin_quota.username={where}"],
tables=["admin_quota", "admin_domain"],
order_by=["%s%s" % (sort_dir, sort_order)],
order_by=[f"{sort_dir}{sort_order}"],
)
else:
if db_type == "postgres":
@@ -102,9 +102,9 @@ def list_quotas(request):
)
mboxes = mboxes.extra(
select={"quota_usage": select},
where=["admin_quota.username=%s" % where],
where=[f"admin_quota.username={where}"],
tables=["admin_quota", "admin_domain"],
order_by=["%s%s" % (sort_dir, sort_order)],
order_by=[f"{sort_dir}{sort_order}"],
)
else:
raise BadRequest(_("Invalid request"))
@@ -199,7 +199,7 @@ def remove_permission(request):
account = User.objects.get(pk=daid)
domain = Domain.objects.get(pk=domid)
except (User.DoesNotExist, Domain.DoesNotExist):
raise BadRequest(_("Invalid request"))
raise BadRequest(_("Invalid request")) from None
if not request.user.can_access(account) or not request.user.can_access(domain):
raise PermDeniedException
domain.remove_admin(account)
@@ -215,14 +215,14 @@ class AccountDetailView(auth_mixins.PermissionRequiredMixin, generic.DetailView)
def has_permission(self):
"""Check object-level access."""
result = super(AccountDetailView, self).has_permission()
result = super().has_permission()
if not result:
return result
return self.request.user.can_access(self.get_object())
def get_context_data(self, **kwargs):
"""Add information to context."""
context = super(AccountDetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
del context["user"]
result = signals.extra_account_dashboard_widgets.send(
self.__class__, user=self.request.user, account=self.object
+2 -2
View File
@@ -12,7 +12,7 @@ class UserCalendarFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.UserCalendar
name = factory.Sequence(lambda n: "User calendar %s" % n)
name = factory.Sequence(lambda n: f"User calendar {n}")
mailbox = factory.SubFactory(admin_factories.MailboxFactory)
@@ -21,7 +21,7 @@ class SharedCalendarFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.SharedCalendar
name = factory.Sequence(lambda n: "Shared calendar %s" % n)
name = factory.Sequence(lambda n: f"Shared calendar {n}")
domain = factory.SubFactory(admin_factories.DomainFactory)
+3 -2
View File
@@ -162,6 +162,7 @@ class AccessRule(models.Model):
access = "r" if self.read else ""
access += "w" if self.write else ""
return smart_str(
"%s access rule to %s -> %s"
% (self.mailbox, self.calendar, access if access else "no access")
"{} access rule to {} -> {}".format(
self.mailbox, self.calendar, access if access else "no access"
)
)
@@ -44,7 +44,7 @@ class Command(BaseCommand):
).first()
if not addressbook:
raise CommandError(
"Address Book for email '%s' not found" % options["email"]
"Address Book for email '{}' not found".format(options["email"])
)
try:
import_csv_file(
@@ -55,5 +55,5 @@ class Command(BaseCommand):
options.get("carddav_password"),
)
except RuntimeError as err:
raise CommandError(err)
raise CommandError(err) from None
self.stdout.write(self.style.SUCCESS("File was imported successfuly"))
+1 -1
View File
@@ -24,7 +24,7 @@ class TestDataMixin:
@classmethod
def setUpTestData(cls):
"""Create test data."""
super(TestDataMixin, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.user = core_models.User.objects.get(username="user@test.com")
cls.addressbook = cls.user.addressbook_set.first()
+2 -2
View File
@@ -45,7 +45,7 @@ class AccountViewSet(GetThrottleViewsetMixin, viewsets.ViewSet):
device = StaticDevice.objects.create(
user=request.user, name=f"{request.user} static device"
)
for cpt in range(10):
for _cpt in range(10):
token = StaticToken.random_token()
device.token_set.create(token=token)
django_otp.login(self.request, request.user.totpdevice_set.first())
@@ -82,7 +82,7 @@ class AccountViewSet(GetThrottleViewsetMixin, viewsets.ViewSet):
if device is None:
return response.Response({"error": _("2FA is not enabled")}, status=403)
device.token_set.all().delete()
for cpt in range(10):
for _cpt in range(10):
token = StaticToken.random_token()
device.token_set.create(token=token)
return response.Response(
+6 -6
View File
@@ -180,21 +180,21 @@ class CoreGlobalParametersSerializer(serializers.Serializer):
try:
value % {"user": "toto"}
except (KeyError, ValueError):
raise serializers.ValidationError(_("Invalid syntax"))
raise serializers.ValidationError(_("Invalid syntax")) from None
return value
def validate_ldap_sync_account_dn_template(self, value):
try:
value % {"user": "toto"}
except (KeyError, ValueError):
raise serializers.ValidationError(_("Invalid syntax"))
raise serializers.ValidationError(_("Invalid syntax")) from None
return value
def validate_ldap_search_filter(self, value):
try:
value % {"user": "toto"}
except (KeyError, ValueError, TypeError):
raise serializers.ValidationError(_("Invalid syntax"))
raise serializers.ValidationError(_("Invalid syntax")) from None
return value
def validate_rounds_number(self, value):
@@ -416,7 +416,7 @@ class PasswordRecoverySmsConfirmSerializer(serializers.Serializer):
except KeyError:
raise CustomValidationError(
{"reason": "totp secret not set in session"}, 403
)
) from None
if not oath.accept_totp(self.context["totp_secret"], data["sms_totp"])[0]:
raise CustomValidationError({"reason": "Wrong totp"}, 400)
@@ -445,7 +445,7 @@ class PasswordRecoverySmsResendSerializer(serializers.Serializer):
except KeyError:
raise CustomValidationError(
{"reason": "totp secret not set in session"}, status.HTTP_403_FORBIDDEN
)
) from None
# Attempt to get user, will raise an error if pk is not valid
self.context["user"] = User.objects.filter(
@@ -501,7 +501,7 @@ class PasswordRecoveryConfirmSerializer(serializers.Serializer):
try:
password_validation.validate_password(data["new_password1"], user)
except djangoValidationError as e:
raise PasswordRequirementsFailure(e.messages)
raise PasswordRequirementsFailure(e.messages) from None
self.context["user"] = user
return super().validate(data)
+5 -8
View File
@@ -512,7 +512,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
}
def __init__(self, *args, **kwargs):
super(GeneralParametersForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields["default_top_redirection"].choices = enabled_applications()
self._add_visibilty_rules(sms_backends.get_all_backend_visibility_rules())
self.fields["password_scheme"].choices = get_password_scheme()
@@ -532,7 +532,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
try:
tpl % {"user": "toto"}
except (KeyError, ValueError):
raise forms.ValidationError(_("Invalid syntax"))
raise forms.ValidationError(_("Invalid syntax")) from None
return tpl
def clean_ldap_sync_account_dn_template(self):
@@ -540,7 +540,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
try:
tpl % {"user": "toto"}
except (KeyError, ValueError):
raise forms.ValidationError(_("Invalid syntax"))
raise forms.ValidationError(_("Invalid syntax")) from None
return tpl
def clean_ldap_search_filter(self):
@@ -548,7 +548,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
try:
ldap_filter % {"user": "toto"}
except (KeyError, ValueError, TypeError):
raise forms.ValidationError(_("Invalid syntax"))
raise forms.ValidationError(_("Invalid syntax")) from None
return ldap_filter
def clean_rounds_number(self):
@@ -613,10 +613,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
{"first_name": "givenName", "email": "mail", "last_name": "sn"},
)
ldap_uri = "ldaps://" if values["ldap_secured"] == "ssl" else "ldap://"
ldap_uri += "%s:%s" % (
values[backend.srv_address_setting_name],
values[backend.srv_port_setting_name],
)
ldap_uri += f"{values[backend.srv_address_setting_name]}:{values[backend.srv_port_setting_name]}"
setattr(settings, backend.setting_fullname("SERVER_URI"), ldap_uri)
if values["ldap_secured"] == "starttls":
setattr(settings, backend.setting_fullname("START_TLS"), True)
+7 -6
View File
@@ -25,7 +25,7 @@ class Command:
{"BACKEND": ("django.template.backends.django.DjangoTemplates")}
]
)
self._templates_dir = "%s/templates" % os.path.dirname(__file__)
self._templates_dir = f"{os.path.dirname(__file__)}/templates"
def _render_template(self, tplfile, env):
"""Render an HTML template."""
@@ -70,7 +70,7 @@ def scan_for_commands(dirname=""):
else:
cmdclassname = cmdname.capitalize()
try:
cmdclass = getattr(cmdmod, "%sCommand" % cmdclassname)
cmdclass = getattr(cmdmod, f"{cmdclassname}Command")
except AttributeError:
continue
result[cmdname] = cmdclass
@@ -83,9 +83,10 @@ def handle_command_line():
parser = argparse.ArgumentParser(
description="A set of utilities to ease the installation of Modoboa.",
epilog="""Available commands:
%s
"""
% "\n".join(["\t%s" % c for c in sorted(commands)]),
{}
""".format(
"\n".join([f"\t{c}" for c in sorted(commands)])
),
)
parser.add_argument(
"--verbose", action="store_true", help="Activate verbose output"
@@ -94,7 +95,7 @@ def handle_command_line():
(args, remaining) = parser.parse_known_args()
if args.command not in commands:
print("Unknown command '%s'" % args.command, file=sys.stderr)
print(f"Unknown command '{args.command}'", file=sys.stderr)
sys.exit(1)
commands[args.command](commands, verbose=args.verbose).run(remaining)
+3 -3
View File
@@ -8,14 +8,14 @@ class HelpCommand(Command):
help = "Display the help message associated to a specific command" # NOQA:A003
def __init__(self, *args, **kwargs):
super(HelpCommand, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self._parser.add_argument("name", type=str, help="A command name")
def handle(self, parsed_args):
if parsed_args.name not in self._commands:
print("Unknown command: %s" % parsed_args.name, file=sys.stderr)
print(f"Unknown command: {parsed_args.name}", file=sys.stderr)
sys.exit(1)
cmd = self._commands[parsed_args.name](self._commands)
cmd._parser.prog = "modoboa-admin.py %s" % parsed_args.name
cmd._parser.prog = f"modoboa-admin.py {parsed_args.name}"
cmd._parser.description = cmd.help
cmd._parser.print_help()
+1 -1
View File
@@ -133,7 +133,7 @@ class APIAccessForm(forms.Form):
def __init__(self, *args, **kwargs):
"""Initialize form."""
user = kwargs.pop("user")
super(APIAccessForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.fields["enable_api_access"].initial = hasattr(user, "auth_token")
@@ -38,7 +38,7 @@ class Command(BaseCommand):
self.verbose = options["verbose"]
log_maximum_age = param_tools.get_global_parameter("log_maximum_age")
self.__vprint("Deleting logs older than %d days..." % log_maximum_age)
self.__vprint(f"Deleting logs older than {log_maximum_age} days...")
limit = timezone.now() - datetime.timedelta(log_maximum_age)
Log.objects.filter(date_created__lt=limit).delete()
self.__vprint("Done.")
+6 -4
View File
@@ -373,15 +373,17 @@ class User(AbstractUser):
if len(row) < 8 or not row[7].strip():
raise BadRequest(
_(
"The simple user '%s' must have a valid email address"
% self.username
"The simple user '{}' must have a valid email address".format(
self.username
)
)
)
if self.username != row[7].strip():
raise BadRequest(
_(
"username and email fields must not differ for '%s'"
% self.username
"username and email fields must not differ for '{}'".format(
self.username
)
)
)
+1 -1
View File
@@ -28,7 +28,7 @@ def get_password_hasher(scheme: str) -> type[PasswordHasher]:
"""
try:
scheme = scheme.replace("-", "")
hasher = globals()["%sHasher" % scheme.upper()]
hasher = globals()[f"{scheme.upper()}Hasher"]
except KeyError:
hasher = PLAINHasher
return hasher
+1 -1
View File
@@ -148,7 +148,7 @@ if argon2_hasher is not None:
def __init__(
self,
):
super(ARGON2IDHasher, self).__init__()
super().__init__()
parameters = dict()
+1 -1
View File
@@ -80,7 +80,7 @@ class PasswordHasher(metaclass=MetaHasher):
:return: encrypted password
"""
pwhash = self._b64encode(self._encrypt(force_str(clearvalue)))
return "%s%s" % (self.scheme, force_str(pwhash))
return f"{self.scheme}{force_str(pwhash)}"
def verify(self, clearvalue, hashed_value):
"""Verify a password against a hashed value.
+6 -7
View File
@@ -181,7 +181,7 @@ def colorize_level(level):
}
if level not in classes:
return level
return "<p class='%s'>%s</p>" % (classes[level], level)
return f"<p class='{classes[level]}'>{level}</p>"
@register.filter
@@ -238,7 +238,7 @@ def connected_users(parser, token):
except ValueError:
raise template.TemplateSyntaxError(
"connected_users usage: {% connected_users as users %}"
)
) from None
return ConnectedUsers(varname)
@@ -279,14 +279,13 @@ def display_messages(msgs):
timeout = "undefined"
return mark_safe(
"""
f"""
<script type="text/javascript">
$(document).ready(function() {
$('body').notify('%s', '%s', %s);
});
$(document).ready(function() {{
$('body').notify('{level}', '{text}', {timeout});
}});
</script>
"""
% (level, text, timeout)
)
+3 -3
View File
@@ -21,7 +21,7 @@ class AuthenticationTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(AuthenticationTestCase, cls).setUpTestData()
super().setUpTestData()
cls.account = factories.UserFactory(
username="user@test.com", groups=("SimpleUsers",)
)
@@ -115,7 +115,7 @@ class ProfileTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(ProfileTestCase, cls).setUpTestData()
super().setUpTestData()
cls.account = factories.UserFactory(
username="user@test.com", groups=("SimpleUsers",)
)
@@ -231,7 +231,7 @@ class APIAccessFormTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(APIAccessFormTestCase, cls).setUpTestData()
super().setUpTestData()
cls.account = factories.UserFactory(
username="user@test.com", groups=("SimpleUsers",)
)
+2 -2
View File
@@ -84,7 +84,7 @@ class LDAPAuthenticationTestCase(LDAPTestCaseMixin, ModoTestCase):
def setUp(self):
"""Create test data."""
super(LDAPAuthenticationTestCase, self).setUp()
super().setUp()
self.activate_ldap_authentication()
def check_created_user(self, username, group="SimpleUsers", with_mb=True):
@@ -142,7 +142,7 @@ class ProfileTestCase(LDAPTestCaseMixin, ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(ProfileTestCase, cls).setUpTestData()
super().setUpTestData()
cls.account = factories.UserFactory(
username="user@test.com", groups=("SimpleUsers",)
)
+3 -3
View File
@@ -148,7 +148,7 @@ class DashboardTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create some data."""
super(DashboardTestCase, cls).setUpTestData()
super().setUpTestData()
cls.dadmin = factories.UserFactory(
username="admin@test.com", groups=("DomainAdmins",)
)
@@ -317,13 +317,13 @@ class PreferencesTestCase(ModoTestCase):
@classmethod
def setUpClass(cls):
"""Register user form."""
super(PreferencesTestCase, cls).setUpClass()
super().setUpClass()
param_tools.registry.add("user", UserSettings, "Test")
@classmethod
def tearDownClass(cls):
"""Remove user class."""
super(PreferencesTestCase, cls).tearDownClass()
super().tearDownClass()
del param_tools.registry._registry["user"]["core"]
def test_get_user_index(self):
+1 -1
View File
@@ -88,7 +88,7 @@ def get_logs_page(request, page_id=None):
if page_id is None:
return None
return get_listing_page(
Log.objects.all().order_by("%s%s" % (sort_dir, sort_order)), page_id
Log.objects.all().order_by(f"{sort_dir}{sort_order}"), page_id
)
+8 -9
View File
@@ -141,11 +141,10 @@ class LoginView(LoginViewMixin, auth_views.LoginView):
def form_invalid(self, form):
# FIXME: should we return a 401 as before ?
self.logger.warning(
"Failed connection attempt from '%(addr)s' as user '%(user)s'"
% {
"addr": self.request.META["REMOTE_ADDR"],
"user": escape(form.cleaned_data["username"]),
}
"Failed connection attempt from '{addr}' as user '{user}'".format(
addr=self.request.META["REMOTE_ADDR"],
user=escape(form.cleaned_data["username"]),
)
)
return self.render_to_response(self.get_context_data(form=form), status=401)
@@ -220,7 +219,7 @@ class VerifySMSCodeView(generic.FormView):
try:
kwargs.update({"totp_secret": self.request.session["totp_secret"]})
except KeyError:
raise Http404
raise Http404 from None
return kwargs
def form_valid(self, form):
@@ -241,11 +240,11 @@ class ResendSMSCodeView(generic.View):
"sms_password_recovery"
)
if not sms_password_recovery:
raise Http404
raise Http404 from None
try:
user = models.User._default_manager.get(pk=self.request.session["user_pk"])
except KeyError:
raise Http404
raise Http404 from None
backend = sms_backends.get_active_backend(self.request.localconfig.parameters)
secret = cryptutils.random_hex_key(20)
code = oath.totp(secret)
@@ -255,7 +254,7 @@ class ResendSMSCodeView(generic.View):
)
)
if not backend.send(text, [user.phone_number]):
raise Http404
raise Http404 from None
self.request.session["totp_secret"] = secret
return JsonResponse({"status": "ok"})
@@ -12,7 +12,7 @@ class ManagementCommandTestCase(mixins.CallCommandMixin, ModoTestCase):
@classmethod
def setUpTestData(cls):
super(ManagementCommandTestCase, cls).setUpTestData()
super().setUpTestData()
cls.domain = admin_factories.DomainFactory(name="ngyn.org")
def test_import_from_archive(self):
+1 -1
View File
@@ -78,7 +78,7 @@ class DomainReportView(auth_mixins.PermissionRequiredMixin, generic.TemplateView
def get_context_data(self, *args, **kwargs):
"""Extra context data."""
context = super(DomainReportView, self).get_context_data(*args, **kwargs)
context = super().get_context_data(*args, **kwargs)
qset = self.get_queryset()
stats = {"total": 0, "aligned": 0, "trusted": 0, "forwarded": 0, "failed": 0}
aligned = {}
+3 -3
View File
@@ -83,7 +83,7 @@ def check_spf_ip4(value):
try:
ipaddress.ip_network(parts[1], False)
except ValueError:
raise DNSSyntaxError(_("Wrong IPv4 address format"))
raise DNSSyntaxError(_("Wrong IPv4 address format")) from None
def check_spf_ip6(value):
@@ -94,7 +94,7 @@ def check_spf_ip6(value):
try:
ipaddress.ip_network(value, False)
except ValueError:
raise DNSSyntaxError(_("Wrong IPv6 address format"))
raise DNSSyntaxError(_("Wrong IPv6 address format")) from None
def _check_domain_and_mask(value, mechanism):
@@ -229,7 +229,7 @@ def check_dmarc_tag(tag, value):
try:
value = int(value)
except ValueError:
raise DNSSyntaxError(error + _(" not an integer"))
raise DNSSyntaxError(error + _(" not an integer")) from None
if "min_value" in tdef and value < tdef["min_value"]:
raise DNSSyntaxError(error + _(" less than {}").format(tdef["min_value"]))
if "max_value" in tdef and value > tdef["max_value"]:
+1 -1
View File
@@ -133,7 +133,7 @@ class ViewsTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls):
"""Create some records."""
super(ViewsTestCase, cls).setUpTestData()
super().setUpTestData()
cls.spf_rec = factories.DNSRecordFactory(
type="spf", value="v=SPF1 mx -all", is_valid=True, domain__name="test.com"
)
+4 -4
View File
@@ -16,7 +16,7 @@ class DomainAccessRequiredMixin(auth_mixins.AccessMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.can_access(self.get_object()):
return self.handle_no_permission()
return super(DomainAccessRequiredMixin, self).dispatch(request, *args, **kwargs)
return super().dispatch(request, *args, **kwargs)
class DNSRecordDetailView(
@@ -29,7 +29,7 @@ class DNSRecordDetailView(
def get_context_data(self, **kwargs):
"""Add extra variables."""
context = super(DNSRecordDetailView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context.update(
{
"title": _("{} record of {}").format(
@@ -59,7 +59,7 @@ class AutoConfigRecordsStatusView(
def get_context_data(self, **kwargs):
"""Add extra data to context."""
context = super(AutoConfigRecordsStatusView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context.update(
{"title": _("Auto configuration records for {}").format(self.object.name)}
)
@@ -76,6 +76,6 @@ class DomainDNSConfigurationView(
def get_context_data(self, **kwargs):
"""Add extra variables."""
context = super(DomainDNSConfigurationView, self).get_context_data(**kwargs)
context = super().get_context_data(**kwargs)
context.update({"title": _("DNS configuration for {}").format(self.object)})
return context
+2 -2
View File
@@ -26,7 +26,7 @@ class DataMixin:
@classmethod
def setUpTestData(cls):
super(DataMixin, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.mb = admin_models.Mailbox.objects.get(user__username="user@test.com")
cls.migration = factories.MigrationFactory(
@@ -110,7 +110,7 @@ class ManagementCommandTestCase(DataMixin, ModoTestCase):
"""Management command test cases."""
def setUp(self):
super(ManagementCommandTestCase, self).setUp()
super().setUp()
self.workdir = tempfile.mkdtemp()
def tearDown(self):
+1 -1
View File
@@ -18,4 +18,4 @@ class IndexView(
def get_context_data(self, **kwargs):
"""Set menu selection."""
kwargs.update({"selection": "imap_migrations"})
return super(IndexView, self).get_context_data(**kwargs)
return super().get_context_data(**kwargs)
+2 -2
View File
@@ -9,7 +9,7 @@ class ConnectionsManager(type):
"""
def __init__(self, name, bases, ctx):
super(ConnectionsManager, self).__init__(name, bases, ctx)
super().__init__(name, bases, ctx)
self.instances = {}
def __call__(self, **kwargs):
@@ -24,7 +24,7 @@ class ConnectionsManager(type):
kwargs["password"] = decrypt(kwargs["password"])
if self.instances[key] is None:
self.instances[key] = super(ConnectionsManager, self).__call__(**kwargs)
self.instances[key] = super().__call__(**kwargs)
else:
self.instances[key].refresh(key, kwargs["password"])
return self.instances[key]
+1 -1
View File
@@ -19,7 +19,7 @@ def db_type(cname="default"):
:return: a string or None
"""
if cname not in settings.DATABASES:
raise InternalError(_("Connection to database %s not configured" % cname))
raise InternalError(_("Connection to database {} not configured".format(cname)))
for t in ["postgres", "mysql", "sqlite"]:
if settings.DATABASES[cname]["ENGINE"].find(t) != -1:
return t
+8 -11
View File
@@ -113,7 +113,7 @@ class Email:
def body(self):
if self._body is None:
self._parse(self.msg)
self._body = getattr(self, "viewmail_%s" % self.dformat)()
self._body = getattr(self, f"viewmail_{self.dformat}")()
return self._body
@@ -215,7 +215,7 @@ class Email:
# Duplicate Content-ID
return
self._images[cid] = "data:%s;base64,%s" % (
self._images[cid] = "data:{};base64,{}".format(
content_type,
"".join(msg.get_payload().splitlines(False)),
)
@@ -263,7 +263,7 @@ class Email:
contents = self.contents["plain"]
else:
contents = conditional_escape(contents)
return "<pre>%s</pre>" % contents
return f"<pre>{contents}</pre>"
def viewmail_html(self, contents=None, **kwargs):
# contents and **kwargs parameters to maintain compatibility with
@@ -385,7 +385,7 @@ def set_email_headers(msg, subject, sender, rcpt):
msg["From"] = sender
msg["To"] = prepare_addresses(rcpt)
msg["Message-ID"] = make_msgid()
msg["User-Agent"] = "Modoboa %s" % (
msg["User-Agent"] = "Modoboa {}".format(
pkg_resources.get_distribution("modoboa").version
)
msg["Date"] = formatdate(time.time(), True)
@@ -409,7 +409,7 @@ def _sendmail(sender, rcpt, msgstring, server="localhost", port=25):
s.sendmail(sender, [rcpt], msgstring)
s.quit()
except smtplib.SMTPException as e:
return False, "SMTP error: %s" % str(e)
return False, f"SMTP error: {str(e)}"
return True, None
@@ -449,12 +449,9 @@ def sendmail_fromfile(sender, rcpt, fname):
except OSError as e:
return False, str(e)
content = """From: %s
To: %s
""" % (
sender,
rcpt,
)
content = f"""From: {sender}
To: {rcpt}
"""
content += fp.read()
fp.close()
+1 -1
View File
@@ -82,5 +82,5 @@ class PermDeniedException(ModoboaException):
def __str__(self):
if self.msg:
return _("Permission denied: %s" % self.msg)
return _("Permission denied: {}".format(self.msg))
return _("Permission denied")
+3 -3
View File
@@ -17,7 +17,7 @@ class DomainNameField(forms.fields.CharField):
def clean(self, value):
value = self.to_python(value).strip()
return super(DomainNameField, self).clean(value)
return super().clean(value)
class UTF8EmailField(forms.fields.EmailField):
@@ -41,7 +41,7 @@ class DRFEmailFieldUTF8(serializers.CharField):
default_error_messages = {"invalid": gettext_lazy("Enter a valid email address.")}
def __init__(self, **kwargs):
super(DRFEmailFieldUTF8, self).__init__(**kwargs)
super().__init__(**kwargs)
validator = validators.UTF8EmailValidator(
message=self.error_messages["invalid"]
)
@@ -54,7 +54,7 @@ class DRFEmailFieldUTF8AndEmptyUser(serializers.CharField):
default_error_messages = {"invalid": gettext_lazy("Enter a valid email address.")}
def __init__(self, **kwargs):
super(DRFEmailFieldUTF8AndEmptyUser, self).__init__(**kwargs)
super().__init__(**kwargs)
validator = validators.UTF8AndEmptyUserEmailValidator(
message=self.error_messages["invalid"]
)
+5 -6
View File
@@ -218,7 +218,7 @@ class DynamicForm:
:param string pattern: pattern used to find field instances
:param typ: a form field class
"""
expr = re.compile(r"%s_\d+" % pattern)
expr = re.compile(rf"{pattern}_\d+")
values = []
for k, v in list(qdict.items()):
if k == pattern or expr.match(k):
@@ -258,7 +258,7 @@ class TabForms:
args.append(request.POST)
if instances is not None:
self.instances = instances
mname = "check_%s" % fd["id"]
mname = "check_{}".format(fd["id"])
if hasattr(self, mname):
if not getattr(self, mname)(instances[fd["id"]]):
to_remove += [fd]
@@ -326,8 +326,7 @@ class TabForms:
return self.forward()
def forward(self):
for form in self.forms:
yield form
yield from self.forms
def extra_context(self, context):
""" "Provide additional information to template's context."""
@@ -387,7 +386,7 @@ class SeparatorField(Field):
def __init__(self, *args, **kwargs):
kwargs["required"] = False
super(SeparatorField, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
class YesNoField(TypedChoiceField):
@@ -402,4 +401,4 @@ class YesNoField(TypedChoiceField):
"coerce": lambda x: x == "True",
}
)
super(YesNoField, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
+1 -1
View File
@@ -112,7 +112,7 @@ class LDAPAuthBackend:
self.connect_to_server(user, password)
user_dn = self._find_user_dn(user)
if self.ldap_ad:
newpassword = ('"%s"' % newpassword).encode("utf-16").lstrip("\377\376")
newpassword = (f'"{newpassword}"').encode("utf-16").lstrip("\377\376")
ldif = [
(
ldap.MOD_REPLACE,
+1 -1
View File
@@ -4,7 +4,7 @@ class _Singleton(type):
def __call__(self, *args, **kwargs):
if self not in self._instances:
self._instances[self] = super(_Singleton, self).__call__(*args, **kwargs)
self._instances[self] = super().__call__(*args, **kwargs)
return self._instances[self]
+1 -1
View File
@@ -27,7 +27,7 @@ def exec_cmd(cmd, sudo_user=None, pinput=None, capture_output=True, **kwargs):
:return: return code, command output
"""
if sudo_user is not None:
cmd = "sudo -u %s %s" % (sudo_user, cmd)
cmd = f"sudo -u {sudo_user} {cmd}"
kwargs["shell"] = True
if pinput is not None:
kwargs["stdin"] = subprocess.PIPE
+3 -3
View File
@@ -20,7 +20,7 @@ def render_form(form, tpl=None):
ret = ""
for field in form:
ret += "%s\n" % render_field(field)
ret += f"{render_field(field)}\n"
return mark_safe(ret)
@@ -42,7 +42,7 @@ def render_field(field, help_display_mode="tooltip", label_width="col-sm-4", **o
from modoboa.core.templatetags.core_tags import visirule
if isinstance(field.field, SeparatorField):
return "<h5%s>%s</h5>" % (visirule(field), smart_str(field.label))
return f"<h5{visirule(field)}>{smart_str(field.label)}</h5>"
configure_field_classes(field)
context = {
"field": field,
@@ -64,7 +64,7 @@ def render_fields_group(form, pattern):
cpt = 1
haserror = len(first.errors) != 0
while True:
fname = "%s_%d" % (pattern, cpt)
fname = f"{pattern}_{cpt}"
if fname not in form.fields:
break
bfield = forms.BoundField(form, form.fields[fname], fname)
+2 -2
View File
@@ -18,13 +18,13 @@ def join(items, sep=","):
for k, v in list(items.items()):
if res != "":
res += sep
res += "%s : '%s'" % (k, v)
res += f"{k} : '{v}'"
return res
@register.simple_tag
def tolist(values):
return mark_safe("[%s]" % ",".join(['"%s"' % v for v in values]))
return mark_safe("[{}]".format(",".join([f'"{v}"' for v in values])))
@register.simple_tag
+3 -3
View File
@@ -15,8 +15,8 @@ SAMPLES_DIR = os.path.realpath(
class EmailTestImplementation(Email):
def _fetch_message(self):
message_path = os.path.join(SAMPLES_DIR, "%s-input.txt" % self.mailid)
assert os.path.isfile(message_path), "%s does not exist." % message_path
message_path = os.path.join(SAMPLES_DIR, f"{self.mailid}-input.txt")
assert os.path.isfile(message_path), f"{message_path} does not exist."
with open(message_path, "rb") as fp:
mail_text = smart_bytes(fp.read())
@@ -38,7 +38,7 @@ class EmailTests(SimpleTestCase):
ext = kwargs["dformat"] if "dformat" in kwargs else "plain"
ext += "_links" if "links" in kwargs and kwargs["links"] else "_nolinks"
message_path = os.path.join(SAMPLES_DIR, f"{message_id}-output-{ext}.txt")
assert os.path.isfile(message_path), "%s does not exist." % message_path
assert os.path.isfile(message_path), f"{message_path} does not exist."
with open(message_path, "rb") as fp:
# output should always be unicode (py2) or str (py3)
+2 -2
View File
@@ -16,7 +16,7 @@ from django.template.loader import render_to_string
def _render_error(request, errortpl="error", user_context=None):
if user_context is None:
user_context = {}
return render(request, "common/%s.html" % errortpl, user_context)
return render(request, f"common/{errortpl}.html", user_context)
def render_actions(actions):
@@ -102,7 +102,7 @@ def static_url(path):
"""
if path.startswith("/"):
path = path[1:]
return "%s%s" % (settings.STATIC_URL, path)
return f"{settings.STATIC_URL}{path}"
def size2integer(value, output_unit="B"):
+3 -3
View File
@@ -20,7 +20,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(APIAdminLimitsTestCase, cls).setUpTestData()
super().setUpTestData()
for name, _definition in utils.get_user_limit_templates():
cls.localconfig.parameters.set_value(f"deflt_user_{name}_limit", 2)
cls.localconfig.save()
@@ -189,7 +189,7 @@ class APIDomainLimitsTestCase(lib_tests.ModoAPITestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(APIDomainLimitsTestCase, cls).setUpTestData()
super().setUpTestData()
cls.localconfig.parameters.set_value("enable_domain_limits", True)
for name, _definition in utils.get_domain_limit_templates():
cls.localconfig.parameters.set_value(f"deflt_domain_{name}_limit", 2)
@@ -251,7 +251,7 @@ class ResourcesAPITestCase(lib_tests.ModoAPITestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(ResourcesAPITestCase, cls).setUpTestData()
super().setUpTestData()
for name, _definition in utils.get_user_limit_templates():
cls.localconfig.parameters.set_value(f"deflt_user_{name}_limit", 2)
cls.localconfig.save()
+4 -4
View File
@@ -13,7 +13,7 @@ class ResourcePoolForm(forms.Form):
def __init__(self, *args, **kwargs):
self.account = kwargs.pop("instance", None)
super(ResourcePoolForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
for name, tpl in utils.get_user_limit_templates():
if "required_role" in tpl:
condition = (
@@ -30,7 +30,7 @@ class ResourcePoolForm(forms.Form):
def clean(self):
"""Ensure limit values are correct."""
cleaned_data = super(ResourcePoolForm, self).clean()
cleaned_data = super().clean()
if self.errors:
return cleaned_data
for lname in list(self.fields.keys()):
@@ -65,7 +65,7 @@ class DomainLimitsForm(forms.Form):
def __init__(self, *args, **kwargs):
"""Define limits as fields."""
self.domain = kwargs.pop("instance", None)
super(DomainLimitsForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
for name, tpl in utils.get_domain_limit_templates():
self.fields[f"{name}_limit"] = forms.IntegerField(
label=tpl["label"], help_text=tpl["help"]
@@ -80,7 +80,7 @@ class DomainLimitsForm(forms.Form):
def clean(self):
"""Ensure limit values are correct."""
cleaned_data = super(DomainLimitsForm, self).clean()
cleaned_data = super().clean()
if self.errors:
return cleaned_data
for lname in list(self.fields.keys()):
+3 -3
View File
@@ -14,7 +14,7 @@ class LimitImportTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(LimitImportTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.reseller = core_factories.UserFactory(
username="reseller", groups=("Resellers",)
@@ -119,7 +119,7 @@ class UserLimitImportTestCase(LimitImportTestCase):
for name, _definition in utils.get_user_limit_templates():
localconfig.parameters.set_value(f"deflt_user_{name}_limit", 2)
localconfig.save()
super(UserLimitImportTestCase, cls).setUpTestData()
super().setUpTestData()
def test_domains_import(self):
"""Check domains limit."""
@@ -181,7 +181,7 @@ class DomainLimitImportTestCase(LimitImportTestCase):
for name, _definition in utils.get_domain_limit_templates():
localconfig.parameters.set_value(f"deflt_domain_{name}_limit", 2)
localconfig.save()
super(DomainLimitImportTestCase, cls).setUpTestData()
super().setUpTestData()
mb = admin_factories.MailboxFactory(
user__username="user@test4.com", domain__name="test4.com", address="user"
)
+9 -9
View File
@@ -15,7 +15,7 @@ class PermissionsTestCase(lib_tests.ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(PermissionsTestCase, cls).setUpTestData()
super().setUpTestData()
populate_database()
def test_domainadmin_deletes_reseller(self):
@@ -49,7 +49,7 @@ class ResourceTestCase(lib_tests.ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Custom setUpTestData method."""
super(ResourceTestCase, cls).setUpTestData()
super().setUpTestData()
cls.localconfig.parameters.set_values(
{"enable_admin_limits": True, "enable_domain_limits": False}
)
@@ -116,7 +116,7 @@ class ResourceTestCase(lib_tests.ModoTestCase):
else:
aliases.remove(name)
for cpt, alias in enumerate(aliases):
fname = "aliases" if not cpt else "aliases_%d" % cpt
fname = "aliases" if not cpt else f"aliases_{cpt}"
values[fname] = alias
self.ajax_post(reverse("admin:domain_change", args=[dom.id]), values, status)
@@ -131,7 +131,7 @@ class DomainAdminTestCase(ResourceTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(DomainAdminTestCase, cls).setUpTestData()
super().setUpTestData()
cls.user = User.objects.get(username="admin@test.com")
cls.user.userobjectlimit_set.filter(
name__in=["mailboxes", "mailbox_aliases"]
@@ -139,7 +139,7 @@ class DomainAdminTestCase(ResourceTestCase):
def setUp(self):
"""Test initialization."""
super(DomainAdminTestCase, self).setUp()
super().setUp()
self.client.force_login(self.user)
def test_mailboxes_limit(self):
@@ -173,7 +173,7 @@ class DomainAdminTestCase(ResourceTestCase):
self._check_limit("mailbox_aliases", 3, -1)
self.ajax_delete(
reverse("admin:alias_delete")
+ "?selection=%d" % Alias.objects.get(address="alias2@test.com").id
+ f"?selection={Alias.objects.get(address='alias2@test.com').id}"
)
self._check_limit("mailbox_aliases", 2, -1)
@@ -201,14 +201,14 @@ class ResellerTestCase(ResourceTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(ResellerTestCase, cls).setUpTestData()
super().setUpTestData()
cls.localconfig.parameters.set_value("deflt_user_quota_limit", 1000)
cls.localconfig.save()
cls.user = UserFactory(username="reseller", groups=("Resellers",))
def setUp(self):
"""Test initialization."""
super(ResellerTestCase, self).setUp()
super().setUp()
self.client.force_login(self.user)
def test_domains_limit(self):
@@ -380,7 +380,7 @@ class ResellerTestCase(ResourceTestCase):
self.client.logout()
self.client.login(username="admin", password="password")
self.ajax_delete(
"{0}?domid={1}&daid={2}".format(
"{}?domid={}&daid={}".format(
reverse("admin:permission_remove"), dom.id, self.user.id
),
{},
+4 -4
View File
@@ -36,12 +36,12 @@ class Curve:
:return: a list
"""
rrdfile = os.path.join(
param_tools.get_global_parameter("rrd_rootdir"), "%s.rrd" % rrdfile
param_tools.get_global_parameter("rrd_rootdir"), f"{rrdfile}.rrd"
)
return [
"DEF:%s=%s:%s:%s" % (self.dsname, rrdfile, self.dsname, self.cfunc),
"CDEF:%(ds)spm=%(ds)s,UN,0,%(ds)s,IF,60,*" % {"ds": self.dsname},
'XPORT:%spm:"%s"' % (self.dsname, self.legend),
f"DEF:{self.dsname}={rrdfile}:{self.dsname}:{self.cfunc}",
f"CDEF:{self.dsname}pm={self.dsname},UN,0,{self.dsname},IF,60,*",
f'XPORT:{self.dsname}pm:"{self.legend}"',
]
+1 -1
View File
@@ -11,7 +11,7 @@ def date_to_timestamp(timetuple):
:return: an integer
"""
date = " ".join(
[("%d" % elem) if isinstance(elem, int) else elem for elem in timetuple]
[str(elem) if isinstance(elem, int) else elem for elem in timetuple]
)
fmt = "%Y %m %d %H %M %S" if timetuple[1].isdigit() else "%Y %b %d %H %M %S"
try:
@@ -204,12 +204,12 @@ class LogParser:
# Set up data sources for our RRD
params = []
for v in variables:
params += ["DS:%s:%s:%s:0:U" % (v, ds_type, rrdstep * 2)]
params += [f"DS:{v}:{ds_type}:{rrdstep * 2}:0:U"]
# Set up RRD to archive data
for cf in ["AVERAGE", "MAX"]:
for step in [day_steps, week_steps, month_steps, year_steps]:
params += ["RRA:%s:0.5:%s:%s" % (cf, step, realrows)]
params += [f"RRA:{cf}:0.5:{step}:{realrows}"]
# With those setup, we can now created the RRD
rrdtool.create(str(fname), "--start", str(m), "--step", str(rrdstep), *params)
@@ -221,16 +221,16 @@ class LogParser:
Add missing Data Sources (DS) to existing Round Robin Archive (RRA):
See init_rrd for details.
"""
ds_def = "DS:%s:ABSOLUTE:%s:0:U" % (dsname, rrdstep * 2)
ds_def = f"DS:{dsname}:ABSOLUTE:{rrdstep * 2}:0:U"
rrdtool.tune(fname, ds_def)
self._dprint("[rrd] added DS %s to %s" % (dsname, fname))
self._dprint(f"[rrd] added DS {dsname} to {fname}")
def add_point_to_rrd(self, fname, tpl, values, ts=None):
"""Try to add a new point to RRD file."""
if ts:
values = f"{ts}:{values}"
if self.verbose:
print("[rrd] VERBOSE update -t %s %s" % (tpl, values))
print(f"[rrd] VERBOSE update -t {tpl} {values}")
try:
rrdtool.update(str(fname), "-t", tpl, values)
except rrdtool.OperationalError as e:
@@ -249,20 +249,20 @@ class LogParser:
False : syslog may have probably been already recorded
or something wrong
"""
fname = "%s/%s.rrd" % (self.workdir, dom)
fname = f"{self.workdir}/{dom}.rrd"
m = t - (t % rrdstep)
self._dprint("[rrd] updating %s" % fname)
self._dprint(f"[rrd] updating {fname}")
if not os.path.exists(fname):
self.lupdates[fname] = self.init_rrd(fname, m)
self._dprint("[rrd] create new RRD file %s" % fname)
self._dprint(f"[rrd] create new RRD file {fname}")
else:
if fname not in self.lupdates:
self.lupdates[fname] = rrdtool.last(str(fname))
if m <= self.lupdates[fname]:
if self.verbose:
print("[rrd] VERBOSE events at %s already recorded in RRD" % m)
print(f"[rrd] VERBOSE events at {m} already recorded in RRD")
return False
tpl = ""
@@ -281,7 +281,7 @@ class LogParser:
for p in range(self.lupdates[fname] + rrdstep, m, rrdstep):
self.add_point_to_rrd(fname, tpl, values, ts=p)
values = "%s" % m
values = f"{m}"
tpl = ""
for v in variables:
values += ":"
@@ -356,7 +356,7 @@ class LogParser:
m = self._srs_regex["reverse_srs1"].match(mail_address) if m is None else m
if m is not None:
return "%s@%s" % m.group(2, 1)
return "{}@{}".format(*m.group(2, 1))
else:
return mail_address
@@ -474,12 +474,10 @@ class LogParser:
return False
(msg_to, msg_status) = m.groups()
if queue_id not in self.workdict:
self._dprint(
"[parser] inconsistent mail (%s: %s), skipping" % (queue_id, msg_to)
)
self._dprint(f"[parser] inconsistent mail ({queue_id}: {msg_to}), skipping")
return True
if msg_status not in variables:
self._dprint("[parser] unsupported status %s, skipping" % msg_status)
self._dprint(f"[parser] unsupported status {msg_status}, skipping")
return True
# orig_to is optional.
@@ -564,7 +562,7 @@ class LogParser:
try:
parser = getattr(self, f"_parse_{prog}")
if not parser(log, host, pid, subprog):
self._dprint("[parser] ignoring %r log: %r" % (prog, log))
self._dprint(f"[parser] ignoring {prog!r} log: {log!r}")
except AttributeError:
self._dprint(f'[parser] no log handler for "{prog}": {log}')
@@ -579,11 +577,11 @@ class LogParser:
for line in fp:
self._parse_line(line)
except OSError as errno:
self._dprint("%s" % errno)
self._dprint(f"{errno}")
sys.exit(1)
for dom, data in self.data.items():
self._dprint("[rrd] dealing with domain %s" % dom)
self._dprint(f"[rrd] dealing with domain {dom}")
for t in sorted(data.keys()):
self.update_rrd(dom, t)
+5 -7
View File
@@ -162,7 +162,7 @@ class MaillogParser:
m = self._srs_regex["reverse_srs1"].match(mail_address) if m is None else m
if m is not None:
return "%s@%s" % m.group(2, 1)
return "{}@{}".format(*m.group(2, 1))
return mail_address
def new_domain_event(self, domain, name, size=None):
@@ -221,9 +221,7 @@ class MaillogParser:
return False
(msg_to, msg_status) = m.groups()
if queue_id not in self.workdict:
self._dprint(
"[parser] inconsistent mail (%s: %s), skipping" % (queue_id, msg_to)
)
self._dprint(f"[parser] inconsistent mail ({queue_id}: {msg_to}), skipping")
return True
# orig_to is optional.
@@ -270,16 +268,16 @@ class MaillogParser:
try:
parser = getattr(self, f"_parse_{prog}")
if not parser(log, host, pid, subprog):
self._dprint("[parser] ignoring %r log: %r" % (prog, log))
self._dprint(f"[parser] ignoring {prog!r} log: {log!r}")
except AttributeError:
self._dprint('[parser] no log handler for "%r": %r' % (prog, log))
self._dprint(f'[parser] no log handler for "{prog!r}": {log!r}')
def parse(self, logfile):
"""Process the log file."""
try:
fp = open(logfile, encoding="utf-8")
except OSError as errno:
self._dprint("%s" % errno)
self._dprint(f"{errno}")
return
for line in fp.readlines():
+4 -4
View File
@@ -19,7 +19,7 @@ class RunCommandsMixin:
"""Mixin to run management commands."""
def setUp(self):
super(RunCommandsMixin, self).setUp()
super().setUp()
self.workdir = tempfile.mkdtemp()
self.set_global_parameter("rrd_rootdir", self.workdir)
@@ -54,12 +54,12 @@ class ViewsTestCase(RunCommandsMixin, ModoTestCase):
@classmethod
def setUpTestData(cls): # noqa
super(ViewsTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.da = core_models.User.objects.get(username="admin@test.com")
def tearDown(self):
super(ViewsTestCase, self).tearDown()
super().tearDown()
self.set_global_parameter("greylist", False)
def test_index(self):
@@ -139,7 +139,7 @@ class ManagementCommandsTestCase(RunCommandsMixin, ModoTestCase):
@classmethod
def setUpTestData(cls): # noqa
super(ManagementCommandsTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
def test_logparser(self):
+2 -2
View File
@@ -75,12 +75,12 @@ def graphs(request):
start = request.GET["start"]
end = request.GET["end"]
expr = re.compile(r"[:\- ]")
period_name = "%s_%s" % (expr.sub("", start), expr.sub("", end))
period_name = "{}_{}".format(expr.sub("", start), expr.sub("", end))
start = date_to_timestamp(expr.split(start))
end = date_to_timestamp(expr.split(end))
else:
end = int(time.mktime(time.localtime()))
start = "-1%s" % period
start = f"-1{period}"
period_name = period
tplvars["domain_selector"] = graph_sets[gset].domain_selector
+5 -5
View File
@@ -21,7 +21,7 @@ class GenericParametersForm(forms.Form):
kwargs["prefix"] = self.app
load_values_from_db = kwargs.pop("load_values_from_db", True)
super(GenericParametersForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self._add_dynamic_fields()
@@ -36,8 +36,8 @@ class GenericParametersForm(forms.Form):
"""Add visibility rules to this form."""
for key, rule in list(rules.items()):
field, value = rule.split("=")
visibility = {"field": "id_%s-%s" % (self.app, field), "value": value}
self.visirules["%s-%s" % (self.app, key)] = visibility
visibility = {"field": f"id_{self.app}-{field}", "value": value}
self.visirules[f"{self.app}-{key}"] = visibility
def _add_dynamic_fields(self):
"""Add dynamic fields to this form."""
@@ -60,7 +60,7 @@ class AdminParametersForm(GenericParametersForm):
def __init__(self, *args, **kwargs):
"""Store LocalConfig instance."""
self.localconfig = kwargs.pop("localconfig", None)
super(AdminParametersForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def _load_initial_values(self):
"""Load form initial values from database."""
@@ -92,7 +92,7 @@ class UserParametersForm(GenericParametersForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
super(UserParametersForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def _load_initial_values(self):
"""Load initial values from User instance."""
+1 -1
View File
@@ -308,7 +308,7 @@ class ParametersForm(param_forms.AdminParametersForm):
def __init__(self, *args, **kwargs):
"""Set initial values."""
super(ParametersForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if not self.fields["webpanel_url"].initial:
url = f"https://{self.hostname}{settings.LOGIN_URL}"
self.fields["webpanel_url"].initial = url
+2 -2
View File
@@ -19,12 +19,12 @@ class EventsTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls):
"""Create some data."""
super(EventsTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.DomainFactory(name="test.com")
def setUp(self):
"""Create temp. directory to store files."""
super(EventsTestCase, self).setUp()
super().setUp()
self.workdir = tempfile.mkdtemp()
self.set_global_parameter("storage_dir", self.workdir)
+1 -1
View File
@@ -14,7 +14,7 @@ class ARMessageViewSetTestCase(ModoAPITestCase):
@classmethod
def setUpTestData(cls):
super(ARMessageViewSetTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.account = User.objects.get(username="user@test.com")
cls.account2 = User.objects.get(username="user@test2.com")
+1 -1
View File
@@ -150,7 +150,7 @@ Best regards,
try:
tpl % {"name": "Antoine Nguyen"}
except (KeyError, ValueError):
raise forms.ValidationError(gettext_lazy("Invalid syntax"))
raise forms.ValidationError(gettext_lazy("Invalid syntax")) from None
return tpl
+6 -8
View File
@@ -92,15 +92,13 @@ def extra_js(sender, caller, st_type, user, **kwargs):
"""Add static content."""
if caller != "user_index" or st_type != "js":
return ""
return """function autoreply_cb() {
$('.datefield').datetimepicker({
return f"""function autoreply_cb() {{
$('.datefield').datetimepicker({{
format: 'YYYY-MM-DD HH:mm:ss',
locale: '%(lang)s'
});
}
""" % {
"lang": user.language
}
locale: '{user.language}'
}});
}}
"""
@receiver(core_signals.extra_user_menu_entries)
+6 -6
View File
@@ -111,7 +111,7 @@ class EventsTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(EventsTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
def test_domain_created_event(self):
@@ -241,12 +241,12 @@ class FormTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(FormTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
def setUp(self):
"""Initialize tests."""
super(FormTestCase, self).setUp()
super().setUp()
self.client.logout()
self.client.login(username="user@test.com", password="toto")
@@ -314,7 +314,7 @@ class RepairTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create some data."""
super(RepairTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
def test_management_command(self):
@@ -342,13 +342,13 @@ class ManagementCommandTestCase(ModoTestCase):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create some data."""
super(ManagementCommandTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.account = User.objects.get(username="user@test.com")
def setUp(self):
"""Replace stdin."""
super(ManagementCommandTestCase, self).setUp()
super().setUp()
self.stdin = sys.stdin
sys.stdin = StringIO(SIMPLE_EMAIL_CONTENT.strip())
self.arm = factories.ARmessageFactory(mbox=self.account.mailbox)
+1 -1
View File
@@ -14,7 +14,7 @@ class DataMixin:
@classmethod
def setUpTestData(cls): # NOQA:N802
super(DataMixin, cls).setUpTestData()
super().setUpTestData()
transport = tr_factories.TransportFactory(
pattern="test.com",
_settings={
+1 -1
View File
@@ -52,7 +52,7 @@ class RelayDomainFormGeneral(tr_forms.TransportForm):
# We don't want to recreate the transport we just deleted it
# (post_save signal).
return None
instance = super(RelayDomainFormGeneral, self).save()
instance = super().save()
instance.pattern = domain.name
instance.save()
if not domain.transport:
+4 -4
View File
@@ -48,7 +48,7 @@ class Operations:
else:
aliases.remove(name)
for cpt, alias in enumerate(aliases):
fname = "aliases" if not cpt else "aliases_%d" % cpt
fname = "aliases" if not cpt else f"aliases_{cpt}"
values[fname] = alias
return self.ajax_post(
reverse("admin:domain_change", args=[domain.id]), values, status
@@ -65,7 +65,7 @@ class RelayDomainsTestCase(ModoTestCase, Operations):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(RelayDomainsTestCase, cls).setUpTestData()
super().setUpTestData()
admin_factories.populate_database()
cls.transport = tr_factories.TransportFactory(
pattern="relaydomain.tld",
@@ -277,7 +277,7 @@ class LimitsTestCase(ModoTestCase, Operations):
@classmethod
def setUpTestData(cls): # NOQA:N802
"""Create test data."""
super(LimitsTestCase, cls).setUpTestData()
super().setUpTestData()
for name, _definition in limits_utils.get_user_limit_templates():
cls.localconfig.parameters.set_value(
f"deflt_user_{name}_limit", 2, app="limits"
@@ -287,7 +287,7 @@ class LimitsTestCase(ModoTestCase, Operations):
def setUp(self):
"""Initialize test."""
super(LimitsTestCase, self).setUp()
super().setUp()
self.client.force_login(self.user)
def test_relay_domains_limit(self):
+1 -1
View File
@@ -76,7 +76,7 @@ class SieveClient:
def pushscript(self, name: str, content: str, active: bool = False) -> None:
if not self.msc.havespace(name, len(content)):
error = "%s (%s)" % (_("Not enough space on server"), self.msc.errmsg)
error = "{} ({})".format(_("Not enough space on server"), self.msc.errmsg)
raise SieveClientError(error)
if not self.msc.putscript(name, content):
raise SieveClientError(self.msc.errmsg.decode())
+5 -5
View File
@@ -82,25 +82,25 @@ def build_header(filename, disposition="attachment", filename_compat=None):
rv = disposition
if is_token(filename):
rv += "; filename=%s" % (filename,)
rv += f"; filename={filename}"
return rv
elif is_ascii(filename) and is_lws_safe(filename):
qd_filename = qd_quote(filename)
rv += '; filename="%s"' % (qd_filename,)
rv += f'; filename="{qd_filename}"'
if qd_filename == filename:
# RFC 6266 claims some implementations are iffy on qdtext's
# backslash-escaping, we'll include filename* in that case.
return rv
elif filename_compat:
if is_token(filename_compat):
rv += "; filename=%s" % (filename_compat,)
rv += f"; filename={filename_compat}"
else:
assert is_lws_safe(filename_compat)
rv += '; filename="%s"' % (qd_quote(filename_compat),)
rv += f'; filename="{qd_quote(filename_compat)}"'
# alnum are already considered always-safe, but the rest isn't.
# Python encodes ~ when it shouldn't, for example.
rv += "; filename*=utf-8''%s" % (
rv += "; filename*=utf-8''{}".format(
percent_encode(filename, safe=attr_chars_nonalnum, encoding="utf-8"),
)
+1 -1
View File
@@ -120,4 +120,4 @@ version = {attr = "modoboa.version.get_version"}
exclude = ["migrations"]
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "Q"]
select = ["E4", "E7", "E9", "F", "B", "Q", "UP"]