Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace starlettes Headers and MutableHeaders, move FormMultiDict to multidict #732

Merged
merged 18 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ repos:
args: ["--unsafe-load-any-extension=y"]
additional_dependencies:
[
multidict,
orjson,
piccolo,
picologging,
Expand All @@ -128,6 +129,7 @@ repos:
[
aiomcache,
httpx,
multidict,
orjson,
piccolo,
picologging,
Expand Down Expand Up @@ -160,6 +162,7 @@ repos:
httpx,
hypothesis,
mako,
multidict,
orjson,
jinja2,
piccolo,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Headers

::: starlite.datastructures.Headers
options:
members:
- __init__
- from_scope

::: starlite.datastructures.MutableScopeHeaders
options:
members:
- __init__
- add
- getall
- extend_header_value

::: starlite.datastructures.ResponseHeader
options:
members:
Expand Down
1 change: 1 addition & 0 deletions docs/reference/datastructures/7-form-multi-dict.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
options:
members:
- close
- multi_items
2 changes: 1 addition & 1 deletion docs/usage/2-route-handlers/0-route-handlers-concept.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Additionally, you can specify the following special kwargs, what's called "reser
```python
from typing import Any, Dict
from starlite import State, Request, get
from starlette.datastructures import Headers
from starlite.datastructures import Headers


@get(path="/")
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ nav:
- reference/datastructures/0-state.md
- reference/datastructures/1-cookie.md
- reference/datastructures/2-provide.md
- reference/datastructures/3-header.md
- reference/datastructures/3-headers.md
- reference/datastructures/4-background.md
- reference/datastructures/5-response-containers.md
- reference/datastructures/6-upload-file.md
Expand Down
71 changes: 70 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ starlette = ">=0.21"
starlite-multipart = ">=1.2.0"
structlog = { version = "*", optional = true }
typing-extensions = "*"
multidict = ">=6.0.2"

[tool.poetry.group.dev.dependencies]
aiomcache = "*"
Expand Down
5 changes: 3 additions & 2 deletions starlite/connection/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
cast,
)

from starlette.datastructures import URL, Address, Headers, URLPath
from starlette.datastructures import URL, Address, URLPath

from starlite.datastructures.headers import Headers
from starlite.datastructures.state import State
from starlite.exceptions import ImproperlyConfiguredException
from starlite.parsers import parse_cookie_string, parse_query_params
Expand Down Expand Up @@ -151,7 +152,7 @@ def headers(self) -> Headers:
"""
if self._headers is Empty:
self.scope.setdefault("headers", [])
self._headers = self.scope["_headers"] = Headers(scope=self.scope) # type: ignore[typeddict-item]
self._headers = self.scope["_headers"] = Headers.from_scope(self.scope) # type: ignore[typeddict-item]
return cast("Headers", self._headers)

@property
Expand Down
2 changes: 1 addition & 1 deletion starlite/connection/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,6 @@ async def send_push_promise(self, path: str) -> None:
if "http.response.push" in extensions:
raw_headers = []
for name in SERVER_PUSH_HEADERS:
for value in self.headers.getlist(name):
for value in self.headers.getall(name, []):
raw_headers.append((name.encode("latin-1"), value.encode("latin-1")))
await self.send({"type": "http.response.push", "path": path, "headers": raw_headers})
6 changes: 3 additions & 3 deletions starlite/connection/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
)

from orjson import OPT_OMIT_MICROSECONDS, OPT_SERIALIZE_NUMPY, dumps, loads
from starlette.datastructures import Headers

from starlite.connection.base import (
ASGIConnection,
Expand All @@ -21,6 +20,7 @@
empty_receive,
empty_send,
)
from starlite.datastructures.headers import Headers
from starlite.exceptions import WebSocketDisconnect, WebSocketException
from starlite.status_codes import WS_1000_NORMAL_CLOSURE
from starlite.utils.serialization import default_serializer
Expand Down Expand Up @@ -137,10 +137,10 @@ async def accept(
_headers: List[Tuple[bytes, bytes]] = headers if isinstance(headers, list) else []

if isinstance(headers, dict):
_headers = Headers(headers=headers).raw
_headers = Headers(headers=headers).to_header_list()

if isinstance(headers, Headers):
_headers = headers.raw
_headers = headers.to_header_list()

event: "WebSocketAcceptEvent" = {
"type": "websocket.accept",
Expand Down
11 changes: 9 additions & 2 deletions starlite/datastructures/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from starlite.datastructures.background_tasks import BackgroundTask, BackgroundTasks
from starlite.datastructures.cookie import Cookie
from starlite.datastructures.form_multi_dict import FormMultiDict
from starlite.datastructures.headers import CacheControlHeader, ETag
from starlite.datastructures.headers import (
CacheControlHeader,
ETag,
Headers,
MutableScopeHeaders,
)
from starlite.datastructures.provide import Provide
from starlite.datastructures.response_containers import (
File,
Expand All @@ -17,11 +22,13 @@
__all__ = (
"BackgroundTask",
"BackgroundTasks",
"Cookie",
"CacheControlHeader",
"Cookie",
"ETag",
"File",
"FormMultiDict",
"Headers",
"MutableScopeHeaders",
"Provide",
"Redirect",
"ResponseContainer",
Expand Down
32 changes: 29 additions & 3 deletions starlite/datastructures/form_multi_dict.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
from typing import Any
from typing import Any, Iterable, List, Mapping, Optional, Tuple, Union

from starlette.datastructures import ImmutableMultiDict
from multidict import MultiDict, MultiDictProxy

from starlite.datastructures.upload_file import UploadFile
from starlite.utils import deprecated


class FormMultiDict(ImmutableMultiDict[str, Any]):
class FormMultiDict(MultiDictProxy[Any]):
def __init__(
self, args: Optional[Union["FormMultiDict", Mapping[str, Any], Iterable[Tuple[str, Any]]]] = None
) -> None:
super().__init__(MultiDict(args or {}))

def multi_items(self) -> List[Tuple[str, Any]]:
"""Get all keys and values, including duplicates.

Returns:
A list of tuples containing key-value pairs
"""
return [(key, value) for key in set(self) for value in self.getall(key)]

@deprecated("1.36.0", alternative="FormMultiDict.getall")
def getlist(self, key: str) -> List[str]:
"""Get all values.

Args:
key: The key

Returns:
A list of values
"""
return super().getall(key, [])

async def close(self) -> None:
"""Closes all files in the multi-dict.

Expand Down
Loading