Skip to content

Commit

Permalink
feat: add 'aiomqtt' recipe. (#280)
Browse files Browse the repository at this point in the history
* feat: add 'aiomqtt' recipe.
* [pre-commit.ci] auto fixes from pre-commit.com hooks

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
lucas-six and pre-commit-ci[bot] authored Apr 4, 2024
1 parent df62a45 commit 104816f
Show file tree
Hide file tree
Showing 16 changed files with 305 additions and 254 deletions.
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ repos:
rev: v1.9.0
hooks:
- id: mypy
exclude: (settings.py|manage.py|models.py|(migrations/)|admin.py)
additional_dependencies: [pydantic, types-redis]
exclude: (manage.py|models.py|(migrations/)|admin.py)
additional_dependencies: [pydantic, types-redis, aiomqtt]
language_version: python3.11
- repo: https://github.com/PyCQA/pylint
rev: v3.1.0
Expand All @@ -58,6 +58,7 @@ repos:
motor,
redis,
types-redis,
aiomqtt,
]
exclude: django_project/
language_version: python3.11
Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ celery = {version = "*", extras = ["librabbitmq", "mongodb", "redis"]}
#django = "~=4.2"
#psycopg = {version = ">=3.2", extras = ["binary", "pool"]}
motor = "*"
aiomqtt = "*"

[dev-packages]
black = "*"
Expand Down
334 changes: 175 additions & 159 deletions Pipfile.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@

### Redis

