Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-aiosignal for openSUSE:Factory checked in at 2025-07-10 23:15:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-aiosignal (Old) and /work/SRC/openSUSE:Factory/.python-aiosignal.new.7373 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-aiosignal" Thu Jul 10 23:15:00 2025 rev:6 rq:1291582 version:1.4.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-aiosignal/python-aiosignal.changes 2025-06-13 18:43:47.034772467 +0200 +++ /work/SRC/openSUSE:Factory/.python-aiosignal.new.7373/python-aiosignal.changes 2025-07-10 23:15:15.281054528 +0200 @@ -1,0 +2,10 @@ +Thu Jul 10 04:53:25 UTC 2025 - Steve Kowalik <steven.kowa...@suse.com> + +- Upgrade to 1.4.0: + * Added decorator functionality to Signal as a convenient way to add a + callback + * Improved type safety by allowing callback parameters to be type checked + (typing-extensions is now required for Python <3.13). Parameters for a + Signal callback should now be defined like Signal[int, str] + +------------------------------------------------------------------- Old: ---- aiosignal-1.3.2.tar.gz New: ---- aiosignal-1.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-aiosignal.spec ++++++ --- /var/tmp/diff_new_pack.EBuJsC/_old 2025-07-10 23:15:15.957082688 +0200 +++ /var/tmp/diff_new_pack.EBuJsC/_new 2025-07-10 23:15:15.957082688 +0200 @@ -16,27 +16,31 @@ # -%define skip_python2 1 %{?sle15_python_module_pythons} Name: python-aiosignal -Version: 1.3.2 +Version: 1.4.0 Release: 0 Summary: a list of registered asynchronous callbacks License: Apache-2.0 URL: https://github.com/aio-libs/aiosignal Source: https://files.pythonhosted.org/packages/source/a/aiosignal/aiosignal-%{version}.tar.gz +BuildRequires: %{python_module base >= 3.9} BuildRequires: %{python_module pip} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module wheel} BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-frozenlist >= 1.1.0 +%if 0%{?python_version_nodots} < 313 +Requires: python-typing_extensions >= 4.4 +%endif BuildArch: noarch # SECTION test requirements BuildRequires: %{python_module frozenlist >= 1.1.0} BuildRequires: %{python_module pytest-asyncio} BuildRequires: %{python_module pytest-cov} BuildRequires: %{python_module pytest} +BuildRequires: %{python_module typing_extensions >= 4.4} # /SECTION %python_subpackages ++++++ aiosignal-1.3.2.tar.gz -> aiosignal-1.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/.codecov.yml new/aiosignal-1.4.0/.codecov.yml --- old/aiosignal-1.3.2/.codecov.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/.codecov.yml 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,32 @@ +coverage: + range: 95..100 + + status: + project: off + +flags: + library: + paths: + - aiosignal/ + configs: + paths: + - requirements/ + - .git* + - '*.toml' + - '*.yml' + changelog: + paths: + - CHANGES/ + - CHANGES.rst + docs: + paths: + - docs/ + - '*.md' + - '*.rst' + - '*.txt' + tests: + paths: + - tests/ + tools: + paths: + - tools/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/.coveragerc new/aiosignal-1.4.0/.coveragerc --- old/aiosignal-1.3.2/.coveragerc 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/.coveragerc 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,22 @@ +[html] +show_contexts = true +skip_covered = false + +[paths] +_site-packages-to-src-mapping = + . + */lib/pypy*/site-packages + */lib/python*/site-packages + *\Lib\site-packages + +[run] +branch = true +cover_pylib = false +omit = + setup.py +parallel = true +relative_files = true +source = + . +source_pkgs = + aiosignal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/CHANGES.rst new/aiosignal-1.4.0/CHANGES.rst --- old/aiosignal-1.3.2/CHANGES.rst 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/CHANGES.rst 2025-07-04 00:38:03.000000000 +0200 @@ -14,6 +14,29 @@ .. towncrier release notes start +1.4.0 (2025-07-03) +================== + +Features +-------- + +- Added decorator functionality to ``Signal`` as a convenient way to add a callback -- by ``@Vizonex``. + `#699 <https://github.com/aio-libs/aiosignal/pulls/699>`_ + +- Improved type safety by allowing callback parameters to be type checked (typing-extensions is now required for Python <3.13). + Parameters for a ``Signal`` callback should now be defined like ``Signal[int, str]`` -- by @Vizonex and @Dreamsorcerer. + `#699 <https://github.com/aio-libs/aiosignal/pulls/699>`_, `#710 <https://github.com/aio-libs/aiosignal/pulls/710>`_ + + +Misc +---- + +- Removed the sphinxcontrib-asyncio documentation dependency. + `#528 <https://github.com/aio-libs/aiosignal/pull/528>`_ + + +---- + 1.3.2 (2024-12-13) ================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/CONTRIBUTORS.txt new/aiosignal-1.4.0/CONTRIBUTORS.txt --- old/aiosignal-1.3.2/CONTRIBUTORS.txt 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/CONTRIBUTORS.txt 2025-07-04 00:38:03.000000000 +0200 @@ -3,3 +3,4 @@ Andrew Svetlov Martijn Pieters Nikolay Kim +Vizonex diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/MANIFEST.in new/aiosignal-1.4.0/MANIFEST.in --- old/aiosignal-1.3.2/MANIFEST.in 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/MANIFEST.in 2025-07-04 00:38:03.000000000 +0200 @@ -1,10 +1,15 @@ +include .codecov.yml +include .coveragerc include LICENSE include CHANGES.rst include README.rst include CONTRIBUTORS.txt include Makefile +include pytest.ini +include tox.ini graft aiosignal graft docs +graft requirements graft tests global-include *.pyi global-exclude *.pyc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/PKG-INFO new/aiosignal-1.4.0/PKG-INFO --- old/aiosignal-1.3.2/PKG-INFO 2024-12-13 18:10:33.602803500 +0100 +++ new/aiosignal-1.4.0/PKG-INFO 2025-07-04 00:38:12.641044000 +0200 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: aiosignal -Version: 1.3.2 +Version: 1.4.0 Summary: aiosignal: a list of registered asynchronous callbacks Home-page: https://github.com/aio-libs/aiosignal Maintainer: aiohttp team <t...@aiohttp.org> @@ -26,6 +26,8 @@ Description-Content-Type: text/x-rst License-File: LICENSE Requires-Dist: frozenlist>=1.1.0 +Requires-Dist: typing-extensions>=4.2; python_version < "3.13" +Dynamic: license-file ========= aiosignal @@ -35,8 +37,8 @@ :target: https://github.com/aio-libs/aiosignal/actions?query=workflow%3ACI :alt: GitHub status for master branch -.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aiosignal +.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg?flag=pytest + :target: https://codecov.io/gh/aio-libs/aiosignal?flags[0]=pytest :alt: codecov.io status for master branch .. image:: https://badge.fury.io/py/aiosignal.svg @@ -86,25 +88,12 @@ $ pip install aiosignal -The library requires Python 3.8 or newer. - Documentation ============= https://aiosignal.readthedocs.io/ -Communication channels -====================== - -*gitter chat* https://gitter.im/aio-libs/Lobby - -Requirements -============ - -- Python >= 3.8 -- frozenlist >= 1.0.0 - License ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/README.rst new/aiosignal-1.4.0/README.rst --- old/aiosignal-1.3.2/README.rst 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/README.rst 2025-07-04 00:38:03.000000000 +0200 @@ -6,8 +6,8 @@ :target: https://github.com/aio-libs/aiosignal/actions?query=workflow%3ACI :alt: GitHub status for master branch -.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aiosignal +.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg?flag=pytest + :target: https://codecov.io/gh/aio-libs/aiosignal?flags[0]=pytest :alt: codecov.io status for master branch .. image:: https://badge.fury.io/py/aiosignal.svg @@ -57,25 +57,12 @@ $ pip install aiosignal -The library requires Python 3.8 or newer. - Documentation ============= https://aiosignal.readthedocs.io/ -Communication channels -====================== - -*gitter chat* https://gitter.im/aio-libs/Lobby - -Requirements -============ - -- Python >= 3.8 -- frozenlist >= 1.0.0 - License ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/aiosignal/__init__.py new/aiosignal-1.4.0/aiosignal/__init__.py --- old/aiosignal-1.3.2/aiosignal/__init__.py 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/aiosignal/__init__.py 2025-07-04 00:38:03.000000000 +0200 @@ -1,11 +1,27 @@ +import sys +from typing import Any, Awaitable, Callable, TypeVar + from frozenlist import FrozenList -__version__ = "1.3.2" +if sys.version_info >= (3, 11): + from typing import Unpack +else: + from typing_extensions import Unpack + +if sys.version_info >= (3, 13): + from typing import TypeVarTuple +else: + from typing_extensions import TypeVarTuple + +_T = TypeVar("_T") +_Ts = TypeVarTuple("_Ts", default=Unpack[tuple[()]]) + +__version__ = "1.4.0" __all__ = ("Signal",) -class Signal(FrozenList): +class Signal(FrozenList[Callable[[Unpack[_Ts]], Awaitable[object]]]): """Coroutine-based signal implementation. To connect a callback to a signal, use any list method. @@ -16,16 +32,16 @@ __slots__ = ("_owner",) - def __init__(self, owner): + def __init__(self, owner: object): super().__init__() self._owner = owner - def __repr__(self): + def __repr__(self) -> str: return "<Signal owner={}, frozen={}, {!r}>".format( self._owner, self.frozen, list(self) ) - async def send(self, *args, **kwargs): + async def send(self, *args: Unpack[_Ts], **kwargs: Any) -> None: """ Sends data to all registered receivers. """ @@ -33,4 +49,11 @@ raise RuntimeError("Cannot send non-frozen signal.") for receiver in self: - await receiver(*args, **kwargs) # type: ignore + await receiver(*args, **kwargs) + + def __call__( + self, func: Callable[[Unpack[_Ts]], Awaitable[_T]] + ) -> Callable[[Unpack[_Ts]], Awaitable[_T]]: + """Decorator to add a function to this Signal.""" + self.append(func) + return func diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/aiosignal/__init__.pyi new/aiosignal-1.4.0/aiosignal/__init__.pyi --- old/aiosignal-1.3.2/aiosignal/__init__.pyi 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/aiosignal/__init__.pyi 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -from typing import Any, Generic, TypeVar - -from frozenlist import FrozenList - -__all__ = ("Signal",) - -_T = TypeVar("_T") - -class Signal(FrozenList[_T], Generic[_T]): - def __init__(self, owner: Any) -> None: ... - def __repr__(self) -> str: ... - async def send(self, *args: Any, **kwargs: Any) -> None: ... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/aiosignal.egg-info/PKG-INFO new/aiosignal-1.4.0/aiosignal.egg-info/PKG-INFO --- old/aiosignal-1.3.2/aiosignal.egg-info/PKG-INFO 2024-12-13 18:10:33.000000000 +0100 +++ new/aiosignal-1.4.0/aiosignal.egg-info/PKG-INFO 2025-07-04 00:38:12.000000000 +0200 @@ -1,6 +1,6 @@ -Metadata-Version: 2.1 +Metadata-Version: 2.4 Name: aiosignal -Version: 1.3.2 +Version: 1.4.0 Summary: aiosignal: a list of registered asynchronous callbacks Home-page: https://github.com/aio-libs/aiosignal Maintainer: aiohttp team <t...@aiohttp.org> @@ -26,6 +26,8 @@ Description-Content-Type: text/x-rst License-File: LICENSE Requires-Dist: frozenlist>=1.1.0 +Requires-Dist: typing-extensions>=4.2; python_version < "3.13" +Dynamic: license-file ========= aiosignal @@ -35,8 +37,8 @@ :target: https://github.com/aio-libs/aiosignal/actions?query=workflow%3ACI :alt: GitHub status for master branch -.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aiosignal +.. image:: https://codecov.io/gh/aio-libs/aiosignal/branch/master/graph/badge.svg?flag=pytest + :target: https://codecov.io/gh/aio-libs/aiosignal?flags[0]=pytest :alt: codecov.io status for master branch .. image:: https://badge.fury.io/py/aiosignal.svg @@ -86,25 +88,12 @@ $ pip install aiosignal -The library requires Python 3.8 or newer. - Documentation ============= https://aiosignal.readthedocs.io/ -Communication channels -====================== - -*gitter chat* https://gitter.im/aio-libs/Lobby - -Requirements -============ - -- Python >= 3.8 -- frozenlist >= 1.0.0 - License ======= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/aiosignal.egg-info/SOURCES.txt new/aiosignal-1.4.0/aiosignal.egg-info/SOURCES.txt --- old/aiosignal-1.3.2/aiosignal.egg-info/SOURCES.txt 2024-12-13 18:10:33.000000000 +0100 +++ new/aiosignal-1.4.0/aiosignal.egg-info/SOURCES.txt 2025-07-04 00:38:12.000000000 +0200 @@ -1,3 +1,5 @@ +.codecov.yml +.coveragerc CHANGES.rst CONTRIBUTORS.txt LICENSE @@ -5,10 +7,11 @@ Makefile README.rst pyproject.toml +pytest.ini setup.cfg setup.py +tox.ini aiosignal/__init__.py -aiosignal/__init__.pyi aiosignal/py.typed aiosignal.egg-info/PKG-INFO aiosignal.egg-info/SOURCES.txt @@ -20,5 +23,13 @@ docs/index.rst docs/make.bat docs/spelling_wordlist.txt +requirements/ci-bot.txt +requirements/ci-wheel.txt +requirements/ci.txt +requirements/dev.txt +requirements/doc-spelling.txt +requirements/doc.txt +requirements/towncrier.txt +requirements/wheel.txt tests/conftest.py tests/test_signals.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/aiosignal.egg-info/requires.txt new/aiosignal-1.4.0/aiosignal.egg-info/requires.txt --- old/aiosignal-1.3.2/aiosignal.egg-info/requires.txt 2024-12-13 18:10:33.000000000 +0100 +++ new/aiosignal-1.4.0/aiosignal.egg-info/requires.txt 2025-07-04 00:38:12.000000000 +0200 @@ -1 +1,4 @@ frozenlist>=1.1.0 + +[:python_version < "3.13"] +typing-extensions>=4.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/docs/conf.py new/aiosignal-1.4.0/docs/conf.py --- old/aiosignal-1.3.2/docs/conf.py 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/docs/conf.py 2025-07-04 00:38:03.000000000 +0200 @@ -45,7 +45,6 @@ extensions = [ "sphinx.ext.viewcode", "sphinx.ext.intersphinx", - "sphinxcontrib.asyncio", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/docs/index.rst new/aiosignal-1.4.0/docs/index.rst --- old/aiosignal-1.3.2/docs/index.rst 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/docs/index.rst 2025-07-04 00:38:03.000000000 +0200 @@ -15,6 +15,14 @@ The only available operation is calling the previously registered callbacks by using ``await sig.send(data)``. +The callback parameters, which should be passed in the ``.send()`` call, can be +specified for a type checker: + +```python +signal = Signal[int, str](owner) +signal.send(42, "foo") +``` + For concrete usage examples see the :ref:`aiohttp:aiohttp-web-signals` section of the :doc:`aiohttp:web_advanced` chapter of the :doc:`aiohttp documentation <aiohttp:index>`. API diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/docs/spelling_wordlist.txt new/aiosignal-1.4.0/docs/spelling_wordlist.txt --- old/aiosignal-1.3.2/docs/spelling_wordlist.txt 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/docs/spelling_wordlist.txt 2025-07-04 00:38:03.000000000 +0200 @@ -66,9 +66,6 @@ css ctor Ctrl -Cython -cythonized -Cythonize de deduplicate # de-facto: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/pytest.ini new/aiosignal-1.4.0/pytest.ini --- old/aiosignal-1.3.2/pytest.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/pytest.ini 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,83 @@ +[pytest] +addopts = + # `pytest-xdist`: + # --numprocesses=auto + # NOTE: the plugin disabled because it's slower with so few tests + # --numprocesses=0 + + # Show 10 slowest invocations: + --durations=10 + + # Report all the things == -rxXs: + -ra + + # Show values of the local vars in errors/tracebacks: + --showlocals + + # Autocollect and invoke the doctests from all modules: + # https://docs.pytest.org/en/stable/doctest.html + --doctest-modules + + # Pre-load the `pytest-cov` plugin early: + -p pytest_cov + + # `pytest-cov`: + --cov + --cov-config=.coveragerc + --cov-context=test + --no-cov-on-fail + + # Fail on config parsing warnings: + # --strict-config + + # Fail on non-existing markers: + # * Deprecated since v6.2.0 but may be reintroduced later covering a + # broader scope: + # --strict + # * Exists since v4.5.0 (advised to be used instead of `--strict`): + --strict-markers + +asyncio_mode = auto +asyncio_default_fixture_loop_scope = function + +doctest_optionflags = ALLOW_UNICODE ELLIPSIS + +# Marks tests with an empty parameterset as xfail(run=False) +empty_parameter_set_mark = xfail + +faulthandler_timeout = 30 + +filterwarnings = + error + +# https://docs.pytest.org/en/stable/usage.html#creating-junitxml-format-files +junit_duration_report = call +# xunit1 contains more metadata than xunit2 so it's better for CI UIs: +junit_family = xunit1 +junit_logging = all +junit_log_passing_tests = true +junit_suite_name = aiosignal_test_suite + +# A mapping of markers to their descriptions allowed in strict mode: +markers = + +minversion = 6.1.0 + +# Optimize pytest's lookup by restricting potentially deep dir tree scan: +norecursedirs = + build + dependencies + dist + docs + .* + *.egg + *.egg-info + */*.egg-info + */**/*.egg-info + *.dist-info + */*.dist-info + */**/*.dist-info + +testpaths = tests/ + +xfail_strict = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/ci-bot.txt new/aiosignal-1.4.0/requirements/ci-bot.txt --- old/aiosignal-1.3.2/requirements/ci-bot.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/ci-bot.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,2 @@ +-r ci-wheel.txt +-e . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/ci-wheel.txt new/aiosignal-1.4.0/requirements/ci-wheel.txt --- old/aiosignal-1.3.2/requirements/ci-wheel.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/ci-wheel.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,5 @@ +-r wheel.txt + +coverage==7.9.1 +pytest-cov==6.2.1 +tox==4.27.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/ci.txt new/aiosignal-1.4.0/requirements/ci.txt --- old/aiosignal-1.3.2/requirements/ci.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/ci.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,7 @@ +setuptools-git==1.2 +mypy==1.16.1; implementation_name=="cpython" +mypy-extensions==1.1.0; implementation_name=="cpython" + +-r ci-wheel.txt +-r doc.txt +-e . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/dev.txt new/aiosignal-1.4.0/requirements/dev.txt --- old/aiosignal-1.3.2/requirements/dev.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/dev.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,3 @@ +-r ci.txt +-r towncrier.txt +cherry_picker==2.5.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/doc-spelling.txt new/aiosignal-1.4.0/requirements/doc-spelling.txt --- old/aiosignal-1.3.2/requirements/doc-spelling.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/doc-spelling.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,2 @@ +-r doc.txt +sphinxcontrib-spelling==8.0.1; platform_system!="Windows" # We only use it in Travis CI diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/doc.txt new/aiosignal-1.4.0/requirements/doc.txt --- old/aiosignal-1.3.2/requirements/doc.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/doc.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,3 @@ +sphinx==8.2.3 +pygments>=2.1 +aiohttp-theme==0.1.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/towncrier.txt new/aiosignal-1.4.0/requirements/towncrier.txt --- old/aiosignal-1.3.2/requirements/towncrier.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/towncrier.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1 @@ +towncrier==24.8.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/requirements/wheel.txt new/aiosignal-1.4.0/requirements/wheel.txt --- old/aiosignal-1.3.2/requirements/wheel.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/requirements/wheel.txt 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,4 @@ +pytest==8.4.1 +pytest-asyncio==1.0.0 +pre-commit==4.2.0 +twine==6.1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/setup.cfg new/aiosignal-1.4.0/setup.cfg --- old/aiosignal-1.3.2/setup.cfg 2024-12-13 18:10:33.602803500 +0100 +++ new/aiosignal-1.4.0/setup.cfg 2025-07-04 00:38:12.642043800 +0200 @@ -1,6 +1,3 @@ -[bdist_wheel] -universal = True - [metadata] name = aiosignal version = attr: aiosignal.__version__ @@ -40,6 +37,7 @@ include_package_data = True install_requires = frozenlist >= 1.1.0 + typing-extensions >= 4.2; python_version < '3.13' [pep8] max-line-length = 88 @@ -65,34 +63,6 @@ @abc.abstractmethod @abstractmethod -[tool:pytest] -addopts = --cov=aiosignal -v -rxXs -filterwarnings = error -junit_suite_name = aiosignal_test_suite -junit_family = xunit2 -norecursedirs = dist docs build .tox .eggs -minversion = 3.8.2 -testpaths = tests/ -asyncio_mode = strict -asyncio_default_fixture_loop_scope = function - -[coverage:run] -branch = True -source = aiosignal -omit = site-packages - -[mypy] -follow_imports = silent -strict_optional = True -warn_redundant_casts = True -check_untyped_defs = True -disallow_any_generics = True -disallow_untyped_defs = True -warn_unused_ignores = True - -[mypy-pytest] -ignore_missing_imports = true - [egg_info] tag_build = tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/tests/test_signals.py new/aiosignal-1.4.0/tests/test_signals.py --- old/aiosignal-1.3.2/tests/test_signals.py 2024-12-13 18:10:20.000000000 +0100 +++ new/aiosignal-1.4.0/tests/test_signals.py 2025-07-04 00:38:03.000000000 +0200 @@ -1,10 +1,16 @@ import re +import sys from unittest import mock import pytest from aiosignal import Signal +if sys.version_info >= (3, 11): + from typing import Unpack +else: + from typing_extensions import Unpack + class Owner: def __repr__(self) -> str: @@ -16,24 +22,32 @@ return Owner() -@pytest.mark.asyncio +async def test_signal_positional_args(owner: Owner) -> None: + async def callback(a: int, b: str) -> None: + return + + signal = Signal[int, str](owner) + signal.append(callback) + signal.freeze() + await signal.send(42, "foo") + + async def test_add_signal_handler_not_a_callable(owner: Owner) -> None: callback = True signal = Signal(owner) - signal.append(callback) + signal.append(callback) # type: ignore[arg-type] signal.freeze() with pytest.raises(TypeError): await signal.send() -@pytest.mark.asyncio async def test_function_signal_dispatch_kwargs(owner: Owner) -> None: signal = Signal(owner) kwargs = {"foo": 1, "bar": 2} callback_mock = mock.Mock() - async def callback(**kwargs): + async def callback(**kwargs: object) -> None: callback_mock(**kwargs) signal.append(callback) @@ -43,25 +57,22 @@ callback_mock.assert_called_once_with(**kwargs) -@pytest.mark.asyncio async def test_function_signal_dispatch_args_kwargs(owner: Owner) -> None: - signal = Signal(owner) - args = {"a", "b"} + signal = Signal[Unpack[tuple[str, ...]]](owner) kwargs = {"foo": 1, "bar": 2} callback_mock = mock.Mock() - async def callback(*args, **kwargs): + async def callback(*args: str, **kwargs: object) -> None: callback_mock(*args, **kwargs) signal.append(callback) signal.freeze() - await signal.send(*args, **kwargs) - callback_mock.assert_called_once_with(*args, **kwargs) + await signal.send("a", "b", **kwargs) + callback_mock.assert_called_once_with("a", "b", **kwargs) -@pytest.mark.asyncio async def test_non_coroutine(owner: Owner) -> None: signal = Signal(owner) kwargs = {"foo": 1, "bar": 2} @@ -129,14 +140,13 @@ assert list(signal) == [m1] -@pytest.mark.asyncio async def test_cannot_send_non_frozen_signal(owner: Owner) -> None: signal = Signal(owner) callback_mock = mock.Mock() - async def callback(**kwargs): - callback_mock(**kwargs) + async def callback(**kwargs: object) -> None: + callback_mock(**kwargs) # pragma: no cover # mustn't be called signal.append(callback) @@ -158,3 +168,17 @@ ) is not None ) + +async def test_decorator_callback_dispatch_args_kwargs(owner: Owner) -> None: + signal = Signal(owner) + args = {"a", "b"} + kwargs = {"foo": 1, "bar": 2} + + callback_mock = mock.Mock() + + @signal + async def callback(*args: object, **kwargs: object) -> None: + callback_mock(*args, **kwargs) + + signal.freeze() + await signal.send(*args, **kwargs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiosignal-1.3.2/tox.ini new/aiosignal-1.4.0/tox.ini --- old/aiosignal-1.3.2/tox.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/aiosignal-1.4.0/tox.ini 2025-07-04 00:38:03.000000000 +0200 @@ -0,0 +1,426 @@ +[tox] +envlist = check, clean, {py39,py310,py311,py312,py313}, report +minversion = 4 + + +[python-cli-options] +byte-warnings = -b +byte-errors = -bb +max-isolation = -E -s -I +# some-isolation = -I +# FIXME: Python 2 shim. Is this equivalent to the above? +some-isolation = -E -s +warnings-to-errors = -Werror + + +[testenv] +description = Run pytest under {envpython} +# deps = +# pytest +# pytest-asyncio +# pytest-xdist +# pytest-cov +deps = -rrequirements{/}ci-wheel.txt + +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -W 'ignore:Coverage failure::pytest_cov.plugin' \ + -m pytest \ + {tty:--color=yes} \ + {posargs:--cov-report=html:{envtmpdir}{/}htmlcov{/}} +commands_post = + -{envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c \ + 'import atexit, os, sys; \ + os.getenv("GITHUB_ACTIONS") == "true" or sys.exit(); \ + import coverage; \ + gh_summary_fd = open(\ + os.environ["GITHUB_STEP_SUMMARY"], encoding="utf-8", mode="a",\ + ); \ + atexit.register(gh_summary_fd.close); \ + cov = coverage.Coverage(); \ + cov.load(); \ + cov.report(file=gh_summary_fd, output_format="markdown")' + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c \ + 'import os, pathlib, sys; \ + os.getenv("GITHUB_ACTIONS") == "true" or sys.exit(); \ + cov_report_arg_prefix = "--cov-report=xml:"; \ + test_report_arg_prefix = "--junitxml="; \ + cov_reports = [\ + arg[len(cov_report_arg_prefix):] for arg in sys.argv \ + if arg.startswith(cov_report_arg_prefix)\ + ]; \ + test_reports = [\ + arg[len(test_report_arg_prefix):] for arg in sys.argv \ + if arg.startswith(test_report_arg_prefix)\ + ]; \ + cov_report_file = cov_reports[-1] if cov_reports else None; \ + test_report_file = test_reports[-1] if test_reports else None; \ + gh_output_fd = open(\ + os.environ["GITHUB_OUTPUT"], encoding="utf-8", mode="a",\ + ); \ + cov_report_file and \ + print(f"cov-report-files={cov_report_file !s}", file=gh_output_fd); \ + test_report_file and \ + print(f"test-result-files={test_report_file !s}", file=gh_output_fd); \ + print("codecov-flags=pytest", file=gh_output_fd); \ + gh_output_fd.close()' \ + {posargs} + # Print out the output coverage dir and a way to serve html: + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c\ + 'import pathlib, shlex, sys; \ + cov_html_report_arg_prefix = "--cov-report=html:"; \ + cov_html_reports = [\ + arg[len(cov_html_report_arg_prefix):] for arg in sys.argv \ + if arg.startswith(cov_html_report_arg_prefix)\ + ]; \ + cov_html_reports or sys.exit(); \ + cov_html_report_dir = pathlib.Path(cov_html_reports[-1]); \ + index_file = cov_html_report_dir / "index.html";\ + index_file.exists() or sys.exit(); \ + html_url = f"file://\{index_file\}";\ + browse_cmd = shlex.join(("python3", "-Im", "webbrowser", html_url)); \ + serve_cmd = shlex.join((\ + "python3", "-Im", "http.server", \ + "--directory", str(cov_html_report_dir), "0", \ + )); \ + print(f"\nTo open the HTML coverage report, run\n\n\ + \t\{browse_cmd !s\}\n");\ + print(f"To serve \ + the HTML coverage report with a local web server, use\n\n\ + \t\{serve_cmd !s\}\n")' \ + {posargs:--cov-report=html:{envtmpdir}{/}htmlcov{/}} +package = editable +pass_env = + CI + GITHUB_* + SSH_AUTH_SOCK + TERM +set_env = + COVERAGE_PROCESS_START = {toxinidir}{/}.coveragerc +wheel_build_env = .pkg + + +[testenv:cleanup-dists] +description = + Wipe the the dist{/} folder +deps = +commands_pre = +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c \ + 'import os, shutil, sys; \ + dists_dir = "{toxinidir}{/}dist{/}"; \ + shutil.rmtree(dists_dir, ignore_errors=True); \ + sys.exit(os.path.exists(dists_dir))' +commands_post = +package = skip + + +[testenv:build-dists] +description = + Build dists with {basepython} and put them into the dist{/} folder +depends = + cleanup-dists +deps = + build +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -m build \ + {posargs:} +commands_post = +package = skip + + +[testenv:metadata-validation] +description = + Verify that dists under the `dist{/}` dir + have valid metadata +depends = + build-dists +deps = -rrequirements{/}wheel.txt +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -m twine \ + check \ + --strict \ + dist{/}* +commands_post = +package = skip + + +[testenv:pre-commit] +description = + Run the quality checks under {basepython}; run as + `SKIP=check-id1,check-id2 tox r -e pre-commit` to instruct the underlying + `pre-commit` invocation avoid running said checks; Use + `tox r -e pre-commit -- check-id1 --all-files` to select checks matching IDs + aliases{:} `tox r -e pre-commit -- mypy --all-files` will run 3 MyPy + invocations, but `tox r -e pre-commit -- mypy-py313 --all-files` runs one. +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -m pre_commit \ + run \ + --color=always \ + --show-diff-on-failure \ + {posargs:--all-files} + + # Print out the advice on how to install pre-commit from this env into Git: + -{envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c \ + 'cmd = "{envpython} -m pre_commit install"; \ + scr_width = len(cmd) + 10; \ + sep = "=" * scr_width; \ + cmd_str = " $ \{cmd\}";' \ + 'print(f"\n\{sep\}\nTo install pre-commit hooks into the Git repo, run:\ + \n\n\{cmd_str\}\n\n\{sep\}\n")' +commands_post = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c \ + 'import os, pathlib, sys; \ + os.getenv("GITHUB_ACTIONS") == "true" or sys.exit(); \ + project_root_path = pathlib.Path(r"{toxinidir}"); \ + test_results_dir = pathlib.Path(r"{temp_dir}") / ".test-results"; \ + coverage_result_files = ",".join(\ + str(xml_path.relative_to(project_root_path)) \ + for xml_path in test_results_dir.glob("mypy--py-*{/}cobertura.xml")\ + ); \ + gh_output_fd = open(\ + os.environ["GITHUB_OUTPUT"], encoding="utf-8", mode="a",\ + ); \ + print(\ + f"cov-report-files={coverage_result_files !s}", file=gh_output_fd\ + ); \ + print("codecov-flags=MyPy", file=gh_output_fd); \ + gh_output_fd.close()' + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c \ + 'import itertools, os, pathlib, shlex, sys; \ + os.getenv("GITHUB_ACTIONS") == "true" or sys.exit(); \ + test_results_dir = pathlib.Path(r"{temp_dir}") / ".test-results"; \ + text_and_json_reports = itertools.chain( \ + test_results_dir.glob("mypy--py-*{/}*.json"), \ + test_results_dir.glob("mypy--py-*{/}*.txt"), \ + ); \ + report_contents = { \ + report{:} report.read_text() \ + for report in text_and_json_reports \ + }; \ + reports_summary_text_blob = "\n\n".join( \ + f"\N\{NUMBER SIGN\}\N\{NUMBER SIGN\} {report_path.parent.name}{:} " \ + f"`{report_path.name}`\n\n" \ + f"```{report_path.suffix[1:]}\n{report_text}\n```\n" \ + for report_path, report_text in report_contents.items() \ + ); \ + gh_summary_fd = open( \ + os.environ["GITHUB_STEP_SUMMARY"], encoding="utf-8", mode="a", \ + ); \ + print(reports_summary_text_blob, file=gh_summary_fd); \ + gh_summary_fd.close()' + # Print out the output coverage dir and a way to serve html: + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c\ + 'import os, pathlib, sys; \ + os.getenv("GITHUB_ACTIONS") == "true" and sys.exit(); \ + len(sys.argv) >= 3 and all(\ + arg != "mypy" and not arg.startswith("mypy-py3") \ + for arg in sys.argv \ + ) and sys.exit(); \ + project_root_path = pathlib.Path(r"{toxinidir}"); \ + test_results_dir = pathlib.Path(r"{temp_dir}") / ".test-results"; \ + coverage_html_report_urls = [\ + f"file://\{xml_path !s\}" \ + for xml_path in test_results_dir.glob("mypy--py-*{/}index.html")\ + ]; \ + coverage_html_report_open_cmds = [\ + f"python3 -Im webbrowser \N\{QUOTATION MARK\}\{html_url !s\}\N\{QUOTATION MARK\}" \ + for html_url in coverage_html_report_urls\ + ]; \ + coverage_html_report_open_cmds_blob = "\n\n\t".join(\ + coverage_html_report_open_cmds,\ + ); \ + print(\ + f"\nTo open the HTML coverage reports, run\n\n\ + \t\{coverage_html_report_open_cmds_blob !s\}\n"\ + ); \ + print(\ + f"[*] Find rest of JSON and text reports, are in the same directories."\ + )\ + ' \ + {posargs:--all-files} +deps = -rrequirements{/}wheel.txt +isolated_build = true +package = skip +pass_env = + {[testenv]pass_env} + SKIP # set this variable + + +[testenv:build-docs] +# NOTE: Passing the `is_unversioned` tag speeds up rebuilds in dev env +allowlist_externals = + git +description = Build The Docs +changedir = docs{/} +commands_pre = + # Retrieve possibly missing commits: + -git fetch --unshallow + -git fetch --tags + + # Clean up sphinxcontrib-apidoc generated RST files: + -git clean -x -f -- 'pkg{/}*.rst' +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -m sphinx \ + -j auto \ + -b html \ + {tty:--color} \ + -a \ + -n \ + -W --keep-going \ + -d '{temp_dir}{/}.doctrees' \ + . \ + {posargs:{envtmpdir}{/}html -t is_unversioned} +commands_post = + # Print out the output docs dir and a way to serve html: + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -c\ + 'import os, pathlib;\ + IS_RTD_ENV = os.getenv("READTHEDOCS", "False") == "True";\ + docs_dir = pathlib.Path(r"{envdir}") / r"{envtmpdir}" / "html";\ + index_file = docs_dir / "index.html";\ + docs_url = os.environ["READTHEDOCS_CANONICAL_URL"] if IS_RTD_ENV \ + else f"file://\{index_file\}";\ + print(f"\nTo open the documentation, run\n\n\ + \tpython3 -Im webbrowser \ + \N\{QUOTATION MARK\}\{docs_url !s\}\N\{QUOTATION MARK\}\n");\ + not IS_RTD_ENV and \ + print(f"To serve \ + the docs with a local web server, use\n\n\ + \tpython3 -Im http.server --directory \ + \N\{QUOTATION MARK\}\{docs_dir\}\N\{QUOTATION MARK\} 0\n")' +deps = + -r{toxinidir}{/}requirements{/}doc.txt +pass_env = + {[testenv]pass_env} + READTHEDOCS* # Present @ RTD + + +[testenv:spellcheck-docs] +allowlist_externals = + {[testenv:build-docs]allowlist_externals} +description = Spellcheck The Docs +changedir = {[testenv:build-docs]changedir} +commands_pre = + # Retrieve possibly missing commits: + -git fetch --unshallow + -git fetch --tags + + # Clean up sphinxcontrib-apidoc generated RST files: + -git clean -x -f -- 'pkg{/}*.rst' +commands = + {envpython} \ + {[python-cli-options]byte-errors} \ + {[python-cli-options]max-isolation} \ + {[python-cli-options]warnings-to-errors} \ + -m sphinx \ + -j auto \ + {tty:--color} \ + -a \ + -n \ + -W --keep-going \ + -b spelling --color \ + -d "{temp_dir}{/}.doctrees" \ + . "{toxworkdir}{/}spelling" +commands_post = +deps = + -r{toxinidir}{/}requirements{/}doc-spelling.txt +pass_env = + {[testenv:build-docs]pass_env} + + +[testenv:check] +basepython = python3.13 + +deps = + wheel + flake8 + docutils + pygments + twine + build + +commands = + flake8 aiosignal tests + python -m build + python -m twine check --strict dist/* +commands_post = + +[testenv:clean] +basepython = python3.13 + +deps = coverage +skip_install = true + +commands = + coverage erase +commands_post = + +[testenv:report] +basepython = python3.13 + +deps = coverage +skip_install = true + +commands = + coverage report + coverage html + {envpython} -c '\ + print("python -m webbrowser \ + \N{Apostrophe}file://{toxinidir}/htmlcov/index.html\N{Apostrophe}")\ + ' +commands_post =