Skip to content

Commit 21e20b6

Browse files
committed
Preparing code for docs generation, black formatting, updating examples
1 parent 41edff8 commit 21e20b6

File tree

11 files changed

+190
-59
lines changed

11 files changed

+190
-59
lines changed

adafruit_httpserver/methods.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
`adafruit_httpserver.methods.HTTPMethod`
6+
====================================================
7+
* Author(s): Michał Pokusa
8+
"""
19

210
class HTTPMethod:
3-
"""HTTP method."""
11+
"""Enum with HTTP methods."""
412

513
GET = "GET"
14+
"""GET method."""
15+
616
POST = "POST"
17+
"""POST method."""
18+
719
PUT = "PUT"
20+
"""PUT method"""
21+
822
DELETE = "DELETE"
23+
"""DELETE method"""
24+
925
PATCH = "PATCH"
26+
"""PATCH method"""
27+
1028
HEAD = "HEAD"
29+
"""HEAD method"""
30+
1131
OPTIONS = "OPTIONS"
32+
"""OPTIONS method"""
33+
1234
TRACE = "TRACE"
35+
"""TRACE method"""
36+
1337
CONNECT = "CONNECT"
38+
"""CONNECT method"""

adafruit_httpserver/mime_type.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
`adafruit_httpserver.mime_type.MIMEType`
6+
====================================================
7+
* Author(s): Dan Halbert, Michał Pokusa
8+
"""
9+
110
class MIMEType:
211
"""Common MIME types.
312
From https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
@@ -78,12 +87,12 @@ class MIMEType:
7887
ZIP = "application/zip"
7988
_7Z = "application/x-7z-compressed"
8089

81-
8290
@staticmethod
8391
def from_file_name(filename: str):
8492
"""Return the mime type for the given filename. If not known, return "text/plain"."""
8593
attr_name = filename.split(".")[-1].upper()
8694

87-
if attr_name[0].isdigit(): attr_name = "_" + attr_name
95+
if attr_name[0].isdigit():
96+
attr_name = "_" + attr_name
8897

8998
return getattr(MIMEType, attr_name, MIMEType.TXT)

adafruit_httpserver/request.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,57 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
`adafruit_httpserver.request.HTTPRequest`
6+
====================================================
7+
* Author(s): Dan Halbert, Michał Pokusa
8+
"""
9+
110
try:
211
from typing import Dict, Tuple
312
except ImportError:
413
pass
514

615

716
class HTTPRequest:
17+
"""
18+
Incoming request, constructed from raw incoming bytes, that is passed as first argument to route handlers.
19+
"""
820

921
method: str
22+
"""Request method e.g. "GET" or "POST"."""
23+
1024
path: str
25+
"""Path of the request."""
26+
1127
query_params: Dict[str, str]
28+
"""
29+
Query/GET parameters in the request.
30+
31+
Example::
32+
33+
request = HTTPRequest(raw_request=b"GET /?foo=bar HTTP/1.1...")
34+
request.query_params
35+
# {"foo": "bar"}
36+
"""
37+
1238
http_version: str
39+
"""HTTP version, e.g. "HTTP/1.1"."""
1340

1441
headers: Dict[str, str]
15-
body: bytes | None
42+
"""Headers from the request."""
43+
44+
body: bytes
45+
"""Body of the request, as bytes."""
1646

1747
raw_request: bytes
48+
"""Raw bytes passed to the constructor."""
1849

19-
def __init__(
20-
self, raw_request: bytes = None
21-
) -> None:
50+
def __init__(self, raw_request: bytes = None) -> None:
2251
self.raw_request = raw_request
2352

24-
if raw_request is None: raise ValueError("raw_request cannot be None")
53+
if raw_request is None:
54+
raise ValueError("raw_request cannot be None")
2555

2656
empty_line_index = raw_request.find(b"\r\n\r\n")
2757

