or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mddev-server.mdexceptions.mdhttp-utilities.mdindex.mdmiddleware.mdrequest-response.mdrouting.mdsecurity.mdtesting.mdurl-wsgi-utils.md

data-structures.mddocs/

0

# HTTP Data Structures

1

2

Specialized data structures for handling HTTP-specific data including multi-value dictionaries, headers, file uploads, and accept headers with proper parsing and type conversion. These structures form the foundation for HTTP data processing in Werkzeug.

3

4

## Capabilities

5

6

### MultiDict - Multi-Value Dictionary

7

8

A dictionary-like data structure that can store multiple values for a single key, essential for handling HTTP form data and query parameters.

9

10

```python { .api }

11

class MultiDict:

12

def __init__(self, mapping=None):

13

"""

14

Create a new MultiDict.

15

16

Parameters:

17

- mapping: Initial data (dict, list of tuples, or MultiDict)

18

"""

19

20

def get(self, key, default=None, type=None):

21

"""

22

Get the first value for a key with optional type conversion.

23

24

Parameters:

25

- key: Key to look up

26

- default: Default value if key not found

27

- type: Callable to convert value (e.g., int, float)

28

29

Returns:

30

First value for key, converted by type function if provided

31

"""

32

33

def getlist(self, key, type=None):

34

"""

35

Get all values for a key as a list.

36

37

Parameters:

38

- key: Key to look up

39

- type: Callable to convert each value

40

41

Returns:

42

List of all values for the key

43

"""

44

45

def add(self, key, value):

46

"""

47

Add a new value for a key without replacing existing values.

48

49

Parameters:

50

- key: Key to add value for

51

- value: Value to add

52

"""

53

54

def setlist(self, key, new_list):

55

"""

56

Set multiple values for a key, replacing any existing values.

57

58

Parameters:

59

- key: Key to set values for

60

- new_list: List of values to set

61

"""

62

63

def setlistdefault(self, key, default_list=None):

64

"""

65

Set default values for a key if it doesn't exist.

66

67

Parameters:

68

- key: Key to check/set

69

- default_list: Default list of values

70

71

Returns:

72

List of values for the key

73

"""

74

75

def items(self, multi=False):

76

"""

77

Iterate over items.

78

79

Parameters:

80

- multi: If True, yield all key-value pairs including duplicates

81

82

Yields:

83

Key-value pairs

84

"""

85

86

def lists(self):

87

"""

88

Iterate over keys and their complete list of values.

89

90

Yields:

91

(key, list_of_values) pairs

92

"""

93

94

def keys(self):

95

"""Return an iterator over all keys."""

96

97

def values(self):

98

"""Return an iterator over all values (first value per key)."""

99

100

def listvalues(self):

101

"""Return an iterator over all values (all values including duplicates)."""

102

```

103

104

### ImmutableMultiDict - Immutable Multi-Value Dictionary

105

106

An immutable version of MultiDict that raises exceptions on modification attempts.

107

108

```python { .api }

109

class ImmutableMultiDict(MultiDict):

110

def __init__(self, mapping=None):

111

"""

112

Create a new immutable MultiDict.

113

114

Parameters:

115

- mapping: Initial data (dict, list of tuples, or MultiDict)

116

"""

117

118

def copy(self):

119

"""

120

Create a mutable copy of this MultiDict.

121

122

Returns:

123

New MultiDict with same data

124

"""

125

```

126

127

### CombinedMultiDict - Combined Multi-Value Dictionaries

128

129

Combines multiple MultiDict instances into a single read-only view.

130

131

```python { .api }

132

class CombinedMultiDict:

133

def __init__(self, dicts):

134

"""

135

Create a combined view of multiple MultiDict instances.

136

137

Parameters:

138

- dicts: List of MultiDict instances to combine

139

"""

140

141

def get(self, key, default=None, type=None):

142

"""

143

Get first value for key from any of the combined dicts.

144

145

Parameters:

146

- key: Key to look up

147

- default: Default value if key not found

148

- type: Callable to convert value

149

150

Returns:

151

First value found in any dict

152

"""

153

154

def getlist(self, key, type=None):

155

"""

156

Get all values for key from all combined dicts.

157

158

Parameters:

159

- key: Key to look up

160

- type: Callable to convert each value

161

162

Returns:

163

List of all values from all dicts

164

"""

165

166

def to_dict(self, flat=True):

167

"""

168

Convert to regular dict.

169

170

Parameters:

171

- flat: If True, use only first value per key

172

173

Returns:

174

Regular dict representation

175

"""

176

```

