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 <[email protected]>
+
+- 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 <[email protected]>
@@ -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 <[email protected]>
@@ -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()
[email protected]
+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()
[email protected]
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)
[email protected]
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)
[email protected]
async def test_non_coroutine(owner: Owner) -> None:
signal = Signal(owner)
kwargs = {"foo": 1, "bar": 2}
@@ -129,14 +140,13 @@
assert list(signal) == [m1]
[email protected]
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 =