Merge pull request #443 from JuroOravec/jo-drop-support-django-32-40-41

This commit is contained in:
Juro Oravec 2024-04-19 09:41:35 +02:00 committed by GitHub
commit be4b1f1a02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 95 additions and 84 deletions

View file

@ -144,10 +144,10 @@ Django-components supports all supported combinations versions of [Django](https
| Python version | Django version | | Python version | Django version |
|----------------|--------------------------| |----------------|--------------------------|
| 3.8 | 3.2, 4.0, 4.1, 4.2 | | 3.8 | 4.2 |
| 3.9 | 3.2, 4.0, 4.1, 4.2 | | 3.9 | 4.2 |
| 3.10 | 3.2, 4.0, 4.1, 4.2, 5.0 | | 3.10 | 4.2, 5.0 |
| 3.11 | 4.1, 4.2, 5.0 | | 3.11 | 4.2, 5.0 |
| 3.12 | 4.2, 5.0 | | 3.12 | 4.2, 5.0 |
## Create your first component ## Create your first component

View file

@ -6,8 +6,7 @@ from django.test import override_settings
from django_components import component from django_components import component
from django_components.middleware import CSS_DEPENDENCY_PLACEHOLDER, JS_DEPENDENCY_PLACEHOLDER from django_components.middleware import CSS_DEPENDENCY_PLACEHOLDER, JS_DEPENDENCY_PLACEHOLDER
from tests.django_test_setup import * # NOQA from tests.django_test_setup import * # NOQA
from tests.testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from tests.testutils import BaseTestCase, create_and_process_template_response
from tests.testutils import create_and_process_template_response
class SlottedComponent(component.Component): class SlottedComponent(component.Component):
@ -67,7 +66,7 @@ EXPECTED_JS = """<script src="test.js"></script>"""
@override_settings(COMPONENTS={"RENDER_DEPENDENCIES": True}) @override_settings(COMPONENTS={"RENDER_DEPENDENCIES": True})
class RenderBenchmarks(SimpleTestCase): class RenderBenchmarks(BaseTestCase):
def setUp(self): def setUp(self):
component.registry.clear() component.registry.clear()
component.registry.register("test_component", SlottedComponent) component.registry.register("test_component", SlottedComponent)

View file

@ -14,9 +14,6 @@ authors = [
] ]
classifiers = [ classifiers = [
"Framework :: Django", "Framework :: Django",
"Framework :: Django :: 3.2",
"Framework :: Django :: 4.0",
"Framework :: Django :: 4.1",
"Framework :: Django :: 4.2", "Framework :: Django :: 4.2",
"Framework :: Django :: 5.0", "Framework :: Django :: 5.0",
"Operating System :: OS Independent", "Operating System :: OS Independent",
@ -29,7 +26,7 @@ classifiers = [
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",
] ]
dependencies = [ dependencies = [
'Django>=3.2', 'Django>=4.2',
] ]
license = {text = "MIT"} license = {text = "MIT"}

View file

@ -1,7 +1,7 @@
import re import re
import textwrap import textwrap
from collections import defaultdict from collections import defaultdict
from typing import Dict, List, Tuple from typing import Any, Callable, Dict, List, Tuple
from urllib import request from urllib import request
Version = Tuple[int, ...] Version = Tuple[int, ...]
@ -37,7 +37,7 @@ def get_python_supported_version(url: str) -> list[Version]:
return parse_supported_versions(content) return parse_supported_versions(content)
def get_supported_versions(url: str): def get_django_to_pythoon_versions(url: str):
with request.urlopen(url) as response: with request.urlopen(url) as response:
response_content = response.read() response_content = response.read()
@ -66,6 +66,32 @@ def get_supported_versions(url: str):
return parse_supported_versions(content) return parse_supported_versions(content)
def get_django_supported_versions(url: str) -> List[Tuple[int, ...]]:
"""Extract Django versions from the HTML content, e.g. `5.0` or `4.2`"""
with request.urlopen(url) as response:
response_content = response.read()
content = response_content.decode("utf-8")
content = cut_by_content(
content,
"<table class='django-supported-versions'>",
"</table>",
)
rows = re.findall(r"<tr>(.*?)</tr>", content.replace("\n", " "))
versions: List[Tuple[int, ...]] = []
# NOTE: Skip first row as that's headers
for row in rows[1:]:
data: List[str] = re.findall(r"<td>(.*?)</td>", row)
# NOTE: First column is version like `5.0` or `4.2 LTS`
version_with_test = data[0]
version = version_with_test.split(" ")[0]
version_tuple = tuple(map(int, version.split(".")))
versions.append(version_tuple)
return versions
def get_latest_version(url: str): def get_latest_version(url: str):
with request.urlopen(url) as response: with request.urlopen(url) as response:
response_content = response.read() response_content = response.read()
@ -200,14 +226,20 @@ def build_ci_python_versions(python_to_django: Dict[str, str]):
return lines_formatted return lines_formatted
def filter_dict(d: Dict, filter_fn: Callable[[Any], bool]):
return dict(filter(filter_fn, d.items()))
def main(): def main():
active_python = get_python_supported_version("https://devguide.python.org/versions/") active_python = get_python_supported_version("https://devguide.python.org/versions/")
django_to_python = get_supported_versions("https://docs.djangoproject.com/en/dev/faq/install/") django_to_python = get_django_to_pythoon_versions("https://docs.djangoproject.com/en/dev/faq/install/")
django_supported_versions = get_django_supported_versions("https://www.djangoproject.com/download/")
latest_version = get_latest_version("https://www.djangoproject.com/download/") latest_version = get_latest_version("https://www.djangoproject.com/download/")
python_to_django = build_python_to_django(django_to_python, latest_version) supported_django_to_python = filter_dict(django_to_python, lambda item: item[0] in django_supported_versions)
python_to_django = build_python_to_django(supported_django_to_python, latest_version)
python_to_django = dict(filter(lambda item: item[0] in active_python, python_to_django.items())) python_to_django = filter_dict(python_to_django, lambda item: item[0] in active_python)
tox_envlist = build_tox_envlist(python_to_django) tox_envlist = build_tox_envlist(python_to_django)
print("Add this to tox.ini:\n") print("Add this to tox.ini:\n")

View file

@ -6,7 +6,7 @@ from django.urls import include, path
# isort: off # isort: off
from .django_test_setup import settings from .django_test_setup import settings
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase
# isort: on # isort: on
@ -18,7 +18,7 @@ urlpatterns = [
] ]
class TestAutodiscover(SimpleTestCase): class TestAutodiscover(BaseTestCase):
def setUp(self): def setUp(self):
settings.SETTINGS_MODULE = "tests.test_autodiscover" # noqa settings.SETTINGS_MODULE = "tests.test_autodiscover" # noqa
@ -38,7 +38,7 @@ class TestAutodiscover(SimpleTestCase):
self.assertEqual(imported_components_count, 1) self.assertEqual(imported_components_count, 1)
class TestLoaderSettingsModule(SimpleTestCase): class TestLoaderSettingsModule(BaseTestCase):
def tearDown(self) -> None: def tearDown(self) -> None:
del settings.SETTINGS_MODULE # noqa del settings.SETTINGS_MODULE # noqa
@ -106,7 +106,7 @@ class TestLoaderSettingsModule(SimpleTestCase):
) )
class TestBaseDir(SimpleTestCase): class TestBaseDir(BaseTestCase):
def setUp(self): def setUp(self):
settings.BASE_DIR = Path(__file__).parent.resolve() / "test_structures" / "test_structure_1" # noqa settings.BASE_DIR = Path(__file__).parent.resolve() / "test_structures" / "test_structure_1" # noqa
settings.SETTINGS_MODULE = "tests_fake.test_autodiscover_fake" # noqa settings.SETTINGS_MODULE = "tests_fake.test_autodiscover_fake" # noqa
@ -125,7 +125,7 @@ class TestBaseDir(SimpleTestCase):
self.assertEqual(sorted(dirs), sorted(expected)) self.assertEqual(sorted(dirs), sorted(expected))
class TestFilepathToPythonModule(SimpleTestCase): class TestFilepathToPythonModule(BaseTestCase):
def test_prepares_path(self): def test_prepares_path(self):
self.assertEqual( self.assertEqual(
_filepath_to_python_module(Path("tests.py")), _filepath_to_python_module(Path("tests.py")),

View file

@ -8,14 +8,14 @@ from django.test import override_settings
# isort: off # isort: off
from .django_test_setup import * # NOQA from .django_test_setup import * # NOQA
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase
# isort: on # isort: on
from django_components import component from django_components import component
class ComponentTest(SimpleTestCase): class ComponentTest(BaseTestCase):
def test_empty_component(self): def test_empty_component(self):
class EmptyComponent(component.Component): class EmptyComponent(component.Component):
pass pass
@ -260,7 +260,7 @@ class ComponentTest(SimpleTestCase):
) )
class InlineComponentTest(SimpleTestCase): class InlineComponentTest(BaseTestCase):
def test_inline_html_component(self): def test_inline_html_component(self):
class InlineHTMLComponent(component.Component): class InlineHTMLComponent(component.Component):
template = "<div class='inline'>Hello Inline</div>" template = "<div class='inline'>Hello Inline</div>"
@ -382,7 +382,7 @@ class InlineComponentTest(SimpleTestCase):
) )
class ComponentMediaTests(SimpleTestCase): class ComponentMediaTests(BaseTestCase):
def test_component_media_with_strings(self): def test_component_media_with_strings(self):
class SimpleComponent(component.Component): class SimpleComponent(component.Component):
class Media: class Media:
@ -491,7 +491,7 @@ class ComponentMediaTests(SimpleTestCase):
) )
class ComponentIsolationTests(SimpleTestCase): class ComponentIsolationTests(BaseTestCase):
def setUp(self): def setUp(self):
class SlottedComponent(component.Component): class SlottedComponent(component.Component):
template_name = "slotted_template.html" template_name = "slotted_template.html"
@ -539,7 +539,7 @@ class ComponentIsolationTests(SimpleTestCase):
) )
class SlotBehaviorTests(SimpleTestCase): class SlotBehaviorTests(BaseTestCase):
def setUp(self): def setUp(self):
class SlottedComponent(component.Component): class SlottedComponent(component.Component):
template_name = "slotted_template.html" template_name = "slotted_template.html"

