or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdcore-application.mddata-structures.mdexceptions-status.mdindex.mdmiddleware.mdrequests-responses.mdrouting.mdstatic-files.mdtesting.mdwebsockets.md

data-structures.mddocs/

0

# Data Structures

1

2

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.

3

4

## URL Manipulation

5

6

### URL Class

7

8

```python { .api }

9

from starlette.datastructures import URL

10

from urllib.parse import SplitResult

11

from typing import Any, Dict, Union

12

13

class URL(str):

14

"""

15

URL manipulation class with convenient methods.

16

17

Immutable URL class that provides easy access to URL components

18

and methods for creating modified URLs.

19

"""

20

21

def __new__(

22

cls,

23

url: str = "",

24

scope: Dict[str, Any] = None,

25

**components: Any

26

) -> "URL":

27

"""

28

Create URL from string or ASGI scope.

29

30

Args:

31

url: URL string

32

scope: ASGI scope dict

33

**components: URL components to override

34

"""

35

36

@property

37

def scheme(self) -> str:

38

"""URL scheme (http, https, ws, wss)."""

39

40

@property

41

def netloc(self) -> str:

42

"""Network location (host:port)."""

43

44

@property

45

def hostname(self) -> str:

46

"""Hostname without port."""

47

48

@property

49

def port(self) -> int | None:

50

"""Port number or None if not specified."""

51

52

@property

53

def path(self) -> str:

54

"""URL path."""

55

56

@property

57

def query(self) -> str:

58

"""Query string."""

59

60

@property

61

def fragment(self) -> str:

62

"""URL fragment (after #)."""

63

64

@property

65

def username(self) -> str | None:

66

"""Username from URL."""

67

68

@property

69

def password(self) -> str | None:

70

"""Password from URL."""

71

72

@property

73

def is_secure(self) -> bool:

74

"""True if scheme is https or wss."""

75

76

@property

77

def components(self) -> SplitResult:

78

"""urllib.parse.SplitResult object."""

79

80

def replace(self, **kwargs: Any) -> "URL":

81

"""

82

Create new URL with replaced components.

83

84

Args:

85

**kwargs: Components to replace (scheme, netloc, path, query, fragment)

86

87

Returns:

88

New URL with replaced components

89

"""

90

91

def include_query_params(self, **params: Any) -> "URL":

92

"""

93

Create new URL with additional query parameters.

94

95

Args:

96

**params: Query parameters to add

97

98

Returns:

99

New URL with added parameters

100

"""

101

102

def replace_query_params(self, **params: Any) -> "URL":

103

"""

104

Create new URL with replaced query parameters.

105

106

Args:

107

**params: Query parameters to set (replaces all existing)

108

109

Returns:

110

New URL with new query parameters

111

"""

112

113

def remove_query_params(

114

self,

115

keys: Union[str, list[str]]

116

) -> "URL":

117

"""

118

Create new URL with specified query parameters removed.

119

120

Args:

121

keys: Parameter key(s) to remove

122

123

Returns:

124

New URL without specified parameters

125

"""

126

```

127

128

### URLPath Class

129

130

```python { .api }

131

from starlette.datastructures import URLPath

132

133

class URLPath(str):

134

"""

135

URL path with protocol and host information.

136

137

Used for generating absolute URLs from relative paths.

138

"""

139

140

def __new__(

141

cls,

142

path: str,

143

protocol: str = "",

144

host: str = ""

145

) -> "URLPath":

146

"""

147

Create URLPath.

148

149

Args:

150

path: URL path

151

protocol: Protocol ("http" or "websocket")

152

host: Host name

153

"""

154

155

@property

156

def protocol(self) -> str:

157

"""Protocol type."""

158

159

@property

160

def host(self) -> str:

161

"""Host name."""

162

163

def make_absolute_url(self, base_url: str) -> str:

164

"""

165

Create absolute URL from base URL.

166

167

Args:

168

base_url: Base URL to combine with path

169

170

Returns:

171

Complete absolute URL

172

"""

173

```

174

175

## Headers Management

176

177

### Headers Class

178

179

