A high-performance ASGI and WSGI web server implementation that provides comprehensive support for modern web protocols including HTTP/1, HTTP/2, WebSockets, and experimental HTTP/3
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Wrapper classes that adapt ASGI and WSGI applications to Hypercorn's internal protocol interface. These wrappers handle protocol translation, request/response lifecycle management, and provide the bridge between applications and Hypercorn's event-driven architecture.
Wrapper for ASGI applications that provides the interface between ASGI applications and Hypercorn's internal protocol handling.
class ASGIWrapper:
"""
Wrapper for ASGI applications.
Adapts ASGI applications to Hypercorn's internal protocol interface,
handling the ASGI application lifecycle and providing the necessary
sync_spawn and call_soon capabilities for ASGI compatibility.
"""
def __init__(self, app: ASGIFramework):
"""
Initialize ASGI wrapper.
Args:
app: ASGI application callable that follows the ASGI spec
"""
async def __call__(
self,
scope: Scope,
receive: ASGIReceiveCallable,
send: ASGISendCallable,
sync_spawn: Callable,
call_soon: Callable
):
"""
Execute the ASGI application.
Args:
scope: ASGI scope dictionary containing request information
receive: ASGI receive callable for getting request data
send: ASGI send callable for sending response data
sync_spawn: Function to spawn synchronous tasks
call_soon: Function to schedule tasks for immediate execution
The wrapper handles the ASGI application lifecycle, managing
the connection between Hypercorn's event-driven architecture
and the ASGI application interface.
"""Wrapper for WSGI applications that adapts them to work within Hypercorn's async environment, handling the synchronous WSGI interface within an async context.
class WSGIWrapper:
"""
Wrapper for WSGI applications.
Adapts WSGI applications to work within Hypercorn's async environment
by handling the synchronous WSGI interface and translating between
WSGI's request/response model and ASGI's event-driven interface.
"""
def __init__(self, app: WSGIFramework, max_body_size: int):
"""
Initialize WSGI wrapper.
Args:
app: WSGI application callable following WSGI spec
max_body_size: Maximum request body size in bytes
"""
async def __call__(
self,
scope: Scope,
receive: ASGIReceiveCallable,
send: ASGISendCallable,
sync_spawn: Callable,
call_soon: Callable
):
"""
Execute the WSGI application.
Args:
scope: ASGI scope dictionary (converted to WSGI environ)
receive: ASGI receive callable for getting request data
send: ASGI send callable for sending response data
sync_spawn: Function to spawn synchronous tasks (used for WSGI execution)
call_soon: Function to schedule tasks for immediate execution
The wrapper translates between ASGI's async event model and
WSGI's synchronous request/response model, handling:
- Environ dictionary creation from ASGI scope
- Request body streaming and buffering
- Response handling and chunked encoding
- Synchronous execution within async context
"""Exceptions raised during application loading and wrapping processes.
class InvalidPathError(Exception):
"""
Raised when an invalid application path is provided.
This exception occurs when the application path cannot be
resolved to a valid ASGI or WSGI application, such as:
- Module import failures
- Missing application attributes
- Invalid application callable signatures
"""Type definitions for the application frameworks supported by the wrappers.
# ASGI application interface
ASGIFramework = Callable[[Scope, ASGIReceiveCallable, ASGISendCallable], Awaitable[None]]
# WSGI application interface
WSGIFramework = Callable[[dict, Callable], Iterable[bytes]]
# ASGI scope types
Scope = HTTPScope | WebsocketScope | LifespanScope
# ASGI callable types
ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]]
ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]]from hypercorn.app_wrappers import ASGIWrapper
async def asgi_app(scope, receive, send):
"""Simple ASGI application"""
if scope['type'] == 'http':
await send({
'type': 'http.response.start',
'status': 200,
'headers': [[b'content-type', b'text/plain']],
})
await send({
'type': 'http.response.body',
'body': b'Hello from ASGI',
})
# Wrap the ASGI application
wrapper = ASGIWrapper(asgi_app)
# The wrapper is now ready for use by Hypercorn's internal protocol handlersfrom hypercorn.app_wrappers import WSGIWrapper
def wsgi_app(environ, start_response):
"""Simple WSGI application"""
status = '200 OK'
headers = [('Content-Type', 'text/plain')]
start_response(status, headers)
return [b'Hello from WSGI']
# Wrap the WSGI application with body size limit
max_body_size = 16 * 1024 * 1024 # 16MB
wrapper = WSGIWrapper(wsgi_app, max_body_size)
# The wrapper is now ready for use by Hypercorn's internal protocol handlersThe wrappers are typically used internally by Hypercorn, but can be used directly for custom server implementations:
from hypercorn.app_wrappers import ASGIWrapper, WSGIWrapper
from hypercorn.utils import is_asgi
def wrap_application(app, max_body_size=16*1024*1024):
"""Wrap application based on its type"""
if is_asgi(app):
return ASGIWrapper(app)
else:
return WSGIWrapper(app, max_body_size)
# Usage
wrapped_app = wrap_application(my_app)For advanced use cases, you can create custom wrappers following the same interface:
class CustomWrapper:
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send, sync_spawn, call_soon):
# Custom application adaptation logic
if scope['type'] == 'http':
# Handle HTTP requests
await self.handle_http(scope, receive, send)
elif scope['type'] == 'websocket':
# Handle WebSocket connections
await self.handle_websocket(scope, receive, send)
async def handle_http(self, scope, receive, send):
# Custom HTTP handling
pass
async def handle_websocket(self, scope, receive, send):
# Custom WebSocket handling
passfrom hypercorn.app_wrappers import InvalidPathError, WSGIWrapper
try:
wrapper = WSGIWrapper(invalid_app, 1024*1024)
except InvalidPathError as e:
print(f"Failed to wrap application: {e}")
# Handle invalid application pathThe application wrappers provide the essential bridge between standard Python web frameworks (ASGI/WSGI) and Hypercorn's high-performance async server architecture, enabling seamless integration of existing applications with modern protocol support.
Install with Tessl CLI
npx tessl i tessl/pypi-hypercorn