177

178

### Headers - HTTP Headers Collection

179

180

Specialized collection for HTTP headers with case-insensitive access and proper handling of multi-value headers.

181

182

```python { .api }

183

class Headers:

184

def __init__(self, defaults=None):

185

"""

186

Create a new Headers collection.

187

188

Parameters:

189

- defaults: Initial headers (dict, list of tuples, or Headers)

190

"""

191

192

def get(self, key, default=None, type=None):

193

"""

194

Get header value with optional type conversion.

195

196

Parameters:

197

- key: Header name (case-insensitive)

198

- default: Default value if header not found

199

- type: Callable to convert value

200

201

Returns:

202

Header value, converted by type function if provided

203

"""

204

205

def set(self, _key, _value, **kw):

206

"""

207

Set a header, replacing any existing values.

208

209

Parameters:

210

- _key: Header name

211

- _value: Header value

212

- **kw: Additional parameters for the header

213

"""

214

215

def add(self, _key, _value, **kw):

216

"""

217

Add a header value without replacing existing values.

218

219

Parameters:

220

- _key: Header name

221

- _value: Header value

222

- **kw: Additional parameters for the header

223

"""

224

225

def remove(self, key):

226

"""

227

Remove all values for a header.

228

229

Parameters:

230

- key: Header name to remove

231

"""

232

233

def extend(self, *args, **kwargs):

234

"""

235

Extend headers with new values from dict, list, or other Headers.

236

237

Parameters:

238

- *args: Headers to add (dict, list, Headers)

239

- **kwargs: Header key-value pairs

240

"""

241

242

def to_wsgi_list(self):

243

"""

244

Convert to WSGI-compatible list of (name, value) tuples.

245

246

Returns:

247

List of (header_name, header_value) tuples

248

"""

249

250

def get_all(self, name):

251

"""

252

Get all values for a header as a list.

253

254

Parameters:

255

- name: Header name

256

257

Returns:

258

List of all values for the header

259

"""

260

```

261

262

### EnvironHeaders - WSGI Environment Headers Adapter

263

264

Provides a Headers-like interface to WSGI environ HTTP headers.

265

266

```python { .api }

267

class EnvironHeaders:

268

def __init__(self, environ):

269

"""

270

Create headers adapter for WSGI environ.

271

272

Parameters:

273

- environ: WSGI environment dictionary

274

"""

275

276

def get(self, key, default=None, type=None):

277

"""

278

Get header from WSGI environ.

279

280

Parameters:

281

- key: Header name

282

- default: Default value if not found

283

- type: Type conversion function

284

285

Returns:

286

Header value from environ

287

"""

288

```

289

290

### FileStorage - Uploaded File Wrapper

291

292

Represents an uploaded file with convenient access to metadata and content.

293

294

```python { .api }

295

class FileStorage:

296

def __init__(self, stream=None, filename=None, name=None, content_type=None, content_length=None, headers=None):

297

"""

298

Create a new FileStorage instance.

299

300

Parameters:

301

- stream: File-like object containing the data

302

- filename: Original filename

303

- name: Form field name

304

- content_type: MIME type of the file

305

- content_length: Size of the file in bytes

306

- headers: Additional headers

307

"""

308

309

# Properties

310

filename: str | None # Original filename

311

name: str | None # Form field name

312

content_type: str | None # MIME type

313

content_length: int # File size in bytes

314

headers: Headers # Additional headers

315

stream: IO[bytes] # File data stream

316

317

def save(self, dst, buffer_size=16384):

318

"""

319

Save file to filesystem or file-like object.

320

321

Parameters:

322

- dst: Destination path or file-like object

323

- buffer_size: Buffer size for copying data

324

"""

325

326

def read(self, length=-1):

327

"""

328

Read data from file.

329

330

Parameters:

331

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

332

333

Returns:

334

File data as bytes

335

"""

336

337

def readline(self, length=-1):

338

"""

339

Read one line from file.

340

341

Parameters:

342

- length: Maximum number of bytes to read

343

344

Returns:

345

One line as bytes

346

"""

347

348

def readlines(self):

349

"""

350

Read all lines from file.

351

352

Returns:

353

List of lines as bytes

354

"""

355

356

def seek(self, pos, whence=0):

357

"""

358

Seek to position in file.

359

360

Parameters:

361

- pos: Position to seek to

362

- whence: How to interpret pos (0=absolute, 1=relative, 2=from end)

363

"""

364

365

def tell(self):

366

"""

367

Get current position in file.

368

369

Returns:

370

Current byte position

371

"""

372

373

def close(self):

374

"""Close the file stream."""

375

```

