Skip to content

Commit

Permalink
feat: ✨ Drop Python 3.9 support, add 3.13 support and update things
Browse files Browse the repository at this point in the history
  • Loading branch information
ddanier committed Nov 7, 2024
1 parent 6368f81 commit c5c3dce
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 37 deletions.
12 changes: 4 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: check-added-large-files
- id: check-merge-conflict
- id: check-docstring-first
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.1
rev: v0.7.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/Lucas-C/pre-commit-hooks-safety
rev: v1.3.3
hooks:
- id: python-safety-dependencies-check
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.11.0
rev: v9.18.0
hooks:
- id: commitlint
stages: [commit-msg]
additional_dependencies:
- "@commitlint/config-conventional"
default_stages:
- commit
- pre-commit
default_install_hook_types:
- pre-commit
- commit-msg
19 changes: 10 additions & 9 deletions async_signals/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import logging
import threading
import weakref
from typing import Any, Callable, Dict, Hashable, List, Optional, Tuple, Type, Union
from collections.abc import Hashable
from typing import Any, Callable, Optional, Union

from .utils import func_accepts_kwargs

Expand All @@ -11,7 +12,7 @@

def _make_id(
target: Union[Hashable, Callable, None],
) -> Union[Hashable, Tuple[Hashable, ...]]:
) -> Union[Hashable, tuple[Hashable, ...]]:
if hasattr(target, "__self__") and hasattr(target, "__func__"):
return id(target.__self__), id(target.__func__) # type: ignore
return id(target)
Expand All @@ -33,7 +34,7 @@ class Signal:
{ receiverkey (id) : weakref(receiver) }
"""

receivers: List[Tuple[Tuple[Hashable, Hashable], Callable]]
receivers: list[tuple[tuple[Hashable, Hashable], Callable]]
use_caching: bool
debug: bool

Expand All @@ -55,7 +56,7 @@ def __init__(
# distinct sender we cache the receivers that sender has in
# 'sender_receivers_cache'. The cache is cleaned when .connect() or
# .disconnect() is called and populated on send().
self.sender_receivers_cache: Union[weakref.WeakKeyDictionary, Dict] \
self.sender_receivers_cache: Union[weakref.WeakKeyDictionary, dict] \
= weakref.WeakKeyDictionary() if use_caching else {}
self._dead_receivers = False

Expand Down Expand Up @@ -115,7 +116,7 @@ def connect(
lookup_key = (_make_id(receiver), _make_id(sender))

if weak:
ref: Union[Type[weakref.WeakMethod[Any]], Type[weakref.ReferenceType[Any]]] \
ref: Union[type[weakref.WeakMethod[Any]], type[weakref.ReferenceType[Any]]] \
= weakref.ref
receiver_object = receiver
# Check for bound methods
Expand Down Expand Up @@ -201,7 +202,7 @@ async def send(
self,
sender: Hashable,
**named: Any,
) -> List[Tuple[Callable, Any]]:
) -> list[tuple[Callable, Any]]:
"""
Send signal from sender to all connected receivers.
Expand Down Expand Up @@ -243,7 +244,7 @@ async def send_robust(
self,
sender: Hashable,
**named: Any,
) -> List[Tuple[Callable, Any]]:
) -> list[tuple[Callable, Any]]:
"""
Send signal from sender to all connected receivers catching errors.
Expand Down Expand Up @@ -302,7 +303,7 @@ def _clear_dead_receivers(self) -> None:
if not (isinstance(r[1], weakref.ReferenceType) and r[1]() is None)
]

def _live_receivers(self, sender: Union[Hashable, None]) -> List[Callable]:
def _live_receivers(self, sender: Union[Hashable, None]) -> list[Callable]:
"""
Filter sequence of receivers to get resolved, live receivers.
Expand Down Expand Up @@ -353,7 +354,7 @@ def _remove_receiver(self, receiver: Optional[Callable] = None) -> None: # noqa


