Skip to content

Commit f2309a1

Browse files
authored
Kombu typing improvements (#207)
I've been working with Kombu directly in the last weeks, and tried to improve the type stubs along the way. Overall I think the result is decent. The workflow was basically just to run stubgen/stubtest to get first to some basic stubs, then mypy/basedpyright/ruff/tests to catch issues, everything semi-automated with AI, then some manual review. I've added the external deps which means the type checkers can actually resolve base classes and give useful feedback on overrides. This is mainly here for some feedback. Personally I would go with this approach and just aim for full type stubs coverage, and then work out the kinks. But I can also see that this is not ideal.
1 parent 6340f39 commit f2309a1

95 files changed

Lines changed: 6544 additions & 91 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ dist
33
.idea
44
node_modules
55
.python-version
6+
__pycache__
7+
*.pyc

amqp-stubs/__init__.pyi

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,155 @@
1-
from amqp.exceptions import ConnectionError
1+
from collections.abc import Callable, Mapping, Sequence
2+
from typing import Any
23

3-
__all__ = ["ConnectionError"]
4+
from amqp.basic_message import Message as Message
5+
from amqp.channel import Channel as Channel
6+
from amqp.connection import Connection as Connection
7+
from amqp.exceptions import (
8+
AccessRefused as AccessRefused,
9+
)
10+
from amqp.exceptions import (
11+
AMQPError as AMQPError,
12+
)
13+
from amqp.exceptions import (
14+
AMQPNotImplementedError as AMQPNotImplementedError,
15+
)
16+
from amqp.exceptions import (
17+
ChannelError as ChannelError,
18+
)
19+
from amqp.exceptions import (
20+
ChannelNotOpen as ChannelNotOpen,
21+
)
22+
from amqp.exceptions import (
23+
ConnectionError as ConnectionError,
24+
)
25+
from amqp.exceptions import (
26+
ConnectionForced as ConnectionForced,
27+
)
28+
from amqp.exceptions import (
29+
ConsumerCancelled as ConsumerCancelled,
30+
)
31+
from amqp.exceptions import (
32+
ContentTooLarge as ContentTooLarge,
33+
)
34+
from amqp.exceptions import (
35+
FrameError as FrameError,
36+
)
37+
from amqp.exceptions import (
38+
FrameSyntaxError as FrameSyntaxError,
39+
)
40+
from amqp.exceptions import (
41+
InternalError as InternalError,
42+
)
43+
from amqp.exceptions import (
44+
InvalidCommand as InvalidCommand,
45+
)
46+
from amqp.exceptions import (
47+
InvalidPath as InvalidPath,
48+
)
49+
from amqp.exceptions import (
50+
IrrecoverableChannelError as IrrecoverableChannelError,
51+
)
52+
from amqp.exceptions import (
53+
IrrecoverableConnectionError as IrrecoverableConnectionError,
54+
)
55+
from amqp.exceptions import (
56+
NoConsumers as NoConsumers,
57+
)
58+
from amqp.exceptions import (
59+
NotAllowed as NotAllowed,
60+
)
61+
from amqp.exceptions import (
62+
NotFound as NotFound,
63+
)
64+
from amqp.exceptions import (
65+
PreconditionFailed as PreconditionFailed,
66+
)
67+
from amqp.exceptions import (
68+
RecoverableChannelError as RecoverableChannelError,
69+
)
70+
from amqp.exceptions import (
71+
RecoverableConnectionError as RecoverableConnectionError,
72+
)
73+
from amqp.exceptions import (
74+
ResourceError as ResourceError,
75+
)
76+
from amqp.exceptions import (
77+
ResourceLocked as ResourceLocked,
78+
)
79+
from amqp.exceptions import (
80+
UnexpectedFrame as UnexpectedFrame,
81+
)
82+
from amqp.exceptions import (
83+
error_for_code as error_for_code,
84+
)
85+
86+
__all__ = (
87+
"AMQPError",
88+
"AMQPNotImplementedError",
89+
"AccessRefused",
90+
"Channel",
91+
"ChannelError",
92+
"ChannelNotOpen",
93+
"Connection",
94+
"ConnectionError",
95+
"ConnectionForced",
96+
"ConsumerCancelled",
97+
"ContentTooLarge",
98+
"FrameError",
99+
"FrameSyntaxError",
100+
"InternalError",
101+
"InvalidCommand",
102+
"InvalidPath",
103+
"IrrecoverableChannelError",
104+
"IrrecoverableConnectionError",
105+
"Message",
106+
"NoConsumers",
107+
"NotAllowed",
108+
"NotFound",
109+
"PreconditionFailed",
110+
"RecoverableChannelError",
111+
"RecoverableConnectionError",
112+
"ResourceError",
113+
"ResourceLocked",
114+
"UnexpectedFrame",
115+
"error_for_code",
116+
"promise",
117+
)
118+
119+
class promise:
120+
fun: Callable[..., Any] | None
121+
args: Sequence[Any]
122+
kwargs: Mapping[str, Any]
123+
on_error: Callable[..., Any] | None
124+
cancelled: bool
125+
failed: bool
126+
ready: bool
127+
reason: BaseException | None
128+
weak: bool
129+
ignore_result: bool
130+
value: Any
131+
132+
def __init__(
133+
self,
134+
fun: Callable[..., Any] | None = ...,
135+
args: Sequence[Any] | None = ...,
136+
kwargs: Mapping[str, Any] | None = ...,
137+
callback: Callable[..., Any] | None = ...,
138+
on_error: Callable[..., Any] | None = ...,
139+
weak: bool = ...,
140+
ignore_result: bool = ...,
141+
) -> None: ...
142+
def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
143+
def then(
144+
self, callback: Callable[..., Any], on_error: Callable[..., Any] | None = ...
145+
) -> promise: ...
146+
def throw(
147+
self,
148+
exc: BaseException | None = ...,
149+
tb: Any | None = ...,
150+
propagate: bool = ...,
151+
) -> None: ...
152+
def throw1(self, exc: BaseException | None = ...) -> None: ...
153+
def cancel(self) -> None: ...
154+
@property
155+
def listeners(self) -> list[promise]: ...

amqp-stubs/abstract_channel.pyi

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from collections.abc import Callable
2+
from logging import Logger
3+
from typing import Any
4+
5+
from amqp.exceptions import AMQPNotImplementedError as AMQPNotImplementedError
6+
from amqp.exceptions import RecoverableConnectionError as RecoverableConnectionError
7+
from typing_extensions import Self
8+
from vine import promise
9+
10+
__all__ = ("AbstractChannel",)
11+
12+
AMQP_LOGGER: Logger
13+
IGNORED_METHOD_DURING_CHANNEL_CLOSE: str
14+
15+
class AbstractChannel:
16+
auto_decode: bool
17+
channel_id: int | None
18+
connection: Any
19+
is_closing: bool
20+
method_queue: list[Any]
21+
22+
def __init__(self, connection: Any, channel_id: int | None) -> None: ...
23+
def __enter__(self) -> Self: ...
24+
def __exit__(self, *args: object) -> None: ...
25+
def close(self) -> None: ...
26+
def dispatch_method(
27+
self, method_sig: tuple[int, int], payload: bytes, content: Any
28+
) -> None: ...
29+
def send_method(
30+
self,
31+
sig: tuple[int, int],
32+
format: str | None = ...,
33+
args: tuple[Any, ...] | None = ...,
34+
content: Any | None = ...,
35+
wait: Any | None = ...,
36+
callback: Callable[..., Any] | None = ...,
37+
returns_tuple: bool = ...,
38+
) -> Any: ...
39+
def wait(
40+
self,
41+
method: Any,
42+
callback: Callable[..., Any] | None = ...,
43+
timeout: float | None = ...,
44+
returns_tuple: bool = ...,
45+
) -> Any: ...
46+
47+
def dumps(format: str, values: tuple[Any, ...]) -> bytes: ...
48+
def loads(format: str, buf: bytes, offset: int) -> tuple[Any, ...]: ...
49+
def ensure_promise(p: promise | Callable[..., Any] | None) -> promise: ...

amqp-stubs/basic_message.pyi

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from typing import Any
2+
3+
__all__ = ("Message",)
4+
5+
class Message:
6+
CLASS_ID: int
7+
PROPERTIES: list[tuple[str, str]]
8+
9+
body: bytes | str
10+
body_size: int
11+
body_received: int
12+
channel: Any
13+
delivery_info: dict[str, Any]
14+
properties: dict[str, Any]
15+
ready: bool
16+
frame_method: tuple[int, int] | None
17+
frame_args: bytes | None
18+
19+
content_type: str | None
20+
content_encoding: str | None
21+
application_headers: dict[str, Any] | None
22+
delivery_mode: int | None
23+
priority: int | None
24+
correlation_id: str | None
25+
reply_to: str | None
26+
expiration: str | None
27+
message_id: str | None
28+
timestamp: int | None
29+
type: str | None
30+
user_id: str | None
31+
app_id: str | None
32+
cluster_id: str | None
33+
34+
def __init__(
35+
self,
36+
body: bytes | str = ...,
37+
children: Any | None = ...,
38+
channel: Any | None = ...,
39+
**properties: Any,
40+
) -> None: ...
41+
@property
42+
def headers(self) -> dict[str, Any] | None: ...
43+
@property
44+
def delivery_tag(self) -> int | None: ...

0 commit comments

Comments
 (0)