CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-starlette

The little ASGI library that shines.

Overview
Eval results
Files

data-structures.mddocs/

Data Structures

Starlette provides specialized data structures for handling web-specific data types like URLs, headers, query parameters, form data, and file uploads, with convenient APIs for manipulation and access.

URL Manipulation

URL Class

from starlette.datastructures import URL
from urllib.parse import SplitResult
from typing import Any, Dict, Union

class URL(str):
    """
    URL manipulation class with convenient methods.
    
    Immutable URL class that provides easy access to URL components
    and methods for creating modified URLs.
    """
    
    def __new__(
        cls,
        url: str = "",
        scope: Dict[str, Any] = None,
        **components: Any
    ) -> "URL":
        """
        Create URL from string or ASGI scope.
        
        Args:
            url: URL string
            scope: ASGI scope dict
            **components: URL components to override
        """
    
    @property
    def scheme(self) -> str:
        """URL scheme (http, https, ws, wss)."""
    
    @property
    def netloc(self) -> str:
        """Network location (host:port)."""
    
    @property
    def hostname(self) -> str:
        """Hostname without port."""
    
    @property
    def port(self) -> int | None:
        """Port number or None if not specified."""
    
    @property
    def path(self) -> str:
        """URL path."""
    
    @property
    def query(self) -> str:
        """Query string."""
    
    @property
    def fragment(self) -> str:
        """URL fragment (after #)."""
    
    @property
    def username(self) -> str | None:
        """Username from URL."""
    
    @property
    def password(self) -> str | None:
        """Password from URL."""
    
    @property
    def is_secure(self) -> bool:
        """True if scheme is https or wss."""
    
    @property
    def components(self) -> SplitResult:
        """urllib.parse.SplitResult object."""
    
    def replace(self, **kwargs: Any) -> "URL":
        """
        Create new URL with replaced components.
        
        Args:
            **kwargs: Components to replace (scheme, netloc, path, query, fragment)
            
        Returns:
            New URL with replaced components
        """
    
    def include_query_params(self, **params: Any) -> "URL":
        """
        Create new URL with additional query parameters.
        
        Args:
            **params: Query parameters to add
            
        Returns:
            New URL with added parameters
        """
    
    def replace_query_params(self, **params: Any) -> "URL":
        """
        Create new URL with replaced query parameters.
        
        Args:
            **params: Query parameters to set (replaces all existing)
            
        Returns:
            New URL with new query parameters
        """
    
    def remove_query_params(
        self, 
        keys: Union[str, list[str]]
    ) -> "URL":
        """
        Create new URL with specified query parameters removed.
        
        Args:
            keys: Parameter key(s) to remove
            
        Returns:
            New URL without specified parameters
        """

URLPath Class

from starlette.datastructures import URLPath

class URLPath(str):
    """
    URL path with protocol and host information.
    
    Used for generating absolute URLs from relative paths.
    """
    
    def __new__(
        cls,
        path: str,
        protocol: str = "",
        host: str = ""
    ) -> "URLPath":
        """
        Create URLPath.
        
        Args:
            path: URL path
            protocol: Protocol ("http" or "websocket")  
            host: Host name
        """
    
    @property
    def protocol(self) -> str:
        """Protocol type."""
    
    @property
    def host(self) -> str:
        """Host name."""
    
    def make_absolute_url(self, base_url: str) -> str:
        """
        Create absolute URL from base URL.
        
        Args:
            base_url: Base URL to combine with path
            
        Returns:
            Complete absolute URL
        """

Headers Management

Headers Class

from starlette.datastructures import Headers, MutableHeaders
from typing import Iterator, List, Tuple

class Headers:
    """
    Immutable case-insensitive HTTP headers.
    
    Provides dictionary-like access to HTTP headers with
    case-insensitive matching and multi-value support.
    """
    
    def __init__(
        self,
        headers: Union[
            Dict[str, str],
            List[Tuple[str, str]],
            List[Tuple[bytes, bytes]]
        ] = None,
        raw: List[Tuple[bytes, bytes]] = None,
        scope: Dict[str, Any] = None,
    ) -> None:
        """
        Initialize headers.
        
        Args:
            headers: Headers as dict or list of tuples
            raw: Raw header bytes (ASGI format)
            scope: ASGI scope containing headers
        """
    
    @property
    def raw(self) -> List[Tuple[bytes, bytes]]:
        """Raw header list in ASGI format."""
    
    def keys(self) -> List[str]:
        """Get all header names."""
    
    def values(self) -> List[str]:
        """Get all header values."""
    
    def items(self) -> List[Tuple[str, str]]:
        """Get header name-value pairs."""
    
    def get(self, key: str, default: str = None) -> str | None:
        """
        Get header value (case-insensitive).
        
        Args:
            key: Header name
            default: Default value if header not found
            
        Returns:
            Header value or default
        """
    
    def getlist(self, key: str) -> List[str]:
        """
        Get all values for header (case-insensitive).
        
        Args:
            key: Header name
            
        Returns:
            List of all values for the header
        """
    
    def mutablecopy(self) -> "MutableHeaders":
        """Create mutable copy of headers."""
    
    # Dictionary-like access
    def __getitem__(self, key: str) -> str:
        """Get header value (raises KeyError if not found)."""
    
    def __contains__(self, key: str) -> bool:
        """Check if header exists (case-insensitive)."""
    
    def __iter__(self) -> Iterator[str]:
        """Iterate over header names."""
    
    def __len__(self) -> int:
        """Number of headers."""

