diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index d8f34ed5d..2d5c2dab6 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -8,8 +8,8 @@ jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.x - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4f0befbf..aac499405 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install pypa/build diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f201b07ee..4738207b0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -52,9 +52,9 @@ jobs: -u${{ env.IMPORT_EXPORT_MYSQL_USER }} -p${{ env.IMPORT_EXPORT_MYSQL_PASSWORD }} - name: Check out repository code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies diff --git a/docs/changelog.rst b/docs/changelog.rst index 6920b1c50..977e0c752 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,11 @@ Changelog Version 4 introduces breaking changes. Please refer to :doc:`release notes`. +4.0.0-rc.4 (unreleased) +----------------------- + +- Removed support for django 3.2 (#1790) + 4.0.0-rc.3 (2024-04-13) ----------------------- diff --git a/import_export/admin.py b/import_export/admin.py index 2e39b5821..4c41b9a57 100644 --- a/import_export/admin.py +++ b/import_export/admin.py @@ -667,8 +667,7 @@ def get_export_queryset(self, request): "model_admin": self, "sortable_by": self.sortable_by, } - if django.VERSION >= (4, 0): - changelist_kwargs["search_help_text"] = self.search_help_text + changelist_kwargs["search_help_text"] = self.search_help_text class ExportChangeList(ChangeList): def get_results(self, request): diff --git a/pyproject.toml b/pyproject.toml index 22597bafe..db4c20d2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,6 @@ requires-python = ">=3.8" dynamic = ["version", "readme"] classifiers = [ "Framework :: Django", - "Framework :: Django :: 3.2", "Framework :: Django :: 4.2", "Framework :: Django :: 5.0", "Intended Audience :: Developers", diff --git a/tests/core/tests/admin_integration/test_import.py b/tests/core/tests/admin_integration/test_import.py index 2226c0475..b2d1cb595 100644 --- a/tests/core/tests/admin_integration/test_import.py +++ b/tests/core/tests/admin_integration/test_import.py @@ -4,7 +4,6 @@ from unittest import mock from unittest.mock import patch -import django from core.admin import AuthorAdmin, BookAdmin, CustomBookAdmin, ImportMixin from core.models import Author, Book, EBook, Parent from core.tests.admin_integration.mixins import AdminTestMixin @@ -162,19 +161,14 @@ def test_import_action_handles_UnicodeDecodeError_as_form_error(self): "'UnicodeDecodeError' encountered while trying to read file. " "Ensure you have chosen the correct format for the file." ) - # required for testing via tox - # remove after django 5.0 released - if django.VERSION >= (4, 0): - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - try: - self.assertFormError( - response.context["form"], "import_file", target_msg - ) - except TypeError: - self.assertFormError(response, "form", "import_file", target_msg) - else: - self.assertFormError(response, "form", "import_file", target_msg) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + try: + self.assertFormError( + response.context["form"], "import_file", target_msg + ) + except TypeError: + self.assertFormError(response, "form", "import_file", target_msg) def test_import_action_handles_ValueError_as_form_error(self): with mock.patch( @@ -188,19 +182,14 @@ def test_import_action_handles_ValueError_as_form_error(self): "Ensure you have chosen the correct format for the file." ) - # required for testing via tox - # remove after django 5.0 released - if django.VERSION >= (4, 0): - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - try: - self.assertFormError( - response.context["form"], "import_file", target_msg - ) - except TypeError: - self.assertFormError(response, "form", "import_file", target_msg) - else: - self.assertFormError(response, "form", "import_file", target_msg) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + try: + self.assertFormError( + response.context["form"], "import_file", target_msg + ) + except TypeError: + self.assertFormError(response, "form", "import_file", target_msg) def test_import_action_handles_FieldError(self): # issue 1722 @@ -226,19 +215,14 @@ def test_import_action_handles_ValueError_as_form_error_with_translation(self): "Asegúrese que seleccionó el formato correcto para el archivo." ) - # required for testing via tox - # remove after django 5.0 released - if django.VERSION >= (4, 0): - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - try: - self.assertFormError( - response.context["form"], "import_file", target_msg - ) - except TypeError: - self.assertFormError(response, "form", "import_file", target_msg) - else: - self.assertFormError(response, "form", "import_file", target_msg) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + try: + self.assertFormError( + response.context["form"], "import_file", target_msg + ) + except TypeError: + self.assertFormError(response, "form", "import_file", target_msg) def test_import_action_invalidates_data_sheet_with_no_headers_or_data(self): # GET the import form @@ -256,19 +240,14 @@ def test_import_action_invalidates_data_sheet_with_no_headers_or_data(self): "has the correct headers or data for import." ) - # required for testing via tox - # remove after django 5.0 released - if django.VERSION >= (4, 0): - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) - try: - self.assertFormError( - response.context["form"], "import_file", target_msg - ) - except TypeError: - self.assertFormError(response, "form", "import_file", target_msg) - else: - self.assertFormError(response, "form", "import_file", target_msg) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + try: + self.assertFormError( + response.context["form"], "import_file", target_msg + ) + except TypeError: + self.assertFormError(response, "form", "import_file", target_msg) @ignore_widget_deprecation_warning def test_delete_from_admin(self): diff --git a/tests/core/tests/test_widgets.py b/tests/core/tests/test_widgets.py index 2fa090294..241d28e8e 100644 --- a/tests/core/tests/test_widgets.py +++ b/tests/core/tests/test_widgets.py @@ -1,7 +1,7 @@ import json from datetime import date, datetime, time, timedelta from decimal import Decimal -from unittest import mock, skipUnless +from unittest import mock from unittest.mock import patch import django @@ -102,17 +102,6 @@ class FormatDatetimeTest(TestCase): target_dt = "02.08.0010" format = "%d.%m.%Y" - @skipUnless( - django.VERSION[0] < 4, f"skipping django {django.VERSION} version specific test" - ) - def test_format_datetime_lt_django4(self): - self.assertEqual( - self.target_dt, widgets.format_datetime(self.date, self.format) - ) - - @skipUnless( - django.VERSION[0] >= 4, f"running django {django.VERSION} version specific test" - ) def test_format_datetime_gte_django4(self): self.assertEqual( self.target_dt, widgets.format_datetime(self.date, self.format) @@ -383,17 +372,6 @@ def test_render_None_coerce_to_string_False(self): def test_render_invalid_type(self): self.assertEqual(self.widget.render("a"), "") - @skipUnless( - django.VERSION[0] < 4, f"skipping django {django.VERSION} version specific test" - ) - @override_settings(LANGUAGE_CODE="fr-fr", USE_L10N=True) - def test_locale_render_coerce_to_string_lt4(self): - self.assertEqual("11,111", self.widget_coerce_to_string.render(self.value)) - - @skipUnless( - django.VERSION[0] >= 4, - f"skipping django {django.VERSION} version specific test", - ) @override_settings(LANGUAGE_CODE="fr-fr") def test_locale_render_coerce_to_string_gte4(self): self.assertEqual("11,111", self.widget_coerce_to_string.render(self.value)) @@ -426,17 +404,6 @@ def test_clean_empty_string(self): self.assertEqual(self.widget.clean(" "), None) self.assertEqual(self.widget.clean("\r\n\t"), None) - @skipUnless( - django.VERSION[0] < 4, f"skipping django {django.VERSION} version specific test" - ) - @override_settings(LANGUAGE_CODE="fr-fr", USE_L10N=True) - def test_locale_render_coerce_to_string_lt4(self): - self.assertEqual(self.widget_coerce_to_string.render(self.value), "11,111") - - @skipUnless( - django.VERSION[0] >= 4, - f"skipping django {django.VERSION} version specific test", - ) @override_settings(LANGUAGE_CODE="fr-fr") def test_locale_render_coerce_to_string_gte4(self): self.assertEqual(self.widget_coerce_to_string.render(self.value), "11,111") @@ -470,17 +437,6 @@ def test_clean_empty_string(self): self.assertEqual(self.widget.clean(" "), None) self.assertEqual(self.widget.clean("\r\n\t"), None) - @skipUnless( - django.VERSION[0] < 4, f"skipping django {django.VERSION} version specific test" - ) - @override_settings(LANGUAGE_CODE="fr-fr", USE_L10N=True) - def test_locale_render_coerce_to_string_lt4(self): - self.assertEqual(self.widget.render(self.value), "11,111") - - @skipUnless( - django.VERSION[0] >= 4, - f"skipping django {django.VERSION} version specific test", - ) @override_settings(LANGUAGE_CODE="fr-fr") def test_locale_render_coerce_to_string_gte4(self): self.assertEqual(self.widget.render(self.value), "11,111") @@ -511,17 +467,6 @@ def test_clean_empty_string(self): def test_render_invalid_type(self): self.assertEqual(self.widget.render("a"), "") - @skipUnless( - django.VERSION[0] < 4, f"skipping django {django.VERSION} version specific test" - ) - @override_settings(LANGUAGE_CODE="fr-fr", USE_L10N=True) - def test_locale_render_lt_django4(self): - self.assertEqual(self.widget_coerce_to_string.render(self.value), "0") - - @skipUnless( - django.VERSION[0] >= 4, - f"skipping django {django.VERSION} version specific test", - ) @override_settings(LANGUAGE_CODE="fr-fr") def test_locale_render_gte_django4(self): self.assertEqual(self.widget_coerce_to_string.render(self.value), "0") diff --git a/tox.ini b/tox.ini index 7f65d7376..1c77412dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] min_version = 4.0 envlist = - {py38,py39,py310}-{django32} + {py38,py39}-{django42} {py310,py311,py312}-{django42,django50,djangomain} # tablib dev temporarily removed - see issue #1602 # py311-djangomain-tablibdev @@ -19,8 +19,7 @@ setenv = PYTHONPATH = {toxinidir}/tests commands = python ./runtests.py deps = tablibdev: -egit+https://github.com/jazzband/tablib.git@master\#egg=tablib - django32: Django>=3.2,<4.0 - django42: Django>=4.2,<4.3 + django42: Django>=4.2,<5.0 django50: Django>=5.0,<6.0 djangomain: https://github.com/django/django/archive/main.tar.gz -rrequirements/test.txt