376

377

### FileMultiDict - MultiDict for File Uploads

378

379

Specialized MultiDict for handling multiple file uploads with the same field name.

380

381

```python { .api }

382

class FileMultiDict(MultiDict):

383

def __init__(self, mapping=None):

384

"""

385

Create MultiDict specifically for FileStorage objects.

386

387

Parameters:

388

- mapping: Initial file data

389

"""

390

```

391

392

### Accept Headers

393

394

Specialized classes for parsing and handling HTTP Accept headers with quality values.

395

396

```python { .api }

397

class Accept:

398

def __init__(self, values=None):

399

"""

400

Base class for Accept header parsing.

401

402

Parameters:

403

- values: Accept header values with quality parameters

404

"""

405

406

def best_match(self, matches, default=None):

407

"""

408

Find the best match from available options.

409

410

Parameters:

411

- matches: List of available content types/languages/etc.

412

- default: Default value if no match found

413

414

Returns:

415

Best matching value based on quality scores

416

"""

417

418

def quality(self, key):

419

"""

420

Get quality value for a specific option.

421

422

Parameters:

423

- key: Option to get quality for

424

425

Returns:

426

Quality value (0.0 to 1.0)

427

"""

428

429

class MIMEAccept(Accept):

430

def __init__(self, values=None):

431

"""

432

Parse Accept header for MIME types.

433

434

Parameters:

435

- values: Accept header string or parsed values

436

"""

437

438

@property

439

def accept_html(self) -> bool:

440

"""True if HTML is accepted."""

441

442

@property

443

def accept_json(self) -> bool:

444

"""True if JSON is accepted."""

445

446

class LanguageAccept(Accept):

447

def __init__(self, values=None):

448

"""

449

Parse Accept-Language header.

450

451

Parameters:

452

- values: Accept-Language header string or parsed values

453

"""

454

455

class CharsetAccept(Accept):

456

def __init__(self, values=None):

457

"""

458

Parse Accept-Charset header.

459

460

Parameters:

461

- values: Accept-Charset header string or parsed values

462

"""

463

```

464

465

### Authorization and Authentication

466

467

Classes for handling HTTP authentication headers.

468

469

```python { .api }

470

class Authorization:

471

def __init__(self, auth_type, data=None, token=None, username=None, password=None, realm=None, nonce=None, uri=None, nc=None, cnonce=None, response=None, opaque=None, qop=None):

472

"""

473

Parse and represent Authorization header.

474

475

Parameters:

476

- auth_type: Authentication type (Basic, Digest, Bearer, etc.)

477

- data: Raw authorization data

478

- token: Bearer token

479

- username: Username for Basic/Digest auth

480

- password: Password for Basic auth

481

- realm, nonce, uri, nc, cnonce, response, opaque, qop: Digest auth parameters

482

"""

483

484

# Properties

485

type: str # Authentication type

486

username: str | None # Username

487

password: str | None # Password (Basic auth only)

488

realm: str | None # Realm

489

token: str | None # Bearer token

490

491

class WWWAuthenticate:

492

def __init__(self, auth_type=None, values=None, on_update=None):

493

"""

494

Represent WWW-Authenticate header.

495

496

Parameters:

497

- auth_type: Authentication type required

498

- values: Authentication parameters

499

- on_update: Callback for updates

500

"""

501

502

# Properties

503

type: str # Authentication type

504

realm: str | None # Authentication realm

505

```

506

507

### Cache Control

508

509

Classes for parsing and managing Cache-Control headers.

510

511

```python { .api }

512

class RequestCacheControl:

513

def __init__(self, values=None, on_update=None):

514

"""

515

Parse request Cache-Control header.

516

517

Parameters:

518

- values: Cache-Control header values

519

- on_update: Callback for updates

520

"""

521

522

# Properties

523

no_cache: bool # no-cache directive

524

no_store: bool # no-store directive

525

max_age: int | None # max-age in seconds

526

max_stale: int | None # max-stale in seconds

527

min_fresh: int | None # min-fresh in seconds

528

no_transform: bool # no-transform directive

529

only_if_cached: bool # only-if-cached directive

530

531

class ResponseCacheControl:

532

def __init__(self, values=None, on_update=None):

533

"""

534

Parse response Cache-Control header.

535

536

Parameters:

537

- values: Cache-Control header values

538

- on_update: Callback for updates

539

"""

540

541

# Properties

542

no_cache: bool # no-cache directive

543

no_store: bool # no-store directive

544

max_age: int | None # max-age in seconds

545

s_maxage: int | None # s-maxage in seconds

546

public: bool # public directive

547

private: bool # private directive

548

must_revalidate: bool # must-revalidate directive

549

proxy_revalidate: bool # proxy-revalidate directive

550

no_transform: bool # no-transform directive

551

immutable: bool # immutable directive

552

```