class MutableHeaders(Headers):
    """
    Mutable case-insensitive HTTP headers.
    
    Extends Headers with methods for modifying header values.
    """
    
    def __setitem__(self, key: str, value: str) -> None:
        """Set header value."""
    
    def __delitem__(self, key: str) -> None:
        """Delete header."""
    
    def setdefault(self, key: str, value: str) -> str:
        """Set header if not already present."""
    
    def update(self, other: Union[Headers, Dict[str, str]]) -> None:
        """Update headers from another headers object or dict."""
    
    def append(self, key: str, value: str) -> None:
        """Append value to existing header."""
    
    def add_vary_header(self, vary: str) -> None:
        """Add value to Vary header."""

Query Parameters

QueryParams Class

from starlette.datastructures import QueryParams, ImmutableMultiDict

class QueryParams(ImmutableMultiDict):
    """
    URL query parameters with multi-value support.
    
    Immutable dictionary-like container for URL query parameters
    that supports multiple values per key.
    """
    
    def __init__(
        self,
        query: Union[
            str,
            bytes, 
            Dict[str, str],
            Dict[str, List[str]],
            List[Tuple[str, str]]
        ] = None,
        **kwargs: str
    ) -> None:
        """
        Initialize query parameters.
        
        Args:
            query: Query string, dict, or list of tuples
            **kwargs: Additional query parameters
        """
    
    # Inherited from ImmutableMultiDict
    def get(self, key: str, default: str = None) -> str | None:
        """Get first value for key."""
    
    def getlist(self, key: str) -> List[str]:
        """Get all values for key."""
    
    def keys(self) -> List[str]:
        """Get all parameter names."""
    
    def values(self) -> List[str]:
        """Get all parameter values."""
    
    def items(self) -> List[Tuple[str, str]]:
        """Get key-value pairs."""
    
    def multi_items(self) -> List[Tuple[str, str]]:
        """Get all key-value pairs including duplicates."""
    
    # Dictionary-like access
    def __getitem__(self, key: str) -> str:
        """Get first value for key."""
    
    def __contains__(self, key: str) -> bool:
        """Check if parameter exists."""
    
    def __iter__(self) -> Iterator[str]:
        """Iterate over parameter names."""

Form Data and File Uploads

FormData Class

from starlette.datastructures import FormData, UploadFile, MultiDict

class FormData(ImmutableMultiDict):
    """
    Form data container supporting files and fields.
    
    Immutable container for form data that can contain
    both regular form fields and file uploads.
    """
    
    def get(self, key: str, default: Any = None) -> Union[str, UploadFile, None]:
        """Get form field or file."""
    
    def getlist(self, key: str) -> List[Union[str, UploadFile]]:
        """Get all values for form field."""
    
    async def close(self) -> None:
        """Close all uploaded files to free resources."""

class UploadFile:
    """
    Uploaded file wrapper with async file operations.
    
    Represents a file uploaded through multipart form data
    with methods for reading and manipulating file content.
    """
    
    def __init__(
        self,
        file: BinaryIO,
        size: int = None,
        filename: str = None,
        headers: Headers = None,
    ) -> None:
        """
        Initialize upload file.
        
        Args:
            file: File-like object containing uploaded data
            size: File size in bytes
            filename: Original filename from client
            headers: HTTP headers for this file part
        """
    
    @property
    def filename(self) -> str | None:
        """Original filename from client."""
    
    @property
    def file(self) -> BinaryIO:
        """Underlying file object."""
    
    @property
    def size(self) -> int | None:
        """File size in bytes."""
    
    @property
    def headers(self) -> Headers:
        """Headers for this file part."""
    
    @property
    def content_type(self) -> str | None:
        """MIME content type."""
    
    async def read(self, size: int = -1) -> bytes:
        """
        Read file content.
        
        Args:
            size: Number of bytes to read (-1 for all)
            
        Returns:
            File content as bytes
        """
    
    async def seek(self, offset: int) -> None:
        """
        Seek to position in file.
        
        Args:
            offset: Byte offset to seek to
        """
    
    async def write(self, data: Union[str, bytes]) -> None:
        """
        Write data to file.
        
        Args:
            data: Data to write to file
        """
    
    async def close(self) -> None:
        """Close the file and free resources."""

