aspyx-service 0.10.7__py3-none-any.whl → 0.11.1__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.

Potentially problematic release.


This version of aspyx-service might be problematic. Click here for more details.

aspyx_service/__init__.py CHANGED
@@ -12,6 +12,7 @@ from .healthcheck import health_checks, health_check, HealthCheckManager, Health
12
12
  from .restchannel import RestChannel, post, get, put, delete, QueryParam, Body, rest
13
13
  from .session import Session, SessionManager, SessionContext
14
14
  from .authorization import AuthorizationManager, AbstractAuthorizationFactory
15
+ from .protobuf import ProtobufManager
15
16
 
16
17
  @module()
17
18
  class ServiceModule:
@@ -48,6 +49,10 @@ __all__ = [
48
49
  "MissingTokenException",
49
50
  "AuthorizationException",
50
51
 
52
+ # protobuf
53
+
54
+ "ProtobufManager",
55
+
51
56
  # authorization
52
57
 
53
58
  "AuthorizationManager",
aspyx_service/channels.py CHANGED
@@ -16,7 +16,7 @@ from pydantic import BaseModel
16
16
  from aspyx.di.configuration import inject_value
17
17
  from aspyx.reflection import DynamicProxy, TypeDescriptor
18
18
  from aspyx.threading import ThreadLocal, ContextLocal
19
- from aspyx.util import get_deserializer, TypeDeserializer, TypeSerializer, get_serializer
19
+ from aspyx.util import get_deserializer, TypeDeserializer, TypeSerializer, get_serializer, CopyOnWriteCache
20
20
  from .service import ServiceManager, ServiceCommunicationException, TokenExpiredException, InvalidTokenException, \
21
21
  AuthorizationException, MissingTokenException
22
22
 
@@ -61,6 +61,9 @@ class TokenContext:
61
61
  cls.refresh_token.reset(refresh_token)
62
62
 
63
63
  class HTTPXChannel(Channel):
64
+ """
65
+ A channel using the httpx clients.
66
+ """
64
67
  __slots__ = [
65
68
  "client",
66
69
  "async_client",
@@ -75,28 +78,6 @@ class HTTPXChannel(Channel):
75
78
  client_local = ThreadLocal[Client]()
76
79
  async_client_local = ThreadLocal[AsyncClient]()
77
80
 
78
- # class methods
79
-
80
- @classmethod
81
- def to_dict(cls, obj: Any) -> Any:
82
- if isinstance(obj, BaseModel):
83
- return obj.model_dump()
84
-
85
- elif is_dataclass(obj):
86
- return {
87
- f.name: cls.to_dict(getattr(obj, f.name))
88
-
89
- for f in fields(obj)
90
- }
91
-
92
- elif isinstance(obj, (list, tuple)):
93
- return [cls.to_dict(item) for item in obj]
94
-
95
- elif isinstance(obj, dict):
96
- return {key: cls.to_dict(value) for key, value in obj.items()}
97
-
98
- return obj
99
-
100
81
  # constructor
101
82
 
102
83
  def __init__(self):
@@ -104,9 +85,8 @@ class HTTPXChannel(Channel):
104
85
 
105
86
  self.timeout = 1000.0
106
87
  self.service_names: dict[Type, str] = {}
107
- self.serializers: dict[Callable, list[Callable]] = {}
108
- self.deserializers: dict[Callable, Callable] = {}
109
- self.optimize_serialization = True
88
+ self.serializers = CopyOnWriteCache[Callable, list[Callable]]()
89
+ self.deserializers = CopyOnWriteCache[Callable, Callable]()
110
90
 
111
91
  # inject
112
92
 
@@ -132,7 +112,7 @@ class HTTPXChannel(Channel):
132
112
 
133
113
  serializers = [get_serializer(type) for type in param_types]
134
114
 
135
- self.serializers[method] = serializers
115
+ self.serializers.put(method, serializers)
136
116
 
137
117
  return serializers
138
118
 
@@ -143,7 +123,7 @@ class HTTPXChannel(Channel):
143
123
 
144
124
  deserializer = get_deserializer(return_type)
145
125
 
146
- self.deserializers[method] = deserializer
126
+ self.deserializers.put(method, deserializer)
147
127
 
148
128
  return deserializer
149
129
 
@@ -291,16 +271,11 @@ class DispatchJSONChannel(HTTPXChannel):
291
271
  def invoke(self, invocation: DynamicProxy.Invocation):
292
272
  service_name = self.service_names[invocation.type] # map type to registered service name
293
273
 
294
- request : dict = {
295
- "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}"
296
- #"args": invocation.args
274
+ request = {
275
+ "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}",
276
+ "args": self.serialize_args(invocation)
297
277
  }
298
278
 
299
- if self.optimize_serialization:
300
- request["args"] = self.serialize_args(invocation)
301
- else:
302
- request["args"] = self.to_dict(invocation.args)
303
-
304
279
  try:
305
280
  http_result = self.request( "post", f"{self.get_url()}/invoke", json=request, timeout=self.timeout)
306
281
  result = http_result.json()
@@ -317,15 +292,11 @@ class DispatchJSONChannel(HTTPXChannel):
317
292
 
318
293
  async def invoke_async(self, invocation: DynamicProxy.Invocation):
319
294
  service_name = self.service_names[invocation.type] # map type to registered service name
320
- request : dict = {
321
- "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}"
295
+ request = {
296
+ "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}",
297
+ "args": self.serialize_args(invocation)
322
298
  }
323
299
 
324
- if self.optimize_serialization:
325
- request["args"] = self.serialize_args(invocation)
326
- else:
327
- request["args"] = self.to_dict(invocation.args)
328
-
329
300
  try:
330
301
  data = await self.request_async("post", f"{self.get_url()}/invoke", json=request, timeout=self.timeout)
331
302
  result = data.json()
@@ -361,15 +332,11 @@ class DispatchMSPackChannel(HTTPXChannel):
361
332
 
362
333
  def invoke(self, invocation: DynamicProxy.Invocation):
363
334
  service_name = self.service_names[invocation.type] # map type to registered service name
364
- request: dict = {
365
- "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}"
335
+ request = {
336
+ "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}",
337
+ "args": self.serialize_args(invocation)
366
338
  }
367
339
 
368
- if self.optimize_serialization:
369
- request["args"] = self.serialize_args(invocation)
370
- else:
371
- request["args"] = self.to_dict(invocation.args)
372
-
373
340
  try:
374
341
  packed = msgpack.packb(request, use_bin_type=True)
375
342
 
@@ -397,10 +364,11 @@ class DispatchMSPackChannel(HTTPXChannel):
397
364
  if "invalid_token" in www_auth:
398
365
  if 'expired' in www_auth:
399
366
  raise TokenExpiredException() from e
400
- elif 'missing' in www_auth:
367
+
368
+ if 'missing' in www_auth:
401
369
  raise MissingTokenException() from e
402
- else:
403
- raise InvalidTokenException() from e
370
+
371
+ raise InvalidTokenException() from e
404
372
 
405
373
  raise RemoteServiceException(str(e)) from e
406
374
  except httpx.HTTPError as e:
@@ -417,15 +385,11 @@ class DispatchMSPackChannel(HTTPXChannel):
417
385
 
418
386
  async def invoke_async(self, invocation: DynamicProxy.Invocation):
419
387
  service_name = self.service_names[invocation.type] # map type to registered service name
420
- request: dict = {
421
- "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}"
388
+ request = {
389
+ "method": f"{self.component_descriptor.name}:{service_name}:{invocation.method.__name__}",
390
+ "args": self.serialize_args(invocation)
422
391
  }
423
392
 
424
- if self.optimize_serialization:
425
- request["args"] = self.serialize_args(invocation)
426
- else:
427
- request["args"] = self.to_dict(invocation.args)
428
-
429
393
  try:
430
394
  packed = msgpack.packb(request, use_bin_type=True)
431
395
 
@@ -15,7 +15,7 @@ from aspyx.reflection import Decorators, TypeDescriptor
15
15
 
16
16
  def health_checks():
17
17
  """
18
- Instances of classes that are annotated with @injectable can be created by an Environment.
18
+ Instances of classes that are annotated with @health_checks contain healt mehtods.
19
19
  """
20
20
  def decorator(cls):
21
21
  Decorators.add(cls, health_checks)
@@ -31,7 +31,7 @@ def health_checks():
31
31
 
32
32
  def health_check(name="", cache = 0, fail_if_slower_than = 0):
33
33
  """
34
- Methods annotated with `@on_init` will be called when the instance is created.
34
+ Methods annotated with `@health_check` specify health checks that will be executed.
35
35
  """
36
36
  def decorator(func):
37
37
  Decorators.add(func, health_check, name, cache, fail_if_slower_than)