Coverage for aiocoap/numbers/codes.py: 92%
87 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-16 16:09 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-16 16:09 +0000
1# SPDX-FileCopyrightText: Christian Amsüss and the aiocoap contributors
2#
3# SPDX-License-Identifier: MIT
5"""List of known values for the CoAP "Code" field.
7The values in this module correspond to the IANA registry "`CoRE Parameters`_",
8subregistries "CoAP Method Codes" and "CoAP Response Codes".
10The codes come with methods that can be used to get their rough meaning, see
11the :class:`Code` class for details.
13.. _`CoRE Parameters`: https://www.iana.org/assignments/core-parameters/core-parameters.xhtml
14"""
16import warnings
18from ..util import ExtensibleIntEnum
20class Code(ExtensibleIntEnum):
21 """Value for the CoAP "Code" field.
23 As the number range for the code values is separated, the rough meaning of
24 a code can be determined using the :meth:`is_request`, :meth:`is_response` and
25 :meth:`is_successful` methods."""
27 EMPTY = 0
28 GET = 1
29 POST = 2
30 PUT = 3
31 DELETE = 4
32 FETCH = 5
33 PATCH = 6
34 iPATCH = 7
35 CREATED = 65
36 DELETED = 66
37 VALID = 67
38 CHANGED = 68
39 CONTENT = 69
40 CONTINUE = 95
41 BAD_REQUEST = 128
42 UNAUTHORIZED = 129
43 BAD_OPTION = 130
44 FORBIDDEN = 131
45 NOT_FOUND = 132
46 METHOD_NOT_ALLOWED = 133
47 NOT_ACCEPTABLE = 134
48 REQUEST_ENTITY_INCOMPLETE = 136
49 CONFLICT = (4 << 5) + 9
50 PRECONDITION_FAILED = 140
51 REQUEST_ENTITY_TOO_LARGE = 141
52 UNSUPPORTED_CONTENT_FORMAT = 143
53 @property
54 def UNSUPPORTED_MEDIA_TYPE(self):
55 warnings.warn("UNSUPPORTED_MEDIA_TYPE is a deprecated alias for UNSUPPORTED_CONTENT_FORMAT")
56 return self.UNSUPPORTED_CONTENT_FORMAT
57 UNPROCESSABLE_ENTITY = (4 << 5) + 22
58 TOO_MANY_REQUESTS = (4 << 5) + 29
59 INTERNAL_SERVER_ERROR = 160
60 NOT_IMPLEMENTED = 161
61 BAD_GATEWAY = 162
62 SERVICE_UNAVAILABLE = 163
63 GATEWAY_TIMEOUT = 164
64 PROXYING_NOT_SUPPORTED = 165
65 HOP_LIMIT_REACHED = (5 << 5) + 8
67 CSM = 225
68 PING = 226
69 PONG = 227
70 RELEASE = 228
71 ABORT = 229
73 def is_request(self):
74 """True if the code is in the request code range"""
75 return True if (self >= 1 and self < 32) else False
78 def is_response(self):
79 """True if the code is in the response code range"""
80 return True if (self >= 64 and self < 192) else False
82 def is_signalling(self):
83 return True if self >= 224 else False
86 def is_successful(self):
87 """True if the code is in the successful subrange of the response code range"""
88 return True if (self >= 64 and self < 96) else False
90 def can_have_payload(self):
91 """True if a message with that code can carry a payload. This is not
92 checked for strictly, but used as an indicator."""
93 return self.is_response() or self in (self.POST, self.PUT, self.FETCH, self.PATCH, self.iPATCH)
95 @property
96 def class_(self):
97 """The class of a code (distinguishing whether it's successful, a
98 request or a response error or more).
100 >>> Code.CONTENT
101 <Successful Response Code 69 "2.05 Content">
102 >>> Code.CONTENT.class_
103 2
104 >>> Code.BAD_GATEWAY
105 <Response Code 162 "5.02 Bad Gateway">
106 >>> Code.BAD_GATEWAY.class_
107 5
108 """
109 return self >> 5
111 @property
112 def dotted(self):
113 """The numeric value three-decimal-digits (c.dd) form"""
114 return "%d.%02d" % divmod(self, 32)
116 @property
117 def name_printable(self):
118 """The name of the code in human-readable form"""
119 return self.name.replace('_', ' ').title()
121 def __str__(self):
122 """
123 >>> print(Code.GET)
124 GET
125 >>> print(Code.CONTENT)
126 2.05 Content
127 >>> print(Code.BAD_GATEWAY)
128 5.02 Bad Gateway
129 >>> print(Code(32))
130 32
131 """
132 if self.is_request() or self is self.EMPTY:
133 return self.name
134 elif self.is_response() or self.is_signalling():
135 return "%s %s" % (self.dotted, self.name_printable)
136 else:
137 return "%d" % self
139 def _classification(self):
140 return ("Successful " if self.is_successful() else "") + ("Request " if self.is_request() else "Response " if self.is_response() else "")
142 def __repr__(self):
143 """
144 >>> Code.GET
145 <Request Code 1 "GET">
146 >>> Code.CONTENT
147 <Successful Response Code 69 "2.05 Content">
148 >>> Code.BAD_GATEWAY
149 <Response Code 162 "5.02 Bad Gateway">
150 >>> Code(32)
151 <Code 32 "32">
152 """
153 return '<%sCode %d "%s">' % (self._classification(), self, self)
155 name = property(lambda self: self._name if hasattr(self, "_name") else "(unknown)", lambda self, value: setattr(self, "_name", value), doc="The constant name of the code (equals name_printable readable in all-caps and with underscores)")
157 def _repr_html_(self):
158 import html
159 if hasattr(self, "_name"):
160 return f'<abbr title="{self._classification()}Code {self.dotted}">{html.escape(self.name)}</abbr>'
161 else:
162 return f'<abbr title="Unknown {self._classification()}Code">{self.dotted}</abbr>'
164for k in vars(Code):
165 if isinstance(getattr(Code, k), Code):
166 locals()[k] = getattr(Code, k)
168__all__ = ['Code'] + [k for (k, v) in locals().items() if isinstance(v, Code)]