Skip to content

Commit 8302eb5

Browse files
Add Method and value checking.
1 parent 16ab11d commit 8302eb5

File tree

14 files changed

+82
-50
lines changed

14 files changed

+82
-50
lines changed

src/ahttpx/__init__.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ._pool import * # Connection, ConnectionPool, Transport
88
from ._quickstart import * # get, post, put, patch, delete
99
from ._response import * # Response
10-
from ._request import * # Request
10+
from ._request import * # Method, Request
1111
from ._streams import * # ByteStream, DuplexStream, FileStream, Stream
1212
from ._server import * # serve_http, run
1313
from ._urlencode import * # quote, unquote, urldecode, urlencode
@@ -34,6 +34,7 @@
3434
"HTTPParser",
3535
"HTTPStream",
3636
"JSON",
37+
"Method",
3738
"MultiPart",
3839
"NetworkBackend",
3940
"NetworkStream",
@@ -57,9 +58,3 @@
5758
"urldecode",
5859
"urlencode",
5960
]
60-
61-
62-
__locals = locals()
63-
for __name in __all__:
64-
if not __name.startswith('__'):
65-
setattr(__locals[__name], "__module__", "httpx")

src/ahttpx/_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from ._content import Content
55
from ._headers import Headers
66
from ._pool import ConnectionPool, Transport
7-
from ._request import Request
7+
from ._request import Method, Request
88
from ._response import Response
99
from ._streams import Stream
1010
from ._urls import URL
@@ -33,7 +33,7 @@ def __init__(
3333

3434
def build_request(
3535
self,
36-
method: str,
36+
method: Method | str,
3737
url: URL | str,
3838
headers: Headers | typing.Mapping[str, str] | None = None,
3939
content: Content | Stream | bytes | None = None,
@@ -47,7 +47,7 @@ def build_request(
4747

4848
async def request(
4949
self,
50-
method: str,
50+
method: Method | str,
5151
url: URL | str,
5252
headers: Headers | typing.Mapping[str, str] | None = None,
5353
content: Content | Stream | bytes | None = None,
@@ -59,7 +59,7 @@ async def request(
5959

6060
async def stream(
6161
self,
62-
method: str,
62+
method: Method | str,
6363
url: URL | str,
6464
headers: Headers | typing.Mapping[str, str] | None = None,
6565
content: Content | Stream | bytes | None = None,

src/ahttpx/_pool.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ._network import Lock, NetworkBackend, Semaphore
88
from ._parsers import HTTPParser, HTTPStream
99
from ._response import Response
10-
from ._request import Request
10+
from ._request import Method, Request
1111
from ._streams import Stream
1212
from ._urls import URL
1313

@@ -29,7 +29,7 @@ async def close(self):
2929

3030
async def request(
3131
self,
32-
method: str,
32+
method: Method | str,
3333
url: URL | str,
3434
headers: Headers | dict[str, str] | None = None,
3535
content: Content | Stream | bytes | None = None,
@@ -41,7 +41,7 @@ async def request(
4141

4242
async def stream(
4343
self,
44-
method: str,
44+
method: Method | str,
4545
url: URL | str,
4646
headers: Headers | dict[str, str] | None = None,
4747
content: Content | Stream | bytes | None = None,
@@ -141,7 +141,7 @@ async def __aexit__(
141141
class Connection(Transport):
142142
def __init__(self, stream: Stream, origin: URL | str):
143143
self._stream = stream
144-
self._origin = URL(origin)
144+
self._origin = URL(origin) if not isinstance(origin, URL) else origin
145145
self._keepalive_duration = 5.0
146146
self._idle_expiry = time.monotonic() + self._keepalive_duration
147147
self._request_lock = Lock()
@@ -183,7 +183,7 @@ async def close(self) -> None:
183183
# Top-level API for working directly with a connection.
184184
async def request(
185185
self,
186-
method: str,
186+
method: Method | str,
187187
url: URL | str,
188188
headers: Headers | typing.Mapping[str, str] | None = None,
189189
content: Content | Stream | bytes | None = None,
@@ -196,7 +196,7 @@ async def request(
196196

197197
async def stream(
198198
self,
199-
method: str,
199+
method: Method | str,
200200
url: URL | str,
201201
headers: Headers | typing.Mapping[str, str] | None = None,
202202
content: Content | Stream | bytes | None = None,
@@ -207,7 +207,7 @@ async def stream(
207207

208208
# Send the request...
209209
async def _send_head(self, request: Request) -> None:
210-
method = request.method.encode('ascii')
210+
method = bytes(request.method)
211211
target = request.url.target.encode('ascii')
212212
protocol = b'HTTP/1.1'
213213
await self._parser.send_method_line(method, target, protocol)

src/ahttpx/_request.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,38 @@
99
__all__ = ["Request"]
1010

1111

12+
class Method:
13+
def __init__(self, method: str, standard=True):
14+
if standard:
15+
method = method.upper()
16+
if method not in ("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"):
17+
raise ValueError("Non-standard method {method!r}")
18+
self._method = method
19+
20+
def __eq__(self, other) -> bool:
21+
return str(self) == str(other)
22+
23+
def __bytes__(self) -> bytes:
24+
return self._method.encode('ascii')
25+
26+
def __str__(self) -> str:
27+
return self._method
28+
29+
def __repr__(self):
30+
return "<Method {self._method}>"
31+
32+
1233
class Request:
1334
def __init__(
1435
self,
15-
method: str,
36+
method: Method | str,
1637
url: URL | str,
1738
headers: Headers | typing.Mapping[str, str] | None = None,
1839
content: Content | Stream | bytes | None = None,
1940
):
20-
self.method = method
21-
self.url = URL(url)
22-
self.headers = Headers(headers)
41+
self.method = Method(method) if not isinstance(method, Method) else method
42+
self.url = URL(url) if not isinstance(url, URL) else url
43+
self.headers = Headers(headers) if not isinstance(headers, Headers) else headers
2344
self.stream: Stream = ByteStream(b"")
2445

2546
# https://datatracker.ietf.org/doc/html/rfc2616#section-14.23

src/ahttpx/_response.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def __init__(
8585
content: Content | Stream | bytes | None = None,
8686
):
8787
self.status_code = status_code
88-
self.headers = Headers(headers)
88+
self.headers = Headers(headers) if not isinstance(headers, Headers) else headers
8989
self.stream: Stream = ByteStream(b"")
9090

9191
if content is not None:

src/httpx/__init__.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ._pool import * # Connection, ConnectionPool, Transport
88
from ._quickstart import * # get, post, put, patch, delete
99
from ._response import * # Response
10-
from ._request import * # Request
10+
from ._request import * # Method, Request
1111
from ._streams import * # ByteStream, DuplexStream, FileStream, Stream
1212
from ._server import * # serve_http, run
1313
from ._urlencode import * # quote, unquote, urldecode, urlencode
@@ -34,6 +34,7 @@
3434
"HTTPParser",
3535
"HTTPStream",
3636
"JSON",
37+
"Method",
3738
"MultiPart",
3839
"NetworkBackend",
3940
"NetworkStream",
@@ -57,9 +58,3 @@
5758
"urldecode",
5859
"urlencode",
5960
]
60-
61-
62-
__locals = locals()
63-
for __name in __all__:
64-
if not __name.startswith('__'):
65-
setattr(__locals[__name], "__module__", "httpx")

src/httpx/_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from ._content import Content
55
from ._headers import Headers
66
from ._pool import ConnectionPool, Transport
7-
from ._request import Request
7+
from ._request import Method, Request
88
from ._response import Response
99
from ._streams import Stream
1010
from ._urls import URL
@@ -33,7 +33,7 @@ def __init__(
3333

3434
def build_request(
3535
self,
36-
method: str,
36+
method: Method | str,
3737
url: URL | str,
3838
headers: Headers | typing.Mapping[str, str] | None = None,
3939
content: Content | Stream | bytes | None = None,
@@ -47,7 +47,7 @@ def build_request(
4747

4848
def request(
4949
self,
50-
method: str,
50+
method: Method | str,
5151
url: URL | str,
5252
headers: Headers | typing.Mapping[str, str] | None = None,
5353
content: Content | Stream | bytes | None = None,
@@ -59,7 +59,7 @@ def request(
5959

6060
def stream(
6161
self,
62-
method: str,
62+
method: Method | str,
6363
url: URL | str,
6464
headers: Headers | typing.Mapping[str, str] | None = None,
6565
content: Content | Stream | bytes | None = None,

src/httpx/_pool.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ._network import Lock, NetworkBackend, Semaphore
88
from ._parsers import HTTPParser, HTTPStream
99
from ._response import Response
10-
from ._request import Request
10+
from ._request import Method, Request
1111
from ._streams import Stream
1212
from ._urls import URL
1313

@@ -29,7 +29,7 @@ def close(self):
2929

3030
def request(
3131
self,
32-
method: str,
32+
method: Method | str,
3333
url: URL | str,
3434
headers: Headers | dict[str, str] | None = None,
3535
content: Content | Stream | bytes | None = None,
@@ -41,7 +41,7 @@ def request(
4141

4242
def stream(
4343
self,
44-
method: str,
44+
method: Method | str,
4545
url: URL | str,
4646
headers: Headers | dict[str, str] | None = None,
4747
content: Content | Stream | bytes | None = None,
@@ -141,7 +141,7 @@ def __exit__(
141141
class Connection(Transport):
142142
def __init__(self, stream: Stream, origin: URL | str):
143143
self._stream = stream
144-
self._origin = URL(origin)
144+
self._origin = URL(origin) if not isinstance(origin, URL) else origin
145145
self._keepalive_duration = 5.0
146146
self._idle_expiry = time.monotonic() + self._keepalive_duration
147147
self._request_lock = Lock()
@@ -183,7 +183,7 @@ def close(self) -> None:
183183
# Top-level API for working directly with a connection.
184184
def request(
185185
self,
186-
method: str,
186+
method: Method | str,
187187
url: URL | str,
188188
headers: Headers | typing.Mapping[str, str] | None = None,
189189
content: Content | Stream | bytes | None = None,
@@ -196,7 +196,7 @@ def request(
196196

197197
def stream(
198198
self,
199-
method: str,
199+
method: Method | str,
200200
url: URL | str,
201201
headers: Headers | typing.Mapping[str, str] | None = None,
202202
content: Content | Stream | bytes | None = None,
@@ -207,7 +207,7 @@ def stream(
207207

208208
# Send the request...
209209
def _send_head(self, request: Request) -> None:
210-
method = request.method.encode('ascii')
210+
method = bytes(request.method)
211211
target = request.url.target.encode('ascii')
212212
protocol = b'HTTP/1.1'
213213
self._parser.send_method_line(method, target, protocol)

src/httpx/_request.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,38 @@
99
__all__ = ["Request"]
1010

1111

12+
class Method:
13+
def __init__(self, method: str, standard=True):
14+
if standard:
15+
method = method.upper()
16+
if method not in ("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"):
17+
raise ValueError("Non-standard method {method!r}")
18+
self._method = method
19+
20+
def __eq__(self, other) -> bool:
21+
return str(self) == str(other)
22+
23+
def __bytes__(self) -> bytes:
24+
return self._method.encode('ascii')
25+
26+
def __str__(self) -> str:
27+
return self._method
28+
29+
def __repr__(self):
30+
return "<Method {self._method}>"
31+
32+
1233
class Request:
1334
def __init__(
1435
self,
15-
method: str,
36+
method: Method | str,
1637
url: URL | str,
1738
headers: Headers | typing.Mapping[str, str] | None = None,
1839
content: Content | Stream | bytes | None = None,
1940
):
20-
self.method = method
21-
self.url = URL(url)
22-
self.headers = Headers(headers)
41+
self.method = Method(method) if not isinstance(method, Method) else method
42+
self.url = URL(url) if not isinstance(url, URL) else url
43+
self.headers = Headers(headers) if not isinstance(headers, Headers) else headers
2344
self.stream: Stream = ByteStream(b"")
2445

2546
# https://datatracker.ietf.org/doc/html/rfc2616#section-14.23

src/httpx/_response.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def __init__(
8585
content: Content | Stream | bytes | None = None,
8686
):
8787
self.status_code = status_code
88-
self.headers = Headers(headers)
88+
self.headers = Headers(headers) if not isinstance(headers, Headers) else headers
8989
self.stream: Stream = ByteStream(b"")
9090

9191
if content is not None:

0 commit comments

Comments
 (0)