```python { .api }

180

from starlette.datastructures import Headers, MutableHeaders

181

from typing import Iterator, List, Tuple

182

183

class Headers:

184

"""

185

Immutable case-insensitive HTTP headers.

186

187

Provides dictionary-like access to HTTP headers with

188

case-insensitive matching and multi-value support.

189

"""

190

191

def __init__(

192

self,

193

headers: Union[

194

Dict[str, str],

195

List[Tuple[str, str]],

196

List[Tuple[bytes, bytes]]

197

] = None,

198

raw: List[Tuple[bytes, bytes]] = None,

199

scope: Dict[str, Any] = None,

200

) -> None:

201

"""

202

Initialize headers.

203

204

Args:

205

headers: Headers as dict or list of tuples

206

raw: Raw header bytes (ASGI format)

207

scope: ASGI scope containing headers

208

"""

209

210

@property

211

def raw(self) -> List[Tuple[bytes, bytes]]:

212

"""Raw header list in ASGI format."""

213

214

def keys(self) -> List[str]:

215

"""Get all header names."""

216

217

def values(self) -> List[str]:

218

"""Get all header values."""

219

220

def items(self) -> List[Tuple[str, str]]:

221

"""Get header name-value pairs."""

222

223

def get(self, key: str, default: str = None) -> str | None:

224

"""

225

Get header value (case-insensitive).

226

227

Args:

228

key: Header name

229

default: Default value if header not found

230

231

Returns:

232

Header value or default

233

"""

234

235

def getlist(self, key: str) -> List[str]:

236

"""

237

Get all values for header (case-insensitive).

238

239

Args:

240

key: Header name

241

242

Returns:

243

List of all values for the header

244

"""

245

246

def mutablecopy(self) -> "MutableHeaders":

247

"""Create mutable copy of headers."""

248

249

# Dictionary-like access

250

def __getitem__(self, key: str) -> str:

251

"""Get header value (raises KeyError if not found)."""

252

253

def __contains__(self, key: str) -> bool:

254

"""Check if header exists (case-insensitive)."""

255

256

def __iter__(self) -> Iterator[str]:

257

"""Iterate over header names."""

258

259

def __len__(self) -> int:

260

"""Number of headers."""

261

262

class MutableHeaders(Headers):

263

"""

264

Mutable case-insensitive HTTP headers.

265

266

Extends Headers with methods for modifying header values.

267

"""

268

269

def __setitem__(self, key: str, value: str) -> None:

270

"""Set header value."""

271

272

def __delitem__(self, key: str) -> None:

273

"""Delete header."""

274

275

def setdefault(self, key: str, value: str) -> str:

276

"""Set header if not already present."""

277

278

def update(self, other: Union[Headers, Dict[str, str]]) -> None:

279

"""Update headers from another headers object or dict."""

280

281

def append(self, key: str, value: str) -> None:

282

"""Append value to existing header."""

283

284

def add_vary_header(self, vary: str) -> None:

285

"""Add value to Vary header."""

286

```

287

288

## Query Parameters

289

290

### QueryParams Class

291

292

```python { .api }

293

from starlette.datastructures import QueryParams, ImmutableMultiDict

294

295

class QueryParams(ImmutableMultiDict):

296

"""

297

URL query parameters with multi-value support.

298

299

Immutable dictionary-like container for URL query parameters

300

that supports multiple values per key.

301

"""

302

303

def __init__(

304

self,

305

query: Union[

306

str,

307

bytes,

308

Dict[str, str],

309

Dict[str, List[str]],

310

List[Tuple[str, str]]

311

] = None,

312

**kwargs: str

313

) -> None:

314

"""

315

Initialize query parameters.

316

317

Args:

318

query: Query string, dict, or list of tuples

319

**kwargs: Additional query parameters

320

"""

321

322

# Inherited from ImmutableMultiDict

323

def get(self, key: str, default: str = None) -> str | None:

324

"""Get first value for key."""

325

326

def getlist(self, key: str) -> List[str]:

327

"""Get all values for key."""

328

329

def keys(self) -> List[str]:

330

"""Get all parameter names."""

331

332

def values(self) -> List[str]:

333

"""Get all parameter values."""

334

335

def items(self) -> List[Tuple[str, str]]:

336

"""Get key-value pairs."""

337

338

def multi_items(self) -> List[Tuple[str, str]]:

339

"""Get all key-value pairs including duplicates."""

340

341

# Dictionary-like access

342

def __getitem__(self, key: str) -> str:

343

"""Get first value for key."""

344

345

def __contains__(self, key: str) -> bool:

346

"""Check if parameter exists."""

347

348

def __iter__(self) -> Iterator[str]:

349

"""Iterate over parameter names."""

350

```

