forked from frequenz-floss/frequenz-channels-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path_sender.py
More file actions
111 lines (79 loc) · 3.45 KB
/
Copy path_sender.py
File metadata and controls
111 lines (79 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# License: MIT
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH
"""Sender interface and related exceptions.
# Senders
Messages are sent to a [channel](/user-guide/channels) through
[Sender][frequenz.channels.Sender] objects. [Senders][frequenz.channels.Sender] are
usually created by calling `channel.new_sender()`, and are a very simple abstraction
that only provides a single [`send()`][frequenz.channels.Sender.send] method:
```python show_lines="6:"
from frequenz.channels import Anycast
channel = Anycast[int](name="test-channel")
sender = channel.new_sender()
await sender.send("Hello, world!")
```
Although [`send()`][frequenz.channels.Sender.send] is an asynchronous method, some
channels may implement it in a synchronous, non-blocking way. For example, buffered
channels that drop messages when the buffer is full could guarantee that
[`send()`][frequenz.channels.Sender.send] never blocks. However, please keep in mind
that the [asyncio][] event loop could give control to another task at any time,
effectively making the [`send()`][frequenz.channels.Sender.send] method blocking.
# Error Handling
!!! Tip inline end
For more information about handling errors, please refer to the
[Error Handling](/user-guide/error-handling/) section of the user guide.
If there is any failure sending a message,
a [SenderError][frequenz.channels.SenderError] exception is raised.
```python show_lines="6:"
from frequenz.channels import Anycast
channel = Anycast[int](name="test-channel")
sender = channel.new_sender()
try:
await sender.send("Hello, world!")
except SenderError as error:
print(f"Error sending message: {error}")
```
"""
from abc import ABC, abstractmethod
from typing import Generic
from ._exceptions import Error
from ._generic import SenderMessageT_co, SenderMessageT_contra
class Sender(ABC, Generic[SenderMessageT_contra]):
"""An endpoint to sends messages."""
@abstractmethod
async def send(self, message: SenderMessageT_contra, /) -> None:
"""Send a message.
Args:
message: The message to be sent.
Raises:
SenderError: If there was an error sending the message.
"""
@abstractmethod
async def aclose(self) -> None:
"""Close this sender.
After a sender is closed, it can no longer be used to send messages. Any
attempt to send a message through a closed sender will raise a
[SenderClosedError][frequenz.channels.SenderClosedError].
"""
class SenderError(Error, Generic[SenderMessageT_co]):
"""An error that originated in a [Sender][frequenz.channels.Sender].
All exceptions generated by senders inherit from this exception.
"""
def __init__(self, message: str, sender: Sender[SenderMessageT_co]):
"""Initialize this error.
Args:
message: The error message.
sender: The [Sender][frequenz.channels.Sender] where the error
happened.
"""
super().__init__(message)
self.sender: Sender[SenderMessageT_co] = sender
"""The sender where the error happened."""
class SenderClosedError(SenderError[SenderMessageT_co]):
"""An error indicating that a send operation was attempted on a closed sender."""
def __init__(self, sender: Sender[SenderMessageT_co]):
"""Initialize this error.
Args:
sender: The [Sender][frequenz.channels.Sender] that was closed.
"""
super().__init__("Sender is closed", sender)