Skip to content

Commit b3329c0

Browse files
authored
Merge pull request #94 from azogue/env/maintenance-update
Enable compatibility with new `fastapi-slim` and update examples
2 parents d4da8ac + fe62137 commit b3329c0

File tree

11 files changed

+114
-101
lines changed

11 files changed

+114
-101
lines changed

.pre-commit-config.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
minimum_pre_commit_version: 2.9.2
22
repos:
33
- repo: https://github.com/charliermarsh/ruff-pre-commit
4-
rev: v0.1.9
4+
rev: v0.4.4
55
hooks:
66
- id: ruff
77
args:
88
- --fix
99
- id: ruff-format
1010

1111
- repo: https://github.com/pre-commit/pre-commit-hooks
12-
rev: "v4.5.0"
12+
rev: "v4.6.0"
1313
hooks:
1414
- id: end-of-file-fixer
1515
- id: trailing-whitespace
@@ -24,6 +24,8 @@ repos:
2424
types_or: [yaml, markdown]
2525

2626
- repo: "https://github.com/pre-commit/mirrors-mypy"
27-
rev: "v1.8.0"
27+
rev: "v1.10.0"
2828
hooks:
2929
- id: "mypy"
30+
additional_dependencies:
31+
- pydantic

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pip install fastapi-mqtt
4141
### 🕹 Guide
4242

4343
```python
44+
from contextlib import asynccontextmanager
4445
from typing import Any
4546

4647
from fastapi import FastAPI
@@ -49,11 +50,17 @@ from gmqtt import Client as MQTTClient
4950
from fastapi_mqtt import FastMQTT, MQTTConfig
5051

5152
mqtt_config = MQTTConfig()
52-
5353
fast_mqtt = FastMQTT(config=mqtt_config)
5454

55-
app = FastAPI()
56-
fast_mqtt.init_app(app)
55+
56+
@asynccontextmanager
57+
async def _lifespan(_app: FastAPI):
58+
await fast_mqtt.mqtt_startup()
59+
yield
60+
await fast_mqtt.mqtt_shutdown()
61+
62+
63+
app = FastAPI(lifespan=_lifespan)
5764

5865

5966
@fast_mqtt.on_connect()

docs/example.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
11
### Full example
22

33
```python
4+
from contextlib import asynccontextmanager
45

5-
from fastapi_mqtt.fastmqtt import FastMQTT
66
from fastapi import FastAPI
77
from fastapi_mqtt.config import MQTTConfig
8+
from fastapi_mqtt.fastmqtt import FastMQTT
89

9-
app = FastAPI()
10-
11-
mqtt_config = MQTTConfig()
10+
fast_mqtt = FastMQTT(config=MQTTConfig())
1211

13-
fast_mqtt = FastMQTT(config=mqtt_config)
12+
@asynccontextmanager
13+
async def _lifespan(_app: FastAPI):
14+
await fast_mqtt.mqtt_startup()
15+
yield
16+
await fast_mqtt.mqtt_shutdown()
1417

15-
fast_mqtt.init_app(app)
18+
app = FastAPI(lifespan=_lifespan)
1619

17-
@mqtt.on_connect()
20+
@fast_mqtt.on_connect()
1821
def connect(client, flags, rc, properties):
19-
mqtt.client.subscribe("/mqtt") #subscribing mqtt topic
22+
fast_mqtt.client.subscribe("/mqtt") #subscribing mqtt topic
2023
print("Connected: ", client, flags, rc, properties)
2124

22-
@mqtt.on_message()
25+
@fast_mqtt.on_message()
2326
async def message(client, topic, payload, qos, properties):
2427
print("Received message: ",topic, payload.decode(), qos, properties)
2528
return 0
2629

27-
@mqtt.subscribe("my/mqtt/topic/#")
30+
@fast_mqtt.subscribe("my/mqtt/topic/#")
2831
async def message_to_topic(client, topic, payload, qos, properties):
2932
print("Received message to specific topic: ", topic, payload.decode(), qos, properties)
3033

31-
@mqtt.on_disconnect()
34+
@fast_mqtt.on_disconnect()
3235
def disconnect(client, packet, exc=None):
3336
print("Disconnected")
3437

