soia-client 1.1.1__tar.gz → 1.1.3__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.

Potentially problematic release.


This version of soia-client might be problematic. Click here for more details.

Files changed (34) hide show
  1. {soia_client-1.1.1 → soia_client-1.1.3}/PKG-INFO +1 -1
  2. {soia_client-1.1.1 → soia_client-1.1.3}/pyproject.toml +1 -1
  3. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/enums.py +8 -2
  4. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/service.py +29 -2
  5. {soia_client-1.1.1 → soia_client-1.1.3}/soia/reflection.py +29 -4
  6. {soia_client-1.1.1 → soia_client-1.1.3}/soia_client.egg-info/PKG-INFO +1 -1
  7. {soia_client-1.1.1 → soia_client-1.1.3}/tests/test_module_initializer.py +5 -2
  8. {soia_client-1.1.1 → soia_client-1.1.3}/LICENSE +0 -0
  9. {soia_client-1.1.1 → soia_client-1.1.3}/README.md +0 -0
  10. {soia_client-1.1.1 → soia_client-1.1.3}/setup.cfg +0 -0
  11. {soia_client-1.1.1 → soia_client-1.1.3}/soia/__init__.py +0 -0
  12. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/__init__.py +0 -0
  13. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/arrays.py +0 -0
  14. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/function_maker.py +0 -0
  15. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/keep.py +0 -0
  16. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/keyed_items.py +0 -0
  17. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/method.py +0 -0
  18. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/never.py +0 -0
  19. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/optionals.py +0 -0
  20. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/primitives.py +0 -0
  21. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/repr.py +0 -0
  22. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/serializer.py +0 -0
  23. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/serializers.py +0 -0
  24. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/service_client.py +0 -0
  25. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/structs.py +0 -0
  26. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/timestamp.py +0 -0
  27. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_impl/type_adapter.py +0 -0
  28. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_module_initializer.py +0 -0
  29. {soia_client-1.1.1 → soia_client-1.1.3}/soia/_spec.py +0 -0
  30. {soia_client-1.1.1 → soia_client-1.1.3}/soia_client.egg-info/SOURCES.txt +0 -0
  31. {soia_client-1.1.1 → soia_client-1.1.3}/soia_client.egg-info/dependency_links.txt +0 -0
  32. {soia_client-1.1.1 → soia_client-1.1.3}/soia_client.egg-info/top_level.txt +0 -0
  33. {soia_client-1.1.1 → soia_client-1.1.3}/tests/test_serializers.py +0 -0
  34. {soia_client-1.1.1 → soia_client-1.1.3}/tests/test_timestamp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soia-client
3
- Version: 1.1.1
3
+ Version: 1.1.3
4
4
  Author-email: Tyler Fibonacci <gepheum@gmail.com>
5
5
  License: MIT License
6
6
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "soia-client"
7
- version = "1.1.1"
7
+ version = "1.1.3"
8
8
  description = ""
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Tyler Fibonacci", email = "gepheum@gmail.com" }]
@@ -3,12 +3,11 @@ from collections.abc import Callable, Sequence
3
3
  from dataclasses import FrozenInstanceError, dataclass
4
4
  from typing import Any, Final, Union
5
5
 
6
+ from soia import _spec, reflection
6
7
  from soia._impl.function_maker import BodyBuilder, Expr, ExprLike, Line, make_function
7
8
  from soia._impl.repr import repr_impl
8
9
  from soia._impl.type_adapter import TypeAdapter
9
10
 
10
- from soia import _spec, reflection
11
-
12
11
 
13
12
  class EnumAdapter(TypeAdapter):
