100% found this document useful (6 votes)
74 views

Full Download Expert Twisted: Event-Driven and Asynchronous Programming with Python 1st Edition Mark Williams PDF DOCX

Expert

Uploaded by

nnekestiim
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (6 votes)
74 views

Full Download Expert Twisted: Event-Driven and Asynchronous Programming with Python 1st Edition Mark Williams PDF DOCX

Expert

Uploaded by

nnekestiim
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 55

Experience Seamless Full Ebook Downloads for Every Genre at textbookfull.

com

Expert Twisted: Event-Driven and Asynchronous


Programming with Python 1st Edition Mark Williams

https://textbookfull.com/product/expert-twisted-event-
driven-and-asynchronous-programming-with-python-1st-edition-
mark-williams/

OR CLICK BUTTON

DOWNLOAD NOW

Explore and download more ebook at https://textbookfull.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Expert Twisted: Event-Driven and Asynchronous Programming


with Python 1st Edition Mark Williams

https://textbookfull.com/product/expert-twisted-event-driven-and-
asynchronous-programming-with-python-1st-edition-mark-williams-2/

textboxfull.com

Reactive Programming with RxJava Creating Asynchronous


Event Based Applications 1st Edition Tomasz Nurkiewicz Ben
Christensen
https://textbookfull.com/product/reactive-programming-with-rxjava-
creating-asynchronous-event-based-applications-1st-edition-tomasz-
nurkiewicz-ben-christensen/
textboxfull.com

Using Asyncio in Python Understanding Python s


Asynchronous Programming Features Caleb Hattingh

https://textbookfull.com/product/using-asyncio-in-python-
understanding-python-s-asynchronous-programming-features-caleb-
hattingh/
textboxfull.com

Practical Microservices Build Event Driven Architectures


With Event Sourcing and CQRS 1st Edition Ethan Garofolo

https://textbookfull.com/product/practical-microservices-build-event-
driven-architectures-with-event-sourcing-and-cqrs-1st-edition-ethan-
garofolo/
textboxfull.com
Combine Asynchronous Programming with Swift First Edition
Scott Gardner

https://textbookfull.com/product/combine-asynchronous-programming-
with-swift-first-edition-scott-gardner/

textboxfull.com

Combine Asynchronous Programming with Swift First Edition


Scott Gardner

https://textbookfull.com/product/combine-asynchronous-programming-
with-swift-first-edition-scott-gardner-2/

textboxfull.com

Programming with MicroPython Embedded Programming with


Microcontrollers and Python 1st Edition Nicholas H.
Tollervey
https://textbookfull.com/product/programming-with-micropython-
embedded-programming-with-microcontrollers-and-python-1st-edition-
nicholas-h-tollervey/
textboxfull.com

Asynchronous Android Programming Helder Vasconcelos

https://textbookfull.com/product/asynchronous-android-programming-
helder-vasconcelos/

textboxfull.com

Reactive Programming with RxJS 5 Untangle your


asynchronous Javascript code 1st Edition Sergi Mansilla

https://textbookfull.com/product/reactive-programming-with-
rxjs-5-untangle-your-asynchronous-javascript-code-1st-edition-sergi-
mansilla/
textboxfull.com
Expert Twisted
Event-Driven and Asynchronous
Programming with Python

Mark Williams
Cory Benfield
Brian Warner
Moshe Zadka
Dustin Mitchell
Kevin Samuel
Pierre Tardy
Expert Twisted
Event-Driven and Asynchronous
Programming with Python

Mark Williams
Cory Benfield
Brian Warner
Moshe Zadka
Dustin Mitchell
Kevin Samuel
Pierre Tardy
Expert Twisted
Mark Williams Cory Benfield
Pasadena, CA, USA London, UK

Brian Warner Moshe Zadka


New York, USA New York, USA

Dustin Mitchell Kevin Samuel


New York, USA Nice, France

Pierre Tardy
Toulouse, France

ISBN-13 (pbk): 978-1-4842-3741-0 ISBN-13 (electronic): 978-1-4842-3742-7


