Skip to content

Commit 711d54b

Browse files
committed
feat: enhance documentation and improve type hints in Litestar integration
1 parent bd1adbc commit 711d54b

File tree

5 files changed

+1814
-64
lines changed

5 files changed

+1814
-64
lines changed

supertokens_python/framework/litestar/litestar_exception_handlers.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ def supertokens_exception_handler(
3333
logic in the event loop.
3434
3535
Args:
36-
request: The Litestar request object
37-
exc: The SuperTokens exception
36+
request: The Litestar request object
37+
exc: The SuperTokens exception
3838
3939
Returns:
40-
A Litestar Response object with proper status code and session cookies
40+
A Litestar Response object with proper status code and session cookies
4141
"""
4242
from supertokens_python import Supertokens
4343
from supertokens_python.framework.litestar.litestar_request import LitestarRequest
@@ -101,7 +101,7 @@ async def handle_async() -> Response[Any]:
101101
# Create a task and run it
102102
import nest_asyncio # type: ignore
103103

104-
nest_asyncio.apply()
104+
nest_asyncio.apply() # type: ignore
105105
return loop.run_until_complete(handle_async())
106106

107107

@@ -110,23 +110,23 @@ def get_exception_handlers() -> dict[int | type[Exception], Any]:
110110
Get exception handlers for SuperTokens errors.
111111
112112
Returns:
113-
A dictionary mapping exception types to handler functions.
113+
A dictionary mapping exception types to handler functions.
114114
115115
Example:
116-
```python
117-
from litestar import Litestar
118-
from supertokens_python.framework.litestar import (
119-
get_exception_handlers,
120-
get_supertokens_plugin,
121-
create_supertokens_middleware,
122-
)
123-
124-
app = Litestar(
125-
route_handlers=[...],
126-
middleware=[create_supertokens_middleware()],
127-
plugins=[get_supertokens_plugin(api_base_path="/auth")],
128-
exception_handlers=get_exception_handlers(),
129-
)
130-
```
116+
```python
117+
from litestar import Litestar
118+
from supertokens_python.framework.litestar import (
119+
get_exception_handlers,
120+
get_supertokens_plugin,
121+
create_supertokens_middleware,
122+
)
123+
124+
app = Litestar(
125+
route_handlers=[...],
126+
middleware=[create_supertokens_middleware()],
127+
plugins=[get_supertokens_plugin(api_base_path="/auth")],
128+
exception_handlers=get_exception_handlers(),
129+
)
130+
```
131131
"""
132132
return {SuperTokensError: supertokens_exception_handler} # type: ignore

supertokens_python/framework/litestar/litestar_middleware.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,31 +52,30 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
5252
async def send_wrapper(message: Message) -> None:
5353
if message["type"] == "http.response.start":
5454
# Apply session mutators to response headers
55-
if hasattr(request.state, "supertokens") and isinstance(
56-
getattr(request.state, "supertokens", None), SessionContainer
55+
if hasattr(request.state, "supertokens") and isinstance( # type: ignore
56+
getattr(request.state, "supertokens", None), # type: ignore
57+
SessionContainer, # type: ignore
5758
):
5859
# Create a temporary Litestar Response
5960
temp_response = LitestarResponseObj(content=None)
6061

6162
# Convert raw ASGI headers to dict for Litestar Response
6263
for name, value in message.get("headers", []): # type: ignore
63-
temp_response.headers[
64-
name.decode() if isinstance(name, bytes) else name
65-
] = value.decode() if isinstance(value, bytes) else value
64+
temp_response.headers[name.decode()] = value.decode()
6665

6766
# Wrap it for SuperTokens
6867
wrapped_response = LitestarResponse(temp_response)
6968

7069
# Apply session mutators (this will modify temp_response)
7170
manage_session_post_response(
72-
getattr(request.state, "supertokens"),
71+
getattr(request.state, "supertokens"), # type: ignore
7372
wrapped_response,
7473
user_context,
7574
)
7675

7776
# Convert the Litestar Response to ASGI format to get cookies as Set-Cookie headers
78-
asgi_response = temp_response.to_asgi_response(
79-
app=None, request=None
77+
asgi_response = temp_response.to_asgi_response( # type: ignore
78+
app=None, request=Request(scope, receive=receive, send=send)
8079
) # type: ignore
8180

8281
# Use the encoded headers which include Set-Cookie headers from cookies

supertokens_python/framework/litestar/litestar_plugin.py

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
14-
from typing import Union
14+
from typing import Union, cast
1515

1616
from litestar import asgi
1717
from litestar.config.app import AppConfig
@@ -31,9 +31,9 @@ def __init__(self, api_base_path: str = "/auth", app_root_path: str = ""):
3131
Initialize the SuperTokens plugin.
3232
3333
Args:
34-
api_base_path: The base path for SuperTokens API routes (default: "/auth")
35-
app_root_path: The root path of the Litestar app (e.g., "api/v1").
36-
If provided, will be stripped from api_base_path for mounting.
34+
api_base_path: The base path for SuperTokens API routes (default: "/auth")
35+
app_root_path: The root path of the Litestar app (e.g., "api/v1").
36+
If provided, will be stripped from api_base_path for mounting.
3737
"""
3838
self.full_api_base_path = api_base_path.rstrip("/")
3939
self.app_root_path = app_root_path.strip("/")
@@ -63,10 +63,10 @@ def on_app_init(self, app_config: AppConfig) -> AppConfig:
6363
Called during app initialization to register the SuperTokens ASGI app.
6464
6565
Args:
66-
app_config: The Litestar application configuration
66+
app_config: The Litestar application configuration
6767
6868
Returns:
69-
The modified application configuration
69+
The modified application configuration
7070
"""
7171
from litestar import Request, Response
7272
from litestar.types import Receive, Scope, Send
@@ -92,9 +92,9 @@ async def supertokens_asgi_app(
9292
if scope["type"] != "http":
9393
# Pass through non-HTTP requests
9494
not_found = Response(content=None, status_code=404)
95-
await not_found.to_asgi_response(app=None, request=None)(
96-
scope, receive, send
97-
) # type: ignore
95+
await not_found.to_asgi_response( # type: ignore
96+
app=None, request=Request(scope, receive, send)
97+
)(scope, receive, send)
9898
return
9999

100100
st = Supertokens.get_instance()
@@ -110,16 +110,17 @@ async def supertokens_asgi_app(
110110
response = LitestarResponse(litestar_response)
111111

112112
# Let SuperTokens middleware handle the request
113-
result: Union[LitestarResponse, None] = await st.middleware(
114-
custom_request, response, user_context
113+
result: Union[LitestarResponse, None] = cast(
114+
LitestarResponse,
115+
await st.middleware(custom_request, response, user_context),
115116
)
116117

117118
if result is None:
118119
# Request was not handled by SuperTokens
119120
not_found_response = Response(content=None, status_code=404)
120-
await not_found_response.to_asgi_response(app=None, request=None)(
121-
scope, receive, send
122-
) # type: ignore
121+
await not_found_response.to_asgi_response(
122+
app=None, request=Request(scope, receive, send)
123+
)(scope, receive, send) # type: ignore
123124
return
124125

125126
# Handle session management
@@ -133,7 +134,7 @@ async def supertokens_asgi_app(
133134
# Send the response
134135
if isinstance(result, LitestarResponse):
135136
asgi_response = result.response.to_asgi_response(
136-
app=None, request=None
137+
app=None, request=Request(scope, receive=receive, send=send)
137138
) # type: ignore
138139
await asgi_response(scope, receive, send)
139140
return
@@ -142,8 +143,11 @@ async def supertokens_asgi_app(
142143
# Handle SuperTokens-specific errors
143144
error_response_obj = Response(content=None)
144145
error_response = LitestarResponse(error_response_obj)
145-
result = await st.handle_supertokens_error(
146-
custom_request, e, error_response, user_context
146+
result = cast(
147+
LitestarResponse,
148+
await st.handle_supertokens_error(
149+
custom_request, e, error_response, user_context
150+
),
147151
)
148152

149153
# Clear the session from request.state to prevent the middleware
@@ -153,16 +157,16 @@ async def supertokens_asgi_app(
153157

154158
if isinstance(result, LitestarResponse):
155159
asgi_response = result.response.to_asgi_response(
156-
app=None, request=None
160+
app=None, request=Request(scope, receive, send)
157161
) # type: ignore
158162
await asgi_response(scope, receive, send)
159163
return
160164

161165
# Fallback - this should not normally be reached
162166
fallback_response = Response(content=None, status_code=500)
163-
await fallback_response.to_asgi_response(app=None, request=None)(
164-
scope, receive, send
165-
) # type: ignore
167+
await fallback_response.to_asgi_response(
168+
app=None, request=Request(scope, receive, send)
169+
)(scope, receive, send) # type: ignore
166170

167171
# Mount the SuperTokens ASGI app to handle auth routes
168172
app_mount = asgi(self.api_base_path, is_mount=True)(supertokens_asgi_app)
@@ -178,24 +182,24 @@ def get_supertokens_plugin(
178182
Get a configured SuperTokens plugin for Litestar.
179183
180184
Args:
181-
api_base_path: The base path for SuperTokens API routes (default: "/auth").
182-
This should match the api_base_path in your SuperTokens init().
183-
app_root_path: The root path of your Litestar app if using app path (e.g., "api/v1").
184-
This will be automatically stripped from api_base_path for proper mounting.
185+
api_base_path: The base path for SuperTokens API routes (default: "/auth").
186+
This should match the api_base_path in your SuperTokens init().
187+
app_root_path: The root path of your Litestar app if using app path (e.g., "api/v1").
188+
This will be automatically stripped from api_base_path for proper mounting.
185189
186190
Returns:
187-
A configured SupertokensPlugin instance
191+
A configured SupertokensPlugin instance
188192
189193
Example:
190-
# Without app root path
191-
app = Litestar(
192-
plugins=[get_supertokens_plugin(api_base_path="/auth")]
193-
)
194-
195-
# With app root path
196-
app = Litestar(
197-
path="api/v1",
198-
plugins=[get_supertokens_plugin(api_base_path="/api/v1/auth", app_root_path="api/v1")]
199-
)
194+
# Without app root path
195+
app = Litestar(
196+
plugins=[get_supertokens_plugin(api_base_path="/auth")]
197+
)
198+
199+
# With app root path
200+
app = Litestar(
201+
path="api/v1",
202+
plugins=[get_supertokens_plugin(api_base_path="/api/v1/auth", app_root_path="api/v1")]
203+
)
200204
"""
201205
return SupertokensPlugin(api_base_path=api_base_path, app_root_path=app_root_path)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
2+
#
3+
# This software is licensed under the Apache License, Version 2.0 (the
4+
# "License") as published by the Apache Software Foundation.
5+
#
6+
# You may not use this file except in compliance with the License. You may
7+
# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.

0 commit comments

Comments
 (0)