def receiver(
signal: Union[Signal, List[Signal], Tuple[Signal, ...]],
signal: Union[Signal, list[Signal], tuple[Signal, ...]],
*,
sender: Optional[Hashable] = None,
weak: bool = True,
Expand Down
6 changes: 3 additions & 3 deletions async_signals/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import functools
import inspect
from typing import Callable, Tuple
from typing import Callable

# Those functions are copied from
# https://github.com/django/django/blob/main/django/utils/inspect.py
Expand All @@ -10,7 +10,7 @@
def _get_func_parameters(
func: Callable,
remove_first: bool,
) -> Tuple[inspect.Parameter, ...]:
) -> tuple[inspect.Parameter, ...]:
parameters = tuple(inspect.signature(func).parameters.values())
if remove_first:
parameters = parameters[1:]
Expand All @@ -19,7 +19,7 @@ def _get_func_parameters(

def _get_callable_parameters(
meth_or_func: Callable,
) -> Tuple[inspect.Parameter, ...]:
) -> tuple[inspect.Parameter, ...]:
is_method = inspect.ismethod(meth_or_func)
func = meth_or_func.__func__ if is_method else meth_or_func # type: ignore
return _get_func_parameters(func, remove_first=is_method)
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ readme = "README.md"
packages = [{include = "async_signals"}]

[tool.poetry.dependencies]
python = "^3.8"
python = "^3.9"

[tool.poetry.group.dev.dependencies]
pytest = ">=7.1.3,<9.0.0"
Expand All @@ -22,7 +22,7 @@ pyright = ">=1.1.350,<1.2"

[tool.ruff]
line-length = 115
target-version = "py38"
target-version = "py39"
output-format = "grouped"

[tool.ruff.lint]
Expand Down
26 changes: 13 additions & 13 deletions tests/test_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@
from async_signals import Signal, receiver


@pytest.fixture()
@pytest.fixture
def signal() -> Signal:
return Signal()


@pytest.fixture()
@pytest.fixture
def signal2() -> Signal:
return Signal()


@pytest.fixture()
@pytest.fixture
def debug_signal() -> Signal:
return Signal(debug=True)


@pytest.fixture()
@pytest.fixture
def cached_signal() -> Signal:
return Signal(use_caching=True)

Expand Down Expand Up @@ -153,14 +153,14 @@ def invalid_receiver_function():
debug_signal.connect(invalid_receiver_function)


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_without_receivers(signal: Signal, mocker):
result = await signal.send(sender=test_signal_send_without_receivers, x="a", y="b")

assert len(result) == 0


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_without_receivers_and_caching(signal: Signal, mocker):
signal.use_caching = True

Expand All @@ -169,7 +169,7 @@ async def test_signal_send_without_receivers_and_caching(signal: Signal, mocker)
assert len(result) == 0


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_sync(signal: Signal, mocker):
receiver_function = mocker.Mock()

Expand All @@ -186,7 +186,7 @@ async def test_signal_send_sync(signal: Signal, mocker):
)


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_async(signal: Signal, mocker):
receiver_function = mocker.AsyncMock()

Expand All @@ -203,7 +203,7 @@ async def test_signal_send_async(signal: Signal, mocker):
)


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_will_raise_exception(signal: Signal, mocker):
receiver_function = mocker.AsyncMock(
side_effect=RuntimeError("Boom!"),
Expand All @@ -215,14 +215,14 @@ async def test_signal_send_will_raise_exception(signal: Signal, mocker):
await signal.send(sender=test_signal_send_will_raise_exception, x="a", y="b")


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_robust_without_receivers(signal: Signal, mocker):
result = await signal.send_robust(sender=test_signal_send_without_receivers, x="a", y="b")

assert len(result) == 0


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_robust_works_normally(signal: Signal, mocker):
receiver_function = mocker.AsyncMock()

Expand All @@ -239,7 +239,7 @@ async def test_signal_send_robust_works_normally(signal: Signal, mocker):
)


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_signal_send_robust_will_catch_exception(signal: Signal, mocker):
receiver_function = mocker.AsyncMock(
side_effect=Exception("Boom!"),
Expand Down Expand Up @@ -268,7 +268,7 @@ def receiver_function(**kwargs):
assert len(signal2.receivers) == 1


@pytest.mark.anyio()
@pytest.mark.anyio
async def test_receivers_only_called_when_sender_matches(signal: Signal, mocker):
receiver_function1 = mocker.AsyncMock()
receiver_function2 = mocker.AsyncMock()
Expand Down
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[tox]
isolated_build = True
envlist =
py38,
py39,
py310,
py311,
py312
py312,
py313

[testenv]
deps =
Expand Down

0 comments on commit c5c3dce

Please sign in to comment.