Python APIs for GIL and Free-Threaded CPython
dexpot
SYNCHRONOUS PYTHON APIS
Synchronous APIs. GIL or free-threaded.
Keep plain synchronous handlers while Dexpot adapts bounded admission and scheduling to standard GIL or free-threaded CPython.

GET STARTED
Install Dexpot
pip install "dexpot[cli]"Quick start guide EXPLORE THE MECHANISM
Try bounded CRUD behavior.
Explore the existing playground’s bounded item operations, response outcomes, and recorded loopback evidence.
Browser-local preview. JavaScript computes bounded results in this tab; it does not execute Python or send requests. Recorded loopback timings are separate evidence, not this preview’s runtime.
Run a typed synchronous endpoint
Section titled “Run a typed synchronous endpoint”Dexpot keeps the route handler as an ordinary synchronous Python function. This is the same minimal application shipped in examples/minimal.py:
from msgspec import Struct
from dexpot import Dex
app = Dex()
class ItemOut(Struct): id: int name: str price: float
@app.get("/items/{item_id}", response=ItemOut)def get_item(item_id: int) -> ItemOut: """Return one typed item.""" return ItemOut(id=item_id, name=f"item-{item_id}", price=float(item_id))Save it as examples/minimal.py, install the CLI extra, and start the public server command from the repository root:
pip install "dexpot[cli]"PYTHONPATH=examples dexpot serve minimal:app --host 127.0.0.1 --port 8000In another terminal, call the actual HTTP route:
curl -i http://127.0.0.1:8000/items/7The example responds with the typed item for that path. The homepage preview remains browser-local; this command starts the real Python server.
One application. Two interpreter modes.
Section titled “One application. Two interpreter modes.”Dexpot keeps application code synchronous while changing admission and scheduling around the interpreter that runs it. The original execution diagram is a conceptual overview, not a literal request sequence.
| Runtime | Serving model | Overload behavior |
|---|---|---|
| Free-threaded CPython (GIL disabled) | One process; each admitted connection owns a thread | A process-wide active-connection cap sheds excess work before thread creation |
| CPython with the GIL enabled | A bounded pool of connection-owning threads | A bounded queue sheds excess work with 503 |
| CPython with the GIL enabled and workers | POSIX SO_REUSEPORT processes, each with its own bounded pool |
Each worker sheds independently |

Worker lifecycle
Section titled “Worker lifecycle”The new supporting diagram explains v0.7.1 startup and connection ownership without replacing the execution overview above. Dexpot selects its serving mode when serve() starts, after application imports, using the actual GIL state. The application handler syntax does not change.

On macOS with the GIL disabled, workers can use an owner-scoped scheduling policy and offer other workers a turn after at least 1 ms of accumulated CPU work, at a completed continuing-response boundary. Waiting does not use that budget; application handlers are not preempted. Successful policy changes are restored before worker exit. Linux and GIL-enabled execution retain their existing paths; the main/acceptor thread policy is unchanged.
Checked response policy
Section titled “Checked response policy”In v0.7.0, response=ItemOut also checks the returned data and projects it onto the declared public fields before sending success bytes. Malformed or non-finite output returns a sanitized 500. Leave response=None for generic JSON, or use RawResponse on an unchecked route for bytes. The response-contract illustration shows the public-field and rejection paths.

Keep learning
Section titled “Keep learning”- Quick start: install, define an app, serve it, and call HTTP routes.
- Build guides: practical setup and operation paths.
- Route contract: handler signatures, path binding, and response behavior.
- Execution model: GIL and free-threaded scheduling boundaries.
- Runnable examples: complete shipped applications and requests.
What dexpot owns
Section titled “What dexpot owns”- Plain synchronous handlers without an event loop or coroutine bridge.
- Compiled endpoint plans for route matching, argument binding, path conversion, and msgspec codecs.
- Interpreter-adaptive scheduling selected when
serve()starts, after application imports, from the actual GIL state. - A bounded HTTP core for parsing, routing, scheduling, draining, and response writes.
- An optional parser-only Rust extension without moving sockets, routing, handlers, or scheduling out of Python.
Dexpot is part of ModePot, an open-source family of modern frameworks, tools, engines, and games.