soia-client 1.0.21__py3-none-any.whl → 1.0.23__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.
@@ -1,6 +1,7 @@
1
1
  import http.client
2
2
  import re
3
- from typing import Any, Final, Mapping
3
+ import typing
4
+ from typing import Any, Final, Mapping, Protocol
4
5
  from urllib.parse import urlparse
5
6
 
6
7
  from soia._impl.method import Method, Request, Response
@@ -77,3 +78,88 @@ class ServiceClient:
77
78
  if re.match(r"text/plain\b", content_type):
78
79
  message = f"{message}: {response_data}"
79
80
  raise RuntimeError(message)
81
+
82
+ async def invoke_remote_async(
83
+ self,
84
+ aiohttp_client_session: "_AiohttpClientSession",
85
+ method: Method[Request, Response],
86
+ request: Request,
87
+ headers: Mapping[str, str] = {},
88
+ *,
89
+ res_headers: list[tuple[str, str]] | None = None,
90
+ ) -> Response:
91
+ """
92
+ Asynchronously invokes the given method on the remote server through an RPC.
93
+
94
+ Usage:
95
+ import aiohttp
96
+
97
+ async with aiohttp.ClientSession() as session:
98
+ response = await service_client.invoke_remote_async(
99
+ session,
100
+ method,
101
+ request,
102
+ headers,
103
+ )
104
+
105
+ With timeout:
106
+ timeout = aiohttp.ClientTimeout(total=30)
107
+ async with aiohttp.ClientSession(timeout=timeout) as session:
108
+ response = await service_client.invoke_remote_async(
109
+ session,
110
+ method,
111
+ request,
112
+ headers,
113
+ )
114
+ """
115
+
116
+ request_json = method.request_serializer.to_json_code(request)
117
+ body = ":".join(
118
+ [
119
+ method.name,
120
+ str(method.number),
121
+ "",
122
+ request_json,
123
+ ]
124
+ )
125
+
126
+ request_headers = {
127
+ **headers,
128
+ "Content-Type": "text/plain; charset=utf-8",
129
+ "Content-Length": str(len(body)),
130
+ }
131
+
132
+ # Build the URL
133
+ url = f"{self._scheme}://{self._host}{self._path}"
134
+
135
+ async with aiohttp_client_session.post(
136
+ url,
137
+ data=body,
138
+ headers=request_headers,
139
+ ) as response:
140
+ if res_headers is not None:
141
+ res_headers.clear()
142
+ res_headers.extend(response.headers.items())
143
+
144
+ status_code = response.status
145
+ content_type = response.headers.get("Content-Type", "")
146
+ response_data = await response.text(encoding="utf-8", errors="ignore")
147
+
148
+ if status_code in range(200, 300):
149
+ return method.response_serializer.from_json_code(response_data)
150
+ else:
151
+ message = f"HTTP status {status_code}"
152
+ if re.match(r"text/plain\b", content_type):
153
+ message = f"{message}: {response_data}"
154
+ raise RuntimeError(message)
155
+
156
+
157
+ class _AiohttpClientSession(Protocol):
158
+ def post(
159
+ self,
160
+ url: str,
161
+ *,
162
+ data: str,
163
+ headers: Mapping[str, str],
164
+ ) -> Any:
165
+ ...
soia/_impl/structs.py CHANGED
@@ -135,6 +135,7 @@ class StructAdapter(TypeAdapter):
135
135
  ),
136
136
  )
137
137
  mutable_class.__init__ = cast(Any, _make_mutable_class_init_fn(fields))
138
+ frozen_class.whole = _make_whole_static_factory_method(frozen_class)
138
139
 
139
140
  frozen_class.__eq__ = _make_eq_fn(fields)
140
141
  frozen_class.__hash__ = cast(Any, _make_hash_fn(fields, self.record_hash))
