yet another library to convert request object to curl command
Project description
curlify3
Convert request objects from popular Python HTTP libraries into ready-to-run curl commands.
curlify3 takes a request object from any supported client or server framework and renders it as an equivalent curl command — useful for logging, debugging, sharing reproductions, and copy-pasting from your IDE into a terminal.
Features
- Single dispatch entrypoint —
to_curl()(sync) andto_curl_async()(async) - Works with client-side requests (
requests,httpx,httpx2) and server-side incoming requests (aiohttp.web,starlette/fastapi) - Faithful rendering of headers, query parameters, cookies (
-b), and bodies - Body payloads: text, JSON, form-encoded, multipart, binary
- Zero runtime dependencies
Installation
pip install curlify3
Requires Python 3.10+.
Comparison with curlify and curlify2
curlify |
curlify2 |
curlify3 |
|
|---|---|---|---|
requests |
[x] | [x] | [x] |
httpx |
[ ] | [x] | [x] |
httpx2 (HTTP/2) |
[ ] | [ ] | [x] |
aiohttp (server-side) |
[ ] | [ ] | [x] |
starlette / fastapi (server-side) |
[ ] | [ ] | [x] |
| Async API | [ ] | [ ] | [x] |
| Python | 3.7+ | 3.7–3.11 | 3.10+ |
curlify is the original and covers only requests. curlify2 added httpx but is sync-only, client-side-only, and has not seen a release since 2023. curlify3 extends the same idea with HTTP/2 (httpx2), an async entrypoint, and server-side adapters for aiohttp and starlette / fastapi so you can dump incoming requests as curl from inside a handler.
Quick start
import requests
from curlify3 import to_curl
response = requests.get("https://httpbin.org/get")
print(to_curl(response.request))
# curl -H 'user-agent: python-requests/2.32.3' -H 'accept-encoding: gzip, deflate' \
# -H 'accept: */*' -H 'connection: keep-alive' https://httpbin.org/get
Usage
requests
import requests
from curlify3 import to_curl
req = requests.Request(
"POST",
"https://httpbin.org/post",
json={"hello": "world"},
).prepare()
print(to_curl(req))
httpx (sync)
import httpx
from curlify3 import to_curl
req = httpx.Request("POST", "https://httpbin.org/post", json={"hello": "world"})
print(to_curl(req))
httpx (async)
import asyncio
import httpx
from curlify3 import to_curl_async
async def main():
req = httpx.Request("POST", "https://httpbin.org/post", json={"a": 1})
print(await to_curl_async(req))
asyncio.run(main())
httpx2 — HTTP/2
The generated command includes --http2.
import httpx2
from curlify3 import to_curl
req = httpx2.Request("GET", "https://httpbin.org/get")
print(to_curl(req))
# curl --http2 -H 'host: httpbin.org' https://httpbin.org/get
to_curl_async() works with httpx2.Request too.
aiohttp — server-side
Render an incoming request inside a handler. The async variant is required because the body is read from the stream.
from aiohttp import web
from curlify3 import to_curl_async
async def handler(request: web.Request) -> web.Response:
curl = await to_curl_async(request)
print(curl)
return web.json_response({"ok": True})
starlette / fastapi — server-side
from fastapi import FastAPI, Request
from curlify3 import to_curl_async
app = FastAPI()
@app.post("/echo")
async def echo(request: Request):
curl = await to_curl_async(request)
return {"curl": curl}
API
to_curl(request) -> str
Render a request object as a curl command. Use for synchronous request types (requests.PreparedRequest, httpx.Request, httpx2.Request).
to_curl_async(request) -> str
Async variant. Use for server-side request objects whose body must be await-ed (aiohttp.web.Request, starlette.requests.Request) or when you prefer the async pathway for httpx / httpx2.
Both functions raise ValueError("unknown request object") if the request type is not recognized.
Supported request objects
| Library | Type | to_curl |
to_curl_async |
Notes |
|---|---|---|---|---|
requests |
PreparedRequest |
[x] | [ ] | Pass Request(...).prepare() |
httpx |
httpx.Request |
[x] | [x] | |
httpx2 |
httpx2.Request |
[x] | [x] | Adds --http2 |
aiohttp |
aiohttp.web.Request |
[ ] | [x] | Server-side |
starlette / fastapi |
starlette.requests.Request |
[ ] | [x] | Server-side |
Payload handling
| Payload | Rendered as |
|---|---|
| Plain text | -d 'text' |
| JSON | -d '{"k":"v"}' with content-type: application/json |
| Form-encoded | -d 'k=v&k2=v2' with content-type: application/x-www-form-urlencoded |
| Multipart / files | -F 'field=@file' -F 'other=value' |
| Binary | -d with raw bytes (falls back when not UTF-8) |
| Cookies | -b 'k=v' (lifted out of Cookie header) |
| Headers | -H 'name: value' (lowercased) |
Content-Length is dropped. If a body is present without Content-Type, content-type: plain/text is added so curl does not guess.
Development
uv sync --group dev
just tests # uv run pytest -vv
just fmt # isort + black
CI runs the test suite on Python 3.10–3.14.
Changelog
See CHANGELOG.md.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file curlify3-0.7.tar.gz.
File metadata
- Download URL: curlify3-0.7.tar.gz
- Upload date:
- Size: 6.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c8367499d7cd9134b8f987f25acd1c2126dc0215253ab12fc71c40a242d700d
|
|
| MD5 |
40557fcad9463467e031615c5494cd71
|
|
| BLAKE2b-256 |
0b77b2a9d6beb691c21caa25fa18cd3fca61481cc67fb20e82f78c1b92a6bd18
|
File details
Details for the file curlify3-0.7-py3-none-any.whl.
File metadata
- Download URL: curlify3-0.7-py3-none-any.whl
- Upload date:
- Size: 7.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
002011e2d042392095fd6e809e4dfe3e03325643a3b952597c24045da3017ccd
|
|
| MD5 |
f6b57bb5b6addffe73ab83702928d70f
|
|
| BLAKE2b-256 |
f06bdf47d5eb234031f0786060f96239530e3c7b43862cf2de86b4efec526e89
|