soia-client 1.0.27__tar.gz → 1.0.28__tar.gz
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_client-1.0.27 → soia_client-1.0.28}/PKG-INFO +1 -1
- {soia_client-1.0.27 → soia_client-1.0.28}/pyproject.toml +1 -1
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/enums.py +3 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/service.py +111 -39
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/service_client.py +1 -1
- {soia_client-1.0.27 → soia_client-1.0.28}/soia_client.egg-info/PKG-INFO +1 -1
- {soia_client-1.0.27 → soia_client-1.0.28}/tests/test_module_initializer.py +5 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/LICENSE +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/README.md +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/setup.cfg +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/__init__.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/__init__.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/arrays.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/function_maker.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/keyed_items.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/method.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/never.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/optionals.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/primitives.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/repr.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/serializer.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/serializers.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/structs.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/timestamp.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_impl/type_adapter.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_module_initializer.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/_spec.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia/reflection.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia_client.egg-info/SOURCES.txt +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia_client.egg-info/dependency_links.txt +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/soia_client.egg-info/top_level.txt +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/tests/test_serializers.py +0 -0
- {soia_client-1.0.27 → soia_client-1.0.28}/tests/test_timestamp.py +0 -0
|
@@ -41,6 +41,9 @@ class EnumAdapter(TypeAdapter):
|
|
|
41
41
|
constant = constant_class()
|
|
42
42
|
setattr(base_class, constant_field.attribute, constant)
|
|
43
43
|
|
|
44
|
+
# Add the Kind type alias.
|
|
45
|
+
setattr(base_class, "Kind", str)
|
|
46
|
+
|
|
44
47
|
def finalize(
|
|
45
48
|
self,
|
|
46
49
|
resolve_type_fn: Callable[[_spec.Type], TypeAdapter],
|
|
@@ -5,6 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from typing import Any, Generic, Literal, TypeVar, Union, cast
|
|
6
6
|
|
|
7
7
|
from soia._impl.method import Method, Request, Response
|
|
8
|
+
from soia._impl.never import Never
|
|
8
9
|
|
|
9
10
|
RequestHeaders = TypeVar("RequestHeaders")
|
|
10
11
|
|
|
@@ -90,42 +91,84 @@ class _HandleRequestFlow(Generic[Request, Response, RequestHeaders, ResponseHead
|
|
|
90
91
|
tuple[Any, _MethodImpl[Request, Response, RequestHeaders, ResponseHeaders]],
|
|
91
92
|
RawServiceResponse,
|
|
92
93
|
]:
|
|
93
|
-
if self.req_body
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
)
|
|
94
|
+
if self.req_body in ["", "list"]:
|
|
95
|
+
return self._handle_list()
|
|
96
|
+
|
|
97
|
+
# Method invokation
|
|
98
|
+
method_name: str
|
|
99
|
+
method_number: int | None
|
|
100
|
+
format: str
|
|
101
|
+
request_data: tuple[Literal["json-code"], str] | tuple[Literal["json"], Any]
|
|
102
|
+
|
|
103
|
+
first_char = self.req_body[0]
|
|
104
|
+
if first_char.isspace() or first_char == "{":
|
|
105
|
+
# A JSON object
|
|
106
|
+
try:
|
|
107
|
+
req_body_json = json.loads(self.req_body)
|
|
108
|
+
except json.JSONDecodeError:
|
|
109
|
+
return RawServiceResponse(
|
|
110
|
+
"bad request: invalid JSON", "bad-request"
|
|
111
|
+
)
|
|
112
|
+
method = req_body_json.get("method", ())
|
|
113
|
+
if method == ():
|
|
114
|
+
return RawServiceResponse(
|
|
115
|
+
"bad request: missing 'method' field in JSON", "bad-request"
|
|
116
|
+
)
|
|
117
|
+
if isinstance(method, str):
|
|
118
|
+
method_name = method
|
|
119
|
+
method_number = None
|
|
120
|
+
elif isinstance(method, int):
|
|
121
|
+
method_name = "?"
|
|
122
|
+
method_number = method
|
|
123
|
+
else:
|
|
124
|
+
return RawServiceResponse(
|
|
125
|
+
"bad request: 'method' field must be a string or an integer",
|
|
126
|
+
"bad-request",
|
|
127
|
+
)
|
|
128
|
+
format = "readable"
|
|
129
|
+
data = req_body_json.get("request", ())
|
|
130
|
+
if data == ():
|
|
131
|
+
return RawServiceResponse(
|
|
132
|
+
"bad request: missing 'request' field in JSON", "bad-request"
|
|
133
|
+
)
|
|
134
|
+
request_data = ("json", data)
|
|
135
|
+
else:
|
|
136
|
+
# A colon-separated string
|
|
137
|
+
parts = self.req_body.split(":", 3)
|
|
138
|
+
if len(parts) != 4:
|
|
139
|
+
return RawServiceResponse(
|
|
140
|
+
"bad request: invalid request format", "bad-request"
|
|
141
|
+
)
|
|
142
|
+
method_name = parts[0]
|
|
143
|
+
method_number_str = parts[1]
|
|
144
|
+
format = parts[2]
|
|
145
|
+
request_data = ("json-code", parts[3])
|
|
146
|
+
if method_number_str:
|
|
147
|
+
try:
|
|
148
|
+
method_number = int(method_number_str)
|
|
149
|
+
except Exception:
|
|
150
|
+
return RawServiceResponse(
|
|
151
|
+
"bad request: can't parse method number", "bad-request"
|
|
152
|
+
)
|
|
153
|
+
else:
|
|
154
|
+
method_number = None
|
|
155
|
+
self.format = format
|
|
156
|
+
if method_number is None:
|
|
157
|
+
# Try to get the method number by name
|
|
158
|
+
all_methods = self.number_to_method_impl.values()
|
|
159
|
+
name_matches = [m for m in all_methods if m.method.name == method_name]
|
|
160
|
+
if not name_matches:
|
|
161
|
+
return RawServiceResponse(
|
|
162
|
+
f"bad request: method not found: {method_name}",
|
|
163
|
+
"bad-request",
|
|
164
|
+
)
|
|
165
|
+
elif len(name_matches) != 1:
|
|
166
|
+
return RawServiceResponse(
|
|
167
|
+
f"bad request: method name '{method_name}' is ambiguous; "
|
|
168
|
+
"use method number instead",
|
|
169
|
+
"bad-request",
|
|
170
|
+
)
|
|
171
|
+
method_number = name_matches[0].method.number
|
|
129
172
|
method_impl = self.number_to_method_impl.get(method_number)
|
|
130
173
|
if not method_impl:
|
|
131
174
|
return RawServiceResponse(
|
|
@@ -133,15 +176,44 @@ class _HandleRequestFlow(Generic[Request, Response, RequestHeaders, ResponseHead
|
|
|
133
176
|
"bad-request",
|
|
134
177
|
)
|
|
135
178
|
try:
|
|
136
|
-
req: Any
|
|
137
|
-
|
|
138
|
-
|
|
179
|
+
req: Any
|
|
180
|
+
if request_data[0] == "json-code":
|
|
181
|
+
req = method_impl.method.request_serializer.from_json_code(
|
|
182
|
+
request_data
|
|
183
|
+
)
|
|
184
|
+
elif request_data[0] == "json":
|
|
185
|
+
req = method_impl.method.request_serializer.from_json(
|
|
186
|
+
request_data
|
|
187
|
+
)
|
|
188
|
+
else:
|
|
189
|
+
_: Never = request_data[0]
|
|
190
|
+
del _
|
|
139
191
|
except Exception as e:
|
|
140
192
|
return RawServiceResponse(
|
|
141
193
|
f"bad request: can't parse JSON: {e}", "bad-request"
|
|
142
194
|
)
|
|
143
195
|
return (req, method_impl)
|
|
144
196
|
|
|
197
|
+
def _handle_list(self) -> RawServiceResponse:
|
|
198
|
+
def method_to_json(method: Method) -> Any:
|
|
199
|
+
return {
|
|
200
|
+
"method": method.name,
|
|
201
|
+
"number": method.number,
|
|
202
|
+
"request": method.request_serializer.type_descriptor.as_json(),
|
|
203
|
+
"response": method.response_serializer.type_descriptor.as_json(),
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
json_code = json.dumps(
|
|
207
|
+
{
|
|
208
|
+
"methods": [
|
|
209
|
+
method_to_json(method_impl.method)
|
|
210
|
+
for method_impl in self.number_to_method_impl.values()
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
indent=2,
|
|
214
|
+
)
|
|
215
|
+
return RawServiceResponse(json_code, "ok-json")
|
|
216
|
+
|
|
145
217
|
def _response_to_json(
|
|
146
218
|
self,
|
|
147
219
|
res: Response,
|
|
@@ -702,6 +702,11 @@ class ModuleInitializerTestCase(unittest.TestCase):
|
|
|
702
702
|
{"kind": "error", "value": "An error occurred"},
|
|
703
703
|
)
|
|
704
704
|
|
|
705
|
+
def test_enum_kind(self):
|
|
706
|
+
module = self.init_test_module()
|
|
707
|
+
primary_color_cls = module["Status"]
|
|
708
|
+
self.assertEqual(primary_color_cls.Kind, str)
|
|
709
|
+
|
|
705
710
|
def test_enum_wrap_around_mutable_struct(self):
|
|
706
711
|
module = self.init_test_module()
|
|
707
712
|
json_value_cls = module["JsonValue"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|