diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 50eee10..9941991 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,20 +14,18 @@ jobs: matrix: include: # Django 3.2: Python 3.8, 3.9, 3.10 - - python-version: "3.8" - django-family: 32 - python-version: "3.9" django-family: 32 - python-version: "3.10" django-family: 32 - # Django 4.1: Python 3.9, 3.10, 3.11 + # Django 4.2: Python 3.9, 3.10, 3.11 - python-version: "3.9" - django-family: 41 + django-family: 42 - python-version: "3.10" - django-family: 41 + django-family: 42 - python-version: "3.11" - django-family: 41 + django-family: 42 env: TOXENV: django${{ matrix.django-family }} diff --git a/Makefile b/Makefile index c617168..384dfa4 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ testall: # DOC: Run tests for the currently installed version test: - python -Wdefault -m nose2 + python -Werr -m nose2 # DOC: Perform code quality tasks lint: check-manifest flake8 diff --git a/semantic_version/base.py b/semantic_version/base.py index 6be5624..b62b493 100644 --- a/semantic_version/base.py +++ b/semantic_version/base.py @@ -604,7 +604,7 @@ def compare(v1, v2): def match(spec, version): - return Spec(spec).match(Version(version)) + return SimpleSpec(spec).match(Version(version)) def validate(version_string): diff --git a/tests/django_test_app/models.py b/tests/django_test_app/models.py index 5f790b4..bcbd533 100644 --- a/tests/django_test_app/models.py +++ b/tests/django_test_app/models.py @@ -1,26 +1,23 @@ # -*- coding: utf-8 -*- # Copyright (c) The python-semanticversion project -try: - from django.db import models - django_loaded = True -except ImportError: - django_loaded = False +from django.db import models +from semantic_version import django_fields as semver_fields -if django_loaded: - from semantic_version import django_fields as semver_fields - class VersionModel(models.Model): - version = semver_fields.VersionField(verbose_name='my version') - spec = semver_fields.SpecField(verbose_name='my spec') - npm_spec = semver_fields.SpecField(syntax='npm', blank=True, verbose_name='npm spec') +class VersionModel(models.Model): + version = semver_fields.VersionField(verbose_name='my version') + spec = semver_fields.SpecField(verbose_name='my spec') + npm_spec = semver_fields.SpecField(syntax='npm', blank=True, verbose_name='npm spec') - class PartialVersionModel(models.Model): - partial = semver_fields.VersionField(partial=True, verbose_name='partial version') - optional = semver_fields.VersionField(verbose_name='optional version', blank=True, null=True) - optional_spec = semver_fields.SpecField(verbose_name='optional spec', blank=True, null=True) - class CoerceVersionModel(models.Model): - version = semver_fields.VersionField(verbose_name='my version', coerce=True) - partial = semver_fields.VersionField(verbose_name='partial version', coerce=True, partial=True) +class PartialVersionModel(models.Model): + partial = semver_fields.VersionField(partial=True, verbose_name='partial version') + optional = semver_fields.VersionField(verbose_name='optional version', blank=True, null=True) + optional_spec = semver_fields.SpecField(verbose_name='optional spec', blank=True, null=True) + + +class CoerceVersionModel(models.Model): + version = semver_fields.VersionField(verbose_name='my version', coerce=True) + partial = semver_fields.VersionField(verbose_name='partial version', coerce=True, partial=True) diff --git a/tests/setup_django.py b/tests/setup_django.py index 1ea55e6..8c143c0 100644 --- a/tests/setup_django.py +++ b/tests/setup_django.py @@ -1,16 +1,13 @@ # -*- coding: utf-8 -*- # Copyright (c) The python-semanticversion project -try: # pragma: no cover - import django - django_loaded = True -except ImportError: # pragma: no cover - django_loaded = False - django = None +import django +from django.apps import apps +from django.conf import settings -if django_loaded: - from django.conf import settings + +def configure_django(): if not settings.configured: settings.configure( DATABASES={ @@ -24,6 +21,7 @@ ], MIDDLEWARE_CLASSES=[], ) + django.setup() - from django.apps import apps + apps.populate(settings.INSTALLED_APPS) diff --git a/tests/test_base.py b/tests/test_base.py old mode 100755 new mode 100644 index 4136045..3addd56 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -10,16 +10,11 @@ from semantic_version import base +from . import testing -class TopLevelTestCase(unittest.TestCase): - """Test module-level functions.""" - - if sys.version_info[0] <= 2: - import contextlib - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class TopLevelTestCase(testing.TestCase): + """Test module-level functions.""" versions = ( ('0.1.0', '0.1.1', -1), @@ -96,13 +91,7 @@ def test_validate_invalid(self): "%r should not be a valid version" % (version,)) -class VersionTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class VersionTestCase(testing.TestCase): versions = { '1.0.0-alpha': (1, 0, 0, ('alpha',), ()), @@ -171,6 +160,7 @@ def test_compare_to_self(self): (1, 1, 3, (), ('build', '2012-04-13', 'HUY', 'alpha-12', '1')), } + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_parsing_partials(self): for text, expected_fields in self.partial_versions.items(): with self.subTest(text=text): @@ -181,6 +171,7 @@ def test_parsing_partials(self): self.assertEqual(expected_fields, actual_fields) self.assertTrue(version.partial, "%r should have partial=True" % version) + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_str_partials(self): for text in self.partial_versions: with self.subTest(text=text): @@ -188,6 +179,7 @@ def test_str_partials(self): self.assertEqual(text, str(version)) self.assertEqual("Version('%s', partial=True)" % text, repr(version)) + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_compare_partial_to_self(self): for text in self.partial_versions: with self.subTest(text=text): @@ -196,6 +188,7 @@ def test_compare_partial_to_self(self): base.Version(text, partial=True)) self.assertNotEqual(text, base.Version(text, partial=True)) + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_hash(self): self.assertEqual( 1, @@ -415,20 +408,14 @@ class MyVersion(base.Version): self.assertEqual(type(subv), MyVersion) -class SpecItemTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - - @contextlib.contextmanager - def subTest(self, **kwargs): - yield - +class SpecItemTestCase(testing.TestCase): invalids = [ '<=0.1.1+build3', '<=0.1.1+', '>0.2.3-rc2+', ] + @testing.expect_warning(testing.WARN_SPEC_PARTIAL, testing.WARN_SPECITEM) def test_invalids(self): for invalid in self.invalids: with self.subTest(invalid=invalid): @@ -453,6 +440,7 @@ def test_invalids(self): '^0.1.3': (base.SpecItem.KIND_CARET, 0, 1, 3, None, None), } + @testing.expect_warning(testing.WARN_SPEC_CLASS, testing.WARN_SPEC_PARTIAL, testing.WARN_SPECITEM) def test_components(self): for spec_text, components in self.components.items(): with self.subTest(spec_text=spec_text): @@ -561,6 +549,7 @@ def test_components(self): ), } + @testing.expect_warning(testing.WARN_SPEC_CLASS, testing.WARN_SPEC_PARTIAL, testing.WARN_SPECITEM) def test_matches(self): for spec_text, versions in self.matches.items(): spec = base.SpecItem(spec_text) @@ -578,30 +567,27 @@ def test_matches(self): spec.match(version), "%r should not match %r" % (version, spec)) + @testing.expect_warning(testing.WARN_SPEC_CLASS, testing.WARN_SPEC_PARTIAL, testing.WARN_SPECITEM) def test_equality(self): spec1 = base.SpecItem('==0.1.0') spec2 = base.SpecItem('==0.1.0') self.assertEqual(spec1, spec2) self.assertFalse(spec1 == '==0.1.0') + @testing.expect_warning(testing.WARN_SPEC_CLASS, testing.WARN_SPEC_PARTIAL, testing.WARN_SPECITEM) def test_to_string(self): spec = base.SpecItem('==0.1.0') self.assertEqual('==0.1.0', str(spec)) self.assertEqual(base.SpecItem.KIND_EQUAL, spec.kind) + @testing.expect_warning(testing.WARN_SPEC_CLASS, testing.WARN_SPEC_PARTIAL, testing.WARN_SPECITEM) def test_hash(self): self.assertEqual( 1, len(set([base.SpecItem('==0.1.0'), base.SpecItem('==0.1.0')]))) -class CoerceTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class CoerceTestCase(testing.TestCase): examples = { # Dict of target: [list of equivalents] @@ -626,21 +612,7 @@ def test_invalid(self): self.assertRaises(ValueError, base.Version.coerce, 'v1') -class SpecTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - - @contextlib.contextmanager - def subTest(self, **kwargs): - yield - - def assertCountEqual(self, a, b): - import collections - - self.assertEqual( - collections.Counter(a), - collections.Counter(b), - ) +class SpecTestCase(testing.TestCase): examples = { '>=0.1.1,<0.1.2': ['>=0.1.1', '<0.1.2'], @@ -651,6 +623,7 @@ def assertCountEqual(self, a, b): '~=1.2.3': ['>=1.2.3', '<1.3.0'], } + @testing.expect_warning(testing.WARN_SPEC_CLASS, testing.WARN_SPEC_ITER, testing.WARN_SPEC_PARTIAL) def test_parsing(self): for spec_list_text, specs in self.examples.items(): with self.subTest(spec=spec_list_text): @@ -665,6 +638,13 @@ def test_parsing(self): ('>=0.1.0', '!=0.1.3-rc1,<0.1.3'): ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'], } + @testing.expect_warning( + testing.WARN_SIMPLESPEC_MANY, + testing.WARN_SPECITEM, + testing.WARN_SPEC_CLASS, + testing.WARN_SPEC_ITER, + testing.WARN_SPEC_PARTIAL, + ) def test_parsing_split(self): for spec_list_texts, specs in self.split_examples.items(): with self.subTest(spec=spec_list_texts): @@ -703,6 +683,7 @@ def test_parsing_split(self): ), } + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_matches(self): for spec_list_text, versions in self.matches.items(): spec_list = base.Spec(spec_list_text) @@ -728,6 +709,7 @@ def test_matches(self): spec_list.match(version), "%r should not match %r" % (version, spec_list)) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_equality(self): for spec_list_text in self.examples: with self.subTest(spec=spec_list_text): @@ -736,11 +718,13 @@ def test_equality(self): self.assertEqual(slist1, slist2) self.assertFalse(slist1 == spec_list_text) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_filter_empty(self): s = base.Spec('>=0.1.1') res = tuple(s.filter(())) self.assertEqual((), res) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_filter_incompatible(self): s = base.Spec('>=0.1.1,!=0.1.4') res = tuple(s.filter([ @@ -750,6 +734,7 @@ def test_filter_incompatible(self): ])) self.assertEqual((), res) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_filter_compatible(self): s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0') res = tuple(s.filter([ @@ -770,10 +755,12 @@ def test_filter_compatible(self): self.assertEqual(expected, res) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_select_empty(self): s = base.Spec('>=0.1.1') self.assertIsNone(s.select(())) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_select_incompatible(self): s = base.Spec('>=0.1.1,!=0.1.4') res = s.select([ @@ -783,6 +770,7 @@ def test_select_incompatible(self): ]) self.assertIsNone(res) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_select_compatible(self): s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0') res = s.select([ @@ -797,14 +785,12 @@ def test_select_compatible(self): self.assertEqual(base.Version('0.1.5'), res) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_contains(self): self.assertFalse('ii' in base.Spec('>=0.1.1')) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_hash(self): self.assertEqual( 1, len(set([base.Spec('>=0.1.1'), base.Spec('>=0.1.1')]))) - - -if __name__ == '__main__': # pragma: no cover - unittest.main() diff --git a/tests/test_django.py b/tests/test_django.py index 3361a9b..c5eaf9a 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -2,36 +2,34 @@ # Copyright (c) The python-semanticversion project # This code is distributed under the two-clause BSD License. -import unittest - from semantic_version import Version, SimpleSpec, NpmSpec -from .setup_django import django_loaded +# Import Django code +from django.core import serializers +from django.core.management import call_command +from django.db import connection +from django.test import TestCase as DjangoTestCase +from django.test import TransactionTestCase +from django.test import runner as django_test_runner +from django.test import utils as django_test_utils +from semantic_version import django_fields -if django_loaded: # pragma: no cover - from semantic_version import django_fields - from .django_test_app import models +# Configure Django +from .setup_django import configure_django +from . import testing - from django.core import serializers - from django.core.management import call_command - from django.db import connection - from django.test import TestCase as DjangoTestCase - from django.test import TransactionTestCase - from django.test import runner as django_test_runner - from django.test import utils as django_test_utils +with testing.expect_warning(testing.WARN_VERSION_PARTIAL): + configure_django() -else: - DjangoTestCase = unittest.TestCase - TransactionTestCase = unittest.TestCase +from .django_test_app import models # noqa: E402 test_state = {} +@testing.expect_warning(testing.WARN_VERSION_PARTIAL) def setUpModule(): - if not django_loaded: # pragma: no cover - raise unittest.SkipTest("Django not installed") django_test_utils.setup_test_environment() runner = django_test_runner.DiscoverRunner() runner_state = runner.setup_databases() @@ -42,8 +40,6 @@ def setUpModule(): def tearDownModule(): - if not django_loaded: # pragma: no cover - return runner = test_state['runner'] runner_state = test_state['runner_state'] runner.teardown_databases(runner_state) @@ -58,8 +54,7 @@ def save_and_refresh(obj): obj = obj.__class__.objects.get(id=obj.id) -@unittest.skipIf(not django_loaded, "Django not installed") -class DjangoFieldTestCase(unittest.TestCase): +class DjangoFieldTestCase(testing.TestCase): def test_version(self): obj = models.VersionModel( version=Version('0.1.1'), @@ -126,6 +121,7 @@ def test_partial_spec_clean(self): self.assertEqual(Version('0.1.1'), obj.version) self.assertEqual(SimpleSpec('==0,!=0.2'), obj.spec) + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_coerce_clean(self): obj = models.CoerceVersionModel(version='0.1.1a+2', partial='23') obj.full_clean() @@ -144,6 +140,7 @@ def test_invalid_input(self): v2 = models.VersionModel(version='0.1', spec='==0.1.1,!=0.1.1-alpha') self.assertRaises(ValueError, v2.full_clean) + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_partial(self): obj = models.PartialVersionModel(partial=Version('0.1.0')) @@ -188,6 +185,7 @@ def test_serialization(self): self.assertEqual(o2.spec, obj2.object.spec) self.assertEqual(o2.npm_spec, obj2.object.npm_spec) + @testing.expect_warning(testing.WARN_SPEC_PARTIAL) def test_serialization_partial(self): o1 = models.PartialVersionModel( partial=Version('0.1.1', partial=True), @@ -209,8 +207,8 @@ def test_serialization_partial(self): self.assertEqual(o2.optional, obj2.object.optional) -@unittest.skipIf(not django_loaded, "Django not installed") class FieldMigrationTests(DjangoTestCase): + @testing.expect_warning(testing.WARN_VERSION_PARTIAL) def test_version_field(self): field = django_fields.VersionField( partial=True, @@ -234,8 +232,8 @@ def test_nondefault_spec_field(self): self.assertEqual(field.deconstruct()[3], expected) -@unittest.skipIf(not django_loaded, "Django not installed") class FullMigrateTests(TransactionTestCase): + @testing.expect_warning(testing.WARN_VERSION_PARTIAL) def test_migrate(self): # Let's check that this does not crash call_command('makemigrations', verbosity=0) @@ -246,7 +244,6 @@ def test_migrate(self): self.assertIn('django_test_app_versionmodel', table_list) -@unittest.skipIf(not django_loaded, "Django not installed") class DbInteractingTestCase(DjangoTestCase): def test_db_interaction(self): diff --git a/tests/test_match.py b/tests/test_match.py old mode 100755 new mode 100644 index 6851eb2..742a1ea --- a/tests/test_match.py +++ b/tests/test_match.py @@ -3,20 +3,12 @@ # Copyright (c) The python-semanticversion project # This code is distributed under the two-clause BSD License. -import unittest -import sys - import semantic_version +from . import testing -class MatchTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class MatchTestCase(testing.TestCase): invalid_specs = [ '', '!0.1', @@ -125,12 +117,14 @@ def subTest(self, **kwargs): ], } + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_invalid(self): for invalid in self.invalid_specs: with self.subTest(spec=invalid): with self.assertRaises(ValueError, msg="Spec(%r) should be invalid" % invalid): semantic_version.Spec(invalid) + @testing.expect_warning(testing.WARN_SPECITEM, testing.WARN_SPEC_CLASS, testing.WARN_SPEC_PARTIAL) def test_simple(self): for valid in self.valid_specs: with self.subTest(spec=valid): @@ -138,6 +132,7 @@ def test_simple(self): normalized = str(spec) self.assertEqual(spec, semantic_version.SpecItem(normalized)) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_match(self): for spec_text, versions in self.matches.items(): for version_text in versions: @@ -149,6 +144,7 @@ def test_match(self): self.assertTrue(spec.match(version), "%r does not match %r" % (version, spec)) self.assertTrue(semantic_version.match(spec_text, version_text)) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_contains(self): spec = semantic_version.Spec('<=0.1.1') self.assertFalse('0.1.0' in spec, "0.1.0 should not be in %r" % spec) @@ -159,6 +155,7 @@ def test_contains(self): version = semantic_version.Version('0.1.1-rc1+4.2') self.assertTrue(version in spec, "%r should be in %r" % (version, spec)) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_prerelease_check(self): strict_spec = semantic_version.Spec('>=0.1.1-') lax_spec = semantic_version.Spec('>=0.1.1') @@ -166,11 +163,8 @@ def test_prerelease_check(self): self.assertFalse(version in lax_spec, "%r should not be in %r" % (version, lax_spec)) self.assertFalse(version in strict_spec, "%r should not be in %r" % (version, strict_spec)) + @testing.expect_warning(testing.WARN_SPEC_CLASS) def test_build_check(self): spec = semantic_version.Spec('<=0.1.1-rc1') version = semantic_version.Version('0.1.1-rc1+4.2') self.assertTrue(version in spec, "%r should be in %r" % (version, spec)) - - -if __name__ == '__main__': # pragma: no cover - unittest.main() diff --git a/tests/test_npm.py b/tests/test_npm.py index 2102cd8..979cde4 100644 --- a/tests/test_npm.py +++ b/tests/test_npm.py @@ -5,19 +5,12 @@ """Test NPM-style specifications.""" -import unittest -import sys - from semantic_version import base +from . import testing -class NpmSpecTests(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class NpmSpecTests(testing.TestCase): examples = { # range: [matchings], [failings] diff --git a/tests/test_parsing.py b/tests/test_parsing.py old mode 100755 new mode 100644 index 45d22c6..386e86e --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -4,19 +4,13 @@ # This code is distributed under the two-clause BSD License. import itertools -import unittest -import sys import semantic_version +from . import testing -class ParsingTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class ParsingTestCase(testing.TestCase): invalids = [ None, @@ -73,13 +67,7 @@ def test_kwargs(self): self.assertEqual(text, str(version)) -class ComparisonTestCase(unittest.TestCase): - if sys.version_info[0] <= 2: - import contextlib - - @contextlib.contextmanager - def subTest(self, **kwargs): - yield +class ComparisonTestCase(testing.TestCase): order = [ '1.0.0-alpha', @@ -138,7 +126,3 @@ def test_unordered(self): self.assertTrue(v1 <= v2, "%r !<= %r" % (v1, v2)) self.assertFalse(v2 > v1, "%r !> %r" % (v2, v1)) self.assertTrue(v2 >= v1, "%r !>= %r" % (v2, v1)) - - -if __name__ == '__main__': # pragma: no cover - unittest.main() diff --git a/tests/test_spec.py b/tests/test_spec.py index b5fcd98..9bd1b55 100644 --- a/tests/test_spec.py +++ b/tests/test_spec.py @@ -5,15 +5,15 @@ """Test conformance to the specs.""" -import unittest - import semantic_version +from . import testing + # shortcut Version = semantic_version.Version -class FormatTests(unittest.TestCase): +class FormatTests(testing.TestCase): """Tests proper version validation.""" def test_major_minor_patch(self): diff --git a/tests/testing.py b/tests/testing.py new file mode 100644 index 0000000..f28ca17 --- /dev/null +++ b/tests/testing.py @@ -0,0 +1,40 @@ +import contextlib +import unittest +import sys +import warnings + + +class TestCase(unittest.TestCase): + if sys.version_info[0] <= 2: + + @contextlib.contextmanager + def subTest(self, **kwargs): + yield + + def assertCountEqual(self, a, b): + import collections + + self.assertEqual( + collections.Counter(a), + collections.Counter(b), + ) + + +@contextlib.contextmanager +def expect_warning(*messages): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + yield + actual = {str(warning.message) for warning in w} + assert actual == set(messages), "{actual!r} should match {expected!r}".format( + actual=actual, + expected=set(messages), + ) + + +WARN_SIMPLESPEC_MANY = "Passing 2+ arguments to SimpleSpec will be removed in 3.0; concatenate them with ',' instead." +WARN_SPECITEM = "The `SpecItem` class will be removed in 3.0." +WARN_SPEC_CLASS = "The Spec() class will be removed in 3.1; use SimpleSpec() instead." +WARN_SPEC_ITER = "Iterating over the components of a SimpleSpec object will be removed in 3.0." +WARN_SPEC_PARTIAL = "Partial versions will be removed in 3.0; use SimpleSpec('1.x.x') instead." +WARN_VERSION_PARTIAL = "Use of `partial=True` will be removed in 3.0." diff --git a/tox.ini b/tox.ini index 369cf12..b0cfaa7 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = py{37,38,39,310}-django32 - py{38,39,310,311}-django41 + py{38,39,310,311}-django42 pypy3-django{32} lint @@ -11,7 +11,7 @@ toxworkdir = {env:TOX_WORKDIR:.tox} extras = dev deps = django32: Django>=3.2,<3.3 - django41: Django>=4.1,<4.2 + django42: Django>=4.2,<4.3 allowlist_externals = make whitelist_externals = make