diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9e910923..14b4c400 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,14 +10,18 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] - django-version: ['2.2', '3.1', '3.2', 'main'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] + django-version: ['4.2', '5.0', '5.1', 'main'] exclude: # No such tox envs: - - {python-version: '3.7', django-version: 'main'} - - {python-version: '3.10', django-version: '2.2'} - - {python-version: '3.10', django-version: '3.1'} - - {python-version: '3.10', django-version: '3.2'} + - {python-version: '3.8', django-version: 'main'} + - {python-version: '3.9', django-version: 'main'} + - {python-version: '3.8', django-version: '5.0'} + - {python-version: '3.9', django-version: '5.0'} + - {python-version: '3.8', django-version: '5.1'} + - {python-version: '3.9', django-version: '5.1'} + - {python-version: '3.13', django-version: '4.2'} + - {python-version: '3.13', django-version: '5.0'} steps: - uses: actions/checkout@v2 diff --git a/CHANGES.rst b/CHANGES.rst index 389d676d..93b99c79 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,15 @@ Changes ======= +1.0(unreleased) +--------------- +- Drop support for Django <4.2 +- Drop support for Python <3.8 +- Add support for Django 4.2, 5.0, 5.1 +- Add support for Python 3.11, 3.12 +- Fix Compatibility issues with Django 5.1 + + 1.0b1 (unreleased) ------------------ - Add support for Django 3.1 diff --git a/README.rst b/README.rst index 784f8a33..b4f45331 100644 --- a/README.rst +++ b/README.rst @@ -54,7 +54,7 @@ soon as near-full coverage is reached. Compatibility ============= -Currently, django-newsletter officially supports Django 2.2.x LTS, 3.1.x and 3.2.x and Python 3.7 through 3.10. +Currently, django-newsletter officially supports Django 4.2.x LTS, 5.0.x and 5.1.x and Python 3.8 through 3.12. Requirements ============ diff --git a/newsletter/__init__.py b/newsletter/__init__.py index 6b350941..8ad5651d 100644 --- a/newsletter/__init__.py +++ b/newsletter/__init__.py @@ -1,7 +1,7 @@ -from pkg_resources import get_distribution, DistributionNotFound +from importlib.metadata import version, PackageNotFoundError try: - __version__ = get_distribution("django-newsletter").version -except DistributionNotFound: + __version__ = version("django-newsletter") +except PackageNotFoundError: # package is not installed __version__ = None diff --git a/newsletter/migrations/0009_alter_article_id_alter_attachment_id_and_more.py b/newsletter/migrations/0009_alter_article_id_alter_attachment_id_and_more.py new file mode 100644 index 00000000..63653e88 --- /dev/null +++ b/newsletter/migrations/0009_alter_article_id_alter_attachment_id_and_more.py @@ -0,0 +1,54 @@ +# Generated by Django 5.0.6 on 2024-05-08 15:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("newsletter", "0008_longer_subscription_name"), + ] + + operations = [ + migrations.AlterField( + model_name="article", + name="id", + field=models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + migrations.AlterField( + model_name="attachment", + name="id", + field=models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + migrations.AlterField( + model_name="message", + name="id", + field=models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + migrations.AlterField( + model_name="newsletter", + name="id", + field=models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + migrations.AlterField( + model_name="submission", + name="id", + field=models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + migrations.AlterField( + model_name="subscription", + name="id", + field=models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ] diff --git a/newsletter/models.py b/newsletter/models.py index 0e945555..a13f2ef3 100644 --- a/newsletter/models.py +++ b/newsletter/models.py @@ -1,4 +1,5 @@ import logging +import sys import os import time from datetime import datetime @@ -17,7 +18,7 @@ from django.utils.timezone import now from django.urls import reverse -from distutils.version import LooseVersion +# from distutils.version import LooseVersion from .fields import DynamicImageField from .utils import ( @@ -740,8 +741,11 @@ def get_absolute_url(self): def get_address(name, email): # Converting name to ascii for compatibility with django < 1.9. # Remove this when django 1.8 is no longer supported. - if LooseVersion(django.get_version()) < LooseVersion('1.9'): - name = name.encode('ascii', 'ignore').decode('ascii').strip() + # if LooseVersion(django.get_version()) < LooseVersion('1.9'): + # name = name.encode('ascii', 'ignore').decode('ascii').strip() + # Assuming django.get_version() returns a string like '1.8.18' + django_version = tuple(map(int, django.get_version().split('.'))) + name = name.encode('ascii', 'ignore').decode('ascii').strip() if django_version < (1, 9) else name if name: return f'{name} <{email}>' else: diff --git a/setup.py b/setup.py index 7bfb5ed4..0ad7d410 100755 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ ), long_description=README, install_requires=[ - "Django>=2.2.16", + "Django>=4.2", "python-card-me<1.0", "ldif3<3.2", "chardet", @@ -55,23 +55,24 @@ url='http://github.com/jazzband/django-newsletter/', packages=find_packages(exclude=("tests", "test_project")), include_package_data=True, - python_requires='>=3.7', + python_requires='>=3.8', classifiers=[ 'Development Status :: 6 - Mature', 'Environment :: Web Environment', 'Framework :: Django', - 'Framework :: Django :: 2.2', - 'Framework :: Django :: 3.1', - 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.2', + 'Framework :: Django :: 5.0', + 'Framework :: Django :: 5.2', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU Affero General Public License v3', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3 :: Only', 'Topic :: Utilities' ], diff --git a/tests/test_admin.py b/tests/test_admin.py index 6ae80fbf..fac5354e 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -315,7 +315,7 @@ def test_message_with_attachment_admin(self): change_url = reverse('admin:newsletter_message_change', args=(self.message_with_attachment.pk,)) response = self.client.get(change_url) - self.assertContains(response, '