14
13
  __slots__ = (
@@ -139,6 +138,13 @@ class EnumAdapter(TypeAdapter):
139
138
  kind="enum",
140
139
  id=record_id,
141
140
  fields=tuple(
141
+ reflection.Field(
142
+ name=field.name,
143
+ number=field.number,
144
+ type=None,
145
+ )
146
+ for field in self.all_constant_fields if field.number != 0
147
+ ) + tuple(
142
148
  reflection.Field(
143
149
  name=field.spec.name,
144
150
  number=field.spec.number,
@@ -26,29 +26,50 @@ class _MethodImpl(Generic[Request, Response, RequestHeaders, ResponseHeaders]):
26
26
  @dataclass(frozen=True)
27
27
  class RawServiceResponse:
28
28
  data: str
29
- type: Literal["ok-json", "bad-request", "server-error"]
29
+ type: Literal["ok-json", "ok-html", "bad-request", "server-error"]
30
30
 
31
31
  @property
32
32
  def status_code(self):
33
- if self.type == "ok-json":
33
+ if self.type == "ok-json" or self.type == "ok-html":
34
34
  return 200
35
35
  elif self.type == "bad-request":
36
36
  return 400
37
37
  elif self.type == "server-error":
38
38
  return 500
39
39
  else:
40
+ _: Never = self.type
40
41
  raise TypeError(f"Unknown response type: {self.type}")
41
42
 
42
43
  @property
43
44
  def content_type(self):
44
45
  if self.type == "ok-json":
45
46
  return "application/json"
47
+ if self.type == "ok-html":
48
+ return "text/html; charset=utf-8"
46
49
  elif self.type == "bad-request" or self.type == "server-error":
47
50
  return "text/plain; charset=utf-8"
48
51
  else:
52
+ _: Never = self.type
49
53
  raise TypeError(f"Unknown response type: {self.type}")
50
54
 
51
55
 
56
+ # Copied from
57
+ # https://github.com/gepheum/restudio/blob/main/index.jsdeliver.html
58
+ _RESTUDIO_HTML = """<!DOCTYPE html>
59
+
60
+ <html>
61
+ <head>
62
+ <meta charset="utf-8" />
63
+ <title>RESTudio</title>
64
+ <script src="dist/restudio-standalone.js"></script>
65
+ </head>
66
+ <body style="margin: 0; padding: 0;">
67
+ <restudio-app></restudio-app>
68
+ </body>
69
+ </html>
70
+ """
71
+
72
+
52
73
  @dataclass()
53
74
  class _HandleRequestFlow(Generic[Request, Response, RequestHeaders, ResponseHeaders]):
54
75
  req_body: str
@@ -94,6 +115,9 @@ class _HandleRequestFlow(Generic[Request, Response, RequestHeaders, ResponseHead
94
115
  if self.req_body in ["", "list"]:
95
116
  return self._handle_list()
96
117
 
118
+ if self.req_body == "restudio":
119
+ return self._handle_restudio()
120
+
97
121
  # Method invokation
98
122
  method_name: str
99
123
  method_number: int | None
@@ -211,6 +235,9 @@ class _HandleRequestFlow(Generic[Request, Response, RequestHeaders, ResponseHead
211
235
  )
212
236
  return RawServiceResponse(json_code, "ok-json")
213
237
 
238
+ def _handle_restudio(self) -> RawServiceResponse:
239
+ return RawServiceResponse(_RESTUDIO_HTML, "ok-html")
240
+
214
241
  def _response_to_json(
215
242
  self,
216
243
  res: Response,
@@ -109,11 +109,19 @@ class _Serializer(Generic[_T]):
109
109
  from_json: Callable[[Any], _T]
110
110
 
111
111
 
112
+ @dataclass(frozen=True, eq=True)
113
+ class _NoDefault:
114
+ pass
115
+
116
+
117
+ _NO_DEFAULT: Final = _NoDefault()
118
+
119
+
112
120
  @dataclass(frozen=True)
113
121
  class _FieldSerializer(Generic[_T]):
114
122
  name: str
115
123
  serializer: _Serializer[_T]
116
- default: Optional[_T] = None
124
+ default: _T | _NoDefault = _NO_DEFAULT
117
125
 
118
126
 
119
127
  def _primitive_serializer(check_type_fn: Callable[[Any], _T]) -> _Serializer[_T]:
@@ -144,7 +152,7 @@ def _dataclass_serializer(
144
152
  def field_from_json(field: _FieldSerializer) -> Any:
145
153
  value_json = json.get(field.name)
146
154
  if value_json is None:
147
- if field.default is not None:
155
+ if field.default != _NO_DEFAULT:
148
156
  return field.default
149
157
  else:
150
158
  # Will raise an exception.
@@ -196,6 +204,22 @@ def _forwarding_serializer(
196
204
  return _Serializer(to_json, from_json)
197
205
 
198
206
 
207
+ def _optional_serializer(
208
+ other_serializer: _Serializer[_T],
209
+ ) -> _Serializer[Optional[_T]]:
210
+ def to_json(input: Optional[_T]) -> Any:
211
+ if input is None:
212
+ return None
213
+ return other_serializer.to_json(input)
214
+
215
+ def from_json(json: Any) -> Optional[_T]:
216
+ if json is None:
217
+ return None
218
+ return other_serializer.from_json(json)
219
+
220
+ return _Serializer(to_json, from_json)
221
+
222
+
199
223
  # ==============================================================================
200
224
  # INTERNAL: JSON serialization of TypeDescriptor
201
225
  # ==============================================================================
@@ -292,9 +316,10 @@ _FIELD_SERIALIZER: Final = _dataclass_serializer(
292
316
  "name",
293
317
  _primitive_serializer(str),
294
318
  ),
295
- _FieldSerializer(
319
+ _FieldSerializer[Optional[Type]](
296
320
  "type",
297
- _forwarding_serializer(_type_serializer),
321
+ _optional_serializer(_forwarding_serializer(_type_serializer)),
322
+ default=None,
298
323
  ),
299
324
  _FieldSerializer(
300
325
  "number",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soia-client
3
- Version: 1.1.1
3
+ Version: 1.1.3
4
4
  Author-email: Tyler Fibonacci <gepheum@gmail.com>
5
5
  License: MIT License
6
6
 
@@ -2,11 +2,10 @@ import dataclasses
2
2
  import unittest
3
3
  from typing import Any
4
4
 
5
+ from soia import KeyedItems, Method, Timestamp, _spec
5
6
  from soia._module_initializer import init_module
6
7
  from soia.reflection import TypeDescriptor
7
8
 
8
- from soia import KeyedItems, Method, Timestamp, _spec
9
-
10
9
 
11
10
  class ModuleInitializerTestCase(unittest.TestCase):
12
11
  def init_test_module(self) -> dict[str, Any]:
@@ -1201,6 +1200,10 @@ class ModuleInitializerTestCase(unittest.TestCase):
1201
1200
  "kind": "enum",
1202
1201
  "id": "my/module.soia:JsonValue",
1203
1202
  "fields": [
1203
+ {
1204
+ "name": "NULL",
1205
+ "number": 1,
1206
+ },
1204
1207
  {
1205
1208
  "name": "bool",
1206
1209
  "type": {"kind": "primitive", "value": "bool"},
File without changes
File without changes
File without changes
File without changes