@@ -35,7 +65,6 @@ def __init__(
3565
except Exception as error:
3666
raise ValueError("Unparseable raw_request: ", raw_request) from error
3767

38-
3968
@staticmethod
4069
def _parse_start_line(header_bytes: bytes) -> Tuple[str, str, Dict[str, str], str]:
4170
"""Parse HTTP Start line to method, path, query_params and http_version."""
@@ -44,7 +73,8 @@ def _parse_start_line(header_bytes: bytes) -> Tuple[str, str, Dict[str, str], st
4473

4574
method, path, http_version = start_line.split()
4675

47-
if "?" not in path: path += "?"
76+
if "?" not in path:
77+
path += "?"
4878

4979
path, query_string = path.split("?", 1)
5080

@@ -58,7 +88,6 @@ def _parse_start_line(header_bytes: bytes) -> Tuple[str, str, Dict[str, str], st
5888

5989
return method, path, query_params, http_version
6090

61-
6291
@staticmethod
6392
def _parse_headers(header_bytes: bytes) -> Dict[str, str]:
6493
"""Parse HTTP headers from raw request."""

adafruit_httpserver/response.py

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
`adafruit_httpserver.response.HTTPResponse`
6+
====================================================
7+
* Author(s): Dan Halbert, Michał Pokusa
8+
"""
9+
110
try:
211
from typing import Optional, Dict, Union
312
from socket import socket
13+
from socketpool import SocketPool
414
except ImportError:
515
pass
616

717
from errno import EAGAIN, ECONNRESET
818
import os
919

10-
from socketpool import SocketPool
1120

1221
from .mime_type import MIMEType
1322
from .status import HTTPStatus, CommonHTTPStatus
1423

24+
1525
class HTTPResponse:
1626
"""Details of an HTTP response. Use in `HTTPServer.route` decorator functions."""
1727

@@ -33,7 +43,7 @@ def __init__(
3343
content_type: str = MIMEType.TXT,
3444
filename: Optional[str] = None,
3545
root_path: str = "",
36-
http_version: str = "HTTP/1.1"
46+
http_version: str = "HTTP/1.1",
3747
) -> None:
3848
"""
3949
Creates an HTTP response.
@@ -65,7 +75,7 @@ def _construct_response_bytes(
6575
headers = headers or {}
6676

6777
headers.setdefault("Content-Type", content_type)
68-
headers.setdefault("Content-Length", content_length if content_length is not None else len(body))
78+
headers.setdefault("Content-Length", content_length or len(body))
6979
headers.setdefault("Connection", "close")
7080

7181
for header, value in headers.items():
@@ -75,7 +85,7 @@ def _construct_response_bytes(
7585

7686
return response
7787

78-
def send(self, conn: Union[SocketPool.Socket, socket.socket]) -> None:
88+
def send(self, conn: Union["SocketPool.Socket", "socket.socket"]) -> None:
7989
"""
8090
Send the constructed response over the given socket.
8191
"""
@@ -85,60 +95,60 @@ def send(self, conn: Union[SocketPool.Socket, socket.socket]) -> None:
8595
file_length = os.stat(self.root_path + self.filename)[6]
8696
self._send_file_response(
8797
conn,
88-
filename = self.filename,
89-
root_path = self.root_path,
90-
file_length = file_length,
91-
headers = self.headers,
98+
filename=self.filename,
99+
root_path=self.root_path,
100+
file_length=file_length,
101+
headers=self.headers,
92102
)
93103
except OSError:
94104
self._send_response(
95105
conn,
96-
status = CommonHTTPStatus.NOT_FOUND_404,
97-
content_type = MIMEType.TXT,
98-
body = f"{CommonHTTPStatus.NOT_FOUND_404} {self.filename}",
106+
status=CommonHTTPStatus.NOT_FOUND_404,
107+
content_type=MIMEType.TXT,
108+
body=f"{CommonHTTPStatus.NOT_FOUND_404} {self.filename}",
99109
)
100110
else:
101111
self._send_response(
102112
conn,
103-
status = self.status,
104-
content_type = self.content_type,
105-
headers = self.headers,
106-
body = self.body,
113+
status=self.status,
114+
content_type=self.content_type,
115+
headers=self.headers,
116+
body=self.body,
107117
)
108118

109119
def _send_response(
110120
self,
111-
conn: Union[SocketPool.Socket, socket.socket],
121+
conn: Union["SocketPool.Socket", "socket.socket"],
112122
status: HTTPStatus,
113123
content_type: str,
114124
body: str,
115-
headers: Dict[str, str] = None
125+
headers: Dict[str, str] = None,
116126
):
117127
self._send_bytes(
118128
conn,
119129
self._construct_response_bytes(
120-
status = status,
121-
content_type = content_type,
122-
headers = headers,
123-
body = body,
124-
)
130+
status=status,
131+
content_type=content_type,
132+
headers=headers,
133+
body=body,
134+
),
125135
)
126136

127137
def _send_file_response(
128138
self,
129-
conn: Union[SocketPool.Socket, socket.socket],
139+
conn: Union["SocketPool.Socket", "socket.socket"],
130140
filename: str,
131141
root_path: str,
132142
file_length: int,
133-
headers: Dict[str, str] = None
143+
headers: Dict[str, str] = None,
134144
):
135145
self._send_bytes(
136146
conn,
137147
self._construct_response_bytes(
138-
status = self.status,
139-
content_type = MIMEType.from_file_name(filename),
140-
content_length = file_length,
141-
headers = headers,
148+
status=self.status,
149+
content_type=MIMEType.from_file_name(filename),
150+
content_length=file_length,
151+
headers=headers,
142152
),
143153
)
144154
with open(root_path + filename, "rb") as file:
@@ -147,7 +157,7 @@ def _send_file_response(
147157

148158
@staticmethod
149159
def _send_bytes(
150-
conn: Union[SocketPool.Socket, socket.socket],
160+
conn: Union["SocketPool.Socket", "socket.socket"],
151161
buffer: Union[bytes, bytearray, memoryview],
152162
):
153163
bytes_sent = 0
@@ -157,5 +167,7 @@ def _send_bytes(
157167
try:
158168
bytes_sent += conn.send(view[bytes_sent:])
159169
except OSError as exc:
160-
if exc.errno == EAGAIN: continue
161-
if exc.errno == ECONNRESET: return
170+
if exc.errno == EAGAIN:
171+
continue
172+
if exc.errno == ECONNRESET:
173+
return

adafruit_httpserver/route.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
"""
5+
`adafruit_httpserver.route.HTTPRoute`
6+
====================================================
7+
* Author(s): Dan Halbert, Michał Pokusa
8+
"""
9+
110
from .methods import HTTPMethod
211

312

4-
class HTTPRoute:
5-
def __init__(
6-
self,
7-
path: str = "",
8-
method: HTTPMethod = HTTPMethod.GET
9-
) -> None:
13+
class _HTTPRoute:
14+
"""Route definition for different paths, see `HTTPServer.route`."""
15+
16+
def __init__(self, path: str = "", method: HTTPMethod = HTTPMethod.GET) -> None:
1017

1118
self.path = path
1219
self.method = method
1320

1421
def __hash__(self) -> int:
1522
return hash(self.method) ^ hash(self.path)
1623

17-
def __eq__(self, other: "HTTPRoute") -> bool:
24+
def __eq__(self, other: "_HTTPRoute") -> bool:
1825
return self.method == other.method and self.path == other.path
1926

2027
def __repr__(self) -> str:

0 commit comments

Comments
 (0)