Multi-Value Dictionaries

ImmutableMultiDict Class

from starlette.datastructures import ImmutableMultiDict, MultiDict

class ImmutableMultiDict:
    """
    Immutable multi-value dictionary.
    
    Dictionary-like container that supports multiple values
    per key while maintaining immutability.
    """
    
    def __init__(
        self,
        items: Union[
            Dict[str, str],
            Dict[str, List[str]], 
            List[Tuple[str, str]]
        ] = None
    ) -> None:
        """Initialize from various input formats."""
    
    def get(self, key: str, default: Any = None) -> Any:
        """Get first value for key."""
    
    def getlist(self, key: str) -> List[Any]:
        """Get all values for key."""
    
    def keys(self) -> List[str]:
        """Get all keys."""
    
    def values(self) -> List[Any]:
        """Get all values (first value per key)."""
    
    def items(self) -> List[Tuple[str, Any]]:
        """Get key-value pairs (first value per key)."""
    
    def multi_items(self) -> List[Tuple[str, Any]]:
        """Get all key-value pairs including duplicates."""
    
    # Dictionary-like interface
    def __getitem__(self, key: str) -> Any:
        """Get first value for key."""
    
    def __contains__(self, key: str) -> bool:
        """Check if key exists."""
    
    def __iter__(self) -> Iterator[str]:
        """Iterate over keys."""

class MultiDict(ImmutableMultiDict):
    """
    Mutable multi-value dictionary.
    
    Extends ImmutableMultiDict with methods for modifying content.
    """
    
    def __setitem__(self, key: str, value: Any) -> None:
        """Set single value for key (replaces existing)."""
    
    def __delitem__(self, key: str) -> None:
        """Delete all values for key."""
    
    def setlist(self, key: str, values: List[Any]) -> None:
        """Set multiple values for key."""
    
    def append(self, key: str, value: Any) -> None:
        """Append value to existing values for key."""
    
    def pop(self, key: str, default: Any = None) -> Any:
        """Remove and return first value for key."""
    
    def popitem(self) -> Tuple[str, Any]:
        """Remove and return arbitrary key-value pair."""
    
    def poplist(self, key: str) -> List[Any]:
        """Remove and return all values for key."""
    
    def clear(self) -> None:
        """Remove all items."""
    
    def setdefault(self, key: str, default: Any = None) -> Any:
        """Set key to default if not present."""
    
    def update(self, *args, **kwargs) -> None:
        """Update with items from another mapping."""

Utility Data Structures

Address Class

from starlette.datastructures import Address
from typing import NamedTuple

class Address(NamedTuple):
    """
    Network address (host, port) tuple.
    
    Represents client or server address information.
    """
    
    host: str
    port: int

Secret Class

from starlette.datastructures import Secret

class Secret(str):
    """
    String that hides its value in repr.
    
    Used for sensitive data like passwords and API keys
    to prevent accidental exposure in logs or debug output.
    """
    
    def __new__(cls, value: str) -> "Secret":
        """Create secret string."""
    
    def __repr__(self) -> str:
        """Hide value in string representation."""
        return f"{self.__class__.__name__}('**********')"
    
    def __str__(self) -> str:
        """Return actual value when converted to string."""

CommaSeparatedStrings Class

from starlette.datastructures import CommaSeparatedStrings

class CommaSeparatedStrings(list[str]):
    """
    Comma-separated string sequence.
    
    Parses comma-separated strings into a list while
    maintaining list interface.
    """
    
    def __init__(self, value: Union[str, List[str]]) -> None:
        """
        Initialize from string or sequence.
        
        Args:
            value: Comma-separated string or list of strings
        """
    
    def __str__(self) -> str:
        """Convert back to comma-separated string."""

State Class

from starlette.datastructures import State

class State:
    """
    Arbitrary state container with attribute access.
    
    Simple container for storing application or request state
    with convenient attribute-based access.
    """
    
    def __init__(self, state: Dict[str, Any] = None) -> None:
        """
        Initialize state container.
        
        Args:
            state: Initial state dictionary
        """
    
    def __setattr__(self, name: str, value: Any) -> None:
        """Set state attribute."""
    
    def __getattr__(self, name: str) -> Any:
        """Get state attribute."""
    
    def __delattr__(self, name: str) -> None:
        """Delete state attribute."""

