diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index afe047d..9ac3f29 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,30 +13,8 @@ jobs: matrix: os: [ubuntu-20.04] python-version: [python3.9, python3.8] - django-version: [django3.2, django3.1, django3.0, django2.2, django2.1, django2.0] - drf-version: [drf3.12, drf3.11, drf3.10, drf3.09] - exclude: - - os: ubuntu-20.04 - django-version: django3.2 - drf-version: drf3.10 - - os: ubuntu-20.04 - django-version: django3.1 - drf-version: drf3.10 - - os: ubuntu-20.04 - django-version: django3.2 - drf-version: drf3.09 - - os: ubuntu-20.04 - django-version: django3.1 - drf-version: drf3.09 - - os: ubuntu-20.04 - django-version: django3.0 - drf-version: drf3.09 - - os: ubuntu-20.04 - django-version: django2.1 - drf-version: drf3.12 - - os: ubuntu-20.04 - django-version: django2.0 - drf-version: drf3.12 + django-version: [django4.0, django3.2, django3.1, django3.0] + drf-version: [drf3.14, drf3.13, drf3.12, drf3.11] name: ${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.django-version }}-${{ matrix.drf-version }} steps: - name: "Set job environments" @@ -66,7 +44,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install --upgrade tox tox-gh-actions testfixtures + python -m pip install --upgrade 'tox>=3,<4' tox-gh-actions testfixtures - name: Tox tests run: | tox -e $TOXENV @@ -89,10 +67,10 @@ jobs: needs: run-tests steps: - uses: actions/checkout@master - - name: Set up Python 3.7 + - name: Set up Python 3.9 uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.9 - name: Install pypa/build run: >- python -m diff --git a/README.rst b/README.rst index cbc7632..d3e7cab 100644 --- a/README.rst +++ b/README.rst @@ -32,14 +32,11 @@ Compatibility - `Django `_: - - 2.0.x - - 2.1.x - - 2.2.x - 3.0.x - 3.1.x - 3.2.x - -**NOTE**: Python 3.6 does not have support for Django <= 1.x. + - 4.0.x + - 4.1.x **NOTE**: The 1.4 release dropped support for Django 1.5.x & 1.6.x. @@ -47,14 +44,16 @@ Compatibility **NOTE**: The 2.1 release dropped support for Django 1.9.x. -- `Pillow `_ >= 2.4.0 +**NOTE**: The 3.0 release dropped support for Django 2.x. + +- `Pillow `_ >= 6.2.0 - `Django REST Framework `_: - - 3.9.x - - 3.10.x - 3.11.x - 3.12.x + - 3.13.x + - 3.14.x Documentation ============= diff --git a/docs/index.rst b/docs/index.rst index 4617243..1e5ddca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -39,20 +39,20 @@ Compatibility - `Django `_: - - 2.0.x - - 2.1.x - - 2.2.x - 3.0.x - 3.1.x - 3.2.x + - 4.0.x + - 4.1.x - `Pillow `_ >=2.4.0 - `Django REST Framework `_: - - 3.9.x - - 3.10.x + - 3.11.x - 3.12.x + - 3.13.x + - 3.14.x Code ==== @@ -78,6 +78,12 @@ Table of Contents Release Notes ============= +3.0 +^^^ +- Removed support for Django < 3.x. Thanks, `@browniebroke `_! +- Added support for Django 4.0 & 4.1. Thanks, `@browniebroke `_! +- General code clean-up, improved Django REST Framework support and doc updates. Thanks, `@browniebroke `_! + 2.2 ^^^ - Added WEBP support for sizers & filters. Thanks, `@ahmedaljazzar `_! diff --git a/docs/installation.rst b/docs/installation.rst index d6a6b04..110d086 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -18,11 +18,11 @@ Python Compatibility Django Compatibility -------------------- -- 2.0.x -- 2.2.x - 3.0.x - 3.1.x - 3.2.x +- 4.0.x +- 4.1.x Dependencies ------------ diff --git a/docs/overview.rst b/docs/overview.rst index 8f9a681..9cc3f97 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -151,7 +151,7 @@ Flexible in development, light-weight in production Fully Tested & Python 3 Ready ----------------------------- -``django-versatileimagefield`` is a rock solid, `fully-tested `_ Django app that is compatible with Python 3.6 thru 3.9 and works with Django 2.0.x thru 3.2.x +``django-versatileimagefield`` is a rock solid, `fully-tested `_ Django app that is compatible with Python 3.6 thru 3.9 and works with Django 3.0.x thru 4.1.x Get Started ----------- diff --git a/post_processor_runtests.py b/post_processor_runtests.py index 1743b74..3591fc1 100644 --- a/post_processor_runtests.py +++ b/post_processor_runtests.py @@ -11,8 +11,7 @@ from django.test.utils import get_runner # Run post-processor tests os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.post_processor.test_settings' - if django.VERSION >= (1, 7): - django.setup() + django.setup() TestRunnerPostProcessor = get_runner( settings, 'tests.post_processor.discover_tests.DiscoverPostProcessorRunner' diff --git a/setup.py b/setup.py index 591eab8..1618cbb 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ name='django-versatileimagefield', packages=find_packages(), version='2.2', - author=u'Jonathan Ellenberger', + author='Jonathan Ellenberger', author_email='jonathan_ellenberger@wgbh.org', url='http://github.com/respondcreate/django-versatileimagefield/', license='MIT License, see LICENSE', @@ -15,7 +15,11 @@ "creating new images from the one assigned to the field.", long_description=open('README.rst').read(), zip_safe=False, - install_requires=['Pillow>=2.4.0', 'python-magic>=0.4.15,<1.0.0'], + install_requires=[ + 'Pillow>=2.4.0', + 'python-magic>=0.4.15,<1.0.0', + 'Django>=3.0', + ], include_package_data=True, keywords=[ 'django', @@ -24,20 +28,17 @@ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', - 'Framework :: Django :: 2.0', - 'Framework :: Django :: 2.1', - 'Framework :: Django :: 2.2', 'Framework :: Django :: 3.0', 'Framework :: Django :: 3.1', 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.0', + 'Framework :: Django :: 4.1', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', diff --git a/tests/settings_base.py b/tests/settings_base.py index f193fb5..a03976a 100644 --- a/tests/settings_base.py +++ b/tests/settings_base.py @@ -75,3 +75,5 @@ }, }, ] + +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' diff --git a/tests/tests.py b/tests/tests.py index 3415ac7..9dcde45 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -421,7 +421,7 @@ def test_widget_javascript(self): response = self.client.get(self.admin_url) self.assertEqual(response.status_code, 200) # Test that javascript loads correctly - if DJANGO_VERSION[0] >= 3 and DJANGO_VERSION[1] >= 1: + if DJANGO_VERSION >= (3, 1): expected_response = '' else: expected_response = '' @@ -1081,28 +1081,6 @@ def test_corrupt_file(self): instance.image.delete(save=False) - @skipIf(django.VERSION >= (2, 2), "Not applicable for Django>=2.2") - def test_webp_wrong_dimensions(self): - """Test WebP image dimensions behavior on Django<2.2""" - with self.assertRaisesMessage(RuntimeError, "could not create decoder object"): - VersatileImageTestModel.objects.create( - img_type='webp-no-dimensions', - image="python-logo.webp", - width=0, - height=0 - ) - - try: - VersatileImageTestModel.objects.create( - img_type='webp-with-dimensions', - image="python-logo.webp", - width=580, - height=164 - ) - except RuntimeError as e: - self.fail("ImageField raised RuntimeError unexpectedly! msg: %s" % e) - - @skipIf(django.VERSION < (2, 2), "Different behavior exists on Django<2.2") def test_webp_dimensions_dimensions(self): """Test no failures on all WebP image dimensions""" try: diff --git a/tests/urls.py b/tests/urls.py index aec6259..5e88d8c 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -1,19 +1,19 @@ from django.conf import settings -from django.conf.urls import include, url +from django.urls import include, path, re_path from django.contrib import admin admin.autodiscover() urlpatterns = [ - url(r'^admin/', admin.site.urls), + path('admin/', admin.site.urls), ] if settings.DEBUG: urlpatterns = [ - url( + re_path( r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT, 'show_indexes': True} ), - url(r'', include('django.contrib.staticfiles.urls')), + path('', include('django.contrib.staticfiles.urls')), ] + urlpatterns diff --git a/tox.ini b/tox.ini index 048261f..1a22f46 100644 --- a/tox.ini +++ b/tox.ini @@ -3,24 +3,20 @@ minversion = 3.23.0 requires: pip >= 21.0.1 envlist = - py{3.6,3.7}-django{20,21,22}-drf{307,308,309,310,311} - py{3.8,3.9}-django{22}-drf{309,310,311,312} - py{3.8,3.9}-django{30,31,32}-drf{311,312} + py{3.8,3.9}-django{30,31,32,40,41}-drf{311,312,313,314} [gh-actions] python = - 3.6: py3.6 - 3.7: py3.7 3.8: py3.8 3.9: py3.9 [travis:env] DJANGO = - 2.0: django20 - 2.2: django22 3.0: django30 3.1: django31 3.2: django32 + 4.0: django40 + 4.1: django41 [testenv] passenv = TRAVIS TRAVIS_* GITHUB_* @@ -28,23 +24,17 @@ deps= coverage coveralls testfixtures - django20: Django>=2.0.13,<2.1.0 - django21: Django>=2.1.14,<2.2.0 - django22: Django>=2.2.19,<3.0.0 + pytz django30: Django>=3.0.13,<3.1.0 django31: Django>=3.1.7,<3.2.0 - django32: Django>=3.2.0rc1,<3.3.0 - drf304: djangorestframework>=3.4.7,<3.5.0 - drf305: djangorestframework>=3.5.4,<3.6.0 - drf306: djangorestframework>=3.6.4,<3.7.0 - drf307: djangorestframework>=3.7.7,<3.8.0 - drf308: djangorestframework>=3.8.2,<3.9.0 - drf309: djangorestframework>=3.9.4,<3.10.0 - drf310: djangorestframework>=3.10.3,<3.11.0 + django32: Django>=3.2.0,<3.3.0 + django40: Django>=4.0.0,<4.1.0 + django41: Django>=4.1.0,<4.2.0 drf311: djangorestframework>=3.11.2,<3.12.0 drf312: djangorestframework>=3.12.4,<3.13.0 + drf313: djangorestframework>=3.13,<3.14 + drf314: djangorestframework>=3.14,<3.15 flake8 - coveralls sitepackages = False recreate = False commands = diff --git a/versatileimagefield/files.py b/versatileimagefield/files.py index 019d322..d8bb4be 100644 --- a/versatileimagefield/files.py +++ b/versatileimagefield/files.py @@ -13,7 +13,7 @@ class VersatileImageFieldFile(VersatileImageMixIn, ImageFieldFile): def __setstate__(self, state): self.__dict__.update(state) - if DJANGO_VERSION[0] >= 3 and DJANGO_VERSION[1] > 0: + if DJANGO_VERSION >= (3, 1): self.storage = self.field.storage self._create_on_demand = state.get('_create_on_demand') self._ppoi_value = state.get('_ppoi_value') diff --git a/versatileimagefield/widgets.py b/versatileimagefield/widgets.py index 766a4b7..189681a 100644 --- a/versatileimagefield/widgets.py +++ b/versatileimagefield/widgets.py @@ -1,6 +1,4 @@ -import django from django.forms.widgets import ClearableFileInput, HiddenInput, MultiWidget, Select -from django.template.loader import render_to_string from django.utils.safestring import mark_safe CENTERPOINT_CHOICES = ( @@ -18,7 +16,6 @@ class ClearableFileInputWithImagePreview(ClearableFileInput): - has_template_widget_rendering = django.VERSION >= (1, 11) template_name = 'versatileimagefield/forms/widgets/versatile_image.html' def get_hidden_field_id(self, name): @@ -36,20 +33,6 @@ def get_ppoi_id(self, name): def get_point_stage_id(self, name): return name + '_point-stage' - def render(self, name, value, attrs=None, renderer=None): - """ - Render the widget as an HTML string. - - Overridden here to support Django < 1.11. - """ - if self.has_template_widget_rendering: - return super(ClearableFileInputWithImagePreview, self).render( - name, value, attrs=attrs, renderer=renderer - ) - else: # pragma: no cover - context = self.get_context(name, value, attrs) - return render_to_string(self.template_name, context) - def get_sized_url(self, value): """Do not fail completely on invalid images""" try: @@ -63,11 +46,7 @@ def get_sized_url(self, value): def get_context(self, name, value, attrs): """Get the context to render this widget with.""" - # Initialize widget context. - context = {} - - if self.has_template_widget_rendering: - context = super(ClearableFileInputWithImagePreview, self).get_context(name, value, attrs) + context = super(ClearableFileInputWithImagePreview, self).get_context(name, value, attrs) # It seems Django 1.11's ClearableFileInput doesn't add everything to the 'widget' key, so we can't use it # in MultiWidget. Add it manually here.