Run pre-commit on all files

This commit is contained in:
Rémy HUBSCHER 2024-08-05 10:51:17 +02:00
parent dd35f867e0
commit 711b2e50b5
No known key found for this signature in database
GPG key ID: A500E24B95405094
53 changed files with 90 additions and 56 deletions

View file

@ -11,7 +11,7 @@ This is a `Jazzband <https://jazzband.co>`_ project. By contributing you agree t
This document provides guidelines for people who want to contribute to
`django-downloadview`.
``django-downloadview``.
**************
@ -50,7 +50,7 @@ Use topic branches
Fork, clone
***********
Clone `django-downloadview` repository (adapt to use your own fork):
Clone ``django-downloadview`` repository (adapt to use your own fork):
.. code:: sh
@ -62,7 +62,7 @@ Clone `django-downloadview` repository (adapt to use your own fork):
Usual actions
*************
The `Makefile` is the reference card for usual actions in development
The ``Makefile`` is the reference card for usual actions in development
environment:
* Install development toolkit with `pip`_: ``make develop``.
@ -70,7 +70,7 @@ environment:
* Run tests with `tox`_: ``make test``.
* Build documentation: ``make documentation``. It builds `Sphinx`_
documentation in `var/docs/html/index.html`.
documentation in ``var/docs/html/index.html``.
* Release project with `zest.releaser`_: ``make release``.
@ -84,7 +84,7 @@ See also ``make help``.
Demo project included
*********************
The `demo` included in project's repository is part of the tests and
The ``demo`` included in project's repository is part of the tests and
documentation. Maintain it along with code and documentation.

View file

@ -26,16 +26,16 @@ django-downloadview
:target: https://codecov.io/gh/jazzband/django-downloadview
:alt: Coverage
`django-downloadview` makes it easy to serve files with `Django`_:
``django-downloadview`` makes it easy to serve files with `Django`_:
* you manage files with Django (permissions, filters, generation, ...);
* files are stored somewhere or generated somehow (local filesystem, remote
storage, memory...);
* `django-downloadview` helps you stream the files with very little code;
* ``django-downloadview`` helps you stream the files with very little code;
* `django-downloadview` helps you improve performances with reverse proxies,
* ``django-downloadview`` helps you improve performances with reverse proxies,
via mechanisms such as Nginx's X-Accel or Apache's X-Sendfile.

View file

@ -3,7 +3,7 @@ Demo project
############
`Demo folder in project's repository`_ contains a Django project to illustrate
`django-downloadview` usage.
``django-downloadview`` usage.
*****************************************

View file

@ -58,4 +58,4 @@ class ModifiedHeadersTestCase(django.test.TestCase):
basename="hello-world.txt",
file_path="/apache-modified-headers/hello-world.txt",
)
self.assertEqual(response['X-Test'], 'header')
self.assertEqual(response["X-Test"], "header")

View file

@ -1,4 +1,5 @@
"""URL mapping."""
from django.urls import path
from demoproject.apache import views

View file

@ -27,7 +27,7 @@ optimized_by_decorator = x_sendfile(
def _modified_headers(request):
view = StorageDownloadView.as_view(storage=storage, path="hello-world.txt")
response = view(request)
response["X-Test"] = 'header'
response["X-Test"] = "header"
return response

View file

@ -58,4 +58,4 @@ class ModifiedHeadersTestCase(django.test.TestCase):
basename="hello-world.txt",
file_path="/lighttpd-modified-headers/hello-world.txt",
)
self.assertEqual(response['X-Test'], 'header')
self.assertEqual(response["X-Test"], "header")

View file

@ -1,4 +1,5 @@
"""URL mapping."""
from django.urls import path
from demoproject.lighttpd import views

View file

@ -27,7 +27,7 @@ optimized_by_decorator = x_sendfile(
def _modified_headers(request):
view = StorageDownloadView.as_view(storage=storage, path="hello-world.txt")
response = view(request)
response["X-Test"] = 'header'
response["X-Test"] = "header"
return response

View file

@ -70,4 +70,4 @@ class ModifiedHeadersTestCase(django.test.TestCase):
with_buffering=None,
limit_rate=None,
)
self.assertEqual(response['X-Test'], 'header')
self.assertEqual(response["X-Test"], "header")

View file