Usage Examples

URL Manipulation

# Creating and manipulating URLs
url = URL("https://example.com/path?param=value")

print(url.scheme)    # "https"
print(url.hostname)  # "example.com" 
print(url.path)      # "/path"
print(url.query)     # "param=value"
print(url.is_secure) # True

# Creating modified URLs
new_url = url.replace(scheme="http", path="/new-path")
# "http://example.com/new-path?param=value"

# Adding query parameters
url_with_params = url.include_query_params(new_param="new_value")
# "https://example.com/path?param=value&new_param=new_value"

# Replacing query parameters
url_new_params = url.replace_query_params(param="new_value", other="param")
# "https://example.com/path?param=new_value&other=param"

# Removing query parameters
url_no_param = url.remove_query_params("param")
# "https://example.com/path"

Headers Manipulation

# Creating headers
headers = Headers({
    "content-type": "application/json",
    "authorization": "Bearer token123"
})

# Case-insensitive access
print(headers["Content-Type"])  # "application/json"
print(headers.get("AUTHORIZATION"))  # "Bearer token123"

# Multiple values for same header
headers_multi = Headers([
    ("accept", "text/html"),
    ("accept", "application/json"),
    ("accept", "*/*")
])

accept_values = headers_multi.getlist("accept")
# ["text/html", "application/json", "*/*"]

# Mutable headers
mutable = headers.mutablecopy()
mutable["x-custom"] = "custom-value"
mutable.append("cache-control", "no-cache")
mutable.add_vary_header("Accept-Encoding")

Query Parameters

# From query string
params = QueryParams("name=john&age=30&tags=python&tags=web")

print(params["name"])        # "john"
print(params.get("age"))     # "30" 
print(params.getlist("tags")) # ["python", "web"]

# From dictionary
params = QueryParams({
    "search": "starlette",
    "page": "2",
    "per_page": "10"
})

# Iterate over parameters
for key in params:
    print(f"{key}: {params[key]}")

Form Data Handling

async def handle_form(request):
    form = await request.form()
    
    # Access form fields
    name = form.get("name", "")
    email = form.get("email", "")
    
    # Handle file uploads
    avatar = form.get("avatar")
    if avatar and isinstance(avatar, UploadFile):
        # Read file content
        content = await avatar.read()
        
        # Get file info
        filename = avatar.filename
        content_type = avatar.content_type
        size = avatar.size
        
        # Save file
        with open(f"uploads/{filename}", "wb") as f:
            await avatar.seek(0)  # Reset file position
            while chunk := await avatar.read(1024):
                f.write(chunk)
        
        # Clean up
        await avatar.close()
    
    # Close form to clean up all files
    await form.close()
    
    return JSONResponse({
        "name": name,
        "email": email,
        "file_uploaded": bool(avatar and avatar.filename)
    })

Multi-Value Dictionary Usage

# Create multi-dict from form data
form_data = MultiDict([
    ("name", "John"),
    ("interests", "python"),
    ("interests", "web"),
    ("interests", "api")
])

# Access values
name = form_data["name"]  # "John"
interests = form_data.getlist("interests")  # ["python", "web", "api"]

# Modify (mutable version)
form_data.append("interests", "database")
form_data.setlist("skills", ["programming", "design"])

# All items including duplicates
all_items = form_data.multi_items()
# [("name", "John"), ("interests", "python"), ("interests", "web"), ...]

Utility Classes Usage

# Secret values
api_key = Secret("sk_live_abc123")
print(api_key)        # Shows actual value
print(repr(api_key))  # Secret('**********')

# Comma-separated strings
allowed_hosts = CommaSeparatedStrings("localhost,127.0.0.1,example.com")
print(allowed_hosts)  # ["localhost", "127.0.0.1", "example.com"]

# Application state
app.state.database_url = "postgresql://..."
app.state.cache = {}
app.state.config = {"debug": True}

# Request state
request.state.user_id = 123
request.state.start_time = time.time()

# Network address
client_addr = Address("192.168.1.100", 54321)
print(client_addr.host)  # "192.168.1.100"
print(client_addr.port)  # 54321

Starlette's data structures provide convenient, type-safe handling of web-specific data with immutable defaults, comprehensive APIs, and proper resource management for files and other resources.

Install with Tessl CLI

npx tessl i tessl/pypi-starlette

docs

authentication.md

core-application.md

data-structures.md

exceptions-status.md

index.md

middleware.md

requests-responses.md

routing.md

static-files.md

testing.md

websockets.md

tile.json