Skip to content

Commit

Permalink
fix uvicorn compatibility (#139)
Browse files Browse the repository at this point in the history
Changes:

The last version accidentally introduced a bug with uvicorn.
Uvicorn assumes the headers in scope being a list instead of an
iterator, which is actually an asgi spec violation.
But we work around by allowing the the contains check to succeed which
is required for uvicorn.
  • Loading branch information
devkral authored Feb 5, 2025
1 parent c9e54c4 commit db3c00f
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 1 deletion.
7 changes: 7 additions & 0 deletions docs/en/docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ hide:

# Release Notes


## 0.12.6

### Fixed

- Bug with uvicorn. It assumes the headers in scope being a list instead of an iterator.

## 0.12.5

### Added
Expand Down
2 changes: 1 addition & 1 deletion lilya/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.12.5"
__version__ = "0.12.6"
7 changes: 7 additions & 0 deletions lilya/datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ def __iter__(self) -> Generator[tuple[bytes, bytes], None, None]:
"""For compatibility with ASGI."""
return self.encoded_multi_items()

def __contains__(self, item: Any) -> bool:
try:
return super().__contains__(item)
except TypeError:
# uvicorn compatibility
return any(kv == item for kv in self.encoded_multi_items())

def get_encoded_multi_items(self) -> list[tuple[bytes, bytes]]:
"""
Returns a list of values from the bytes encoded multi items for ASGI
Expand Down
7 changes: 7 additions & 0 deletions tests/test_datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,13 @@ async def test_upload_file_repr():
assert repr(file) == "DataUpload(filename='file', size=4, headers=Header({}))"


def test_header_in():
# required for uvicorn
multi = Header([(b"content-length", b"6"), (b"Connection", b"close")])
assert (b"Connection", b"close") in multi
assert (b"foo", b"close") not in multi


@pytest.mark.anyio
async def test_upload_file_repr_headers():
stream = io.BytesIO(b"data")
Expand Down

0 comments on commit db3c00f

Please sign in to comment.