351

352

## Form Data and File Uploads

353

354

### FormData Class

355

356

```python { .api }

357

from starlette.datastructures import FormData, UploadFile, MultiDict

358

359

class FormData(ImmutableMultiDict):

360

"""

361

Form data container supporting files and fields.

362

363

Immutable container for form data that can contain

364

both regular form fields and file uploads.

365

"""

366

367

def get(self, key: str, default: Any = None) -> Union[str, UploadFile, None]:

368

"""Get form field or file."""

369

370

def getlist(self, key: str) -> List[Union[str, UploadFile]]:

371

"""Get all values for form field."""

372

373

async def close(self) -> None:

374

"""Close all uploaded files to free resources."""

375

376

class UploadFile:

377

"""

378

Uploaded file wrapper with async file operations.

379

380

Represents a file uploaded through multipart form data

381

with methods for reading and manipulating file content.

382

"""

383

384

def __init__(

385

self,

386

file: BinaryIO,

387

size: int = None,

388

filename: str = None,

389

headers: Headers = None,

390

) -> None:

391

"""

392

Initialize upload file.

393

394

Args:

395

file: File-like object containing uploaded data

396

size: File size in bytes

397

filename: Original filename from client

398

headers: HTTP headers for this file part

399

"""

400

401

@property

402

def filename(self) -> str | None:

403

"""Original filename from client."""

404

405

@property

406

def file(self) -> BinaryIO:

407

"""Underlying file object."""

408

409

@property

410

def size(self) -> int | None:

411

"""File size in bytes."""

412

413

@property

414

def headers(self) -> Headers:

415

"""Headers for this file part."""

416

417

@property

418

def content_type(self) -> str | None:

419

"""MIME content type."""

420

421

async def read(self, size: int = -1) -> bytes:

422

"""

423

Read file content.

424

425

Args:

426

size: Number of bytes to read (-1 for all)

427

428

Returns:

429

File content as bytes

430

"""

431

432

async def seek(self, offset: int) -> None:

433

"""

434

Seek to position in file.

435

436

Args:

437

offset: Byte offset to seek to

438

"""

439

440

async def write(self, data: Union[str, bytes]) -> None:

441

"""

442

Write data to file.

443

444

Args:

445

data: Data to write to file

446

"""

447

448

async def close(self) -> None:

449

"""Close the file and free resources."""

450

```

451

452

## Multi-Value Dictionaries

453

454

### ImmutableMultiDict Class

455

456

```python { .api }

457

from starlette.datastructures import ImmutableMultiDict, MultiDict

458

459

class ImmutableMultiDict:

460

"""

461

Immutable multi-value dictionary.

462

463

Dictionary-like container that supports multiple values

464

per key while maintaining immutability.

465

"""

466

467

def __init__(

468

self,

469

items: Union[

470

Dict[str, str],

471

Dict[str, List[str]],

472

List[Tuple[str, str]]

473

] = None

474

) -> None:

475

"""Initialize from various input formats."""

476

477

def get(self, key: str, default: Any = None) -> Any:

478

"""Get first value for key."""

479

480

def getlist(self, key: str) -> List[Any]:

481

"""Get all values for key."""

482

483

def keys(self) -> List[str]:

484

"""Get all keys."""

485

486

def values(self) -> List[Any]:

487

"""Get all values (first value per key)."""

488

489

def items(self) -> List[Tuple[str, Any]]:

490

"""Get key-value pairs (first value per key)."""

491

492

def multi_items(self) -> List[Tuple[str, Any]]:

493

"""Get all key-value pairs including duplicates."""

494

495

# Dictionary-like interface

496

def __getitem__(self, key: str) -> Any:

497

"""Get first value for key."""

498

499

def __contains__(self, key: str) -> bool:

500

"""Check if key exists."""

501

502

def __iter__(self) -> Iterator[str]:

503

"""Iterate over keys."""

504

505

class MultiDict(ImmutableMultiDict):

506

"""

507

Mutable multi-value dictionary.

508

509

Extends ImmutableMultiDict with methods for modifying content.

510

"""

511

512

def __setitem__(self, key: str, value: Any) -> None:

513

"""Set single value for key (replaces existing)."""

514

515

def __delitem__(self, key: str) -> None:

516

"""Delete all values for key."""

517

518

def setlist(self, key: str, values: List[Any]) -> None:

519

"""Set multiple values for key."""

520

521

def append(self, key: str, value: Any) -> None:

522

"""Append value to existing values for key."""

523

524

def pop(self, key: str, default: Any = None) -> Any:

525

"""Remove and return first value for key."""

526

527

def popitem(self) -> Tuple[str, Any]:

528

"""Remove and return arbitrary key-value pair."""

529

530

def poplist(self, key: str) -> List[Any]:

531

"""Remove and return all values for key."""

532

533

def clear(self) -> None:

534

"""Remove all items."""

535

536

def setdefault(self, key: str, default: Any = None) -> Any:

537

"""Set key to default if not present."""

538

539

def update(self, *args, **kwargs) -> None:

540

"""Update with items from another mapping."""

541

```

