or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

command-line.mdcontext-management.mdcss-processing.mddocument-processing.mdfile-handling.mdindex.mdpdf-features.mdutilities.mdwsgi-integration.md

wsgi-integration.mddocs/

0

# WSGI Integration

1

2

WSGI middleware components for integrating PDF generation directly into web applications with automatic HTML-to-PDF conversion, content filtering, and seamless web framework integration.

3

4

## Capabilities

5

6

### WSGI Middleware Architecture

7

8

Complete WSGI middleware system for automatic PDF conversion in web applications with flexible filtering and processing capabilities.

9

10

```python { .api }

11

class Filter:

12

"""

13

Base WSGI filter class for content transformation.

14

15

Provides foundation for WSGI-based content filtering

16

and transformation with pluggable processing pipeline.

17

"""

18

def __init__(self, app):

19

"""

20

Initialize WSGI filter with wrapped application.

21

22

Args:

23

app: WSGI application to wrap

24

"""

25

26

def __call__(self, environ, start_response):

27

"""

28

WSGI application interface for request processing.

29

30

Args:

31

environ (dict): WSGI environment dictionary

32

start_response (callable): WSGI start_response callable

33

34

Returns:

35

Response iterator

36

"""

37

38

def should_filter(self):

39

"""

40

Determine if filtering should be applied to current request.

41

42

Returns:

43

bool: True if request should be filtered

44

"""

45

46

def filter(self):

47

"""

48

Apply filter transformation to response content.

49

50

Processes response content and applies necessary

51

transformations based on filter configuration.

52

"""

53

54

class HTMLFilter(Filter):

55

"""

56

HTML-specific WSGI filter for HTML content processing.

57

58

Extends base Filter with HTML-specific processing

59

capabilities and content type handling.

60

"""

61

62

class PisaMiddleware(HTMLFilter):

63

"""

64

WSGI middleware for automatic HTML-to-PDF conversion.

65

66

Intercepts HTML responses and converts them to PDF format

67

based on request parameters and configuration settings.

68

"""

69

```

70

71

### Automatic PDF Conversion

72

73

Seamless integration that automatically converts HTML responses to PDF based on URL parameters, headers, or content negotiation.

74

75

#### Basic WSGI Integration

76

77

```python

78

from xhtml2pdf.wsgi import PisaMiddleware

79

from your_web_app import app

80

81

# Wrap your WSGI application

82

pdf_enabled_app = PisaMiddleware(app)

83

84

# Use with any WSGI server

85

if __name__ == '__main__':

86

from wsgiref.simple_server import make_server

87

server = make_server('localhost', 8080, pdf_enabled_app)

88

server.serve_forever()

89

```

90

91

#### Framework-Specific Integration

92

93

**Flask Integration:**

94

95

```python

96

from flask import Flask, render_template

97

from xhtml2pdf.wsgi import PisaMiddleware

98

99

app = Flask(__name__)

100

101

@app.route('/report')

102

def generate_report():

103

return render_template('report.html', data=get_report_data())

104

105

# Enable PDF conversion middleware

106

app.wsgi_app = PisaMiddleware(app.wsgi_app)

107

108

# Access as PDF: /report?format=pdf

109

# Or with Accept header: Accept: application/pdf

110

```

111

112

**Django Integration:**

113

114

```python

115

# settings.py

116

MIDDLEWARE = [

117

# ... other middleware

118

'xhtml2pdf.wsgi.PisaMiddleware',

119

]

120

121

# Or in wsgi.py

122

from django.core.wsgi import get_wsgi_application

123

from xhtml2pdf.wsgi import PisaMiddleware

124

125

application = get_wsgi_application()

126

application = PisaMiddleware(application)

127

```

128

129

**Pyramid Integration:**

130

131

```python

132

from pyramid.config import Configurator

133

from xhtml2pdf.wsgi import PisaMiddleware

134

135

def main(global_config, **settings):

136

config = Configurator(settings=settings)

137

138

# Configure routes and views

139

config.add_route('report', '/report')

140

config.scan()

141

142

app = config.make_wsgi_app()

143

return PisaMiddleware(app)

144

```

145

146

### Content Negotiation

147

148

Automatic PDF conversion based on HTTP content negotiation, URL parameters, and custom headers.

149

150

```python

151

# URL parameter-based conversion

152

# GET /invoice/123?format=pdf

153

154

# Accept header-based conversion

155

# Accept: application/pdf

156

157

# Custom header-based conversion

158

# X-PDF-Convert: true

159

160

# File extension-based conversion

161

# GET /report.pdf

162

```

