The command
curl -X POST https://httpbin.org/post \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Ada","role":"admin"}'
Curl flag to requests argument
| curl | Python requests |
|---|---|
-X METHOD | requests.request("METHOD", url) or requests.post(url) and friends |
-H "K: v" | headers={"K": "v"} |
-d "a=1&b=2" | data={"a": "1", "b": "2"} |
-d '{"a":1}' + JSON header | json={"a": 1} (sets the header itself) |
-F "file=@x.png" | files={"file": open("x.png", "rb")} |
-u user:pw | auth=("user", "pw") |
-b "k=v" | cookies={"k": "v"} |
-x proxy | proxies={"https": "http://proxy:8080"} |
-m 20 | timeout=20 |
-k | verify=False |
--cacert ca.pem | verify="ca.pem" |
-L | default; turn off with allow_redirects=False |
The same request in Python
The command above becomes a single call. Passing a dictionary to json= serialises it and sets Content-Type: application/json, so that header disappears from your code. The token comes from the environment, as $TOKEN did in the shell.
import os
import requests
response = requests.post(
"https://httpbin.org/post",
headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
json={"name": "Ada", "role": "admin"},
timeout=20,
)
response.raise_for_status()
print(response.json())
Three defaults that differ
Redirects. Requests follows them automatically; curl does not unless given -L. A curl command without -L that returns a 302 will, once translated, quietly return the page behind it.
Timeouts. Requests has none by default and will wait forever. Curl is the same, but a hung terminal is obvious and a hung worker process is not. Always pass timeout=.
Errors. Like curl without -f, requests does not treat a 4xx or 5xx as a failure. raise_for_status() is the equivalent of -f.
Data: string or dictionary
data= with a dictionary form-encodes it, the same as several --data-urlencode flags. data= with a string or bytes sends it untouched, like --data-binary, and then you set Content-Type yourself. Do not pass an already-serialised JSON string to json=; it would be encoded a second time and arrive as a quoted string.
requests.post(url, data={"q": "rate limit & retries"}) # form-encoded
requests.post(url, data=raw_xml.encode("utf-8"),
headers={"Content-Type": "application/xml"}) # raw body
Common mistakes
- Do not set
Content-Typewhen usingfiles=. As withcurl -F, the library must generate the multipart boundary. - Use a
Sessionfor several calls. It reuses the connection and keeps cookies, like one curl process with a cookie jar. - Compressed responses are decoded automatically, so
--compressedhas no counterpart to write.
Related curl examples
Convert Curl to JavaScript Fetch
fetch() takes a URL and an options object that lines up closely with curl's flags.
Convert Curl to PHP
PHP's cURL extension is a wrapper around the same library the command-line tool uses, so every flag has a matching option.
Curl POST JSON Example
Sending JSON takes two things: the JSON itself and a header saying that is what it is.
Convert Curl to a Raw HTTP Request
Every curl command turns into a few lines of text sent over a socket.
cURL Converter
Paste a curl command and get Python, JavaScript, PHP, Go and more, with shell quoting parsed properly.
All Curl Examples
49 worked examples, grouped by what you are trying to do.
References
- Requests documentation — The Python library the converted code uses.
- curl man page — What each flag being translated actually does.
These links leave api-tester.com, which is independent of the projects they point to.
FAQ
How do I convert a curl command to Python?
Map each flag to a requests argument: -H to headers, -d to data or json, -u to auth, -F to files, and the method to requests.get, post, put and so on. A converter tool can do this automatically.
What is the Python equivalent of curl -d?
requests.post(url, data=...) for form data or a raw string, and requests.post(url, json=...) when the body is JSON.
Does Python requests follow redirects like curl -L?
Yes, and by default. Pass allow_redirects=False to get the behaviour of curl without -L.