pybrid-computing 0.10.0__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.
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2022-2024 anabrid GmbH
2
+ # Contact: https://www.anabrid.com/licensing/
3
+ # SPDX-License-Identifier: MIT OR GPL-2.0-or-later
4
+
5
+ import logging
6
+ import typing
7
+
8
+ from uuid import UUID, uuid4
9
+ from pydantic import BaseModel, Field, ValidationError
10
+
11
+ from pybrid.base.hybrid.protocol import MalformedDataError, MalformedMessageError
12
+
13
+ from .messages import Message
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class MalformedEnvelopeError(MalformedDataError):
19
+ pass
20
+
21
+
22
+ class Envelope(BaseModel):
23
+ """
24
+ Envelope containing a :class:`Message`.
25
+
26
+ While the relevant data for the communication as part of this protocol is encoded
27
+ using the various message classes, the most fundamental data package that is sent
28
+ between two recipients is this envelope.
29
+
30
+ The envelope contains an :attr:`id`, which is used to identify responses to previous requests
31
+ (optional for notifications).
32
+
33
+ The :attr:`type` field contains a unique type identifier, telling the recipient which :class:`Message`
34
+ is contained in the :attr:`msg` field. The type identifier is defined to be the python message class name,
35
+ with any Request, Response or Notification suffix removed and converted to underscore case.
36
+
37
+ For responses, the :attr:`success` field and :attr:`error` field define whether the request was successfully
38
+ handled. Only if :attr:`success` is true, :attr:`msg` contains an actual response.
39
+ """
40
+ #: Optional ID of the request and its response. None for Notifications
41
+ id: typing.Optional[UUID] = Field(default_factory=uuid4)
42
+ #: Unique string defining the type of the contained message
43
+ type: str
44
+ #: The msg, None if :attr:`success` is false for responses
45
+ msg: typing.Optional[dict] = None
46
+ #: Whether the request was handled successfully (only in responses)
47
+ success: typing.Optional[bool] = Field(exclude=True, default=True)
48
+ #: Optional error, in case :attr:`success` is false
49
+ error: typing.Optional[str] = Field(exclude=True, default="")
50
+
51
+ @classmethod
52
+ def from_message(cls, message):
53
+ return cls(**{"type": message.get_type_identifier(), "msg": message})
54
+
55
+ def get_message(self) -> Message:
56
+ try:
57
+ msg_class = Message.get_class_for_type_identifier(self.type)
58
+ msg = msg_class(**self.msg)
59
+ return msg
60
+ except (KeyError, AttributeError, ValidationError) as exc:
61
+ logger.exception("Error while parsing message from envelope: %s.", exc)
62
+ raise MalformedMessageError() from exc