Attachments

', html=True) + self.assertContains(response, 'tests/files/sample.txt', html=True) class MessageAdminTests(AdminTestMixin, TestCase): diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 00000000..8e9a3905 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,19 @@ +from django.test import TestCase +from importlib.metadata import version, PackageNotFoundError +from newsletter import __version__ + +class TestNewsletterInit(TestCase): + + def test_version(self): + try: + expected_version = version("django-newsletter") + except PackageNotFoundError: + expected_version = None + self.assertEqual(__version__, expected_version) + + def test_not_existing_version(self): + try: + expected_version = version("django-not-existing-newsletter") + except PackageNotFoundError: + expected_version = None + self.assertIsNone(expected_version) diff --git a/tests/test_validators.py b/tests/test_validators.py index 759ef330..9dce068f 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -15,7 +15,7 @@ def test_validate_email_nouser_noerror(self): def test_validate_email_nouser_error(self): """ Test validate_email_nouser where error is raised. """ User = get_user_model() - password = User.objects.make_random_password() + password = 'testpassword123' user = User.objects.create_user( 'john', 'lennon@thebeatles.com', password) user.save() diff --git a/tests/test_web.py b/tests/test_web.py index 5cfa771c..76443c48 100644 --- a/tests/test_web.py +++ b/tests/test_web.py @@ -582,7 +582,7 @@ def test_subscribe_request_post_existinguser_email(self): """ Post the subscription form without email shoud fail. """ User = get_user_model() - password = User.objects.make_random_password() + password = 'testpassword123' user = User.objects.create_user( 'john', 'lennon@thebeatles.com', password) user.save() @@ -781,7 +781,7 @@ def test_user_update(self): """ User = get_user_model() - password = User.objects.make_random_password() + password = 'testpassword123' user = User.objects.create_user( 'john', 'lennon@thebeatles.com', password) user.save() @@ -1055,7 +1055,7 @@ def test_update_request_post_existinguser_email(self): """ Post the update form without email shoud fail. """ User = get_user_model() - password = User.objects.make_random_password() + password = 'testpassword123' user = User.objects.create_user( 'john', 'lennon@thebeatles.com', password) user.save() diff --git a/tox.ini b/tox.ini index d00ab7d2..10870188 100644 --- a/tox.ini +++ b/tox.ini @@ -1,21 +1,21 @@ [tox] envlist = - py{37,38,39}-dj{22,31,32} - py{38,39,310}-djmain + py{38,39,310,311,312}-dj{42} + py{310,311,312}-dj{50} + py{310,311,312,313}-dj{51} + py{310,311,312,313}-djmain [testenv] deps = coverage django-imperavi - # TinyMCE above 3 doesn't support Python 3.5 anymore. - # TODO: Remove version freeze when Django 2.2 LTS support is dropped, early 2022. - django-tinymce<3 + django-tinymce pytz webtest django-webtest - dj22: Django>=2.2,<3.0 - dj31: Django>=3.1,<3.2 - dj32: Django>=3.2,<3.3 + dj42: Django>=4.2,<4.3 + dj50: Django>=5.0,<5.1 + dj51: Django>=5.1,<5.2 djmain: https://github.com/django/django/archive/main.tar.gz usedevelop = True ignore_outcome = @@ -30,14 +30,16 @@ setenv = [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 [gh-actions:env] DJANGO = - 2.2: dj22 - 3.1: dj31 - 3.2: dj32 + 4.2: dj42 + 5.0: dj50 + 5.1: dj51 main: djmain