From 68f1a3819d40d5b4b5a0abdb33e68a69fd54b08b Mon Sep 17 00:00:00 2001 From: "alex.oleshkevich" Date: Wed, 3 Apr 2024 22:00:19 +0200 Subject: [PATCH 1/5] update linting tools, sync lint configs with starlette, improve typings --- .github/workflows/test-suite.yml | 2 +- broadcaster/_backends/kafka.py | 4 +++- broadcaster/_backends/memory.py | 6 ++++-- broadcaster/_backends/postgres.py | 2 +- broadcaster/_base.py | 22 ++++++++++------------ pyproject.toml | 9 +++++++-- requirements.txt | 19 +++++++++---------- scripts/check | 4 ++-- scripts/lint | 6 +++--- tests/test_broadcast.py | 5 ++--- tests/test_unsubscribe.py | 1 + 11 files changed, 43 insertions(+), 37 deletions(-) diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 900834d..13fb4a0 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11-dev"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13-dev"] services: zookeeper: diff --git a/broadcaster/_backends/kafka.py b/broadcaster/_backends/kafka.py index 18b88d2..e577769 100644 --- a/broadcaster/_backends/kafka.py +++ b/broadcaster/_backends/kafka.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import typing from urllib.parse import urlparse @@ -10,7 +12,7 @@ class KafkaBackend(BroadcastBackend): def __init__(self, url: str): self._servers = [urlparse(url).netloc] - self._consumer_channels: typing.Set = set() + self._consumer_channels: set[str] = set() async def connect(self) -> None: self._producer = AIOKafkaProducer(bootstrap_servers=self._servers) diff --git a/broadcaster/_backends/memory.py b/broadcaster/_backends/memory.py index 5a9fa53..bfd0c44 100644 --- a/broadcaster/_backends/memory.py +++ b/broadcaster/_backends/memory.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import asyncio import typing @@ -7,10 +9,10 @@ class MemoryBackend(BroadcastBackend): def __init__(self, url: str): - self._subscribed: typing.Set = set() + self._subscribed: set[str] = set() async def connect(self) -> None: - self._published: asyncio.Queue = asyncio.Queue() + self._published: asyncio.Queue[Event] = asyncio.Queue() async def disconnect(self) -> None: pass diff --git a/broadcaster/_backends/postgres.py b/broadcaster/_backends/postgres.py index 47ef4f6..7769962 100644 --- a/broadcaster/_backends/postgres.py +++ b/broadcaster/_backends/postgres.py @@ -13,7 +13,7 @@ def __init__(self, url: str): async def connect(self) -> None: self._conn = await asyncpg.connect(self._url) - self._listen_queue: asyncio.Queue = asyncio.Queue() + self._listen_queue: asyncio.Queue[Event] = asyncio.Queue() async def disconnect(self) -> None: await self._conn.close() diff --git a/broadcaster/_base.py b/broadcaster/_base.py index c8dc221..e958fdb 100644 --- a/broadcaster/_base.py +++ b/broadcaster/_base.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import asyncio from contextlib import asynccontextmanager -from typing import Any, AsyncGenerator, AsyncIterator, Dict, Optional +from typing import Any, AsyncGenerator, AsyncIterator from urllib.parse import urlparse @@ -10,11 +12,7 @@ def __init__(self, channel: str, message: str) -> None: self.message = message def __eq__(self, other: object) -> bool: - return ( - isinstance(other, Event) - and self.channel == other.channel - and self.message == other.message - ) + return isinstance(other, Event) and self.channel == other.channel and self.message == other.message def __repr__(self) -> str: return f"Event(channel={self.channel!r}, message={self.message!r})" @@ -30,7 +28,7 @@ def __init__(self, url: str): parsed_url = urlparse(url) self._backend: BroadcastBackend - self._subscribers: Dict[str, Any] = {} + self._subscribers: dict[str, set[asyncio.Queue[Event | None]]] = {} if parsed_url.scheme in ("redis", "rediss"): from broadcaster._backends.redis import RedisBackend @@ -51,7 +49,7 @@ def __init__(self, url: str): self._backend = MemoryBackend(url) - async def __aenter__(self) -> "Broadcast": + async def __aenter__(self) -> Broadcast: await self.connect() return self @@ -79,8 +77,8 @@ async def publish(self, channel: str, message: Any) -> None: await self._backend.publish(channel, message) @asynccontextmanager - async def subscribe(self, channel: str) -> AsyncIterator["Subscriber"]: - queue: asyncio.Queue = asyncio.Queue() + async def subscribe(self, channel: str) -> AsyncIterator[Subscriber]: + queue: asyncio.Queue[Event | None] = asyncio.Queue() try: if not self._subscribers.get(channel): @@ -99,10 +97,10 @@ async def subscribe(self, channel: str) -> AsyncIterator["Subscriber"]: class Subscriber: - def __init__(self, queue: asyncio.Queue) -> None: + def __init__(self, queue: asyncio.Queue[Event | None]) -> None: self._queue = queue - async def __aiter__(self) -> Optional[AsyncGenerator]: + async def __aiter__(self) -> AsyncGenerator[Event | None, None] | None: try: while True: yield await self.get() diff --git a/pyproject.toml b/pyproject.toml index 10f7cc5..a3f7239 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,8 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dependencies = [ "anyio>=3.4.0,<5", @@ -48,14 +50,17 @@ include = [ ] [tool.ruff] -ignore = [] line-length = 120 -select = ["E","F","W"] + +[tool.ruff.lint] +select = ["E", "F", "I", "FA", "UP"] [tool.ruff.isort] combine-as-imports = true [tool.mypy] +strict = true +python_version = "3.8" disallow_untyped_defs = true ignore_missing_imports = true diff --git a/requirements.txt b/requirements.txt index dcf0fcf..9d863df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,17 @@ -e .[redis,postgres,kafka] # Documentation -mkdocs==1.3.1 +mkdocs==1.5.3 +mkdocs-material==9.5.12 mkautodoc==0.2.0 -mkdocs-material==8.4.0 # Packaging -build==0.10.0 -twine==4.0.1 +build==1.1.1 +twine==5.0.0 # Tests & Linting -ruff==0.0.277 -black==22.6.0 -coverage==6.4.4 -mypy==0.971 -pytest==7.1.2 -pytest-asyncio==0.19.0 \ No newline at end of file +ruff==0.1.15 +coverage==7.4.3 +mypy==1.8.0 +pytest==8.0.2 +pytest-asyncio==0.23.6 \ No newline at end of file diff --git a/scripts/check b/scripts/check index e514548..d8fb02b 100755 --- a/scripts/check +++ b/scripts/check @@ -8,6 +8,6 @@ export SOURCE_FILES="broadcaster tests" set -x -${PREFIX}black --check --diff --target-version=py37 $SOURCE_FILES -${PREFIX}ruff check $SOURCE_FILES +${PREFIX}ruff format --check --diff $SOURCE_FILES ${PREFIX}mypy $SOURCE_FILES +${PREFIX}ruff check $SOURCE_FILES diff --git a/scripts/lint b/scripts/lint index 4751285..d71af20 100755 --- a/scripts/lint +++ b/scripts/lint @@ -1,12 +1,12 @@ #!/bin/sh -e export PREFIX="" -if [ -d 'venv' ]; then +if [ -d 'venv' ] ; then export PREFIX="venv/bin/" fi export SOURCE_FILES="broadcaster tests" set -x -${PREFIX}ruff --fix $SOURCE_FILES -${PREFIX}black --target-version=py37 $SOURCE_FILES +${PREFIX}ruff format $SOURCE_FILES +${PREFIX}ruff --fix $SOURCE_FILES \ No newline at end of file diff --git a/tests/test_broadcast.py b/tests/test_broadcast.py index e3313bc..f57f61c 100644 --- a/tests/test_broadcast.py +++ b/tests/test_broadcast.py @@ -9,6 +9,7 @@ async def test_memory(): async with broadcast.subscribe("chatroom") as subscriber: await broadcast.publish("chatroom", "hello") event = await subscriber.get() + assert event assert event.channel == "chatroom" assert event.message == "hello" @@ -25,9 +26,7 @@ async def test_redis(): @pytest.mark.asyncio async def test_postgres(): - async with Broadcast( - "postgres://postgres:postgres@localhost:5432/broadcaster" - ) as broadcast: + async with Broadcast("postgres://postgres:postgres@localhost:5432/broadcaster") as broadcast: async with broadcast.subscribe("chatroom") as subscriber: await broadcast.publish("chatroom", "hello") event = await subscriber.get() diff --git a/tests/test_unsubscribe.py b/tests/test_unsubscribe.py index 30f928b..ae89401 100644 --- a/tests/test_unsubscribe.py +++ b/tests/test_unsubscribe.py @@ -1,4 +1,5 @@ import pytest + from broadcaster import Broadcast From b124c69117d27150fcdb2ca5589a006bc31523ab Mon Sep 17 00:00:00 2001 From: "alex.oleshkevich" Date: Wed, 3 Apr 2024 22:18:27 +0200 Subject: [PATCH 2/5] disable 3.13-dev as asyncpg cannot be build yet --- .github/workflows/test-suite.yml | 2 +- .python-version | 1 + pyproject.toml | 1 - tests/test_broadcast.py | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 .python-version diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 13fb4a0..81db761 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13-dev"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] services: zookeeper: diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..014e2ea --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13.0a3 diff --git a/pyproject.toml b/pyproject.toml index a3f7239..4bbd2fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", ] dependencies = [ "anyio>=3.4.0,<5", diff --git a/tests/test_broadcast.py b/tests/test_broadcast.py index f57f61c..0508f54 100644 --- a/tests/test_broadcast.py +++ b/tests/test_broadcast.py @@ -9,7 +9,6 @@ async def test_memory(): async with broadcast.subscribe("chatroom") as subscriber: await broadcast.publish("chatroom", "hello") event = await subscriber.get() - assert event assert event.channel == "chatroom" assert event.message == "hello" From 634c4ea17718d1f4f21bcc80d24b12748d527ef6 Mon Sep 17 00:00:00 2001 From: "alex.oleshkevich" Date: Thu, 4 Apr 2024 11:26:59 +0200 Subject: [PATCH 3/5] remove .python-version --- .python-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .python-version diff --git a/.python-version b/.python-version deleted file mode 100644 index 014e2ea..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.13.0a3 From 82624b67d5ca673d448abc3d50b3402555ff5cb8 Mon Sep 17 00:00:00 2001 From: Alex Oleshkevich Date: Thu, 4 Apr 2024 17:52:14 +0200 Subject: [PATCH 4/5] Update scripts/lint Co-authored-by: Zanie Blue --- scripts/lint | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/lint b/scripts/lint index d71af20..cb718d0 100755 --- a/scripts/lint +++ b/scripts/lint @@ -9,4 +9,4 @@ export SOURCE_FILES="broadcaster tests" set -x ${PREFIX}ruff format $SOURCE_FILES -${PREFIX}ruff --fix $SOURCE_FILES \ No newline at end of file +${PREFIX}ruff check --fix $SOURCE_FILES \ No newline at end of file From 3bbc011e98f5ac538787bc3a5817b43e7f920b5e Mon Sep 17 00:00:00 2001 From: "alex.oleshkevich" Date: Thu, 4 Apr 2024 17:54:05 +0200 Subject: [PATCH 5/5] update ruff --- pyproject.toml | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4bbd2fd..c4e8036 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ line-length = 120 [tool.ruff.lint] select = ["E", "F", "I", "FA", "UP"] -[tool.ruff.isort] +[tool.ruff.lint.isort] combine-as-imports = true [tool.mypy] diff --git a/requirements.txt b/requirements.txt index 9d863df..ed2926b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ build==1.1.1 twine==5.0.0 # Tests & Linting -ruff==0.1.15 +ruff==0.3.5 coverage==7.4.3 mypy==1.8.0 pytest==8.0.2