542

543

## Utility Data Structures

544

545

### Address Class

546

547

```python { .api }

548

from starlette.datastructures import Address

549

from typing import NamedTuple

550

551

class Address(NamedTuple):

552

"""

553

Network address (host, port) tuple.

554

555

Represents client or server address information.

556

"""

557

558

host: str

559

port: int

560

```

561

562

### Secret Class

563

564

```python { .api }

565

from starlette.datastructures import Secret

566

567

class Secret(str):

568

"""

569

String that hides its value in repr.

570

571

Used for sensitive data like passwords and API keys

572

to prevent accidental exposure in logs or debug output.

573

"""

574

575

def __new__(cls, value: str) -> "Secret":

576

"""Create secret string."""

577

578

def __repr__(self) -> str:

579

"""Hide value in string representation."""

580

return f"{self.__class__.__name__}('**********')"

581

582

def __str__(self) -> str:

583

"""Return actual value when converted to string."""

584

```

585

586

### CommaSeparatedStrings Class

587

588

```python { .api }

589

from starlette.datastructures import CommaSeparatedStrings

590

591

class CommaSeparatedStrings(list[str]):

592

"""

593

Comma-separated string sequence.

594

595

Parses comma-separated strings into a list while

596

maintaining list interface.

597

"""

598

599

def __init__(self, value: Union[str, List[str]]) -> None:

600

"""

601

Initialize from string or sequence.

602

603

Args:

604

value: Comma-separated string or list of strings

605

"""

606

607

def __str__(self) -> str:

608

"""Convert back to comma-separated string."""

609

```

610

611

### State Class

612

613

```python { .api }

614

from starlette.datastructures import State

615

616

class State:

617

"""

618

Arbitrary state container with attribute access.

619

620

Simple container for storing application or request state

621

with convenient attribute-based access.

622

"""

623

624

def __init__(self, state: Dict[str, Any] = None) -> None:

625

"""

626

Initialize state container.

627

628

Args:

629

state: Initial state dictionary

630

"""

631

632

def __setattr__(self, name: str, value: Any) -> None:

633

"""Set state attribute."""

634

635

def __getattr__(self, name: str) -> Any:

636

"""Get state attribute."""

637

638

def __delattr__(self, name: str) -> None:

639

"""Delete state attribute."""

640

```

641

642

## Usage Examples

643

644

### URL Manipulation

645

646

```python { .api }

647

# Creating and manipulating URLs

648

url = URL("https://example.com/path?param=value")

649

650

print(url.scheme) # "https"

651

print(url.hostname) # "example.com"

652

print(url.path) # "/path"

653

print(url.query) # "param=value"

654

print(url.is_secure) # True

655

656

# Creating modified URLs

657

new_url = url.replace(scheme="http", path="/new-path")

658

# "http://example.com/new-path?param=value"

659

660

# Adding query parameters

661

url_with_params = url.include_query_params(new_param="new_value")

662

# "https://example.com/path?param=value&new_param=new_value"

663

664

# Replacing query parameters

665

url_new_params = url.replace_query_params(param="new_value", other="param")

666

# "https://example.com/path?param=new_value&other=param"

667

668

# Removing query parameters

669

url_no_param = url.remove_query_params("param")

670

# "https://example.com/path"

671

```