@@ -260,7 +261,7 @@ def _make_frozen_class_init_fn(
260
261
  fields: Sequence[_Field],
261
262
  frozen_class: type,
262
263
  simple_class: type,
263
- ) -> Callable[[Any], None]:
264
+ ) -> Callable[..., None]:
264
265
  """
265
266
  Returns the implementation of the __init__() method of the frozen class.
266
267
  """
@@ -354,7 +355,7 @@ def _make_frozen_class_init_fn(
354
355
  )
355
356
 
356
357
 
357
- def _make_mutable_class_init_fn(fields: Sequence[_Field]) -> Callable[[Any], None]:
358
+ def _make_mutable_class_init_fn(fields: Sequence[_Field]) -> Callable[..., None]:
358
359
  """
359
360
  Returns the implementation of the __init__() method of the mutable class.
360
361
  """
@@ -383,6 +384,12 @@ def _make_mutable_class_init_fn(fields: Sequence[_Field]) -> Callable[[Any], Non
383
384
  )
384
385
 
385
386
 
387
+ def _make_whole_static_factory_method(frozen_class: type) -> Callable[..., Any]:
388
+ def whole(**kwargs):
389
+ return frozen_class(**kwargs)
390
+ return whole
391
+
392
+
386
393
  def _make_to_mutable_fn(
387
394
  mutable_class: type,
388
395
  simple_class: type,
@@ -526,7 +533,7 @@ def _make_hash_fn(
526
533
  )
527
534
 
528
535
 
529
- def _make_repr_fn(fields: Sequence[_Field]) -> Callable[[Any], Any]:
536
+ def _make_repr_fn(fields: Sequence[_Field]) -> Callable[[Any], str]:
530
537
  """
531
538
  Returns the implementation of the __repr__() method of both the frozen class and the
532
539
  mutable class.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soia-client
3
- Version: 1.0.21
3
+ Version: 1.0.23
4
4
  Author-email: Tyler Fibonacci <gepheum@gmail.com>
5
5
  License: MIT License
6
6
 
@@ -15,12 +15,12 @@ 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
17
  soia/_impl/service.py,sha256=PsV286BYMoJpXIjeBc__MHHakcqof0Pbb3B_Zha1PZI,11928
18
- soia/_impl/service_client.py,sha256=qDntwRyXfLsmXl4ELfOkh-fgv553nrGy72K0JghLM80,2734
19
- soia/_impl/structs.py,sha256=YTc3Ykj2TxPquar2XsP2DhFfkfIoELXOveyd8yTqN90,26545
18
+ soia/_impl/service_client.py,sha256=vxlUUVCGtd-S9JF-xTTM0R9maO7ZVpfhbAJGYRoBnzw,5333
19
+ soia/_impl/structs.py,sha256=iEO6Mu2I0--oNqvPWxFxXEzZ_0RXNIKndhdzWU5Zqw8,26781
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.21.dist-info/licenses/LICENSE,sha256=SaAftKkX6hfSOiPdENQPS70tifH3PDHgazq8eK2Pwfw,1064
23
- soia_client-1.0.21.dist-info/METADATA,sha256=Ru0EEbE4aLijjzYSjeaCuC3WImJuTYL0HfxpqaL8KFc,2122
24
- soia_client-1.0.21.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
25
- soia_client-1.0.21.dist-info/top_level.txt,sha256=lsYG9JrvauFe1oIV5zvnwsS9hsx3ztwfK_937op9mxc,5
26
- soia_client-1.0.21.dist-info/RECORD,,
22
+ soia_client-1.0.23.dist-info/licenses/LICENSE,sha256=SaAftKkX6hfSOiPdENQPS70tifH3PDHgazq8eK2Pwfw,1064
23
+ soia_client-1.0.23.dist-info/METADATA,sha256=cDChHoM5TBijDK4m3YB-CH5kbhU3KglDeqRPETz-zms,2122
24
+ soia_client-1.0.23.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ soia_client-1.0.23.dist-info/top_level.txt,sha256=lsYG9JrvauFe1oIV5zvnwsS9hsx3ztwfK_937op9mxc,5
26
+ soia_client-1.0.23.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5