Skip to content

Commit

Permalink
Fix ASGI incompatiblity on Python 3.12
Browse files Browse the repository at this point in the history
  • Loading branch information
adamchainz committed Nov 14, 2023
1 parent dbb6520 commit edf821c
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 11 deletions.
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog
=========

* Fix ASGI incompatibility on Python 3.12.

Thanks to Grigory Vydrin for the report in `Issue #381 <https://github.com/adamchainz/django-htmx/issues/381>`__.

1.17.0 (2023-10-11)
-------------------

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ version = "1.17.0"
description = "Extensions for using Django with htmx."
readme = {file = "README.rst", content-type = "text/x-rst"}
keywords = [
"asgiref>=3.6",
"Django",
]
license = {text = "MIT"}
Expand Down
18 changes: 7 additions & 11 deletions src/django_htmx/middleware.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import asyncio
import json
from typing import Any
from typing import Awaitable
Expand All @@ -9,6 +8,8 @@
from urllib.parse import urlsplit
from urllib.parse import urlunsplit

from asgiref.sync import iscoroutinefunction
from asgiref.sync import markcoroutinefunction
from django.http import HttpRequest
from django.http.response import HttpResponseBase
from django.utils.functional import cached_property
Expand All @@ -26,29 +27,24 @@ def __init__(
),
) -> None:
self.get_response = get_response
self.async_mode = iscoroutinefunction(self.get_response)

if asyncio.iscoroutinefunction(self.get_response):
if self.async_mode:
# Mark the class as async-capable, but do the actual switch
# inside __call__ to avoid swapping out dunder methods
self._is_coroutine = (
asyncio.coroutines._is_coroutine # type: ignore [attr-defined]
)
else:
self._is_coroutine = None
markcoroutinefunction(self)

def __call__(
self, request: HttpRequest
) -> HttpResponseBase | Awaitable[HttpResponseBase]:
if self._is_coroutine:
if self.async_mode:
return self.__acall__(request)
request.htmx = HtmxDetails(request) # type: ignore [attr-defined]
return self.get_response(request)

async def __acall__(self, request: HttpRequest) -> HttpResponseBase:
request.htmx = HtmxDetails(request) # type: ignore [attr-defined]
result = self.get_response(request)
assert not isinstance(result, HttpResponseBase) # type narrow
return await result
return await self.get_response(request) # type: ignore [no-any-return, misc]


class HtmxDetails:
Expand Down

0 comments on commit edf821c

Please sign in to comment.