https://doi.org/10.1007/978-1-4842-3742-7
Library of Congress Control Number: 2018965166
Copyright © 2019 by Mark Williams, Cory Benfield, Brian Warner, Moshe Zadka,
Dustin Mitchell, Kevin Samuel, Pierre Tardy
This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the
material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation,
broadcasting, reproduction on microfilms or in any other physical way, and transmission or information
storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now
known or hereafter developed.
Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with
every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an
editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.
The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not
identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to
proprietary rights.
While the advice and information in this book are believed to be true and accurate at the date of publication,
neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or
omissions that may be made. The publisher makes no warranty, express or implied, with respect to the
material contained herein.
Managing Director, Apress Media LLC: Welmoed Spahr
Acquisitions Editor: Jonathan Gennick
Development Editor: James Markham
Coordinating Editor: Jill Balzano
Cover image designed by Freepik (www.freepik.com)
Distributed to the book trade worldwide by Springer Science+Business Media New York, 233 Spring Street,
6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail orders-ny@springer-
sbm.com, or visit www.springeronline.com. Apress Media, LLC is a California LLC and the sole member
(owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a
Delaware corporation.
For information on translations, please e-mail [email protected], or visit http://www.apress.com/
rights-permissions.
Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and
licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales
web page at http://www.apress.com/bulk-sales.
Any source code or other supplementary material referenced by the author in this book is available to
readers on GitHub via the book’s product page, located at www.apress.com/9781484237410. For more
detailed information, please visit http://www.apress.com/source-code.
Printed on acid-free paper
Dedicated to AZ, NZ, and TS: Twisted prevails,
and we're looking forward to the next
generation of maintainers.
—Moshe Zadka
Table of Contents
About the Authors�������������������������������������������������������������������������������������������������� xiii

About the Technical Reviewers�������������������������������������������������������������������������������xv


Acknowledgments�������������������������������������������������������������������������������������������������xvii

Introduction������������������������������������������������������������������������������������������������������������xix

Part 1: Foundations���������������������������������������������������������������������������������������� 1
Chapter 1: An Introduction to Event-­Driven Programming with Twisted����������������� 3
A Note About Python Versions������������������������������������������������������������������������������������������������������� 4
What Is Event-Driven Programming?�������������������������������������������������������������������������������������������� 4
Multiple Events����������������������������������������������������������������������������������������������������������������������������� 5
Application(tkinter.Tk()).mainloop()����������������������������������������������������������������������������������������������� 6
Multiplexing and Demultiplexing��������������������������������������������������������������������������������������������������� 7
The select Multiplexer������������������������������������������������������������������������������������������������������������������� 9
Its History, Its Siblings, and Its Purpose���������������������������������������������������������������������������������� 9
select and Sockets������������������������������������������������������������������������������������������������������������������ 9
The How and Why of Socket Events�������������������������������������������������������������������������������������� 11
Handling Events��������������������������������������������������������������������������������������������������������������������� 12
An Event Loop with select����������������������������������������������������������������������������������������������������� 13
Event-Driven Clients and Servers������������������������������������������������������������������������������������������ 15
Non-blocking I/O������������������������������������������������������������������������������������������������������������������������� 18
Knowing When to Stop���������������������������������������������������������������������������������������������������������� 18
Tracking State������������������������������������������������������������������������������������������������������������������������ 19
State Makes Programs Complex������������������������������������������������������������������������������������������� 23
Managing Complexity with Transports and Protocols����������������������������������������������������������������� 23
Reactors: Working with Transports���������������������������������������������������������������������������������������� 24

v
Table of Contents

Transports: Working with Protocols�������������������������������������������������������������������������������������������� 25


Playing Ping-Pong with Protocols and Transports����������������������������������������������������������������� 26
Clients and Servers with Protocols and Transports��������������������������������������������������������������� 31
Twisted and Reactors, Protocols, and Transports������������������������������������������������������������������ 33
The Value of Event-Driven Programming������������������������������������������������������������������������������������ 33
Twisted and the Real World��������������������������������������������������������������������������������������������������������� 36
Events in Time����������������������������������������������������������������������������������������������������������������������������� 41
Repeated Events with LoopingCall���������������������������������������������������������������������������������������� 44
Event Interfaces with zope.interface������������������������������������������������������������������������������������������� 46
Flow Control in Event-Driven Programs�������������������������������������������������������������������������������������� 49
Flow Control in Twisted with Producers and Consumers������������������������������������������������������������ 50
Push Producers��������������������������������������������������������������������������������������������������������������������� 51
Consumers���������������������������������������������������������������������������������������������������������������������������� 54
Pull Producers����������������������������������������������������������������������������������������������������������������������� 57
Summary������������������������������������������������������������������������������������������������������������������������������������ 57

Chapter 2: An Introduction to Asynchronous Programming with Twisted������������� 59


Event Handlers and Composition������������������������������������������������������������������������������������������������ 59
What Is Asynchronous Programming?���������������������������������������������������������������������������������������� 63
Placeholders for Future Values��������������������������������������������������������������������������������������������������� 63
Asynchronous Exception Handling���������������������������������������������������������������������������������������������� 66
An Introduction to Twisted’s Deferred����������������������������������������������������������������������������������������� 71
Callbacks������������������������������������������������������������������������������������������������������������������������������� 71
Errbacks and Failures������������������������������������������������������������������������������������������������������������ 73
Composing Deferreds������������������������������������������������������������������������������������������������������������ 76
Generators and InlineCallbacks�������������������������������������������������������������������������������������������������� 80
yield��������������������������������������������������������������������������������������������������������������������������������������� 80
send��������������������������������������������������������������������������������������������������������������������������������������� 81
throw������������������������������������������������������������������������������������������������������������������������������������� 84
Asynchronous Programming with inlineCallbacks���������������������������������������������������������������� 85

vi
Table of Contents

Coroutines in Python������������������������������������������������������������������������������������������������������������������� 88
Coroutines with yield from���������������������������������������������������������������������������������������������������� 88
Coroutines async and await�������������������������������������������������������������������������������������������������� 90
Awaiting Deferreds��������������������������������������������������������������������������������������������������������������������� 95
Coroutines to Deferreds with ensureDeferred���������������������������������������������������������������������������� 97
Multiplexing Deferreds���������������������������������������������������������������������������������������������������������������� 99
Testing Deferreds���������������������������������������������������������������������������������������������������������������������� 102
Summary���������������������������������������������������������������������������������������������������������������������������������� 106

Chapter 3: Applications with treq and Klein��������������������������������������������������������� 109


Why Libraries?�������������������������������������������������������������������������������������������������������������������������� 109
Feed Aggregation���������������������������������������������������������������������������������������������������������������������� 110
Introducing treq������������������������������������������������������������������������������������������������������������������������ 111
Introducing Klein����������������������������������������������������������������������������������������������������������������������� 115
Klein and Deferreds������������������������������������������������������������������������������������������������������������� 117
Klein Templates with Plating����������������������������������������������������������������������������������������������� 118
A First Draft of Feed Aggregation���������������������������������������������������������������������������������������������� 121
Test-Driven Development with Klein and treq�������������������������������������������������������������������������� 128
Running Test on an Installable Project�������������������������������������������������������������������������������� 128
Testing Klein with StubTreq������������������������������������������������������������������������������������������������� 131
Testing treq with Klein��������������������������������������������������������������������������������������������������������� 140
Logging with twisted.logger������������������������������������������������������������������������������������������������ 143
Running Twisted Applications with twist����������������������������������������������������������������������������� 149
Summary���������������������������������������������������������������������������������������������������������������������������������� 154

Part 2: Projects������������������������������������������������������������������������������������������� 155


Chapter 4: Twisted in Docker�������������������������������������������������������������������������������� 157
Intro to Docker�������������������������������������������������������������������������������������������������������������������������� 157
Containers��������������������������������������������������������������������������������������������������������������������������� 157
Container Images���������������������������������������������������������������������������������������������������������������� 158
Runc and Containerd����������������������������������������������������������������������������������������������������������� 159

vii
Table of Contents

Client����������������������������������������������������������������������������������������������������������������������������������� 159
Registry������������������������������������������������������������������������������������������������������������������������������� 160
Build������������������������������������������������������������������������������������������������������������������������������������ 160
Multi-stage Build����������������������������������������������������������������������������������������������������������������� 161
Python on Docker���������������������������������������������������������������������������������������������������������������������� 163
Deployment Options������������������������������������������������������������������������������������������������������������ 163
Full env�������������������������������������������������������������������������������������������������������������������������������� 163
Virtualenv���������������������������������������������������������������������������������������������������������������������������� 169
Pex��������������������������������������������������������������������������������������������������������������������������������������� 170
Build Options����������������������������������������������������������������������������������������������������������������������� 172
One Big Bag������������������������������������������������������������������������������������������������������������������������� 172
Copying Wheels Between Stages���������������������������������������������������������������������������������������� 172
Copying Environment Between Stages������������������������������������������������������������������������������� 173
Copying the Pex Executable Between Stages��������������������������������������������������������������������� 173
Automation with Dockerpy�������������������������������������������������������������������������������������������������� 173
Twisted on Docker�������������������������������������������������������������������������������������������������������������������� 174
ENTRYPOINT and PID 1�������������������������������������������������������������������������������������������������������� 174
Custom Plugins�������������������������������������������������������������������������������������������������������������������� 174
NColony������������������������������������������������������������������������������������������������������������������������������� 175
Summary���������������������������������������������������������������������������������������������������������������������������������� 178

Chapter 5: Using Twisted as a WSGI Server���������������������������������������������������������� 179


Introduction to WSGI����������������������������������������������������������������������������������������������������������������� 179
PEP�������������������������������������������������������������������������������������������������������������������������������������� 180
Raw Example����������������������������������������������������������������������������������������������������������������������� 181
Reference Implementation�������������������������������������������������������������������������������������������������� 183
WebOb Example������������������������������������������������������������������������������������������������������������������ 185
Pyramid Example����������������������������������������������������������������������������������������������������������������� 186
Getting Started�������������������������������������������������������������������������������������������������������������������������� 187
WSGI Server������������������������������������������������������������������������������������������������������������������������ 188
Finding Code������������������������������������������������������������������������������������������������������������������������ 191

viii
Table of Contents

Default Path������������������������������������������������������������������������������������������������������������������������� 191


PYTHONPATH����������������������������������������������������������������������������������������������������������������������� 192
setup.py������������������������������������������������������������������������������������������������������������������������������� 192
Why Twisted������������������������������������������������������������������������������������������������������������������������ 192
Production vs. Development������������������������������������������������������������������������������������������������ 192
TLS�������������������������������������������������������������������������������������������������������������������������������������� 194
Server Name Indication������������������������������������������������������������������������������������������������������� 195
Static Files��������������������������������������������������������������������������������������������������������������������������� 197
Resource Model������������������������������������������������������������������������������������������������������������������� 197
Pure Static��������������������������������������������������������������������������������������������������������������������������� 198
Combining Static Files with WSGI��������������������������������������������������������������������������������������� 200
Built-In Scheduled Tasks����������������������������������������������������������������������������������������������������� 203
Control Channels����������������������������������������������������������������������������������������������������������������� 206
Strategies for Using Multiple Cores������������������������������������������������������������������������������������������ 208
Load Balancer���������������������������������������������������������������������������������������������������������������������� 208
Opening Socket in Shared Mode����������������������������������������������������������������������������������������� 210
Other Options����������������������������������������������������������������������������������������������������������������������� 213
Dynamic Configuration�������������������������������������������������������������������������������������������������������������� 214
A/B Testable Pyramid App���������������������������������������������������������������������������������������������������� 214
Custom Plugin with AMP����������������������������������������������������������������������������������������������������� 216
Control Program������������������������������������������������������������������������������������������������������������������ 219
Summary���������������������������������������������������������������������������������������������������������������������������������� 221

Chapter 6: Tahoe-LAFS: The Least-­Authority File System������������������������������������ 223


How Tahoe-LAFS Works������������������������������������������������������������������������������������������������������������ 224
System Architecture������������������������������������������������������������������������������������������������������������������ 227
How It Uses Twisted������������������������������������������������������������������������������������������������������������������ 229
Problems We’ve Run Into���������������������������������������������������������������������������������������������������������� 230
Daemonization Tools������������������������������������������������������������������������������������������������������������ 231
Internal FileNode Interfaces������������������������������������������������������������������������������������������������������ 232
Front-End Protocol Integration�������������������������������������������������������������������������������������������������� 233

ix
Table of Contents

The Web Front End�������������������������������������������������������������������������������������������������������������������� 234


File Types, Content-Type, /name/����������������������������������������������������������������������������������������� 237
Saving to Disk���������������������������������������������������������������������������������������������������������������������� 238
Range Headers�������������������������������������������������������������������������������������������������������������������� 238
Error Conversion on the Return Side����������������������������������������������������������������������������������� 240
Rendering UI Elements: Nevow Templates�������������������������������������������������������������������������� 241
The FTP Front End��������������������������������������������������������������������������������������������������������������������� 242
The SFTP Front End������������������������������������������������������������������������������������������������������������������� 248
Backward-Incompatible Twisted APIs��������������������������������������������������������������������������������������� 248
Summary���������������������������������������������������������������������������������������������������������������������������������� 251
References�������������������������������������������������������������������������������������������������������������������������������� 251

Chapter 7: Magic Wormhole��������������������������������������������������������������������������������� 253


What It Looks Like��������������������������������������������������������������������������������������������������������������������� 254
How It Works����������������������������������������������������������������������������������������������������������������������������� 255
Network Protocols, Transfer Latency, Client Compatibility�������������������������������������������������������� 257
Network Protocols and Client Compatibility������������������������������������������������������������������������ 258
Server Architecture������������������������������������������������������������������������������������������������������������������� 260
Persistent Database������������������������������������������������������������������������������������������������������������ 262
Transit Client: Cancelable Deferreds����������������������������������������������������������������������������������������� 262
Transit Relay Server������������������������������������������������������������������������������������������������������������������ 265
Wormhole Client Architecture��������������������������������������������������������������������������������������������������� 267
Deferreds vs State Machines, One-Shot Observer�������������������������������������������������������������������� 268
One-Shot Observers������������������������������������������������������������������������������������������������������������������ 271
Promises/Futures vs. Deferreds������������������������������������������������������������������������������������������������ 272
Eventual-Send, Synchronous Testing���������������������������������������������������������������������������������������� 275
Asynchronous Testing with Deferreds��������������������������������������������������������������������������������������� 277
Synchronous Testing with Deferreds���������������������������������������������������������������������������������������� 278
Synchronous Testing and Eventual Send����������������������������������������������������������������������������� 281
Summary���������������������������������������������������������������������������������������������������������������������������������� 283
References�������������������������������������������������������������������������������������������������������������������������������� 283

x
Table of Contents

Chapter 8: Push Data to Browsers and Micro-services with WebSocket������������� 285


Why WebSocket?���������������������������������������������������������������������������������������������������������������������� 285
WebSocket and Twisted������������������������������������������������������������������������������������������������������������ 286
Raw WebSocket, from Python to Python����������������������������������������������������������������������������������� 288
Raw WebSocket, Between Python and JavaScript�������������������������������������������������������������������� 292
More Powerful WebSocket with WAMP������������������������������������������������������������������������������������� 294
Summary���������������������������������������������������������������������������������������������������������������������������������� 303

Chapter 9: Applications with asyncio and Twisted����������������������������������������������� 305


Core Concepts��������������������������������������������������������������������������������������������������������������������������� 305
Promises����������������������������������������������������������������������������������������������������������������������������������� 306
Event Loops������������������������������������������������������������������������������������������������������������������������� 307
Guidelines��������������������������������������������������������������������������������������������������������������������������������� 308
Case Study: A Proxy with aiohttp and treq�������������������������������������������������������������������������������� 312
Summary���������������������������������������������������������������������������������������������������������������������������������� 316

Chapter 10: Buildbot and Twisted������������������������������������������������������������������������� 317


History of Buildbot�������������������������������������������������������������������������������������������������������������������� 317
The Evolution of Buildbot’s Async Python���������������������������������������������������������������������������� 318
Migrating Synchronous APIs������������������������������������������������������������������������������������������������ 321
Async Build Steps���������������������������������������������������������������������������������������������������������������� 322
Buildbot’s Code������������������������������������������������������������������������������������������������������������������������� 323
Async Utilities���������������������������������������������������������������������������������������������������������������������� 323
Debounce���������������������������������������������������������������������������������������������������������������������������� 323
Async Services�������������������������������������������������������������������������������������������������������������������� 324
LRU Cache��������������������������������������������������������������������������������������������������������������������������� 326
Eventual������������������������������������������������������������������������������������������������������������������������������� 327
Interfacing with Synchronous Code������������������������������������������������������������������������������������� 327
SQLAlchemy������������������������������������������������������������������������������������������������������������������������ 328
requests������������������������������������������������������������������������������������������������������������������������������� 329
Docker��������������������������������������������������������������������������������������������������������������������������������� 332
Concurrent Access to Shared Resources���������������������������������������������������������������������������� 333
xi
Table of Contents

Yield as a Concurrency Barrier�������������������������������������������������������������������������������������������� 333


Thread-Pool Functions Should Not Mutate State���������������������������������������������������������������� 334
DeferredLocks��������������������������������������������������������������������������������������������������������������������� 336
Testing��������������������������������������������������������������������������������������������������������������������������������� 336
Fakes����������������������������������������������������������������������������������������������������������������������������������� 338
Summary���������������������������������������������������������������������������������������������������������������������������������� 338

Chapter 11: Twisted and HTTP/2�������������������������������������������������������������������������� 339


Introduction������������������������������������������������������������������������������������������������������������������������������� 339
Design Goals����������������������������������������������������������������������������������������������������������������������������� 341
Seamless Integration����������������������������������������������������������������������������������������������������������� 341
Most-Optimized Behavior by Default����������������������������������������������������������������������������������� 343
Separating Concerns and Reusing Code����������������������������������������������������������������������������� 343
Implementation Concerns��������������������������������������������������������������������������������������������������������� 344
What Is a Connection Anyway? The Value of Standard Interfaces��������������������������������������� 345
Multiplexing and Priority����������������������������������������������������������������������������������������������������� 348
Backpressure���������������������������������������������������������������������������������������������������������������������� 355
Backpressure in Twisted����������������������������������������������������������������������������������������������������� 356
Backpressure in HTTP/2������������������������������������������������������������������������������������������������������ 359
Current Status and Future Expansion��������������������������������������������������������������������������������������� 362
Summary���������������������������������������������������������������������������������������������������������������������������������� 363

Chapter 12: Twisted and Django Channels����������������������������������������������������������� 365


Introduction������������������������������������������������������������������������������������������������������������������������������� 365
Channels Building Blocks���������������������������������������������������������������������������������������������������������� 367
Message Brokers and Queues�������������������������������������������������������������������������������������������������� 368
Distributed Multi-Layer Systems in Twisted����������������������������������������������������������������������������� 369
Current Status and Future Expansion��������������������������������������������������������������������������������������� 371
Summary���������������������������������������������������������������������������������������������������������������������������������� 371

Index��������������������������������������������������������������������������������������������������������������������� 373

xii
About the Authors
Mark Williams works on Twisted. At eBay and PayPal, he worked on high-performance
Python web services (over a billion requests a day!), application and information
security, and porting enterprise, Java-only libraries to Python.

Cory Benfield is an open source Python developer heavily involved in the Python HTTP
community. He's a Requests core contributor, a urllib3 core contributor, and the lead
maintainer of the Hyper Project, a collection of HTTP and HTTP/2 tools for Python. For
his sins, he also helps out with the Python Cryptographic Authority on PyOpenSSL.

Brian Warner is a security engineer and software developer, having worked at Mozilla
on Firefox Sync, the Add-On SDK, and Persona. He is co-founder of the Tahoe-LAFS
distributed secure filesystem, and develops secure storage and communication tools.

Moshe Zadka has been part of the open source community since 1995, made his first
core Python contributions in 1998, and is a founding member of the Twisted open
source project. He also loves to teach Twisted and Python, having given tutorials at
several conferences as well as regularly blogging.

Dustin Mitchell has contributed to Buildbot and is a member of the TaskCluster team
at Mozilla, having also worked on the Release Engineering, Release Operations, and
Infrastructure teams.

Kevin Samuel has been a Dev and trainer since Python 2.4 and has been putting
his skills to work in East Europe, North America, Asia, and West Africa. He has been
working closely with the Crossbar.io team and is an active member of the French Python
community.

Pierre Tardy is a continuous integration specialist with Renault Software Labs, and he is
currently the lead committer for Buildbot.

xiii
About the Technical Reviewers
Julian Berman is a New York-based software developer and
open source contributor. He is the author of the jsonschema
Python library, an occasional contributor to the Twisted
ecosystem, and an active member of the Python community.

Shawn Shojaie lives in the clement chaparral of California's Bay Area, where he works
as a back-end software engineer. He has worked at Intel, NetApp, and now SimpleLegal,
where he happily builds web-based applications for legal services. He spends weekdays
writing Django and tuning PostgreSQL, and his weekends contributing to open source
projects like django-pylint, occasionally editing technical essays. Find out more at him at
shawnshojaie.com.
Tom Most is a software engineer in the telecommunications industry. He is a Twisted
committer with 10 years of experience of applying Twisted to web services, client
libraries, and command-line applications. He is the maintainer of Afkak, the Twisted
Kafka client. He can be found online at freecog.net and reached at [email protected].

xv
Acknowledgments
Thanks to my wife, Jennifer Zadka, without whose support I could not have done it.

Thanks to my parents, Yaacov and Pnina Zadka, who taught me how to learn.

Thanks to my advisor, Yael Karshon, for teaching me how to write.

Thanks to Mahmoud Hashemi, for inspiration and encouragement.

Thanks to Mark Williams, for always being there for me.

Thanks to Glyph Lefkowitz, for teaching me things about Python, about programming,
and about being a good person.

—Moshe Zadka

Thanks to Mahmoud Hashemi and David Karapetyan for their feedback. Thanks to
Annie for putting up with me while I wrote

—Mark Williams

xvii
Introduction
Twisted has recently celebrated its sweet sixteen birthday. It has been around for a
while; and in that time, it grew to be a powerful library. In that time, some interesting
applications have been built on top of it. In that time, many of us learned a lot about how
to use Twisted well, how to think about networking code, and how to architect event-­
based programs.
After going through the introductory materials that we have on the Twisted site,
a common thing to hear is “What now? How can I learn more about Twisted?” The
usual way we answered that question is with a question: “What do you want to do with
Twisted?” This book shows how to do interesting things with Twisted.
Each of the contributors to this book has done slightly different things with Twisted
and learned different lessons. We are excited to present all of these lessons, with the
goals of making them common knowledge in the community.
Enjoy!

xix
PART 1

Foundations
CHAPTER 1

An Introduction to
Event-­Driven
Programming with Twisted
Twisted is a powerful, well-tested, and mature concurrent networking library and
framework. As we’ll see in this book, many projects and individuals have used it to great
effect for more than a decade.
At the same time, Twisted is large, complicated, and old. Its lexicon teems with
strange names, like “reactor,” “protocol,” “endpoint,” and “Deferred.” These describe a
philosophy and architecture that have baffled both newcomers and old hands with years
of Python experience.
Two fundamental programming paradigms inform Twisted’s pantheon of APIs:
event-driven programming and asynchronous programming. The rise of JavaScript
and the introduction of asyncio into the Python standard library have brought both
further into the mainstream, but neither paradigm dominates Python programming
so completely that merely knowing the language makes them familiar. They remain
specialized topics reserved for intermediate or advanced programmers.
This chapter and the next introduce the motivations behind event-driven and
asynchronous programming, and then show how Twisted employs these paradigms.
They lay the foundation for later chapters that explore real-world Twisted programs.
We’ll begin by exploring the nature of event-driven programming outside of the
context of Twisted. Once we have a sense of what defines event-driven programming,
we’ll see how Twisted provides software abstractions that help developers write clear
and effective event-driven programs. We’ll also stop along the way to learn about
some of the unique parts of those abstractions, like interfaces, and explore how they’re
documented on Twisted’s website.

3
© Mark Williams, Cory Benfield, Brian Warner, Moshe Zadka, Dustin Mitchell, Kevin Samuel, Pierre Tardy 2019
M. Williams et al., Expert Twisted, https://doi.org/10.1007/978-1-4842-3742-7_1
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

By the end of this chapter you’ll know Twisted terminology: protocols, transports,
reactors, consumers, and producers. These concepts form the foundation of Twisted’s
approach to event-driven programming, and knowing them is essential to writing useful
software with Twisted.

A Note About Python Versions


Twisted itself supports Python 2 and 3, so all code examples in this chapter are written
to work on both Python 2 and 3. Python 3 is the future, but part of Twisted’s strength is
its rich history of protocol implementations; for that reason, it’s important that you’re
comfortable with code that runs on Python 2, even if you never write it.

What Is Event-Driven Programming?


An event is something that causes an event-driven program to perform an action.
This broad definition allows many programs to be understood as event-driven;
consider, for example, a simple program that prints either Hello or World!
depending on user input:

import sys
line = sys.stdin.readline().strip()
if line == "h":
     print("Hello")
else:
     print("World")

The availability of a line of input over standard input is an event. Our program
pauses on sys.stdin.readline(), which asks the operating system to allow the user to
input a complete line. Until one is received, our program can make no progress. When
the operating system receives input, and Python’s internals determine it’s a line, sys.
stdin.readline() resumes our program by returning that data to it. This resumption
is the event that drives our program forward. Even this simple program, then, can be
understood as an event-driven one.

4
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

Multiple Events
A program that receives a single event and then exits doesn’t benefit from an event-­
driven approach. Programs in which more than one thing can happen at a time,
however, are more naturally organized around events. A graphical user interface implies
just such a program: at any moment, a user might click a button, select an item from a
menu, scroll through a text widget, and so on.
Here’s a version of our previous program with a Tkinter GUI:

from six.moves import tkinter


from six.moves.tkinter import scrolledtext

class Application(tkinter.Frame):
    def __init__ (self, root):
        super(Application,self). __init__ (root)
        self.pack()
        self.helloButton = tkinter.Button(self,
                                      text="Say Hello",
                                      command=self.sayHello)
        self.worldButton = tkinter.Button(self,
                                        text="Say World",
                                        command=self.sayWorld)
         self.output = scrolledtext.ScrolledText(master=self)
         self.helloButton.pack(side="top")
        self.worldButton.pack(side="top")
         self.output.pack(side="top")
    def outputLine(self, text):
        self.output.insert(tkinter.INSERT, text+ '\n')
    def sayHello(self):
        self.outputLine("Hello")
    def sayWorld(self):
        self.outputLine("World")

5
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

Application(tkinter.Tk()).mainloop()
This version of our program presents the user with two buttons, either of which can
generate an independent click event. This differs from our previous program, where only
sys.stdin.readline could generate the single “line ready” event.
We cope with the possible occurrence of either button’s event by associating event
handlers with each one. Tkinter buttons accept a callable command to invoke when they
are clicked. When the button labeled “Say Hello” generates a click event, that event
drives our program to call Application.sayHello as shown in Figure 1-1. This, in turn,
outputs a line consisting of Hello to a scrollable text widget. The same process applies to
the button labeled “Say Hello” and Application.sayWorld.

Figure 1-1. Our Tkinter GUI application after a series of clicks of “Say Hello” and
“Say World”

tkinter.Frame’s mainloop method, which our Application class inherits, waits


until a button bound to it generates an event and then runs the associated event handler.
After each event handler has run, tkinter.Frame.mainloop again begins waiting for new
events. A loop that monitors event sources and dispatches their associated handlers is
typical of event-driven programs, and is known as an event loop.

6
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

These concepts are the core of event-driven programming:

1. Events represent that something has occurred and to which the


program should react. In both our examples, events correspond
naturally to program input, but as we’ll see, they can represent
anything that causes our program to perform some action.

2. Event handlers constitute the program’s reactions to events.


Sometimes an event’s handler just consists of a sequence of
code, as in our sys.stdin.readline example, but more often
it’s encapsulated by a function or method, as in our tkinter
example.

3. An event loop waits for events and invokes the event handler
associated with each. Not all event-driven programs have an event
loop; our sys.stdin.readline example did not because it only
responds to a single event. However, most resemble our tkinter
example in that they process many events before finally exiting.
These kinds of programs use an event loop.

Multiplexing and Demultiplexing


The way event loops wait for events affects the way we write event-driven programs, so
we must take a closer look at them. Consider our tkinter example and its two buttons;
the event loop inside mainloop must wait until the user has clicked at least one button.
A naive implementation might look like this:

def mainloop(self):
    while self.running:
         ready = [button for button in self.buttons if button.hasEvent()]
         if ready:
            self.dispatchButtonEventHandlers(ready)

mainloop continually polls each button for a new event, dispatching event handlers
only for those that have an event ready. When no events are ready, the program makes
no progress because no action has been taken that requires a response. An event-driven
program must suspend its execution during these periods of inactivity.

7
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

The while loop in our mainloop example suspends its program until one of the
buttons has been clicked and sayHello or sayWorld should run. Unless the user is
supernaturally fast with a mouse, this loop spends most of its time checking buttons that
haven’t been clicked. This is known as a busy wait because the program is actively busy
waiting.
A busy wait like this pauses a program’s overall execution until one of its event
sources reports an event, and so it suffices as a mechanism to pause an event loop.
The inner list comprehension that powers our implementation’s busy wait asks
a critical question: Has anything happened? The answer comes from the ready
variable, which contains all buttons that have been clicked in a single place. The
truthiness of ready decides the answer to the event loop’s question: when ready is
empty and thus falsey, no buttons have been clicked and so nothing has happened.
When it’s truthy, however, at least one has been clicked, and so something has
happened.
The list comprehension that constructs ready coalesces many separate inputs
into one. This is known as multiplexing, while the inverse process of separating
different inputs out from a single coalesced input is known as demultiplexing.
The list comprehension multiplexes our buttons into ready while the
dispatchButtonEventHandlers method demultiplexes them out by invoking each
event’s handler.
We can now refine our understanding of event loops by precisely describing how
they wait for events:

• An event loop waits for events by multiplexing their sources into a


single input. When that input indicates that events have occurred, the
event loop demultiplexes it into its constituent inputs and invokes the
event handler associated with each.
Our mainloop multiplexer wastes most of its time polling buttons that haven’t
been clicked. Not all multiplexers are so inefficient. tkinter.Frame.mainloop’s
actual implementation employs a similar multiplexer that polls all widgets unless the
operating system provides more efficient primitives. To improve its efficiency, mainloop’s
multiplexer exploits the insight that computers can check a GUI’s widgets faster than a
person can interact with them, and inserts a sleep call that pauses the entire program
for several milliseconds. This allows the program to spend part of its busy-wait loop
passively rather than actively do nothing, saving CPU time and energy at the expense of
negligible latency.

8
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

While Twisted can integrate with graphical user interfaces, and in fact has special
support for tkinter, it is at its heart a networking engine. Sockets, not buttons, are the
fundamental object in networking, and operating systems expose efficient primitives for
multiplexing socket events. Twisted’s event loop uses these primitives to wait for events.
To understand Twisted’s approach to event-driven programming, we must understand
the interaction between these sockets and these multiplexing networking primitives.

The select Multiplexer


Its History, Its Siblings, and Its Purpose
Almost all modern operating systems support the select multiplexer. select gets its
name from its ability to take a list of sockets and “select” only those that have events
ready to be handled.
select was born in 1983, when computers were capable of far less. Consequently, its
interface prevents it from operating at maximum efficiency, especially when multiplexing
a large number of sockets. Each operating system family provides its own, more efficient
multiplexer, such as BSD’s kqueue and Linux’s epoll, but no two interoperate. Luckily
their principles are similar enough to select that we can generalize their behavior from
select’s. We’ll use select to explore how these socket multiplexers behave.

select and Sockets


The code that follows omits error handling and will break on many edge cases that occur
in practice. It is intended only as a teaching tool. Do not use it in real applications.
Use Twisted instead. Twisted strives to correctly handle errors and edge cases; that’s
part of why its implementation is so complicated.
With that disclaimer out of the way, let’s begin an interactive Python session and
create sockets for select to multiplex:

>>> import socket


>>> listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> listener.bind(('127.0.0.1', 0))
>>> listener.listen(1)
>>> client = socket.create_connection(listener.getsockname())
>>> server, _ = listener.accept()

9
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

A full explanation of the socket API is beyond the scope of this book. Indeed, we
expect that the parts we discuss will lead you to prefer Twisted! The preceding code,
however, contains more fundamental concepts than irrelevant details:

1. listener - This socket can accept incoming connections. It is an


internet (socket.AF_INET) and TCP (socket.SOCK_STREAM) socket
accessible by clients on the internal, local-only network interface
(which conventionally has an address of 127.0.0.1) and on a port
randomly assigned by the operating system (0). This listener can
perform the setup necessary for one incoming connection and
enqueue it until we’re reading for it (listen(1)).

2. client - This socket is an outgoing connection. Python’s socket.


create_connection function accepts a (host, port) tuple
representing the listening socket to which to connect and returns
a socket connected to it. Because our listening socket is in the
same process and named listener, we can retrieve its host and
port with the listener.getsockname().

3. server - The server’s incoming connection. Once client has


connected to our host and port, we must accept the connection
from listener’s queue of length 1. listener.accept returns a
(socket, address) tuple; we only need the socket, so we discard
the address. A real program might log the address or use it to track
connection metrics. The listening queue, which we set to 1 via the
socket’s listen method, holds this socket for us before we call
accept and allows create_connection to return.

client and server are two ends of the same TCP connection. An established TCP
connection has no concept of “client” and “server”; our client socket has the same
privileges to read, write, or close the connection as our server:

>>> data = b"xyz"


>>> client.sendall(data)
>>> server.recv(1024) == data
True
>>> server.sendall(data)
>>> client.recv(1024) == data
True
10
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

The How and Why of Socket Events


Under the hood, the operating system maintains read and write buffers for each TCP
socket to account for network unreliability and clients and servers that read and write
at different speeds. If server became temporarily unable to receive data, the b"xyz"
we passed client.sendall would remain in its write buffer until server again became
active. Similarly, if we were too busy to call client.recv to receive the b"xyz" server.
sendall sent, client's read buffer would hold onto it until we got around to receiving
it. The number that we pass recv represents the maximum data we’re willing to remove
from the read buffer. If the read buffer has less than the maximum, as it does in our
example, recv will remove all the data from the buffer and return it.
Our sockets’ bidirectionality implies two possible events:

1. A readable event, which means the socket has something available


for us. A connected server socket generates this event when
data has landed in the socket’s receive buffer, so that calling
recv after a readable event will immediately return that data.
A disconnection is represented by recving no data. By convention,
a listening socket generates this event when we can accept a new
connection.

2. A writable event, which means space is available in the socket’s


write buffer. This is a subtle point: as long as the socket receives
acknowledgment from the server for the data it’s transmistted
across the network faster than we add it to the send buffer, it
remains writable.

select’s interface reflects these possible events. It accepts up to four arguments:

1. a sequence of sockets to monitor for readable events;

2. a sequence of sockets to monitor for writable events;

3. a sequence of sockets to monitor for “exceptional events.” In our


examples, no exceptional events will occur, so we will always pass
an empty list here;

4. An optional timeout. This is the number of seconds select will


wait for one of the monitor sockets to generate an event. Omitting
this argument will cause select to wait forever.

11
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

We can ask select about the events our sockets have just generated:

>>> import select


>>> maybeReadable = [listener, client, server]
>>> maybeWritable = [client, server]
>>> readable, writable, _ = select.select(maybeReadable, maybeWritable, [], 0)
>>> readable
[]
>>> writable == maybeWritable and writable == [client, server]
True

We instruct select not to wait for any new events by providing a timeout of 0. As
explained above, our client and server sockets might be readable or writable, while
our listener, which can only accept incoming connections, can only be readable.
If we had omitted the timeout, select would pause our program until one of the
sockets it monitored became readable or writable. This suspension of execution is
analogous to the multiplexing busy-wait that polled all buttons in our naive mainloop
implementation above.
Invoking select multiplexes sockets more efficiently than a busy wait because
the operating system will only resume our program when at least one event has been
generated; inside the kernel an event loop, not unlike our select, waits for events from
the network hardware and dispatches them to our application.

Handling Events
select returns a tuple with three lists, in the same order as its arguments. Iterating
over each returned list demultiplexes select’s return value. None of our sockets have
generated readable events, even though we’ve written data to both client and server;
our preceding calls to recv emptied their read buffers, and no new connections have
arrived for listener since we accepted server. Both client and server have generated
a writable event, however, because there’s space available in their send buffers.
Sending data from client to server causes server to generate a readable event, so
select places it in the readables list:

>>> client.sendall(b'xyz')
>>> readable, writable, _ = select.select(maybeReadable, maybeWritable, [], 0)
>>> readable == [server]
True
12
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

The writable list, interestingly, once again contains our client and server sockets:

>>> writable == maybeWritable and writable == [client, server]


True

If we called select again, our server socket would again be in readable and our
client and server sockets again in writable. The reason is simple: as long as data
remains in a socket’s read buffer, it will continuously generate a readable event, and as
long as space remains in a socket’s write buffer, it will generate a writable event. We can
confirm this by recving the data client sent to server and calling select again for new
events:

>>> server.recv(1024) == b'xyz'


True
>>> readable, writable, _ = select.select(maybeReadable, maybeWritable,
[], 0)
>>> readable
[]
>>> writable == maybeWritable and writable == [client, server]
True

Emptying server’s read buffer has caused it to stop generating readable events, and
client and server continue to generate writable events because there’s still space in
their write buffers.

An Event Loop with select


We now know how select multiplexes sockets:

1. Different sockets generate readable or writable events to indicate


that an event-driven program should accept incoming data or
connections, or write outgoing data.

2. select multiplexes sockets by monitoring them for readable


or writable events, pausing the program until at least one is
generated or the optional timeout has elapsed.

3. Sockets continue generating readable and writable events until


the circumstances that led to those events changes: a socket
with readable data emits readable events until its read buffer

13
Chapter 1 An Introduction to Event-­Driven Programming with Twisted

is emptied; a listening socket emits readable events until all


incoming connections have been accepted; and a writable socket
emits writable events until its write buffer is filled.

With this knowledge, we can sketch an event loop around select:

import select

class Reactor(object):
    def __init__ (self):
        self._readers = {}
        self._writers = {}
    def addReader(self, readable, handler):
        self._readers[readable] = handler
    def addWriter(self, writable, handler):
        self._writers[writable] = handler
    def removeReader(self, readable):
        self._readers.pop(readable,None)
    def removeWriter(self, writable):
        self._writers.pop(writable,None)
    def run(self):
        while self._readers or self._writers:
            r, w, _ = select.select(list(self._readers), list
(self._writers), [])
            for readable in r:
                self._readers[readable](self, readable)
            for writable in w:
                if writable in self._writers:
                   self._writers[writable](self, writable)

We call our event loop a reactor because it reacts to socket events. We can request
our Reactor call readable event handlers on sockets with addReader and writable event
handlers with addWriter. Event handlers accept two arguments: the reactor itself and
the socket that generated the event.
The loop inside the run method multiplexes our sockets with select, then
demultiplexes the result between sockets that have generated a read event and sockets
that have generated a write event. The event handlers for each readable socket run
first. Then, the event loop checks that each writable socket is still registered as a writer
14
Exploring the Variety of Random
Documents with Different Content
I don’t mean those that are insincere or hypocritical: but all those
who are content with outward religion, with any thing short of that
inward holiness, that newness of spirit which the gospel describes.

They should consider that charity, chastity, sobriety and justice


may be practised without Christianity. A Jew, a Heathen may be
(what you call) charitable and temperate: but to make these parts of
Christianity, they must proceed from a heart truly turned to God, that
is full of an infant simplicity, that is crucified with Christ, that is born
again of the Spirit, that has overcome the world. Temperance or
justice without this, may be the temperance of a Jew or a Heathen:
but it is not Christian temperance or justice, till it proceeds from a
Christian spirit. Could we do and suffer all that Christ himself did or
suffered, yet if it was not all done in the same temper, in the Spirit of
Christ, it would profit us nothing.

XXV. A Christian is sober, charitable and just, upon the same


principles and with the same spirit that he receives the Holy
communion; as acts of obedience to God, and as so many instances
of a heart truly devoted to God.

A Christian is sober, not only so far as suits with a regular life, but
so as becomes one who is born of the Holy Spirit, who dwelleth in
God and God in him.

He is charitable, not only so far as suits with his natural temper,


and with good esteem among men; but in such a measure as is
suitable to the doctrines and spirit of the gospel.

For indeed, neither charity, nor temperance, nor justice, nor any
other virtues (as they are called) are parts of Christian holiness, till
they spring from holiness of heart, from the mind that was in Christ.

This is what cannot be too much considered by those whose


religion has made no change in their hearts; who fancy themselves
Christians, only because of the regularity of their lives, altho’ they
have never experienced a renewal in the spirit of their minds, who
pray without devotion, give alms without charity, and are Christians
without the Spirit of Christianity.

XXVI. Secondly, This doctrine may serve to instruct those who


are convinced, they have been hitherto strangers to religion.

Some people who begin to look toward religion, think they have
done enough, when they have reformed the outward course of their
lives; when they have left off their gross vices and follies, or are
grown careful of some particular duties.

Thus a man who has been a drunkard many years, thinks he has
made a sufficient change by becoming temperate: another imagines,
he is in a very good and safe state, because he does not neglect the
public worship, as he used to do: a lady fancies she lives enough to
God because she has left off plays, and lives more at home than
formerly.

But such people should consider, that Christianity does not


consist in the fewness of our vices; no nor in any one particular
virtue, nor yet in the outward amendment of our lives: but in such a
thorough change of heart, as makes the love of God the spring and
measure and rule of all our tempers and actions.

XXVII. It is a miserable error, to think we are Christians, because


we are less vain or covetous, more sober and decent in our
behaviour than we used to be. Yet this is the case with many, who
think they are well, because they are not so bad as they were,
because they are reformed from outward wickedness; not
considering how entire a reformation of heart, as well as life,
Christianity implies.

But let such people remember, that they who thus measure
themselves by themselves are not wise. Let them remember that
they are not disciples of Christ, till they have, like him, offered their
whole soul and body as a reasonable living sacrifice to God; that
they are not members of Christ’s mystical body, till they are united
unto him by a new spirit; that they have not entered into the kingdom
of God, till they have entered into an infant simplicity of heart, till they
are so born of God as not to commit sin, so full of an heavenly Spirit
as to have overcome the world.

Let them remember, He that is in Christ is a new creature, and


that nothing short of this will avail before God, nothing less than the
entire renewal of the soul in righteousness and all true holiness. Let
them remember, that there is no religion that will stand us in any
stead, but that which is the conversion of the heart to God, when all
our tempers are holy, heavenly, divine, springing from a soul that is
born again of the Spirit, and tends with one full bent to a perfection
and happiness in the enjoyment of God.

XXVIII. Let us therefore look carefully to ourselves, and consider


what manner of spirit we are of: let us not think our condition safe,
because we are of this or that church or persuasion, or because we
are strict observers of the outward offices of religion. For we can’t
but see, these are marks that belong to more than belong to Christ.
All are not his that prophesy, or even cast out devils, and work
miracles in his name. Much less those who, with corrupt minds and
worldly hearts, are only baptized in his name.

*If religion has raised us into a new world; if it has filled us with
new ends of life; if it has taken possession of our hearts, altered the
whole turn of our minds, and changed the whole stream of our
affections: if it has given us new joys and griefs, new hopes and
fears; if all things in us are become new: if the love of God is shed
abroad in our hearts, by the Holy Ghost given unto us, and this Spirit
beareth witness with our spirit that we are the children of God: then
are we Christians, not in name only, but in truth; then we do believe
in the Holy Jesus, and we shall rejoice in the day of Christ, that we
have not run in vain, neither laboured in vain.
CHAP. II.

C
HRISTIANITY requires a renouncing of the world, and all
worldly tempers.

I. The Christian religion being to raise a new, spiritual, and, as


yet, invisible world, and to place man among thrones, principalities
and spiritual beings, is at entire enmity with this present corrupt state
of flesh and blood.

It ranks the world, with the flesh and the devil, as an equal enemy
to those glorious ends which it proposes.

Accordingly the gospel lays its foundation, in utterly renouncing


those false goods and enjoyments, which feed the vanity and
corruption of our nature, fill our hearts with foolish and wicked
passions, and keep us separate from God, the only happiness of all
spirits.

II. For not only the vices, the wickedness, and vanity of this world,
but even its most lawful concerns, if unduly pursued, make men
unable to enter into the true state of Christianity.

He who is busied in an honest calling, may, on that account, be


finally rejected of God.

*For it is no more pardonable to be less affected to the things of


God, for the sake of any worldly business, than for the indulgence of
our pride, or any other sinful passion: every business of life being
equally trifling, when compared with the one thing needful.
III. Men of serious business indeed generally censure those, who
trifle away their time in vain and impertinent pleasures.

But they don’t consider that their own employments also are as
vain as vanity itself: they don’t consider that any business or
employment, if it has got hold of the heart, renders men as vain and
odious in the sight of God, as any sensual gratification.

They may call it an honest care, a wise industry, or by any other


plausible name. But it is a wisdom which can no more recommend
itself to the eyes of God than the wisdom of an epicure.

*For it shews as wrong a turn of mind, and as great a contempt of


the true good, to neglect any degrees of piety for the sake of
business, as for any the most trifling pleasures of life.

IV. *The wisdom of this world indeed gives an importance and air
of greatness to several ways of life, and ridicules others as vain and
contemptible, which differ only in their kind of vanity. But the wisdom
from above condemns all labour as equally fruitless, which hinders
our labouring after everlasting life. For what can it signify whether a
man forgets God in his farm, or in a shop, or at a gaming table? The
world is full as important in its pleasures as in its cares; there is no
more wisdom in the one than in the other. And the man who, by the
cares and business of the world is made less affected to the things
of God, is no wiser than he who takes his delight in running foxes
and hares out of breath.

For there is no wisdom in any thing but religion. Nor is any way of
life less vain than another, but as it is made serviceable to piety, and
conspires with the designs of religion, to raise mankind to a
participation and enjoyment of the divine nature.

V. Let those who are not at all ashamed to be devoted to the


cares and business of the world, consider those states of life, which
they own to be vain and foolish, and contrary to religion.
Some people have no other care, than how to give their palate
fresh pleasure, and enlarge the happiness of tasting.

Others live to no other purpose, than to breed dogs, and attend


the sports of the field.

Men of sober business, who seem to act the grave part of life,
generally condemn these ways of life.

But why are they to be condemned? Produce but the true reason
why any of these are vain and sinful, and the same reason will
conclude against every way of life which is not wholly devoted to
God.

VI. Let the man who is deep in worldly business, but shew the
vanity and shame of a life devoted to pleasures, and the same
reasons will shew the vanity and shame of a life filled with worldly
cares. So that whosoever can condemn sensuality, ambition, or any
way of life upon the principles of reason and religion, carries his own
condemnation within his own breast, unless his life be entirely
devoted to God.

VII. It is granted that some cares are made necessary by the


necessities of nature. And the same also may be observed of some
pleasures, as the pleasures of eating, drinking and rest. But if reason
and religion do not limit these pleasures by the necessities of nature,
we fall from rational creatures into drones, sots, gluttons, and
epicures.

*In like manner our care after some worldly things is necessary.
But if this care is not bounded by the just wants of nature, if it
wanders into unnecessary pursuits, and fills the mind with false
desires and cravings; if it wants to add an imaginary splendour to the
plain demands of nature, it is vain and irregular; it is the care of an
epicure, a longing for sauces and ragous, and corrupts the soul like
any other sensual indulgence.
For this reason our Lord points so many of his doctrines at the
common allowed employments of life, to teach us, that they may
employ our minds as falsely and dangerously as any trifles whatever.

He teaches us, that even the necessaries of life should be sought


with a kind of indifference, that so our souls may be truly sensible of
greater wants, and disposed to hunger and thirst after enjoyments
that will make us happy for ever.

VIII. But how unlike are Christians to Christianity! It commands us


to take no thought, saying, what shall we eat, or what shall we drink?
Yet Christians are restless and laborious, till they can eat in plate.

It commands us to be indifferent about raiment. But Christians


are full of care and concern, to be cloathed in purple and fine linen. It
enjoins us to take no thought for the morrow. Yet Christians think
they have lived in vain, if they don’t leave estates at their death. And
these call themselves disciples of that Lord, who saith, He that
forsaketh not all that he hath, cannot be my disciple.

IX. It must not be said that these doctrines are not plainly enough
taught in scripture, because the lives and behaviour of Christians are
so contrary to them. For if the lives of Christians might be alledged
against the doctrines of scripture, none of them would have lasted to
this day.

It is one of the ten commandments, Thou shalt not take the name
of the Lord thy God in vain. And our Saviour has forbid swearing,
yea, in the most solemn manner. Yet where more swearing than
among Christians, and among such Christians as would think it hard
to be reckoned a reproach to the Christian name?

The scripture says of Christians, that they are born of God, and
have overcome the world. Can they then be reckoned of that
number, who have not so much as overcome that flagrant sin, to
which they have no temptation in nature?
Well therefore may the doctrines of heavenly-mindedness, and
contempt of the world be disregarded, since they run counter to all
the corruptions of flesh and blood, to all the pride and vanity of our
nature.

X. But let those who are startled at these doctrines, deal faithfully
with their own hearts, and ask themselves whether they should not
have had the same dislike to them, had they lived in our Saviour’s
days? Or whether they can find any one reason, why they should
have been so spiritual and heavenly then, which is not as good and
as strong a reason for their being as spiritual and heavenly now?

*Hath heaven or earth suffered any change since that time? Is


the world become now more worth our notice, or heavenly treasure
of less value than it was then? Or have we had another Saviour
since, that has compounded things with this world, and helped us to
an easier way to the next?

Yet, if an apostle was to raise from the dead, calling rich and
great men to these doctrines, they would drive their coaches from
such a preacher, rather than be saved at such a price.

XI. To set this great truth in a still clearer light, I will appeal a little
even to the imagination of the reader.

Let it be supposed, that rich men are now enjoying their riches,
and taking all the usual delights of plenty; that they are labouring for
the meat that perisheth, contriving scenes of pleasure, and spending
their estates in proud expences.

After this supposition let it be imagined, that we saw the Holy


Jesus, who had not where to lay his head, with his twelve apostles,
that had left all to follow him. Let us imagine, that we heard him call
all the world, to take up the cross and follow him, promising, a
treasure in heaven to such as would quit all for his sake, and
rejecting all that would not comply therewith: denouncing woe and
eternal death to all that lived in fulness, pomp and worldly delights.
Let it be imagined, that we heard him commanding his disciples, to
take no thought, saying, What shall we eat, or what shall we drink, or
wherewithal shall we be cloathed? And giving this reason for it, After
all these things do the Gentiles seek.

Let it be imagined, that we saw the first Christians taking up the


cross, renouncing the world, and counting all things but dung that
they might win Christ.

I do not now so immediately appeal to the judgment or reason of


the reader. I leave it even with his imagination, that wild faculty, to
determine, whether it be possible for these two different sorts of
men, to be true disciples of the same Lord?

XII. *To proceed; Let us suppose that a rich man was to put up
such a prayer as this to God:

“O Lord, I thy sinful creature, whom thou hast called to a lively


hope of glory in Christ Jesus, beg of thee to grant me a thousand
times more riches than I need, that I may be able to gratify myself
and family in the delights of eating and drinking, state and grandeur.
Grant that as the little span of life wears out, I may abound more and
more in wealth; and that I may see and perceive all the best and
surest ways of growing richer than any of my neighbours. This I
humbly and fervently beg, in the name, &c.”

Such a prayer as this should have had no place in this treatise;


but in hope that proportionably as it offends the ear, it may amend
the heart.

XIII. There is no one, I believe, but would be ashamed to put up


such a prayer as this to God. Yet let it be well observed, that all are
of the temper of this prayer, but those who have renounced the
world.

We need not go among villains, and people of scandalous


characters, to find those who desire a thousand times more than
they want, who have an eagerness to be every day richer and richer,
who catch at still new ways of gain; and scarce think any thing
enough, except it equals or exceeds the estate of their neighbours.

I beg of such that they would heartily condemn the profane and
unchristian spirit of the foregoing prayer, and that they would satisfy
themselves, nothing can be more odious and contrary to religion.

But let them be assured also of this, that the same things which
make an unchristian prayer, make an unchristian life.

For the reason why these things appear so odious in a prayer, is


because they are so contrary to the spirit of religion. But is it not as
bad to live contrary to the spirit of religion, as to pray contrary to it?

At least, must not that way of life be highly blameable, which is so


shocking when put into the form of a prayer?

XIV. Need we any other conviction, that this manner of life is


contrary to the spirit of Christianity, than this, that the praying
according to it in Christ’s name, comes near to blasphemy?

Let it be considered how we should abominate a person, whom


we knew to use such a prayer: and let that teach us, how
abominable such a life must appear in the eyes of God! And with this
addition of folly, that we call the prayer profane, but think the life that
answers to it to be Christian.

From all this it is plain, that the present followers of Jesus Christ,
have no more to do with worldly enjoyments, than those he chose
while he himself was on earth; and that we are to have the same
heavenly devotion to God, the same affection, as any of those he
conversed with in the days of his flesh.

XV. Yet notwithstanding the scriptures are so express, men will


not give up their pre-conceived opinions.

It will still be asked, Where can be the harm of getting or enjoying


an estate?
Whether it be not a commendable thing, to provide an estate for
one’s family?

And what people of birth and fortune are to do with themselves, if


they are not to live up to their estates and qualities?

To the first question let it be answered, Take no thought, saying,


what shall we eat, or what shall we drink, or wherewithal shall we be
cloathed? For after all these things do the Gentiles seek.

Now, if to be careful and thoughtful, even about the necessaries


of life, be a care that is here forbidden, and that because it is such a
care as only becomes Heathens; surely to be careful and thoughtful
how to raise an estate, and enrich one’s family, is a care that is
sufficiently forbidden in Christians. And he that can yet think it lawful,
to make this the care and design of his life, is too blind to be
convinced by arguments. Our Saviour saith, Labour not for the meat
that perisheth, but for that meat which endureth unto everlasting life.
He commands us not to lay up for ourselves treasures on earth; he
assures us that we cannot serve God and mammon.

Now these places have no meaning, if it is still lawful for


Christians to heap up treasures, to labour for estates, and pursue
designs of enriching their families.

XVI. I know it is easy to evade the force of these texts, and to


make plausible harangues, upon the innocency of labouring to be
rich, and the consistency of serving God and mammon.

I don’t question but the rich young man in the gospel could have
made a very good apology for himself, and have shewn how
reasonable and innocent a thing it was, for so good and so young a
man to enjoy an estate.

The rich man in torments could have alledged how much good he
did with his fortune; how many trades he encouraged with his purple
and fine linen, and faring sumptuously every day; and how he
conformed to the ends of society, by so spending his estate.
XVII. *But still the word of God shall not pass away. Having food
and raiment, let us be therewith content. For they who will be rich fall
into a temptation and a snare, and into many foolish and hurtful
lusts, which drown men in destruction and perdition. 1 Tim. vi. 8.

We may, perhaps, by some acuteness of reasoning, find out, that


this still leaves us at our liberty, whether we will labour to be rich or
not: that notwithstanding what the apostle says, of a snare, a
temptation, and foolish lusts, yet we can pursue the means and
desire the happiness of riches, without any danger to our virtue.

But if so, we are as prudent as those Christians, who think they


can secure their virtue without watching and prayer, tho’ our Saviour
has said, Watch and pray that ye enter not into temptation.

And he that neglects watching and prayer, tho’ the appointed


means of avoiding temptation, lives as much according to scripture,
as he that is careful and desirous of riches, tho’ the declared
occasions of sin, snares and destruction.

XVIII. If we could submit to the plain doctrines of scripture, it


would never be asked what people of fortune are to do with
themselves, if they are not to live up to the splendour and plenty of
their estates?

The rich man in the gospel was a ruler, a young man, and a good
man: if therefore there are any of his rank who are neither young nor
good, it can hardly be thought, they have less to do to inherit eternal
life.

And as for those who, like him, have kept the commandments of
God from their youth, I dare not tell them, that they are not under a
necessity of offering all their wealth to God, and of making their
estates, however acquired, not the support of vain indulgences, but
the relief of their brethren.

XIX. Suppose great people, by means of their wealth, could throw


themselves into a deep sleep of pleasant dreams, which would last
till death awaked them, would any one think it lawful for them to
make such use of their riches?

And yet he that had done nothing but sleep and dream to the
time of his death, might as well say, that he had been working out his
salvation with fear and trembling, as he that has been living in luxury,
splendour, and sensual gratifications.

The gospel has made no exception for dignity of birth, or


difference in fortune; but has appointed the same straight gate, the
common passage for all persons to enter into glory.

The distinctions of civil life have their use; but if any one thinks he
may be less devoted to God, less afraid of the corruptions of
pleasure and pride, because he is born of a rich family, he is as
much mistaken as he that fancies he has a privilege to steal,
because he was born of a Father that was poor.

XX. If the rich or great man can find out a course of pleasures,
that support no wrong turn of mind, an indulgence which does not
gratify sensuality, entertainments which feed no vain passions: if
they can find out such instances of splendour and greatness, as
shew they love God with all their hearts, and as gratify neither the
lust of the flesh, the lust of the eye, nor the pride of life, religion has
no command against such enjoyments.

But if this cannot be done, then the rich have no more permission
to live in vain indulgences than the poor have to steal.

*And let it be always remembered, that if any distinction of life


makes men forget that sin is their only baseness, and holiness their
only honour; if any condition makes them less disposed to imitate the
low, humble estate of their suffering Master; instead of being any real
advantage, it is their curse, their snare and destruction.

XXI. I know it will still be objected, that a man is not necessarily


proud, because he lives in shew and figure, any more than another
is necessarily humble, because he lives in a low estate.
It is granted, that men may be of a temper contrary to the estate
in which they live. But this is only true, of such as are in any state by
force, and contrary to their desires and endeavours.

A man in a low estate may be proud, because he is in such a


state by force; and is uneasy till he can raise himself out of it. If the
same is true of him that lives in figure and pomp, that he is in this
state by force, and is restless till he can lay it all aside, then we grant
he may be humble.

But nothing is weaker than to say, because a man may be in a


low estate per force, without lowliness of mind, therefore another
may chuse to live in all the height of grandeur and vanity, without any
height or vanity of mind.

A man may be an epicure in his temper, tho’ he is forced to live


upon bread and water. But will you therefore say, another who lives
on all sorts of dainties, and that by choice, may be no epicure?

If therefore they that live in pomp and shew, live therein out of
choice, and are not willing to live otherwise, we must talk nonsense if
we do not say their minds are as vain as the vanity of their state.

XXII. The necessity of renouncing the world, in whatever state of


life we are, may be yet farther proved from those divine tempers
which Christianity requires.

Christians are to love God with all their heart, with all their soul,
with all their mind, and with all their strength.

Now it is absolutely impossible we should do this, unless we have


renounced the world.

A man that has his head and his heart full of worldly concerns,
can no more love God with all his strength, than a man, who has his
eyes on the ground, can be looking towards heaven with all the
strength of his sight.
XXIII. It is certain, that we unavoidably love every thing in
proportion as it appears to be our happiness: if it appears to be half
our happiness, it will necessarily have half the strength of our love:
and if it appears to be all our happiness, we shall love it with all our
strength.

The Christian religion therefore, which requires the whole


strength of our nature to love God, lays a just foundation in requiring
us absolutely to renounce the happiness of the world; seeing it is
impossible to have two happinesses, and but one love.

And indeed what can be more ridiculous than to fancy, that a man
who is taken up with the enjoyments of the world, is at the same time
loving God with all his soul and with all his strength?

Is it not as absurd as to suppose that a man, who is devoted to,


and taken up with the sports of the field, is at the same time
contemplating mathematical speculations, with the whole ardour of
his mind?

XXIV. Another duty which proves the absolute necessity of thus


renouncing the world, is, The love of our neighbour.

Thou shalt love thy neighbour as thyself: if a man would know


what this implies, let him look impartially into his own heart, and see
what it is that he wishes to himself. Then let him turn all the same
wishes to his neighbour, and he will feel the just measure of his duty.

This will also teach him, that the true love of his neighbour is as
inconsistent with the love of the world, as duelling is inconsistent with
meekness and the forgiveness of injuries.

XXV. *This love is a temper that suits only such beings as have
one common undivided happiness, wherein they cannot be rivals to
one another. Now this is the state of all Christians, who have as truly
one common happiness as they have one common God. But if we
put ourselves out of this state, and seek for happiness in the
enjoyments of this life, we are as incapable of this love, as wolves
and bears that live upon prey.

One common undivided happiness, being the only possible


foundation for this love, if we seek any other happiness, if we don’t
renounce all other pretensions, we cannot keep clear of such
tempers as are utterly inconsistent with the loving our neighbour as
ourselves.

But when we are governed by a happiness wherein none can


make himself our rival, it will be no harder to love all men as
ourselves, than to wish them the enjoyment of the same light, or the
common air: which being goods that may be equally enjoyed by all,
are not the occasions of envy.

XXVI. *It is plain our Saviour intended this brotherly love, to be


the governing principle of our lives. But it cannot be so, unless we
are content to make no more of this world, than a supply of our
necessities, and to look for one only happiness in the enjoyment of
God.

I don’t appeal to niggards and worldlings, to the proud and


ambitious: let those who think themselves moderate in their worldly
desires and enjoyments, deal faithfully with themselves and see
whether their prosecution of their worldly affairs, permits them to love
all men as themselves.

Perhaps they have not those bitter envyings and hatreds to which
ambitious worldlings are subject. But still they have as certainly, in
their degree, and in proportion to their love of the world, their
envyings and hatreds, and want of sincere love, as other men.

XXVII. For a further proof of this, we need only look into the
world, and see the spirit that appears among almost all Christians.

We need not go to wicked and loose people. Let us go into any


virtuous family, and we shall find it has its particular friendships and
hatreds, its envyings and evil speakings, and all founded in the
interests of the world.

And this necessarily springs from hence, that all Christians are
busy in attending to their worldly interests, intending only to keep
clear of dishonest practices: that is, they use the world as far as
honest Heathens or Jews would do, and consequently have such
tempers as Jews and Heathens have.

For it is not only cheating and dishonesty, but the bare desire of
worldly things, and the placing happiness in them, that lays the
foundation of all these unchristian tempers; and divides Christians
into more parties than there are families among them.

So that it is purely the engaging so far in the world as sober


Christians do: it is their false satisfaction in so many things that they
ought to renounce; it is their being too much alive to the world, that
makes all, even those who are called religious, subject to tempers so
contrary to the love of their neighbour.

Let this therefore teach us that we must renounce the world, if we


would live and love like Christians.

XXVIII. By renouncing the world, I do not mean, retiring into a


cloister. This would be like laying aside all use of cloaths, to avoid
the vanity of dress.

There is a reasonable use of the world, which is as lawful as it is


to eat and drink.

We may buy and sell; we may labour; we may provide for


ourselves and our families; that is, so far as is needful for life and
godliness. But farther we may not go.

The first step our desires take beyond things of necessity, ranks
us among worldlings, and raises in our minds all those tempers,
which disturb the minds of worldly men.
XXIX. You think yourself conformable to Christianity, because you
are moderate in your desires. You don’t desire a large estate; you
desire only a little finery, a little state, and to have things genteel
about you.

Imagine now, that what you say, of moderate desires, and little
fineries, had been said to our blessed Saviour when he was upon
earth, calling men to renounce the world and deny themselves.

Your own conscience tells you, he would have rebuked the


author of such a pretence with as much indignation as he rebuked
Peter, Get thee behind me, Satan, for thou savourest not the things
that be of God.

Now the spirit of Christianity is the same spirit that was in Christ
when he was upon earth. And if we have reason to think that such a
pretence would have been severely condemned by Christ, we have
the same reason to be sure, it is as severely condemned by
Christianity.

XXX. Had our blessed Saviour a little before he left the world,
given estates to his apostles, with a permission for them to enjoy
little fineries, and a moderate state in a genteel manner, he had
undone all that he had said of the contempt of the world, and
heavenly-mindedness. Such a permission had been a contradiction
to the main doctrines which he had taught.

Had the apostles lived in a little state, and in moderate worldly


delights, how could they have said, the world is crucified to me, and I
unto the world?

And how blind and weak must we be, if we can think that we may
live in a spirit and temper, which could not possibly be the spirit and
temper of Christ and his apostles?

XXXI. *Another pretence for worldly care and labour after riches,
is to provide for our families.
You want to leave fortunes to your children, that they may have
their share in the figure and shew of the world. Now consider, do you
do this on principles of religion, as the best thing you can do, either
for yourself or them?

Can you then be said, to have chosen the one thing needful for
yourself, or the one thing needful for them, who take such care to put
them in a state of life, that is a snare and a temptation, and the most
likely of all others, to fill their minds with foolish and hurtful lusts?

Is it your kindness toward them that puts you upon this labour?
Consider therefore what this kindness is founded upon? Perhaps it is
such a kindness as when tender mothers carry their daughters to
plays and balls: such a kindness as when indulgent fathers support
their sons in all the expence of their follies. Such kind parents may
more properly be called the betrayers and murderers of their
children.

You love your children, and therefore you would have them rich. It
is said of our blessed Saviour, that he loved the young rich man that
came unto him, and therefore he bid him sell all that he had. What a
contrariety is here? The love which dwelleth in you, is as contrary to
the love which dwelt in Christ as darkness is to light.

We have our Saviour’s express command, to love one another,


as he loved us. And can you think you are following this love, when
you are giving those things to your children, which he took away
from his friends, and which he could not possibly have given them
without contradicting the greatest part of his doctrines?

XXXII. *But suppose you succeed in your designs, and leave


your children rich, what must you say to them when you are dying?
Will you then tell them that you have the same opinion of the value of
riches you ever had; that you feel the pleasure of remembring how
much thought and care you have taken to acquire them? Will you tell
them that you have provided for their ease and softness, their
pleasure and indulgence and figure in the world; and that they
cannot do better than to eat and drink and take their fill of such
enjoyments as riches afford? This would be dying like an Atheist.

If you would die like a Christian, must you not endeavour to fill
their minds with your dying thoughts? Must you not tell them that
very soon the world will signify no more to them than it does to you?
And that there is a vanity, a littleness in the things of this life, which
only dying men feel as they ought?

Will you not tell them, that all your own failings, the irregularity of
your life, the folly of your tempers, and your failure of Christian
perfection, has been owing to wrong opinions of the value of worldly
things? And that if you had always seen the world in the same light
that you see it now, your life had been devoted to God, and you
would have lived in all those holy tempers and heavenly affections in
which you now desire to die?

Will you not tell them, that riches spent upon ourselves, either in
the pleasures of ease and indulgence, in the vanity of dress, or in
state and grandeur, are the bane and destruction of our souls,
making us blindly content with dreams of happiness, till death
awakes us into real misery?

From all this therefore it appears, that your kindness for your
children is so far from being a good reason why you should so
carefully labour to leave them rich, and in the enjoyment of the state
and shew of the world; that if you die in a spirit of piety, if you love
them as Christ loved his disciples, your kindness will oblige you to
exhort them to renounce all such enjoyment of riches, as is contrary
to those holy tempers and that heavenly affection which you now find
to be the only good and happiness of human nature.
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

textbookfull.com

You might also like