553

554

### Content Security Policy

555

556

Class for managing Content Security Policy headers.

557

558

```python { .api }

559

class ContentSecurityPolicy:

560

def __init__(self, values=None, on_update=None):

561

"""

562

Parse and manage CSP header.

563

564

Parameters:

565

- values: CSP directive values

566

- on_update: Callback for updates

567

"""

568

569

# Common directives as properties

570

default_src: list[str] | None

571

script_src: list[str] | None

572

style_src: list[str] | None

573

img_src: list[str] | None

574

connect_src: list[str] | None

575

font_src: list[str] | None

576

object_src: list[str] | None

577

media_src: list[str] | None

578

frame_src: list[str] | None

579

580

def to_header(self):

581

"""

582

Convert to CSP header string.

583

584

Returns:

585

Complete CSP header value

586

"""

587

```

588

589

### Range Headers

590

591

Classes for handling HTTP Range requests and responses.

592

593

```python { .api }

594

class Range:

595

def __init__(self, units, ranges):

596

"""

597

Parse HTTP Range header.

598

599

Parameters:

600

- units: Range units (usually 'bytes')

601

- ranges: List of range specifications

602

"""

603

604

units: str # Range units

605

ranges: list[tuple[int | None, int | None]] # List of (start, end) ranges

606

607

def range_for_length(self, length):

608

"""

609

Get range for content of specific length.

610

611

Parameters:

612

- length: Total content length

613

614

Returns:

615

Tuple of (start, stop) or None if invalid

616

"""

617

618

class ContentRange:

619

def __init__(self, units, start, stop, length=None, on_update=None):

620

"""

621

Represent Content-Range header.

622

623

Parameters:

624

- units: Range units

625

- start: Start position

626

- stop: Stop position

627

- length: Total length

628

- on_update: Callback for updates

629

"""

630

631

units: str # Range units

632

start: int # Start position

633

stop: int # Stop position

634

length: int | None # Total content length

635

```

636

637

### ETags

638

639

Class for handling ETag collections and validation.

640

641

```python { .api }

642

class ETags:

643

def __init__(self, strong_etags=None, weak_etags=None, star_tag=False):

644

"""

645

Represent collection of ETags.

646

647

Parameters:

648

- strong_etags: List of strong ETag values

649

- weak_etags: List of weak ETag values

650

- star_tag: Whether "*" wildcard is present

651

"""

652

653

def contains(self, etag):

654

"""

655

Check if ETag is contained in collection.

656

657

Parameters:

658

- etag: ETag to check

659

660

Returns:

661

True if ETag matches any in collection

662

"""

663

664

def contains_weak(self, etag):

665

"""

666

Check if ETag matches using weak comparison.

667

668

Parameters:

669

- etag: ETag to check

670

671

Returns:

672

True if ETag matches weakly

673

"""

674

675

def to_header(self):

676

"""

677

Convert to header string.

678

679

Returns:

680

ETag header value

681

"""

682

```

683

684

## Usage Examples

685

686

### Working with Form Data

687

688

```python

689

from werkzeug.datastructures import MultiDict

690

from werkzeug.wrappers import Request

691

692

def handle_form(environ, start_response):

693

request = Request(environ)

694

695

# Access form data with type conversion

696

age = request.form.get('age', type=int, default=0)

697

email = request.form.get('email', '')

698

699

# Get all values for checkboxes/multi-select

700

interests = request.form.getlist('interests')

701

702

# Manual MultiDict creation

703

form_data = MultiDict([

704

('name', 'John'),

705

('interests', 'coding'),

706

('interests', 'music')

707

])

708

709

# Add more values

710

form_data.add('interests', 'reading')

711

712

response = Response(f"Age: {age}, Interests: {interests}")

713

return response(environ, start_response)

714

```

715

716

### File Upload Handling

717

718

