From 1862ead1f726893ea2b09051d75544c5fc69dc83 Mon Sep 17 00:00:00 2001 From: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:10:39 +0100 Subject: [PATCH 1/3] refactor: initial migration to paho-mqtt 2.0 --- aiomqtt/client.py | 44 +++++++++-------- aiomqtt/exceptions.py | 9 ++-- aiomqtt/message.py | 3 +- aiomqtt/types.py | 6 +-- poetry.lock | 100 ++++++++++++++------------------------- pyproject.toml | 8 ++-- tests/test_client.py | 18 +++---- tests/test_exceptions.py | 5 +- 8 files changed, 88 insertions(+), 105 deletions(-) diff --git a/aiomqtt/client.py b/aiomqtt/client.py index 8d64de4..636601d 100644 --- a/aiomqtt/client.py +++ b/aiomqtt/client.py @@ -21,11 +21,16 @@ Generator, Iterable, Iterator, + Literal, TypeVar, cast, ) import paho.mqtt.client as mqtt +from paho.mqtt.enums import CallbackAPIVersion +from paho.mqtt.properties import Properties +from paho.mqtt.reasoncodes import ReasonCodes +from paho.mqtt.subscribeoptions import SubscribeOptions from .exceptions import MqttCodeError, MqttConnectError, MqttError, MqttReentrantError from .message import Message @@ -116,7 +121,7 @@ class Will: payload: PayloadType | None = None qos: int = 0 retain: bool = False - properties: mqtt.Properties | None = None + properties: Properties | None = None class Client: @@ -185,7 +190,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 protocol: ProtocolVersion | None = None, will: Will | None = None, clean_session: bool | None = None, - transport: str = "tcp", + transport: Literal["tcp", "websockets"] = "tcp", timeout: float | None = None, keepalive: int = 60, bind_address: str = "", @@ -195,7 +200,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 max_queued_outgoing_messages: int | None = None, max_inflight_messages: int | None = None, max_concurrent_outgoing_calls: int | None = None, - properties: mqtt.Properties | None = None, + properties: Properties | None = None, tls_context: ssl.SSLContext | None = None, tls_params: TLSParameters | None = None, tls_insecure: bool | None = None, @@ -220,7 +225,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 # Pending subscribe, unsubscribe, and publish calls self._pending_subscribes: dict[ - int, asyncio.Future[tuple[int] | list[mqtt.ReasonCodes]] + int, asyncio.Future[tuple[int, ...] | list[ReasonCodes]] ] = {} self._pending_unsubscribes: dict[int, asyncio.Event] = {} self._pending_publishes: dict[int, asyncio.Event] = {} @@ -247,6 +252,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 # Create the underlying paho-mqtt client instance self._client: mqtt.Client = mqtt.Client( + callback_api_version=CallbackAPIVersion.VERSION1, client_id=identifier, protocol=protocol, clean_session=clean_session, @@ -322,7 +328,7 @@ def identifier(self) -> str: Note that paho-mqtt stores the client ID as `bytes` internally. We assume that the client ID is a UTF8-encoded string and decode it first. """ - return cast(bytes, self._client._client_id).decode() # type: ignore[attr-defined] # noqa: SLF001 + return self._client._client_id.decode() # noqa: SLF001 @property def _pending_calls(self) -> Generator[int, None, None]: @@ -337,12 +343,12 @@ async def subscribe( # noqa: PLR0913 /, topic: SubscribeTopic, qos: int = 0, - options: mqtt.SubscribeOptions | None = None, - properties: mqtt.Properties | None = None, + options: SubscribeOptions | None = None, + properties: Properties | None = None, *args: Any, timeout: float | None = None, **kwargs: Any, - ) -> tuple[int] | list[mqtt.ReasonCodes]: + ) -> tuple[int] | list[ReasonCodes]: """Subscribe to a topic or wildcard. Args: @@ -366,7 +372,7 @@ async def subscribe( # noqa: PLR0913 raise MqttCodeError(result, "Could not subscribe to topic") # Create future for when the on_subscribe callback is called callback_result: asyncio.Future[ - tuple[int] | list[mqtt.ReasonCodes] + tuple[int] | list[ReasonCodes] ] = asyncio.Future() with self._pending_call(mid, callback_result, self._pending_subscribes): # Wait for callback_result @@ -377,7 +383,7 @@ async def unsubscribe( self, /, topic: str | list[str], - properties: mqtt.Properties | None = None, + properties: Properties | None = None, *args: Any, timeout: float | None = None, **kwargs: Any, @@ -412,7 +418,7 @@ async def publish( # noqa: PLR0913 payload: PayloadType = None, qos: int = 0, retain: bool = False, - properties: mqtt.Properties | None = None, + properties: Properties | None = None, *args: Any, timeout: float | None = None, **kwargs: Any, @@ -518,8 +524,8 @@ def _on_connect( # noqa: PLR0913 client: mqtt.Client, userdata: Any, flags: dict[str, int], - rc: int | mqtt.ReasonCodes, - properties: mqtt.Properties | None = None, + rc: int | ReasonCodes, + properties: Properties | None = None, ) -> None: """Called when we receive a CONNACK message from the broker.""" # Return early if already connected. Sometimes, paho-mqtt calls _on_connect @@ -538,8 +544,8 @@ def _on_disconnect( self, client: mqtt.Client, userdata: Any, - rc: int | mqtt.ReasonCodes | None, - properties: mqtt.Properties | None = None, + rc: int | ReasonCodes | None, + properties: Properties | None = None, ) -> None: # Return early if the disconnect is already acknowledged. # Sometimes (e.g., due to timeouts), paho-mqtt calls _on_disconnect @@ -570,8 +576,8 @@ def _on_subscribe( # noqa: PLR0913 client: mqtt.Client, userdata: Any, mid: int, - granted_qos: tuple[int] | list[mqtt.ReasonCodes], - properties: mqtt.Properties | None = None, + granted_qos: tuple[int, ...] | list[ReasonCodes], + properties: Properties | None = None, ) -> None: """Called when we receive a SUBACK message from the broker.""" try: @@ -588,8 +594,8 @@ def _on_unsubscribe( # noqa: PLR0913 client: mqtt.Client, userdata: Any, mid: int, - properties: mqtt.Properties | None = None, - reason_codes: list[mqtt.ReasonCodes] | mqtt.ReasonCodes | None = None, + properties: Properties | None = None, + reason_codes: list[ReasonCodes] | ReasonCodes | None = None, ) -> None: """Called when we receive an UNSUBACK message from the broker.""" try: diff --git a/aiomqtt/exceptions.py b/aiomqtt/exceptions.py index 6e5baea..e0a0913 100644 --- a/aiomqtt/exceptions.py +++ b/aiomqtt/exceptions.py @@ -4,6 +4,7 @@ from typing import Any import paho.mqtt.client as mqtt +from paho.mqtt.reasoncodes import ReasonCodes class MqttError(Exception): @@ -11,12 +12,12 @@ class MqttError(Exception): class MqttCodeError(MqttError): - def __init__(self, rc: int | mqtt.ReasonCodes | None, *args: Any) -> None: + def __init__(self, rc: int | ReasonCodes | None, *args: Any) -> None: super().__init__(*args) self.rc = rc def __str__(self) -> str: - if isinstance(self.rc, mqtt.ReasonCodes): + if isinstance(self.rc, ReasonCodes): return f"[code:{self.rc.value}] {self.rc!s}" if isinstance(self.rc, int): return f"[code:{self.rc}] {mqtt.error_string(self.rc)}" @@ -24,8 +25,8 @@ def __str__(self) -> str: class MqttConnectError(MqttCodeError): - def __init__(self, rc: int | mqtt.ReasonCodes) -> None: - if isinstance(rc, mqtt.ReasonCodes): + def __init__(self, rc: int | ReasonCodes) -> None: + if isinstance(rc, ReasonCodes): super().__init__(rc) return msg = "Connection refused" diff --git a/aiomqtt/message.py b/aiomqtt/message.py index 133b67e..6f6fb27 100644 --- a/aiomqtt/message.py +++ b/aiomqtt/message.py @@ -4,6 +4,7 @@ import sys import paho.mqtt.client as mqtt +from paho.mqtt.properties import Properties if sys.version_info >= (3, 11): from typing import Self @@ -50,7 +51,7 @@ def __init__( # noqa: PLR0913 qos: int, retain: bool, mid: int, - properties: mqtt.Properties | None, + properties: Properties | None, ) -> None: self.topic = Topic(topic) if not isinstance(topic, Topic) else topic self.payload = payload diff --git a/aiomqtt/types.py b/aiomqtt/types.py index 039a76b..61438b0 100644 --- a/aiomqtt/types.py +++ b/aiomqtt/types.py @@ -6,7 +6,7 @@ import sys from typing import Any, Callable, TypeVar -import paho.mqtt.client as mqtt +from paho.mqtt.subscribeoptions import SubscribeOptions if sys.version_info >= (3, 10): from typing import ParamSpec, TypeAlias @@ -18,10 +18,10 @@ P = ParamSpec("P") PayloadType: TypeAlias = "str | bytes | bytearray | int | float | None" -SubscribeTopic: TypeAlias = "str | tuple[str, mqtt.SubscribeOptions] | list[tuple[str, mqtt.SubscribeOptions]] | list[tuple[str, int]]" +SubscribeTopic: TypeAlias = "str | tuple[str, SubscribeOptions] | list[tuple[str, SubscribeOptions]] | list[tuple[str, int]]" WebSocketHeaders: TypeAlias = ( "dict[str, str] | Callable[[dict[str, str]], dict[str, str]]" ) -_PahoSocket: TypeAlias = "socket.socket | ssl.SSLSocket | mqtt.WebsocketWrapper | Any" +_PahoSocket: TypeAlias = "socket.socket | ssl.SSLSocket | Any" # See the overloads of `socket.setsockopt` for details. SocketOption: TypeAlias = "tuple[int, int, int | bytes] | tuple[int, int, None, int]" diff --git a/poetry.lock b/poetry.lock index ce6a4a1..fd0a97d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "alabaster" @@ -414,16 +414,6 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -488,38 +478,38 @@ files = [ [[package]] name = "mypy" -version = "1.8.0" +version = "1.9.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, + {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, + {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, + {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, + {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, + {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, + {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, + {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, + {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, + {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, + {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, + {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, + {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, + {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, + {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, + {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, + {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, + {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, ] [package.dependencies] @@ -583,16 +573,17 @@ files = [ [[package]] name = "paho-mqtt" -version = "1.6.1" +version = "2.0.0" description = "MQTT version 5.0/3.1.1 client class" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "paho-mqtt-1.6.1.tar.gz", hash = "sha256:2a8291c81623aec00372b5a85558a372c747cbca8e9934dfe218638b8eefc26f"}, + {file = "paho_mqtt-2.0.0-py3-none-any.whl", hash = "sha256:2ef745073dfc9aa68bfec30d0b9b6f0304ea75182bae85a7c77a80cefce1eff5"}, + {file = "paho_mqtt-2.0.0.tar.gz", hash = "sha256:13b205f29251e4f2c66a6c923c31fc4fd780561e03b2d775cff8e4f2915cf947"}, ] [package.extras] -proxy = ["PySocks"] +proxy = ["pysocks"] [[package]] name = "pluggy" @@ -686,7 +677,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -694,15 +684,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -719,7 +702,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -727,7 +709,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1033,17 +1014,6 @@ files = [ {file = "tornado-6.3.3.tar.gz", hash = "sha256:e7d8db41c0181c80d76c982aacc442c0783a2c54d6400fe028954201a2e032fe"}, ] -[[package]] -name = "types-paho-mqtt" -version = "1.6.0.7" -description = "Typing stubs for paho-mqtt" -optional = false -python-versions = "*" -files = [ - {file = "types-paho-mqtt-1.6.0.7.tar.gz", hash = "sha256:fe34c68abc849cd96e1482138bbdf5f465de59629dd367cb3a2423dd9ca3220b"}, - {file = "types_paho_mqtt-1.6.0.7-py3-none-any.whl", hash = "sha256:50313d93f63d777da391acaac0278d346cf9e4a2576d814989d6500bd0ca4a35"}, -] - [[package]] name = "typing-extensions" version = "4.7.1" @@ -1090,4 +1060,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "14edfc0e4acfb8cfc32adf72ff8e2dce8a3a41ef3c2cb9a5b74e683386868903" +content-hash = "c3b552ed6bd7864b8437dadcec211382d038f518e811385b8dc1364780e033a0" diff --git a/pyproject.toml b/pyproject.toml index 069c373..02ab6d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,16 +20,15 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8" -paho-mqtt = "^1.6.0" +paho-mqtt = "^2.0.0" typing-extensions = {version = "^4.4.0", markers = "python_version < '3.10'"} [tool.poetry.group.dev] optional = true [tool.poetry.group.dev.dependencies] -mypy = "^1.8.0" +mypy = "^1.9.0" ruff = "^0.1.9" -types-paho-mqtt = "^1.6.0.7" pytest = "^7.3.1" pytest-cov = "^4.0.0" anyio = "^3.6.2" @@ -137,6 +136,9 @@ pretty = true filterwarnings = [ "error", "ignore:ssl.PROTOCOL_TLS is deprecated:DeprecationWarning", + # TODO(jonathan): Remove these once we finish the migration to the new API + "ignore:ReasonCodes is deprecated, use ReasonCode \\(singular\\) instead:DeprecationWarning", + "ignore:Callback API version 1 is deprecated, update to latest version:DeprecationWarning", ] markers = [ "network: tests that requires network access" diff --git a/tests/test_client.py b/tests/test_client.py index 333a882..d1a49c1 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -11,6 +11,8 @@ import pytest from anyio import TASK_STATUS_IGNORED from anyio.abc import TaskStatus +from paho.mqtt.properties import Properties +from paho.mqtt.subscribeoptions import SubscribeOptions from aiomqtt import ( Client, @@ -85,7 +87,7 @@ async def launch_client() -> None: tg.start_soon(launch_client) await event.wait() async with Client(HOSTNAME, will=Will(topic)) as client: - client._client._sock_close() # type: ignore[attr-defined] + client._client._sock_close() @pytest.mark.network @@ -152,7 +154,7 @@ async def handle(tg: anyio.abc.TaskGroup) -> None: async def test_client_logger() -> None: logger = logging.getLogger("aiomqtt") async with Client(HOSTNAME, logger=logger) as client: - assert logger is client._client._logger # type: ignore[attr-defined] + assert logger is client._client._logger @pytest.mark.network @@ -165,19 +167,19 @@ class MockPahoClient(mqtt.Client): def subscribe( self, topic: str - | tuple[str, mqtt.SubscribeOptions] - | list[tuple[str, mqtt.SubscribeOptions]] + | tuple[str, SubscribeOptions] + | list[tuple[str, SubscribeOptions]] | list[tuple[str, int]], qos: int = 0, - options: mqtt.SubscribeOptions | None = None, - properties: mqtt.Properties | None = None, + options: SubscribeOptions | None = None, + properties: Properties | None = None, ) -> tuple[int, int]: assert client._outgoing_calls_sem is not None assert client._outgoing_calls_sem.locked() return super().subscribe(topic, qos, options, properties) def unsubscribe( - self, topic: str | list[str], properties: mqtt.Properties | None = None + self, topic: str | list[str], properties: Properties | None = None ) -> tuple[int, int]: assert client._outgoing_calls_sem is not None assert client._outgoing_calls_sem.locked() @@ -189,7 +191,7 @@ def publish( # noqa: PLR0913 payload: PayloadType | None = None, qos: int = 0, retain: bool = False, - properties: mqtt.Properties | None = None, + properties: Properties | None = None, ) -> mqtt.MQTTMessageInfo: assert client._outgoing_calls_sem is not None assert client._outgoing_calls_sem.locked() diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 4a24928..bc31761 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,6 +1,7 @@ import paho.mqtt.client as mqtt import pytest from paho.mqtt.packettypes import PacketTypes +from paho.mqtt.reasoncodes import ReasonCodes from aiomqtt.exceptions import _CONNECT_RC_STRINGS, MqttCodeError, MqttConnectError @@ -41,7 +42,7 @@ def test_mqtt_code_error_int(rc: int) -> None: ], ) def test_mqtt_code_error_reason_codes(packet_type: int, a_name: str) -> None: - rc = mqtt.ReasonCodes(packet_type, a_name) + rc = ReasonCodes(packet_type, a_name) assert str(MqttCodeError(rc)) == f"[code:{rc.value}] {rc!s}" @@ -68,5 +69,5 @@ def test_mqtt_connect_error_int(rc: int, message: str) -> None: ], ) def test_mqtt_connect_error_reason_codes(packet_type: int, a_name: str) -> None: - rc = mqtt.ReasonCodes(packet_type, a_name) + rc = ReasonCodes(packet_type, a_name) assert str(MqttConnectError(rc)) == f"[code:{rc.value}] {rc!s}" From 8c72a1ae5cba421df4eda2507a0157c97dd32c0a Mon Sep 17 00:00:00 2001 From: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com> Date: Sun, 24 Mar 2024 08:33:49 +0100 Subject: [PATCH 2/3] fix: MyPy errors --- aiomqtt/client.py | 22 +++++++++++----------- aiomqtt/exceptions.py | 10 +++++----- poetry.lock | 16 ++++++++++------ pyproject.toml | 3 +-- tests/test_client.py | 10 ++++++---- tests/test_exceptions.py | 6 +++--- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/aiomqtt/client.py b/aiomqtt/client.py index 636601d..1a1ad76 100644 --- a/aiomqtt/client.py +++ b/aiomqtt/client.py @@ -29,7 +29,7 @@ import paho.mqtt.client as mqtt from paho.mqtt.enums import CallbackAPIVersion from paho.mqtt.properties import Properties -from paho.mqtt.reasoncodes import ReasonCodes +from paho.mqtt.reasoncodes import ReasonCode from paho.mqtt.subscribeoptions import SubscribeOptions from .exceptions import MqttCodeError, MqttConnectError, MqttError, MqttReentrantError @@ -195,7 +195,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 keepalive: int = 60, bind_address: str = "", bind_port: int = 0, - clean_start: int = mqtt.MQTT_CLEAN_START_FIRST_ONLY, + clean_start: mqtt.CleanStartOption = mqtt.MQTT_CLEAN_START_FIRST_ONLY, max_queued_incoming_messages: int | None = None, max_queued_outgoing_messages: int | None = None, max_inflight_messages: int | None = None, @@ -225,7 +225,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 # Pending subscribe, unsubscribe, and publish calls self._pending_subscribes: dict[ - int, asyncio.Future[tuple[int, ...] | list[ReasonCodes]] + int, asyncio.Future[tuple[int, ...] | list[ReasonCode]] ] = {} self._pending_unsubscribes: dict[int, asyncio.Event] = {} self._pending_publishes: dict[int, asyncio.Event] = {} @@ -348,7 +348,7 @@ async def subscribe( # noqa: PLR0913 *args: Any, timeout: float | None = None, **kwargs: Any, - ) -> tuple[int] | list[ReasonCodes]: + ) -> tuple[int, ...] | list[ReasonCode]: """Subscribe to a topic or wildcard. Args: @@ -368,11 +368,11 @@ async def subscribe( # noqa: PLR0913 topic, qos, options, properties, *args, **kwargs ) # Early out on error - if result != mqtt.MQTT_ERR_SUCCESS: + if result != mqtt.MQTT_ERR_SUCCESS or mid is None: raise MqttCodeError(result, "Could not subscribe to topic") # Create future for when the on_subscribe callback is called callback_result: asyncio.Future[ - tuple[int] | list[ReasonCodes] + tuple[int, ...] | list[ReasonCode] ] = asyncio.Future() with self._pending_call(mid, callback_result, self._pending_subscribes): # Wait for callback_result @@ -402,7 +402,7 @@ async def unsubscribe( """ result, mid = self._client.unsubscribe(topic, properties, *args, **kwargs) # Early out on error - if result != mqtt.MQTT_ERR_SUCCESS: + if result != mqtt.MQTT_ERR_SUCCESS or mid is None: raise MqttCodeError(result, "Could not unsubscribe from topic") # Create event for when the on_unsubscribe callback is called confirmation = asyncio.Event() @@ -524,7 +524,7 @@ def _on_connect( # noqa: PLR0913 client: mqtt.Client, userdata: Any, flags: dict[str, int], - rc: int | ReasonCodes, + rc: int | ReasonCode, properties: Properties | None = None, ) -> None: """Called when we receive a CONNACK message from the broker.""" @@ -544,7 +544,7 @@ def _on_disconnect( self, client: mqtt.Client, userdata: Any, - rc: int | ReasonCodes | None, + rc: int | ReasonCode | None, properties: Properties | None = None, ) -> None: # Return early if the disconnect is already acknowledged. @@ -576,7 +576,7 @@ def _on_subscribe( # noqa: PLR0913 client: mqtt.Client, userdata: Any, mid: int, - granted_qos: tuple[int, ...] | list[ReasonCodes], + granted_qos: tuple[int, ...] | list[ReasonCode], properties: Properties | None = None, ) -> None: """Called when we receive a SUBACK message from the broker.""" @@ -595,7 +595,7 @@ def _on_unsubscribe( # noqa: PLR0913 userdata: Any, mid: int, properties: Properties | None = None, - reason_codes: list[ReasonCodes] | ReasonCodes | None = None, + reason_codes: list[ReasonCode] | ReasonCode | None = None, ) -> None: """Called when we receive an UNSUBACK message from the broker.""" try: diff --git a/aiomqtt/exceptions.py b/aiomqtt/exceptions.py index e0a0913..e6ddc8c 100644 --- a/aiomqtt/exceptions.py +++ b/aiomqtt/exceptions.py @@ -4,7 +4,7 @@ from typing import Any import paho.mqtt.client as mqtt -from paho.mqtt.reasoncodes import ReasonCodes +from paho.mqtt.reasoncodes import ReasonCode class MqttError(Exception): @@ -12,12 +12,12 @@ class MqttError(Exception): class MqttCodeError(MqttError): - def __init__(self, rc: int | ReasonCodes | None, *args: Any) -> None: + def __init__(self, rc: int | ReasonCode | None, *args: Any) -> None: super().__init__(*args) self.rc = rc def __str__(self) -> str: - if isinstance(self.rc, ReasonCodes): + if isinstance(self.rc, ReasonCode): return f"[code:{self.rc.value}] {self.rc!s}" if isinstance(self.rc, int): return f"[code:{self.rc}] {mqtt.error_string(self.rc)}" @@ -25,8 +25,8 @@ def __str__(self) -> str: class MqttConnectError(MqttCodeError): - def __init__(self, rc: int | ReasonCodes) -> None: - if isinstance(rc, ReasonCodes): + def __init__(self, rc: int | ReasonCode) -> None: + if isinstance(rc, ReasonCode): super().__init__(rc) return msg = "Connection refused" diff --git a/poetry.lock b/poetry.lock index fd0a97d..137cacc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -573,18 +573,22 @@ files = [ [[package]] name = "paho-mqtt" -version = "2.0.0" +version = "2.0.1.dev0" description = "MQTT version 5.0/3.1.1 client class" optional = false python-versions = ">=3.7" -files = [ - {file = "paho_mqtt-2.0.0-py3-none-any.whl", hash = "sha256:2ef745073dfc9aa68bfec30d0b9b6f0304ea75182bae85a7c77a80cefce1eff5"}, - {file = "paho_mqtt-2.0.0.tar.gz", hash = "sha256:13b205f29251e4f2c66a6c923c31fc4fd780561e03b2d775cff8e4f2915cf947"}, -] +files = [] +develop = false [package.extras] proxy = ["pysocks"] +[package.source] +type = "git" +url = "https://github.com/JonathanPlasse/paho.mqtt.python.git" +reference = "fix-type-annotations" +resolved_reference = "34e74068675b63ae60f3fc4f97f42b77d85f3274" + [[package]] name = "pluggy" version = "1.2.0" @@ -1060,4 +1064,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "c3b552ed6bd7864b8437dadcec211382d038f518e811385b8dc1364780e033a0" +content-hash = "3163fac664d09732007fadec3786321dbcf913afe7a96bda3104143094b56bdb" diff --git a/pyproject.toml b/pyproject.toml index 02ab6d1..56b0c80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8" -paho-mqtt = "^2.0.0" +paho-mqtt = {git = "https://github.com/JonathanPlasse/paho.mqtt.python.git", rev = "fix-type-annotations"} typing-extensions = {version = "^4.4.0", markers = "python_version < '3.10'"} [tool.poetry.group.dev] @@ -137,7 +137,6 @@ filterwarnings = [ "error", "ignore:ssl.PROTOCOL_TLS is deprecated:DeprecationWarning", # TODO(jonathan): Remove these once we finish the migration to the new API - "ignore:ReasonCodes is deprecated, use ReasonCode \\(singular\\) instead:DeprecationWarning", "ignore:Callback API version 1 is deprecated, update to latest version:DeprecationWarning", ] markers = [ diff --git a/tests/test_client.py b/tests/test_client.py index d1a49c1..f4be910 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -11,6 +11,7 @@ import pytest from anyio import TASK_STATUS_IGNORED from anyio.abc import TaskStatus +from paho.mqtt.enums import MQTTErrorCode from paho.mqtt.properties import Properties from paho.mqtt.subscribeoptions import SubscribeOptions @@ -167,20 +168,21 @@ class MockPahoClient(mqtt.Client): def subscribe( self, topic: str + | tuple[str, int] | tuple[str, SubscribeOptions] - | list[tuple[str, SubscribeOptions]] - | list[tuple[str, int]], + | list[tuple[str, int]] + | list[tuple[str, SubscribeOptions]], qos: int = 0, options: SubscribeOptions | None = None, properties: Properties | None = None, - ) -> tuple[int, int]: + ) -> tuple[MQTTErrorCode, int | None]: assert client._outgoing_calls_sem is not None assert client._outgoing_calls_sem.locked() return super().subscribe(topic, qos, options, properties) def unsubscribe( self, topic: str | list[str], properties: Properties | None = None - ) -> tuple[int, int]: + ) -> tuple[MQTTErrorCode, int | None]: assert client._outgoing_calls_sem is not None assert client._outgoing_calls_sem.locked() return super().unsubscribe(topic, properties) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index bc31761..306e878 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,7 +1,7 @@ import paho.mqtt.client as mqtt import pytest from paho.mqtt.packettypes import PacketTypes -from paho.mqtt.reasoncodes import ReasonCodes +from paho.mqtt.reasoncodes import ReasonCode from aiomqtt.exceptions import _CONNECT_RC_STRINGS, MqttCodeError, MqttConnectError @@ -42,7 +42,7 @@ def test_mqtt_code_error_int(rc: int) -> None: ], ) def test_mqtt_code_error_reason_codes(packet_type: int, a_name: str) -> None: - rc = ReasonCodes(packet_type, a_name) + rc = ReasonCode(packet_type, a_name) assert str(MqttCodeError(rc)) == f"[code:{rc.value}] {rc!s}" @@ -69,5 +69,5 @@ def test_mqtt_connect_error_int(rc: int, message: str) -> None: ], ) def test_mqtt_connect_error_reason_codes(packet_type: int, a_name: str) -> None: - rc = ReasonCodes(packet_type, a_name) + rc = ReasonCode(packet_type, a_name) assert str(MqttConnectError(rc)) == f"[code:{rc.value}] {rc!s}" From 93014c141ea6cd6c371b071fed3a527bb9cca312 Mon Sep 17 00:00:00 2001 From: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com> Date: Sun, 24 Mar 2024 08:37:17 +0100 Subject: [PATCH 3/3] refactor: use paho-mqtt v2.0.0 with type ignores --- aiomqtt/client.py | 4 ++-- aiomqtt/exceptions.py | 2 +- poetry.lock | 16 ++++++---------- pyproject.toml | 2 +- tests/test_client.py | 2 +- tests/test_exceptions.py | 8 ++++---- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/aiomqtt/client.py b/aiomqtt/client.py index 1a1ad76..4e52517 100644 --- a/aiomqtt/client.py +++ b/aiomqtt/client.py @@ -253,7 +253,7 @@ def __init__( # noqa: C901, PLR0912, PLR0913, PLR0915 # Create the underlying paho-mqtt client instance self._client: mqtt.Client = mqtt.Client( callback_api_version=CallbackAPIVersion.VERSION1, - client_id=identifier, + client_id=identifier, # type: ignore[arg-type] protocol=protocol, clean_session=clean_session, transport=transport, @@ -400,7 +400,7 @@ async def unsubscribe( **kwargs: Additional keyword arguments to pass to paho-mqtt's unsubscribe method. """ - result, mid = self._client.unsubscribe(topic, properties, *args, **kwargs) + result, mid = self._client.unsubscribe(topic, properties, *args, **kwargs) # type: ignore[arg-type] # Early out on error if result != mqtt.MQTT_ERR_SUCCESS or mid is None: raise MqttCodeError(result, "Could not unsubscribe from topic") diff --git a/aiomqtt/exceptions.py b/aiomqtt/exceptions.py index e6ddc8c..3763e05 100644 --- a/aiomqtt/exceptions.py +++ b/aiomqtt/exceptions.py @@ -20,7 +20,7 @@ def __str__(self) -> str: if isinstance(self.rc, ReasonCode): return f"[code:{self.rc.value}] {self.rc!s}" if isinstance(self.rc, int): - return f"[code:{self.rc}] {mqtt.error_string(self.rc)}" + return f"[code:{self.rc}] {mqtt.error_string(self.rc)}" # type: ignore[arg-type] return f"[code:{self.rc}] {super().__str__()}" diff --git a/poetry.lock b/poetry.lock index 137cacc..fd0a97d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -573,22 +573,18 @@ files = [ [[package]] name = "paho-mqtt" -version = "2.0.1.dev0" +version = "2.0.0" description = "MQTT version 5.0/3.1.1 client class" optional = false python-versions = ">=3.7" -files = [] -develop = false +files = [ + {file = "paho_mqtt-2.0.0-py3-none-any.whl", hash = "sha256:2ef745073dfc9aa68bfec30d0b9b6f0304ea75182bae85a7c77a80cefce1eff5"}, + {file = "paho_mqtt-2.0.0.tar.gz", hash = "sha256:13b205f29251e4f2c66a6c923c31fc4fd780561e03b2d775cff8e4f2915cf947"}, +] [package.extras] proxy = ["pysocks"] -[package.source] -type = "git" -url = "https://github.com/JonathanPlasse/paho.mqtt.python.git" -reference = "fix-type-annotations" -resolved_reference = "34e74068675b63ae60f3fc4f97f42b77d85f3274" - [[package]] name = "pluggy" version = "1.2.0" @@ -1064,4 +1060,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "3163fac664d09732007fadec3786321dbcf913afe7a96bda3104143094b56bdb" +content-hash = "c3b552ed6bd7864b8437dadcec211382d038f518e811385b8dc1364780e033a0" diff --git a/pyproject.toml b/pyproject.toml index 56b0c80..4a0d018 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8" -paho-mqtt = {git = "https://github.com/JonathanPlasse/paho.mqtt.python.git", rev = "fix-type-annotations"} +paho-mqtt = "^2.0.0" typing-extensions = {version = "^4.4.0", markers = "python_version < '3.10'"} [tool.poetry.group.dev] diff --git a/tests/test_client.py b/tests/test_client.py index f4be910..6caede1 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -185,7 +185,7 @@ def unsubscribe( ) -> tuple[MQTTErrorCode, int | None]: assert client._outgoing_calls_sem is not None assert client._outgoing_calls_sem.locked() - return super().unsubscribe(topic, properties) + return super().unsubscribe(topic, properties) # type: ignore[arg-type] def publish( # noqa: PLR0913 self, diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 306e878..11e445e 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -30,7 +30,7 @@ ], ) def test_mqtt_code_error_int(rc: int) -> None: - assert str(MqttCodeError(rc)) == f"[code:{rc}] {mqtt.error_string(rc)}" + assert str(MqttCodeError(rc)) == f"[code:{rc}] {mqtt.error_string(rc)}" # type: ignore[arg-type] @pytest.mark.parametrize( @@ -42,7 +42,7 @@ def test_mqtt_code_error_int(rc: int) -> None: ], ) def test_mqtt_code_error_reason_codes(packet_type: int, a_name: str) -> None: - rc = ReasonCode(packet_type, a_name) + rc = ReasonCode(packet_type, a_name) # type: ignore[no-untyped-call] assert str(MqttCodeError(rc)) == f"[code:{rc.value}] {rc!s}" @@ -57,7 +57,7 @@ def test_mqtt_connect_error_int(rc: int, message: str) -> None: if rc in _CONNECT_RC_STRINGS: arg += f": {message}" assert error.args[0] == arg - assert str(error) == f"[code:{rc}] {mqtt.error_string(rc)}" + assert str(error) == f"[code:{rc}] {mqtt.error_string(rc)}" # type: ignore[arg-type] @pytest.mark.parametrize( @@ -69,5 +69,5 @@ def test_mqtt_connect_error_int(rc: int, message: str) -> None: ], ) def test_mqtt_connect_error_reason_codes(packet_type: int, a_name: str) -> None: - rc = ReasonCode(packet_type, a_name) + rc = ReasonCode(packet_type, a_name) # type: ignore[no-untyped-call] assert str(MqttConnectError(rc)) == f"[code:{rc.value}] {rc!s}"