Classes
StaticMount
6
▼
Configuration for a static file mount point.
StaticMount
6
▼
Configuration for a static file mount point.
Attributes
| Name | Type | Description |
|---|---|---|
url_path |
str
|
— |
directory |
Path
|
— |
cache_control |
str
|
— |
precompressed |
bool
|
— |
follow_symlinks |
bool
|
— |
index_file |
str | None
|
— |
StaticFile
6
▼
Resolved static file with metadata.
StaticFile
6
▼
Resolved static file with metadata.
Attributes
| Name | Type | Description |
|---|---|---|
path |
Path
|
— |
size |
int
|
— |
mtime |
float
|
— |
mime_type |
str
|
— |
etag |
str
|
— |
encoding |
str | None
|
— |
StaticFiles
15
▼
ASGI-compatible static file handler.
Can be used as middleware or integrated into Worker.
Example…
StaticFiles
15
▼
ASGI-compatible static file handler.
Can be used as middleware or integrated into Worker.
Example as middleware:
from pounce import StaticFiles
app = StaticFiles(
app,
mounts=[
StaticMount("/static", Path("./public")),
StaticMount("/assets", Path("./dist")),
]
)
Example in Worker (built-in): config = ServerConfig(static_files={"/static": "./public"})
Methods
Internal Methods 15 ▼
__init__
2
▼
Initialize static file handler.
__init__
2
▼
def __init__(self, app: ASGIApp | None = None, *, mounts: list[StaticMount]) -> None
Parameters
| Name | Type | Description |
|---|---|---|
app |
— |
Optional ASGI app to call if path doesn't match (middleware mode) Default:None
|
mounts |
— |
List of static mount configurations |
_prepare_mounts
1
list[StaticMount]
▼
Normalize and validate mount configurations.
_prepare_mounts
1
list[StaticMount]
▼
def _prepare_mounts(self, mounts: list[StaticMount]) -> list[StaticMount]
Parameters
| Name | Type | Description |
|---|---|---|
mounts |
— |
Returns
list[StaticMount]
Sorted list of mounts (longest url_path first for correct matching)
__call__
3
▼
Handle ASGI request.
If path matches a static mount, serve the file. Otherwise…
async
__call__
3
▼
async def __call__(self, scope: dict[str, Any], receive: Receive, send: Send) -> None
Handle ASGI request.
If path matches a static mount, serve the file. Otherwise, call the app.
Parameters
| Name | Type | Description |
|---|---|---|
scope |
— |
|
receive |
— |
|
send |
— |
_resolve_file
2
StaticFile | None
▼
Resolve URL path to static file.
_resolve_file
2
StaticFile | None
▼
def _resolve_file(self, url_path: str, accept_encoding: bytes | None) -> StaticFile | None
Parameters
| Name | Type | Description |
|---|---|---|
url_path |
— |
|
accept_encoding |
— |
Returns
StaticFile | None
StaticFile if found and valid, None otherwise
_find_precompressed
4
tuple[Path, str | None]
▼
Find precompressed variant if available and client supports.
Priority: zstd > …
_find_precompressed
4
tuple[Path, str | None]
▼
def _find_precompressed(self, path: Path, mount: StaticMount, accept_encoding: bytes | None, original_stat: os.stat_result) -> tuple[Path, str | None]
Find precompressed variant if available and client supports.
Priority: zstd > gzip > identity
Parameters
| Name | Type | Description |
|---|---|---|
path |
— |
|
mount |
— |
|
accept_encoding |
— |
|
original_stat |
— |
Returns
tuple[Path, str | None]
(file_path, encoding) where encoding is "gzip", "zstd", or None
_get_mime_type
1
str
▼
Get MIME type for file.
_get_mime_type
1
str
▼
def _get_mime_type(self, path: Path) -> str
Parameters
| Name | Type | Description |
|---|---|---|
path |
— |
Returns
str
MIME type string (defaults to application/octet-stream)
_generate_etag
2
str
▼
Generate ETag from mtime and size.
Uses weak ETag (W/) because we use mtime, n…
_generate_etag
2
str
▼
def _generate_etag(self, mtime: float, size: int) -> str
Generate ETag from mtime and size.
Uses weak ETag (W/) because we use mtime, not content hash.
Parameters
| Name | Type | Description |
|---|---|---|
mtime |
— |
|
size |
— |
Returns
str
ETag header value (e.g., W/"5f3c-1a2b")
_check_not_modified
2
bool
▼
Check if client has cached version (If-None-Match).
_check_not_modified
2
bool
▼
def _check_not_modified(self, headers: list[tuple[bytes, bytes]], file: StaticFile) -> bool
Parameters
| Name | Type | Description |
|---|---|---|
headers |
— |
|
file |
— |
Returns
bool
True if client cache is valid (send 304), False otherwise
_parse_range_header
2
list[tuple[int, int]] | …
▼
Parse Range header and return list of (start, end) byte ranges.
Format: "bytes…
_parse_range_header
2
list[tuple[int, int]] | …
▼
def _parse_range_header(self, range_header: str, file_size: int) -> list[tuple[int, int]] | None
Parse Range header and return list of (start, end) byte ranges.
Format: "bytes=0-499" or "bytes=500-999" or "bytes=-500"
Parameters
| Name | Type | Description |
|---|---|---|
range_header |
— |
|
file_size |
— |
Returns
list[tuple[int, int]] | None
List of (start, end) tuples (inclusive), or None if invalid
_get_header
2
bytes | None
▼
Get header value by name (case-insensitive).
_get_header
2
bytes | None
▼
def _get_header(self, headers: list[tuple[bytes, bytes]], name: bytes) -> bytes | None
Parameters
| Name | Type | Description |
|---|---|---|
headers |
— |
|
name |
— |
Returns
bytes | None
Header value as bytes, or None if not found
_send_304
2
▼
Send 304 Not Modified response.
async
_send_304
2
▼
async def _send_304(self, file: StaticFile, send: Send) -> None
Parameters
| Name | Type | Description |
|---|---|---|
file |
— |
|
send |
— |
_send_206
3
▼
Send 206 Partial Content response.
Currently supports single range only (multi…
async
_send_206
3
▼
async def _send_206(self, file: StaticFile, ranges: list[tuple[int, int]], send: Send) -> None
Send 206 Partial Content response.
Currently supports single range only (multipart ranges not implemented).
Parameters
| Name | Type | Description |
|---|---|---|
file |
— |
|
ranges |
— |
|
send |
— |
_send_file
3
▼
Send full file response (200 OK).
async
_send_file
3
▼
async def _send_file(self, file: StaticFile, method: str, send: Send) -> None
Parameters
| Name | Type | Description |
|---|---|---|
file |
— |
|
method |
— |
|
send |
— |
_send_file_body
4
▼
Send file body using chunked reads.
TODO: Optimize with sendfile for zero-copy…
async
_send_file_body
4
▼
async def _send_file_body(self, path: Path, offset: int, count: int, send: Send) -> None
Send file body using chunked reads.
TODO: Optimize with sendfile for zero-copy transfer.
Parameters
| Name | Type | Description |
|---|---|---|
path |
— |
|
offset |
— |
|
count |
— |
|
send |
— |
_send_file_range
4
▼
Send file range (for 206 responses).
async
_send_file_range
4
▼
async def _send_file_range(self, path: Path, start: int, count: int, send: Send) -> None
Parameters
| Name | Type | Description |
|---|---|---|
path |
— |
|
start |
— |
|
count |
— |
|
send |
— |
Functions
create_static_handler
5
StaticFiles
▼
Create StaticFiles handler from simple dict config.
create_static_handler
5
StaticFiles
▼
def create_static_handler(mounts: dict[str, str], cache_control: str = 'public, max-age=3600', precompressed: bool = True, follow_symlinks: bool = False, index_file: str | None = 'index.html') -> StaticFiles
Parameters
| Name | Type | Description |
|---|---|---|
mounts |
dict[str, str] |
Dict of {url_path: directory} mappings |
cache_control |
str |
Cache-Control header value Default:'public, max-age=3600'
|
precompressed |
bool |
Serve .gz/.zst if available Default:True
|
follow_symlinks |
bool |
Allow serving symlinked files Default:False
|
index_file |
str | None |
Filename to serve for directories Default:'index.html'
|
Returns
StaticFiles