<jupyter_start><jupyter_text>ASGIHandlersAsyncFileASGIHandler inherits from Djangos ASGIHandler and delegates serving the actual content to the http response itself if the response has the attribute `is_async_fileresponse`.<jupyter_code># export

from asgiref.sync import sync_to_async
from django.core.handlers.asgi import ASGIHandler


class AsyncFileASGIHandler(ASGIHandler):
    """
    Same as default ASGIHandler from Django if there's no `is_async_fileresponse`
    attribute. If set to true, AsyncFileASGIHandler delegates the streaming of the
    actual response to the response to allow for statements like:
    ```python
        async with aiofiles.open(path):
            ...
    ```
    or
    ```python
        async with minio_response["Body"] as stream:
            ...
    ```
    """
    async def send_response(self, response, send):
        is_async_fileresponse = getattr(response, "is_async_fileresponse", False)
        if is_async_fileresponse:
            return await response.stream(send)
        else:
            return await super().send_response(response, send)<jupyter_output><empty_output><jupyter_text>Tests<jupyter_code># hide
import django

from django.conf import settings

try:
    settings.configure()
except RuntimeError:
    pass
class Response:
    cookies = {}
    streaming = True
    status_code = 200
    stream_called = False

    def __init__(self, content, is_async_fileresponse=None):
        self.index = -1
        self.contents = [content]
        if is_async_fileresponse is not None:
            self.is_async_fileresponse = is_async_fileresponse

    async def stream(self, send):
        self.stream_called = True
        for content in self.contents:
            await send(content)

    def __iter__(self):
        return self

    def __next__(self):
        self.index += 1
        try:
            return self.contents[self.index]
        except IndexError:
            raise StopIteration

    def items(self):
        return []

    def close(self):
        pass


def get_send(received):
    async def send(data):
        received.append(data)

    return send<jupyter_output><empty_output><jupyter_text>Happy Path<jupyter_code>app = AsyncFileASGIHandler()
content = "<h1>Content!</h1>"
response = Response(content, is_async_fileresponse=True)
received = []
send = get_send(received)
await app.send_response(response, send)
returned_content = received[0]
assert response.stream_called
assert content == returned_content<jupyter_output><empty_output><jupyter_text>Response Without is_async_fileresponse attribute<jupyter_code>app = AsyncFileASGIHandler()
content = "<h1>Content!</h1>"
response = Response(content)
received = []
send = get_send(received)
await app.send_response(response, send)
returned_content = received[1]["body"]
assert not response.stream_called
assert content == returned_content<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08531951640759931, 'fraction_numerical': 0.0037996545768566492, 'mean_word_length': 3.6188197767145134, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '268739', 'license': 'Apache-2.0', 'n_tokens_mistral': 868, 'n_tokens_neox': 836, 'n_words': 214, 'path': 'nbs/01_handlers.ipynb', 'repo_name': 'ephes/django-fileresponse', 'size': '2895'}