672

673

### Headers Manipulation

674

675

```python { .api }

676

# Creating headers

677

headers = Headers({

678

"content-type": "application/json",

679

"authorization": "Bearer token123"

680

})

681

682

# Case-insensitive access

683

print(headers["Content-Type"]) # "application/json"

684

print(headers.get("AUTHORIZATION")) # "Bearer token123"

685

686

# Multiple values for same header

687

headers_multi = Headers([

688

("accept", "text/html"),

689

("accept", "application/json"),

690

("accept", "*/*")

691

])

692

693

accept_values = headers_multi.getlist("accept")

694

# ["text/html", "application/json", "*/*"]

695

696

# Mutable headers

697

mutable = headers.mutablecopy()

698

mutable["x-custom"] = "custom-value"

699

mutable.append("cache-control", "no-cache")

700

mutable.add_vary_header("Accept-Encoding")

701

```

702

703

### Query Parameters

704

705

```python { .api }

706

# From query string

707

params = QueryParams("name=john&age=30&tags=python&tags=web")

708

709

print(params["name"]) # "john"

710

print(params.get("age")) # "30"

711

print(params.getlist("tags")) # ["python", "web"]

712

713

# From dictionary

714

params = QueryParams({

715

"search": "starlette",

716

"page": "2",

717

"per_page": "10"

718

})

719

720

# Iterate over parameters

721

for key in params:

722

print(f"{key}: {params[key]}")

723

```

724

725

### Form Data Handling

726

727

```python { .api }

728

async def handle_form(request):

729

form = await request.form()

730

731

# Access form fields

732

name = form.get("name", "")

733

email = form.get("email", "")

734

735

# Handle file uploads

736

avatar = form.get("avatar")

737

if avatar and isinstance(avatar, UploadFile):

738

# Read file content

739

content = await avatar.read()

740

741

# Get file info

742

filename = avatar.filename

743

content_type = avatar.content_type

744

size = avatar.size

745

746

# Save file

747

with open(f"uploads/{filename}", "wb") as f:

748

await avatar.seek(0) # Reset file position

749

while chunk := await avatar.read(1024):

750

f.write(chunk)

751

752

# Clean up

753

await avatar.close()

754

755

# Close form to clean up all files

756

await form.close()

757

758

return JSONResponse({

759

"name": name,

760

"email": email,

761

"file_uploaded": bool(avatar and avatar.filename)

762

})

763

```

764

765

### Multi-Value Dictionary Usage

766

767

```python { .api }

768

# Create multi-dict from form data

769

form_data = MultiDict([

770

("name", "John"),

771

("interests", "python"),

772

("interests", "web"),

773

("interests", "api")

774

])

775

776

# Access values

777

name = form_data["name"] # "John"

778

interests = form_data.getlist("interests") # ["python", "web", "api"]

779

780

# Modify (mutable version)

781

form_data.append("interests", "database")

782

form_data.setlist("skills", ["programming", "design"])

783

784

# All items including duplicates

785

all_items = form_data.multi_items()

786

# [("name", "John"), ("interests", "python"), ("interests", "web"), ...]

787

```

788

789

### Utility Classes Usage

790

791

```python { .api }

792

# Secret values

793

api_key = Secret("sk_live_abc123")

794

print(api_key) # Shows actual value

795

print(repr(api_key)) # Secret('**********')

796

797

# Comma-separated strings

798

allowed_hosts = CommaSeparatedStrings("localhost,127.0.0.1,example.com")

799

print(allowed_hosts) # ["localhost", "127.0.0.1", "example.com"]

800

801

# Application state

802

app.state.database_url = "postgresql://..."

803

app.state.cache = {}

804

app.state.config = {"debug": True}

805

806

# Request state

807

request.state.user_id = 123

808

request.state.start_time = time.time()

809

810

# Network address

811

client_addr = Address("192.168.1.100", 54321)

812

print(client_addr.host) # "192.168.1.100"

813

print(client_addr.port) # 54321

814

```

815

816

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.