35-
@mqtt.on_subscribe()
38+
@fast_mqtt.on_subscribe()
3639
def subscribe(client, mid, qos, properties):
3740
print("subscribed", client, mid, qos, properties)
3841

examples/app.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from contextlib import asynccontextmanager
12
from typing import Any
23

34
from fastapi import FastAPI
@@ -9,8 +10,15 @@
910

1011
fast_mqtt = FastMQTT(config=mqtt_config)
1112

12-
app = FastAPI()
13-
fast_mqtt.init_app(app)
13+
14+
@asynccontextmanager
15+
async def _lifespan(_app: FastAPI):
16+
await fast_mqtt.mqtt_startup()
17+
yield
18+
await fast_mqtt.mqtt_shutdown()
19+
20+
21+
app = FastAPI(lifespan=_lifespan)
1422

1523

1624
@fast_mqtt.on_connect()

examples/app_will_message.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from contextlib import asynccontextmanager
2+
13
from fastapi import FastAPI
24

35
from fastapi_mqtt.config import MQTTConfig
@@ -12,9 +14,14 @@
1214
fast_mqtt = FastMQTT(config=mqtt_config)
1315

1416

15-
app = FastAPI()
17+
@asynccontextmanager
18+
async def _lifespan(_app: FastAPI):
19+
await fast_mqtt.mqtt_startup()
20+
yield
21+
await fast_mqtt.mqtt_shutdown()
22+
1623

17-
fast_mqtt.init_app(app)
24+
app = FastAPI(lifespan=_lifespan)
1825

1926

2027
@fast_mqtt.on_connect()

fastapi_mqtt/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from typing import Optional, Union
33

44
from gmqtt.mqtt.constants import MQTTv50
5-
from pydantic import BaseModel, ConfigDict
5+
from pydantic import BaseModel, ConfigDict, Field
66

77

88
class MQTTConfig(BaseModel):
@@ -47,7 +47,7 @@ class MQTTConfig(BaseModel):
4747
keepalive: int = 60
4848
username: Optional[str] = None
4949
password: Optional[str] = None
50-
version: int = MQTTv50
50+
version: int = Field(default=MQTTv50, ge=4, le=5)
5151

5252
reconnect_retries: Optional[int] = 1
5353
reconnect_delay: Optional[int] = 6

fastapi_mqtt/fastmqtt.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
from itertools import zip_longest
55
from typing import Any, Callable, Dict, List, Optional, Tuple
66

7-
from fastapi import FastAPI
87
from gmqtt import Client as MQTTClient
98
from gmqtt import Message, Subscription
109
from gmqtt.mqtt.constants import MQTTv50
1110

1211
from .config import MQTTConfig
13-
from .handlers import MQTTHandlers
12+
from .handlers import (
13+
MQTTConnectionHandler,
14+
MQTTDisconnectHandler,
15+
MQTTHandlers,
16+
MQTTMessageHandler,
17+
MQTTSubscriptionHandler,
18+
)
1419