```python

719

from werkzeug.datastructures import FileStorage

720

from werkzeug.utils import secure_filename

721

import os

722

723

def handle_upload(environ, start_response):

724

request = Request(environ)

725

726

if request.method == 'POST':

727

uploaded_file = request.files.get('document')

728

729

if uploaded_file and uploaded_file.filename:

730

# Secure the filename

731

filename = secure_filename(uploaded_file.filename)

732

733

# Check file type

734

if uploaded_file.content_type.startswith('image/'):

735

# Save to uploads directory

736

upload_path = os.path.join('/uploads', filename)

737

uploaded_file.save(upload_path)

738

739

response = Response(f"Image {filename} uploaded successfully")

740

else:

741

response = Response("Only image files allowed", status=400)

742

else:

743

response = Response("No file provided", status=400)

744

else:

745

response = Response('''

746

<form method="POST" enctype="multipart/form-data">

747

<input type="file" name="document" accept="image/*">

748

<input type="submit" value="Upload">

749

</form>

750

''', mimetype='text/html')

751

752

return response(environ, start_response)

753

```

754

755

### Headers Management

756

757

```python

758

from werkzeug.datastructures import Headers

759

from werkzeug.wrappers import Response

760

761

def api_response():

762

# Create response with custom headers

763

response = Response('{"status": "success"}', mimetype='application/json')

764

765

# Add security headers

766

response.headers['X-Content-Type-Options'] = 'nosniff'

767

response.headers['X-Frame-Options'] = 'DENY'

768

response.headers['X-XSS-Protection'] = '1; mode=block'

769

770

# Add multiple values for same header

771

response.headers.add('Set-Cookie', 'session=abc123; HttpOnly')

772

response.headers.add('Set-Cookie', 'theme=dark; Path=/')

773

774

# Create headers object manually

775

custom_headers = Headers([

776

('Content-Security-Policy', "default-src 'self'"),

777

('Strict-Transport-Security', 'max-age=31536000')

778

])

779

780

# Extend response headers

781

response.headers.extend(custom_headers)

782

783

return response

784

```

785

786

### Content Negotiation with Accept Headers

787

788

```python

789

from werkzeug.wrappers import Request, Response

790

import json

791

792

def content_negotiation(environ, start_response):

793

request = Request(environ)

794

data = {"message": "Hello World", "version": "1.0"}

795

796

# Check client preferences

797

if request.accept_mimetypes.accept_json:

798

response = Response(

799

json.dumps(data),

800

mimetype='application/json'

801

)

802

elif request.accept_mimetypes.accept_html:

803

html = f"<h1>{data['message']}</h1><p>Version: {data['version']}</p>"

804

response = Response(html, mimetype='text/html')

805

elif 'application/xml' in request.accept_mimetypes:

806

xml = f"<root><message>{data['message']}</message><version>{data['version']}</version></root>"

807

response = Response(xml, mimetype='application/xml')

808

else:

809

# Plain text fallback

810

text = f"{data['message']} (v{data['version']})"

811

response = Response(text, mimetype='text/plain')

812

813

return response(environ, start_response)

814

```

815

816

### Range Requests for Large Files

817

818

```python

819

from werkzeug.datastructures import Range

820

from werkzeug.wrappers import Request, Response

821

import os

822

823

def serve_file_with_ranges(environ, start_response):

824

request = Request(environ)

825

file_path = '/path/to/large/file.mp4'

826

file_size = os.path.getsize(file_path)

827

828

# Check for Range header

829

if request.range and request.range.ranges:

830

# Get first range

831

range_spec = request.range.ranges[0]

832

start, end = request.range.range_for_length(file_size)

833

834

if start is not None and end is not None:

835

# Serve partial content

836

with open(file_path, 'rb') as f:

837

f.seek(start)

838

data = f.read(end - start)

839

840

response = Response(

841

data,

842

status=206, # Partial Content

843

mimetype='video/mp4'

844

)

845

response.headers['Content-Range'] = f'bytes {start}-{end-1}/{file_size}'

846

response.headers['Accept-Ranges'] = 'bytes'

847

848

else:

849

# Invalid range

850

response = Response(status=416) # Range Not Satisfiable

851

response.headers['Content-Range'] = f'bytes */{file_size}'

852

else:

853

# Serve full file

854

with open(file_path, 'rb') as f:

855

data = f.read()

856

857

response = Response(data, mimetype='video/mp4')

858

response.headers['Accept-Ranges'] = 'bytes'

859

response.headers['Content-Length'] = str(file_size)

860

861

return response(environ, start_response)

862

```