@ -27,7 +27,7 @@ optimized_by_decorator = x_accel_redirect(
def _modified_headers(request):
view = StorageDownloadView.as_view(storage=storage, path="hello-world.txt")
response = view(request)
response["X-Test"] = 'header'
response["X-Test"] = "header"
return response

View file

@ -1,4 +1,5 @@
"""Django settings for django-downloadview demo project."""
import os

View file

@ -44,8 +44,7 @@ class StaticPathTestCase(django.test.TestCase):
url = reverse("storage:static_path", kwargs={"path": "1.txt"})
year = datetime.date.today().year + 4
response = self.client.get(
url,
HTTP_IF_MODIFIED_SINCE=f"Sat, 29 Oct {year} 19:43:31 GMT",
url, headers={"if-modified-since": f"Sat, 29 Oct {year} 19:43:31 GMT"}
)
self.assertTrue(isinstance(response, HttpResponseNotModified))
@ -55,7 +54,7 @@ class StaticPathTestCase(django.test.TestCase):
setup_file("1.txt")
url = reverse("storage:static_path", kwargs={"path": "1.txt"})
response = self.client.get(
url, HTTP_IF_MODIFIED_SINCE="Sat, 29 Oct 1980 19:43:31 GMT"
url, headers={"if-modified-since": "Sat, 29 Oct 1980 19:43:31 GMT"}
)
assert_download_response(
self,

View file

@ -1,4 +1,5 @@
"""Test suite for demoproject.download."""
from django.test import TestCase
from django.urls import reverse

View file

@ -12,6 +12,7 @@ middleware here, or combine a Django application with an application of another
framework.
"""
import os
from django.core.wsgi import get_wsgi_application

View file

@ -1,4 +1,5 @@
"""Serve files with Django and reverse proxies."""
from django_downloadview.api import * # NoQA
import importlib.metadata

View file

@ -5,6 +5,7 @@ See also `documentation of mod_xsendfile for Apache
Apache optimizations </optimizations/apache>`.
"""
# API shortcuts.
from django_downloadview.apache.decorators import x_sendfile # NoQA
from django_downloadview.apache.middlewares import XSendfileMiddleware # NoQA

View file

@ -1,4 +1,5 @@
"""Decorators to apply Apache X-Sendfile on a specific view."""
from django_downloadview.apache.middlewares import XSendfileMiddleware
from django_downloadview.decorators import DownloadDecorator

View file

@ -1,4 +1,5 @@
"""Apache's specific responses."""
import os.path
from django_downloadview.response import ProxiedDownloadResponse, content_disposition
@ -7,11 +8,13 @@ from django_downloadview.response import ProxiedDownloadResponse, content_dispos
class XSendfileResponse(ProxiedDownloadResponse):
"Delegates serving file to Apache via X-Sendfile header."
def __init__(self, file_path, content_type, basename=None, attachment=True, headers=None):
def __init__(
self, file_path, content_type, basename=None, attachment=True, headers=None
):
"""Return a HttpResponse with headers for Apache X-Sendfile."""
# content-type must be provided only as keyword argument to response
if headers and content_type:
headers.pop('Content-Type', None)
headers.pop("Content-Type", None)
super().__init__(content_type=content_type, headers=headers)
if attachment:
self.basename = basename or os.path.basename(file_path)

View file

@ -1,5 +1,6 @@
# flake8: noqa
"""Declaration of API shortcuts."""
from django_downloadview.files import HTTPFile, StorageFile, VirtualFile
from django_downloadview.io import BytesIteratorIO, TextIteratorIO
from django_downloadview.middlewares import (

View file

@ -1,4 +1,5 @@
"""File wrappers for use as exchange data between views and responses."""
from io import BytesIO
from urllib.parse import urlparse

View file

@ -1,4 +1,5 @@
"""Low-level IO operations, for use with file wrappers."""
import io
from django.utils.encoding import force_bytes, force_str

View file

@ -6,6 +6,7 @@ See also `documentation of X-Sendfile for Lighttpd
</optimizations/lighttpd>`.
"""
# API shortcuts.
from django_downloadview.lighttpd.decorators import x_sendfile # NoQA
from django_downloadview.lighttpd.middlewares import XSendfileMiddleware # NoQA

View file

@ -1,4 +1,5 @@
"""Decorators to apply Lighttpd X-Sendfile on a specific view."""
from django_downloadview.decorators import DownloadDecorator
from django_downloadview.lighttpd.middlewares import XSendfileMiddleware

View file

@ -1,4 +1,5 @@
"""Lighttpd's specific responses."""
import os.path
from django_downloadview.response import ProxiedDownloadResponse, content_disposition
@ -7,11 +8,13 @@ from django_downloadview.response import ProxiedDownloadResponse, content_dispos
class XSendfileResponse(ProxiedDownloadResponse):
"Delegates serving file to Lighttpd via X-Sendfile header."
def __init__(self, file_path, content_type, basename=None, attachment=True, headers=None):
def __init__(
self, file_path, content_type, basename=None, attachment=True, headers=None
):
"""Return a HttpResponse with headers for Lighttpd X-Sendfile."""
# content-type must be porvided only as keyword argument to response
if headers and content_type:
headers.pop('Content-Type', None)
headers.pop("Content-Type", None)
super().__init__(content_type=content_type, headers=headers)
if attachment:
self.basename = basename or os.path.basename(file_path)

View file

@ -4,6 +4,7 @@ Download middlewares capture :py:class:`django_downloadview.DownloadResponse`
responses and may replace them with optimized download responses.
"""
import collections.abc
import copy
import os
@ -36,6 +37,7 @@ class BaseDownloadMiddleware:
Subclasses **must** implement :py:meth:`process_download_response` method.
"""
def __init__(self, get_response):
self.get_response = get_response
@ -75,9 +77,8 @@ class RealDownloadMiddleware(BaseDownloadMiddleware):
whose file attribute have either an URL or a file name.
"""
return (
super().is_download_response(response)
and bool(getattr(response.file, 'url', None) or getattr(response.file, 'name', None))
return super().is_download_response(response) and bool(
getattr(response.file, "url", None) or getattr(response.file, "name", None)
)
@ -91,7 +92,7 @@ class DownloadDispatcher:
def auto_configure_middlewares(self):
"""Populate :attr:`middlewares` from
``settings.DOWNLOADVIEW_MIDDLEWARES``."""
for (key, import_string, kwargs) in getattr(
for key, import_string, kwargs in getattr(
settings, "DOWNLOADVIEW_MIDDLEWARES", []
):
factory = import_member(import_string)
@ -100,7 +101,7 @@ class DownloadDispatcher:
def dispatch(self, request, response):
"""Dispatches job to children middlewares."""
for (key, middleware) in self.middlewares:
for key, middleware in self.middlewares:
response = middleware.process_response(request, response)
return response

View file

@ -5,6 +5,7 @@ See also `Nginx X-accel documentation <http://wiki.nginx.org/X-accel>`_ and
</optimizations/nginx>`.
"""
# API shortcuts.
from django_downloadview.nginx.decorators import x_accel_redirect # NoQA
from django_downloadview.nginx.middlewares import XAccelRedirectMiddleware # NoQA

View file

@ -1,4 +1,5 @@
"""Decorators to apply Nginx X-Accel on a specific view."""
from django_downloadview.decorators import DownloadDecorator
from django_downloadview.nginx.middlewares import XAccelRedirectMiddleware

View file

@ -1,4 +1,5 @@
"""Nginx's specific responses."""
from datetime import timedelta
from django.utils.timezone import now
@ -24,7 +25,7 @@ class XAccelRedirectResponse(ProxiedDownloadResponse):
"""Return a HttpResponse with headers for Nginx X-Accel-Redirect."""
# content-type must be porvided only as keyword argument to response
if headers and content_type:
headers.pop('Content-Type', None)
headers.pop("Content-Type", None)
super().__init__(content_type=content_type, headers=headers)
if attachment:
self.basename = basename or url_basename(redirect_url, content_type)

View file

@ -7,6 +7,7 @@
for details.
"""
import warnings
from django.conf import settings

View file

@ -1,4 +1,5 @@
""":py:class:`django.http.HttpResponse` subclasses."""
import mimetypes
import os
import re
@ -77,11 +78,10 @@ def content_disposition(filename):
# which can permit a reflected file download attack. The UTF-8
# version is immune because it's not quoted.
ascii_filename = (
encode_basename_ascii(filename).replace("\\", "\\\\").replace('"', r'\"')
encode_basename_ascii(filename).replace("\\", "\\\\").replace('"', r"\"")
)
utf8_filename = encode_basename_utf8(filename)
if ascii_filename == utf8_filename: # ASCII only.
return f'attachment; filename="{ascii_filename}"'
else:
return (

View file

@ -1,4 +1,5 @@
"""Port of django-sendfile in django-downloadview."""
from django_downloadview.views.path import PathDownloadView

View file

@ -1,4 +1,5 @@
"""Utility functions that may be implemented in external packages."""
import re
charset_pattern = re.compile(r"charset=(?P<charset>.+)$", re.I | re.U)

View file

@ -1,4 +1,5 @@
"""Views to stream files."""
# API shortcuts.
from django_downloadview.views.base import BaseDownloadView, DownloadMixin # NoQA
from django_downloadview.views.http import HTTPDownloadView # NoQA

View file

@ -1,5 +1,6 @@
"""Base material for download views: :class:`DownloadMixin` and
:class:`BaseDownloadView`"""
import calendar
from django.http import Http404, HttpResponseNotModified
@ -156,7 +157,7 @@ class DownloadMixin(object):
except exceptions.FileNotFound:
return self.file_not_found_response()
# Respect the If-Modified-Since header.
since = self.request.META.get("HTTP_IF_MODIFIED_SINCE", None)
since = self.request.headers.get("if-modified-since", None)
if since is not None:
if not self.was_modified_since(self.file_instance, since):
return self.not_modified_response(**response_kwargs)

View file

@ -1,4 +1,5 @@
"""Stream files given an URL, i.e. files you want to proxy."""
from django_downloadview.files import HTTPFile
from django_downloadview.views.base import BaseDownloadView
@ -44,5 +45,5 @@ class HTTPDownloadView(BaseDownloadView):
request_factory=self.get_request_factory(),
name=self.get_basename(),
url=self.get_url(),
**self.get_request_kwargs()
**self.get_request_kwargs(),
)

View file

@ -1,4 +1,5 @@
"""Stream files that live in models."""
from django.views.generic.detail import SingleObjectMixin
from django_downloadview.exceptions import FileNotFound

View file

@ -1,4 +1,5 @@
""":class:`PathDownloadView`."""
import os
from django.core.files import File

View file

@ -1,4 +1,5 @@
"""Stream files from storage."""
from django.core.files.storage import DefaultStorage
from django_downloadview.files import StorageFile

View file

@ -1,4 +1,5 @@
"""Stream files that you generate or that live in memory."""
from django_downloadview.views.base import BaseDownloadView

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""django-downloadview documentation build configuration file."""
import os
import re
import importlib.metadata
@ -51,7 +51,7 @@ author_slug = re.sub(r"([\w_.-]+)", "-", author)
# The full version, including alpha/beta/rc tags.
release = importlib.metadata.version("django-downloadview")
# The short X.Y version.
version = '.'.join(release.split('.')[:2])
version = ".".join(release.split(".")[:2])
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View file

@ -41,4 +41,3 @@ Example, related to :doc:`StorageDownloadView demo </views/storage>`:
.. literalinclude:: /../demo/demoproject/storage/tests.py
:language: python
:lines: 1-2, 8-12, 59-

View file

@ -10,7 +10,7 @@ setup(
setup_requires=["setuptools_scm"],
description="Serve files with Django and reverse-proxies.",
long_description=open(os.path.join(here, "README.rst")).read(),
long_description_content_type='text/x-rst',
long_description_content_type="text/x-rst",
classifiers=[
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: BSD License",
@ -20,9 +20,9 @@ setup(
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
'Framework :: Django',
'Framework :: Django :: 4.2',
'Framework :: Django :: 5.0',
"Framework :: Django",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
],
keywords=" ".join(
[

View file

@ -1,4 +1,5 @@
"""Test suite around :mod:`django_downloadview.api` and deprecation plan."""
from importlib import import_module, reload
import unittest
import warnings
@ -130,7 +131,7 @@ class DeprecatedAPITestCase(django.test.SimpleTestCase):
reload(django_downloadview.nginx.settings)
caught = False
for warning_item in warning_list:
if warning_item.category == DeprecationWarning:
if warning_item.category is DeprecationWarning:
if "deprecated" in str(warning_item.message):
if setting_name in str(warning_item.message):
caught = True

View file

@ -1,4 +1,5 @@
"""Tests around :mod:`django_downloadview.io`."""
import unittest
from django_downloadview import BytesIteratorIO, TextIteratorIO

View file

@ -1,4 +1,5 @@
"""Tests around project's distribution and packaging."""
import importlib.metadata
import os
import unittest

View file

@ -1,4 +1,5 @@
"""Unit tests around responses."""
import unittest
from django_downloadview.response import DownloadResponse
@ -23,12 +24,9 @@ class DownloadResponseTestCase(unittest.TestCase):
def test_content_disposition_escaping(self):
"""Content-Disposition headers escape special characters."""
response = DownloadResponse(
"fake file",
attachment=True,
basename=r'"malicious\file.exe'
"fake file", attachment=True, basename=r'"malicious\file.exe'
)
headers = response.default_headers
self.assertIn(
r'filename="\"malicious\\file.exe"',
headers["Content-Disposition"]
r'filename="\"malicious\\file.exe"', headers["Content-Disposition"]
)

View file

@ -1,4 +1,5 @@
"""Tests around :py:mod:`django_downloadview.sendfile`."""
from django.http import Http404
import django.test

View file

@ -1,4 +1,5 @@
"""Tests around :mod:`django_downloadview.views`."""
import calendar
from datetime import datetime
import os