mirror of
https://github.com/jazzband/django-downloadview.git
synced 2026-03-16 22:40:25 +00:00
Merge pull request #188 from tari/django-4.0-compat
Update compatibility for Django 4.0
This commit is contained in:
commit
7e9f81d758
7 changed files with 67 additions and 49 deletions
20
.github/workflows/test.yml
vendored
20
.github/workflows/test.yml
vendored
|
|
@ -8,10 +8,24 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 5
|
||||
matrix:
|
||||
python-version: ['3.6', '3.7', '3.8', '3.9']
|
||||
django-version: ['2.2', '3.1', '3.2', 'main']
|
||||
python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
|
||||
django-version: ['2.2', '3.1', '3.2', '4.0', 'main']
|
||||
exclude:
|
||||
# Django prior to 3.2 does not support Python 3.10
|
||||
- django-version: '2.2'
|
||||
python-version: '3.10'
|
||||
- django-version: '3.1'
|
||||
python-version: '3.10'
|
||||
# Django after 3.2 dropped support for Python prior to 3.8
|
||||
- django-version: '4.0'
|
||||
python-version: '3.6'
|
||||
- django-version: 'main'
|
||||
python-version: '3.6'
|
||||
- django-version: '4.0'
|
||||
python-version: '3.7'
|
||||
- django-version: 'main'
|
||||
python-version: '3.7'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ INSTALLED_APPS = (
|
|||
"django.contrib.sites",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
# Stuff that must be at the end.
|
||||
"django_nose",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -111,15 +109,6 @@ DOWNLOADVIEW_RULES += [
|
|||
|
||||
# Test/development settings.
|
||||
DEBUG = True
|
||||
TEST_RUNNER = "django_nose.NoseTestSuiteRunner"
|
||||
NOSE_ARGS = [
|
||||
"--verbosity=2",
|
||||
"--no-path-adjustment",
|
||||
"--nocapture",
|
||||
"--all-modules",
|
||||
"--with-coverage",
|
||||
"--with-doctest",
|
||||
]
|
||||
|
||||
|
||||
TEMPLATES = [
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ setup(
|
|||
packages=["demoproject"],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=["django-downloadview", "django-nose"],
|
||||
install_requires=["django-downloadview", "pytest-django"],
|
||||
entry_points={"console_scripts": ["demo = demoproject.manage:main"]},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""Low-level IO operations, for use with file wrappers."""
|
||||
import io
|
||||
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
from django.utils.encoding import force_bytes, force_str
|
||||
|
||||
|
||||
class TextIteratorIO(io.TextIOBase):
|
||||
|
|
@ -32,7 +32,7 @@ class TextIteratorIO(io.TextIOBase):
|
|||
break
|
||||
else:
|
||||
# Make sure we handle text.
|
||||
self._left = force_text(self._left)
|
||||
self._left = force_str(self._left)
|
||||
ret = self._left[:n]
|
||||
self._left = self._left[len(ret) :]
|
||||
return ret
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Download middlewares capture :py:class:`django_downloadview.DownloadResponse`
|
|||
responses and may replace them with optimized download responses.
|
||||
|
||||
"""
|
||||
import collections
|
||||
import collections.abc
|
||||
import copy
|
||||
import os
|
||||
|
||||
|
|
@ -14,14 +14,6 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
from django_downloadview.response import DownloadResponse
|
||||
from django_downloadview.utils import import_member
|
||||
|
||||
try:
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
except ImportError:
|
||||
|
||||
class MiddlewareMixin(object):
|
||||
def __init__(self, get_response=None):
|
||||
super(MiddlewareMixin, self).__init__()
|
||||
|
||||
|
||||
#: Sentinel value to detect whether configuration is to be loaded from Django
|
||||
#: settings or not.
|
||||
|
|
@ -38,12 +30,18 @@ def is_download_response(response):
|
|||
return isinstance(response, DownloadResponse)
|
||||
|
||||
|
||||
class BaseDownloadMiddleware(MiddlewareMixin):
|
||||
class BaseDownloadMiddleware:
|
||||
"""Base (abstract) Django middleware that handles download responses.
|
||||
|
||||
Subclasses **must** implement :py:meth:`process_download_response` method.
|
||||
|
||||
"""
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
response = self.get_response(request)
|
||||
return self.process_response(request, response)
|
||||
|
||||
def is_download_response(self, response):
|
||||
"""Return True if ``response`` can be considered as a file download.
|
||||
|
|
@ -87,11 +85,8 @@ class RealDownloadMiddleware(BaseDownloadMiddleware):
|
|||
return False
|
||||
|
||||
|
||||
class DownloadDispatcherMiddleware(BaseDownloadMiddleware):
|
||||
"Download middleware that dispatches job to several middleware instances."
|
||||
|
||||
def __init__(self, get_response=None, middlewares=AUTO_CONFIGURE):
|
||||
super(DownloadDispatcherMiddleware, self).__init__(get_response)
|
||||
class DownloadDispatcher:
|
||||
def __init__(self, middlewares=AUTO_CONFIGURE):
|
||||
#: List of children middlewares.
|
||||
self.middlewares = middlewares
|
||||
if self.middlewares is AUTO_CONFIGURE:
|
||||
|
|
@ -107,27 +102,35 @@ class DownloadDispatcherMiddleware(BaseDownloadMiddleware):
|
|||
middleware = factory(**kwargs)
|
||||
self.middlewares.append((key, middleware))
|
||||
|
||||
def process_download_response(self, request, response):
|
||||
def dispatch(self, request, response):
|
||||
"""Dispatches job to children middlewares."""
|
||||
for (key, middleware) in self.middlewares:
|
||||
response = middleware.process_response(request, response)
|
||||
return response
|
||||
|
||||
|
||||
class SmartDownloadMiddleware(BaseDownloadMiddleware):
|
||||
class DownloadDispatcherMiddleware(BaseDownloadMiddleware):
|
||||
"Download middleware that dispatches job to several middleware instances."
|
||||
|
||||
def __init__(self, get_response, middlewares=AUTO_CONFIGURE):
|
||||
super(DownloadDispatcherMiddleware, self).__init__(get_response)
|
||||
self.dispatcher = DownloadDispatcher(middlewares)
|
||||
|
||||
def process_download_response(self, request, response):
|
||||
return self.dispatcher.dispatch(request, response)
|
||||
|
||||
|
||||
class SmartDownloadMiddleware(DownloadDispatcherMiddleware):
|
||||
"""Easy to configure download middleware."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
get_response=None,
|
||||
get_response,
|
||||
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=[])
|
||||
super(SmartDownloadMiddleware, self).__init__(get_response, middlewares=[])
|
||||
#: Callable (typically a class) to instantiate backend (typically a
|
||||
#: :class:`DownloadMiddleware` subclass).
|
||||
self.backend_factory = backend_factory
|
||||
|
|
@ -160,7 +163,7 @@ class SmartDownloadMiddleware(BaseDownloadMiddleware):
|
|||
for key, options in enumerate(options_list):
|
||||
args = []
|
||||
kwargs = {}
|
||||
if isinstance(options, collections.Mapping): # Using kwargs.
|
||||
if isinstance(options, collections.abc.Mapping): # Using kwargs.
|
||||
kwargs = options
|
||||
else:
|
||||
args = options
|
||||
|
|
@ -172,10 +175,6 @@ class SmartDownloadMiddleware(BaseDownloadMiddleware):
|
|||
middleware_instance = factory(*args, **kwargs)
|
||||
self.dispatcher.middlewares.append((key, middleware_instance))
|
||||
|
||||
def process_download_response(self, request, response):
|
||||
"""Use :attr:`dispatcher` to process download response."""
|
||||
return self.dispatcher.process_download_response(request, response)
|
||||
|
||||
|
||||
class NoRedirectionMatch(Exception):
|
||||
"""Response object does not match redirection rules."""
|
||||
|
|
@ -185,7 +184,7 @@ class ProxiedDownloadMiddleware(RealDownloadMiddleware):
|
|||
"""Base class for middlewares that use optimizations of reverse proxies."""
|
||||
|
||||
def __init__(
|
||||
self, get_response=None, source_dir=None, source_url=None, destination_url=None
|
||||
self, get_response, source_dir=None, source_url=None, destination_url=None
|
||||
):
|
||||
"""Constructor."""
|
||||
super(ProxiedDownloadMiddleware, self).__init__(get_response)
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -23,6 +23,7 @@ setup(
|
|||
'Framework :: Django :: 2.2',
|
||||
'Framework :: Django :: 3.1',
|
||||
'Framework :: Django :: 3.2',
|
||||
'Framework :: Django :: 4.0',
|
||||
],
|
||||
keywords=" ".join(
|
||||
[
|
||||
|
|
|
|||
23
tox.ini
23
tox.ini
|
|
@ -1,7 +1,7 @@
|
|||
[tox]
|
||||
envlist =
|
||||
py{36,37,38,39}-dj{22,31,32}
|
||||
py{38,39}-djmain
|
||||
py{36,37,38,39,310}-dj{22,31,32}
|
||||
py{38,39,310}-dj{40,main}
|
||||
lint
|
||||
sphinx
|
||||
readme
|
||||
|
|
@ -12,12 +12,14 @@ python =
|
|||
3.7: py37
|
||||
3.8: py38, lint, sphinx, readme
|
||||
3.9: py39
|
||||
3.10: py310
|
||||
|
||||
[gh-actions:env]
|
||||
DJANGO =
|
||||
2.2: dj22
|
||||
3.1: dj31
|
||||
3.2: dj32
|
||||
4.0: dj40
|
||||
main: djmain
|
||||
|
||||
[testenv]
|
||||
|
|
@ -26,12 +28,18 @@ deps =
|
|||
dj22: Django>=2.2,<3.0
|
||||
dj31: Django>=3.1,<3.2
|
||||
dj32: Django>=3.2,<3.3
|
||||
dj40: Django>=4.0,<4.1
|
||||
djmain: https://github.com/django/django/archive/main.tar.gz
|
||||
nose
|
||||
pytest
|
||||
pytest-cov
|
||||
commands =
|
||||
pip install -e .
|
||||
pip install -e demo
|
||||
python -Wd {envbindir}/demo test --cover-package=django_downloadview --cover-package=demoproject --cover-xml {posargs: tests demoproject}
|
||||
# doctests
|
||||
pytest --cov=django_downloadview --cov=demoproject {posargs}
|
||||
# all other test cases
|
||||
coverage run --append {envbindir}/demo test {posargs: tests demoproject}
|
||||
coverage xml
|
||||
pip freeze
|
||||
ignore_outcome =
|
||||
djmain: True
|
||||
|
|
@ -65,3 +73,10 @@ commands =
|
|||
[flake8]
|
||||
max-line-length = 88
|
||||
ignore = E203, W503
|
||||
|
||||
[coverage:run]
|
||||
source = django_downloadview,demo
|
||||
|
||||
[pytest]
|
||||
DJANGO_SETTINGS_MODULE = demoproject.settings
|
||||
addopts = --doctest-modules --ignore=docs/
|
||||
|
|
|
|||
Loading…
Reference in a new issue