1520
try:
1621
from uvicorn.config import logger as log_info
@@ -67,7 +72,7 @@ def __init__(
6772
self.client._connect_properties = kwargs
6873
self.client.on_message = self.__on_message
6974
self.client.on_connect = self.__on_connect
70-
self.subscriptions: Dict[str, Tuple[Subscription, List[Callable]]] = {}
75+
self.subscriptions: Dict[str, Tuple[Subscription, List[MQTTMessageHandler]]] = {}
7176
self._logger = mqtt_logger or log_info
7277
self.mqtt_handlers = MQTTHandlers(self.client, self._logger)
7378

@@ -225,14 +230,14 @@ async def mqtt_shutdown(self) -> None:
225230
"""Final disconnection for MQTT client, for lifespan shutdown."""
226231
await self.client.disconnect()
227232

228-
def init_app(self, app: FastAPI) -> None: # pragma: no cover
233+
def init_app(self, fastapi_app) -> None: # pragma: no cover
229234
"""Add startup and shutdown event handlers for app without lifespan."""
230235

231-
@app.on_event("startup")
236+
@fastapi_app.on_event("startup")
232237
async def startup() -> None:
233238
await self.mqtt_startup()
234239

235-
@app.on_event("shutdown")
240+
@fastapi_app.on_event("shutdown")
236241
async def shutdown() -> None:
237242
await self.mqtt_shutdown()
238243

@@ -249,7 +254,7 @@ def subscribe(
249254
Decorator method used to subscribe for specific topics.
250255
"""
251256

252-
def subscribe_handler(handler: Callable) -> Callable:
257+
def subscribe_handler(handler: MQTTMessageHandler) -> MQTTMessageHandler:
253258
self._logger.debug("Subscribe for topics: %s", topics)
254259
for topic in topics:
255260
if topic not in self.subscriptions:
@@ -290,7 +295,7 @@ def on_connect(self) -> Callable[..., Any]:
290295
Decorator method used to handle the connection to MQTT.
291296
"""
292297

293-
def connect_handler(handler: Callable) -> Callable:
298+
def connect_handler(handler: MQTTConnectionHandler) -> MQTTConnectionHandler:
294299
self._logger.debug("handler accepted")
295300
return self.mqtt_handlers.on_connect(handler)
296301

@@ -301,7 +306,7 @@ def on_message(self) -> Callable[..., Any]:
301306
The decorator method is used to subscribe to messages from all topics.
302307
"""
303308

304-
def message_handler(handler: Callable) -> Callable:
309+
def message_handler(handler: MQTTMessageHandler) -> MQTTMessageHandler:
305310
self._logger.debug("on_message handler accepted")
306311
return self.mqtt_handlers.on_message(handler)
307312

@@ -312,7 +317,7 @@ def on_disconnect(self) -> Callable[..., Any]:
312317
The Decorator method used wrap disconnect callback.
313318
"""
314319

315-
def disconnect_handler(handler: Callable) -> Callable:
320+
def disconnect_handler(handler: MQTTDisconnectHandler) -> MQTTDisconnectHandler:
316321
self._logger.debug("on_disconnect handler accepted")
317322
return self.mqtt_handlers.on_disconnect(handler)
318323

@@ -323,7 +328,7 @@ def on_subscribe(self) -> Callable[..., Any]:
323328
Decorator method is used to obtain subscribed topics and properties.
324329
"""
325330

326-
def subscribe_handler(handler: Callable):
331+
def subscribe_handler(handler: MQTTSubscriptionHandler) -> MQTTSubscriptionHandler:
327332
self._logger.debug("on_subscribe handler accepted")
328333
return self.mqtt_handlers.on_subscribe(handler)
329334

fastapi_mqtt/handlers.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
MQTTMessageHandler = Callable[[MQTTClient, str, bytes, int, Any], Awaitable[Any]]
99
# client: MQTTClient, flags: int, rc: int, properties: Any
1010
MQTTConnectionHandler = Callable[[MQTTClient, int, int, Any], Any]
11+
# client: MQTTClient, mid: int, qos: int, properties: Any
12+
MQTTSubscriptionHandler = Callable[[MQTTClient, int, int, Any], Any]
13+
# client: MQTTClient, packet: bytes, exc=None
14+
MQTTDisconnectHandler = Callable[[MQTTClient, bytes, Optional[Exception]], Any]
1115

1216

1317
class MQTTHandlers:
@@ -22,15 +26,15 @@ def on_message(self, handler: MQTTMessageHandler) -> MQTTMessageHandler:
2226
self.user_message_handler = handler
2327
return handler
2428

25-
def on_subscribe(self, handler: Callable) -> Callable[..., Any]:
29+
def on_subscribe(self, handler: MQTTSubscriptionHandler) -> MQTTSubscriptionHandler:
2630
"""
2731
Decorator method is used to obtain subscribed topics and properties.
2832
"""
2933
self._logger.info("on_subscribe handler accepted")
3034
self.client.on_subscribe = handler
3135
return handler
3236

33-
def on_disconnect(self, handler: Callable) -> Callable[..., Any]:
37+
def on_disconnect(self, handler: MQTTDisconnectHandler) -> MQTTDisconnectHandler:
3438
self.client.on_disconnect = handler
3539
return handler
3640

0 commit comments

Comments
 (0)