diff --git a/.travis.yml b/.travis.yml index c6931de..eff1a53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,12 @@ language: python +dist: bionic python: - - "3.5" -env: - - TOXENV=py27-django15 - - TOXENV=py27-django16 - - TOXENV=py27-django17 - - TOXENV=py27-django18 - - TOXENV=py27-django19 - - TOXENV=py27-django110 - - TOXENV=py27-django111 - - TOXENV=py34-django15 - - TOXENV=py34-django16 - - TOXENV=py34-django17 - - TOXENV=py34-django18 - - TOXENV=py34-django19 - - TOXENV=py34-django110 - - TOXENV=py34-django111 - - TOXENV=py35-django18 - - TOXENV=py35-django19 - - TOXENV=py34-django110 - - TOXENV=py34-django111 - - TOXENV=flake8 -# - TOXENV=sphinx -# - TOXENV=readme + - 2.7 + - 3.6 + - 3.7 + - 3.8 install: + - pip install tox + - pip install -q tox-travis script: - - make test + - tox diff --git a/CHANGELOG b/CHANGELOG index 0efd530..cf1d150 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,7 +8,8 @@ future releases, check `milestones`_ and :doc:`/about/vision`. 1.10 (unreleased) ----------------- -- Nothing changed yet. +- Introduced support from Django 1.10 to 2.2. +- Drop support of Django 1.5, 1.6 & 1.7 1.9 (2016-03-15) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 26d8289..646da8b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -87,8 +87,8 @@ documentation. Maintain it along with code and documentation. .. _`bugtracker`: https://github.com/benoitbryon/django-downloadview/issues .. _`rebase`: http://git-scm.com/book/en/Git-Branching-Rebasing -.. _`merge-based rebase`: http://tech.novapost.fr/psycho-rebasing-en.html +.. _`merge-based rebase`: https://tech.people-doc.com/psycho-rebasing.html .. _`pip`: https://pypi.python.org/pypi/pip/ -.. _`tox`: http://tox.testrun.org +.. _`tox`: https://tox.readthedocs.io/ .. _`Sphinx`: https://pypi.python.org/pypi/Sphinx/ .. _`zest.releaser`: https://pypi.python.org/pypi/zest.releaser/ diff --git a/demo/demoproject/apache/tests.py b/demo/demoproject/apache/tests.py index c24d7a9..b5c9bb6 100644 --- a/demo/demoproject/apache/tests.py +++ b/demo/demoproject/apache/tests.py @@ -1,11 +1,11 @@ import os from django.core.files.base import ContentFile -from django.core.urlresolvers import reverse import django.test from django_downloadview.apache import assert_x_sendfile +from demoproject.compat import reverse from demoproject.apache.views import storage, storage_dir diff --git a/demo/demoproject/apache/urls.py b/demo/demoproject/apache/urls.py index aec9cdf..7af509e 100644 --- a/demo/demoproject/apache/urls.py +++ b/demo/demoproject/apache/urls.py @@ -1,8 +1,8 @@ """URL mapping.""" from django.conf.urls import url +from demoproject.compat import patterns from demoproject.apache import views -from demoproject.urlpatterns import patterns urlpatterns = patterns( diff --git a/demo/demoproject/compat.py b/demo/demoproject/compat.py new file mode 100644 index 0000000..5e2dc71 --- /dev/null +++ b/demo/demoproject/compat.py @@ -0,0 +1,22 @@ +from distutils.version import StrictVersion +from django.utils.version import get_version + + +try: + from django.conf.urls import patterns # noqa +except ImportError: + def patterns(prefix, *args): + return list(args) + +try: + from django.urls import reverse # noqa +except ImportError: + from django.core.urlresolvers import reverse # noqa + +if StrictVersion(get_version()) >= StrictVersion('2.0'): + from django.conf.urls import include as urlinclude # noqa + + def include(arg, namespace=None, app_name=None): + return urlinclude((arg, app_name), namespace=namespace) +else: + from django.conf.urls import include # noqa diff --git a/demo/demoproject/http/tests.py b/demo/demoproject/http/tests.py index 4296790..7e6a1eb 100644 --- a/demo/demoproject/http/tests.py +++ b/demo/demoproject/http/tests.py @@ -1,8 +1,9 @@ -from django.core.urlresolvers import reverse import django.test from django_downloadview import assert_download_response +from demoproject.compat import reverse + class SimpleURLTestCase(django.test.TestCase): def test_download_response(self): diff --git a/demo/demoproject/http/urls.py b/demo/demoproject/http/urls.py index f8e0c92..6198c39 100644 --- a/demo/demoproject/http/urls.py +++ b/demo/demoproject/http/urls.py @@ -1,7 +1,8 @@ from django.conf.urls import url +from demoproject.compat import patterns from demoproject.http import views -from demoproject.urlpatterns import patterns + urlpatterns = patterns( '', diff --git a/demo/demoproject/lighttpd/tests.py b/demo/demoproject/lighttpd/tests.py index 4918d15..2a9fc89 100644 --- a/demo/demoproject/lighttpd/tests.py +++ b/demo/demoproject/lighttpd/tests.py @@ -1,11 +1,11 @@ import os from django.core.files.base import ContentFile -from django.core.urlresolvers import reverse import django.test from django_downloadview.lighttpd import assert_x_sendfile +from demoproject.compat import reverse from demoproject.lighttpd.views import storage, storage_dir diff --git a/demo/demoproject/lighttpd/urls.py b/demo/demoproject/lighttpd/urls.py index a325a37..c300ec1 100644 --- a/demo/demoproject/lighttpd/urls.py +++ b/demo/demoproject/lighttpd/urls.py @@ -1,8 +1,8 @@ """URL mapping.""" from django.conf.urls import url +from demoproject.compat import patterns from demoproject.lighttpd import views -from demoproject.urlpatterns import patterns urlpatterns = patterns( diff --git a/demo/demoproject/nginx/tests.py b/demo/demoproject/nginx/tests.py index d3c7930..b8e599b 100644 --- a/demo/demoproject/nginx/tests.py +++ b/demo/demoproject/nginx/tests.py @@ -1,11 +1,11 @@ import os from django.core.files.base import ContentFile -from django.core.urlresolvers import reverse import django.test from django_downloadview.nginx import assert_x_accel_redirect +from demoproject.compat import reverse from demoproject.nginx.views import storage, storage_dir diff --git a/demo/demoproject/nginx/urls.py b/demo/demoproject/nginx/urls.py index 1f13ecb..874a7a7 100644 --- a/demo/demoproject/nginx/urls.py +++ b/demo/demoproject/nginx/urls.py @@ -2,8 +2,8 @@ from django.conf.urls import url +from demoproject.compat import patterns from demoproject.nginx import views -from demoproject.urlpatterns import patterns urlpatterns = patterns( diff --git a/demo/demoproject/object/tests.py b/demo/demoproject/object/tests.py index 527936a..2530d3b 100644 --- a/demo/demoproject/object/tests.py +++ b/demo/demoproject/object/tests.py @@ -1,9 +1,9 @@ from django.core.files.base import ContentFile -from django.core.urlresolvers import reverse import django.test from django_downloadview import temporary_media_root, assert_download_response +from demoproject.compat import reverse from demoproject.object.models import Document diff --git a/demo/demoproject/object/urls.py b/demo/demoproject/object/urls.py index 03e7fd4..ee3f54c 100644 --- a/demo/demoproject/object/urls.py +++ b/demo/demoproject/object/urls.py @@ -1,7 +1,8 @@ from django.conf.urls import url +from demoproject.compat import patterns from demoproject.object import views -from demoproject.urlpatterns import patterns + urlpatterns = patterns( '', diff --git a/demo/demoproject/path/tests.py b/demo/demoproject/path/tests.py index facef1b..6fe25a8 100644 --- a/demo/demoproject/path/tests.py +++ b/demo/demoproject/path/tests.py @@ -1,8 +1,9 @@ -from django.core.urlresolvers import reverse import django.test from django_downloadview import assert_download_response +from demoproject.compat import reverse + class StaticPathTestCase(django.test.TestCase): def test_download_response(self): diff --git a/demo/demoproject/path/urls.py b/demo/demoproject/path/urls.py index 17dad33..161203d 100644 --- a/demo/demoproject/path/urls.py +++ b/demo/demoproject/path/urls.py @@ -1,7 +1,8 @@ from django.conf.urls import url +from demoproject.compat import patterns from demoproject.path import views -from demoproject.urlpatterns import patterns + urlpatterns = patterns( '', diff --git a/demo/demoproject/settings.py b/demo/demoproject/settings.py index c091ce6..cb548a8 100755 --- a/demo/demoproject/settings.py +++ b/demo/demoproject/settings.py @@ -64,14 +64,24 @@ INSTALLED_APPS = ( # BEGIN middlewares -MIDDLEWARE_CLASSES = [ - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django_downloadview.SmartDownloadMiddleware' -] +if StrictVersion(get_version()) >= StrictVersion('1.10'): + MIDDLEWARE = [ + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django_downloadview.SmartDownloadMiddleware' + ] +else: + MIDDLEWARE_CLASSES = [ + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django_downloadview.SmartDownloadMiddleware' + ] # END middlewares diff --git a/demo/demoproject/storage/tests.py b/demo/demoproject/storage/tests.py index 8536781..3f0abc2 100644 --- a/demo/demoproject/storage/tests.py +++ b/demo/demoproject/storage/tests.py @@ -2,13 +2,13 @@ import datetime import unittest from django.core.files.base import ContentFile -from django.core.urlresolvers import reverse from django.http.response import HttpResponseNotModified import django.test from django_downloadview import assert_download_response, temporary_media_root from django_downloadview import setup_view +from demoproject.compat import reverse from demoproject.storage import views diff --git a/demo/demoproject/storage/urls.py b/demo/demoproject/storage/urls.py index 53cd38c..1932cd4 100644 --- a/demo/demoproject/storage/urls.py +++ b/demo/demoproject/storage/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url +from demoproject.compat import patterns from demoproject.storage import views -from demoproject.urlpatterns import patterns urlpatterns = patterns( diff --git a/demo/demoproject/tests.py b/demo/demoproject/tests.py index 35e6304..9bfc783 100644 --- a/demo/demoproject/tests.py +++ b/demo/demoproject/tests.py @@ -1,6 +1,7 @@ # coding=utf8 """Test suite for demoproject.download.""" -from django.core.urlresolvers import reverse +from demoproject.compat import reverse + from django.test import TestCase diff --git a/demo/demoproject/urlpatterns.py b/demo/demoproject/urlpatterns.py deleted file mode 100644 index 6e046ad..0000000 --- a/demo/demoproject/urlpatterns.py +++ /dev/null @@ -1,5 +0,0 @@ -try: - from django.conf.urls import patterns -except: - def patterns(prefix, *args): - return list(args) diff --git a/demo/demoproject/urls.py b/demo/demoproject/urls.py index dc43654..6ec45f7 100755 --- a/demo/demoproject/urls.py +++ b/demo/demoproject/urls.py @@ -1,7 +1,7 @@ -from django.conf.urls import include, url +from django.conf.urls import url from django.views.generic import TemplateView -from demoproject.urlpatterns import patterns +from demoproject.compat import patterns, include home = TemplateView.as_view(template_name='home.html') diff --git a/demo/demoproject/virtual/tests.py b/demo/demoproject/virtual/tests.py index a8b92b0..63aa74e 100644 --- a/demo/demoproject/virtual/tests.py +++ b/demo/demoproject/virtual/tests.py @@ -1,8 +1,9 @@ -from django.core.urlresolvers import reverse import django.test from django_downloadview import assert_download_response +from demoproject.compat import reverse + class TextTestCase(django.test.TestCase): def test_download_response(self): diff --git a/demo/demoproject/virtual/urls.py b/demo/demoproject/virtual/urls.py index 2595b3f..2ad7105 100644 --- a/demo/demoproject/virtual/urls.py +++ b/demo/demoproject/virtual/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url +from demoproject.compat import patterns from demoproject.virtual import views -from demoproject.urlpatterns import patterns urlpatterns = patterns( diff --git a/django_downloadview/apache/middlewares.py b/django_downloadview/apache/middlewares.py index ee854b3..9f4b716 100644 --- a/django_downloadview/apache/middlewares.py +++ b/django_downloadview/apache/middlewares.py @@ -12,11 +12,13 @@ class XSendfileMiddleware(ProxiedDownloadMiddleware): :py:class:`django_downloadview.decorators.DownloadDecorator`. """ - def __init__(self, source_dir=None, source_url=None, destination_dir=None): + def __init__(self, + get_response=None, + source_dir=None, source_url=None, destination_dir=None): """Constructor.""" - super(XSendfileMiddleware, self).__init__(source_dir, - source_url, - destination_dir) + super(XSendfileMiddleware, self).__init__( + get_response, source_dir, source_url, destination_dir + ) def process_download_response(self, request, response): """Replace DownloadResponse instances by XSendfileResponse ones.""" diff --git a/django_downloadview/files.py b/django_downloadview/files.py index c6b4e0d..70061f1 100644 --- a/django_downloadview/files.py +++ b/django_downloadview/files.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """File wrappers for use as exchange data between views and responses.""" from __future__ import absolute_import + from io import BytesIO from six.moves.urllib.parse import urlparse @@ -122,7 +123,10 @@ class StorageFile(File): Proxy to self.storage.accessed_time(self.name). """ - return self.storage.accessed(self.name) + try: + return self.storage.get_accessed_time(self.name) + except AttributeError: + return self.storage.accessed_time(self.name) @property def created_time(self): @@ -131,7 +135,10 @@ class StorageFile(File): Proxy to self.storage.created_time(self.name). """ - return self.storage.created_time(self.name) + try: + return self.storage.get_created_time(self.name) + except AttributeError: + return self.storage.created_time(self.name) @property def modified_time(self): @@ -140,7 +147,10 @@ class StorageFile(File): Proxy to self.storage.modified_time(self.name). """ - return self.storage.modified_time(self.name) + try: + return self.storage.get_modified_time(self.name) + except AttributeError: + return self.storage.modified_time(self.name) class VirtualFile(File): diff --git a/django_downloadview/io.py b/django_downloadview/io.py index 1935413..882c87f 100644 --- a/django_downloadview/io.py +++ b/django_downloadview/io.py @@ -40,38 +40,38 @@ class TextIteratorIO(io.TextIOBase): def read(self, n=None): """Return content up to ``n`` length.""" - l = [] + chunks = [] if n is None or n < 0: while True: m = self._read1() if not m: break - l.append(m) + chunks.append(m) else: while n > 0: m = self._read1(n) if not m: break n -= len(m) - l.append(m) - return u''.join(l) + chunks.append(m) + return u''.join(chunks) def readline(self): - l = [] + chunks = [] while True: i = self._left.find(u'\n') if i == -1: - l.append(self._left) + chunks.append(self._left) try: self._left = next(self._iter) except StopIteration: self._left = u'' break else: - l.append(self._left[:i + 1]) + chunks.append(self._left[:i + 1]) self._left = self._left[i + 1:] break - return u''.join(l) + return u''.join(chunks) class BytesIteratorIO(io.BytesIO): @@ -108,35 +108,35 @@ class BytesIteratorIO(io.BytesIO): def read(self, n=None): """Return content up to ``n`` length.""" - l = [] + chunks = [] if n is None or n < 0: while True: m = self._read1() if not m: break - l.append(m) + chunks.append(m) else: while n > 0: m = self._read1(n) if not m: break n -= len(m) - l.append(m) - return b''.join(l) + chunks.append(m) + return b''.join(chunks) def readline(self): - l = [] + chunks = [] while True: i = self._left.find(b'\n') if i == -1: - l.append(self._left) + chunks.append(self._left) try: self._left = next(self._iter) except StopIteration: self._left = b'' break else: - l.append(self._left[:i + 1]) + chunks.append(self._left[:i + 1]) self._left = self._left[i + 1:] break - return b''.join(l) + return b''.join(chunks) diff --git a/django_downloadview/lighttpd/middlewares.py b/django_downloadview/lighttpd/middlewares.py index c19e158..626f293 100644 --- a/django_downloadview/lighttpd/middlewares.py +++ b/django_downloadview/lighttpd/middlewares.py @@ -12,11 +12,13 @@ class XSendfileMiddleware(ProxiedDownloadMiddleware): :py:class:`django_downloadview.decorators.DownloadDecorator`. """ - def __init__(self, source_dir=None, source_url=None, destination_dir=None): + def __init__(self, + get_response=None, + source_dir=None, source_url=None, destination_dir=None): """Constructor.""" - super(XSendfileMiddleware, self).__init__(source_dir, - source_url, - destination_dir) + super(XSendfileMiddleware, self).__init__( + get_response, source_dir, source_url, destination_dir + ) def process_download_response(self, request, response): """Replace DownloadResponse instances by XSendfileResponse ones.""" diff --git a/django_downloadview/middlewares.py b/django_downloadview/middlewares.py index bcabce5..3cbc291 100644 --- a/django_downloadview/middlewares.py +++ b/django_downloadview/middlewares.py @@ -12,6 +12,13 @@ import os from django.conf import settings from django.core.exceptions import ImproperlyConfigured +try: + from django.utils.deprecation import MiddlewareMixin +except ImportError: + class MiddlewareMixin(object): + def __init__(self, get_response=None): + super(MiddlewareMixin, self).__init__() + from django_downloadview.response import DownloadResponse from django_downloadview.utils import import_member @@ -31,7 +38,7 @@ def is_download_response(response): return isinstance(response, DownloadResponse) -class BaseDownloadMiddleware(object): +class BaseDownloadMiddleware(MiddlewareMixin): """Base (abstract) Django middleware that handles download responses. Subclasses **must** implement :py:meth:`process_download_response` method. @@ -80,7 +87,8 @@ class RealDownloadMiddleware(BaseDownloadMiddleware): class DownloadDispatcherMiddleware(BaseDownloadMiddleware): "Download middleware that dispatches job to several middleware instances." - def __init__(self, middlewares=AUTO_CONFIGURE): + def __init__(self, get_response=None, middlewares=AUTO_CONFIGURE): + super(DownloadDispatcherMiddleware, self).__init__(get_response) #: List of children middlewares. self.middlewares = middlewares if self.middlewares is AUTO_CONFIGURE: @@ -106,9 +114,11 @@ class DownloadDispatcherMiddleware(BaseDownloadMiddleware): class SmartDownloadMiddleware(BaseDownloadMiddleware): """Easy to configure download middleware.""" def __init__(self, + get_response=None, backend_factory=AUTO_CONFIGURE, backend_options=AUTO_CONFIGURE): """Constructor.""" + super(SmartDownloadMiddleware, self).__init__(get_response) #: :class:`DownloadDispatcher` instance that can hold multiple #: backend instances. self.dispatcher = DownloadDispatcherMiddleware(middlewares=[]) @@ -165,8 +175,14 @@ class NoRedirectionMatch(Exception): class ProxiedDownloadMiddleware(RealDownloadMiddleware): """Base class for middlewares that use optimizations of reverse proxies.""" - def __init__(self, source_dir=None, source_url=None, destination_url=None): + def __init__(self, + get_response=None, + source_dir=None, + source_url=None, + destination_url=None): """Constructor.""" + super(ProxiedDownloadMiddleware, self).__init__(get_response) + self.source_dir = source_dir self.source_url = source_url self.destination_url = destination_url diff --git a/django_downloadview/nginx/middlewares.py b/django_downloadview/nginx/middlewares.py index 1ad2fcc..71fc31d 100644 --- a/django_downloadview/nginx/middlewares.py +++ b/django_downloadview/nginx/middlewares.py @@ -17,7 +17,9 @@ class XAccelRedirectMiddleware(ProxiedDownloadMiddleware): :py:class:`django_downloadview.decorators.DownloadDecorator`. """ - def __init__(self, source_dir=None, source_url=None, destination_url=None, + def __init__(self, + get_response=None, + source_dir=None, source_url=None, destination_url=None, expires=None, with_buffering=None, limit_rate=None, media_root=None, media_url=None): """Constructor.""" @@ -42,9 +44,10 @@ class XAccelRedirectMiddleware(ProxiedDownloadMiddleware): source_dir = source_dir else: source_dir = source_dir - super(XAccelRedirectMiddleware, self).__init__(source_dir, - source_url, - destination_url) + + super(XAccelRedirectMiddleware, self).__init__( + get_response, source_dir, source_url, destination_url) + self.expires = expires self.with_buffering = with_buffering self.limit_rate = limit_rate @@ -105,13 +108,14 @@ class SingleXAccelRedirectMiddleware(XAccelRedirectMiddleware): Replaced by ``NGINX_DOWNLOAD_MIDDLEWARE_DESTINATION_URL``. """ - def __init__(self): + def __init__(self, get_response=None): """Use Django settings as configuration.""" if settings.NGINX_DOWNLOAD_MIDDLEWARE_DESTINATION_URL is None: raise ImproperlyConfigured( 'settings.NGINX_DOWNLOAD_MIDDLEWARE_DESTINATION_URL is ' 'required by %s middleware' % self.__class__.__name__) super(SingleXAccelRedirectMiddleware, self).__init__( + get_response=get_response, source_dir=settings.NGINX_DOWNLOAD_MIDDLEWARE_SOURCE_DIR, source_url=settings.NGINX_DOWNLOAD_MIDDLEWARE_SOURCE_URL, destination_url=settings.NGINX_DOWNLOAD_MIDDLEWARE_DESTINATION_URL, diff --git a/django_downloadview/nginx/settings.py b/django_downloadview/nginx/settings.py index 63dd551..804766a 100644 --- a/django_downloadview/nginx/settings.py +++ b/django_downloadview/nginx/settings.py @@ -16,11 +16,20 @@ from django.core.exceptions import ImproperlyConfigured # In version 1.3, former XAccelRedirectMiddleware has been renamed to # SingleXAccelRedirectMiddleware. So tell the users. -middleware = 'django_downloadview.nginx.XAccelRedirectMiddleware' -if middleware in settings.MIDDLEWARE_CLASSES: +deprecated_middleware = 'django_downloadview.nginx.XAccelRedirectMiddleware' + + +def get_middlewares(): + try: + return settings.MIDDLEWARE + except AttributeError: + return settings.MIDDLEWARE_CLASSES + + +if deprecated_middleware in get_middlewares(): raise ImproperlyConfigured( - '{middleware} middleware has been renamed as of django-downloadview ' - 'version 1.3. You may use ' + '{deprecated_middleware} middleware has been renamed as of ' + 'django-downloadview version 1.3. You may use ' '"django_downloadview.nginx.SingleXAccelRedirectMiddleware" instead, ' 'or upgrade to "django_downloadview.SmartDownloadDispatcher". ') diff --git a/django_downloadview/views/base.py b/django_downloadview/views/base.py index 29121c3..c476d83 100644 --- a/django_downloadview/views/base.py +++ b/django_downloadview/views/base.py @@ -116,7 +116,8 @@ class DownloadMixin(object): modification_time = calendar.timegm( file_instance.modified_time.utctimetuple()) size = file_instance.size - except (AttributeError, NotImplementedError): + except (AttributeError, NotImplementedError) as e: + print("!=======!", e) return True else: return was_modified_since(since, modification_time, size) diff --git a/docs/about/alternatives.txt b/docs/about/alternatives.txt index 140ce87..91742f2 100644 --- a/docs/about/alternatives.txt +++ b/docs/about/alternatives.txt @@ -75,6 +75,6 @@ Here are main differences between the two projects: .. target-notes:: .. _`django.contrib.staticfiles provides a view to serve files`: - https://docs.djangoproject.com/en/1.9/ref/contrib/staticfiles/#static-file-development-view + https://docs.djangoproject.com/en/3.0/ref/contrib/staticfiles/#static-file-development-view .. _`Django ticket #2131`: https://code.djangoproject.com/ticket/2131 .. _`django-sendfile`: http://pypi.python.org/pypi/django-sendfile diff --git a/docs/files.txt b/docs/files.txt index ac451ad..bd82b30 100644 --- a/docs/files.txt +++ b/docs/files.txt @@ -127,4 +127,4 @@ TextIteratorIO .. target-notes:: .. _`Django itself provides some file wrappers`: - https://docs.djangoproject.com/en/1.9/ref/files/file/ + https://docs.djangoproject.com/en/3.0/ref/files/file/ diff --git a/setup.py b/setup.py index 6cf665e..5dce0b0 100644 --- a/setup.py +++ b/setup.py @@ -40,9 +40,10 @@ CLASSIFIERS = [ 'Framework :: Django', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', ] KEYWORDS = ['file', 'stream', @@ -58,7 +59,7 @@ KEYWORDS = ['file', PACKAGES = [NAME.replace('-', '_')] REQUIREMENTS = [ # BEGIN requirements - 'Django>=1.5', + 'Django>=1.11', 'requests', 'setuptools', 'six', diff --git a/tests/api.py b/tests/api.py index f50dccc..9ef17fd 100644 --- a/tests/api.py +++ b/tests/api.py @@ -96,7 +96,9 @@ class DeprecatedAPITestCase(django.test.SimpleTestCase): "XAccelRedirectMiddleware in settings triggers ImproperlyConfigured." with override_settings( MIDDLEWARE_CLASSES=[ - 'django_downloadview.nginx.XAccelRedirectMiddleware']): + 'django_downloadview.nginx.XAccelRedirectMiddleware'], + MIDDLEWARE=[ + 'django_downloadview.nginx.XAccelRedirectMiddleware'],): with self.assertRaises(ImproperlyConfigured): import django_downloadview.nginx.settings reload(django_downloadview.nginx.settings) diff --git a/tox.ini b/tox.ini index 1f9b5d5..0fcb13c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,46 +1,34 @@ [tox] -envlist = py{27}-django{15,16,17,18,19,110,111}, py{33,34}-django{15,16,17}, py{34,35}-django{18,19,110,111}, flake8, sphinx, readme +envlist = py27-django111, + py{35,36,36,37,38}-django{22,30}, + flake8, sphinx, readme + +[travis] +python= + 3.8: py38, flake8, sphinx, readme [testenv] -basepython = - py27: python2.7 - py33: python3.3 - py34: python3.4 - py35: python3.5 deps = coverage - django15: Django>=1.5,<1.6 - django15: django-nose<1.4.3 - django16: Django>=1.6,<1.7 - django16: django-nose<1.4.3 - django17: Django>=1.7,<1.8 - django17: django-nose<1.4.3 - django18: Django>=1.8,<1.9 - django18: django-nose>=1.4.2 - django19: Django>=1.9,<1.10 - django19: django-nose>=1.4.3 - django110: Django>=1.10,<1.11 - django110: django-nose>=1.4.4 django111: Django>=1.11,<2.0 - django111: django-nose>=1.4.5 + django22: Django>=2.2,<3.0 + django30: Django>=3.0,<3.1 nose py27: mock commands = pip install -e . pip install -e demo - demo test --cover-package=django_downloadview --cover-package=demoproject {posargs: tests demoproject} + python -Wd {envbindir}/demo test --cover-package=django_downloadview --cover-package=demoproject {posargs: tests demoproject} coverage erase pip freeze [testenv:flake8] -basepython = python3.5 deps = flake8 commands = flake8 demo django_downloadview tests [testenv:sphinx] -basepython = python3.5 deps = Sphinx commands = @@ -50,7 +38,6 @@ whitelist_externals = make [testenv:readme] -basepython = python3.5 deps = docutils pygments @@ -62,7 +49,6 @@ whitelist_externals = mkdir [testenv:release] -basepython = python3.5 deps = wheel zest.releaser