diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec1dd31..c80b6c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,24 +9,20 @@ on: jobs: tests: name: Python ${{ matrix.python-version }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: - python-version: - - 3.6 - - 3.7 - - 3.8 - - 3.9 + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('requirements/*.txt') }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 3a05705..fae1e71 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -8,15 +8,15 @@ on: jobs: pre-commit: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 - - uses: pre-commit/action@v2.0.0 + - uses: pre-commit/action@v3.0.1 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index aaa3a42..8dc1d22 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ html/ htmlcov/ *.egg-info/ .tox/ +/temp +/venv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cdbfbe9..76c1f2e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v5.0.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -11,16 +11,16 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 25.1.0 hooks: - id: black language_version: python3 - repo: https://github.com/pycqa/isort - rev: 5.10.1 + rev: 6.0.1 hooks: - id: isort - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + rev: 7.1.2 hooks: - id: flake8 additional_dependencies: @@ -28,7 +28,8 @@ repos: - flake8-comprehensions - flake8-tidy-imports - repo: https://github.com/mgedmin/check-manifest - rev: "0.48" + rev: "0.50" hooks: - id: check-manifest args: [--no-build-isolation] + additional_dependencies: [setuptools, wheel] diff --git a/docs/index.md b/docs/index.md index 7c41490..1d33fac 100644 --- a/docs/index.md +++ b/docs/index.md @@ -90,8 +90,8 @@ Writing the same code with `django-vanilla-views`, you'd instead arrive at a sim ## Requirements -* **Django**: 2.2, 3.0, 3.1, 3.2 -* **Python**: 3.6, 3.7, 3.8, 3.9 +* **Django**: 4.2, 5.0, 5.1, 5.2 +* **Python**: 3.10, 3.11, 3.12, 3.13 ## Installation diff --git a/example/example/notes/migrations/0001_initial.py b/example/example/notes/migrations/0001_initial.py index 01f5a86..a92a0b3 100644 --- a/example/example/notes/migrations/0001_initial.py +++ b/example/example/notes/migrations/0001_initial.py @@ -2,7 +2,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [] diff --git a/example/manage.py b/example/manage.py index 2605e37..c6b69b9 100755 --- a/example/manage.py +++ b/example/manage.py @@ -1,10 +1,22 @@ #!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" import os import sys -if __name__ == "__main__": + +def main(): + """Run administrative tasks.""" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) - from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) +if __name__ == "__main__": + main() diff --git a/example/requirements.txt b/example/requirements.txt index 5bec56a..9ca9f82 100644 --- a/example/requirements.txt +++ b/example/requirements.txt @@ -1,2 +1,2 @@ -Django>=1.8 -django-vanilla-views==1.0.4 +Django>=4.2 +django-vanilla-views>=3.1.0 diff --git a/manage.py b/manage.py index 819d703..e0dd572 100755 --- a/manage.py +++ b/manage.py @@ -1,10 +1,22 @@ #!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" import os import sys -if __name__ == "__main__": + +def main(): + """Run administrative tasks.""" os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testsettings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) - from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) +if __name__ == "__main__": + main() diff --git a/mkdocs.py b/mkdocs.py index c92a531..be0409a 100755 --- a/mkdocs.py +++ b/mkdocs.py @@ -61,7 +61,7 @@ next_url_map[path] = rel + path_list[idx + 1][:-3] + suffix -for (dirpath, _dirnames, filenames) in os.walk(docs_dir): +for dirpath, _dirnames, filenames in os.walk(docs_dir): relative_dir = dirpath.replace(docs_dir, "").lstrip(os.path.sep) build_dir = os.path.join(html_dir, relative_dir) diff --git a/pyproject.toml b/pyproject.toml index 0837a22..b7ddf36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["setuptools >= 40.6.0", "wheel"] build-backend = "setuptools.build_meta" [tool.black] -target-version = ['py36'] +target-version = ['py310'] [tool.isort] profile = "black" diff --git a/setup.py b/setup.py index 8ed5e7d..e0e72f8 100755 --- a/setup.py +++ b/setup.py @@ -83,16 +83,16 @@ def get_package_data(package): "Changelog": "http://django-vanilla-views.org/topics/release-notes", "Repository": "https://github.com/tomchristie/django-vanilla-views/", }, - python_requires=">=3.6", + python_requires=">=3.10", install_requires=[], classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", - "Framework :: Django :: 2.2", - "Framework :: Django :: 3.0", - "Framework :: Django :: 3.1", - "Framework :: Django :: 3.2", + "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", + "Framework :: Django :: 5.1", + "Framework :: Django :: 5.2", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", diff --git a/testsettings.py b/testsettings.py index 7b7401f..1d3d8f7 100644 --- a/testsettings.py +++ b/testsettings.py @@ -1,5 +1,3 @@ -import django - DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", @@ -9,18 +7,13 @@ INSTALLED_APPS = ("vanilla",) -if django.VERSION >= (1, 10): - MIDDLEWARE = [ - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - ] -else: - MIDDLEWARE_CLASSES = [ - "django.middleware.common.CommonMiddleware", - "django.middleware.csrf.CsrfViewMiddleware", - ] +MIDDLEWARE = [ + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", +] SECRET_KEY = "abcde12345" -if django.VERSION >= (3, 2): - DEFAULT_AUTO_FIELD = "django.db.models.AutoField" +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + +USE_TZ = False diff --git a/tox.ini b/tox.ini index c9126d2..9a3fa91 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,13 @@ [tox] isolated_build = True envlist = - py36-django{22,30,31,32} - py37-django{22,30,31,32} - py38-django{30,31,32} - py39-django{30,31,32} + py{310,311,312}-django{42,50,51,52} + py313-django{51,52} [testenv] commands = python -W error::DeprecationWarning -W error::PendingDeprecationWarning manage.py test deps = - django22: django>=2.2,<3.0 - django30: django>=3.0,<3.1 - django31: django>=3.1,<3.2 - django32: django>=3.2,<4.0 + django42: django>=4.2,<5.0 + django50: django>=5.0,<5.1 + django51: django>=5.1,<5.2 + django52: django>=5.2b1,<6.0 diff --git a/vanilla/__init__.py b/vanilla/__init__.py index 03f7402..ca290e7 100644 --- a/vanilla/__init__.py +++ b/vanilla/__init__.py @@ -10,7 +10,7 @@ ) from vanilla.views import FormView, GenericView, TemplateView -__version__ = "3.0.0" +__version__ = "3.1.0" __all__ = ( "View", "GenericView", diff --git a/vanilla/tests.py b/vanilla/tests.py index 392886a..bddd83c 100644 --- a/vanilla/tests.py +++ b/vanilla/tests.py @@ -52,14 +52,6 @@ def setUp(self): self.factory = RequestFactory() super(BaseTestCase, self).setUp() - def assertFormError(self, response, form, field, errors, msg_prefix=""): - # Hack to get around the fact that we're using request factory, - # instead of the full test client. - response.context = response.context_data - return super(BaseTestCase, self).assertFormError( - response, form, field, errors, msg_prefix - ) - def assertContext(self, response, expected): # Ensure the keys all match. # Note that this style ensures we get nice descriptive failures. @@ -301,8 +293,7 @@ def test_create_failed(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, ["vanilla/example_form.html"]) self.assertFormError( - response, - "form", + response.context_data["form"], "text", ["Ensure this value has at most 10 characters (it has 700)."], ) @@ -379,8 +370,7 @@ def test_update_failed(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, ["vanilla/example_form.html"]) self.assertFormError( - response, - "form", + response.context_data["form"], "text", ["Ensure this value has at most 10 characters (it has 700)."], ) @@ -614,8 +604,7 @@ def test_form_failure(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.template_name, ["example.html"]) self.assertFormError( - response, - "form", + response.context_data["form"], "text", ["Ensure this value has at most 10 characters (it has 700)."], )