- [**`redis-py`**: Sync / Async](https://lucas-six.github.io/python-cookbook/cookbook/system_services/redis)
- [`aioredis`: Async (Obsoleted by `redis-py`)](https://aioredis.readthedocs.io/en/latest/)
- [**`redis-py`**: Sync + Async](https://lucas-six.github.io/python-cookbook/cookbook/system_services/redis)
- [~~`aioredis`: Async (Obsoleted by `redis-py`)~~](https://aioredis.readthedocs.io/en/latest/)
- `pyton-redis-orm`: ORM

### RabbitMQ
Expand All @@ -234,7 +234,7 @@

### MQTT

- [**`asyncio-mqtt`**: Async](https://pypi.org/project/asyncio-mqtt/) ([中文](https://blog.alexsun.top/vuepress-python-notes/pypi-package/async/asyncio-mqtt.html))
- [**`aiomqtt`**: Async](https://lucas-six.github.io/python-cookbook/cookbook/system_services/mqtt_aiomqtt)

## Recipes

Expand Down
2 changes: 1 addition & 1 deletion cookbook/build/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ disable = [
"locally-disabled",
"file-ignored",
"suppressed-message",
"useless-suppression",
"deprecated-pragma",
"use-symbolic-message-instead",
"logging-fstring-interpolation",
Expand All @@ -148,6 +147,7 @@ disable = [
]
enable = [
"c-extension-no-member",
"useless-suppression",
]

[tool.pylint.design]
Expand Down
58 changes: 58 additions & 0 deletions cookbook/system_services/mqtt_aiomqtt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# `aiomqtt` - Python Asyncio APIs for MQTT

## Set Up

```toml
# pyproject.toml

dependencies = [
"aiomqtt",
]
```

```bash
pipenv install aiomqtt
```

## Usage

```python
"""MQTT `aiomqtt` Usage.
"""

import asyncio
import os
import sys

import aiomqtt

MQTT_HOST = 'localhost'
MQTT_TOPIC_PREFIX = 'python-cookbook'


async def main():
async with aiomqtt.Client(MQTT_HOST, timeout=3.5) as client:

# Subscribe
await client.subscribe(f'{MQTT_TOPIC_PREFIX}/#')
async for message in client.messages:
if isinstance(message.payload, bytes):
print(message.payload.decode('utf-8'))

# Publish
# await client.publish(f'{MQTT_TOPIC_PREFIX}/example', payload={'msg': 'hello'})


# Change to the "Selector" event loop if platform is Windows
if sys.platform.lower() == "win32" or os.name.lower() == "nt":
from asyncio import WindowsSelectorEventLoopPolicy # type: ignore
from asyncio import set_event_loop_policy

set_event_loop_policy(WindowsSelectorEventLoopPolicy())

asyncio.run(main())
```

## References

- [`aiomqtt` Documentation](https://sbtinstruments.github.io/aiomqtt/index.html)
4 changes: 4 additions & 0 deletions cookbook/system_services/redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ dependencies = [
#"redis[hiredis]",
"types-redis",
]

[[tool.mypy.overrides]]
module = "redis.*"
ignore_missing_imports = true
```

```bash
Expand Down
10 changes: 0 additions & 10 deletions cookbook/web/fastapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,12 @@
## Installation

```bash
# HTTP Request
pipenv install aiohttp

# Cache: Redis
pipenv install redis[hiredis]
pipenv install types-redis

# MQ: RabbitMQ/MongoDB/Redis
pipenv install pika
pipenv install types-pika

# Task Queue: Celery
pipenv install celery[librabbitmq, mongodb, redis]

# MQTT
pipenv install asyncio-mqtt
```

## MongoDB
Expand Down
2 changes: 1 addition & 1 deletion cookbook/web/fastapi/fastapi_mongodb.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ async def redoc_html() -> HTMLResponse:

@app.get('/api')
async def root() -> dict[str, str]:
await app.state.mongodb_db['x'].find_one({''})
await DB_XXX['x'].find_one({'name': 'fastapi'})
return {'Hello': 'World'}


Expand Down
20 changes: 15 additions & 5 deletions cookbook/web/fastapi/fastapi_quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ pipenv install --dev pylint-pydantic
# JWT
pipenv install python-jose[cryptography]
pipenv install types-python-jose

# HTTP Request
pipenv install aiohttp

# MQTT
pipenv install aiomqtt
```

## `pyproject.toml`
Expand Down Expand Up @@ -53,6 +59,9 @@ dependencies = [

"python-jose[cryptography]",
"types-python-jose",

#"aiohttp",
#"aio-mqtt",
]
dynamic = ["version"]

Expand Down Expand Up @@ -121,7 +130,7 @@ follow_imports = "silent"
warn_redundant_casts = true
warn_unused_ignores = true
warn_unused_configs = true
disallow_any_generics = true
disallow_any_generics = false
check_untyped_defs = true
no_implicit_reexport = true
disallow_untyped_defs = true
Expand Down Expand Up @@ -158,14 +167,15 @@ disable = [
"bad-inline-option",
"locally-disabled",
"file-ignored",
"suppressed-message",
"deprecated-pragma",
"use-symbolic-message-instead",
"logging-fstring-interpolation",
"missing-function-docstring",
"missing-class-docstring",
]
enable = [
"c-extension-no-member",
"suppressed-message",
"useless-suppression",
]

Expand Down Expand Up @@ -357,7 +367,6 @@ async def redoc_html() -> HTMLResponse:

@app.get('/api')
async def root() -> dict[str, str]:
await app.state.mongodb_db['x'].find_one({''})
return {'Hello': 'World'}


Expand All @@ -377,8 +386,9 @@ See [Uvicorn: ASGI, WebSockets - Python Cookbook](../uvicorn).

- [Python Project - Python Cookbook](../../build/project)
- [ASGI Web Server: **`Uvicorn`** - Python Cookbook](../uvicorn)
- [Data Model: **`Pydantic`**](../pydantic)
- [with MongoDB: **`motor`**](fastapi_mongodb)
- [Data Model: **`Pydantic`** - Python Cookbook](../pydantic)
- [with MongoDB: **`motor`** - Python Cookbook](fastapi_mongodb)
- [with Redis: **`redis`** - Python Cookbook](../../system_services/redis)

## References

Expand Down
4 changes: 2 additions & 2 deletions django_project/django_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []
ALLOWED_HOSTS: list[str] = []


# Application definition
Expand All @@ -53,7 +53,7 @@

ROOT_URLCONF = 'django_project.urls'

TEMPLATES = [ # type: ignore
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
Expand Down
34 changes: 34 additions & 0 deletions examples/system_services/mqtt_aiomqtt_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""MQTT `aiomqtt` Usage.
"""

import asyncio
import os
import sys

import aiomqtt

MQTT_HOST = 'localhost'
MQTT_TOPIC_PREFIX = 'python-cookbook'


async def main() -> None:
async with aiomqtt.Client(MQTT_HOST, timeout=3.5) as client:

# Subscribe
await client.subscribe(f'{MQTT_TOPIC_PREFIX}/#')
async for message in client.messages:
if isinstance(message.payload, bytes):
print(message.payload.decode('utf-8'))

# Publish
# await client.publish(f'{MQTT_TOPIC_PREFIX}/example', payload={'msg': 'hello'})


# Change to the "Selector" event loop if platform is Windows
if sys.platform.lower() == 'win32' or os.name.lower() == 'nt':
from asyncio import WindowsSelectorEventLoopPolicy # type: ignore
from asyncio import set_event_loop_policy

set_event_loop_policy(WindowsSelectorEventLoopPolicy())

asyncio.run(main())
2 changes: 1 addition & 1 deletion examples/web/fastapi/main_mongodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ async def redoc_html() -> HTMLResponse:

@app.get('/api')
async def root() -> dict[str, str]:
await app.state.mongodb_db['x'].find_one({''})
await DB_XXX['x'].find_one({'name': 'fastapi'})
return {'Hello': 'World'}


Expand Down
1 change: 0 additions & 1 deletion examples/web/fastapi/main_openapi_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ async def redoc_html() -> HTMLResponse:

@app.get('/api')
async def root() -> dict[str, str]:
await app.state.mongodb_db['x'].find_one({''})
return {'Hello': 'World'}


Expand Down
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ dependencies = [

"redis[hiredis]",
"types-redis",

"aiomqtt",

"celery[librabbitmq, mongodb, redis]",
#"requests",
#"types-requests",
Expand Down Expand Up @@ -129,11 +132,14 @@ init_typed = true
warn_required_dynamic_aliases = true
warn_untyped_fields = true

# mypy for MongoDB motor
[[tool.mypy.overrides]]
module = "motor.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "redis.*"
ignore_missing_imports = true

[tool.pylint.main]
recursive = true
py-version = 3.11
Expand Down
Loading

0 comments on commit 104816f

Please sign in to comment.