diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4502f3ed..7b162202 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,16 @@ jobs: - uses: chartboost/ruff-action@v1 with: version: 0.4.8 - args: 'format --check' + args: 'format --check' + + ruff-lint: + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + with: + version: 0.4.8 build: runs-on: ubuntu-latest diff --git a/post_office/__init__.py b/post_office/__init__.py index b7343d6d..9fdfdb4b 100644 --- a/post_office/__init__.py +++ b/post_office/__init__.py @@ -1,5 +1,6 @@ from ast import literal_eval -from os.path import dirname, join +from os.path import dirname +from os.path import join with open(join(dirname(__file__), 'version.txt')) as fh: VERSION = literal_eval(fh.read()) diff --git a/post_office/admin.py b/post_office/admin.py index 41dea32f..3e9964c6 100644 --- a/post_office/admin.py +++ b/post_office/admin.py @@ -2,21 +2,30 @@ from django import forms from django.conf import settings -from django.contrib import admin, messages +from django.contrib import admin +from django.contrib import messages from django.core.exceptions import ValidationError from django.core.mail.message import SafeMIMEText from django.db import models from django.forms import BaseInlineFormSet from django.forms.widgets import TextInput -from django.http.response import HttpResponse, HttpResponseNotFound, HttpResponseRedirect -from django.template import Context, Template -from django.urls import re_path, reverse +from django.http.response import HttpResponse +from django.http.response import HttpResponseNotFound +from django.http.response import HttpResponseRedirect +from django.template import Context +from django.template import Template +from django.urls import re_path +from django.urls import reverse from django.utils.html import format_html from django.utils.text import Truncator from django.utils.translation import gettext_lazy as _ from .fields import CommaSeparatedEmailField -from .models import STATUS, Attachment, Email, EmailTemplate, Log +from .models import STATUS +from .models import Attachment +from .models import Email +from .models import EmailTemplate +from .models import Log from .sanitizer import clean_html diff --git a/post_office/backends.py b/post_office/backends.py index b93e49f9..b7dad943 100644 --- a/post_office/backends.py +++ b/post_office/backends.py @@ -1,7 +1,9 @@ from collections import OrderedDict from email.mime.base import MIMEBase + from django.core.files.base import ContentFile from django.core.mail.backends.base import BaseEmailBackend + from .settings import get_default_priority @@ -18,9 +20,10 @@ def send_messages(self, email_messages): email messages sent. """ from .mail import create - from .models import STATUS, Email - from .utils import create_attachments + from .models import STATUS + from .models import Email from .signals import email_queued + from .utils import create_attachments if not email_messages: return diff --git a/post_office/mail.py b/post_office/mail.py index 6a7db7d6..ad7617c5 100644 --- a/post_office/mail.py +++ b/post_office/mail.py @@ -1,37 +1,41 @@ +from email.utils import make_msgid +from multiprocessing import Pool +from multiprocessing.dummy import Pool as ThreadPool + from django.conf import settings from django.core.exceptions import ValidationError from django.db import connection as db_connection from django.db.models import Q -from django.template import Context, Template +from django.template import Context +from django.template import Template from django.utils import timezone -from email.utils import make_msgid -from multiprocessing import Pool -from multiprocessing.dummy import Pool as ThreadPool from .connections import connections -from .lockfile import default_lockfile, FileLock, FileLocked +from .lockfile import FileLock +from .lockfile import FileLocked +from .lockfile import default_lockfile from .logutils import setup_loghandlers -from .models import Email, EmailTemplate, Log, PRIORITY, STATUS -from .settings import ( - get_available_backends, - get_batch_delivery_timeout, - get_batch_size, - get_log_level, - get_max_retries, - get_message_id_enabled, - get_message_id_fqdn, - get_retry_timedelta, - get_sending_order, - get_threads_per_process, -) +from .models import PRIORITY +from .models import STATUS +from .models import Email +from .models import EmailTemplate +from .models import Log +from .settings import get_available_backends +from .settings import get_batch_delivery_timeout +from .settings import get_batch_size +from .settings import get_log_level +from .settings import get_max_retries +from .settings import get_message_id_enabled +from .settings import get_message_id_fqdn +from .settings import get_retry_timedelta +from .settings import get_sending_order +from .settings import get_threads_per_process from .signals import email_queued -from .utils import ( - create_attachments, - get_email_template, - parse_emails, - parse_priority, - split_emails, -) +from .utils import create_attachments +from .utils import get_email_template +from .utils import parse_emails +from .utils import parse_priority +from .utils import split_emails logger = setup_loghandlers('INFO') diff --git a/post_office/migrations/0001_initial.py b/post_office/migrations/0001_initial.py index ff7fcd38..4b2611dc 100644 --- a/post_office/migrations/0001_initial.py +++ b/post_office/migrations/0001_initial.py @@ -1,8 +1,9 @@ -from django.db import models, migrations +from django.db import migrations +from django.db import models import post_office.fields -import post_office.validators import post_office.models +import post_office.validators class Migration(migrations.Migration): diff --git a/post_office/migrations/0002_add_i18n_and_backend_alias.py b/post_office/migrations/0002_add_i18n_and_backend_alias.py index be8c2177..b350863f 100644 --- a/post_office/migrations/0002_add_i18n_and_backend_alias.py +++ b/post_office/migrations/0002_add_i18n_and_backend_alias.py @@ -1,6 +1,8 @@ -from django.db import models, migrations -import post_office.validators +from django.db import migrations +from django.db import models + import post_office.fields +import post_office.validators class Migration(migrations.Migration): diff --git a/post_office/migrations/0003_longer_subject.py b/post_office/migrations/0003_longer_subject.py index a63a2f9e..196676e4 100644 --- a/post_office/migrations/0003_longer_subject.py +++ b/post_office/migrations/0003_longer_subject.py @@ -1,5 +1,6 @@ # Generated by Django 1.9 on 2016-02-04 08:08 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/post_office/migrations/0004_auto_20160607_0901.py b/post_office/migrations/0004_auto_20160607_0901.py index 6b31a287..8567d9ac 100644 --- a/post_office/migrations/0004_auto_20160607_0901.py +++ b/post_office/migrations/0004_auto_20160607_0901.py @@ -1,6 +1,7 @@ # Generated by Django 1.9.6 on 2016-06-07 07:01 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations +from django.db import models import post_office.models diff --git a/post_office/migrations/0006_attachment_mimetype.py b/post_office/migrations/0006_attachment_mimetype.py index f217cbe3..74e273be 100644 --- a/post_office/migrations/0006_attachment_mimetype.py +++ b/post_office/migrations/0006_attachment_mimetype.py @@ -1,4 +1,5 @@ -from django.db import models, migrations +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/post_office/migrations/0008_attachment_headers.py b/post_office/migrations/0008_attachment_headers.py index 44d18969..ece8f9ad 100644 --- a/post_office/migrations/0008_attachment_headers.py +++ b/post_office/migrations/0008_attachment_headers.py @@ -1,5 +1,6 @@ # Generated by Django 1.11.16 on 2018-11-30 08:54 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/post_office/migrations/0009_requeued_mode.py b/post_office/migrations/0009_requeued_mode.py index c877fc32..b1f941f7 100644 --- a/post_office/migrations/0009_requeued_mode.py +++ b/post_office/migrations/0009_requeued_mode.py @@ -1,6 +1,7 @@ # Generated by Django 2.2.11 on 2020-05-10 08:59 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/post_office/migrations/0010_message_id.py b/post_office/migrations/0010_message_id.py index f7966143..2a76607b 100644 --- a/post_office/migrations/0010_message_id.py +++ b/post_office/migrations/0010_message_id.py @@ -1,8 +1,11 @@ import random -from django.db import migrations, models + +from django.db import migrations +from django.db import models from post_office.models import STATUS -from post_office.settings import get_message_id_enabled, get_message_id_fqdn +from post_office.settings import get_message_id_enabled +from post_office.settings import get_message_id_fqdn def forwards(apps, schema_editor): diff --git a/post_office/migrations/0011_models_help_text.py b/post_office/migrations/0011_models_help_text.py index e4426913..d94bc0e8 100644 --- a/post_office/migrations/0011_models_help_text.py +++ b/post_office/migrations/0011_models_help_text.py @@ -1,6 +1,7 @@ # Generated by Django 3.0.10 on 2020-11-02 22:48 -from django.db import migrations, models +from django.db import migrations +from django.db import models class Migration(migrations.Migration): diff --git a/post_office/models.py b/post_office/models.py index aece7604..c6c25097 100644 --- a/post_office/models.py +++ b/post_office/models.py @@ -1,24 +1,28 @@ import os - from collections import namedtuple -from uuid import uuid4 from email.mime.nonmultipart import MIMENonMultipart +from uuid import uuid4 from django.core.exceptions import ValidationError -from django.core.mail import EmailMessage, EmailMultiAlternatives +from django.core.mail import EmailMessage +from django.core.mail import EmailMultiAlternatives from django.db import models -from django.utils.encoding import smart_str -from django.utils.translation import pgettext_lazy, gettext_lazy as _ from django.utils import timezone +from django.utils.encoding import smart_str +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import pgettext_lazy from post_office import cache from post_office.fields import CommaSeparatedEmailField from .connections import connections from .logutils import setup_loghandlers -from .settings import context_field_class, get_log_level, get_template_engine, get_override_recipients -from .validators import validate_email_with_name, validate_template_syntax - +from .settings import context_field_class +from .settings import get_log_level +from .settings import get_override_recipients +from .settings import get_template_engine +from .validators import validate_email_with_name +from .validators import validate_template_syntax logger = setup_loghandlers('INFO') diff --git a/post_office/sanitizer.py b/post_office/sanitizer.py index 71ed49df..19b5e285 100644 --- a/post_office/sanitizer.py +++ b/post_office/sanitizer.py @@ -1,4 +1,5 @@ -from django.utils.html import mark_safe, format_html +from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.translation import gettext_lazy try: diff --git a/post_office/settings.py b/post_office/settings.py index 25b4c3c2..c415ba43 100644 --- a/post_office/settings.py +++ b/post_office/settings.py @@ -1,3 +1,4 @@ +import datetime import warnings from django.conf import settings @@ -5,11 +6,8 @@ from django.core.cache.backends.base import InvalidCacheBackendError from django.core.mail.utils import DNS_NAME from django.template import engines as template_engines - from django.utils.module_loading import import_string -import datetime - def get_backend(alias='default'): return get_available_backends()[alias] diff --git a/post_office/template/__init__.py b/post_office/template/__init__.py index a8cb0d5e..d956cfc0 100644 --- a/post_office/template/__init__.py +++ b/post_office/template/__init__.py @@ -1,4 +1,5 @@ -from django.template.loader import get_template, select_template +from django.template.loader import get_template +from django.template.loader import select_template def render_to_string(template_name, context=None, request=None, using=None): diff --git a/post_office/template/backends/post_office.py b/post_office/template/backends/post_office.py index 5fd4ae2d..206a3e34 100644 --- a/post_office/template/backends/post_office.py +++ b/post_office/template/backends/post_office.py @@ -2,7 +2,9 @@ from django.core.mail import EmailMultiAlternatives from django.template import TemplateDoesNotExist from django.template.backends.base import BaseEngine -from django.template.backends.django import Template as DjangoTemplate, reraise, get_installed_libraries +from django.template.backends.django import Template as DjangoTemplate +from django.template.backends.django import get_installed_libraries +from django.template.backends.django import reraise from django.template.engine import Engine diff --git a/post_office/templatetags/post_office.py b/post_office/templatetags/post_office.py index f5068188..7f9e8799 100644 --- a/post_office/templatetags/post_office.py +++ b/post_office/templatetags/post_office.py @@ -1,6 +1,6 @@ -from email.mime.image import MIMEImage import hashlib import os +from email.mime.image import MIMEImage from django import template from django.conf import settings diff --git a/post_office/tests/__init__.py b/post_office/tests/__init__.py index f682b8bb..e5923baf 100644 --- a/post_office/tests/__init__.py +++ b/post_office/tests/__init__.py @@ -1,8 +1,8 @@ from .test_backends import BackendTest +from .test_cache import CacheTest from .test_commands import CommandTest from .test_lockfile import LockTest from .test_mail import MailTest from .test_models import ModelTest from .test_utils import UtilsTest -from .test_cache import CacheTest from .test_views import AdminViewTest diff --git a/post_office/tests/test_backends.py b/post_office/tests/test_backends.py index e19b2116..c574c8b9 100644 --- a/post_office/tests/test_backends.py +++ b/post_office/tests/test_backends.py @@ -4,12 +4,16 @@ from django.conf import settings from django.core.files.images import File -from django.core.mail import EmailMultiAlternatives, send_mail, EmailMessage +from django.core.mail import EmailMessage +from django.core.mail import EmailMultiAlternatives +from django.core.mail import send_mail from django.core.mail.backends.base import BaseEmailBackend from django.test import TestCase from django.test.utils import override_settings -from ..models import Email, STATUS, PRIORITY +from ..models import PRIORITY +from ..models import STATUS +from ..models import Email from ..settings import get_backend diff --git a/post_office/tests/test_cache.py b/post_office/tests/test_cache.py index 9356e5cd..c8307c44 100644 --- a/post_office/tests/test_cache.py +++ b/post_office/tests/test_cache.py @@ -2,6 +2,7 @@ from django.test import TestCase from post_office import cache + from ..settings import get_cache_backend diff --git a/post_office/tests/test_commands.py b/post_office/tests/test_commands.py index e5322ec5..9e41b9a9 100644 --- a/post_office/tests/test_commands.py +++ b/post_office/tests/test_commands.py @@ -7,7 +7,9 @@ from django.test.utils import override_settings from django.utils.timezone import now -from ..models import Attachment, Email, STATUS +from ..models import STATUS +from ..models import Attachment +from ..models import Email class CommandTest(TestCase): diff --git a/post_office/tests/test_connections.py b/post_office/tests/test_connections.py index 3ed7110f..3f0bfa6d 100644 --- a/post_office/tests/test_connections.py +++ b/post_office/tests/test_connections.py @@ -1,8 +1,8 @@ from django.core.mail import backends from django.test import TestCase -from .test_backends import ErrorRaisingBackend from ..connections import connections +from .test_backends import ErrorRaisingBackend class ConnectionTest(TestCase): diff --git a/post_office/tests/test_forms.py b/post_office/tests/test_forms.py index 29a3d825..ab62edaa 100644 --- a/post_office/tests/test_forms.py +++ b/post_office/tests/test_forms.py @@ -1,11 +1,11 @@ -from django.forms import formset_factory -from django.test import TestCase, Client from django.contrib.auth import get_user_model +from django.forms import formset_factory +from django.test import Client +from django.test import TestCase from django.urls import reverse from post_office.admin import EmailTemplateAdminForm - User = get_user_model() diff --git a/post_office/tests/test_html_email.py b/post_office/tests/test_html_email.py index 507a4fbd..40022895 100644 --- a/post_office/tests/test_html_email.py +++ b/post_office/tests/test_html_email.py @@ -2,18 +2,23 @@ from email.mime.image import MIMEImage from django.contrib.auth import get_user_model -from django.core.mail import EmailMultiAlternatives -from django.core.mail.message import SafeMIMEMultipart, SafeMIMEText from django.core.files.images import ImageFile +from django.core.mail import EmailMultiAlternatives +from django.core.mail.message import SafeMIMEMultipart +from django.core.mail.message import SafeMIMEText from django.template.loader import get_template -from django.test import Client, TestCase +from django.test import Client +from django.test import TestCase from django.test.utils import override_settings from django.urls import reverse -from post_office.models import Email, EmailTemplate, STATUS +from post_office.mail import send +from post_office.mail import send_queued +from post_office.models import STATUS +from post_office.models import Email +from post_office.models import EmailTemplate from post_office.template import render_to_string from post_office.template.backends.post_office import PostOfficeTemplates -from post_office.mail import send, send_queued class HTMLMailTest(TestCase): diff --git a/post_office/tests/test_lockfile.py b/post_office/tests/test_lockfile.py index de16efda..bc275901 100644 --- a/post_office/tests/test_lockfile.py +++ b/post_office/tests/test_lockfile.py @@ -1,9 +1,10 @@ -import time import os +import time from django.test import TestCase -from ..lockfile import FileLock, FileLocked +from ..lockfile import FileLock +from ..lockfile import FileLocked def setup_fake_lock(lock_file_name): diff --git a/post_office/tests/test_mail.py b/post_office/tests/test_mail.py index 22be6dea..f3cfa660 100644 --- a/post_office/tests/test_mail.py +++ b/post_office/tests/test_mail.py @@ -13,9 +13,22 @@ from django.test.utils import override_settings from django.utils import timezone -from ..mail import _send_bulk, create, get_queued, send, send_many, send_queued -from ..models import PRIORITY, STATUS, Attachment, Email, EmailTemplate -from ..settings import get_batch_size, get_log_level, get_max_retries, get_retry_timedelta, get_threads_per_process +from ..mail import _send_bulk +from ..mail import create +from ..mail import get_queued +from ..mail import send +from ..mail import send_many +from ..mail import send_queued +from ..models import PRIORITY +from ..models import STATUS +from ..models import Attachment +from ..models import Email +from ..models import EmailTemplate +from ..settings import get_batch_size +from ..settings import get_log_level +from ..settings import get_max_retries +from ..settings import get_retry_timedelta +from ..settings import get_threads_per_process connection_counter = 0 diff --git a/post_office/tests/test_models.py b/post_office/tests/test_models.py index c4bb30ed..d9fe88a0 100644 --- a/post_office/tests/test_models.py +++ b/post_office/tests/test_models.py @@ -1,19 +1,26 @@ import json import os +from datetime import datetime +from datetime import timedelta -from datetime import datetime, timedelta - -from django.conf import settings as django_settings, settings +from django.conf import settings +from django.conf import settings as django_settings from django.core import mail from django.core import serializers from django.core.files.base import ContentFile -from django.core.mail import EmailMessage, EmailMultiAlternatives +from django.core.mail import EmailMessage +from django.core.mail import EmailMultiAlternatives from django.forms.models import modelform_factory from django.test import TestCase from django.utils import timezone -from ..models import Email, Log, PRIORITY, STATUS, EmailTemplate, Attachment from ..mail import send +from ..models import PRIORITY +from ..models import STATUS +from ..models import Attachment +from ..models import Email +from ..models import EmailTemplate +from ..models import Log class ModelTest(TestCase): diff --git a/post_office/tests/test_utils.py b/post_office/tests/test_utils.py index 38f589f4..3d866d91 100644 --- a/post_office/tests/test_utils.py +++ b/post_office/tests/test_utils.py @@ -1,12 +1,21 @@ -from django.core.files.base import ContentFile from django.core.exceptions import ValidationError - +from django.core.files.base import ContentFile from django.test import TestCase from django.test.utils import override_settings -from ..models import Email, STATUS, PRIORITY, EmailTemplate, Attachment -from ..utils import create_attachments, get_email_template, parse_emails, parse_priority, send_mail, split_emails -from ..validators import validate_email_with_name, validate_comma_separated_emails +from ..models import PRIORITY +from ..models import STATUS +from ..models import Attachment +from ..models import Email +from ..models import EmailTemplate +from ..utils import create_attachments +from ..utils import get_email_template +from ..utils import parse_emails +from ..utils import parse_priority +from ..utils import send_mail +from ..utils import split_emails +from ..validators import validate_comma_separated_emails +from ..validators import validate_email_with_name @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend') diff --git a/post_office/tests/test_views.py b/post_office/tests/test_views.py index 9bf9d43d..37e7a3c8 100644 --- a/post_office/tests/test_views.py +++ b/post_office/tests/test_views.py @@ -1,12 +1,11 @@ from django.contrib.auth.models import User -from django.test.client import Client from django.test import TestCase +from django.test.client import Client from django.urls import reverse from post_office import mail from post_office.models import Email - admin_username = 'real_test_admin' admin_email = 'read@admin.com' admin_pass = 'admin_pass' diff --git a/post_office/utils.py b/post_office/utils.py index 9c5321cb..68269d90 100644 --- a/post_office/utils.py +++ b/post_office/utils.py @@ -4,7 +4,12 @@ from django.utils.encoding import force_str from post_office import cache -from .models import Email, PRIORITY, STATUS, EmailTemplate, Attachment + +from .models import PRIORITY +from .models import STATUS +from .models import Attachment +from .models import Email +from .models import EmailTemplate from .settings import get_default_priority from .signals import email_queued from .validators import validate_email_with_name diff --git a/post_office/validators.py b/post_office/validators.py index 9c3ffd59..2157b5fe 100644 --- a/post_office/validators.py +++ b/post_office/validators.py @@ -1,6 +1,8 @@ from django.core.exceptions import ValidationError from django.core.validators import validate_email -from django.template import Template, TemplateSyntaxError, TemplateDoesNotExist +from django.template import Template +from django.template import TemplateDoesNotExist +from django.template import TemplateSyntaxError from django.utils.encoding import force_str diff --git a/pyproject.toml b/pyproject.toml index fa8051a5..210b0e5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,3 +8,11 @@ quote-style = "single" indent-style = "space" skip-magic-trailing-comma = false line-ending = "auto" + +[tool.ruff.lint] +select = [ + "I", +] + +[tool.ruff.lint.isort] +force-single-line = true \ No newline at end of file diff --git a/setup.py b/setup.py index d697ca6e..d94a3b96 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,8 @@ -from ast import literal_eval import sys -from os.path import dirname, join +from ast import literal_eval +from os.path import dirname +from os.path import join + from setuptools import setup from setuptools.command.test import test as TestCommand @@ -17,9 +19,10 @@ def finalize_options(self): def run_tests(self): # import here, cause outside the eggs aren't loaded - import tox import shlex + import tox + args = self.tox_args if args: args = shlex.split(self.tox_args)