View file

@ -7,7 +7,7 @@ from django.urls import include, path
# isort: off # isort: off
from .django_test_setup import * # noqa from .django_test_setup import * # noqa
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase
# isort: on # isort: on
@ -110,7 +110,7 @@ class CustomClient(Client):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
class TestComponentAsView(SimpleTestCase): class TestComponentAsView(BaseTestCase):
def setUp(self): def setUp(self):
self.client = CustomClient() self.client = CustomClient()

View file

@ -6,7 +6,7 @@ from django.test import override_settings
from django_components import component from django_components import component
from .django_test_setup import * # NOQA from .django_test_setup import * # NOQA
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase
class SimpleComponent(component.Component): class SimpleComponent(component.Component):
@ -77,7 +77,7 @@ component.registry.register(name="simple_component", component=SimpleComponent)
component.registry.register(name="outer_context_component", component=OuterContextComponent) component.registry.register(name="outer_context_component", component=OuterContextComponent)
class ContextTests(SimpleTestCase): class ContextTests(BaseTestCase):
def test_nested_component_context_shadows_parent_with_unfilled_slots_and_component_tag( def test_nested_component_context_shadows_parent_with_unfilled_slots_and_component_tag(
self, self,
): ):
@ -198,7 +198,7 @@ class ContextTests(SimpleTestCase):
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered) self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
class ParentArgsTests(SimpleTestCase): class ParentArgsTests(BaseTestCase):
def test_parent_args_can_be_drawn_from_context(self): def test_parent_args_can_be_drawn_from_context(self):
template = Template( template = Template(
"{% load component_tags %}{% component_dependencies %}" "{% load component_tags %}{% component_dependencies %}"
@ -241,7 +241,7 @@ class ParentArgsTests(SimpleTestCase):
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered) self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
class ContextCalledOnceTests(SimpleTestCase): class ContextCalledOnceTests(BaseTestCase):
def test_one_context_call_with_simple_component(self): def test_one_context_call_with_simple_component(self):
template = Template( template = Template(
"{% load component_tags %}{% component_dependencies %}" "{% load component_tags %}{% component_dependencies %}"
@ -302,7 +302,7 @@ class ContextCalledOnceTests(SimpleTestCase):
) )
class ComponentsCanAccessOuterContext(SimpleTestCase): class ComponentsCanAccessOuterContext(BaseTestCase):
def test_simple_component_can_use_outer_context(self): def test_simple_component_can_use_outer_context(self):
template = Template( template = Template(
"{% load component_tags %}{% component_dependencies %}" "{% load component_tags %}{% component_dependencies %}"
@ -312,7 +312,7 @@ class ComponentsCanAccessOuterContext(SimpleTestCase):
self.assertIn("outer_value", rendered, rendered) self.assertIn("outer_value", rendered, rendered)
class IsolatedContextTests(SimpleTestCase): class IsolatedContextTests(BaseTestCase):
def test_simple_component_can_pass_outer_context_in_args(self): def test_simple_component_can_pass_outer_context_in_args(self):
template = Template( template = Template(
"{% load component_tags %}{% component_dependencies %}" "{% load component_tags %}{% component_dependencies %}"
@ -330,7 +330,7 @@ class IsolatedContextTests(SimpleTestCase):
self.assertNotIn("outer_value", rendered, rendered) self.assertNotIn("outer_value", rendered, rendered)
class IsolatedContextSettingTests(SimpleTestCase): class IsolatedContextSettingTests(BaseTestCase):
def setUp(self): def setUp(self):
self.patcher = patch( self.patcher = patch(
"django_components.app_settings.AppSettings.CONTEXT_BEHAVIOR", "django_components.app_settings.AppSettings.CONTEXT_BEHAVIOR",
@ -385,7 +385,7 @@ class IsolatedContextSettingTests(SimpleTestCase):
self.assertNotIn("outer_value", rendered, rendered) self.assertNotIn("outer_value", rendered, rendered)
class OuterContextPropertyTests(SimpleTestCase): class OuterContextPropertyTests(BaseTestCase):
@override_settings( @override_settings(
COMPONENTS={"context_behavior": "global"}, COMPONENTS={"context_behavior": "global"},
) )

View file

@ -9,8 +9,7 @@ from django_components.middleware import ComponentDependencyMiddleware
from .django_test_setup import * # NOQA from .django_test_setup import * # NOQA
from .test_templatetags import SimpleComponent from .test_templatetags import SimpleComponent
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase, create_and_process_template_response
from .testutils import create_and_process_template_response
class SimpleComponentAlternate(component.Component): class SimpleComponentAlternate(component.Component):
@ -44,7 +43,7 @@ class MultistyleComponent(component.Component):
@override_settings(COMPONENTS={"RENDER_DEPENDENCIES": True}) @override_settings(COMPONENTS={"RENDER_DEPENDENCIES": True})
class ComponentMediaRenderingTests(SimpleTestCase): class ComponentMediaRenderingTests(BaseTestCase):
def setUp(self): def setUp(self):
# NOTE: component.registry is global, so need to clear before each test # NOTE: component.registry is global, so need to clear before each test
component.registry.clear() component.registry.clear()

View file

@ -1,10 +1,10 @@
from django.conf import settings from django.conf import settings
from .django_test_setup import * # NOQA from .django_test_setup import * # NOQA
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase
class ValidateWrongContextBehaviorValueTestCase(SimpleTestCase): class ValidateWrongContextBehaviorValueTestCase(BaseTestCase):
def setUp(self) -> None: def setUp(self) -> None:
settings.COMPONENTS["context_behavior"] = "invalid_value" settings.COMPONENTS["context_behavior"] = "invalid_value"
return super().setUp() return super().setUp()
@ -20,7 +20,7 @@ class ValidateWrongContextBehaviorValueTestCase(SimpleTestCase):
app_settings.CONTEXT_BEHAVIOR app_settings.CONTEXT_BEHAVIOR
class ValidateCorrectContextBehaviorValueTestCase(SimpleTestCase): class ValidateCorrectContextBehaviorValueTestCase(BaseTestCase):
def setUp(self) -> None: def setUp(self) -> None:
settings.COMPONENTS["context_behavior"] = "isolated" settings.COMPONENTS["context_behavior"] = "isolated"
return super().setUp() return super().setUp()

View file

@ -6,7 +6,7 @@ from django.template import Context, Template, TemplateSyntaxError
# isort: off # isort: off
from .django_test_setup import * # NOQA from .django_test_setup import * # NOQA
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase from .testutils import BaseTestCase
# isort: on # isort: on
@ -85,7 +85,7 @@ class ComponentWithDefaultAndRequiredSlot(component.Component):
template_name = "template_with_default_and_required_slot.html" template_name = "template_with_default_and_required_slot.html"
class ComponentTemplateTagTest(SimpleTestCase): class ComponentTemplateTagTest(BaseTestCase):
def setUp(self): def setUp(self):
# NOTE: component.registry is global, so need to clear before each test # NOTE: component.registry is global, so need to clear before each test
component.registry.clear() component.registry.clear()
@ -202,7 +202,7 @@ class ComponentTemplateTagTest(SimpleTestCase):
template.render(Context({})) template.render(Context({}))
class ComponentSlottedTemplateTagTest(SimpleTestCase): class ComponentSlottedTemplateTagTest(BaseTestCase):
def setUp(self): def setUp(self):
# NOTE: component.registry is global, so need to clear before each test # NOTE: component.registry is global, so need to clear before each test
component.registry.clear() component.registry.clear()
@ -522,7 +522,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
raise e raise e
class SlottedTemplateRegressionTests(SimpleTestCase): class SlottedTemplateRegressionTests(BaseTestCase):
def setUp(self): def setUp(self):
# NOTE: component.registry is global, so need to clear before each test # NOTE: component.registry is global, so need to clear before each test
component.registry.clear() component.registry.clear()
@ -565,7 +565,7 @@ class SlottedTemplateRegressionTests(SimpleTestCase):
) )
class MultiComponentTests(SimpleTestCase): class MultiComponentTests(BaseTestCase):
def setUp(self): def setUp(self):
component.registry.clear() component.registry.clear()
@ -623,7 +623,7 @@ class MultiComponentTests(SimpleTestCase):
self.assertHTMLEqual(rendered, self.expected_result("", second_slot_content)) self.assertHTMLEqual(rendered, self.expected_result("", second_slot_content))
class TemplateInstrumentationTest(SimpleTestCase): class TemplateInstrumentationTest(BaseTestCase):
saved_render_method: Callable # Assigned during setup. saved_render_method: Callable # Assigned during setup.
@classmethod @classmethod
@ -685,7 +685,7 @@ class TemplateInstrumentationTest(SimpleTestCase):
self.assertIn("simple_template.html", templates_used) self.assertIn("simple_template.html", templates_used)
class NestedSlotTests(SimpleTestCase): class NestedSlotTests(BaseTestCase):
class NestedComponent(component.Component): class NestedComponent(component.Component):
template_name = "nested_slot_template.html" template_name = "nested_slot_template.html"
@ -744,7 +744,7 @@ class NestedSlotTests(SimpleTestCase):
self.assertHTMLEqual(rendered, "<p>Override</p>") self.assertHTMLEqual(rendered, "<p>Override</p>")
class ConditionalSlotTests(SimpleTestCase): class ConditionalSlotTests(BaseTestCase):
class ConditionalComponent(component.Component): class ConditionalComponent(component.Component):
template_name = "conditional_template.html" template_name = "conditional_template.html"
@ -819,7 +819,7 @@ class ConditionalSlotTests(SimpleTestCase):
self.assertHTMLEqual(rendered, '<p id="a">Override A</p><p id="b">Override B</p>') self.assertHTMLEqual(rendered, '<p id="a">Override A</p><p id="b">Override B</p>')
class SlotSuperTests(SimpleTestCase): class SlotSuperTests(BaseTestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()
@ -906,7 +906,7 @@ class SlotSuperTests(SimpleTestCase):
) )
class TemplateSyntaxErrorTests(SimpleTestCase): class TemplateSyntaxErrorTests(BaseTestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super().setUpClass() super().setUpClass()
@ -1013,7 +1013,7 @@ class TemplateSyntaxErrorTests(SimpleTestCase):
).render(Context({})) ).render(Context({}))
class ComponentNestingTests(SimpleTestCase): class ComponentNestingTests(BaseTestCase):
@classmethod @classmethod
def setUpClass(cls) -> None: def setUpClass(cls) -> None:
super().setUpClass() super().setUpClass()
@ -1081,7 +1081,7 @@ class ComponentNestingTests(SimpleTestCase):
self.assertHTMLEqual(rendered, expected) self.assertHTMLEqual(rendered, expected)
class ConditionalIfFilledSlotsTests(SimpleTestCase): class ConditionalIfFilledSlotsTests(BaseTestCase):
class ComponentWithConditionalSlots(component.Component): class ComponentWithConditionalSlots(component.Component):
template_name = "template_with_conditional_slots.html" template_name = "template_with_conditional_slots.html"
@ -1197,7 +1197,7 @@ class ConditionalIfFilledSlotsTests(SimpleTestCase):
self.assertHTMLEqual(rendered, expected) self.assertHTMLEqual(rendered, expected)
class RegressionTests(SimpleTestCase): class RegressionTests(BaseTestCase):
"""Ensure we don't break the same thing AGAIN.""" """Ensure we don't break the same thing AGAIN."""
def setUp(self): def setUp(self):
@ -1244,7 +1244,7 @@ class RegressionTests(SimpleTestCase):
self.assertHTMLEqual(rendered, expected) self.assertHTMLEqual(rendered, expected)
class IterationFillTest(SimpleTestCase): class IterationFillTest(BaseTestCase):
"""Tests a behaviour of {% fill .. %} tag which is inside a template {% for .. %} loop.""" """Tests a behaviour of {% fill .. %} tag which is inside a template {% for .. %} loop."""
class ComponentSimpleSlotInALoop(django_components.component.Component): class ComponentSimpleSlotInALoop(django_components.component.Component):

View file

@ -2,7 +2,7 @@ from unittest.mock import Mock
from django.template import Context from django.template import Context
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.test import SimpleTestCase, TestCase from django.test import SimpleTestCase
from django_components.middleware import ComponentDependencyMiddleware from django_components.middleware import ComponentDependencyMiddleware
@ -11,21 +11,8 @@ response_stash = None
middleware = ComponentDependencyMiddleware(get_response=lambda _: response_stash) middleware = ComponentDependencyMiddleware(get_response=lambda _: response_stash)
class Django30CompatibleSimpleTestCase(SimpleTestCase): # TODO: Use this class to manage component registry cleanup before/after tests.
def assertHTMLEqual(self, left, right): class BaseTestCase(SimpleTestCase):
left = left.replace(' type="text/javascript"', "")
left = left.replace(' type="text/css"', "")
right = right.replace(' type="text/javascript"', "")
right = right.replace(' type="text/css"', "")
super(Django30CompatibleSimpleTestCase, self).assertHTMLEqual(left, right)
def assertInHTML(self, needle, haystack, count=None, msg_prefix=""):
haystack = haystack.replace(' type="text/javascript"', "")
haystack = haystack.replace(' type="text/css"', "")
super().assertInHTML(needle, haystack, count, msg_prefix)
class Django30CompatibleTestCase(Django30CompatibleSimpleTestCase, TestCase):
pass pass

19
tox.ini
View file

@ -4,10 +4,10 @@
[tox] [tox]
envlist = envlist =
py38-django{32,40,41,42} py38-django{42}
py39-django{32,40,41,42} py39-django{42}
py310-django{32,40,41,42,50} py310-django{42,50}
py311-django{41,42,50} py311-django{42,50}
py312-django{42,50} py312-django{42,50}
flake8 flake8
isort isort
@ -16,10 +16,10 @@ envlist =
[gh-actions] [gh-actions]
python = python =
3.8: py38-django{32,40,41,42} 3.8: py38-django{42}
3.9: py39-django{32,40,41,42} 3.9: py39-django{42}
3.10: py310-django{32,40,41,42,50} 3.10: py310-django{42,50}
3.11: py311-django{41,42,50} 3.11: py311-django{42,50}
3.12: py312-django{42,50}, flake8, isort, coverage, mypy 3.12: py312-django{42,50}, flake8, isort, coverage, mypy
fail_on_no_env = True fail_on_no_env = True
@ -29,9 +29,6 @@ isolated_build = true
package = wheel package = wheel
wheel_build_env = .pkg wheel_build_env = .pkg
deps = deps =
django32: Django>=3.2,<3.3
django40: Django>=4.0,<4.1
django41: Django>=4.1,<4.2
django42: Django>=4.2,<4.3 django42: Django>=4.2,<4.3
django50: Django>=5.0,<5.1 django50: Django>=5.0,<5.1
pytest pytest