soia-client 1.0.17__py3-none-any.whl → 1.0.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- soia/_impl/service.py +16 -12
- soia/_impl/service_client.py +4 -3
- {soia_client-1.0.17.dist-info → soia_client-1.0.19.dist-info}/METADATA +1 -1
- {soia_client-1.0.17.dist-info → soia_client-1.0.19.dist-info}/RECORD +7 -7
- {soia_client-1.0.17.dist-info → soia_client-1.0.19.dist-info}/WHEEL +0 -0
- {soia_client-1.0.17.dist-info → soia_client-1.0.19.dist-info}/licenses/LICENSE +0 -0
- {soia_client-1.0.17.dist-info → soia_client-1.0.19.dist-info}/top_level.txt +0 -0
soia/_impl/service.py
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
import inspect
|
2
2
|
import json
|
3
|
+
from collections.abc import Mapping
|
3
4
|
from dataclasses import dataclass
|
4
|
-
from typing import Any, Callable, Generic, Literal,
|
5
|
+
from typing import Any, Callable, Generic, Literal, TypeAlias, Union, cast
|
5
6
|
|
6
7
|
from soia._impl.method import Method, Request, Response
|
7
8
|
|
8
|
-
|
9
|
-
class RequestHeaders(Protocol):
|
10
|
-
def __getitem__(self, key: str, /) -> str | None: ...
|
9
|
+
RequestHeaders: TypeAlias = Mapping[str, str]
|
11
10
|
|
12
11
|
|
13
12
|
ResponseHeaders: TypeAlias = dict[str, str]
|
@@ -18,27 +17,31 @@ class Service:
|
|
18
17
|
|
19
18
|
Usage: call '.add_method()' to register method implementations, then call
|
20
19
|
'.handle_request()' from the function called by your web framework when an
|
21
|
-
HTTP request is
|
20
|
+
HTTP request is received at your service's endpoint.
|
22
21
|
|
23
22
|
Example with Flask:
|
24
23
|
|
25
24
|
from flask import Response, request
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
s = soia.Service()
|
27
|
+
s.add_method(...)
|
28
|
+
s.add_method(...)
|
30
29
|
|
31
30
|
@app.route("/myapi", methods=["GET", "POST"])
|
32
31
|
def myapi():
|
33
32
|
if request.method == "POST":
|
34
33
|
req_body = request.get_data(as_text=True)
|
35
34
|
else:
|
36
|
-
|
37
|
-
|
35
|
+
query_string = request.query_string.decode("utf-8")
|
36
|
+
req_body = urllib.parse.unquote(query_string)
|
37
|
+
req_headers = dict(request.headers)
|
38
|
+
res_headers: dict[str, str] = {}
|
39
|
+
raw_response = s.handle_request(req_body, req_headers, res_headers)
|
38
40
|
return Response(
|
39
41
|
raw_response.data,
|
40
42
|
status=raw_response.status_code,
|
41
43
|
content_type=raw_response.content_type,
|
44
|
+
headers=res_headers,
|
42
45
|
)
|
43
46
|
"""
|
44
47
|
|
@@ -125,7 +128,7 @@ class Service:
|
|
125
128
|
self,
|
126
129
|
req_body: str,
|
127
130
|
req_headers: RequestHeaders,
|
128
|
-
res_headers: ResponseHeaders
|
131
|
+
res_headers: ResponseHeaders,
|
129
132
|
) -> RawResponse:
|
130
133
|
if req_body == "list":
|
131
134
|
|
@@ -179,8 +182,9 @@ class Service:
|
|
179
182
|
f"bad request: can't parse JSON: {e}", "bad-request"
|
180
183
|
)
|
181
184
|
|
185
|
+
res_headers.clear()
|
182
186
|
try:
|
183
|
-
res: Any = method_impl.impl(req, req_headers, res_headers
|
187
|
+
res: Any = method_impl.impl(req, req_headers, res_headers)
|
184
188
|
except Exception as e:
|
185
189
|
return self.RawResponse(f"server error: {e}", "server-error")
|
186
190
|
|
soia/_impl/service_client.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import http.client
|
2
|
+
import re
|
2
3
|
from typing import Any, Final, Mapping
|
3
4
|
from urllib.parse import urlparse
|
4
5
|
|
@@ -65,14 +66,14 @@ class ServiceClient:
|
|
65
66
|
res_headers.clear()
|
66
67
|
res_headers.extend(response.getheaders())
|
67
68
|
status_code = response.status
|
68
|
-
content_type = response.getheader("Content-Type")
|
69
|
+
content_type = response.getheader("Content-Type") or ""
|
69
70
|
response_data = response.read().decode("utf-8", errors="ignore")
|
70
71
|
finally:
|
71
72
|
conn.close()
|
72
73
|
if status_code in range(200, 300):
|
73
74
|
return method.response_serializer.from_json_code(response_data)
|
74
75
|
else:
|
75
|
-
message = f"HTTP
|
76
|
-
if
|
76
|
+
message = f"HTTP status {status_code}"
|
77
|
+
if re.match(r"text/plain\b", content_type):
|
77
78
|
message = f"{message}: {response_data}"
|
78
79
|
raise RuntimeError(message)
|
@@ -14,13 +14,13 @@ soia/_impl/primitives.py,sha256=Xk26Fv4oQG2oXd3tS_2sAnJYQdXYX9nva09713AcJvs,8940
|
|
14
14
|
soia/_impl/repr.py,sha256=7WX0bEAVENTjlyZIcbT8TcJylS7IRIyafGCmqaIMxFM,1413
|
15
15
|
soia/_impl/serializer.py,sha256=28IwkjtUnLpbnPQfVNfJXkApCK4JhXHwLkC5MVhF8xo,3529
|
16
16
|
soia/_impl/serializers.py,sha256=IL9jHHMo11pgrL1-crarOEElvTyV5YM6FTcgumjW6IU,2564
|
17
|
-
soia/_impl/service.py,sha256=
|
18
|
-
soia/_impl/service_client.py,sha256=
|
17
|
+
soia/_impl/service.py,sha256=U9sZGJIc2cnVedRnPmneVrGwxll6hFUn9s-RA6bjoDs,7167
|
18
|
+
soia/_impl/service_client.py,sha256=qDntwRyXfLsmXl4ELfOkh-fgv553nrGy72K0JghLM80,2734
|
19
19
|
soia/_impl/structs.py,sha256=YTc3Ykj2TxPquar2XsP2DhFfkfIoELXOveyd8yTqN90,26545
|
20
20
|
soia/_impl/timestamp.py,sha256=lXBNH8mPmzflkNjSKZSBl2XS-ot9N8N92B_zGO2SMtU,4078
|
21
21
|
soia/_impl/type_adapter.py,sha256=RyIyh4Fnt9rMy0HRzC-a2v2JAdZsV9FBzoGEUVygVRE,2101
|
22
|
-
soia_client-1.0.
|
23
|
-
soia_client-1.0.
|
24
|
-
soia_client-1.0.
|
25
|
-
soia_client-1.0.
|
26
|
-
soia_client-1.0.
|
22
|
+
soia_client-1.0.19.dist-info/licenses/LICENSE,sha256=SaAftKkX6hfSOiPdENQPS70tifH3PDHgazq8eK2Pwfw,1064
|
23
|
+
soia_client-1.0.19.dist-info/METADATA,sha256=m0ufOfdKiNFEFbINu3oTina-9nafNUtugdhXzzFkIMk,1667
|
24
|
+
soia_client-1.0.19.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
25
|
+
soia_client-1.0.19.dist-info/top_level.txt,sha256=lsYG9JrvauFe1oIV5zvnwsS9hsx3ztwfK_937op9mxc,5
|
26
|
+
soia_client-1.0.19.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|