Pyjo-Reactor-Twisted
Low level event reactor with Twisted support for Pyjoyment.
Pyjo.Reactor.Twisted runs the I/O and the timers of Pyjo.IOLoop in the
reactor of Twisted, so that a Pyjoyment application and the code of Twisted
share one event loop.
Installation
From PyPI, with Pyjoyment and Twisted, which it depends on:
pip install Pyjo-Reactor-Twisted
or, in a project managed with uv:
uv add Pyjo-Reactor-Twisted
The development version is installed from the Git repository:
pip install git+https://github.com/pyjoyment/Pyjo-Reactor-Twisted
Usage
Select the reactor with PYJO_REACTOR before Pyjo.IOLoop is loaded:
PYJO_REACTOR=Pyjo.Reactor.Twisted python myapp.py daemon
The reactor of Twisted is unique in a process, so only one Pyjo.IOLoop uses
it at a time; the others get Pyjo.Reactor.Poll. When the reactor of Twisted
is running already, as under twistd or Scrapy, Pyjo.IOLoop.start() returns
right away and the events are handled by the reactor that runs.
Examples
examples/hello_world_twisted.py runs Pyjo.HelloWorld on the server of
Pyjoyment in the event loop that Twisted runs, with reactor.run(), in a
with block, which closes the listen sockets of the server at its end:
import os
# The reactor of Pyjoyment on the reactor of Twisted, selected before Pyjo.IOLoop is loaded
os.environ['PYJO_REACTOR'] = 'Pyjo.Reactor.Twisted'
import Pyjo.Reactor.Twisted # noqa: E402
# The reactor of Twisted of poll or select, before Twisted is imported, which would install its default, epoll on Linux
Pyjo.Reactor.Twisted.install()
import Pyjo.HelloWorld # noqa: E402
import Pyjo.Server.Daemon # noqa: E402
from twisted.internet import reactor # noqa: E402
# The server of Pyjoyment, which closes its listen sockets at the end of the block
with Pyjo.Server.Daemon.new(app=Pyjo.HelloWorld.new(), listen=['http://*:3000']) as daemon:
daemon.start()
# Twisted runs the event loop, with the server of Pyjoyment in it
reactor.run()
$ python examples/hello_world_twisted.py
Web application available at http://127.0.0.1:3000
$ curl http://127.0.0.1:3000/
Your Pyjo is working!
examples/user_agent_twisted.py is an application of Twisted, a server of
twisted.web, whose timer requests it every second with the user agent of
Pyjoyment, without blocking the reactor of Twisted. The user agent is in a
with block, which closes its connections at its end, so the callback shows
the error of a request that it interrupts:
import os
# The reactor of Pyjoyment on the reactor of Twisted, selected before Pyjo.IOLoop is loaded
os.environ['PYJO_REACTOR'] = 'Pyjo.Reactor.Twisted'
import Pyjo.Reactor.Twisted # noqa: E402
# The reactor of Twisted of poll or select, before Twisted is imported, which would install its default, epoll on Linux
Pyjo.Reactor.Twisted.install()
import Pyjo.UserAgent # noqa: E402
from twisted.internet import reactor, task # noqa: E402
from twisted.web import resource, server # noqa: E402
# An application of Twisted
class Hello(resource.Resource):
isLeaf = True
def render_GET(self, request):
return b'Hello from Twisted!'
reactor.listenTCP(3000, server.Site(Hello()))
# The user agent of Pyjoyment, which closes its connections at the end of the block
with Pyjo.UserAgent.new() as ua:
# A request every second, which does not block the reactor of Twisted; a request that the end of the block
# interrupts gets an error
def fetch():
def done(ua, tx):
print(tx.error['message'] if tx.error else f'{tx.res.code} {tx.res.text}')
ua.get('http://127.0.0.1:3000/', done)
task.LoopingCall(fetch).start(1)
reactor.run()
$ python examples/user_agent_twisted.py
200 Hello from Twisted!
200 Hello from Twisted!
200 Hello from Twisted!
examples/loopback_twisted.py is a server of Pyjoyment and its user agent on
the reactor of Twisted, a blocking request, which runs the event loop until
the response, and the class of the reactor, which Build checks with the wheel:
import os
# The reactor of Pyjoyment on the reactor of Twisted, selected before Pyjo.IOLoop is loaded
os.environ['PYJO_REACTOR'] = 'Pyjo.Reactor.Twisted'
import Pyjo.HelloWorld # noqa: E402
import Pyjo.IOLoop # noqa: E402
import Pyjo.Server.Daemon # noqa: E402
import Pyjo.UserAgent # noqa: E402
# The server, on a port that the system picks, and the user agent, in the same event loop, which close their sockets at
# the end of the block
with (
Pyjo.Server.Daemon.new(app=Pyjo.HelloWorld.new(), listen=['http://127.0.0.1'], silent=True) as daemon,
Pyjo.UserAgent.new(ioloop=Pyjo.IOLoop.singleton) as ua,
):
# A blocking request, which runs the event loop of the server on the reactor of Twisted until the response
tx = ua.get(f'http://127.0.0.1:{daemon.start().ports()[0]}/')
print(type(Pyjo.IOLoop.singleton.reactor).__name__)
print(tx.result.code, tx.result.text)
$ python examples/loopback_twisted.py
Pyjo_Reactor_Twisted
200 Your Pyjo is working!
The first two call Pyjo.Reactor.Twisted.install() before they import
Twisted, which would install its default, epoll on Linux, in the place of poll
or select; the third does not import Twisted, so the reactor installs it.
Documentation
The API of the module and the examples are on Read the Docs.
Status
An experiment: the first reactor of Pyjoyment in a distribution of its own.
License
The Artistic License 2.0, as Pyjoyment.
Metadata
Release files for Pyjo-Reactor-Twisted 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pyjo_reactor_twisted-0.2.0.tar.gz | 19.4 kB | With provenance | Details for pyjo_reactor_twisted-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyjo_reactor_twisted-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for pyjo_reactor_twisted-0.2.0-py3-none-any.whl |
Total release size: 31.1 kB
Release files / pyjo_reactor_twisted-0.2.0.tar.gz
| Download URL | pyjo_reactor_twisted-0.2.0.tar.gz |
|---|---|
| Size | 19.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
21bd3d0a7e1e16ca6b1fb3d1f6ef68a89640fd762905674cbf6493ed0144711d
|
|
BLAKE2b-256 checksum How to use checksums |
b0f5dcfb567e40795d0eb6ce3ec35304933a7b2b7ee936df9662c1e4c3ff2d95
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / pyjo_reactor_twisted-0.2.0-py3-none-any.whl
| Download URL | pyjo_reactor_twisted-0.2.0-py3-none-any.whl |
|---|---|
| Size | 11.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f6e08a2374949198b94a13ac1c14186be1811b48369337b893ff9caf483548ca
|
|
BLAKE2b-256 checksum How to use checksums |
294f33fb4b8b3500182cce3e38455f8f2bc50028caea7b1358d211c8a151941a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logSecurity for Pyjo-Reactor-Twisted 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pyjo_reactor_twisted-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.