Requests: Raise exception if status code doesn't equal 200

Created on 27 Jul 2014  ·  3Comments  ·  Source: psf/requests

Hello,
I often expect the request to have status code 200 and if it doesn't there isn't much I can do about (seriously when the server returns with error 500, I won't be able to do something). So I need to write code like this:

    r = requests.get(self.url(False))
    if r.status_code != 200:
        raise requests.ConnectionError("Expected status code 200, but got {}".format(page.status_code))

I think a kwarg called allowed_status_codes would be very convenient. It could be implemented like this:
By default it is None. None, and an empty list or tuple means allow all status codes. It may be an integer, list, tuple, or enum. If it is an integer, only allow this specific status code. In case it is a list or tuple, only status codes that are inside of the list/tuple are allowed. The list may have integers and/or enums. Enums should be a little bit more flexible.
For instance, if I wanted to allow all "successful" (2xx) requests, I could write: allowed_status_codes=requests.ALLOW_SUCCESS, which will throw an exception unless the status code is 2xx. If I only wanted to disallow server errors (and thus handle not authenticated errors), I could simply write allowed_status_codes=requests.DISALLOW_SERVER_ERROR, which will raise an exception if the server code is 5xx.
Of course there should be lots of enums that cover specific cases. And one should also be able to use it combined within a list (e.g. (200, ALLOW_REDIRECTIONS)).
If the status code isn't allowed, a StatusCodeError(RequestException) will be raised.


Even though I mentioned enums, I'm not talking about Python 3.4's enumerated values. I was talking rather about constants. Enums (constants) could be implemented like this:

#request model.

ALLOW_SUCCESS = AllowSuccessEnum()
# other enums

class RequestEnum(object):
     def is_status_code_allowed(status_code):
         raise NotImplementedError

class AllowSuccessEnum(RequestEnum):
    def is_status_code_allowed(status_code):
        # return false unless status code is 2xx

Most helpful comment

Also, doesn't each Response have a raise_for_status method that will raise an exception if the status code isn't 200?

Python 2.7.7 (default, Jun  2 2014, 18:55:26)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> r = requests.get('http://httpbin.org/404')
>>> r
<Response [404]>
>>> r.raise_for_status()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/requests/models.py", line 795, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: NOT FOUND

All 3 comments

Thanks for this idea!

It's not clear why this belongs in requests itself. The code required is not complex, and I do not believe we would add much value by having this code in the library. We _would_, however, be adding another keyword argument to the API, which is something we're disinclined to do most of the time.

Also, doesn't each Response have a raise_for_status method that will raise an exception if the status code isn't 200?

Python 2.7.7 (default, Jun  2 2014, 18:55:26)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> r = requests.get('http://httpbin.org/404')
>>> r
<Response [404]>
>>> r.raise_for_status()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/requests/models.py", line 795, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: NOT FOUND

@Lukasa Because it is very convenient, can save lots of code (let's just say a project uses request. This project uses about 100 times a request. So, it _could_ save 200 lines of code, and prevent typos because I would have to write the exception 100 times (in case I don't use a method for raising an exception), and it unifies exceptions/errors (another API may use requests and raise a custom error in case of an invalid status code. I like it better if it throws the same exception as requests does).

@sigmavirus24 Sorry, I didn't know this method exists. You should mention that an HTTPError can be raised by raise_for_status in Error and Exceptions section in the docs. An HTTPError currently claims only to be raised "In the rare event of an invalid HTTP response".
You could also consider implementing some of my ideas into my raise_for_status so that it can allow other status codes, too.

Was this page helpful?
0 / 5 - 0 ratings