diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 12cf0dd..ebf9241 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,23 @@ +4.3.0 (2025-07-22) +------------------ + +* Added support for Python 3.13. + +* Dropped support for EOL Python 3.8. + +* Updated Channels dependency to at least v4.2.2. + +* Updated asgiref dependency to at least v3.9.1. + +* Fixed compatibility with latest versions of pytest-asyncio. + +* Renamed internal methods in core channel layer for compatibility with + Channels v4.2.1+ + +* Dropped testing against legacy Channels v3 branch. + +* Updated testing against latest redis-py versions. + 4.2.1 (2024-11-15) ------------------ diff --git a/README.rst b/README.rst index 1673349..6ff225c 100644 --- a/README.rst +++ b/README.rst @@ -19,9 +19,11 @@ There are two available implementations: Both layers support a single-server and sharded configurations. -`channels_redis` is tested against Python 3.9 to 3.13, `redis-py` versions 4.6, -5.0, and the development branch, and Channels versions 3, 4 and the development -branch there. +`channels_redis` is tested against Python 3.9 to 3.13. We test with the latest +`redis-py` version, as well as the older 5.x branch and main development branch, +using the latest stable Python and Channels versions. We test the Channels +development branch, using the latest stable Python and the latest `redis-py` +release. Installation ------------ diff --git a/channels_redis/__init__.py b/channels_redis/__init__.py index aef46ac..111dc91 100644 --- a/channels_redis/__init__.py +++ b/channels_redis/__init__.py @@ -1 +1 @@ -__version__ = "4.2.1" +__version__ = "4.3.0" diff --git a/channels_redis/core.py b/channels_redis/core.py index a230081..9721d7b 100644 --- a/channels_redis/core.py +++ b/channels_redis/core.py @@ -169,7 +169,7 @@ async def send(self, channel, message): """ # Typecheck assert isinstance(message, dict), "message is not a dict" - assert self.valid_channel_name(channel), "Channel name not valid" + assert self.require_valid_channel_name(channel), "Channel name not valid" # Make sure the message does not contain reserved keys assert "__asgi_channel__" not in message # If it's a process-local channel, strip off local part and stick full name in message @@ -256,7 +256,7 @@ async def receive(self, channel): """ # Make sure the channel name is valid then get the non-local part # and thus its index - assert self.valid_channel_name(channel) + assert self.require_valid_channel_name(channel) if "!" in channel: real_channel = self.non_local_name(channel) assert real_channel.endswith( @@ -377,7 +377,9 @@ async def receive_single(self, channel): Receives a single message off of the channel and returns it. """ # Check channel name - assert self.valid_channel_name(channel, receive=True), "Channel name invalid" + assert self.require_valid_channel_name( + channel, receive=True + ), "Channel name invalid" # Work out the connection to use if "!" in channel: assert channel.endswith("!") @@ -482,8 +484,8 @@ async def group_add(self, group, channel): Adds the channel name to a group. """ # Check the inputs - assert self.valid_group_name(group), "Group name not valid" - assert self.valid_channel_name(channel), "Channel name not valid" + assert self.require_valid_group_name(group), "Group name not valid" + assert self.require_valid_channel_name(channel), "Channel name not valid" # Get a connection to the right shard group_key = self._group_key(group) connection = self.connection(self.consistent_hash(group)) @@ -498,8 +500,8 @@ async def group_discard(self, group, channel): Removes the channel from the named group if it is in the group; does nothing otherwise (does not error) """ - assert self.valid_group_name(group), "Group name not valid" - assert self.valid_channel_name(channel), "Channel name not valid" + assert self.require_valid_group_name(group), "Group name not valid" + assert self.require_valid_channel_name(channel), "Channel name not valid" key = self._group_key(group) connection = self.connection(self.consistent_hash(group)) await connection.zrem(key, channel) @@ -508,7 +510,7 @@ async def group_send(self, group, message): """ Sends a message to the entire group. """ - assert self.valid_group_name(group), "Group name not valid" + assert self.require_valid_group_name(group), "Group name not valid" # Retrieve list of all channel names key = self._group_key(group) connection = self.connection(self.consistent_hash(group)) diff --git a/setup.py b/setup.py index bf272f7..56eee12 100644 --- a/setup.py +++ b/setup.py @@ -33,8 +33,8 @@ install_requires=[ "redis>=4.6", "msgpack~=1.0", - "asgiref>=3.2.10,<4", - "channels", + "asgiref>=3.9.1,<4", + "channels>=4.2.2", ], extras_require={"cryptography": crypto_requires, "tests": test_requires}, ) diff --git a/tox.ini b/tox.ini index af89536..ffdfc99 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,8 @@ [tox] envlist = - py{39,310,311,312,313}-ch{30,40,main}-redis50 - py311-chmain-redis{45,46,50,main} + py{39,310,311,312,313}-ch4-redis6 + py313-chmain-redis6 + py313-ch4-redis{5,main} qa [testenv] @@ -10,11 +11,10 @@ extras = tests commands = pytest -v {posargs} deps = - ch30: channels>=3.0,<3.1 - ch40: channels>=4.0,<4.1 + ch4: channels>=4.0,<5 chmain: https://github.com/django/channels/archive/main.tar.gz - redis46: redis>=4.6,<4.7 - redis50: redis>=5.0,<5.1 + redis5: redis>=5.0,<6 + redis6: redis>=6.0,<7 redismain: https://github.com/redis/redis-py/archive/master.tar.gz [testenv:qa]