1from __future__ import annotations
2
3import sys
4from collections.abc import Generator
5from textwrap import dedent
6from typing import Any
7
8if sys.version_info < (3, 11):
9 from exceptiongroup import BaseExceptionGroup
10
11
12class BrokenResourceError(Exception):
13 """
14 Raised when trying to use a resource that has been rendered unusable due to external
15 causes (e.g. a send stream whose peer has disconnected).
16 """
17
18
19class BrokenWorkerProcess(Exception):
20 """
21 Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or
22 otherwise misbehaves.
23 """
24
25
26class BrokenWorkerInterpreter(Exception):
27 """
28 Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is
29 raised in the subinterpreter.
30 """
31
32 def __init__(self, excinfo: Any):
33 # This was adapted from concurrent.futures.interpreter.ExecutionFailed
34 msg = excinfo.formatted
35 if not msg:
36 if excinfo.type and excinfo.msg:
37 msg = f"{excinfo.type.__name__}: {excinfo.msg}"
38 else:
39 msg = excinfo.type.__name__ or excinfo.msg
40
41 super().__init__(msg)
42 self.excinfo = excinfo
43
44 def __str__(self) -> str:
45 try:
46 formatted = self.excinfo.errdisplay
47 except Exception:
48 return super().__str__()
49 else:
50 return dedent(
51 f"""
52 {super().__str__()}
53
54 Uncaught in the interpreter:
55
56 {formatted}
57 """.strip()
58 )
59
60
61class BusyResourceError(Exception):
62 """
63 Raised when two tasks are trying to read from or write to the same resource
64 concurrently.
65 """
66
67 def __init__(self, action: str):
68 super().__init__(f"Another task is already {action} this resource")
69
70
71class ClosedResourceError(Exception):
72 """Raised when trying to use a resource that has been closed."""
73
74
75class ConnectionFailed(OSError):
76 """
77 Raised when a connection attempt fails.
78
79 .. note:: This class inherits from :exc:`OSError` for backwards compatibility.
80 """
81
82
83def iterate_exceptions(
84 exception: BaseException,
85) -> Generator[BaseException, None, None]:
86 if isinstance(exception, BaseExceptionGroup):
87 for exc in exception.exceptions:
88 yield from iterate_exceptions(exc)
89 else:
90 yield exception
91
92
93class DelimiterNotFound(Exception):
94 """
95 Raised during
96 :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
97 maximum number of bytes has been read without the delimiter being found.
98 """
99
100 def __init__(self, max_bytes: int) -> None:
101 super().__init__(
102 f"The delimiter was not found among the first {max_bytes} bytes"
103 )
104
105
106class EndOfStream(Exception):
107 """
108 Raised when trying to read from a stream that has been closed from the other end.
109 """
110
111
112class IncompleteRead(Exception):
113 """
114 Raised during
115 :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or
116 :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
117 connection is closed before the requested amount of bytes has been read.
118 """
119
120 def __init__(self) -> None:
121 super().__init__(
122 "The stream was closed before the read operation could be completed"
123 )
124
125
126class TypedAttributeLookupError(LookupError):
127 """
128 Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute
129 is not found and no default value has been given.
130 """
131
132
133class WouldBlock(Exception):
134 """Raised by ``X_nowait`` functions if ``X()`` would block."""
135
136
137class NoEventLoopError(RuntimeError):
138 """
139 Raised by several functions that require an event loop to be running in the current
140 thread when there is no running event loop.
141
142 This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync`
143 if not calling from an AnyIO worker thread, and no ``token`` was passed.
144 """
145
146
147class RunFinishedError(RuntimeError):
148 """
149 Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event
150 loop associated with the explicitly passed token has already finished.
151 """
152
153 def __init__(self) -> None:
154 super().__init__(
155 "The event loop associated with the given token has already finished"
156 )