1from __future__ import annotations
2
3from enum import IntEnum
4
5
6class codes(IntEnum):
7 """HTTP status codes and reason phrases
8
9 Status codes from the following RFCs are all observed:
10
11 * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
12 * RFC 6585: Additional HTTP Status Codes
13 * RFC 3229: Delta encoding in HTTP
14 * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518
15 * RFC 5842: Binding Extensions to WebDAV
16 * RFC 7238: Permanent Redirect
17 * RFC 2295: Transparent Content Negotiation in HTTP
18 * RFC 2774: An HTTP Extension Framework
19 * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2)
20 * RFC 2324: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0)
21 * RFC 7725: An HTTP Status Code to Report Legal Obstacles
22 * RFC 8297: An HTTP Status Code for Indicating Hints
23 * RFC 8470: Using Early Data in HTTP
24 """
25
26 def __new__(cls, value: int, phrase: str = "") -> codes:
27 obj = int.__new__(cls, value)
28 obj._value_ = value
29
30 obj.phrase = phrase # type: ignore[attr-defined]
31 return obj
32
33 def __str__(self) -> str:
34 return str(self.value)
35
36 @classmethod
37 def get_reason_phrase(cls, value: int) -> str:
38 try:
39 return codes(value).phrase # type: ignore
40 except ValueError:
41 return ""
42
43 @classmethod
44 def is_informational(cls, value: int) -> bool:
45 """
46 Returns `True` for 1xx status codes, `False` otherwise.
47 """
48 return 100 <= value <= 199
49
50 @classmethod
51 def is_success(cls, value: int) -> bool:
52 """
53 Returns `True` for 2xx status codes, `False` otherwise.
54 """
55 return 200 <= value <= 299
56
57 @classmethod
58 def is_redirect(cls, value: int) -> bool:
59 """
60 Returns `True` for 3xx status codes, `False` otherwise.
61 """
62 return 300 <= value <= 399
63
64 @classmethod
65 def is_client_error(cls, value: int) -> bool:
66 """
67 Returns `True` for 4xx status codes, `False` otherwise.
68 """
69 return 400 <= value <= 499
70
71 @classmethod
72 def is_server_error(cls, value: int) -> bool:
73 """
74 Returns `True` for 5xx status codes, `False` otherwise.
75 """
76 return 500 <= value <= 599
77
78 @classmethod
79 def is_error(cls, value: int) -> bool:
80 """
81 Returns `True` for 4xx or 5xx status codes, `False` otherwise.
82 """
83 return 400 <= value <= 599
84
85 # informational
86 CONTINUE = 100, "Continue"
87 SWITCHING_PROTOCOLS = 101, "Switching Protocols"
88 PROCESSING = 102, "Processing"
89 EARLY_HINTS = 103, "Early Hints"
90
91 # success
92 OK = 200, "OK"
93 CREATED = 201, "Created"
94 ACCEPTED = 202, "Accepted"
95 NON_AUTHORITATIVE_INFORMATION = 203, "Non-Authoritative Information"
96 NO_CONTENT = 204, "No Content"
97 RESET_CONTENT = 205, "Reset Content"
98 PARTIAL_CONTENT = 206, "Partial Content"
99 MULTI_STATUS = 207, "Multi-Status"
100 ALREADY_REPORTED = 208, "Already Reported"
101 IM_USED = 226, "IM Used"
102
103 # redirection
104 MULTIPLE_CHOICES = 300, "Multiple Choices"
105 MOVED_PERMANENTLY = 301, "Moved Permanently"
106 FOUND = 302, "Found"
107 SEE_OTHER = 303, "See Other"
108 NOT_MODIFIED = 304, "Not Modified"
109 USE_PROXY = 305, "Use Proxy"
110 TEMPORARY_REDIRECT = 307, "Temporary Redirect"
111 PERMANENT_REDIRECT = 308, "Permanent Redirect"
112
113 # client error
114 BAD_REQUEST = 400, "Bad Request"
115 UNAUTHORIZED = 401, "Unauthorized"
116 PAYMENT_REQUIRED = 402, "Payment Required"
117 FORBIDDEN = 403, "Forbidden"
118 NOT_FOUND = 404, "Not Found"
119 METHOD_NOT_ALLOWED = 405, "Method Not Allowed"
120 NOT_ACCEPTABLE = 406, "Not Acceptable"
121 PROXY_AUTHENTICATION_REQUIRED = 407, "Proxy Authentication Required"
122 REQUEST_TIMEOUT = 408, "Request Timeout"
123 CONFLICT = 409, "Conflict"
124 GONE = 410, "Gone"
125 LENGTH_REQUIRED = 411, "Length Required"
126 PRECONDITION_FAILED = 412, "Precondition Failed"
127 REQUEST_ENTITY_TOO_LARGE = 413, "Request Entity Too Large"
128 REQUEST_URI_TOO_LONG = 414, "Request-URI Too Long"
129 UNSUPPORTED_MEDIA_TYPE = 415, "Unsupported Media Type"
130 REQUESTED_RANGE_NOT_SATISFIABLE = 416, "Requested Range Not Satisfiable"
131 EXPECTATION_FAILED = 417, "Expectation Failed"
132 IM_A_TEAPOT = 418, "I'm a teapot"
133 MISDIRECTED_REQUEST = 421, "Misdirected Request"
134 UNPROCESSABLE_ENTITY = 422, "Unprocessable Entity"
135 LOCKED = 423, "Locked"
136 FAILED_DEPENDENCY = 424, "Failed Dependency"
137 TOO_EARLY = 425, "Too Early"
138 UPGRADE_REQUIRED = 426, "Upgrade Required"
139 PRECONDITION_REQUIRED = 428, "Precondition Required"
140 TOO_MANY_REQUESTS = 429, "Too Many Requests"
141 REQUEST_HEADER_FIELDS_TOO_LARGE = 431, "Request Header Fields Too Large"
142 UNAVAILABLE_FOR_LEGAL_REASONS = 451, "Unavailable For Legal Reasons"
143
144 # server errors
145 INTERNAL_SERVER_ERROR = 500, "Internal Server Error"
146 NOT_IMPLEMENTED = 501, "Not Implemented"
147 BAD_GATEWAY = 502, "Bad Gateway"
148 SERVICE_UNAVAILABLE = 503, "Service Unavailable"
149 GATEWAY_TIMEOUT = 504, "Gateway Timeout"
150 HTTP_VERSION_NOT_SUPPORTED = 505, "HTTP Version Not Supported"
151 VARIANT_ALSO_NEGOTIATES = 506, "Variant Also Negotiates"
152 INSUFFICIENT_STORAGE = 507, "Insufficient Storage"
153 LOOP_DETECTED = 508, "Loop Detected"
154 NOT_EXTENDED = 510, "Not Extended"
155 NETWORK_AUTHENTICATION_REQUIRED = 511, "Network Authentication Required"
156
157
158# Include lower-case styles for `requests` compatibility.
159for code in codes:
160 setattr(codes, code._name_.lower(), int(code))