163

164

### Advanced Configuration

165

166

Comprehensive configuration options for PDF conversion behavior, styling, and processing parameters.

167

168

```python

169

class ConfigurablePisaMiddleware(PisaMiddleware):

170

"""

171

Enhanced WSGI middleware with advanced configuration options.

172

"""

173

def __init__(self, app, **config):

174

"""

175

Initialize middleware with configuration options.

176

177

Args:

178

app: WSGI application to wrap

179

**config: Configuration options:

180

- pdf_triggers: List of trigger conditions

181

- default_css: Default CSS for PDF conversion

182

- base_path: Base path for resource resolution

183

- debug: Debug level for PDF processing

184

- link_callback: Custom link resolution function

185

- page_size: Default page size (A4, Letter, etc.)

186

- margins: Page margins specification

187

- orientation: Page orientation (portrait/landscape)

188

"""

189

super().__init__(app)

190

self.config = {

191

'pdf_triggers': ['format=pdf', 'application/pdf'],

192

'default_css': self.get_default_css(),

193

'base_path': '',

194

'debug': 0,

195

'link_callback': None,

196

'page_size': 'A4',

197

'margins': '1in',

198

'orientation': 'portrait'

199

}

200

self.config.update(config)

201

202

def get_default_css(self):

203

"""

204

Get default CSS for PDF conversion.

205

206

Returns:

207

str: Default CSS stylesheet for PDF formatting

208

"""

209

return """

210

@page {

211

size: A4;

212

margin: 1in;

213

}

214

body {

215

font-family: Arial, sans-serif;

216

font-size: 11pt;

217

line-height: 1.4;

218

}

219

"""

220

221

# Usage with configuration

222

app = ConfigurablePisaMiddleware(

223

your_app,

224

pdf_triggers=['format=pdf', '.pdf', 'application/pdf'],

225

page_size='Letter',

226

margins='0.5in',

227

debug=1

228

)

229

```

230

231

### Custom PDF Processing

232

233

Advanced customization options for PDF generation including custom styling, headers, footers, and post-processing.

234

235

```python

236

class CustomPisaMiddleware(PisaMiddleware):

237

"""

238

Custom WSGI middleware with enhanced PDF processing.

239

"""

240

241

def process_pdf_request(self, environ, html_content):

242

"""

243

Custom PDF processing with enhanced features.

244

245

Args:

246

environ (dict): WSGI environment

247

html_content (str): HTML content to convert

248

249

Returns:

250

bytes: Generated PDF content

251

"""

252

# Add custom headers and footers

253

enhanced_html = self.add_headers_footers(html_content, environ)

254

255

# Apply custom CSS based on request

256

css = self.get_request_css(environ)

257

258

# Custom link callback for resource resolution

259

def custom_link_callback(uri, rel):

260

return self.resolve_resource(uri, rel, environ)

261

262

# Generate PDF with custom options

263

import io

264

from xhtml2pdf import pisa

265

266

output = io.BytesIO()

267

result = pisa.pisaDocument(

268

enhanced_html,

269

dest=output,

270

default_css=css,

271

link_callback=custom_link_callback,

272

path=self.get_base_path(environ),

273

debug=self.config.get('debug', 0)

274

)

275

276

if result.err:

277

raise Exception(f"PDF generation failed: {result.log}")

278

279

return output.getvalue()

280

281

def add_headers_footers(self, html, environ):

282

"""

283

Add custom headers and footers to HTML content.

284

"""

285

header = f"""

286

<div class="pdf-header">

287

Generated on {datetime.now().strftime('%Y-%m-%d %H:%M')}

288

| {environ.get('HTTP_HOST', 'localhost')}

289

</div>

290

"""

291

292

footer = """

293

<div class="pdf-footer">

294

Page <pdf:pagenumber> of <pdf:pagecount>

295

</div>

296

"""

297

298

# Inject header/footer styles and content

299

return self.inject_pdf_elements(html, header, footer)

300

```

301

302

### Error Handling and Logging

303

304

Comprehensive error handling and logging for WSGI PDF conversion operations.

305

306

