NAME
begs – HTTP for humans who have run out of options – pleads with servers until they respond
SYNOPSIS
import begs
begs.get(url, please=True)
begs.post(url, json=data, insistence=3)
begs.grovel(url)
begs.bribe(url, amount=5)
begs.fax(url)
DESCRIPTION
begs is an HTTP library for Python built on a simple principle: ask nicely and you're more likely to get an answer. Ask desperately and you'll at least get sympathy.
When a server responds with an error, begs doesn't give up. It repeats the request – a little more politely each time, a little more desperately each time. Experts call this exponential begging: the delay between attempts doubles, and so does the number of exclamation marks.
Besides status_code, text and json(), every response has a mood
attribute that reveals how reluctantly the server replied. Possible values:
"gladly", "fine", "just this once" and "only because it's you".
FUNCTIONS
begs.get(url, please=False)- Fetches a resource. Without
please=True, begs responds with428 Precondition Required. The missing precondition is manners. begs.post(url, json=None, insistence=1)- Sends data. From
insistence=5onward, begs also emails the administrator; frominsistence=10, the administrator's mother. begs.grovel(url)- The last resort. Sends the request on its knees: with every known user agent at once and a handwritten letter of apology, scanned as a PDF, in the body.
begs.bribe(url, amount=5)- Adds an
X-Tipheader to the request. Works on a surprising number of enterprise APIs. begs.fax(url)- For servers run by German public authorities. Sends the request by fax; the response arrives by post within six to eight weeks. A stamped return envelope is enclosed.
begs.Session()- Remembers cookies, headers and every rejection. After the hundredth one,
session.relationship_statusis set to"it's complicated".
STATUS CODES
begs knows every official HTTP status code, plus a few that should have been introduced years ago:
| Code | Meaning |
|---|---|
202 | Accepted. Being processed. Really. Soon. |
299 | OK, but just this once. |
304 | Not modified – just like your situation. |
402 | Payment required. See begs.bribe(). |
418 | I'm a teapot. begs asks for coffee anyway. |
428 | Manners required. |
509 | Patience exceeded. |
EXAMPLES
Ask for a raise:
>>> r = begs.get("https://api.example.com/salary/raise")
>>> r.status_code
428
>>> r = begs.get("https://api.example.com/salary/raise", please=True)
>>> r.json()
{'raise': 0, 'message': "We'll get back to you."}
>>> r.mood
'fine'
What actually gets sent on retries:
$ BEGS_DEBUG=1 python script.py
begs: attempt 1 GET /api/data Accept: application/json
begs: attempt 2 GET /api/data X-Please: please
begs: attempt 3 GET /api/data X-Please: please please
begs: attempt 4 GET /api/data X-Please: PLEASE!!
begs: attempt 5 GET /api/data X-Please: I have a family, you know
begs: attempt 6 GET /api/data X-Please: ok sorry, didn't mean it like that
begs: response 503 – server is on vacation. Out-of-office reply in body.Apply for a building permit:
>>> r = begs.fax("https://planning.example.de/permit/garden-shed")
>>> r.status_code
202
>>> r.expected
datetime.date(2027, 3, 14)
>>> r.text
'Your application is incomplete. Please submit form B-17a (by fax only).'
EXCEPTIONS
begs.Rejection- The server responded with a 4xx. Don't take it personally. The server doesn't.
begs.LeftOnRead- Timeout. The server has read your request. Two blue ticks.
begs.RestrainingOrder429 Too Many Requests. You asked too often. The server has obtained a court order.
BUGS
begs does not work with servers that have no feelings. As far as we know, that is all of them. The bug is marked "wontfix", with the comment "please don't".
SEE ALSO
left-bad(3), maybealloc(3), wingit(W), – for people who don't ask