Single consistent name for status codes (#1088)

* Single consistent name for status codes
* Gentle deprecation for httpx.StatusCode
This commit is contained in:
Tom Christie 2020-07-27 14:35:01 +01:00 committed by GitHub
parent 2e60e145d7
commit 35f09d1394
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 17 deletions

View File

@ -80,6 +80,7 @@ __all__ = [
"ResponseClosed",
"ResponseNotRead",
"RequestNotRead",
"StatusCode",
"StreamConsumed",
"StreamError",
"ProxyError",
@ -90,7 +91,6 @@ __all__ = [
"URL",
"URLLib3Transport",
"URLLib3ProxyTransport",
"StatusCode",
"Cookies",
"Headers",
"QueryParams",

View File

@ -30,7 +30,7 @@ from ._exceptions import (
ResponseNotRead,
StreamConsumed,
)
from ._status_codes import StatusCode
from ._status_codes import codes
from ._types import (
CookieTypes,
HeaderTypes,
@ -660,7 +660,7 @@ class Response:
@property
def reason_phrase(self) -> str:
return StatusCode.get_reason_phrase(self.status_code)
return codes.get_reason_phrase(self.status_code)
@property
def url(self) -> typing.Optional[URL]:
@ -758,11 +758,11 @@ class Response:
@property
def is_error(self) -> bool:
return StatusCode.is_error(self.status_code)
return codes.is_error(self.status_code)
@property
def is_redirect(self) -> bool:
return StatusCode.is_redirect(self.status_code) and "location" in self.headers
return codes.is_redirect(self.status_code) and "location" in self.headers
def raise_for_status(self) -> None:
"""
@ -773,10 +773,10 @@ class Response:
"For more information check: https://httpstatuses.com/{0.status_code}"
)
if StatusCode.is_client_error(self.status_code):
if codes.is_client_error(self.status_code):
message = message.format(self, error_type="Client Error")
raise HTTPStatusError(message, response=self)
elif StatusCode.is_server_error(self.status_code):
elif codes.is_server_error(self.status_code):
message = message.format(self, error_type="Server Error")
raise HTTPStatusError(message, response=self)

View File

@ -1,7 +1,8 @@
import warnings
from enum import IntEnum
class StatusCode(IntEnum):
class codes(IntEnum):
"""HTTP status codes and reason phrases
Status codes from the following RFCs are all observed:
* RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
@ -17,7 +18,7 @@ class StatusCode(IntEnum):
* RFC 7725: An HTTP Status Code to Report Legal Obstacles
"""
def __new__(cls, value: int, phrase: str = "") -> "StatusCode":
def __new__(cls, value: int, phrase: str = "") -> "codes":
obj = int.__new__(cls, value) # type: ignore
obj._value_ = value
@ -30,7 +31,7 @@ class StatusCode(IntEnum):
@classmethod
def get_reason_phrase(cls, value: int) -> str:
try:
return StatusCode(value).phrase # type: ignore
return codes(value).phrase # type: ignore
except ValueError:
return ""
@ -38,15 +39,15 @@ class StatusCode(IntEnum):
def is_redirect(cls, value: int) -> bool:
return value in (
# 301 (Cacheable redirect. Method may change to GET.)
StatusCode.MOVED_PERMANENTLY,
codes.MOVED_PERMANENTLY,
# 302 (Uncacheable redirect. Method may change to GET.)
StatusCode.FOUND,
codes.FOUND,
# 303 (Client should make a GET or HEAD request.)
StatusCode.SEE_OTHER,
codes.SEE_OTHER,
# 307 (Equiv. 302, but retain method)
StatusCode.TEMPORARY_REDIRECT,
codes.TEMPORARY_REDIRECT,
# 308 (Equiv. 301, but retain method)
StatusCode.PERMANENT_REDIRECT,
codes.PERMANENT_REDIRECT,
)
@classmethod
@ -132,8 +133,26 @@ class StatusCode(IntEnum):
NETWORK_AUTHENTICATION_REQUIRED = 511, "Network Authentication Required"
codes = StatusCode
#  Include lower-case styles for `requests` compatibility.
for code in codes:
setattr(codes, code._name_.lower(), int(code))
class StatusCodeCompat:
def __call__(self, *args, **kwargs): # type: ignore
message = "`httpx.StatusCode` is deprecated. Use `httpx.codes` instead."
warnings.warn(message, DeprecationWarning)
return codes(*args, **kwargs)
def __getattr__(self, attr): # type: ignore
message = "`httpx.StatusCode` is deprecated. Use `httpx.codes` instead."
warnings.warn(message, DeprecationWarning)
return getattr(codes, attr)
def __getitem__(self, item): # type: ignore
message = "`httpx.StatusCode` is deprecated. Use `httpx.codes` instead."
warnings.warn(message, DeprecationWarning)
return codes[item]
StatusCode = StatusCodeCompat()

View File

@ -1,3 +1,5 @@
import pytest
import httpx
@ -6,6 +8,14 @@ def test_status_code_as_int():
assert str(httpx.codes.NOT_FOUND) == "404"
def test_status_code_value_lookup():
assert httpx.codes(404) == 404
def test_status_code_phrase_lookup():
assert httpx.codes["NOT_FOUND"] == 404
def test_lowercase_status_code():
assert httpx.codes.not_found == 404 # type: ignore
@ -16,3 +26,14 @@ def test_reason_phrase_for_status_code():
def test_reason_phrase_for_unknown_status_code():
assert httpx.codes.get_reason_phrase(499) == ""
def test_deprecated_status_code_class():
with pytest.warns(DeprecationWarning):
assert httpx.StatusCode.NOT_FOUND == 404
with pytest.warns(DeprecationWarning):
assert httpx.StatusCode(404) == 404
with pytest.warns(DeprecationWarning):
assert httpx.StatusCode["NOT_FOUND"] == 404