```python

307

import logging

308

from xhtml2pdf.wsgi import PisaMiddleware

309

310

class LoggingPisaMiddleware(PisaMiddleware):

311

"""

312

WSGI middleware with enhanced logging and error handling.

313

"""

314

315

def __init__(self, app, logger=None):

316

super().__init__(app)

317

self.logger = logger or logging.getLogger(__name__)

318

319

def __call__(self, environ, start_response):

320

try:

321

return super().__call__(environ, start_response)

322

except Exception as e:

323

self.logger.error(f"PDF conversion failed: {e}", exc_info=True)

324

325

# Return error response

326

error_html = f"""

327

<html>

328

<body>

329

<h1>PDF Conversion Error</h1>

330

<p>Unable to generate PDF: {str(e)}</p>

331

</body>

332

</html>

333

"""

334

335

response_headers = [

336

('Content-Type', 'text/html'),

337

('Content-Length', str(len(error_html)))

338

]

339

start_response('500 Internal Server Error', response_headers)

340

return [error_html.encode('utf-8')]

341

342

# Configure logging

343

logging.basicConfig(level=logging.INFO)

344

app = LoggingPisaMiddleware(your_app)

345

```

346

347

### Performance Optimization

348

349

Caching and performance optimization strategies for high-traffic web applications.

350

351

```python

352

import hashlib

353

from functools import lru_cache

354

355

class CachingPisaMiddleware(PisaMiddleware):

356

"""

357

WSGI middleware with PDF caching capabilities.

358

"""

359

360

def __init__(self, app, cache_size=128, cache_ttl=3600):

361

super().__init__(app)

362

self.cache_size = cache_size

363

self.cache_ttl = cache_ttl

364

self.pdf_cache = {}

365

366

@lru_cache(maxsize=128)

367

def generate_cached_pdf(self, content_hash, html_content):

368

"""

369

Generate PDF with caching based on content hash.

370

371

Args:

372

content_hash (str): Hash of HTML content

373

html_content (str): HTML content to convert

374

375

Returns:

376

bytes: Generated PDF content

377

"""

378

import io

379

from xhtml2pdf import pisa

380

381

output = io.BytesIO()

382

result = pisa.pisaDocument(html_content, dest=output)

383

384

if result.err:

385

raise Exception("PDF generation failed")

386

387

return output.getvalue()

388

389

def get_content_hash(self, html_content):

390

"""

391

Generate hash of HTML content for caching.

392

"""

393

return hashlib.md5(html_content.encode('utf-8')).hexdigest()

394

```

395

396

## Usage Examples

397

398

### Simple Web Application

399

400

```python

401

from xhtml2pdf.wsgi import PisaMiddleware

402

403

def simple_app(environ, start_response):

404

"""

405

Simple WSGI application that returns HTML content.

406

"""

407

html = """

408

<html>

409

<body>

410

<h1>Hello World</h1>

411

<p>This can be converted to PDF!</p>

412

</body>

413

</html>

414

"""

415

416

response_headers = [

417

('Content-Type', 'text/html'),

418

('Content-Length', str(len(html)))

419

]

420

start_response('200 OK', response_headers)

421

return [html.encode('utf-8')]

422

423

# Enable PDF conversion

424

app = PisaMiddleware(simple_app)

425

426

# Access as PDF: /?format=pdf

427

```

428

429

### Enterprise Integration

430

431

```python

432

from xhtml2pdf.wsgi import PisaMiddleware

433

434

class EnterprisePisaMiddleware(PisaMiddleware):

435

"""

436

Enterprise-grade WSGI middleware with security and audit features.

437

"""

438

439

def __init__(self, app, audit_logger=None, security_config=None):

440

super().__init__(app)

441

self.audit_logger = audit_logger

442

self.security_config = security_config or {}

443

444

def __call__(self, environ, start_response):

445

# Security checks

446

if not self.authorize_pdf_access(environ):

447

start_response('403 Forbidden', [])

448

return [b'PDF access denied']

449

450

# Audit logging

451

if self.audit_logger:

452

self.audit_logger.info(

453

f"PDF requested: {environ.get('PATH_INFO')} "

454

f"by {environ.get('REMOTE_ADDR')}"

455

)

456

457

return super().__call__(environ, start_response)

458

459

def authorize_pdf_access(self, environ):

460

"""

461

Check if user is authorized for PDF conversion.

462

"""

463

# Implement your authorization logic

464

return True

465

```

466

467

## Types

468

469

```python { .api }

470

class Filter:

471

"""

472

Base WSGI filter class for content transformation.

473

474

Attributes:

475

app: Wrapped WSGI application

476

"""

477

478

class HTMLFilter(Filter):

479

"""

480

HTML-specific WSGI filter for HTML content processing.

481

482

Extends base Filter with HTML processing capabilities.

483

"""

484

485

class PisaMiddleware(HTMLFilter):

486

"""

487

WSGI middleware for automatic HTML-to-PDF conversion.

488

489

Provides seamless PDF generation from HTML responses

490

with configurable triggers and processing options.

491

"""

492

```